mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 14:48:47 +00:00
Further improve on NSBlock
* Correct setting the isa of the NSBlock * Make global blocks managed by the odin runtime * Make local blocks copy to a malloc block that is managed by the objc runtime * Add method to create blocks that take a paramater
This commit is contained in:
+70
-35
@@ -1,27 +1,37 @@
|
|||||||
package objc_Foundation
|
package objc_Foundation
|
||||||
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
import "core:builtin"
|
||||||
|
import "core:mem"
|
||||||
|
|
||||||
@(objc_class="NSConcreteGlobalBlock")
|
@(objc_class="NSBlock")
|
||||||
Block :: struct {using _: Object}
|
Block :: struct {using _: Object}
|
||||||
|
|
||||||
@(objc_type=Block, objc_name="createGlobal", objc_is_class_method=true)
|
@(objc_type=Block, objc_name="createGlobal", objc_is_class_method=true)
|
||||||
Block_createGlobal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block {
|
Block_createGlobal :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr), allocator := context.allocator) -> (^Block, mem.Allocator_Error) #optional_allocator_error {
|
||||||
return Block_createInternal(true, user_data, user_proc)
|
return Block_createInternal(true, user_data, user_proc, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(objc_type=Block, objc_name="createLocal", objc_is_class_method=true)
|
@(objc_type=Block, objc_name="createLocal", objc_is_class_method=true)
|
||||||
Block_createLocal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block {
|
Block_createLocal :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block {
|
||||||
return Block_createInternal(false, user_data, user_proc)
|
b, _ := Block_createInternal(false, user_data, user_proc, {})
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
@(objc_type=Block, objc_name="createGlobalWithParam", objc_is_class_method=true)
|
||||||
|
Block_createGlobalWithParam :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr, t: $T), allocator := context.allocator) -> (^Block, mem.Allocator_Error) #optional_allocator_error {
|
||||||
|
return Block_createInternalWithParam(true, user_data, user_proc, allocator)
|
||||||
|
}
|
||||||
|
@(objc_type=Block, objc_name="createLocalWithParam", objc_is_class_method=true)
|
||||||
|
Block_createLocalWithParam :: proc (user_data: rawptr, user_proc: proc "c" (user_data: rawptr, t: $T)) -> ^Block {
|
||||||
|
b, _ := Block_createInternalWithParam(false, user_data, user_proc, {})
|
||||||
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
Internal_Block_Literal_Base :: struct {
|
Internal_Block_Literal_Base :: struct {
|
||||||
isa: ^intrinsics.objc_class,
|
isa: ^intrinsics.objc_class,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
reserved: u32,
|
reserved: u32,
|
||||||
invoke: proc "c" (^Internal_Block_Literal),
|
invoke: rawptr, // contains a pointer to a proc "c" (^Internal_Block_Literal, ...)
|
||||||
descriptor: ^Block_Descriptor,
|
descriptor: ^Block_Descriptor,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +39,7 @@ Internal_Block_Literal_Base :: struct {
|
|||||||
Internal_Block_Literal :: struct {
|
Internal_Block_Literal :: struct {
|
||||||
using base: Internal_Block_Literal_Base,
|
using base: Internal_Block_Literal_Base,
|
||||||
// Imported Variables
|
// Imported Variables
|
||||||
user_proc: proc "c" (user_data: rawptr),
|
user_proc: rawptr, // contains a pointer to a proc "c" (user_data: rawptr, ...)
|
||||||
user_data: rawptr,
|
user_data: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,36 +60,61 @@ global_block_descriptor := Block_Descriptor{
|
|||||||
|
|
||||||
foreign import libSystem "system:System.framework"
|
foreign import libSystem "system:System.framework"
|
||||||
foreign libSystem {
|
foreign libSystem {
|
||||||
_NSConcreteGlobalBlock: ^intrinsics.objc_class
|
_NSConcreteGlobalBlock: intrinsics.objc_class
|
||||||
|
_NSConcreteStackBlock: intrinsics.objc_class
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private="file")
|
@(private="file")
|
||||||
Block_createInternal :: proc "c" (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block {
|
internal_block_literal_make :: proc (is_global: bool, user_data: rawptr, user_proc: rawptr, invoke: rawptr, allocator: mem.Allocator) -> (b: ^Block, err: mem.Allocator_Error) {
|
||||||
// Set to true on blocks that have captures (and thus are not true
|
_init :: proc(bl: ^Internal_Block_Literal, is_global: bool, user_data: rawptr, user_proc: rawptr, invoke: rawptr) {
|
||||||
// global blocks) but are known not to escape for various other
|
// Set to true on blocks that have captures (and thus are not true
|
||||||
// reasons. For backward compatibility with old runtimes, whenever
|
// global blocks) but are known not to escape for various other
|
||||||
// BLOCK_IS_NOESCAPE is set, BLOCK_IS_GLOBAL is set too. Copying a
|
// reasons. For backward compatibility with old runtimes, whenever
|
||||||
// non-escaping block returns the original block and releasing such a
|
// BLOCK_IS_NOESCAPE is set, BLOCK_IS_GLOBAL is set too. Copying a
|
||||||
// block is a no-op, which is exactly how global blocks are handled.
|
// non-escaping block returns the original block and releasing such a
|
||||||
BLOCK_IS_NOESCAPE :: (1 << 23)|BLOCK_IS_GLOBAL
|
// block is a no-op, which is exactly how global blocks are handled.
|
||||||
|
BLOCK_IS_NOESCAPE :: (1 << 23)|BLOCK_IS_GLOBAL
|
||||||
|
|
||||||
BLOCK_HAS_COPY_DISPOSE :: 1 << 25
|
BLOCK_HAS_COPY_DISPOSE :: 1 << 25
|
||||||
BLOCK_HAS_CTOR :: 1 << 26 // helpers have C++ code
|
BLOCK_HAS_CTOR :: 1 << 26 // helpers have C++ code
|
||||||
BLOCK_IS_GLOBAL :: 1 << 28
|
BLOCK_IS_GLOBAL :: 1 << 28
|
||||||
BLOCK_HAS_STRET :: 1 << 29 // IFF BLOCK_HAS_SIGNATURE
|
BLOCK_HAS_STRET :: 1 << 29 // IFF BLOCK_HAS_SIGNATURE
|
||||||
BLOCK_HAS_SIGNATURE :: 1 << 30
|
BLOCK_HAS_SIGNATURE :: 1 << 30
|
||||||
|
|
||||||
extraBytes :: size_of(Internal_Block_Literal) - size_of(Internal_Block_Literal_Base)
|
bl.isa = is_global ? &_NSConcreteGlobalBlock : &_NSConcreteStackBlock
|
||||||
|
bl.flags = BLOCK_IS_GLOBAL if is_global else 0
|
||||||
bl := (^Internal_Block_Literal)(AllocateObject(_NSConcreteGlobalBlock, extraBytes, nil))
|
bl.invoke = invoke
|
||||||
bl.isa = _NSConcreteGlobalBlock
|
bl.descriptor = &global_block_descriptor
|
||||||
bl.flags = BLOCK_IS_GLOBAL if is_global else 0
|
bl.user_proc = auto_cast user_proc
|
||||||
bl.invoke = proc "c" (bl: ^Internal_Block_Literal) {
|
bl.user_data = user_data
|
||||||
bl.user_proc(bl.user_data)
|
}
|
||||||
|
if is_global {
|
||||||
|
bl := builtin.new (Internal_Block_Literal, allocator) or_return
|
||||||
|
_init(bl, true, user_data, user_proc, invoke)
|
||||||
|
return auto_cast bl, .None
|
||||||
|
} else {
|
||||||
|
// malloc blocks are created by calling 'copy' on a stack block
|
||||||
|
bl: Internal_Block_Literal
|
||||||
|
_init(&bl, false, user_data, user_proc, invoke)
|
||||||
|
return auto_cast copy(cast(^Copying(Block))(&bl)), .None
|
||||||
}
|
}
|
||||||
bl.descriptor = &global_block_descriptor
|
|
||||||
bl.user_proc = user_proc
|
|
||||||
bl.user_data = user_data
|
|
||||||
|
|
||||||
return auto_cast bl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
Block_createInternal :: proc (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr), allocator: mem.Allocator) -> (b: ^Block, err: mem.Allocator_Error) {
|
||||||
|
invoke :: proc "c" (bl: ^Internal_Block_Literal) {
|
||||||
|
user_proc := (proc "c" (rawptr))(bl.user_proc)
|
||||||
|
user_proc(bl.user_data)
|
||||||
|
}
|
||||||
|
return internal_block_literal_make(is_global, user_data, auto_cast user_proc, auto_cast invoke, allocator)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
Block_createInternalWithParam :: proc (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr, t: $T), allocator: mem.Allocator) -> (b: ^Block, err: mem.Allocator_Error) {
|
||||||
|
invoke :: proc "c" (bl: ^Internal_Block_Literal, t: T) {
|
||||||
|
user_proc := (proc "c" (rawptr, T))(bl.user_proc)
|
||||||
|
user_proc(bl.user_data, t)
|
||||||
|
}
|
||||||
|
return internal_block_literal_make(is_global, user_data, auto_cast user_proc, auto_cast invoke, allocator)
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user