koffi 2.16.1 → 3.0.0-alpha.2

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 (84) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/README.md +8 -8
  3. package/build/koffi/darwin_arm64/koffi.node +0 -0
  4. package/build/koffi/darwin_x64/koffi.node +0 -0
  5. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  6. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  7. package/build/koffi/freebsd_x64/koffi.node +0 -0
  8. package/build/koffi/linux_arm64/koffi.node +0 -0
  9. package/build/koffi/linux_ia32/koffi.node +0 -0
  10. package/build/koffi/linux_x64/koffi.node +0 -0
  11. package/build/koffi/musl_arm64/koffi.node +0 -0
  12. package/build/koffi/musl_x64/koffi.node +0 -0
  13. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  14. package/build/koffi/openbsd_x64/koffi.node +0 -0
  15. package/build/koffi/win32_ia32/koffi.node +0 -0
  16. package/build/koffi/win32_x64/koffi.node +0 -0
  17. package/doc/benchmarks.md +33 -33
  18. package/doc/benchmarks.xlsx +0 -0
  19. package/doc/contribute.md +37 -25
  20. package/doc/index.md +8 -8
  21. package/doc/variables.md +1 -1
  22. package/index.d.ts +11 -9
  23. package/index.js +1 -634
  24. package/indirect.js +1 -533
  25. package/lib/native/base/base.cc +63 -85
  26. package/lib/native/base/base.hh +178 -151
  27. package/package.json +3 -4
  28. package/src/build.js +1178 -0
  29. package/src/koffi/CMakeLists.txt +97 -34
  30. package/src/koffi/index.js +359 -0
  31. package/src/koffi/indirect.js +216 -0
  32. package/src/koffi/src/{abi_arm32.cc → abi/arm32.cc} +279 -275
  33. package/src/koffi/src/{abi_arm32_asm.S → abi/arm32_asm.S} +2 -5
  34. package/src/koffi/src/abi/arm64.cc +1511 -0
  35. package/src/koffi/src/{abi_arm64_asm.S → abi/arm64_asm.S} +44 -23
  36. package/src/koffi/src/{abi_arm64_asm.asm → abi/arm64_asm.asm} +32 -25
  37. package/src/koffi/src/{abi_loong64_asm.S → abi/loong64_asm.S} +1 -5
  38. package/src/koffi/src/{abi_riscv64.cc → abi/riscv64.cc} +279 -273
  39. package/src/koffi/src/{abi_riscv64_asm.S → abi/riscv64_asm.S} +1 -4
  40. package/src/koffi/src/abi/x64sysv.cc +1456 -0
  41. package/src/koffi/src/{abi_x64_sysv_asm.S → abi/x64sysv_asm.S} +30 -33
  42. package/src/koffi/src/abi/x64win.cc +1121 -0
  43. package/src/koffi/src/{abi_x64_win_asm.S → abi/x64win_asm.S} +8 -12
  44. package/src/koffi/src/{abi_x64_win_asm.asm → abi/x64win_asm.asm} +11 -14
  45. package/src/koffi/src/abi/x86.cc +1233 -0
  46. package/src/koffi/src/{abi_x86_asm.S → abi/x86_asm.S} +49 -25
  47. package/src/koffi/src/{abi_x86_asm.asm → abi/x86_asm.asm} +11 -14
  48. package/src/koffi/src/call.cc +458 -598
  49. package/src/koffi/src/call.hh +61 -82
  50. package/src/koffi/src/ffi.cc +595 -309
  51. package/src/koffi/src/ffi.hh +103 -89
  52. package/src/koffi/src/parser.cc +0 -4
  53. package/src/koffi/src/primitives.inc +39 -0
  54. package/src/koffi/{tools/write_trampolines.js → src/trampolines.js} +1 -1
  55. package/src/koffi/src/util.cc +503 -446
  56. package/src/koffi/src/util.hh +269 -57
  57. package/src/koffi/src/uv.cc +2 -2
  58. package/src/koffi/src/uv.def +3 -0
  59. package/src/koffi/src/win32.hh +30 -1
  60. package/vendor/node-addon-api/napi-inl.h +4 -0
  61. package/vendor/node-addon-api/napi.h +1 -0
  62. package/build/koffi/linux_armhf/koffi.node +0 -0
  63. package/build/koffi/linux_loong64/koffi.node +0 -0
  64. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  65. package/build/koffi/win32_arm64/koffi.exp +0 -0
  66. package/build/koffi/win32_arm64/koffi.lib +0 -0
  67. package/build/koffi/win32_arm64/koffi.node +0 -0
  68. package/doc/platforms.md +0 -36
  69. package/src/cnoke/LICENSE.txt +0 -22
  70. package/src/cnoke/README.md +0 -99
  71. package/src/cnoke/assets/FindCNoke.cmake +0 -127
  72. package/src/cnoke/assets/toolchains.json +0 -126
  73. package/src/cnoke/assets/win_delay_hook.c +0 -36
  74. package/src/cnoke/cnoke.js +0 -170
  75. package/src/cnoke/package.json +0 -24
  76. package/src/cnoke/src/builder.js +0 -511
  77. package/src/cnoke/src/index.js +0 -10
  78. package/src/cnoke/src/tools.js +0 -407
  79. package/src/koffi/src/abi_arm64.cc +0 -1295
  80. package/src/koffi/src/abi_x64_sysv.cc +0 -939
  81. package/src/koffi/src/abi_x64_win.cc +0 -715
  82. package/src/koffi/src/abi_x86.cc +0 -860
  83. package/src/koffi/src/init.js +0 -105
  84. /package/src/koffi/src/{abi_loong64.cc → abi/loong64.cc} +0 -0
@@ -13,22 +13,22 @@ namespace K {
13
13
  // Value does not matter, the tag system uses memory addresses
14
14
  const napi_type_tag TypeInfoMarker = { 0x1cc449675b294374, 0xbb13a50e97dcb017 };
15
15
  const napi_type_tag CastMarker = { 0x77f459614a0a412f, 0x80b3dda1341dc8df };
16
- const napi_type_tag MagicUnionMarker = { 0x5eaf2245526a4c7d, 0x8c86c9ee2b96ffc8 };
16
+ const napi_type_tag UnionClassMarker = { 0x5eaf2245526a4c7d, 0x8c86c9ee2b96ffc8 };
17
17
 
18
- Napi::Function MagicUnion::InitClass(Napi::Env env, const TypeInfo *type)
18
+ Napi::Function UnionClass::InitClass(Napi::Env env, const TypeInfo *type)
19
19
  {
20
20
  K_ASSERT(type->primitive == PrimitiveKind::Union);
21
21
 
22
22
  // node-addon-api wants std::vector
23
- std::vector<Napi::ClassPropertyDescriptor<MagicUnion>> properties;
23
+ std::vector<Napi::ClassPropertyDescriptor<UnionClass>> properties;
24
24
  properties.reserve(type->members.len);
25
25
 
26
26
  for (Size i = 0; i < type->members.len; i++) {
27
27
  const RecordMember &member = type->members[i];
28
28
 
29
29
  napi_property_attributes attr = (napi_property_attributes)(napi_writable | napi_enumerable);
30
- Napi::ClassPropertyDescriptor<MagicUnion> prop = InstanceAccessor(member.name, &MagicUnion::Getter,
31
- &MagicUnion::Setter, attr, (void *)i);
30
+ Napi::ClassPropertyDescriptor<UnionClass> prop = InstanceAccessor(member.name, &UnionClass::Getter,
31
+ &UnionClass::Setter, attr, (void *)i);
32
32
 
33
33
  properties.push_back(prop);
34
34
  }
@@ -37,25 +37,39 @@ Napi::Function MagicUnion::InitClass(Napi::Env env, const TypeInfo *type)
37
37
  return constructor;
38
38
  }
39
39
 
40
- MagicUnion::MagicUnion(const Napi::CallbackInfo &info)
41
- : Napi::ObjectWrap<MagicUnion>(info), type((const TypeInfo *)info.Data())
40
+ UnionClass::UnionClass(const Napi::CallbackInfo &info)
41
+ : Napi::ObjectWrap<UnionClass>(info), type((const TypeInfo *)info.Data())
42
42
  {
43
43
  Napi::Env env = info.Env();
44
- InstanceData *instance = env.GetInstanceData<InstanceData>();
44
+ instance = env.GetInstanceData<InstanceData>();
45
+ }
45
46
 
46
- active_symbol.Reset(instance->active_symbol.Value(), 1);
47
+ void UnionClass::Finalize(Napi::BasicEnv env)
48
+ {
49
+ napi_ref ref = (napi_ref)*this;
50
+
51
+ if (node_api_post_finalizer) {
52
+ node_api_post_finalizer(env, [](napi_env env, void *data, void *) {
53
+ napi_ref ref = (napi_ref)data;
54
+ napi_delete_reference(env, ref);
55
+ }, (void *)ref, nullptr);
56
+ } else {
57
+ napi_delete_reference(env, ref);
58
+ }
59
+
60
+ SuppressDestruct();
47
61
  }
48
62
 
49
- void MagicUnion::SetRaw(const uint8_t *ptr)
63
+ void UnionClass::SetRaw(const uint8_t *ptr)
50
64
  {
51
65
  raw.RemoveFrom(0);
52
66
  raw.Append(MakeSpan(ptr, type->size));
53
67
 
54
- Value().Set(active_symbol.Value(), Env().Undefined());
68
+ Value().Set(instance->active_symbol.Value(), Env().Undefined());
55
69
  active_idx = -1;
56
70
  }
57
71
 
58
- Napi::Value MagicUnion::Getter(const Napi::CallbackInfo &info)
72
+ Napi::Value UnionClass::Getter(const Napi::CallbackInfo &info)
59
73
  {
60
74
  Size idx = (Size)info.Data();
61
75
  const RecordMember &member = type->members[idx];
@@ -63,7 +77,7 @@ Napi::Value MagicUnion::Getter(const Napi::CallbackInfo &info)
63
77
  Napi::Value value;
64
78
 
65
79
  if (idx == active_idx) {
66
- value = Value().Get(active_symbol.Value());
80
+ value = Value().Get(instance->active_symbol.Value());
67
81
  } else {
68
82
  Napi::Env env = info.Env();
69
83
 
@@ -74,7 +88,7 @@ Napi::Value MagicUnion::Getter(const Napi::CallbackInfo &info)
74
88
 
75
89
  value = Decode(env, raw.ptr, member.type);
76
90
 
77
- Value().Set(active_symbol.Value(), value);
91
+ Value().Set(instance->active_symbol.Value(), value);
78
92
  active_idx = idx;
79
93
  }
80
94
 
@@ -82,11 +96,11 @@ Napi::Value MagicUnion::Getter(const Napi::CallbackInfo &info)
82
96
  return value;
83
97
  }
84
98
 
85
- void MagicUnion::Setter(const Napi::CallbackInfo &info, const Napi::Value &value)
99
+ void UnionClass::Setter(const Napi::CallbackInfo &info, const Napi::Value &value)
86
100
  {
87
101
  Size idx = (Size)info.Data();
88
102
 
89
- Value().Set(active_symbol.Value(), value);
103
+ Value().Set(instance->active_symbol.Value(), value);
90
104
  active_idx = idx;
91
105
 
92
106
  raw.Clear();
@@ -180,8 +194,8 @@ const TypeInfo *ResolveType(Napi::Value value, int *out_directions)
180
194
  }
181
195
 
182
196
  return type;
183
- } else if (CheckValueTag(value, &TypeInfoMarker)) {
184
- Napi::External<TypeInfo> external = value.As<Napi::External<TypeInfo>>();
197
+ } else if (GetKindOf(env, value) == napi_external && CheckValueTag(env, value, &TypeInfoMarker)) {
198
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>(env, value);
185
199
  const TypeInfo *raw = external.Data();
186
200
 
187
201
  const TypeInfo *type = AlignDown(raw, 4);
@@ -458,7 +472,7 @@ TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, A
458
472
  Napi::External<TypeInfo> WrapType(Napi::Env env, const TypeInfo *type)
459
473
  {
460
474
  Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
461
- SetValueTag(external, &TypeInfoMarker);
475
+ SetValueTag(env, external, &TypeInfoMarker);
462
476
 
463
477
  return external;
464
478
  }
@@ -520,26 +534,31 @@ bool CanStoreType(const TypeInfo *type)
520
534
  return true;
521
535
  }
522
536
 
523
- const char *GetValueType(const InstanceData *instance, Napi::Value value)
537
+ const char *GetValueType(const InstanceData *instance, napi_value value)
524
538
  {
525
- if (CheckValueTag(value, &CastMarker)) {
526
- Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
527
- ValueCast *cast = external.Data();
539
+ Napi::Env env = instance->env;
540
+ napi_valuetype kind = GetKindOf(env, value);
528
541
 
529
- return cast->type->name;
530
- }
542
+ if (kind == napi_external) {
543
+ if (CheckValueTag(env, value, &CastMarker)) {
544
+ Napi::External<ValueCast> external = Napi::External<ValueCast>(env, value);
545
+ ValueCast *cast = external.Data();
546
+
547
+ return cast->type->name;
548
+ }
531
549
 
532
- if (CheckValueTag(value, &TypeInfoMarker))
533
- return "Type";
534
- for (const TypeInfo &type: instance->types) {
535
- if (type.ref.marker && CheckValueTag(value, type.ref.marker))
536
- return type.name;
550
+ if (CheckValueTag(env, value, &TypeInfoMarker))
551
+ return "Type";
552
+ for (const TypeInfo &type: instance->types) {
553
+ if (type.ref.type && CheckValueTag(env, value, type.ref.type))
554
+ return type.name;
555
+ }
537
556
  }
538
557
 
539
- if (value.IsArray()) {
558
+ if (IsArray(env, value)) {
540
559
  return "Array";
541
- } else if (value.IsTypedArray()) {
542
- Napi::TypedArray array = value.As<Napi::TypedArray>();
560
+ } else if (IsTypedArray(env, value)) {
561
+ Napi::TypedArray array = Napi::TypedArray(env, value);
543
562
 
544
563
  switch (array.TypedArrayType()) {
545
564
  case napi_int8_array: return "Int8Array";
@@ -555,13 +574,13 @@ const char *GetValueType(const InstanceData *instance, Napi::Value value)
555
574
  case napi_bigint64_array: return "BigInt64Array";
556
575
  case napi_biguint64_array: return "BigUint64Array";
557
576
  }
558
- } else if (value.IsArrayBuffer()) {
577
+ } else if (IsArrayBuffer(env, value)) {
559
578
  return "ArrayBuffer";
560
- } else if (value.IsBuffer()) {
579
+ } else if (IsBuffer(env, value)) {
561
580
  return "Buffer";
562
581
  }
563
582
 
564
- switch (value.Type()) {
583
+ switch (kind) {
565
584
  case napi_undefined: return "Undefined";
566
585
  case napi_null: return "Null";
567
586
  case napi_boolean: return "Boolean";
@@ -578,7 +597,7 @@ const char *GetValueType(const InstanceData *instance, Napi::Value value)
578
597
  return "Unknown";
579
598
  }
580
599
 
581
- void SetValueTag(Napi::Value value, const void *marker)
600
+ void SetValueTag(napi_env env, napi_value value, const void *marker)
582
601
  {
583
602
  static_assert(K_SIZE(TypeInfo) >= 16);
584
603
 
@@ -593,18 +612,18 @@ void SetValueTag(Napi::Value value, const void *marker)
593
612
  // and the few other markers we use, such as CastMarker, are actual const napi_type_tag structs.
594
613
  const napi_type_tag *tag = (const napi_type_tag *)marker;
595
614
 
596
- napi_status status = napi_type_tag_object(value.Env(), value, tag);
615
+ napi_status status = napi_type_tag_object(env, value, tag);
597
616
  K_ASSERT(status == napi_ok);
598
617
  }
599
618
 
600
- bool CheckValueTag(Napi::Value value, const void *marker)
619
+ bool CheckValueTag(napi_env env, napi_value value, const void *marker)
601
620
  {
621
+ K_ASSERT(IsObject(env, value) || GetKindOf(env, value) == napi_external);
622
+
602
623
  bool match = false;
603
624
 
604
- if (!IsNullOrUndefined(value)) {
605
- const napi_type_tag *tag = (const napi_type_tag *)marker;
606
- napi_check_object_type_tag(value.Env(), value, tag, &match);
607
- }
625
+ const napi_type_tag *tag = (const napi_type_tag *)marker;
626
+ napi_check_object_type_tag(env, value, tag, &match);
608
627
 
609
628
  return match;
610
629
  }
@@ -662,16 +681,17 @@ Napi::Object DecodeObject(Napi::Env env, const uint8_t *origin, const TypeInfo *
662
681
  // We can't decode unions because we don't know which member is valid
663
682
  if (type->primitive == PrimitiveKind::Union) {
664
683
  Napi::Object wrapper = type->construct.New({}).As<Napi::Object>();
665
- SetValueTag(wrapper, &MagicUnionMarker);
684
+ SetValueTag(env, wrapper, &UnionClassMarker);
666
685
 
667
- MagicUnion *u = MagicUnion::Unwrap(wrapper);
686
+ UnionClass *u = UnionClass::Unwrap(wrapper);
668
687
  u->SetRaw(origin);
669
688
 
670
689
  return wrapper;
671
690
  }
672
691
 
673
692
  Napi::Object obj = Napi::Object::New(env);
674
- DecodeObject(obj, origin, type);
693
+ DecodeObject(env, obj, origin, type);
694
+
675
695
  return obj;
676
696
  }
677
697
 
@@ -689,52 +709,64 @@ static uint32_t DecodeDynamicLength(const uint8_t *origin, const RecordMember &b
689
709
  return (uint32_t)u;
690
710
  } break;
691
711
  case PrimitiveKind::Int16: {
692
- int16_t i = *(int16_t *)src;
712
+ int16_t i;
713
+ memcpy(&i, src, 2);
693
714
  return (uint32_t)i;
694
715
  } break;
695
716
  case PrimitiveKind::Int16S: {
696
- int16_t i = ReverseBytes(*(int16_t *)src);
697
- return (uint32_t)i;
717
+ int16_t i;
718
+ memcpy(&i, src, 2);
719
+ return (uint32_t)ReverseBytes(i);
698
720
  } break;
699
721
  case PrimitiveKind::UInt16: {
700
- uint16_t u = *(uint16_t *)src;
722
+ uint16_t u;
723
+ memcpy(&u, src, 2);
701
724
  return (uint32_t)u;
702
725
  } break;
703
726
  case PrimitiveKind::UInt16S: {
704
- uint16_t u = ReverseBytes(*(uint16_t *)src);
705
- return (uint32_t)u;
727
+ uint16_t u;
728
+ memcpy(&u, src, 2);
729
+ return (uint32_t)ReverseBytes(u);
706
730
  } break;
707
731
  case PrimitiveKind::Int32: {
708
- int32_t i = *(int32_t *)src;
732
+ int32_t i;
733
+ memcpy(&i, src, 4);
709
734
  return (uint32_t)i;
710
735
  } break;
711
736
  case PrimitiveKind::Int32S: {
712
- int32_t i = ReverseBytes(*(int32_t *)src);
713
- return (uint32_t)i;
737
+ int32_t i;
738
+ memcpy(&i, src, 4);
739
+ return (uint32_t)ReverseBytes(i);
714
740
  } break;
715
741
  case PrimitiveKind::UInt32: {
716
- uint32_t u = *(uint32_t *)src;
742
+ uint32_t u;
743
+ memcpy(&u, src, 4);
717
744
  return (uint32_t)u;
718
745
  } break;
719
746
  case PrimitiveKind::UInt32S: {
720
- uint32_t u = ReverseBytes(*(uint32_t *)src);
721
- return (uint32_t)u;
747
+ uint32_t u;
748
+ memcpy(&u, src, 4);
749
+ return (uint32_t)ReverseBytes(u);
722
750
  } break;
723
751
  case PrimitiveKind::Int64: {
724
- int64_t i = *(int64_t *)src;
752
+ int64_t i;
753
+ memcpy(&i, src, 8);
725
754
  return (uint32_t)i;
726
755
  } break;
727
756
  case PrimitiveKind::Int64S: {
728
- int64_t i = ReverseBytes(*(int64_t *)src);
729
- return (uint32_t)i;
757
+ int64_t i;
758
+ memcpy(&i, src, 8);
759
+ return (uint32_t)ReverseBytes(i);
730
760
  } break;
731
761
  case PrimitiveKind::UInt64: {
732
- uint64_t u = *(uint64_t *)src;
762
+ uint64_t u;
763
+ memcpy(&u, src, 8);
733
764
  return (uint32_t)u;
734
765
  } break;
735
766
  case PrimitiveKind::UInt64S: {
736
- uint64_t u = ReverseBytes(*(uint64_t *)src);
737
- return (uint32_t)u;
767
+ uint64_t u;
768
+ memcpy(&u, src, 8);
769
+ return (uint32_t)ReverseBytes(u);
738
770
  } break;
739
771
 
740
772
  case PrimitiveKind::Void:
@@ -755,15 +787,25 @@ static uint32_t DecodeDynamicLength(const uint8_t *origin, const RecordMember &b
755
787
  K_UNREACHABLE();
756
788
  }
757
789
 
758
- void DecodeObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type)
790
+ static inline void SetMemberValue(napi_env env, napi_value obj, const RecordMember &member, napi_value value)
759
791
  {
760
- Napi::Env env = obj.Env();
792
+ if (member.key) {
793
+ napi_value key = nullptr;
794
+ napi_get_reference_value(env, member.key, &key);
761
795
 
762
- K_ASSERT(type->primitive == PrimitiveKind::Record);
796
+ napi_status status = napi_set_property(env, obj, key, value);
797
+ K_ASSERT(status == napi_ok);
798
+ } else {
799
+ napi_status status = napi_set_named_property(env, obj, member.name, value);
800
+ K_ASSERT(status == napi_ok);
801
+ }
802
+ }
763
803
 
764
- for (Size i = 0; i < type->members.len; i++) {
765
- const RecordMember &member = type->members[i];
804
+ void DecodeObject(Napi::Env env, napi_value obj, const uint8_t *origin, const TypeInfo *type)
805
+ {
806
+ K_ASSERT(type->primitive == PrimitiveKind::Record);
766
807
 
808
+ for (const RecordMember &member: type->members) {
767
809
  const uint8_t *src = origin + member.offset;
768
810
 
769
811
  switch (member.type->primitive) {
@@ -771,119 +813,133 @@ void DecodeObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type)
771
813
 
772
814
  case PrimitiveKind::Bool: {
773
815
  bool b = *(bool *)src;
774
- obj.Set(member.name, Napi::Boolean::New(env, b));
816
+ SetMemberValue(env, obj, member, Napi::Boolean::New(env, b));
775
817
  } break;
776
818
  case PrimitiveKind::Int8: {
777
- double d = (double)*(int8_t *)src;
778
- obj.Set(member.name, Napi::Number::New(env, d));
819
+ int8_t i = *(int8_t *)src;
820
+ SetMemberValue(env, obj, member, NewInt(env, i));
779
821
  } break;
780
822
  case PrimitiveKind::UInt8: {
781
- double d = (double)*(uint8_t *)src;
782
- obj.Set(member.name, Napi::Number::New(env, d));
823
+ uint8_t u = *(uint8_t *)src;
824
+ SetMemberValue(env, obj, member, NewInt(env, u));
783
825
  } break;
784
826
  case PrimitiveKind::Int16: {
785
- double d = (double)*(int16_t *)src;
786
- obj.Set(member.name, Napi::Number::New(env, d));
827
+ int16_t i;
828
+ memcpy(&i, src, 2);
829
+ SetMemberValue(env, obj, member, NewInt(env, i));
787
830
  } break;
788
831
  case PrimitiveKind::Int16S: {
789
- int16_t v = *(int16_t *)src;
790
- double d = (double)ReverseBytes(v);
791
-
792
- obj.Set(member.name, Napi::Number::New(env, d));
832
+ int16_t i;
833
+ memcpy(&i, src, 2);
834
+ SetMemberValue(env, obj, member, NewInt(env, ReverseBytes(i)));
793
835
  } break;
794
836
  case PrimitiveKind::UInt16: {
795
- double d = (double)*(uint16_t *)src;
796
- obj.Set(member.name, Napi::Number::New(env, d));
837
+ uint16_t u;
838
+ memcpy(&u, src, 2);
839
+ SetMemberValue(env, obj, member, NewInt(env, u));
797
840
  } break;
798
841
  case PrimitiveKind::UInt16S: {
799
- uint16_t v = *(uint16_t *)src;
800
- double d = (double)ReverseBytes(v);
801
-
802
- obj.Set(member.name, Napi::Number::New(env, d));
842
+ uint16_t u;
843
+ memcpy(&u, src, 2);
844
+ SetMemberValue(env, obj, member, NewInt(env, ReverseBytes(u)));
803
845
  } break;
804
846
  case PrimitiveKind::Int32: {
805
- double d = (double)*(int32_t *)src;
806
- obj.Set(member.name, Napi::Number::New(env, d));
847
+ int32_t i;
848
+ memcpy(&i, src, 4);
849
+ SetMemberValue(env, obj, member, NewInt(env, i));
807
850
  } break;
808
851
  case PrimitiveKind::Int32S: {
809
- int32_t v = *(int32_t *)src;
810
- double d = (double)ReverseBytes(v);
811
-
812
- obj.Set(member.name, Napi::Number::New(env, d));
852
+ int32_t i;
853
+ memcpy(&i, src, 4);
854
+ SetMemberValue(env, obj, member, NewInt(env, ReverseBytes(i)));
813
855
  } break;
814
856
  case PrimitiveKind::UInt32: {
815
- double d = (double)*(uint32_t *)src;
816
- obj.Set(member.name, Napi::Number::New(env, d));
857
+ uint32_t u;
858
+ memcpy(&u, src, 4);
859
+ SetMemberValue(env, obj, member, NewInt(env, u));
817
860
  } break;
818
861
  case PrimitiveKind::UInt32S: {
819
- uint32_t v = *(uint32_t *)src;
820
- double d = (double)ReverseBytes(v);
821
-
822
- obj.Set(member.name, Napi::Number::New(env, d));
862
+ uint32_t u;
863
+ memcpy(&u, src, 4);
864
+ SetMemberValue(env, obj, member, NewInt(env, ReverseBytes(u)));
823
865
  } break;
824
866
  case PrimitiveKind::Int64: {
825
- int64_t v = *(int64_t *)src;
826
- obj.Set(member.name, NewBigInt(env, v));
867
+ int64_t i;
868
+ memcpy(&i, src, 8);
869
+ SetMemberValue(env, obj, member, NewInt(env, i));
827
870
  } break;
828
871
  case PrimitiveKind::Int64S: {
829
- int64_t v = ReverseBytes(*(int64_t *)src);
830
- obj.Set(member.name, NewBigInt(env, v));
872
+ int64_t i;
873
+ memcpy(&i, src, 8);
874
+ SetMemberValue(env, obj, member, NewInt(env, ReverseBytes(i)));
831
875
  } break;
832
876
  case PrimitiveKind::UInt64: {
833
- uint64_t v = *(uint64_t *)src;
834
- obj.Set(member.name, NewBigInt(env, v));
877
+ uint64_t u;
878
+ memcpy(&u, src, 8);
879
+ SetMemberValue(env, obj, member, NewInt(env, u));
835
880
  } break;
836
881
  case PrimitiveKind::UInt64S: {
837
- uint64_t v = ReverseBytes(*(uint64_t *)src);
838
- obj.Set(member.name, NewBigInt(env, v));
882
+ uint64_t u;
883
+ memcpy(&u, src, 8);
884
+ SetMemberValue(env, obj, member, NewInt(env, ReverseBytes(u)));
839
885
  } break;
840
886
  case PrimitiveKind::String: {
841
- const char *str = *(const char **)src;
842
- obj.Set(member.name, str ? Napi::String::New(env, str) : env.Null());
887
+ const char *str;
888
+ memcpy(&str, src, K_SIZE(void *));
889
+ SetMemberValue(env, obj, member, str ? Napi::String::New(env, str) : env.Null());
843
890
 
844
891
  if (member.type->dispose) {
845
892
  member.type->dispose(env, member.type, str);
846
893
  }
847
894
  } break;
848
895
  case PrimitiveKind::String16: {
849
- const char16_t *str16 = *(const char16_t **)src;
850
- obj.Set(member.name, str16 ? Napi::String::New(env, str16) : env.Null());
896
+ const char16_t *str16;
897
+ memcpy(&str16, src, K_SIZE(void *));
898
+ SetMemberValue(env, obj, member, str16 ? Napi::String::New(env, str16) : env.Null());
851
899
 
852
900
  if (member.type->dispose) {
853
901
  member.type->dispose(env, member.type, str16);
854
902
  }
855
903
  } break;
856
904
  case PrimitiveKind::String32: {
857
- const char32_t *str32 = *(const char32_t **)src;
858
- obj.Set(member.name, str32 ? MakeStringFromUTF32(env, str32) : env.Null());
905
+ const char32_t *str32;
906
+ memcpy(&str32, src, K_SIZE(void *));
907
+ SetMemberValue(env, obj, member, str32 ? MakeStringFromUTF32(env, str32) : env.Null());
859
908
  } break;
860
- case PrimitiveKind::Pointer:
861
- case PrimitiveKind::Callback: {
862
- void *ptr2 = *(void **)src;
909
+ case PrimitiveKind::Pointer: {
910
+ void *ptr2;
911
+ memcpy(&ptr2, src, K_SIZE(void *));
863
912
 
864
913
  if (member.countedby >= 0) {
865
914
  const RecordMember &by = type->members[member.countedby];
866
915
  uint32_t len = DecodeDynamicLength(origin, by);
867
916
 
868
917
  Napi::Value value = DecodeArray(env, (const uint8_t *)ptr2, member.type, len);
869
- obj.Set(member.name, value);
870
- } else if (ptr2) {
871
- Napi::External<void> external = Napi::External<void>::New(env, ptr2);
872
- SetValueTag(external, member.type->ref.marker);
873
-
874
- obj.Set(member.name, external);
918
+ SetMemberValue(env, obj, member, value);
875
919
  } else {
876
- obj.Set(member.name, env.Null());
920
+ Napi::Value p = ptr2 ? WrapPointer(env, member.type->ref.type, ptr2) : env.Null();
921
+ SetMemberValue(env, obj, member, p);
877
922
  }
878
923
 
879
924
  if (member.type->dispose) {
880
925
  member.type->dispose(env, member.type, ptr2);
881
926
  }
882
927
  } break;
928
+ case PrimitiveKind::Callback: {
929
+ void *ptr2;
930
+ memcpy(&ptr2, src, K_SIZE(void *));
931
+
932
+ Napi::Value p = ptr2 ? WrapCallback(env, member.type->ref.type, ptr2) : env.Null();
933
+ SetMemberValue(env, obj, member, p);
934
+
935
+ if (member.type->dispose) {
936
+ member.type->dispose(env, member.type, ptr2);
937
+ }
938
+ } break;
883
939
  case PrimitiveKind::Record:
884
940
  case PrimitiveKind::Union: {
885
941
  Napi::Object obj2 = DecodeObject(env, src, member.type);
886
- obj.Set(member.name, obj2);
942
+ SetMemberValue(env, obj, member, obj2);
887
943
  } break;
888
944
  case PrimitiveKind::Array: {
889
945
  if (member.countedby >= 0) {
@@ -896,19 +952,21 @@ void DecodeObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type)
896
952
  len = std::min(len, max);
897
953
 
898
954
  Napi::Value value = DecodeArray(env, src, member.type, len);
899
- obj.Set(member.name, value);
955
+ SetMemberValue(env, obj, member, value);
900
956
  } else {
901
957
  Napi::Value value = DecodeArray(env, src, member.type);
902
- obj.Set(member.name, value);
958
+ SetMemberValue(env, obj, member, value);
903
959
  }
904
960
  } break;
905
961
  case PrimitiveKind::Float32: {
906
- float f = *(float *)src;
907
- obj.Set(member.name, Napi::Number::New(env, (double)f));
962
+ float f;
963
+ memcpy(&f, src, 4);
964
+ SetMemberValue(env, obj, member, Napi::Number::New(env, (double)f));
908
965
  } break;
909
966
  case PrimitiveKind::Float64: {
910
- double d = *(double *)src;
911
- obj.Set(member.name, Napi::Number::New(env, d));
967
+ double d;
968
+ memcpy(&d, src, 8);
969
+ SetMemberValue(env, obj, member, Napi::Number::New(env, d));
912
970
  } break;
913
971
 
914
972
  case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
@@ -916,208 +974,129 @@ void DecodeObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type)
916
974
  }
917
975
  }
918
976
 
977
+ Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *type)
978
+ {
979
+ K_ASSERT(type->primitive == PrimitiveKind::Array);
980
+
981
+ uint32_t len = type->size / type->ref.type->size;
982
+ return DecodeArray(env, origin, type, len);
983
+ }
984
+
919
985
  Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *type, uint32_t len)
920
986
  {
921
- Size offset = 0;
987
+ K_ASSERT(type->primitive == PrimitiveKind::Array || type->primitive == PrimitiveKind::Pointer);
922
988
 
923
- #define POP_ARRAY(SetCode) \
924
- do { \
925
- Napi::Array array = Napi::Array::New(env); \
926
- \
927
- for (uint32_t i = 0; i < len; i++) { \
928
- offset = AlignLen(offset, type->ref.type->align); \
929
- \
930
- const uint8_t *src = origin + offset; \
931
- \
932
- SetCode \
933
- \
934
- offset += type->ref.type->size; \
935
- } \
936
- \
937
- return array; \
938
- } while (false)
939
- #define POP_NUMBER_ARRAY(TypedArrayType, CType) \
940
- do { \
941
- if (type->hint == ArrayHint::Array) { \
942
- POP_ARRAY({ \
943
- double d = (double)*(CType *)src; \
944
- array.Set(i, Napi::Number::New(env, d)); \
945
- }); \
946
- } else { \
947
- Napi::TypedArrayType array = Napi::TypedArrayType::New(env, len); \
948
- Span<uint8_t> buffer = MakeSpan((uint8_t *)array.ArrayBuffer().Data(), (Size)len * K_SIZE(CType)); \
949
- \
950
- DecodeBuffer(buffer, origin, type->ref.type); \
951
- \
952
- return array; \
953
- } \
954
- } while (false)
955
- #define POP_NUMBER_ARRAY_SWAP(TypedArrayType, CType) \
956
- do { \
957
- if (type->hint == ArrayHint::Array) { \
958
- POP_ARRAY({ \
959
- CType v = *(CType *)src; \
960
- double d = (double)ReverseBytes(v); \
961
- array.Set(i, Napi::Number::New(env, d)); \
962
- }); \
963
- } else { \
989
+ const TypeInfo *ref = type->ref.type;
990
+
991
+ if (type->hint == ArrayHint::Typed) {
992
+ #define POP_TYPEDARRAY(TypedArrayType, CType) \
993
+ do { \
964
994
  Napi::TypedArrayType array = Napi::TypedArrayType::New(env, len); \
965
995
  Span<uint8_t> buffer = MakeSpan((uint8_t *)array.ArrayBuffer().Data(), (Size)len * K_SIZE(CType)); \
966
996
  \
967
- DecodeBuffer(buffer, origin, type->ref.type); \
997
+ DecodeBuffer(buffer, origin, ref); \
968
998
  \
969
999
  return array; \
970
- } \
971
- } while (false)
972
-
973
- switch (type->ref.type->primitive) {
974
- case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
1000
+ } while (false)
1001
+
1002
+ switch (ref->primitive) {
1003
+ case PrimitiveKind::Int8: { POP_TYPEDARRAY(Int8Array, int8_t); } break;
1004
+ case PrimitiveKind::UInt8: { POP_TYPEDARRAY(Uint8Array, uint8_t); } break;
1005
+ case PrimitiveKind::Int16: { POP_TYPEDARRAY(Int16Array, int16_t); } break;
1006
+ case PrimitiveKind::Int16S: { POP_TYPEDARRAY(Int16Array, int16_t); } break;
1007
+ case PrimitiveKind::UInt16: { POP_TYPEDARRAY(Uint16Array, uint16_t); } break;
1008
+ case PrimitiveKind::UInt16S: { POP_TYPEDARRAY(Uint16Array, uint16_t); } break;
1009
+ case PrimitiveKind::Int32: { POP_TYPEDARRAY(Int32Array, int32_t); } break;
1010
+ case PrimitiveKind::Int32S: { POP_TYPEDARRAY(Int32Array, int32_t); } break;
1011
+ case PrimitiveKind::UInt32: { POP_TYPEDARRAY(Uint32Array, uint32_t); } break;
1012
+ case PrimitiveKind::UInt32S: { POP_TYPEDARRAY(Uint32Array, uint32_t); } break;
1013
+ case PrimitiveKind::Float32: { POP_TYPEDARRAY(Float32Array, float); } break;
1014
+ case PrimitiveKind::Float64: { POP_TYPEDARRAY(Float64Array, double); } break;
1015
+
1016
+ case PrimitiveKind::Void:
1017
+ case PrimitiveKind::Bool:
1018
+ case PrimitiveKind::Int64:
1019
+ case PrimitiveKind::Int64S:
1020
+ case PrimitiveKind::UInt64:
1021
+ case PrimitiveKind::UInt64S:
1022
+ case PrimitiveKind::String:
1023
+ case PrimitiveKind::String16:
1024
+ case PrimitiveKind::String32:
1025
+ case PrimitiveKind::Pointer:
1026
+ case PrimitiveKind::Callback:
1027
+ case PrimitiveKind::Record:
1028
+ case PrimitiveKind::Union:
1029
+ case PrimitiveKind::Array:
1030
+ case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
1031
+ }
975
1032
 
976
- case PrimitiveKind::Bool: {
977
- POP_ARRAY({
978
- bool b = *(bool *)src;
979
- array.Set(i, Napi::Boolean::New(env, b));
980
- });
981
- } break;
982
- case PrimitiveKind::Int8: {
983
- if (type->hint == ArrayHint::String) {
1033
+ #undef POP_TYPEDARRAY
1034
+ } else if (type->hint == ArrayHint::String) {
1035
+ switch (ref->primitive) {
1036
+ case PrimitiveKind::Int8: {
984
1037
  const char *ptr = (const char *)origin;
985
1038
  size_t count = strnlen(ptr, (size_t)len);
986
1039
 
987
1040
  Napi::String str = Napi::String::New(env, ptr, count);
988
1041
  return str;
989
- }
990
-
991
- POP_NUMBER_ARRAY(Int8Array, int8_t);
992
- } break;
993
- case PrimitiveKind::UInt8: { POP_NUMBER_ARRAY(Uint8Array, uint8_t); } break;
994
- case PrimitiveKind::Int16: {
995
- if (type->hint == ArrayHint::String) {
1042
+ } break;
1043
+ case PrimitiveKind::Int16: {
996
1044
  const char16_t *ptr = (const char16_t *)origin;
997
1045
  Size count = NullTerminatedLength(ptr, len);
998
1046
 
999
1047
  Napi::String str = Napi::String::New(env, ptr, count);
1000
1048
  return str;
1001
- }
1002
-
1003
- POP_NUMBER_ARRAY(Int16Array, int16_t);
1004
- } break;
1005
- case PrimitiveKind::Int16S: { POP_NUMBER_ARRAY_SWAP(Int16Array, int16_t); } break;
1006
- case PrimitiveKind::UInt16: { POP_NUMBER_ARRAY(Uint16Array, uint16_t); } break;
1007
- case PrimitiveKind::UInt16S: { POP_NUMBER_ARRAY_SWAP(Uint16Array, uint16_t); } break;
1008
- case PrimitiveKind::Int32: {
1009
- if (type->hint == ArrayHint::String) {
1049
+ } break;
1050
+ case PrimitiveKind::Int32: {
1010
1051
  const char32_t *ptr = (const char32_t *)origin;
1011
1052
  Size count = NullTerminatedLength(ptr, len);
1012
1053
 
1013
1054
  Napi::String str = MakeStringFromUTF32(env, ptr, count);
1014
1055
  return str;
1015
- }
1016
-
1017
- POP_NUMBER_ARRAY(Int32Array, int32_t);
1018
- } break;
1019
- case PrimitiveKind::Int32S: { POP_NUMBER_ARRAY_SWAP(Int32Array, int32_t); } break;
1020
- case PrimitiveKind::UInt32: { POP_NUMBER_ARRAY(Uint32Array, uint32_t); } break;
1021
- case PrimitiveKind::UInt32S: { POP_NUMBER_ARRAY_SWAP(Uint32Array, uint32_t); } break;
1022
- case PrimitiveKind::Int64: {
1023
- POP_ARRAY({
1024
- int64_t v = *(int64_t *)src;
1025
- array.Set(i, NewBigInt(env, v));
1026
- });
1027
- } break;
1028
- case PrimitiveKind::Int64S: {
1029
- POP_ARRAY({
1030
- int64_t v = ReverseBytes(*(int64_t *)src);
1031
- array.Set(i, NewBigInt(env, v));
1032
- });
1033
- } break;
1034
- case PrimitiveKind::UInt64: {
1035
- POP_ARRAY({
1036
- uint64_t v = *(uint64_t *)src;
1037
- array.Set(i, NewBigInt(env, v));
1038
- });
1039
- } break;
1040
- case PrimitiveKind::UInt64S: {
1041
- POP_ARRAY({
1042
- uint64_t v = ReverseBytes(*(uint64_t *)src);
1043
- array.Set(i, NewBigInt(env, v));
1044
- });
1045
- } break;
1046
- case PrimitiveKind::String: {
1047
- POP_ARRAY({
1048
- const char *str = *(const char **)src;
1049
- array.Set(i, str ? Napi::String::New(env, str) : env.Null());
1050
- });
1051
- } break;
1052
- case PrimitiveKind::String16: {
1053
- POP_ARRAY({
1054
- const char16_t *str16 = *(const char16_t **)src;
1055
- array.Set(i, str16 ? Napi::String::New(env, str16) : env.Null());
1056
- });
1057
- } break;
1058
- case PrimitiveKind::String32: {
1059
- POP_ARRAY({
1060
- const char32_t *str32 = *(const char32_t **)src;
1061
- array.Set(i, str32 ? MakeStringFromUTF32(env, str32) : env.Null());
1062
- });
1063
- } break;
1064
- case PrimitiveKind::Pointer:
1065
- case PrimitiveKind::Callback: {
1066
- POP_ARRAY({
1067
- void *ptr2 = *(void **)src;
1056
+ } break;
1068
1057
 
1069
- if (ptr2) {
1070
- Napi::External<void> external = Napi::External<void>::New(env, ptr2);
1071
- SetValueTag(external, type->ref.type->ref.marker);
1058
+ case PrimitiveKind::Void:
1059
+ case PrimitiveKind::Bool:
1060
+ case PrimitiveKind::UInt8:
1061
+ case PrimitiveKind::Int16S:
1062
+ case PrimitiveKind::UInt16:
1063
+ case PrimitiveKind::UInt16S:
1064
+ case PrimitiveKind::Int32S:
1065
+ case PrimitiveKind::UInt32:
1066
+ case PrimitiveKind::UInt32S:
1067
+ case PrimitiveKind::Int64:
1068
+ case PrimitiveKind::Int64S:
1069
+ case PrimitiveKind::UInt64:
1070
+ case PrimitiveKind::UInt64S:
1071
+ case PrimitiveKind::String:
1072
+ case PrimitiveKind::String16:
1073
+ case PrimitiveKind::String32:
1074
+ case PrimitiveKind::Pointer:
1075
+ case PrimitiveKind::Callback:
1076
+ case PrimitiveKind::Record:
1077
+ case PrimitiveKind::Union:
1078
+ case PrimitiveKind::Array:
1079
+ case PrimitiveKind::Float32:
1080
+ case PrimitiveKind::Float64:
1081
+ case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
1082
+ }
1083
+ } else {
1084
+ K_ASSERT(type->hint == ArrayHint::Array);
1072
1085
 
1073
- array.Set(i, external);
1074
- } else {
1075
- array.Set(i, env.Null());
1076
- }
1077
- });
1078
- } break;
1079
- case PrimitiveKind::Record:
1080
- case PrimitiveKind::Union: {
1081
- POP_ARRAY({
1082
- Napi::Object obj = DecodeObject(env, src, type->ref.type);
1083
- array.Set(i, obj);
1084
- });
1085
- } break;
1086
- case PrimitiveKind::Array: {
1087
- POP_ARRAY({
1088
- Napi::Value value = DecodeArray(env, src, type->ref.type);
1089
- array.Set(i, value);
1090
- });
1091
- } break;
1092
- case PrimitiveKind::Float32: { POP_NUMBER_ARRAY(Float32Array, float); } break;
1093
- case PrimitiveKind::Float64: { POP_NUMBER_ARRAY(Float64Array, double); } break;
1086
+ Napi::Array array = Napi::Array::New(env);
1087
+ DecodeElements(env, array, origin, type->ref.type, len);
1094
1088
 
1095
- case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
1089
+ return array;
1096
1090
  }
1097
1091
 
1098
- #undef POP_NUMBER_ARRAY_SWAP
1099
- #undef POP_NUMBER_ARRAY
1100
- #undef POP_ARRAY
1101
-
1102
1092
  K_UNREACHABLE();
1103
1093
  }
1104
1094
 
1105
- Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *type)
1106
- {
1107
- K_ASSERT(type->primitive == PrimitiveKind::Array);
1108
-
1109
- uint32_t len = type->size / type->ref.type->size;
1110
- return DecodeArray(env, origin, type, len);
1111
- }
1112
-
1113
- void DecodeNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo *ref)
1095
+ void DecodeElements(Napi::Env env, napi_value array, const uint8_t *origin, const TypeInfo *ref, uint32_t len)
1114
1096
  {
1115
- Napi::Env env = array.Env();
1116
-
1117
- K_ASSERT(array.IsArray());
1097
+ K_ASSERT(IsArray(env, array));
1118
1098
 
1119
1099
  Size offset = 0;
1120
- uint32_t len = array.Length();
1121
1100
 
1122
1101
  #define POP_ARRAY(SetCode) \
1123
1102
  do { \
@@ -1131,19 +1110,19 @@ void DecodeNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo
1131
1110
  offset += ref->size; \
1132
1111
  } \
1133
1112
  } while (false)
1134
- #define POP_NUMBER_ARRAY(CType) \
1113
+
1114
+ #define POP_INTEGERS(CType) \
1135
1115
  do { \
1136
1116
  POP_ARRAY({ \
1137
- double d = (double)*(CType *)src; \
1138
- array.Set(i, Napi::Number::New(env, d)); \
1117
+ CType v = *(CType *)src; \
1118
+ napi_set_element(env, array, i, NewInt(env, v)); \
1139
1119
  }); \
1140
1120
  } while (false)
1141
- #define POP_NUMBER_ARRAY_SWAP(CType) \
1121
+ #define POP_INTEGERS_SWAP(CType) \
1142
1122
  do { \
1143
1123
  POP_ARRAY({ \
1144
1124
  CType v = *(CType *)src; \
1145
- double d = (double)ReverseBytes(v); \
1146
- array.Set(i, Napi::Number::New(env, d)); \
1125
+ napi_set_element(env, array, i, NewInt(env, ReverseBytes(v))); \
1147
1126
  }); \
1148
1127
  } while (false)
1149
1128
 
@@ -1153,47 +1132,27 @@ void DecodeNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo
1153
1132
  case PrimitiveKind::Bool: {
1154
1133
  POP_ARRAY({
1155
1134
  bool b = *(bool *)src;
1156
- array.Set(i, Napi::Boolean::New(env, b));
1157
- });
1158
- } break;
1159
- case PrimitiveKind::Int8: { POP_NUMBER_ARRAY(int8_t); } break;
1160
- case PrimitiveKind::UInt8: { POP_NUMBER_ARRAY(uint8_t); } break;
1161
- case PrimitiveKind::Int16: { POP_NUMBER_ARRAY(int16_t); } break;
1162
- case PrimitiveKind::Int16S: { POP_NUMBER_ARRAY_SWAP(int16_t); } break;
1163
- case PrimitiveKind::UInt16: { POP_NUMBER_ARRAY(uint16_t); } break;
1164
- case PrimitiveKind::UInt16S: { POP_NUMBER_ARRAY_SWAP(uint16_t); } break;
1165
- case PrimitiveKind::Int32: { POP_NUMBER_ARRAY(int32_t); } break;
1166
- case PrimitiveKind::Int32S: { POP_NUMBER_ARRAY_SWAP(int32_t); } break;
1167
- case PrimitiveKind::UInt32: { POP_NUMBER_ARRAY(uint32_t); } break;
1168
- case PrimitiveKind::UInt32S: { POP_NUMBER_ARRAY_SWAP(uint32_t); } break;
1169
- case PrimitiveKind::Int64: {
1170
- POP_ARRAY({
1171
- int64_t v = *(int64_t *)src;
1172
- array.Set(i, NewBigInt(env, v));
1173
- });
1174
- } break;
1175
- case PrimitiveKind::Int64S: {
1176
- POP_ARRAY({
1177
- int64_t v = ReverseBytes(*(int64_t *)src);
1178
- array.Set(i, NewBigInt(env, v));
1179
- });
1180
- } break;
1181
- case PrimitiveKind::UInt64: {
1182
- POP_ARRAY({
1183
- uint64_t v = *(uint64_t *)src;
1184
- array.Set(i, NewBigInt(env, v));
1185
- });
1186
- } break;
1187
- case PrimitiveKind::UInt64S: {
1188
- POP_ARRAY({
1189
- uint64_t v = ReverseBytes(*(uint64_t *)src);
1190
- array.Set(i, NewBigInt(env, v));
1135
+ napi_set_element(env, array, i, Napi::Boolean::New(env, b));
1191
1136
  });
1192
1137
  } break;
1138
+ case PrimitiveKind::Int8: { POP_INTEGERS(int8_t); } break;
1139
+ case PrimitiveKind::UInt8: { POP_INTEGERS(uint8_t); } break;
1140
+ case PrimitiveKind::Int16: { POP_INTEGERS(int16_t); } break;
1141
+ case PrimitiveKind::Int16S: { POP_INTEGERS_SWAP(int16_t); } break;
1142
+ case PrimitiveKind::UInt16: { POP_INTEGERS(uint16_t); } break;
1143
+ case PrimitiveKind::UInt16S: { POP_INTEGERS_SWAP(uint16_t); } break;
1144
+ case PrimitiveKind::Int32: { POP_INTEGERS(int32_t); } break;
1145
+ case PrimitiveKind::Int32S: { POP_INTEGERS_SWAP(int32_t); } break;
1146
+ case PrimitiveKind::UInt32: { POP_INTEGERS(uint32_t); } break;
1147
+ case PrimitiveKind::UInt32S: { POP_INTEGERS_SWAP(uint32_t); } break;
1148
+ case PrimitiveKind::Int64: { POP_INTEGERS(int64_t); } break;
1149
+ case PrimitiveKind::Int64S: { POP_INTEGERS_SWAP(int64_t); } break;
1150
+ case PrimitiveKind::UInt64: { POP_INTEGERS(uint64_t); } break;
1151
+ case PrimitiveKind::UInt64S: { POP_INTEGERS_SWAP(uint64_t); } break;
1193
1152
  case PrimitiveKind::String: {
1194
1153
  POP_ARRAY({
1195
1154
  const char *str = *(const char **)src;
1196
- array.Set(i, str ? Napi::String::New(env, str) : env.Null());
1155
+ napi_set_element(env, array, i, str ? Napi::String::New(env, str) : env.Null());
1197
1156
 
1198
1157
  if (ref->dispose) {
1199
1158
  ref->dispose(env, ref, str);
@@ -1203,7 +1162,7 @@ void DecodeNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo
1203
1162
  case PrimitiveKind::String16: {
1204
1163
  POP_ARRAY({
1205
1164
  const char16_t *str16 = *(const char16_t **)src;
1206
- array.Set(i, str16 ? Napi::String::New(env, str16) : env.Null());
1165
+ napi_set_element(env, array, i, str16 ? Napi::String::New(env, str16) : env.Null());
1207
1166
 
1208
1167
  if (ref->dispose) {
1209
1168
  ref->dispose(env, ref, str16);
@@ -1213,26 +1172,31 @@ void DecodeNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo
1213
1172
  case PrimitiveKind::String32: {
1214
1173
  POP_ARRAY({
1215
1174
  const char32_t *str32 = *(const char32_t **)src;
1216
- array.Set(i, str32 ? MakeStringFromUTF32(env, str32) : env.Null());
1175
+ napi_set_element(env, array, i, str32 ? MakeStringFromUTF32(env, str32) : env.Null());
1217
1176
 
1218
1177
  if (ref->dispose) {
1219
1178
  ref->dispose(env, ref, str32);
1220
1179
  }
1221
1180
  });
1222
1181
  } break;
1223
- case PrimitiveKind::Pointer:
1224
- case PrimitiveKind::Callback: {
1182
+ case PrimitiveKind::Pointer: {
1225
1183
  POP_ARRAY({
1226
1184
  void *ptr2 = *(void **)src;
1227
1185
 
1228
- if (ptr2) {
1229
- Napi::External<void> external = Napi::External<void>::New(env, ptr2);
1230
- SetValueTag(external, ref->ref.marker);
1186
+ Napi::Value p = ptr2 ? WrapPointer(env, ref->ref.type, ptr2) : env.Null();
1187
+ napi_set_element(env, array, i, p);
1231
1188
 
1232
- array.Set(i, external);
1233
- } else {
1234
- array.Set(i, env.Null());
1189
+ if (ref->dispose) {
1190
+ ref->dispose(env, ref, ptr2);
1235
1191
  }
1192
+ });
1193
+ } break;
1194
+ case PrimitiveKind::Callback: {
1195
+ POP_ARRAY({
1196
+ void *ptr2 = *(void **)src;
1197
+
1198
+ Napi::Value p = ptr2 ? WrapCallback(env, ref->ref.type, ptr2) : env.Null();
1199
+ napi_set_element(env, array, i, p);
1236
1200
 
1237
1201
  if (ref->dispose) {
1238
1202
  ref->dispose(env, ref, ptr2);
@@ -1243,23 +1207,38 @@ void DecodeNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo
1243
1207
  case PrimitiveKind::Union: {
1244
1208
  POP_ARRAY({
1245
1209
  Napi::Object obj = DecodeObject(env, src, ref);
1246
- array.Set(i, obj);
1210
+ napi_set_element(env, array, i, obj);
1247
1211
  });
1248
1212
  } break;
1249
1213
  case PrimitiveKind::Array: {
1250
1214
  POP_ARRAY({
1251
1215
  Napi::Value value = DecodeArray(env, src, ref);
1252
- array.Set(i, value);
1216
+ napi_set_element(env, array, i, value);
1217
+ });
1218
+ } break;
1219
+ case PrimitiveKind::Float32: {
1220
+ POP_ARRAY({
1221
+ float f;
1222
+ memcpy(&f, src, 4);
1223
+
1224
+ napi_set_element(env, array, i, Napi::Number::New(env, (double)f));
1225
+ });
1226
+ } break;
1227
+ case PrimitiveKind::Float64: {
1228
+ POP_ARRAY({
1229
+ double d;
1230
+ memcpy(&d, src, 8);
1231
+
1232
+ napi_set_element(env, array, i, Napi::Number::New(env, d));
1253
1233
  });
1254
1234
  } break;
1255
- case PrimitiveKind::Float32: { POP_NUMBER_ARRAY(float); } break;
1256
- case PrimitiveKind::Float64: { POP_NUMBER_ARRAY(double); } break;
1257
1235
 
1258
1236
  case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
1259
1237
  }
1260
1238
 
1261
- #undef POP_NUMBER_ARRAY_SWAP
1262
- #undef POP_NUMBER_ARRAY
1239
+ #undef POP_INTEGERS_SWAP
1240
+ #undef POP_INTEGERS
1241
+
1263
1242
  #undef POP_ARRAY
1264
1243
  }
1265
1244
 
@@ -1294,14 +1273,9 @@ Napi::Value Decode(Napi::Value value, Size offset, const TypeInfo *type, const S
1294
1273
  Napi::Env env = value.Env();
1295
1274
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1296
1275
 
1297
- const uint8_t *ptr = nullptr;
1298
-
1299
- if (value.IsExternal()) {
1300
- Napi::External<void> external = value.As<Napi::External<void>>();
1301
- ptr = (const uint8_t *)external.Data();
1302
- } else if (IsRawBuffer(value)) {
1303
- Span<uint8_t> buffer = GetRawBuffer(value);
1276
+ const uint8_t *src = nullptr;
1304
1277
 
1278
+ if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
1305
1279
  if (offset < 0) [[unlikely]] {
1306
1280
  ThrowError<Napi::Error>(env, "Offset must be >= 0");
1307
1281
  return env.Null();
@@ -1312,17 +1286,19 @@ Napi::Value Decode(Napi::Value value, Size offset, const TypeInfo *type, const S
1312
1286
  return env.Null();
1313
1287
  }
1314
1288
 
1315
- ptr = (const uint8_t *)buffer.ptr;
1289
+ src = (const uint8_t *)buffer.ptr;
1290
+ } else if (void *ptr = nullptr; TryPointer(env, value, &ptr)) {
1291
+ src = (const uint8_t *)ptr;
1316
1292
  } else {
1317
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for variable, expected external or TypedArray", GetValueType(instance, value));
1293
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for variable, expected pointer", GetValueType(instance, value));
1318
1294
  return env.Null();
1319
1295
  }
1320
1296
 
1321
- if (!ptr)
1297
+ if (!src)
1322
1298
  return env.Null();
1323
- ptr += offset;
1299
+ src += offset;
1324
1300
 
1325
- Napi::Value ret = Decode(env, ptr, type, len);
1301
+ Napi::Value ret = Decode(env, src, type, len);
1326
1302
  return ret;
1327
1303
  }
1328
1304
 
@@ -1345,17 +1321,17 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
1345
1321
  } break;
1346
1322
  case PrimitiveKind::Int16:
1347
1323
  case PrimitiveKind::UInt16: {
1348
- Size count = NullTerminatedLength((const char16_t *)ptr, K_SIZE_MAX);
1324
+ Size count = NullTerminatedLength((const char16_t *)ptr);
1349
1325
  type = MakeArrayType(instance, type, count);
1350
1326
  } break;
1351
1327
  case PrimitiveKind::Int32:
1352
1328
  case PrimitiveKind::UInt32: {
1353
- Size count = NullTerminatedLength((const char32_t *)ptr, K_SIZE_MAX);
1329
+ Size count = NullTerminatedLength((const char32_t *)ptr);
1354
1330
  type = MakeArrayType(instance, type, count);
1355
1331
  } break;
1356
1332
 
1357
1333
  case PrimitiveKind::Pointer: {
1358
- Size count = NullTerminatedLength((const void **)ptr, K_SIZE_MAX);
1334
+ Size count = NullTerminatedLength((const void **)ptr);
1359
1335
  type = MakeArrayType(instance, type, count);
1360
1336
  } break;
1361
1337
 
@@ -1388,20 +1364,20 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
1388
1364
  bool v = *(bool *)ptr;
1389
1365
  return Napi::Boolean::New(env, v);
1390
1366
  } break;
1391
- case PrimitiveKind::Int8: { RETURN_INT(int8_t, Napi::Number::New); } break;
1392
- case PrimitiveKind::UInt8: { RETURN_INT(uint8_t, Napi::Number::New); } break;
1393
- case PrimitiveKind::Int16: { RETURN_INT(int16_t, Napi::Number::New); } break;
1394
- case PrimitiveKind::Int16S: { RETURN_INT_SWAP(int16_t, Napi::Number::New); } break;
1395
- case PrimitiveKind::UInt16: { RETURN_INT(uint16_t, Napi::Number::New); } break;
1396
- case PrimitiveKind::UInt16S: { RETURN_INT_SWAP(uint16_t, Napi::Number::New); } break;
1397
- case PrimitiveKind::Int32: { RETURN_INT(int32_t, Napi::Number::New); } break;
1398
- case PrimitiveKind::Int32S: { RETURN_INT_SWAP(int32_t, Napi::Number::New); } break;
1399
- case PrimitiveKind::UInt32: { RETURN_INT(uint32_t, Napi::Number::New); } break;
1400
- case PrimitiveKind::UInt32S: { RETURN_INT_SWAP(uint32_t, Napi::Number::New); } break;
1401
- case PrimitiveKind::Int64: { RETURN_INT(int64_t, NewBigInt); } break;
1402
- case PrimitiveKind::Int64S: { RETURN_INT_SWAP(int64_t, NewBigInt); } break;
1403
- case PrimitiveKind::UInt64: { RETURN_INT(uint64_t, NewBigInt); } break;
1404
- case PrimitiveKind::UInt64S: { RETURN_INT_SWAP(uint64_t, NewBigInt); } break;
1367
+ case PrimitiveKind::Int8: { RETURN_INT(int8_t, NewInt); } break;
1368
+ case PrimitiveKind::UInt8: { RETURN_INT(uint8_t, NewInt); } break;
1369
+ case PrimitiveKind::Int16: { RETURN_INT(int16_t, NewInt); } break;
1370
+ case PrimitiveKind::Int16S: { RETURN_INT_SWAP(int16_t, NewInt); } break;
1371
+ case PrimitiveKind::UInt16: { RETURN_INT(uint16_t, NewInt); } break;
1372
+ case PrimitiveKind::UInt16S: { RETURN_INT_SWAP(uint16_t, NewInt); } break;
1373
+ case PrimitiveKind::Int32: { RETURN_INT(int32_t, NewInt); } break;
1374
+ case PrimitiveKind::Int32S: { RETURN_INT_SWAP(int32_t, NewInt); } break;
1375
+ case PrimitiveKind::UInt32: { RETURN_INT(uint32_t, NewInt); } break;
1376
+ case PrimitiveKind::UInt32S: { RETURN_INT_SWAP(uint32_t, NewInt); } break;
1377
+ case PrimitiveKind::Int64: { RETURN_INT(int64_t, NewInt); } break;
1378
+ case PrimitiveKind::Int64S: { RETURN_INT_SWAP(int64_t, NewInt); } break;
1379
+ case PrimitiveKind::UInt64: { RETURN_INT(uint64_t, NewInt); } break;
1380
+ case PrimitiveKind::UInt64S: { RETURN_INT_SWAP(uint64_t, NewInt); } break;
1405
1381
  case PrimitiveKind::String: {
1406
1382
  if (len) {
1407
1383
  const char *str = *(const char **)ptr;
@@ -1429,10 +1405,13 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
1429
1405
  return str32 ? MakeStringFromUTF32(env, str32) : env.Null();
1430
1406
  }
1431
1407
  } break;
1432
- case PrimitiveKind::Pointer:
1408
+ case PrimitiveKind::Pointer: {
1409
+ void *ptr2 = *(void **)ptr;
1410
+ return ptr2 ? WrapPointer(env, type->ref.type, ptr2) : env.Null();
1411
+ } break;
1433
1412
  case PrimitiveKind::Callback: {
1434
1413
  void *ptr2 = *(void **)ptr;
1435
- return ptr2 ? Napi::External<void>::New(env, ptr2, [](Napi::Env, void *) {}) : env.Null();
1414
+ return ptr2 ? WrapCallback(env, type->ref.type, ptr2) : env.Null();
1436
1415
  } break;
1437
1416
  case PrimitiveKind::Record:
1438
1417
  case PrimitiveKind::Union: {
@@ -1444,11 +1423,15 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
1444
1423
  return array;
1445
1424
  } break;
1446
1425
  case PrimitiveKind::Float32: {
1447
- float f = *(float *)ptr;
1448
- return Napi::Number::New(env, f);
1426
+ float f;
1427
+ memcpy(&f, ptr, 4);
1428
+
1429
+ return Napi::Number::New(env, (double)f);
1449
1430
  } break;
1450
1431
  case PrimitiveKind::Float64: {
1451
- double d = *(double *)ptr;
1432
+ double d;
1433
+ memcpy(&d, ptr, 8);
1434
+
1452
1435
  return Napi::Number::New(env, d);
1453
1436
  } break;
1454
1437
 
@@ -1462,16 +1445,14 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
1462
1445
 
1463
1446
  memcpy((void *)func, proto, K_SIZE(*proto));
1464
1447
  memset((void *)&func->parameters, 0, K_SIZE(func->parameters));
1465
- func->parameters = proto->parameters;
1448
+ memset((void *)&func->sync, 0, K_SIZE(func->sync));
1449
+ memset((void *)&func->async, 0, K_SIZE(func->async));
1466
1450
 
1467
1451
  func->name = "<anonymous>";
1468
1452
  func->native = (void *)ptr;
1469
-
1470
- // Fix back parameter offset
1471
- for (ParameterInfo &param: func->parameters) {
1472
- param.offset -= 2;
1473
- }
1474
- func->required_parameters -= 2;
1453
+ func->parameters = proto->parameters;
1454
+ func->sync = proto->sync;
1455
+ func->async = proto->async;
1475
1456
 
1476
1457
  Napi::Function wrapper = WrapFunction(env, func);
1477
1458
  return wrapper;
@@ -1489,14 +1470,9 @@ bool Encode(Napi::Value ref, Size offset, Napi::Value value, const TypeInfo *typ
1489
1470
  Napi::Env env = ref.Env();
1490
1471
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1491
1472
 
1492
- uint8_t *ptr = nullptr;
1493
-
1494
- if (ref.IsExternal()) {
1495
- Napi::External<void> external = ref.As<Napi::External<void>>();
1496
- ptr = (uint8_t *)external.Data();
1497
- } else if (IsRawBuffer(ref)) {
1498
- Span<uint8_t> buffer = GetRawBuffer(ref);
1473
+ uint8_t *dest = nullptr;
1499
1474
 
1475
+ if (Span<uint8_t> buffer = {}; TryBuffer(env, ref, &buffer)) {
1500
1476
  if (offset < 0) [[unlikely]] {
1501
1477
  ThrowError<Napi::Error>(env, "Offset must be >= 0");
1502
1478
  return env.Null();
@@ -1507,19 +1483,21 @@ bool Encode(Napi::Value ref, Size offset, Napi::Value value, const TypeInfo *typ
1507
1483
  return env.Null();
1508
1484
  }
1509
1485
 
1510
- ptr = (uint8_t *)buffer.ptr;
1486
+ dest = (uint8_t *)buffer.ptr;
1487
+ } else if (void *ptr = nullptr; TryPointer(env, ref, &ptr)) {
1488
+ dest = (uint8_t *)ptr;
1511
1489
  } else {
1512
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for reference, expected external or TypedArray", GetValueType(instance, ref));
1490
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for reference, expected pointer", GetValueType(instance, ref));
1513
1491
  return env.Null();
1514
1492
  }
1515
1493
 
1516
- if (!ptr) [[unlikely]] {
1494
+ if (!dest) [[unlikely]] {
1517
1495
  ThrowError<Napi::Error>(env, "Cannot encode data in NULL pointer");
1518
1496
  return env.Null();
1519
1497
  }
1520
- ptr += offset;
1498
+ dest += offset;
1521
1499
 
1522
- return Encode(env, ptr, value, type, len);
1500
+ return Encode(env, dest, value, type, len);
1523
1501
  }
1524
1502
 
1525
1503
  bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *type, const Size *len)
@@ -1539,26 +1517,26 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
1539
1517
  }
1540
1518
 
1541
1519
  InstanceMemory mem = {};
1542
- CallData call(env, instance, &mem);
1520
+ CallData call(env, instance, &mem, nullptr);
1543
1521
 
1544
1522
  #define PUSH_INTEGER(CType) \
1545
1523
  do { \
1546
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
1524
+ CType v; \
1525
+ if (!TryNumber(env, value, &v)) [[unlikely]] { \
1547
1526
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
1548
1527
  return false; \
1549
1528
  } \
1550
1529
  \
1551
- CType v = GetNumber<CType>(value); \
1552
1530
  *(CType *)origin = v; \
1553
1531
  } while (false)
1554
1532
  #define PUSH_INTEGER_SWAP(CType) \
1555
1533
  do { \
1556
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
1534
+ CType v; \
1535
+ if (!TryNumber(env, value, &v)) [[unlikely]] { \
1557
1536
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
1558
1537
  return false; \
1559
1538
  } \
1560
1539
  \
1561
- CType v = GetNumber<CType>(value); \
1562
1540
  *(CType *)origin = ReverseBytes(v); \
1563
1541
  } while (false)
1564
1542
 
@@ -1566,12 +1544,14 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
1566
1544
  case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
1567
1545
 
1568
1546
  case PrimitiveKind::Bool: {
1569
- if (!value.IsBoolean()) [[unlikely]] {
1547
+ bool b;
1548
+ napi_status status = napi_get_value_bool(env, value, &b);
1549
+
1550
+ if (status != napi_ok) [[unlikely]] {
1570
1551
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
1571
1552
  return false;
1572
1553
  }
1573
1554
 
1574
- bool b = value.As<Napi::Boolean>();
1575
1555
  *(bool *)origin = b;
1576
1556
  } break;
1577
1557
  case PrimitiveKind::Int8: { PUSH_INTEGER(int8_t); } break;
@@ -1614,7 +1594,7 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
1614
1594
  } break;
1615
1595
  case PrimitiveKind::Record:
1616
1596
  case PrimitiveKind::Union: {
1617
- if (!IsObject(value)) [[unlikely]] {
1597
+ if (!IsObject(env, value)) [[unlikely]] {
1618
1598
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
1619
1599
  return false;
1620
1600
  }
@@ -1626,11 +1606,10 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
1626
1606
  } break;
1627
1607
  case PrimitiveKind::Array: {
1628
1608
  if (value.IsArray()) {
1629
- Napi::Array array = value.As<Napi::Array>();
1609
+ Napi::Array array = Napi::Array(env, value);
1630
1610
  if (!call.PushNormalArray(array, type, type->size, origin))
1631
1611
  return false;
1632
- } else if (IsRawBuffer(value)) {
1633
- Span<const uint8_t> buffer = GetRawBuffer(value);
1612
+ } else if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
1634
1613
  call.PushBuffer(buffer, type, origin);
1635
1614
  } else if (value.IsString()) {
1636
1615
  if (!call.PushStringArray(value, type, origin))
@@ -1641,35 +1620,31 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
1641
1620
  }
1642
1621
  } break;
1643
1622
  case PrimitiveKind::Float32: {
1644
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
1623
+ float f;
1624
+ if (!TryNumber(env, value, &f)) [[unlikely]] {
1645
1625
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
1646
1626
  return false;
1647
1627
  }
1648
1628
 
1649
- float f = GetNumber<float>(value);
1650
- *(float *)origin = f;
1629
+ memcpy(origin, &f, 4);
1651
1630
  } break;
1652
1631
  case PrimitiveKind::Float64: {
1653
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
1632
+ double d;
1633
+ if (!TryNumber(env, value, &d)) [[unlikely]] {
1654
1634
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
1655
1635
  return false;
1656
1636
  }
1657
1637
 
1658
- double d = GetNumber<double>(value);
1659
- *(double *)origin = d;
1638
+ memcpy(origin, &d, 8);
1660
1639
  } break;
1661
1640
  case PrimitiveKind::Callback: {
1662
1641
  void *ptr;
1663
-
1664
- if (value.IsFunction()) {
1665
- ThrowError<Napi::Error>(env, "Cannot encode non-registered callback");
1666
- return false;
1667
- } else if (CheckValueTag(value, type->ref.marker)) {
1668
- ptr = value.As<Napi::External<void>>().Data();
1669
- } else if (IsNullOrUndefined(value)) {
1670
- ptr = nullptr;
1671
- } else {
1672
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
1642
+ if (!TryPointer(env, value, &ptr)) [[unlikely]] {
1643
+ if (value.IsFunction()) {
1644
+ ThrowError<Napi::Error>(env, "Cannot encode non-registered callback");
1645
+ } else {
1646
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
1647
+ }
1673
1648
  return false;
1674
1649
  }
1675
1650
 
@@ -1683,15 +1658,53 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
1683
1658
  #undef PUSH_INTEGER
1684
1659
 
1685
1660
  // Keep memory around if any was allocated
1686
- if (call.alloc.IsUsed()) {
1687
- BlockAllocator *copy = instance->encode_map.FindValue(origin, nullptr);
1661
+ if (mem.allocator.IsUsed()) {
1662
+ LinkedAllocator *copy = instance->encode_map.FindValue(origin, nullptr);
1688
1663
 
1689
1664
  if (!copy) {
1690
1665
  copy = instance->encode_allocators.AppendDefault();
1691
1666
  instance->encode_map.Set(origin, copy);
1692
1667
  }
1693
1668
 
1694
- std::swap(call.alloc, *copy);
1669
+ std::swap(mem.allocator, *copy);
1670
+ }
1671
+
1672
+ return true;
1673
+ }
1674
+
1675
+ static bool CanTypeAcceptCallbacks(const TypeInfo *type)
1676
+ {
1677
+ if (type->primitive == PrimitiveKind::Pointer)
1678
+ return true;
1679
+ if (type->primitive == PrimitiveKind::Callback)
1680
+ return true;
1681
+
1682
+ if (type->primitive == PrimitiveKind::Record ||
1683
+ type->primitive == PrimitiveKind::Union) {
1684
+ for (const RecordMember &member: type->members) {
1685
+ if (CanTypeAcceptCallbacks(member.type))
1686
+ return false;
1687
+ }
1688
+ }
1689
+
1690
+ return true;
1691
+ }
1692
+
1693
+ static bool CanUseFastCall(const FunctionInfo *func)
1694
+ {
1695
+ if (func->parameters.len > 6)
1696
+ return false;
1697
+
1698
+ // Fast calls basically skip CallData::Finalize(), which handles output arguments
1699
+ // and temporary callback trampolines. If the function does not use any
1700
+ // output argument and cannot accept callbacks (so no pointer or callback arguments),
1701
+ // we can skip finalization!
1702
+
1703
+ for (const ParameterInfo &param: func->parameters) {
1704
+ if (param.directions & 2)
1705
+ return false;
1706
+ if (CanTypeAcceptCallbacks(param.type))
1707
+ return false;
1695
1708
  }
1696
1709
 
1697
1710
  return true;
@@ -1700,20 +1713,38 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
1700
1713
  Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
1701
1714
  {
1702
1715
  Napi::Function wrapper;
1703
- if (func->variadic) {
1704
- Napi::Function::Callback call = TranslateVariadicCall;
1705
- wrapper = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1706
- } else {
1707
- Napi::Function::Callback call = TranslateNormalCall;
1708
- wrapper = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1716
+
1717
+ // Pick appropriate wrapper
1718
+ {
1719
+ napi_value value;
1720
+
1721
+ if (func->variadic) {
1722
+ napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateVariadicCall, (void *)func->Ref(), &value);
1723
+ K_ASSERT(status == napi_ok);
1724
+ } else if (!func->parameters.len) {
1725
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1726
+ napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, instance->translate_zero_call, (void *)func->Ref(), &value);
1727
+ K_ASSERT(status == napi_ok);
1728
+ } else if (CanUseFastCall(func)) {
1729
+ napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateFastCall, (void *)func->Ref(), &value);
1730
+ K_ASSERT(status == napi_ok);
1731
+ } else {
1732
+ napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCall, (void *)func->Ref(), &value);
1733
+ K_ASSERT(status == napi_ok);
1734
+ }
1735
+
1736
+ wrapper = Napi::Function(env, value);
1737
+ wrapper.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
1709
1738
  }
1710
- wrapper.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
1711
1739
 
1712
1740
  if (!func->variadic) {
1713
- Napi::Function::Callback call = TranslateAsyncCall;
1714
- Napi::Function async = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1741
+ napi_value value;
1742
+ napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateAsyncCall, (void *)func->Ref(), &value);
1743
+ K_ASSERT(status == napi_ok);
1715
1744
 
1745
+ Napi::Function async = Napi::Function(env, value);
1716
1746
  async.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
1747
+
1717
1748
  wrapper.Set("async", async);
1718
1749
  }
1719
1750
 
@@ -1737,6 +1768,32 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
1737
1768
  return wrapper;
1738
1769
  }
1739
1770
 
1771
+ Napi::Value WrapPointer(Napi::Env env, const TypeInfo *ref, void *ptr)
1772
+ {
1773
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1774
+
1775
+ if (instance->config.fast_pointers) {
1776
+ Napi::BigInt big = Napi::BigInt::New(env, (uint64_t)(uintptr_t)ptr);
1777
+ return big;
1778
+ } else {
1779
+ Napi::External<void> external = Napi::External<void>::New(env, ptr);
1780
+ return external;
1781
+ }
1782
+ }
1783
+
1784
+ Napi::Value WrapCallback(Napi::Env env, const TypeInfo *ref, void *ptr)
1785
+ {
1786
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1787
+
1788
+ if (instance->config.fast_callbacks) {
1789
+ Napi::BigInt big = Napi::BigInt::New(env, (uint64_t)(uintptr_t)ptr);
1790
+ return big;
1791
+ } else {
1792
+ Napi::External<void> external = Napi::External<void>::New(env, ptr);
1793
+ return external;
1794
+ }
1795
+ }
1796
+
1740
1797
  bool DetectCallConvention(Span<const char> name, CallConvention *out_convention)
1741
1798
  {
1742
1799
  if (name == "__cdecl") {