koffi 1.3.12 → 2.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CMakeLists.txt +8 -10
  2. package/ChangeLog.md +48 -16
  3. package/README.md +6 -0
  4. package/benchmark/atoi_koffi.js +12 -8
  5. package/benchmark/atoi_napi.js +12 -8
  6. package/benchmark/atoi_node_ffi.js +11 -10
  7. package/benchmark/raylib_cc.cc +12 -9
  8. package/benchmark/raylib_koffi.js +15 -13
  9. package/benchmark/raylib_node_ffi.js +15 -13
  10. package/benchmark/raylib_node_raylib.js +14 -11
  11. package/build/qemu/2.1.0-beta.1/koffi_darwin_arm64.tar.gz +0 -0
  12. package/build/qemu/2.1.0-beta.1/koffi_darwin_x64.tar.gz +0 -0
  13. package/build/qemu/2.1.0-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
  14. package/build/qemu/2.1.0-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
  15. package/build/qemu/2.1.0-beta.1/koffi_freebsd_x64.tar.gz +0 -0
  16. package/build/qemu/2.1.0-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
  17. package/build/qemu/2.1.0-beta.1/koffi_linux_arm64.tar.gz +0 -0
  18. package/build/qemu/2.1.0-beta.1/koffi_linux_ia32.tar.gz +0 -0
  19. package/build/qemu/2.1.0-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  20. package/build/qemu/2.1.0-beta.1/koffi_linux_x64.tar.gz +0 -0
  21. package/build/qemu/2.1.0-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
  22. package/build/qemu/2.1.0-beta.1/koffi_openbsd_x64.tar.gz +0 -0
  23. package/build/qemu/2.1.0-beta.1/koffi_win32_arm64.tar.gz +0 -0
  24. package/build/qemu/2.1.0-beta.1/koffi_win32_ia32.tar.gz +0 -0
  25. package/build/qemu/2.1.0-beta.1/koffi_win32_x64.tar.gz +0 -0
  26. package/doc/changes.md +160 -1
  27. package/doc/conf.py +14 -1
  28. package/doc/contribute.md +0 -1
  29. package/doc/dist/doctrees/benchmarks.doctree +0 -0
  30. package/doc/dist/doctrees/changes.doctree +0 -0
  31. package/doc/dist/doctrees/environment.pickle +0 -0
  32. package/doc/dist/doctrees/functions.doctree +0 -0
  33. package/doc/dist/doctrees/index.doctree +0 -0
  34. package/doc/dist/doctrees/types.doctree +0 -0
  35. package/doc/dist/html/.buildinfo +1 -1
  36. package/doc/dist/html/_sources/benchmarks.md.txt +2 -2
  37. package/doc/dist/html/_sources/changes.md.txt +160 -1
  38. package/doc/dist/html/_sources/functions.md.txt +17 -13
  39. package/doc/dist/html/_sources/types.md.txt +87 -35
  40. package/doc/dist/html/benchmarks.html +7 -3
  41. package/doc/dist/html/changes.html +241 -14
  42. package/doc/dist/html/contribute.html +5 -1
  43. package/doc/dist/html/functions.html +30 -23
  44. package/doc/dist/html/genindex.html +5 -1
  45. package/doc/dist/html/index.html +13 -19
  46. package/doc/dist/html/memory.html +7 -3
  47. package/doc/dist/html/objects.inv +0 -0
  48. package/doc/dist/html/platforms.html +6 -2
  49. package/doc/dist/html/search.html +5 -1
  50. package/doc/dist/html/searchindex.js +1 -1
  51. package/doc/dist/html/start.html +5 -1
  52. package/doc/dist/html/types.html +104 -43
  53. package/doc/functions.md +139 -15
  54. package/doc/templates/badges.html +5 -0
  55. package/doc/types.md +108 -40
  56. package/package.json +2 -2
  57. package/qemu/qemu.js +1 -1
  58. package/qemu/registry/machines.json +5 -5
  59. package/qemu/registry/sha256sum.txt +16 -16
  60. package/src/abi_arm32.cc +91 -19
  61. package/src/abi_arm32_fwd.S +121 -57
  62. package/src/abi_arm64.cc +91 -19
  63. package/src/abi_arm64_fwd.S +96 -0
  64. package/src/abi_arm64_fwd.asm +128 -0
  65. package/src/abi_riscv64.cc +89 -19
  66. package/src/abi_riscv64_fwd.S +96 -0
  67. package/src/abi_x64_sysv.cc +94 -22
  68. package/src/abi_x64_sysv_fwd.S +96 -0
  69. package/src/abi_x64_win.cc +89 -19
  70. package/src/abi_x64_win_fwd.asm +128 -0
  71. package/src/abi_x86.cc +94 -19
  72. package/src/abi_x86_fwd.S +96 -0
  73. package/src/abi_x86_fwd.asm +128 -0
  74. package/src/call.cc +128 -78
  75. package/src/call.hh +17 -4
  76. package/src/ffi.cc +514 -145
  77. package/src/ffi.hh +30 -9
  78. package/src/index.js +4 -2
  79. package/src/parser.cc +19 -44
  80. package/src/util.cc +160 -27
  81. package/src/util.hh +7 -2
  82. package/test/async.js +1 -2
  83. package/test/callbacks.js +56 -11
  84. package/test/misc.c +50 -15
  85. package/test/raylib.js +2 -2
  86. package/test/sqlite.js +27 -19
  87. package/test/sync.js +71 -35
  88. package/vendor/libcc/libcc.cc +18 -5
  89. package/vendor/libcc/libcc.hh +70 -23
  90. package/build/qemu/1.3.12/koffi_darwin_arm64.tar.gz +0 -0
  91. package/build/qemu/1.3.12/koffi_darwin_x64.tar.gz +0 -0
  92. package/build/qemu/1.3.12/koffi_freebsd_arm64.tar.gz +0 -0
  93. package/build/qemu/1.3.12/koffi_freebsd_ia32.tar.gz +0 -0
  94. package/build/qemu/1.3.12/koffi_freebsd_x64.tar.gz +0 -0
  95. package/build/qemu/1.3.12/koffi_linux_arm32hf.tar.gz +0 -0
  96. package/build/qemu/1.3.12/koffi_linux_arm64.tar.gz +0 -0
  97. package/build/qemu/1.3.12/koffi_linux_ia32.tar.gz +0 -0
  98. package/build/qemu/1.3.12/koffi_linux_riscv64hf64.tar.gz +0 -0
  99. package/build/qemu/1.3.12/koffi_linux_x64.tar.gz +0 -0
  100. package/build/qemu/1.3.12/koffi_openbsd_ia32.tar.gz +0 -0
  101. package/build/qemu/1.3.12/koffi_openbsd_x64.tar.gz +0 -0
  102. package/build/qemu/1.3.12/koffi_win32_arm64.tar.gz +0 -0
  103. package/build/qemu/1.3.12/koffi_win32_ia32.tar.gz +0 -0
  104. package/build/qemu/1.3.12/koffi_win32_x64.tar.gz +0 -0
package/src/call.cc CHANGED
@@ -40,7 +40,7 @@ CallData::~CallData()
40
40
  mem->stack = old_stack_mem;
41
41
  mem->heap = old_heap_mem;
42
42
 
43
- instance->free_trampolines |= used_trampolines;
43
+ instance->temp_trampolines -= used_trampolines;
44
44
  instance->temporaries -= mem->temporary;
45
45
 
46
46
  if (!--mem->depth && mem->temporary) {
@@ -127,9 +127,8 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
127
127
  RG_ASSERT(IsObject(obj));
128
128
  RG_ASSERT(type->primitive == PrimitiveKind::Record);
129
129
 
130
- Size offset = 0;
131
-
132
- for (const RecordMember &member: type->members) {
130
+ for (Size i = 0; i < type->members.len; i++) {
131
+ const RecordMember &member = type->members[i];
133
132
  Napi::Value value = obj.Get(member.name);
134
133
 
135
134
  if (RG_UNLIKELY(value.IsUndefined())) {
@@ -137,9 +136,7 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
137
136
  return false;
138
137
  }
139
138
 
140
- int16_t align = std::max(member.align, realign);
141
- offset = AlignLen(offset, align);
142
-
139
+ Size offset = realign ? (i * realign) : member.offset;
143
140
  uint8_t *dest = origin + offset;
144
141
 
145
142
  switch (member.type->primitive) {
@@ -257,7 +254,7 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
257
254
  *(const char16_t **)dest = str16;
258
255
  } break;
259
256
  case PrimitiveKind::Pointer: {
260
- if (CheckValueTag(instance, value, member.type)) {
257
+ if (CheckValueTag(instance, value, member.type->ref.marker)) {
261
258
  Napi::External<void> external = value.As<Napi::External<void>>();
262
259
  void *ptr = external.Data();
263
260
  *(void **)dest = ptr;
@@ -281,15 +278,15 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
281
278
  case PrimitiveKind::Array: {
282
279
  if (value.IsArray()) {
283
280
  Napi::Array array = value.As<Napi::Array>();
284
- Size len = (Size)member.type->size / member.type->ref->size;
281
+ Size len = (Size)member.type->size / member.type->ref.type->size;
285
282
 
286
- if (!PushNormalArray(array, len, member.type->ref, dest, realign))
283
+ if (!PushNormalArray(array, len, member.type->ref.type, dest, realign))
287
284
  return false;
288
285
  } else if (value.IsTypedArray()) {
289
286
  Napi::TypedArray array = value.As<Napi::TypedArray>();
290
- Size len = (Size)member.type->size / member.type->ref->size;
287
+ Size len = (Size)member.type->size / member.type->ref.type->size;
291
288
 
292
- if (!PushTypedArray(array, len, member.type->ref, dest, realign))
289
+ if (!PushTypedArray(array, len, member.type->ref.type, dest, realign))
293
290
  return false;
294
291
  } else if (value.IsString() && !realign) {
295
292
  if (!PushStringArray(value, member.type, dest))
@@ -323,10 +320,10 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
323
320
  if (value.IsFunction()) {
324
321
  Napi::Function func = value.As<Napi::Function>();
325
322
 
326
- ptr = ReserveTrampoline(member.type->proto, func);
323
+ ptr = ReserveTrampoline(member.type->ref.proto, func);
327
324
  if (RG_UNLIKELY(!ptr))
328
325
  return false;
329
- } else if (CheckValueTag(instance, value, member.type)) {
326
+ } else if (CheckValueTag(instance, value, member.type->ref.marker)) {
330
327
  Napi::External<void> external = value.As<Napi::External<void>>();
331
328
  ptr = external.Data();
332
329
  } else if (IsNullOrUndefined(value)) {
@@ -338,9 +335,9 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
338
335
 
339
336
  *(void **)dest = ptr;
340
337
  } break;
341
- }
342
338
 
343
- offset += member.type->size;
339
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
340
+ }
344
341
  }
345
342
 
346
343
  return true;
@@ -460,7 +457,7 @@ bool CallData::PushNormalArray(Napi::Array array, Size len, const TypeInfo *ref,
460
457
  });
461
458
  } break;
462
459
  case PrimitiveKind::Pointer: {
463
- PUSH_ARRAY(CheckValueTag(instance, value, ref) || IsNullOrUndefined(value), ref->name, {
460
+ PUSH_ARRAY(CheckValueTag(instance, value, ref->ref.marker) || IsNullOrUndefined(value), ref->name, {
464
461
  if (!IsNullOrUndefined(value)) {
465
462
  Napi::External<void> external = value.As<Napi::External<void>>();
466
463
  *(void **)dest = external.Data();
@@ -487,15 +484,15 @@ bool CallData::PushNormalArray(Napi::Array array, Size len, const TypeInfo *ref,
487
484
 
488
485
  if (value.IsArray()) {
489
486
  Napi::Array array2 = value.As<Napi::Array>();
490
- Size len2 = (Size)ref->size / ref->ref->size;
487
+ Size len2 = (Size)ref->size / ref->ref.type->size;
491
488
 
492
- if (!PushNormalArray(array2, len2, ref->ref, dest, realign))
489
+ if (!PushNormalArray(array2, len2, ref->ref.type, dest, realign))
493
490
  return false;
494
491
  } else if (value.IsTypedArray()) {
495
492
  Napi::TypedArray array2 = value.As<Napi::TypedArray>();
496
- Size len2 = (Size)ref->size / ref->ref->size;
493
+ Size len2 = (Size)ref->size / ref->ref.type->size;
497
494
 
498
- if (!PushTypedArray(array2, len2, ref->ref, dest, realign))
495
+ if (!PushTypedArray(array2, len2, ref->ref.type, dest, realign))
499
496
  return false;
500
497
  } else if (value.IsString() && !realign) {
501
498
  if (!PushStringArray(value, ref, dest))
@@ -534,10 +531,10 @@ bool CallData::PushNormalArray(Napi::Array array, Size len, const TypeInfo *ref,
534
531
  if (value.IsFunction()) {
535
532
  Napi::Function func = value.As<Napi::Function>();
536
533
 
537
- ptr = ReserveTrampoline(ref->proto, func);
534
+ ptr = ReserveTrampoline(ref->ref.proto, func);
538
535
  if (RG_UNLIKELY(!ptr))
539
536
  return false;
540
- } else if (CheckValueTag(instance, value, ref)) {
537
+ } else if (CheckValueTag(instance, value, ref->ref.marker)) {
541
538
  Napi::External<void> external = value.As<Napi::External<void>>();
542
539
  ptr = external.Data();
543
540
  } else if (IsNullOrUndefined(value)) {
@@ -552,6 +549,8 @@ bool CallData::PushNormalArray(Napi::Array array, Size len, const TypeInfo *ref,
552
549
  offset += ref->size;
553
550
  }
554
551
  } break;
552
+
553
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
555
554
  }
556
555
 
557
556
  #undef PUSH_ARRAY
@@ -568,24 +567,26 @@ bool CallData::PushTypedArray(Napi::TypedArray array, Size len, const TypeInfo *
568
567
  return false;
569
568
  }
570
569
 
571
- Size offset = 0;
572
570
  const uint8_t *buf = (const uint8_t *)array.ArrayBuffer().Data();
573
571
 
574
- if (RG_UNLIKELY(array.TypedArrayType() != GetTypedArrayType(ref))) {
572
+ if (RG_UNLIKELY(array.TypedArrayType() != GetTypedArrayType(ref) &&
573
+ ref != instance->void_type)) {
575
574
  ThrowError<Napi::TypeError>(env, "Cannot use %1 value for %2 array", GetValueType(instance, array), ref->name);
576
575
  return false;
577
576
  }
578
577
 
579
578
  if (realign) {
579
+ Size offset = 0;
580
+ Size size = (Size)array.ElementSize();
581
+
580
582
  for (uint32_t i = 0; i < len; i++) {
581
- int16_t align = std::max(ref->align, realign);
582
- offset = AlignLen(offset, align);
583
+ offset = AlignLen(offset, realign);
583
584
 
584
585
  uint8_t *dest = origin + offset;
586
+ const uint8_t *src = buf + i * size;
585
587
 
586
- memcpy(dest, buf + i * ref->size, ref->size);
587
-
588
- offset += ref->size;
588
+ memcpy(dest, src, size);
589
+ offset += size;
589
590
  }
590
591
  } else {
591
592
  memcpy_safe(origin, buf, (size_t)array.ByteLength());
@@ -601,7 +602,7 @@ bool CallData::PushStringArray(Napi::Value obj, const TypeInfo *type, uint8_t *o
601
602
 
602
603
  size_t encoded = 0;
603
604
 
604
- switch (type->ref->primitive) {
605
+ switch (type->ref.type->primitive) {
605
606
  case PrimitiveKind::Int8: {
606
607
  napi_status status = napi_get_value_string_utf8(env, obj, (char *)origin, type->size, &encoded);
607
608
  RG_ASSERT(status == napi_ok);
@@ -614,7 +615,7 @@ bool CallData::PushStringArray(Napi::Value obj, const TypeInfo *type, uint8_t *o
614
615
  } break;
615
616
 
616
617
  default: {
617
- ThrowError<Napi::TypeError>(env, "Strings cannot be converted to %1 array", type->ref->name);
618
+ ThrowError<Napi::TypeError>(env, "Strings cannot be converted to %1 array", type->ref.type->name);
618
619
  return false;
619
620
  } break;
620
621
  }
@@ -626,6 +627,16 @@ bool CallData::PushStringArray(Napi::Value obj, const TypeInfo *type, uint8_t *o
626
627
 
627
628
  bool CallData::PushPointer(Napi::Value value, const ParameterInfo &param, void **out_ptr)
628
629
  {
630
+ const TypeInfo *type = param.type;
631
+
632
+ if (CheckValueTag(instance, value, &CastMarker)) {
633
+ Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
634
+ ValueCast *cast = external.Data();
635
+
636
+ value = cast->ref.Value();
637
+ type = cast->type;
638
+ }
639
+
629
640
  switch (value.Type()) {
630
641
  case napi_undefined:
631
642
  case napi_null: {
@@ -634,7 +645,11 @@ bool CallData::PushPointer(Napi::Value value, const ParameterInfo &param, void *
634
645
  } break;
635
646
 
636
647
  case napi_external: {
637
- if (RG_UNLIKELY(!CheckValueTag(instance, value, param.type)))
648
+ RG_ASSERT(type->primitive == PrimitiveKind::Pointer);
649
+
650
+ if (RG_UNLIKELY(!CheckValueTag(instance, value, type->ref.marker) &&
651
+ !CheckValueTag(instance, value, instance->void_type) &&
652
+ type->ref.type != instance->void_type))
638
653
  goto unexpected;
639
654
 
640
655
  *out_ptr = value.As<Napi::External<uint8_t>>().Data();
@@ -648,12 +663,12 @@ bool CallData::PushPointer(Napi::Value value, const ParameterInfo &param, void *
648
663
  Napi::Array array = value.As<Napi::Array>();
649
664
 
650
665
  Size len = (Size)array.Length();
651
- Size size = len * param.type->ref->size;
666
+ Size size = len * type->ref.type->size;
652
667
 
653
668
  ptr = AllocHeap(size, 16);
654
669
 
655
670
  if (param.directions & 1) {
656
- if (!PushNormalArray(array, len, param.type->ref, ptr))
671
+ if (!PushNormalArray(array, len, type->ref.type, ptr))
657
672
  return false;
658
673
  } else {
659
674
  memset(ptr, 0, size);
@@ -667,27 +682,28 @@ bool CallData::PushPointer(Napi::Value value, const ParameterInfo &param, void *
667
682
  ptr = AllocHeap(size, 16);
668
683
 
669
684
  if (param.directions & 1) {
670
- if (!PushTypedArray(array, len, param.type->ref, ptr))
685
+ if (!PushTypedArray(array, len, type->ref.type, ptr))
671
686
  return false;
672
687
  } else {
673
- if (RG_UNLIKELY(array.TypedArrayType() != GetTypedArrayType(param.type->ref))) {
674
- ThrowError<Napi::TypeError>(env, "Cannot use %1 value for %2 array", GetValueType(instance, array), param.type->ref->name);
688
+ if (RG_UNLIKELY(array.TypedArrayType() != GetTypedArrayType(type->ref.type) &&
689
+ type->ref.type != instance->void_type)) {
690
+ ThrowError<Napi::TypeError>(env, "Cannot use %1 value for %2 array", GetValueType(instance, array), type->ref.type->name);
675
691
  return false;
676
692
  }
677
693
 
678
694
  memset(ptr, 0, size);
679
695
  }
680
- } else if (RG_LIKELY(param.type->ref->primitive == PrimitiveKind::Record)) {
696
+ } else if (RG_LIKELY(type->ref.type->primitive == PrimitiveKind::Record)) {
681
697
  Napi::Object obj = value.As<Napi::Object>();
682
698
  RG_ASSERT(IsObject(value));
683
699
 
684
- ptr = AllocHeap(param.type->ref->size, 16);
700
+ ptr = AllocHeap(type->ref.type->size, 16);
685
701
 
686
702
  if (param.directions & 1) {
687
- if (!PushObject(obj, param.type->ref, ptr))
703
+ if (!PushObject(obj, type->ref.type, ptr))
688
704
  return false;
689
705
  } else {
690
- memset(ptr, 0, param.type->size);
706
+ memset(ptr, 0, type->size);
691
707
  }
692
708
  } else {
693
709
  goto unexpected;
@@ -700,7 +716,7 @@ bool CallData::PushPointer(Napi::Value value, const ParameterInfo &param, void *
700
716
  RG_ASSERT(status == napi_ok);
701
717
 
702
718
  out->ptr = ptr;
703
- out->type = param.type->ref;
719
+ out->type = type->ref.type;
704
720
  }
705
721
 
706
722
  *out_ptr = ptr;
@@ -711,7 +727,7 @@ bool CallData::PushPointer(Napi::Value value, const ParameterInfo &param, void *
711
727
  }
712
728
 
713
729
  unexpected:
714
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), param.offset + 1, param.type->name);
730
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), param.offset + 1, type->name);
715
731
  return false;
716
732
  }
717
733
 
@@ -741,27 +757,34 @@ void CallData::PopOutArguments()
741
757
  Napi::Object obj(env, value);
742
758
  PopObject(obj, out.ptr, out.type);
743
759
  }
760
+
761
+ if (out.type->dispose) {
762
+ out.type->dispose(env, out.type, out.ptr);
763
+ }
744
764
  }
745
765
  }
746
766
 
747
767
  void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func)
748
768
  {
749
- uint32_t idx = CountTrailingZeros(instance->free_trampolines);
750
-
751
- if (RG_UNLIKELY(idx >= MaxTrampolines)) {
752
- ThrowError<Napi::Error>(env, "Too many callbacks are in use (max = %1)", MaxTrampolines);
769
+ if (RG_UNLIKELY(instance->temp_trampolines >= MaxTrampolines)) {
770
+ ThrowError<Napi::Error>(env, "Too many temporary callbacks are in use (max = %1)", MaxTrampolines);
753
771
  return nullptr;
754
772
  }
755
773
 
756
- instance->free_trampolines &= ~(1u << idx);
757
- used_trampolines |= 1u << idx;
774
+ int idx = instance->next_trampoline;
775
+
776
+ instance->next_trampoline = (int16_t)((instance->next_trampoline + 1) % MaxTrampolines);
777
+ instance->temp_trampolines++;
778
+ used_trampolines++;
758
779
 
759
- instance->trampolines[idx].proto = proto;
760
- instance->trampolines[idx].func.Reset(func, 1);
761
- instance->trampolines[idx].generation = mem->generation;
780
+ TrampolineInfo *trampoline = &instance->trampolines[idx];
762
781
 
763
- void *trampoline = GetTrampoline(idx, proto);
764
- return trampoline;
782
+ trampoline->proto = proto;
783
+ trampoline->func.Reset(func, 1);
784
+ trampoline->generation = (int32_t)mem->generation;
785
+
786
+ void *ptr = GetTrampoline(idx, proto);
787
+ return ptr;
765
788
  }
766
789
 
767
790
  void CallData::PopObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type, int16_t realign)
@@ -771,12 +794,10 @@ void CallData::PopObject(Napi::Object obj, const uint8_t *origin, const TypeInfo
771
794
 
772
795
  RG_ASSERT(type->primitive == PrimitiveKind::Record);
773
796
 
774
- Size offset = 0;
775
-
776
- for (const RecordMember &member: type->members) {
777
- int16_t align = std::max(realign, member.align);
778
- offset = AlignLen(offset, align);
797
+ for (Size i = 0; i < type->members.len; i++) {
798
+ const RecordMember &member = type->members[i];
779
799
 
800
+ Size offset = realign ? (i * realign) : member.offset;
780
801
  const uint8_t *src = origin + offset;
781
802
 
782
803
  switch (member.type->primitive) {
@@ -821,10 +842,18 @@ void CallData::PopObject(Napi::Object obj, const uint8_t *origin, const TypeInfo
821
842
  case PrimitiveKind::String: {
822
843
  const char *str = *(const char **)src;
823
844
  obj.Set(member.name, str ? Napi::String::New(env, str) : env.Null());
845
+
846
+ if (member.type->dispose) {
847
+ member.type->dispose(env, member.type, str);
848
+ }
824
849
  } break;
825
850
  case PrimitiveKind::String16: {
826
851
  const char16_t *str16 = *(const char16_t **)src;
827
852
  obj.Set(member.name, str16 ? Napi::String::New(env, str16) : env.Null());
853
+
854
+ if (member.type->dispose) {
855
+ member.type->dispose(env, member.type, str16);
856
+ }
828
857
  } break;
829
858
  case PrimitiveKind::Pointer:
830
859
  case PrimitiveKind::Callback: {
@@ -832,12 +861,16 @@ void CallData::PopObject(Napi::Object obj, const uint8_t *origin, const TypeInfo
832
861
 
833
862
  if (ptr2) {
834
863
  Napi::External<void> external = Napi::External<void>::New(env, ptr2);
835
- SetValueTag(instance, external, member.type);
864
+ SetValueTag(instance, external, member.type->ref.marker);
836
865
 
837
866
  obj.Set(member.name, external);
838
867
  } else {
839
868
  obj.Set(member.name, env.Null());
840
869
  }
870
+
871
+ if (member.type->dispose) {
872
+ member.type->dispose(env, member.type, ptr2);
873
+ }
841
874
  } break;
842
875
  case PrimitiveKind::Record: {
843
876
  Napi::Object obj2 = PopObject(src, member.type, realign);
@@ -855,9 +888,9 @@ void CallData::PopObject(Napi::Object obj, const uint8_t *origin, const TypeInfo
855
888
  double d = *(double *)src;
856
889
  obj.Set(member.name, Napi::Number::New(env, d));
857
890
  } break;
858
- }
859
891
 
860
- offset += member.type->size;
892
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
893
+ }
861
894
  }
862
895
  }
863
896
 
@@ -938,12 +971,20 @@ void CallData::PopNormalArray(Napi::Array array, const uint8_t *origin, const Ty
938
971
  POP_ARRAY({
939
972
  const char *str = *(const char **)src;
940
973
  array.Set(i, str ? Napi::String::New(env, str) : env.Null());
974
+
975
+ if (ref->dispose) {
976
+ ref->dispose(env, ref, str);
977
+ }
941
978
  });
942
979
  } break;
943
980
  case PrimitiveKind::String16: {
944
981
  POP_ARRAY({
945
982
  const char16_t *str16 = *(const char16_t **)src;
946
983
  array.Set(i, str16 ? Napi::String::New(env, str16) : env.Null());
984
+
985
+ if (ref->dispose) {
986
+ ref->dispose(env, ref, str16);
987
+ }
947
988
  });
948
989
  } break;
949
990
  case PrimitiveKind::Pointer:
@@ -953,12 +994,16 @@ void CallData::PopNormalArray(Napi::Array array, const uint8_t *origin, const Ty
953
994
 
954
995
  if (ptr2) {
955
996
  Napi::External<void> external = Napi::External<void>::New(env, ptr2);
956
- SetValueTag(instance, external, ref);
997
+ SetValueTag(instance, external, ref->ref.marker);
957
998
 
958
999
  array.Set(i, external);
959
1000
  } else {
960
1001
  array.Set(i, env.Null());
961
1002
  }
1003
+
1004
+ if (ref->dispose) {
1005
+ ref->dispose(env, ref, ptr2);
1006
+ }
962
1007
  });
963
1008
  } break;
964
1009
  case PrimitiveKind::Record: {
@@ -975,6 +1020,8 @@ void CallData::PopNormalArray(Napi::Array array, const uint8_t *origin, const Ty
975
1020
  } break;
976
1021
  case PrimitiveKind::Float32: { POP_NUMBER_ARRAY(float); } break;
977
1022
  case PrimitiveKind::Float64: { POP_NUMBER_ARRAY(double); } break;
1023
+
1024
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
978
1025
  }
979
1026
 
980
1027
  #undef POP_NUMBER_ARRAY
@@ -984,24 +1031,25 @@ void CallData::PopNormalArray(Napi::Array array, const uint8_t *origin, const Ty
984
1031
  void CallData::PopTypedArray(Napi::TypedArray array, const uint8_t *origin, const TypeInfo *ref, int16_t realign)
985
1032
  {
986
1033
  RG_ASSERT(array.IsTypedArray());
987
- RG_ASSERT(GetTypedArrayType(ref) == array.TypedArrayType());
1034
+ RG_ASSERT(GetTypedArrayType(ref) == array.TypedArrayType() ||
1035
+ ref == instance->void_type);
988
1036
 
989
1037
  uint8_t *buf = (uint8_t *)array.ArrayBuffer().Data();
990
1038
 
991
1039
  if (realign) {
992
1040
  Size offset = 0;
993
1041
  Size len = (Size)array.ElementLength();
1042
+ Size size = (Size)array.ElementSize();
994
1043
 
995
1044
  for (Size i = 0; i < len; i++) {
996
- int16_t align = std::max(ref->align, realign);
997
- offset = AlignLen(offset, align);
1045
+ offset = AlignLen(offset, realign);
998
1046
 
999
- uint8_t *dest = buf + i * ref->size;
1047
+ uint8_t *dest = buf + i * size;
1000
1048
  const uint8_t *src = origin + offset;
1001
1049
 
1002
- memcpy(dest, src, ref->size);
1050
+ memcpy(dest, src, size);
1003
1051
 
1004
- offset += ref->size;
1052
+ offset += size;
1005
1053
  }
1006
1054
  } else {
1007
1055
  memcpy_safe(buf, origin, (size_t)array.ByteLength());
@@ -1012,7 +1060,7 @@ Napi::Value CallData::PopArray(const uint8_t *origin, const TypeInfo *type, int1
1012
1060
  {
1013
1061
  RG_ASSERT(type->primitive == PrimitiveKind::Array);
1014
1062
 
1015
- uint32_t len = type->size / type->ref->size;
1063
+ uint32_t len = type->size / type->ref.type->size;
1016
1064
  Size offset = 0;
1017
1065
 
1018
1066
  #define POP_ARRAY(SetCode) \
@@ -1020,14 +1068,14 @@ Napi::Value CallData::PopArray(const uint8_t *origin, const TypeInfo *type, int1
1020
1068
  Napi::Array array = Napi::Array::New(env); \
1021
1069
  \
1022
1070
  for (uint32_t i = 0; i < len; i++) { \
1023
- int16_t align = std::max(realign, type->ref->align); \
1071
+ int16_t align = std::max(realign, type->ref.type->align); \
1024
1072
  offset = AlignLen(offset, align); \
1025
1073
  \
1026
1074
  const uint8_t *src = origin + offset; \
1027
1075
  \
1028
1076
  SetCode \
1029
1077
  \
1030
- offset += type->ref->size; \
1078
+ offset += type->ref.type->size; \
1031
1079
  } \
1032
1080
  \
1033
1081
  return array; \
@@ -1041,13 +1089,13 @@ Napi::Value CallData::PopArray(const uint8_t *origin, const TypeInfo *type, int1
1041
1089
  }); \
1042
1090
  } else { \
1043
1091
  Napi::TypedArrayType array = Napi::TypedArrayType::New(env, len); \
1044
- PopTypedArray(array, origin, type->ref, realign); \
1092
+ PopTypedArray(array, origin, type->ref.type, realign); \
1045
1093
  \
1046
1094
  return array; \
1047
1095
  } \
1048
1096
  } while (false)
1049
1097
 
1050
- switch (type->ref->primitive) {
1098
+ switch (type->ref.type->primitive) {
1051
1099
  case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
1052
1100
 
1053
1101
  case PrimitiveKind::Bool: {
@@ -1117,7 +1165,7 @@ Napi::Value CallData::PopArray(const uint8_t *origin, const TypeInfo *type, int1
1117
1165
 
1118
1166
  if (ptr2) {
1119
1167
  Napi::External<void> external = Napi::External<void>::New(env, ptr2);
1120
- SetValueTag(instance, external, type->ref);
1168
+ SetValueTag(instance, external, type->ref.type->ref.marker);
1121
1169
 
1122
1170
  array.Set(i, external);
1123
1171
  } else {
@@ -1127,18 +1175,20 @@ Napi::Value CallData::PopArray(const uint8_t *origin, const TypeInfo *type, int1
1127
1175
  } break;
1128
1176
  case PrimitiveKind::Record: {
1129
1177
  POP_ARRAY({
1130
- Napi::Object obj = PopObject(src, type->ref, realign);
1178
+ Napi::Object obj = PopObject(src, type->ref.type, realign);
1131
1179
  array.Set(i, obj);
1132
1180
  });
1133
1181
  } break;
1134
1182
  case PrimitiveKind::Array: {
1135
1183
  POP_ARRAY({
1136
- Napi::Value value = PopArray(src, type->ref, realign);
1184
+ Napi::Value value = PopArray(src, type->ref.type, realign);
1137
1185
  array.Set(i, value);
1138
1186
  });
1139
1187
  } break;
1140
1188
  case PrimitiveKind::Float32: { POP_NUMBER_ARRAY(Float32Array, float); } break;
1141
1189
  case PrimitiveKind::Float64: { POP_NUMBER_ARRAY(Float64Array, double); } break;
1190
+
1191
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
1142
1192
  }
1143
1193
 
1144
1194
  #undef POP_NUMBER_ARRAY
package/src/call.hh CHANGED
@@ -42,7 +42,7 @@ class alignas(8) CallData {
42
42
  Span<uint8_t> old_stack_mem;
43
43
  Span<uint8_t> old_heap_mem;
44
44
 
45
- uint32_t used_trampolines = 0;
45
+ int16_t used_trampolines = 0;
46
46
 
47
47
  LocalArray<OutArgument, MaxOutParameters> out_arguments;
48
48
 
@@ -71,9 +71,21 @@ public:
71
71
  CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func, InstanceMemory *mem);
72
72
  ~CallData();
73
73
 
74
- bool Prepare(const Napi::CallbackInfo &info);
75
- void Execute();
76
- Napi::Value Complete();
74
+ #ifdef UNITY_BUILD
75
+ #ifdef _MSC_VER
76
+ #define INLINE_IF_UNITY __forceinline
77
+ #else
78
+ #define INLINE_IF_UNITY __attribute__((always_inline)) inline
79
+ #endif
80
+ #else
81
+ #define INLINE_IF_UNITY
82
+ #endif
83
+
84
+ INLINE_IF_UNITY bool Prepare(const Napi::CallbackInfo &info);
85
+ INLINE_IF_UNITY void Execute();
86
+ INLINE_IF_UNITY Napi::Value Complete();
87
+
88
+ #undef INLINE_IF_UNITY
77
89
 
78
90
  void Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg);
79
91
 
@@ -103,6 +115,7 @@ private:
103
115
 
104
116
  void *ReserveTrampoline(const FunctionInfo *proto, Napi::Function func);
105
117
  };
118
+ RG_STATIC_ASSERT(MaxTrampolines <= 32);
106
119
 
107
120
  template <typename T>
108
121
  inline bool CallData::AllocStack(Size size, Size align, T **out_ptr)