objc_helper.odin 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package objc_Foundation
  2. import "base:runtime"
  3. import "base:intrinsics"
  4. Subclasser_Proc :: proc(cls: Class, vtable: rawptr)
  5. Object_VTable_Info :: struct {
  6. vtable: rawptr,
  7. size: uint,
  8. impl: Subclasser_Proc,
  9. }
  10. Class_VTable_Info :: struct {
  11. _context: runtime.Context,
  12. super_vtable: rawptr,
  13. protocol_vtable: rawptr,
  14. }
  15. @(require_results)
  16. class_get_metaclass :: #force_inline proc "contextless" (cls: Class) -> Class {
  17. return (^Class)(cls)^
  18. }
  19. @(require_results)
  20. object_get_vtable_info :: proc "contextless" (obj: id) -> ^Class_VTable_Info {
  21. return (^Class_VTable_Info)(object_getIndexedIvars(obj))
  22. }
  23. @(require_results)
  24. make_subclasser :: #force_inline proc(vtable: ^$T, impl: proc(cls: Class, vt: ^T)) -> Object_VTable_Info {
  25. return Object_VTable_Info{
  26. vtable = vtable,
  27. size = size_of(T),
  28. impl = (Subclasser_Proc)(impl),
  29. }
  30. }
  31. @(require_results)
  32. register_subclass :: proc(
  33. class_name: cstring,
  34. superclass: Class,
  35. superclass_overrides: Maybe(Object_VTable_Info) = nil,
  36. protocol: Maybe(Object_VTable_Info) = nil,
  37. _context: Maybe(runtime.Context) = nil,
  38. ) -> Class {
  39. assert(superclass != nil)
  40. super_size: uint
  41. proto_size: uint
  42. if superclass_overrides != nil {
  43. // Align to 8-byte boundary
  44. super_size = (superclass_overrides.?.size + 7)/8 * 8
  45. }
  46. if protocol != nil {
  47. // Align to 8-byte boundary
  48. proto_size = (protocol.?.size + 7)/8 * 8
  49. }
  50. cls := objc_lookUpClass(class_name)
  51. if cls != nil {
  52. return cls
  53. }
  54. extra_size := uint(size_of(Class_VTable_Info)) + 8 + super_size + proto_size
  55. cls = objc_allocateClassPair(superclass, class_name, extra_size)
  56. assert(cls != nil)
  57. if s, ok := superclass_overrides.?; ok {
  58. s.impl(cls, s.vtable)
  59. }
  60. if p, ok := protocol.?; ok {
  61. p.impl(cls, p.vtable)
  62. }
  63. objc_registerClassPair(cls)
  64. meta_cls := class_get_metaclass(cls)
  65. meta_size := uint(class_getInstanceSize(meta_cls))
  66. // Offsets are always aligned to 8-byte boundary
  67. info_offset := (meta_size + 7) / 8 * 8
  68. super_vtable_offset := (info_offset + size_of(Class_VTable_Info) + 7) / 8 * 8
  69. ptoto_vtable_offset := super_vtable_offset + super_size
  70. p_info := (^Class_VTable_Info)(([^]u8)(cls)[info_offset:])
  71. p_super_vtable := ([^]u8)(cls)[super_vtable_offset:]
  72. p_proto_vtable := ([^]u8)(cls)[ptoto_vtable_offset:]
  73. intrinsics.mem_zero(p_info, size_of(Class_VTable_Info))
  74. // Assign the context
  75. p_info._context = _context.? or_else context
  76. if s, ok := superclass_overrides.?; ok {
  77. p_info.super_vtable = p_super_vtable
  78. intrinsics.mem_copy(p_super_vtable, s.vtable, super_size)
  79. }
  80. if p, ok := protocol.?; ok {
  81. p_info.protocol_vtable = p_proto_vtable
  82. intrinsics.mem_copy(p_proto_vtable, p.vtable, p.size)
  83. }
  84. return cls
  85. }
  86. @(require_results)
  87. class_get_vtable_info :: proc "contextless" (cls: Class) -> ^Class_VTable_Info {
  88. meta_cls := class_get_metaclass(cls)
  89. meta_size := uint(class_getInstanceSize(meta_cls))
  90. // Align to 8-byte boundary
  91. info_offset := (meta_size+7) / 8 * 8
  92. p_cls := ([^]u8)(cls)[info_offset:]
  93. ctx := (^Class_VTable_Info)(p_cls)
  94. return ctx
  95. }
  96. @(require_results)
  97. alloc_user_object :: proc "contextless" (cls: Class, _context: Maybe(runtime.Context) = nil) -> id {
  98. info := class_get_vtable_info(cls)
  99. obj := class_createInstance(cls, size_of(Class_VTable_Info))
  100. obj_info := (^Class_VTable_Info)(object_getIndexedIvars(obj))
  101. obj_info^ = info^
  102. if _context != nil {
  103. obj_info._context = _context.?
  104. }
  105. return obj
  106. }