You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A lot of handle types coming from C libs are declared as Void*, but this also has the effect of turning their wrapper classes non-atomic. Take LLVM::PassBuilderOptions as an example:
libLibLLVMtypePassBuilderOptionsRef=Void*
fun create_pass_builder_options =LLVMCreatePassBuilderOptions : PassBuilderOptionsReffundispose_pass_builder_options = LLVMDisposePassBuilderOptions(options : PassBuilderOptionsRef)
end# allocation calls `GC.malloc` rather than `.malloc_atomic`, because# `@options` is an internal pointerclassLLVM::PassBuilderOptionsdefinitialize@options=LibLLVM.create_pass_builder_options
@disposed=falseenddefto_unsafe@optionsenddeffinalizereturnif@disposed@disposed=trueLibLLVM.dispose_pass_builder_options(self)
endend
Given an unreachable LLVM::PassBuilderOptions object on the heap, Boehm GC will scan the object's contents, but not the contents referred by its @options variable, because it knows that the pointer doesn't belong to its own heap (we cannot pass the GC's allocator functions to LLVM). In some other C libraries, the Void* might not even physically refer to a (virtual) memory address, e.g. most LibC::HANDLEs. If we could guarantee this, we may as well use a regular integer type rather than Void*:
libLibLLVMtypePassBuilderOptionsRef=IntPtrend
Since Crystal no longer sees any pointers inside LLVM::PassBuilderOptions's instance variables, LLVM::PassBuilderOptions will now use GC.malloc_atomic instead, and the GC won't scan the object contents at all.
An Array(LLVM::Value) maintains its buffer via Pointer(LLVM::Value).malloc. This uses non-atomic allocation because @unwrap is a pointer, but can be made atomic if LibLLVM::ValueRefValueRef becomes an IntPtr instead. Note that in this case LLVM manages the lifetimes of all LibLLVM::ValueRefs; there is no C API to dispose a value.
FWIW this will need to be nuanced for sure because it's possible to tell the C library (if it's flexible in that way) to allocate with Crystal's allocator and then actually rely on GC for the C type.
A lot of handle types coming from C libs are declared as
Void*
, but this also has the effect of turning their wrapper classes non-atomic. TakeLLVM::PassBuilderOptions
as an example:Given an unreachable
LLVM::PassBuilderOptions
object on the heap, Boehm GC will scan the object's contents, but not the contents referred by its@options
variable, because it knows that the pointer doesn't belong to its own heap (we cannot pass the GC's allocator functions to LLVM). In some other C libraries, theVoid*
might not even physically refer to a (virtual) memory address, e.g. mostLibC::HANDLE
s. If we could guarantee this, we may as well use a regular integer type rather thanVoid*
:Since Crystal no longer sees any pointers inside
LLVM::PassBuilderOptions
's instance variables,LLVM::PassBuilderOptions
will now useGC.malloc_atomic
instead, and the GC won't scan the object contents at all.A similar argument holds for struct wrappers:
An
Array(LLVM::Value)
maintains its buffer viaPointer(LLVM::Value).malloc
. This uses non-atomic allocation because@unwrap
is a pointer, but can be made atomic ifLibLLVM::ValueRefValueRef
becomes anIntPtr
instead. Note that in this case LLVM manages the lifetimes of allLibLLVM::ValueRef
s; there is no C API to dispose a value.IntPtr
may be obtained fromLibC
, or we could also expose it publicly.The text was updated successfully, but these errors were encountered: