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
@@ -21,37 +21,108 @@ struct RelayContext {
21
21
  bool done = false;
22
22
  };
23
23
 
24
+ #if defined(_WIN32)
25
+
24
26
  extern "C" void *FindTrampolineStart();
25
27
  extern "C" void *FindTrampolineEnd();
26
28
 
27
29
  static const uint8_t *TrampolineStart = (const uint8_t *)FindTrampolineStart();
28
30
  static const Size TrampolineSize = ((const uint8_t *)FindTrampolineEnd() - TrampolineStart) / MaxTrampolines;
29
31
 
30
- CallData::CallData(Napi::Env env, InstanceData *instance, InstanceMemory *mem)
31
- : env(env), instance(instance),
32
- mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
33
- {
34
- mem->depth++;
32
+ #else
35
33
 
36
- K_ASSERT(AlignUp(mem->stack.ptr, 16) == mem->stack.ptr);
37
- }
34
+ extern "C" uint8_t Trampoline0;
35
+ extern "C" uint8_t TrampolineEnd;
38
36
 
37
+ static const uint8_t *TrampolineStart = (const uint8_t *)&Trampoline0;
38
+ static const Size TrampolineSize = ((const uint8_t *)&TrampolineEnd - TrampolineStart) / MaxTrampolines;
39
+
40
+ #endif
41
+
42
+ #if defined(K_DEBUG)
39
43
  CallData::~CallData()
40
44
  {
41
- if (!instance)
42
- return;
43
-
44
- Dispose();
45
+ K_ASSERT(mem->stack.end == prev_stack);
46
+ K_ASSERT(mem->heap.ptr == prev_heap);
47
+ K_ASSERT(!out_arguments.len);
48
+ K_ASSERT(!used_trampolines.len);
45
49
  }
50
+ #endif
46
51
 
47
- void CallData::Dispose()
52
+ void CallData::Finalize()
48
53
  {
49
- for (const OutArgument &out: out_arguments) {
50
- napi_delete_reference(env, out.ref);
51
- }
54
+ FinalizeFast();
55
+
56
+ if (out_arguments.len) {
57
+ if (!env.IsExceptionPending()) {
58
+ for (const OutArgument &out: out_arguments) {
59
+ napi_value value = GetReferenceValue(env, out.ref);
60
+
61
+ switch (out.kind) {
62
+ case OutArgument::Kind::Array: {
63
+ K_ASSERT(IsArray(env, value));
64
+
65
+ uint32_t len = GetArrayLength(env, value);
66
+ DecodeElements(env, value, out.ptr, out.type, len);
67
+ } break;
68
+
69
+ case OutArgument::Kind::Buffer: {
70
+ Span<uint8_t> buffer;
71
+
72
+ bool success = TryBuffer(env, value, &buffer);
73
+ K_ASSERT(success);
74
+
75
+ DecodeBuffer(buffer, out.ptr, out.type);
76
+ } break;
77
+
78
+ case OutArgument::Kind::String: {
79
+ K_ASSERT(IsArray(env, value));
80
+ K_ASSERT(GetArrayLength(env, value) == 1);
81
+
82
+ Size len = strnlen((const char *)out.ptr, out.max_len);
83
+ Napi::String str = Napi::String::New(env, (const char *)out.ptr, len);
84
+
85
+ napi_set_element(env, value, 0, str);
86
+ } break;
87
+
88
+ case OutArgument::Kind::String16: {
89
+ K_ASSERT(IsArray(env, value));
90
+ K_ASSERT(GetArrayLength(env, value) == 1);
91
+
92
+ Size len = NullTerminatedLength((const char16_t *)out.ptr, out.max_len);
93
+ Napi::String str = Napi::String::New(env, (const char16_t *)out.ptr, len);
94
+
95
+ napi_set_element(env, value, 0, str);
96
+ } break;
97
+
98
+ case OutArgument::Kind::String32: {
99
+ K_ASSERT(IsArray(env, value));
100
+ K_ASSERT(GetArrayLength(env, value) == 1);
101
+
102
+ Size len = NullTerminatedLength((const char32_t *)out.ptr, out.max_len);
103
+ Napi::String str = MakeStringFromUTF32(env, (const char32_t *)out.ptr, len);
52
104
 
53
- mem->stack = old_stack_mem;
54
- mem->heap = old_heap_mem;
105
+ napi_set_element(env, value, 0, str);
106
+ } break;
107
+
108
+ case OutArgument::Kind::Object: {
109
+ if (CheckValueTag(env, value, &UnionClassMarker)) {
110
+ Napi::Object obj = Napi::Object(env, value);
111
+
112
+ UnionClass *u = UnionClass::Unwrap(obj);
113
+ u->SetRaw(out.ptr);
114
+ } else {
115
+ DecodeObject(env, value, out.ptr, out.type);
116
+ }
117
+ } break;
118
+ }
119
+ }
120
+ }
121
+
122
+ for (const OutArgument &out: out_arguments) {
123
+ napi_delete_reference(env, out.ref);
124
+ }
125
+ }
55
126
 
56
127
  if (used_trampolines.len) {
57
128
  std::lock_guard<std::mutex> lock(shared.mutex);
@@ -63,17 +134,37 @@ void CallData::Dispose()
63
134
  K_ASSERT(trampoline->instance == instance);
64
135
  K_ASSERT(!trampoline->func.IsEmpty());
65
136
 
137
+ trampoline->state = 0;
66
138
  trampoline->func.Reset();
67
139
  trampoline->recv.Reset();
68
- trampoline->used = false;
69
140
 
70
141
  shared.available.Append(idx);
71
142
  }
72
143
  }
73
144
 
74
- ReleaseMemory(instance, mem);
145
+ #if defined(K_DEBUG)
146
+ out_arguments.len = 0;
147
+ used_trampolines.len = 0;
148
+ #endif
149
+ }
75
150
 
76
- instance = nullptr;
151
+ void CallData::FinalizeFast()
152
+ {
153
+ #if defined(K_DEBUG)
154
+ K_ASSERT(!finalized);
155
+ K_DEFER { finalized = true; };
156
+ #endif
157
+
158
+ mem->stack.end = prev_stack;
159
+ mem->heap.ptr = prev_heap;
160
+
161
+ if (release_alloc) {
162
+ // We could check for prev_stack == mem->stack.len and call ReleaseAll() if true, but
163
+ // it is a virtual method. Which means it could be slow (unless devirtualized), and
164
+ // most of the time there's nothing to release.
165
+ // So instead, take note of the need to call ReleaseAll() when big chunks are allocated.
166
+ mem->allocator.ReleaseAll();
167
+ }
77
168
  }
78
169
 
79
170
  void CallData::RelayAsync(Size idx, uint8_t *sp)
@@ -96,77 +187,76 @@ void CallData::RelayAsync(Size idx, uint8_t *sp)
96
187
  }
97
188
  }
98
189
 
99
- bool CallData::PushString(Napi::Value value, int directions, const char **out_str)
190
+ bool CallData::PushString(napi_value value, int directions, const char **out_str)
100
191
  {
101
192
  // Fast path
102
- if (value.IsString()) {
193
+ if (PushStringValue(value, out_str) >= 0) {
103
194
  if (directions & 2) [[unlikely]] {
104
195
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
105
196
  return false;
106
197
  }
107
198
 
108
- PushStringValue(value, out_str);
109
199
  return true;
110
200
  }
111
201
 
112
202
  return PushPointer(value, instance->str_type, directions, (void **)out_str);
113
203
  }
114
204
 
115
- bool CallData::PushString16(Napi::Value value, int directions, const char16_t **out_str16)
205
+ bool CallData::PushString16(napi_value value, int directions, const char16_t **out_str16)
116
206
  {
117
207
  // Fast path
118
- if (value.IsString()) {
208
+ if (PushString16Value(value, out_str16) >= 0) {
119
209
  if (directions & 2) [[unlikely]] {
120
210
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
121
211
  return false;
122
212
  }
123
213
 
124
- PushString16Value(value, out_str16);
125
214
  return true;
126
215
  }
127
216
 
128
217
  return PushPointer(value, instance->str16_type, directions, (void **)out_str16);
129
218
  }
130
219
 
131
- bool CallData::PushString32(Napi::Value value, int directions, const char32_t **out_str32)
220
+ bool CallData::PushString32(napi_value value, int directions, const char32_t **out_str32)
132
221
  {
133
222
  // Fast path
134
- if (value.IsString()) {
223
+ if (PushString32Value(value, out_str32) >= 0) {
135
224
  if (directions & 2) [[unlikely]] {
136
225
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
137
226
  return false;
138
227
  }
139
228
 
140
- PushString32Value(value, out_str32);
141
229
  return true;
142
230
  }
143
231
 
144
232
  return PushPointer(value, instance->str32_type, directions, (void **)out_str32);
145
233
  }
146
234
 
147
- Size CallData::PushStringValue(Napi::Value value, const char **out_str)
235
+ Size CallData::PushStringValue(napi_value value, const char **out_str)
148
236
  {
149
237
  Span<char> buf;
150
238
  size_t len = 0;
151
239
  napi_status status;
152
240
 
153
241
  buf.ptr = (char *)mem->heap.ptr;
154
- buf.len = std::max((Size)0, mem->heap.len - Kibibytes(32));
242
+ buf.len = mem->heap.end - mem->heap.ptr;
155
243
 
156
244
  status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
245
+ if (status == napi_string_expected)
246
+ return -1;
157
247
  K_ASSERT(status == napi_ok);
158
248
 
159
249
  len++;
160
250
 
161
251
  if (len < (size_t)buf.len) [[likely]] {
162
- mem->heap.ptr += (Size)len;
163
- mem->heap.len -= (Size)len;
252
+ mem->heap.ptr += (Size)AlignLen(len, 16);
164
253
  } else {
165
254
  status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
166
255
  K_ASSERT(status == napi_ok);
167
256
 
168
257
  len++;
169
- buf = AllocateSpan<char>(&alloc, (Size)len);
258
+ buf = AllocateSpan<char>(&mem->allocator, (Size)len);
259
+ release_alloc |= (prev_stack == mem->stack.end);
170
260
 
171
261
  status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
172
262
  K_ASSERT(status == napi_ok);
@@ -178,30 +268,31 @@ Size CallData::PushStringValue(Napi::Value value, const char **out_str)
178
268
  return (Size)len;
179
269
  }
180
270
 
181
- Size CallData::PushString16Value(Napi::Value value, const char16_t **out_str16)
271
+ Size CallData::PushString16Value(napi_value value, const char16_t **out_str16)
182
272
  {
183
273
  Span<char16_t> buf;
184
274
  size_t len = 0;
185
275
  napi_status status;
186
276
 
187
- mem->heap.ptr = AlignUp(mem->heap.ptr, 2);
188
277
  buf.ptr = (char16_t *)mem->heap.ptr;
189
- buf.len = std::max((Size)0, mem->heap.len - Kibibytes(32)) / 2;
278
+ buf.len = (mem->heap.end - mem->heap.ptr) / 2;
190
279
 
191
280
  status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
281
+ if (status == napi_string_expected)
282
+ return -1;
192
283
  K_ASSERT(status == napi_ok);
193
284
 
194
285
  len++;
195
286
 
196
287
  if (len < (size_t)buf.len) [[likely]] {
197
- mem->heap.ptr += (Size)len * 2;
198
- mem->heap.len -= (Size)len * 2;
288
+ mem->heap.ptr += (Size)AlignLen(len * 2, 16);
199
289
  } else {
200
290
  status = napi_get_value_string_utf16(env, value, nullptr, 0, &len);
201
291
  K_ASSERT(status == napi_ok);
202
292
 
203
293
  len++;
204
- buf = AllocateSpan<char16_t>(&alloc, (Size)len);
294
+ buf = AllocateSpan<char16_t>(&mem->allocator, (Size)len);
295
+ release_alloc |= (prev_stack == mem->stack.end);
205
296
 
206
297
  status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
207
298
  K_ASSERT(status == napi_ok);
@@ -213,7 +304,7 @@ Size CallData::PushString16Value(Napi::Value value, const char16_t **out_str16)
213
304
  return (Size)len;
214
305
  }
215
306
 
216
- Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
307
+ Size CallData::PushString32Value(napi_value value, const char32_t **out_str32)
217
308
  {
218
309
  static const char32_t ReplacementChar = 0x0000FFFD;
219
310
 
@@ -224,15 +315,14 @@ Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
224
315
  if (buf16.len < 0) [[unlikely]]
225
316
  return -1;
226
317
 
227
- mem->heap.ptr = AlignUp(mem->heap.ptr, 4);
228
318
  buf.ptr = (char32_t *)mem->heap.ptr;
229
- buf.len = std::max((Size)0, mem->heap.len - Kibibytes(32)) / 4;
319
+ buf.len = (mem->heap.end - mem->heap.ptr) / 4;
230
320
 
231
321
  if (buf16.len < buf.len) [[likely]] {
232
- mem->heap.ptr += buf16.len * 4;
233
- mem->heap.len -= buf16.len * 4;
322
+ mem->heap.ptr += AlignLen(buf16.len * 4, 16);
234
323
  } else {
235
- buf = AllocateSpan<char32_t>(&alloc, buf16.len);
324
+ buf = AllocateSpan<char32_t>(&mem->allocator, buf16.len);
325
+ release_alloc |= (prev_stack == mem->stack.end);
236
326
  }
237
327
 
238
328
  Size j = 0;
@@ -262,9 +352,25 @@ Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
262
352
  return j;
263
353
  }
264
354
 
265
- bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origin)
355
+ static inline napi_value GetMemberValue(napi_env env, napi_value obj, const RecordMember &member)
356
+ {
357
+ napi_value value = nullptr;
358
+
359
+ if (member.key) {
360
+ napi_value key = nullptr;
361
+ napi_get_reference_value(env, member.key, &key);
362
+
363
+ napi_get_property(env, obj, key, &value);
364
+ } else {
365
+ napi_get_named_property(env, obj, member.name, &value);
366
+ }
367
+
368
+ return value;
369
+ }
370
+
371
+ bool CallData::PushObject(napi_value obj, const TypeInfo *type, uint8_t *origin)
266
372
  {
267
- K_ASSERT(IsObject(obj));
373
+ K_ASSERT(IsObject(env, obj));
268
374
  K_ASSERT(type->primitive == PrimitiveKind::Record ||
269
375
  type->primitive == PrimitiveKind::Union);
270
376
 
@@ -273,8 +379,8 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
273
379
  if (type->primitive == PrimitiveKind::Record) {
274
380
  members = type->members;
275
381
  } else if (type->primitive == PrimitiveKind::Union) {
276
- if (CheckValueTag(obj, &MagicUnionMarker)) {
277
- MagicUnion *u = MagicUnion::Unwrap(obj);
382
+ if (CheckValueTag(env, obj, &UnionClassMarker)) {
383
+ UnionClass *u = UnionClass::Unwrap(Napi::Object(env, obj));
278
384
  const uint8_t *raw = u->GetRaw();
279
385
 
280
386
  if (u->GetType() != type) [[unlikely]] {
@@ -296,7 +402,7 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
296
402
  return false;
297
403
  }
298
404
  } else {
299
- Napi::Array properties = GetOwnPropertyNames(obj);
405
+ Napi::Array properties = GetOwnPropertyNames(env, obj);
300
406
 
301
407
  if (properties.Length() != 1 || !properties.Get(0u).IsString()) [[unlikely]] {
302
408
  ThrowError<Napi::Error>(env, "Expected object with single property name for union");
@@ -320,9 +426,34 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
320
426
 
321
427
  MemSet(origin, 0, type->size);
322
428
 
429
+ #define PUSH_INTEGER(CType) \
430
+ do { \
431
+ CType v; \
432
+ if (!TryNumber(env, value, &v)) [[unlikely]] { \
433
+ abort(); \
434
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
435
+ return false; \
436
+ } \
437
+ \
438
+ *(CType *)dest = v; \
439
+ } while (false)
440
+ #define PUSH_INTEGER_SWAP(CType) \
441
+ do { \
442
+ CType v; \
443
+ if (!TryNumber(env, value, &v)) [[unlikely]] { \
444
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
445
+ return false; \
446
+ } \
447
+ \
448
+ *(CType *)dest = ReverseBytes(v); \
449
+ } while (false)
450
+
323
451
  for (Size i = 0; i < members.len; i++) {
324
452
  const RecordMember &member = members[i];
325
- Napi::Value value = obj.Get(member.name);
453
+ napi_value value = GetMemberValue(env, obj, member);
454
+
455
+ if (GetKindOf(env, value) == napi_undefined)
456
+ continue;
326
457
 
327
458
  if (member.countedby >= 0) {
328
459
  const char *countedby = members[member.countedby].name;
@@ -331,149 +462,36 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
331
462
  return false;
332
463
  }
333
464
 
334
- if (value.IsUndefined())
335
- continue;
336
-
337
465
  uint8_t *dest = origin + member.offset;
338
466
 
339
467
  switch (member.type->primitive) {
340
468
  case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
341
469
 
342
470
  case PrimitiveKind::Bool: {
343
- if (!value.IsBoolean()) [[unlikely]] {
471
+ bool b;
472
+ napi_status status = napi_get_value_bool(env, value, &b);
473
+
474
+ if (status != napi_ok) [[unlikely]] {
344
475
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
345
476
  return false;
346
477
  }
347
478
 
348
- bool b = value.As<Napi::Boolean>();
349
479
  *(bool *)dest = b;
350
480
  } break;
351
- case PrimitiveKind::Int8: {
352
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
353
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
354
- return false;
355
- }
356
-
357
- int8_t v = GetNumber<int8_t>(value);
358
- *(int8_t *)dest = v;
359
- } break;
360
- case PrimitiveKind::UInt8: {
361
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
362
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
363
- return false;
364
- }
365
-
366
- uint8_t v = GetNumber<uint8_t>(value);
367
- *(uint8_t *)dest = v;
368
- } break;
369
- case PrimitiveKind::Int16: {
370
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
371
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
372
- return false;
373
- }
374
-
375
- int16_t v = GetNumber<int16_t>(value);
376
- *(int16_t *)dest = v;
377
- } break;
378
- case PrimitiveKind::Int16S: {
379
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
380
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
381
- return false;
382
- }
383
-
384
- int16_t v = GetNumber<int16_t>(value);
385
- *(int16_t *)dest = ReverseBytes(v);
386
- } break;
387
- case PrimitiveKind::UInt16: {
388
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
389
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
390
- return false;
391
- }
392
-
393
- uint16_t v = GetNumber<uint16_t>(value);
394
- *(uint16_t *)dest = v;
395
- } break;
396
- case PrimitiveKind::UInt16S: {
397
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
398
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
399
- return false;
400
- }
401
-
402
- uint16_t v = GetNumber<uint16_t>(value);
403
- *(uint16_t *)dest = ReverseBytes(v);
404
- } break;
405
- case PrimitiveKind::Int32: {
406
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
407
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
408
- return false;
409
- }
410
-
411
- int32_t v = GetNumber<int32_t>(value);
412
- *(int32_t *)dest = v;
413
- } break;
414
- case PrimitiveKind::Int32S: {
415
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
416
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
417
- return false;
418
- }
419
-
420
- int32_t v = GetNumber<int32_t>(value);
421
- *(int32_t *)dest = ReverseBytes(v);
422
- } break;
423
- case PrimitiveKind::UInt32: {
424
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
425
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
426
- return false;
427
- }
428
-
429
- uint32_t v = GetNumber<uint32_t>(value);
430
- *(uint32_t *)dest = v;
431
- } break;
432
- case PrimitiveKind::UInt32S: {
433
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
434
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
435
- return false;
436
- }
437
-
438
- uint32_t v = GetNumber<uint32_t>(value);
439
- *(uint32_t *)dest = ReverseBytes(v);
440
- } break;
441
- case PrimitiveKind::Int64: {
442
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
443
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
444
- return false;
445
- }
446
-
447
- int64_t v = GetNumber<int64_t>(value);
448
- *(int64_t *)dest = v;
449
- } break;
450
- case PrimitiveKind::Int64S: {
451
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
452
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
453
- return false;
454
- }
455
-
456
- int64_t v = GetNumber<int64_t>(value);
457
- *(int64_t *)dest = ReverseBytes(v);
458
- } break;
459
- case PrimitiveKind::UInt64: {
460
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
461
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
462
- return false;
463
- }
464
-
465
- uint64_t v = GetNumber<uint64_t>(value);
466
- *(uint64_t *)dest = v;
467
- } break;
468
- case PrimitiveKind::UInt64S: {
469
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
470
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
471
- return false;
472
- }
473
-
474
- uint64_t v = GetNumber<uint64_t>(value);
475
- *(uint64_t *)dest = ReverseBytes(v);
476
- } break;
481
+ case PrimitiveKind::Int8: { PUSH_INTEGER(int8_t); } break;
482
+ case PrimitiveKind::UInt8: { PUSH_INTEGER(uint8_t); } break;
483
+ case PrimitiveKind::Int16: { PUSH_INTEGER(int16_t); } break;
484
+ case PrimitiveKind::Int16S: { PUSH_INTEGER_SWAP(int16_t); } break;
485
+ case PrimitiveKind::UInt16: { PUSH_INTEGER(uint16_t); } break;
486
+ case PrimitiveKind::UInt16S: { PUSH_INTEGER_SWAP(uint16_t); } break;
487
+ case PrimitiveKind::Int32: { PUSH_INTEGER(int32_t); } break;
488
+ case PrimitiveKind::Int32S: { PUSH_INTEGER_SWAP(int32_t); } break;
489
+ case PrimitiveKind::UInt32: { PUSH_INTEGER(uint32_t); } break;
490
+ case PrimitiveKind::UInt32S: { PUSH_INTEGER_SWAP(uint32_t); } break;
491
+ case PrimitiveKind::Int64: { PUSH_INTEGER(int64_t); } break;
492
+ case PrimitiveKind::Int64S: { PUSH_INTEGER_SWAP(int64_t); } break;
493
+ case PrimitiveKind::UInt64: { PUSH_INTEGER(uint64_t); } break;
494
+ case PrimitiveKind::UInt64S: { PUSH_INTEGER_SWAP(uint64_t); } break;
477
495
  case PrimitiveKind::String: {
478
496
  const char *str;
479
497
  if (!PushString(value, 1, &str)) [[unlikely]]
@@ -504,24 +522,22 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
504
522
  } break;
505
523
  case PrimitiveKind::Record:
506
524
  case PrimitiveKind::Union: {
507
- if (!IsObject(value)) [[unlikely]] {
525
+ if (!IsObject(env, value)) [[unlikely]] {
508
526
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
509
527
  return false;
510
528
  }
511
529
 
512
- Napi::Object obj2 = value.As<Napi::Object>();
513
- if (!PushObject(obj2, member.type, dest))
530
+ if (!PushObject(value, member.type, dest))
514
531
  return false;
515
532
  } break;
516
533
  case PrimitiveKind::Array: {
517
- if (value.IsArray()) {
518
- Napi::Array array = value.As<Napi::Array>();
534
+ if (IsArray(env, value)) {
535
+ Napi::Array array = Napi::Array(env, value);
519
536
  if (!PushNormalArray(array, member.type, member.type->size, dest))
520
537
  return false;
521
- } else if (IsRawBuffer(value)) {
522
- Span<const uint8_t> buffer = GetRawBuffer(value);
538
+ } else if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
523
539
  PushBuffer(buffer, member.type, dest);
524
- } else if (value.IsString()) {
540
+ } else if (GetKindOf(env, value) == napi_string) {
525
541
  if (!PushStringArray(value, member.type, dest))
526
542
  return false;
527
543
  } else {
@@ -530,22 +546,22 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
530
546
  }
531
547
  } break;
532
548
  case PrimitiveKind::Float32: {
533
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
549
+ float f;
550
+ if (!TryNumber(env, value, &f)) [[unlikely]] {
534
551
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
535
552
  return false;
536
553
  }
537
554
 
538
- float f = GetNumber<float>(value);
539
- *(float *)dest = f;
555
+ memcpy(dest, &f, 4);
540
556
  } break;
541
557
  case PrimitiveKind::Float64: {
542
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
558
+ double d;
559
+ if (!TryNumber(env, value, &d)) [[unlikely]] {
543
560
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
544
561
  return false;
545
562
  }
546
563
 
547
- double d = GetNumber<double>(value);
548
- *(double *)dest = d;
564
+ memcpy(dest, &d, 8);
549
565
  } break;
550
566
  case PrimitiveKind::Callback: {
551
567
  void *ptr;
@@ -559,6 +575,9 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
559
575
  }
560
576
  }
561
577
 
578
+ #undef PUSH_INTEGER_SWAP
579
+ #undef PUSH_INTEGER
580
+
562
581
  return true;
563
582
  }
564
583
 
@@ -578,7 +597,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
578
597
 
579
598
  Size offset = 0;
580
599
 
581
- #define PUSH_ARRAY(Check, Expected, GetCode) \
600
+ #define PUSH_ARRAY(Code) \
582
601
  do { \
583
602
  for (Size i = 0; i < len; i++) { \
584
603
  Napi::Value value = array[(uint32_t)i]; \
@@ -586,16 +605,33 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
586
605
  offset = AlignLen(offset, ref->align); \
587
606
  uint8_t *dest = origin + offset; \
588
607
  \
589
- if (!(Check)) [[unlikely]] { \
590
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), (Expected)); \
591
- return false; \
592
- } \
593
- \
594
- GetCode \
608
+ Code \
595
609
  \
596
610
  offset += ref->size; \
597
611
  } \
598
612
  } while (false)
613
+ #define PUSH_INTEGERS(CType) \
614
+ PUSH_ARRAY({ \
615
+ CType v; \
616
+ \
617
+ if (!TryNumber(env, value, &v)) [[unlikely]] { \
618
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
619
+ return false; \
620
+ } \
621
+ \
622
+ *(CType *)dest = v; \
623
+ })
624
+ #define PUSH_INTEGERS_SWAP(CType) \
625
+ PUSH_ARRAY({ \
626
+ CType v; \
627
+ \
628
+ if (!TryNumber(env, value, &v)) [[unlikely]] { \
629
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
630
+ return false; \
631
+ } \
632
+ \
633
+ *(CType *)dest = ReverseBytes(v); \
634
+ })
599
635
 
600
636
  switch (ref->primitive) {
601
637
  case PrimitiveKind::Void: {
@@ -604,97 +640,34 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
604
640
  } break;
605
641
 
606
642
  case PrimitiveKind::Bool: {
607
- PUSH_ARRAY(value.IsBoolean(), "boolean", {
608
- bool b = value.As<Napi::Boolean>();
643
+ PUSH_ARRAY({
644
+ bool b;
645
+ napi_status status = napi_get_value_bool(env, value, &b);
646
+
647
+ if (status != napi_ok) [[unlikely]] {
648
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
649
+ return false;
650
+ }
651
+
609
652
  *(bool *)dest = b;
610
653
  });
611
654
  } break;
612
- case PrimitiveKind::Int8: {
613
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
614
- int8_t v = GetNumber<int8_t>(value);
615
- *(int8_t *)dest = v;
616
- });
617
- } break;
618
- case PrimitiveKind::UInt8: {
619
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
620
- uint8_t v = GetNumber<uint8_t>(value);
621
- *(uint8_t *)dest = v;
622
- });
623
- } break;
624
- case PrimitiveKind::Int16: {
625
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
626
- int16_t v = GetNumber<int16_t>(value);
627
- *(int16_t *)dest = v;
628
- });
629
- } break;
630
- case PrimitiveKind::Int16S: {
631
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
632
- int16_t v = GetNumber<int16_t>(value);
633
- *(int16_t *)dest = ReverseBytes(v);
634
- });
635
- } break;
636
- case PrimitiveKind::UInt16: {
637
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
638
- uint16_t v = GetNumber<uint16_t>(value);
639
- *(uint16_t *)dest = v;
640
- });
641
- } break;
642
- case PrimitiveKind::UInt16S: {
643
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
644
- uint16_t v = GetNumber<uint16_t>(value);
645
- *(uint16_t *)dest = ReverseBytes(v);
646
- });
647
- } break;
648
- case PrimitiveKind::Int32: {
649
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
650
- int32_t v = GetNumber<int32_t>(value);
651
- *(int32_t *)dest = v;
652
- });
653
- } break;
654
- case PrimitiveKind::Int32S: {
655
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
656
- int32_t v = GetNumber<int32_t>(value);
657
- *(int32_t *)dest = ReverseBytes(v);
658
- });
659
- } break;
660
- case PrimitiveKind::UInt32: {
661
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
662
- uint32_t v = GetNumber<uint32_t>(value);
663
- *(uint32_t *)dest = v;
664
- });
665
- } break;
666
- case PrimitiveKind::UInt32S: {
667
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
668
- uint32_t v = GetNumber<uint32_t>(value);
669
- *(uint32_t *)dest = ReverseBytes(v);
670
- });
671
- } break;
672
- case PrimitiveKind::Int64: {
673
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
674
- int64_t v = GetNumber<int64_t>(value);
675
- *(int64_t *)dest = v;
676
- });
677
- } break;
678
- case PrimitiveKind::Int64S: {
679
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
680
- int64_t v = GetNumber<int64_t>(value);
681
- *(int64_t *)dest = ReverseBytes(v);
682
- });
683
- } break;
684
- case PrimitiveKind::UInt64: {
685
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
686
- uint64_t v = GetNumber<uint64_t>(value);
687
- *(uint64_t *)dest = v;
688
- });
689
- } break;
690
- case PrimitiveKind::UInt64S: {
691
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
692
- uint64_t v = GetNumber<uint64_t>(value);
693
- *(uint64_t *)dest = ReverseBytes(v);
694
- });
695
- } break;
655
+ case PrimitiveKind::Int8: { PUSH_INTEGERS(int8_t); } break;
656
+ case PrimitiveKind::UInt8: { PUSH_INTEGERS(uint8_t); } break;
657
+ case PrimitiveKind::Int16: { PUSH_INTEGERS(int16_t); } break;
658
+ case PrimitiveKind::Int16S: { PUSH_INTEGERS_SWAP(int16_t); } break;
659
+ case PrimitiveKind::UInt16: { PUSH_INTEGERS(uint16_t); } break;
660
+ case PrimitiveKind::UInt16S: { PUSH_INTEGERS_SWAP(uint16_t); } break;
661
+ case PrimitiveKind::Int32: { PUSH_INTEGERS(int32_t); } break;
662
+ case PrimitiveKind::Int32S: { PUSH_INTEGERS_SWAP(int32_t); } break;
663
+ case PrimitiveKind::UInt32: { PUSH_INTEGERS(uint32_t); } break;
664
+ case PrimitiveKind::UInt32S: { PUSH_INTEGERS_SWAP(uint32_t); } break;
665
+ case PrimitiveKind::Int64: { PUSH_INTEGERS(int64_t); } break;
666
+ case PrimitiveKind::Int64S: { PUSH_INTEGERS_SWAP(int64_t); } break;
667
+ case PrimitiveKind::UInt64: { PUSH_INTEGERS(uint64_t); } break;
668
+ case PrimitiveKind::UInt64S: { PUSH_INTEGERS_SWAP(uint64_t); } break;
696
669
  case PrimitiveKind::String: {
697
- PUSH_ARRAY(true, "string", {
670
+ PUSH_ARRAY({
698
671
  const char *str;
699
672
  if (!PushString(value, 1, &str)) [[unlikely]]
700
673
  return false;
@@ -703,7 +676,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
703
676
  });
704
677
  } break;
705
678
  case PrimitiveKind::String16: {
706
- PUSH_ARRAY(true, "string", {
679
+ PUSH_ARRAY({
707
680
  const char16_t *str16;
708
681
  if (!PushString16(value, 1, &str16)) [[unlikely]]
709
682
  return false;
@@ -712,7 +685,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
712
685
  });
713
686
  } break;
714
687
  case PrimitiveKind::String32: {
715
- PUSH_ARRAY(true, "string", {
688
+ PUSH_ARRAY({
716
689
  const char32_t *str32;
717
690
  if (!PushString32(value, 1, &str32)) [[unlikely]]
718
691
  return false;
@@ -721,7 +694,12 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
721
694
  });
722
695
  } break;
723
696
  case PrimitiveKind::Pointer: {
724
- PUSH_ARRAY(true, ref->name, {
697
+ PUSH_ARRAY({
698
+ if (!IsObject(env, value)) [[unlikely]] {
699
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
700
+ return false;
701
+ }
702
+
725
703
  void *ptr;
726
704
  if (!PushPointer(value, ref, 1, &ptr)) [[unlikely]]
727
705
  return false;
@@ -731,7 +709,12 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
731
709
  } break;
732
710
  case PrimitiveKind::Record:
733
711
  case PrimitiveKind::Union: {
734
- PUSH_ARRAY(IsObject(value), "object", {
712
+ PUSH_ARRAY({
713
+ if (!IsObject(env, value)) [[unlikely]] {
714
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
715
+ return false;
716
+ }
717
+
735
718
  Napi::Object obj2 = value.As<Napi::Object>();
736
719
  if (!PushObject(obj2, ref, dest))
737
720
  return false;
@@ -749,8 +732,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
749
732
  Napi::Array array2 = value.As<Napi::Array>();
750
733
  if (!PushNormalArray(array2, ref, (Size)ref->size, dest))
751
734
  return false;
752
- } else if (IsRawBuffer(value)) {
753
- Span<const uint8_t> buffer = GetRawBuffer(value);
735
+ } else if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
754
736
  PushBuffer(buffer, ref, dest);
755
737
  } else if (value.IsString()) {
756
738
  if (!PushStringArray(value, ref, dest))
@@ -764,15 +746,25 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
764
746
  }
765
747
  } break;
766
748
  case PrimitiveKind::Float32: {
767
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
768
- float f = GetNumber<float>(value);
769
- *(float *)dest = f;
749
+ PUSH_ARRAY({
750
+ float f;
751
+ if (!TryNumber(env, value, &f)) [[unlikely]] {
752
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
753
+ return false;
754
+ }
755
+
756
+ memcpy(dest, &f, 4);
770
757
  });
771
758
  } break;
772
759
  case PrimitiveKind::Float64: {
773
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
774
- double d = GetNumber<double>(value);
775
- *(double *)dest = d;
760
+ PUSH_ARRAY({
761
+ double d;
762
+ if (!TryNumber(env, value, &d)) [[unlikely]] {
763
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
764
+ return false;
765
+ }
766
+
767
+ memcpy(dest, &d, 8);
776
768
  });
777
769
  } break;
778
770
  case PrimitiveKind::Callback: {
@@ -796,6 +788,8 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
796
788
  case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
797
789
  }
798
790
 
791
+ #undef PUSH_INTEGERS_SWAP
792
+ #undef PUSH_INTEGERS
799
793
  #undef PUSH_ARRAY
800
794
 
801
795
  return true;
@@ -834,20 +828,20 @@ void CallData::PushBuffer(Span<const uint8_t> buffer, const TypeInfo *type, uint
834
828
  #undef SWAP
835
829
  }
836
830
 
837
- bool CallData::PushStringArray(Napi::Value obj, const TypeInfo *type, uint8_t *origin)
831
+ bool CallData::PushStringArray(napi_value value, const TypeInfo *type, uint8_t *origin)
838
832
  {
839
- K_ASSERT(obj.IsString());
833
+ K_ASSERT(GetKindOf(env, value) == napi_string);
840
834
  K_ASSERT(type->primitive == PrimitiveKind::Array);
841
835
 
842
836
  size_t encoded = 0;
843
837
 
844
838
  switch (type->ref.type->primitive) {
845
839
  case PrimitiveKind::Int8: {
846
- napi_status status = napi_get_value_string_utf8(env, obj, (char *)origin, type->size, &encoded);
840
+ napi_status status = napi_get_value_string_utf8(env, value, (char *)origin, type->size, &encoded);
847
841
  K_ASSERT(status == napi_ok);
848
842
  } break;
849
843
  case PrimitiveKind::Int16: {
850
- napi_status status = napi_get_value_string_utf16(env, obj, (char16_t *)origin, type->size / 2, &encoded);
844
+ napi_status status = napi_get_value_string_utf16(env, value, (char16_t *)origin, type->size / 2, &encoded);
851
845
  K_ASSERT(status == napi_ok);
852
846
 
853
847
  encoded *= 2;
@@ -864,190 +858,164 @@ bool CallData::PushStringArray(Napi::Value obj, const TypeInfo *type, uint8_t *o
864
858
  return true;
865
859
  }
866
860
 
867
- bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directions, void **out_ptr)
861
+ bool CallData::PushPointer(napi_value value, const TypeInfo *type, int directions, void **out_ptr)
868
862
  {
869
- if (CheckValueTag(value, &CastMarker)) {
870
- Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
871
- ValueCast *cast = external.Data();
872
-
873
- value = cast->ref.Value();
874
- type = cast->type;
875
- }
876
-
877
- const TypeInfo *ref = type->ref.type;
863
+ // In the past we were naively using napi_typeof() and a switch to "reduce" branching,
864
+ // but it did not match the common types very well (so there was still various if tests),
865
+ // and it turns out that napi_typeof() is made of successive type tests anyway so it
866
+ // just made things worse. Oh, well.
878
867
 
879
- switch (value.Type()) {
880
- case napi_undefined:
881
- case napi_null: {
882
- *out_ptr = nullptr;
883
- return true;
884
- } break;
868
+ void *ptr = nullptr;
885
869
 
886
- case napi_external: {
887
- K_ASSERT(type->primitive == PrimitiveKind::Pointer ||
888
- type->primitive == PrimitiveKind::String ||
889
- type->primitive == PrimitiveKind::String16 ||
890
- type->primitive == PrimitiveKind::String32);
870
+ restart:
891
871
 
892
- if (!CheckValueTag(value, type->ref.marker) &&
893
- !CheckValueTag(value, instance->void_type) &&
894
- ref != instance->void_type) [[unlikely]]
895
- goto unexpected;
872
+ // Fast path
873
+ if (bool external = false; TryPointer(env, value, &ptr, &external)) {
874
+ if (external && CheckValueTag(env, value, &CastMarker)) {
875
+ Napi::External<ValueCast> external = Napi::External<ValueCast>(env, value);
876
+ ValueCast *cast = external.Data();
896
877
 
897
- *out_ptr = value.As<Napi::External<uint8_t>>().Data();
898
- return true;
899
- } break;
878
+ napi_get_reference_value(env, cast->ref, &value);
879
+ type = cast->type;
900
880
 
901
- case napi_object: {
902
- uint8_t *ptr = nullptr;
881
+ goto restart;
882
+ }
903
883
 
904
- OutArgument::Kind out_kind;
905
- Size out_max_len = -1;
884
+ *out_ptr = ptr;
885
+ return true;
886
+ }
906
887
 
907
- if (value.IsArray()) {
908
- Napi::Array array = value.As<Napi::Array>();
909
- Size len = PushIndirectString(array, ref, &ptr);
888
+ return PushPointerSlow(value, type, directions, out_ptr);
889
+ }
910
890
 
911
- if (len >= 0) {
912
- if (!ref->size && ref != instance->void_type) [[unlikely]] {
913
- ThrowError<Napi::TypeError>(env, "Cannot pass [string] value to %1", type->name);
914
- return false;
915
- }
916
-
917
- switch (ref->size) {
918
- default: { out_kind = OutArgument::Kind::String; } break;
919
- case 2: { out_kind = OutArgument::Kind::String16; } break;
920
- case 4: { out_kind = OutArgument::Kind::String32; } break;
921
- }
922
- out_max_len = len;
923
- } else {
924
- if (!ref->size) [[unlikely]] {
925
- ThrowError<Napi::TypeError>(env, "Cannot pass %1 value to %2, use koffi.as()",
926
- ref != instance->void_type ? "opaque" : "ambiguous", type->name);
927
- return false;
928
- }
891
+ bool CallData::PushPointerSlow(napi_value value, const TypeInfo *type, int directions, void **out_ptr)
892
+ {
893
+ const TypeInfo *ref = type->ref.type;
929
894
 
930
- Size len = (Size)array.Length();
931
- Size size = len * ref->size;
895
+ void *ptr = nullptr;
932
896
 
933
- ptr = AllocHeap(size, 16);
897
+ if (IsArray(env, value)) {
898
+ Napi::Array array = Napi::Array(env, value);
899
+ Size len = PushIndirectString(array, ref, &ptr);
934
900
 
935
- if (directions & 1) {
936
- if (!PushNormalArray(array, type, size, ptr))
937
- return false;
938
- } else {
939
- MemSet(ptr, 0, size);
940
- }
901
+ OutArgument::Kind out_kind;
902
+ Size out_max_len = -1;
941
903
 
942
- out_kind = OutArgument::Kind::Array;
943
- }
944
- } else if (IsRawBuffer(value)) {
945
- Span<uint8_t> buffer = GetRawBuffer(value);
904
+ if (len >= 0) {
905
+ if (!ref->size && ref != instance->void_type) [[unlikely]] {
906
+ ThrowError<Napi::TypeError>(env, "Cannot pass [string] value to %1", type->name);
907
+ return false;
908
+ }
946
909
 
947
- // We can fast path
948
- ptr = buffer.ptr;
949
- directions = 1;
910
+ switch (ref->size) {
911
+ default: { out_kind = OutArgument::Kind::String; } break;
912
+ case 2: { out_kind = OutArgument::Kind::String16; } break;
913
+ case 4: { out_kind = OutArgument::Kind::String32; } break;
914
+ }
915
+ out_max_len = len;
916
+ } else {
917
+ Size size = (Size)array.Length() * ref->size;
950
918
 
951
- out_kind = OutArgument::Kind::Buffer;
952
- } else if (ref->primitive == PrimitiveKind::Record ||
953
- ref->primitive == PrimitiveKind::Union) [[likely]] {
954
- Napi::Object obj = value.As<Napi::Object>();
955
- K_ASSERT(IsObject(value));
919
+ if (!ref->size) [[unlikely]] {
920
+ ThrowError<Napi::TypeError>(env, "Cannot pass %1 value to %2, use koffi.as()",
921
+ ref != instance->void_type ? "opaque" : "ambiguous", type->name);
922
+ return false;
923
+ }
956
924
 
957
- ptr = AllocHeap(ref->size, 16);
925
+ ptr = AllocHeap(size);
958
926
 
959
- if (ref->primitive == PrimitiveKind::Union &&
960
- (directions & 2) && !CheckValueTag(obj, &MagicUnionMarker)) [[unlikely]] {
961
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected union value", GetValueType(instance, obj));
927
+ if (directions & 1) {
928
+ if (!PushNormalArray(array, type, size, (uint8_t *)ptr))
962
929
  return false;
963
- }
964
-
965
- if (directions & 1) {
966
- if (!PushObject(obj, ref, ptr))
967
- return false;
968
- } else {
969
- MemSet(ptr, 0, ref->size);
970
- }
971
-
972
- out_kind = OutArgument::Kind::Object;
973
930
  } else {
974
- goto unexpected;
931
+ MemSet(ptr, 0, size);
975
932
  }
976
933
 
977
- if (directions & 2) {
978
- OutArgument *out = out_arguments.AppendDefault();
934
+ out_kind = OutArgument::Kind::Array;
935
+ }
979
936
 
980
- napi_status status = napi_create_reference(env, value, 1, &out->ref);
981
- K_ASSERT(status == napi_ok);
937
+ if (directions & 2) {
938
+ OutArgument *out = out_arguments.AppendDefault();
982
939
 
983
- out->kind = out_kind;
984
- out->ptr = ptr;
985
- out->type = ref;
986
- out->max_len = out_max_len;
987
- }
940
+ napi_status status = napi_create_reference(env, value, 1, &out->ref);
941
+ K_ASSERT(status == napi_ok);
988
942
 
989
- *out_ptr = ptr;
990
- return true;
991
- } break;
943
+ out->kind = out_kind;
944
+ out->ptr = (const uint8_t *)ptr;
945
+ out->type = ref;
946
+ out->max_len = out_max_len;
947
+ }
992
948
 
993
- case napi_string: {
994
- K_ASSERT(type->primitive == PrimitiveKind::Pointer);
949
+ *out_ptr = ptr;
950
+ return true;
951
+ } else if (ref->primitive == PrimitiveKind::Record ||
952
+ ref->primitive == PrimitiveKind::Union) [[likely]] {
953
+ K_ASSERT(IsObject(env, value));
995
954
 
996
- if (directions & 2) [[unlikely]]
997
- goto unexpected;
955
+ ptr = (void *)AllocHeap(ref->size);
998
956
 
999
- if (ref == instance->void_type) {
1000
- PushStringValue(value, (const char **)out_ptr);
1001
- return true;
1002
- } else if (ref->primitive == PrimitiveKind::Int8) {
1003
- PushStringValue(value, (const char **)out_ptr);
1004
- return true;
1005
- } else if (ref->primitive == PrimitiveKind::Int16) {
1006
- PushString16Value(value, (const char16_t **)out_ptr);
1007
- return true;
1008
- } else if (ref->primitive == PrimitiveKind::Int32) {
1009
- PushString32Value(value, (const char32_t **)out_ptr);
1010
- return true;
1011
- } else {
1012
- goto unexpected;
1013
- }
1014
- } break;
957
+ if (ref->primitive == PrimitiveKind::Union &&
958
+ (directions & 2) && !CheckValueTag(env, value, &UnionClassMarker)) [[unlikely]] {
959
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected union value", GetValueType(instance, value));
960
+ return false;
961
+ }
1015
962
 
1016
- case napi_function: {
1017
- if (type->primitive != PrimitiveKind::Callback) [[unlikely]] {
1018
- ThrowError<Napi::TypeError>(env, "Cannot pass function to type %1", type->name);
963
+ if (directions & 1) {
964
+ if (!PushObject(value, ref, (uint8_t *)ptr))
1019
965
  return false;
1020
- }
966
+ } else {
967
+ MemSet(ptr, 0, ref->size);
968
+ }
1021
969
 
1022
- Napi::Function func = value.As<Napi::Function>();
970
+ if (directions & 2) {
971
+ OutArgument *out = out_arguments.AppendDefault();
1023
972
 
1024
- void *ptr = ReserveTrampoline(type->ref.proto, func);
1025
- if (!ptr) [[unlikely]]
1026
- return false;
973
+ napi_status status = napi_create_reference(env, value, 1, &out->ref);
974
+ K_ASSERT(status == napi_ok);
1027
975
 
1028
- *out_ptr = (void *)ptr;
1029
- return true;
1030
- } break;
976
+ out->kind = OutArgument::Kind::Object;
977
+ out->ptr = (const uint8_t *)ptr;
978
+ out->type = ref;
979
+ out->max_len = -1;
980
+ }
981
+
982
+ *out_ptr = ptr;
983
+ return true;
984
+ } else if (napi_valuetype kind = GetKindOf(env, value); kind == napi_string) {
985
+ K_ASSERT(type->primitive == PrimitiveKind::Pointer);
1031
986
 
1032
- case napi_number: {
1033
- Napi::Number number = value.As<Napi::Number>();
1034
- intptr_t ptr = (intptr_t)number.Int32Value();
987
+ if (directions & 2) [[unlikely]]
988
+ goto unexpected;
1035
989
 
1036
- *out_ptr = (void *)ptr;
990
+ if (ref == instance->void_type) {
991
+ PushStringValue(value, (const char **)out_ptr);
1037
992
  return true;
1038
- } break;
1039
-
1040
- case napi_bigint: {
1041
- Napi::BigInt bigint = value.As<Napi::BigInt>();
993
+ } else if (ref->primitive == PrimitiveKind::Int8) {
994
+ PushStringValue(value, (const char **)out_ptr);
995
+ return true;
996
+ } else if (ref->primitive == PrimitiveKind::Int16) {
997
+ PushString16Value(value, (const char16_t **)out_ptr);
998
+ return true;
999
+ } else if (ref->primitive == PrimitiveKind::Int32) {
1000
+ PushString32Value(value, (const char32_t **)out_ptr);
1001
+ return true;
1002
+ } else {
1003
+ goto unexpected;
1004
+ }
1005
+ } else if (kind == napi_function) {
1006
+ if (type->primitive != PrimitiveKind::Callback) [[unlikely]] {
1007
+ ThrowError<Napi::TypeError>(env, "Cannot pass function to type %1", type->name);
1008
+ return false;
1009
+ }
1042
1010
 
1043
- bool lossless;
1044
- intptr_t ptr = (intptr_t)bigint.Int64Value(&lossless);
1011
+ Napi::Function func = Napi::Function(env, value);
1045
1012
 
1046
- *out_ptr = (void *)ptr;
1047
- return true;
1048
- } break;
1013
+ ptr = ReserveTrampoline(type->ref.proto, func);
1014
+ if (!ptr) [[unlikely]]
1015
+ return false;
1049
1016
 
1050
- default: {} break;
1017
+ *out_ptr = (void *)ptr;
1018
+ return true;
1051
1019
  }
1052
1020
 
1053
1021
  unexpected:
@@ -1055,51 +1023,47 @@ unexpected:
1055
1023
  return false;
1056
1024
  }
1057
1025
 
1058
- bool CallData::PushCallback(Napi::Value value, const TypeInfo *type, void **out_ptr)
1026
+ bool CallData::PushCallback(napi_value value, const TypeInfo *type, void **out_ptr)
1059
1027
  {
1060
- if (value.IsFunction()) {
1061
- Napi::Function func = value.As<Napi::Function>();
1028
+ void *ptr = nullptr;
1062
1029
 
1063
- void *ptr = ReserveTrampoline(type->ref.proto, func);
1064
- if (!ptr) [[unlikely]]
1065
- return false;
1030
+ restart:
1066
1031
 
1067
- *out_ptr = ptr;
1068
- } else if (CheckValueTag(value, type->ref.marker)) {
1069
- *out_ptr = value.As<Napi::External<void>>().Data();
1070
- } else if (CheckValueTag(value, &CastMarker)) {
1071
- Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
1072
- ValueCast *cast = external.Data();
1032
+ if (bool external = false; TryPointer(env, value, &ptr, &external)) {
1033
+ if (external && CheckValueTag(env, value, &CastMarker)) {
1034
+ Napi::External<ValueCast> external = Napi::External<ValueCast>(env, value);
1035
+ ValueCast *cast = external.Data();
1073
1036
 
1074
- value = cast->ref.Value();
1037
+ napi_get_reference_value(env, cast->ref, &value);
1038
+ type = cast->type;
1075
1039
 
1076
- if (!value.IsExternal() || cast->type != type)
1077
- goto unexpected;
1040
+ goto restart;
1041
+ }
1078
1042
 
1079
- *out_ptr = value.As<Napi::External<void>>().Data();
1080
- } else if (IsNullOrUndefined(value)) {
1081
- *out_ptr = nullptr;
1082
- } else {
1083
- goto unexpected;
1084
- }
1043
+ *out_ptr = ptr;
1044
+ return true;
1045
+ } else if (GetKindOf(env, value) == napi_function) {
1046
+ Napi::Function func = Napi::Function(env, value);
1085
1047
 
1086
- return true;
1048
+ ptr = ReserveTrampoline(type->ref.proto, func);
1049
+ if (!ptr) [[unlikely]]
1050
+ return false;
1051
+
1052
+ *out_ptr = ptr;
1053
+ return true;
1054
+ }
1087
1055
 
1088
- unexpected:
1089
1056
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
1090
1057
  return false;
1091
1058
  }
1092
1059
 
1093
- Size CallData::PushIndirectString(Napi::Array array, const TypeInfo *ref, uint8_t **out_ptr)
1060
+ Size CallData::PushIndirectString(Napi::Array array, const TypeInfo *ref, void **out_ptr)
1094
1061
  {
1095
1062
  if (array.Length() != 1)
1096
1063
  return -1;
1097
1064
 
1098
1065
  Napi::Value value = array[0u];
1099
1066
 
1100
- if (!value.IsString())
1101
- return -1;
1102
-
1103
1067
  if (ref == instance->void_type) {
1104
1068
  return PushStringValue(value, (const char **)out_ptr);
1105
1069
  } else if (ref->primitive == PrimitiveKind::Int8) {
@@ -1137,67 +1101,48 @@ void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func
1137
1101
 
1138
1102
  TrampolineInfo *trampoline = &shared.trampolines[idx];
1139
1103
 
1104
+ trampoline->state = 1;
1140
1105
  trampoline->instance = instance;
1141
1106
  trampoline->proto = proto;
1142
1107
  trampoline->func.Reset(func, 1);
1143
1108
  trampoline->recv.Reset();
1144
- trampoline->used = true;
1145
1109
 
1146
1110
  void *ptr = GetTrampoline(idx);
1147
1111
 
1148
1112
  return ptr;
1149
1113
  }
1150
1114
 
1151
- void CallData::DumpForward(const FunctionInfo *func) const
1152
- {
1153
- PrintLn(StdErr, "%!..+---- %1 (%2) ----%!0", func->name, CallConventionNames[(int)func->convention]);
1154
-
1155
- if (func->parameters.len) {
1156
- PrintLn(StdErr, "Parameters:");
1157
- for (Size i = 0; i < func->parameters.len; i++) {
1158
- const ParameterInfo &param = func->parameters[i];
1159
- PrintLn(StdErr, " %1 = %2 (%3)", i, param.type->name, FmtMemSize(param.type->size));
1160
- }
1161
- }
1162
- PrintLn(StdErr, "Return: %1 (%2)", func->ret.type->name, FmtMemSize(func->ret.type->size));
1163
-
1164
- Span<const uint8_t> stack = MakeSpan(mem->stack.end(), old_stack_mem.end() - mem->stack.end());
1165
- Span<const uint8_t> heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
1166
-
1167
- DumpMemory("Stack", stack);
1168
- DumpMemory("Heap", heap);
1169
- }
1170
-
1171
- bool CallData::CheckDynamicLength(Napi::Object obj, Size element, const char *countedby, Napi::Value value)
1115
+ bool CallData::CheckDynamicLength(napi_value obj, Size element, const char *countedby, napi_value value)
1172
1116
  {
1173
1117
  int64_t expected = -1;
1174
1118
  int64_t size = -1;
1175
1119
 
1176
1120
  // Get expected size
1177
1121
  {
1178
- Napi::Value by = obj.Get(countedby);
1122
+ napi_value by;
1123
+ napi_status status = napi_get_named_property(env, obj, countedby, &by);
1179
1124
 
1180
- if (!by.IsNumber() && !by.IsBigInt()) [[unlikely]] {
1125
+ if (status != napi_ok || !TryNumber(env, by, &expected)) [[unlikely]] {
1181
1126
  ThrowError<Napi::Error>(env, "Unexpected %1 value for dynamic length, expected number", GetValueType(instance, by));
1182
1127
  return false;
1183
1128
  }
1184
1129
 
1185
1130
  // If we get anywhere near overflow there are other problems to worry about.
1186
1131
  // So let's not worry about that.
1187
- expected = GetNumber<int64_t>(by) * element;
1132
+ expected *= element;
1188
1133
  }
1189
1134
 
1190
1135
  // Get actual size
1191
- if (value.IsArray()) {
1192
- Napi::Array array = value.As<Napi::Array>();
1136
+ if (IsArray(env, value)) {
1137
+ Napi::Array array = Napi::Array(env, value);
1193
1138
  size = array.Length() * element;
1194
- } else if (value.IsTypedArray()) {
1195
- Napi::TypedArray typed = value.As<Napi::TypedArray>();
1139
+ } else if (IsTypedArray(env, value)) {
1140
+ Napi::TypedArray typed = Napi::TypedArray(env, value);
1196
1141
  size = typed.ByteLength();
1197
- } else if (value.IsArrayBuffer()) {
1198
- Napi::ArrayBuffer buffer = value.As<Napi::ArrayBuffer>();
1142
+ } else if (IsArrayBuffer(env, value)) {
1143
+ Napi::ArrayBuffer buffer = Napi::ArrayBuffer(env, value);
1199
1144
  size = buffer.ByteLength();
1200
- } else if (!IsNullOrUndefined(value)) {
1145
+ } else if (!IsNullOrUndefined(env, value)) {
1201
1146
  size = element;
1202
1147
  } else {
1203
1148
  size = 0;
@@ -1211,98 +1156,13 @@ bool CallData::CheckDynamicLength(Napi::Object obj, Size element, const char *co
1211
1156
  return true;
1212
1157
  }
1213
1158
 
1214
- static inline Napi::Value GetReferenceValue(Napi::Env env, napi_ref ref)
1215
- {
1216
- napi_value value;
1217
-
1218
- napi_status status = napi_get_reference_value(env, ref, &value);
1219
- K_ASSERT(status == napi_ok);
1220
-
1221
- return Napi::Value(env, value);
1222
- }
1223
-
1224
- void CallData::PopOutArguments()
1225
- {
1226
- for (const OutArgument &out: out_arguments) {
1227
- Napi::Value value = GetReferenceValue(env, out.ref);
1228
- K_ASSERT(!value.IsEmpty());
1229
-
1230
- switch (out.kind) {
1231
- case OutArgument::Kind::Array: {
1232
- K_ASSERT(value.IsArray());
1233
-
1234
- Napi::Array array(env, value);
1235
- DecodeNormalArray(array, out.ptr, out.type);
1236
- } break;
1237
-
1238
- case OutArgument::Kind::Buffer: {
1239
- K_ASSERT(IsRawBuffer(value));
1240
-
1241
- Span<uint8_t> buffer = GetRawBuffer(value);
1242
- DecodeBuffer(buffer, out.ptr, out.type);
1243
- } break;
1244
-
1245
- case OutArgument::Kind::String: {
1246
- Napi::Array array(env, value);
1247
-
1248
- K_ASSERT(array.IsArray());
1249
- K_ASSERT(array.Length() == 1);
1250
-
1251
- Size len = strnlen((const char *)out.ptr, out.max_len);
1252
- Napi::String str = Napi::String::New(env, (const char *)out.ptr, len);
1253
-
1254
- array.Set(0u, str);
1255
- } break;
1256
-
1257
- case OutArgument::Kind::String16: {
1258
- Napi::Array array(env, value);
1259
-
1260
- K_ASSERT(array.IsArray());
1261
- K_ASSERT(array.Length() == 1);
1262
-
1263
- Size len = NullTerminatedLength((const char16_t *)out.ptr, out.max_len);
1264
- Napi::String str = Napi::String::New(env, (const char16_t *)out.ptr, len);
1265
-
1266
- array.Set(0u, str);
1267
- } break;
1268
-
1269
- case OutArgument::Kind::String32: {
1270
- Napi::Array array(env, value);
1271
-
1272
- K_ASSERT(array.IsArray());
1273
- K_ASSERT(array.Length() == 1);
1274
-
1275
- Size len = NullTerminatedLength((const char32_t *)out.ptr, out.max_len);
1276
- Napi::String str = MakeStringFromUTF32(env, (const char32_t *)out.ptr, len);
1277
-
1278
- array.Set(0u, str);
1279
- } break;
1280
-
1281
- case OutArgument::Kind::Object: {
1282
- Napi::Object obj = value.As<Napi::Object>();
1283
-
1284
- if (CheckValueTag(value, &MagicUnionMarker)) {
1285
- MagicUnion *u = MagicUnion::Unwrap(obj);
1286
- u->SetRaw(out.ptr);
1287
- } else {
1288
- DecodeObject(obj, out.ptr, out.type);
1289
- }
1290
- } break;
1291
- }
1292
- }
1293
- }
1294
-
1295
1159
  void PerformAsyncRelay(napi_env, napi_value, void *, void *udata)
1296
1160
  {
1297
1161
  RelayContext *ctx = (RelayContext *)udata;
1298
1162
  CallData *call = ctx->call;
1299
1163
 
1300
1164
  call->Relay(ctx->idx, ctx->sp);
1301
-
1302
- // This CallData was created artificially just to perform the callback. Which means the
1303
- // creator may not run on the main thread, and cannot properly destroy it, because some
1304
- // members are managed by Node.
1305
- call->Dispose();
1165
+ call->Finalize();
1306
1166
 
1307
1167
  // We're done!
1308
1168
  std::lock_guard<std::mutex> lock(ctx->mutex);