koffi 2.15.1 → 2.16.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/build/koffi/darwin_arm64/koffi.node +0 -0
  2. package/build/koffi/darwin_x64/koffi.node +0 -0
  3. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  4. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  5. package/build/koffi/freebsd_x64/koffi.node +0 -0
  6. package/build/koffi/linux_arm64/koffi.node +0 -0
  7. package/build/koffi/linux_armhf/koffi.node +0 -0
  8. package/build/koffi/linux_ia32/koffi.node +0 -0
  9. package/build/koffi/linux_loong64/koffi.node +0 -0
  10. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  11. package/build/koffi/linux_x64/koffi.node +0 -0
  12. package/build/koffi/musl_arm64/koffi.node +0 -0
  13. package/build/koffi/musl_x64/koffi.node +0 -0
  14. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  15. package/build/koffi/openbsd_x64/koffi.node +0 -0
  16. package/build/koffi/win32_arm64/koffi.node +0 -0
  17. package/build/koffi/win32_ia32/koffi.node +0 -0
  18. package/build/koffi/win32_x64/koffi.node +0 -0
  19. package/index.d.ts +11 -9
  20. package/index.js +8 -8
  21. package/indirect.js +8 -8
  22. package/package.json +1 -1
  23. package/src/koffi/src/abi_arm32.cc +222 -219
  24. package/src/koffi/src/abi_arm32_asm.S +1 -29
  25. package/src/koffi/src/abi_arm64.cc +257 -235
  26. package/src/koffi/src/abi_arm64_asm.S +1 -32
  27. package/src/koffi/src/abi_arm64_asm.asm +1 -23
  28. package/src/koffi/src/abi_loong64_asm.S +1 -25
  29. package/src/koffi/src/abi_riscv64.cc +220 -217
  30. package/src/koffi/src/abi_riscv64_asm.S +1 -25
  31. package/src/koffi/src/abi_x64_sysv.cc +196 -192
  32. package/src/koffi/src/abi_x64_sysv_asm.S +1 -31
  33. package/src/koffi/src/abi_x64_win.cc +188 -172
  34. package/src/koffi/src/abi_x64_win_asm.S +1 -19
  35. package/src/koffi/src/abi_x64_win_asm.asm +1 -21
  36. package/src/koffi/src/abi_x86.cc +224 -189
  37. package/src/koffi/src/abi_x86_asm.S +6 -25
  38. package/src/koffi/src/abi_x86_asm.asm +9 -22
  39. package/src/koffi/src/call.cc +246 -428
  40. package/src/koffi/src/call.hh +9 -8
  41. package/src/koffi/src/ffi.cc +140 -87
  42. package/src/koffi/src/ffi.hh +12 -58
  43. package/src/koffi/src/primitives.inc +39 -0
  44. package/src/koffi/src/trampolines/armasm.inc +0 -32770
  45. package/src/koffi/src/trampolines/gnu.inc +0 -24578
  46. package/src/koffi/src/trampolines/masm32.inc +0 -32770
  47. package/src/koffi/src/trampolines/masm64.inc +0 -32770
  48. package/src/koffi/src/trampolines/prototypes.inc +16385 -16385
  49. package/src/koffi/src/util.cc +149 -107
  50. package/src/koffi/src/util.hh +76 -40
@@ -52,8 +52,6 @@ extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_va
52
52
  uint8_t *old_sp, Span<uint8_t> *new_stack,
53
53
  napi_value (*call)(Napi::Function *func, size_t argc, napi_value *argv));
54
54
 
55
- #include "trampolines/prototypes.inc"
56
-
57
55
  static inline void ExpandPair(const uint8_t raw[16], int size1, int size2, uint64_t out_regs[2])
58
56
  {
59
57
  memcpy(out_regs + 0, raw, size1);
@@ -150,213 +148,258 @@ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
150
148
 
151
149
  bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
152
150
  {
153
- uint64_t *args_ptr = nullptr;
154
- uint64_t *gpr_ptr = nullptr;
155
- uint64_t *vec_ptr = nullptr;
151
+ uint64_t *vec_ptr = AllocStack<uint64_t>(16 * 8 + func->args_size);
152
+ uint64_t *gpr_ptr = vec_ptr + 8;
153
+ uint64_t *args_ptr = vec_ptr + 16;
156
154
 
157
- // Return through registers unless it's too big
158
- if (!AllocStack(func->args_size, 16, &args_ptr)) [[unlikely]]
159
- return false;
160
- if (!AllocStack(8 * 8, 8, &gpr_ptr)) [[unlikely]]
161
- return false;
162
- if (!AllocStack(8 * 8, 8, &vec_ptr)) [[unlikely]]
155
+ if (!vec_ptr) [[unlikely]]
163
156
  return false;
164
157
  if (func->ret.use_memory) {
165
158
  return_ptr = AllocHeap(func->ret.type->size, 16);
166
159
  *(uint8_t **)(gpr_ptr++) = return_ptr;
167
160
  }
168
161
 
162
+ Size i = -1;
163
+
164
+ static const void *const DispatchTable[] = {
165
+ #define PRIMITIVE(Name) && Name,
166
+ #include "primitives.inc"
167
+ };
168
+
169
+ #define LOOP
170
+ #define CASE(Primitive) \
171
+ do { \
172
+ PrimitiveKind next = func->primitives[++i]; \
173
+ goto *DispatchTable[(int)next]; \
174
+ } while (false); \
175
+ Primitive:
176
+ #define OR(Primitive) \
177
+ Primitive:
178
+
169
179
  #define PUSH_INTEGER(CType) \
170
180
  do { \
171
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
181
+ const ParameterInfo &param = func->parameters[i]; \
182
+ Napi::Value value = info[param.offset]; \
183
+ \
184
+ CType v; \
185
+ if (!TryNumber(value, &v)) [[unlikely]] { \
172
186
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
173
187
  return false; \
174
188
  } \
175
189
  \
176
- CType v = GetNumber<CType>(value); \
177
190
  *((param.gpr_count ? gpr_ptr : args_ptr)++) = (uint64_t)v; \
178
191
  } while (false)
179
192
  #define PUSH_INTEGER_SWAP(CType) \
180
193
  do { \
181
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
194
+ const ParameterInfo &param = func->parameters[i]; \
195
+ Napi::Value value = info[param.offset]; \
196
+ \
197
+ CType v; \
198
+ if (!TryNumber(value, &v)) [[unlikely]] { \
182
199
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
183
200
  return false; \
184
201
  } \
185
202
  \
186
- CType v = GetNumber<CType>(value); \
187
203
  *((param.gpr_count ? gpr_ptr : args_ptr)++) = (uint64_t)ReverseBytes(v); \
188
204
  } while (false)
189
205
 
190
206
  // Push arguments
191
- for (Size i = 0; i < func->parameters.len; i++) {
192
- const ParameterInfo &param = func->parameters[i];
193
- K_ASSERT(param.directions >= 1 && param.directions <= 3);
207
+ LOOP {
208
+ CASE(Void) { K_UNREACHABLE(); };
194
209
 
195
- Napi::Value value = info[param.offset];
210
+ CASE(Bool) {
211
+ const ParameterInfo &param = func->parameters[i];
212
+ Napi::Value value = info[param.offset];
196
213
 
197
- switch (param.type->primitive) {
198
- case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
214
+ bool b;
215
+ if (napi_get_value_bool(env, value, &b) != napi_ok) [[unlikely]] {
216
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
217
+ return false;
218
+ }
199
219
 
200
- case PrimitiveKind::Bool: {
201
- if (!value.IsBoolean()) [[unlikely]] {
202
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
203
- return false;
204
- }
220
+ *((param.gpr_count ? gpr_ptr : args_ptr)++) = (uint64_t)b;
221
+ };
222
+
223
+ CASE(Int8) { PUSH_INTEGER(int8_t); };
224
+ CASE(UInt8) { PUSH_INTEGER(uint8_t); };
225
+ CASE(Int16) { PUSH_INTEGER(int16_t); };
226
+ CASE(Int16S) { PUSH_INTEGER_SWAP(int16_t); };
227
+ CASE(UInt16) { PUSH_INTEGER(uint16_t); };
228
+ CASE(UInt16S) { PUSH_INTEGER_SWAP(uint16_t); };
229
+ CASE(Int32) { PUSH_INTEGER(int32_t); };
230
+ CASE(Int32S) { PUSH_INTEGER_SWAP(int32_t); };
231
+ CASE(UInt32) { PUSH_INTEGER(uint32_t); };
232
+ CASE(UInt32S) { PUSH_INTEGER_SWAP(uint32_t); };
233
+ CASE(Int64) { PUSH_INTEGER(int64_t); };
234
+ CASE(Int64S) { PUSH_INTEGER_SWAP(int64_t); };
235
+ CASE(UInt64) { PUSH_INTEGER(uint64_t); };
236
+ CASE(UInt64S) { PUSH_INTEGER_SWAP(uint64_t); };
237
+
238
+ CASE(String) {
239
+ const ParameterInfo &param = func->parameters[i];
240
+ Napi::Value value = info[param.offset];
205
241
 
206
- bool b = value.As<Napi::Boolean>();
207
- *((param.gpr_count ? gpr_ptr : args_ptr)++) = (uint64_t)b;
208
- } break;
209
- case PrimitiveKind::Int8: { PUSH_INTEGER(int8_t); } break;
210
- case PrimitiveKind::UInt8: { PUSH_INTEGER(uint8_t); } break;
211
- case PrimitiveKind::Int16: { PUSH_INTEGER(int16_t); } break;
212
- case PrimitiveKind::Int16S: { PUSH_INTEGER_SWAP(int16_t); } break;
213
- case PrimitiveKind::UInt16: { PUSH_INTEGER(uint16_t); } break;
214
- case PrimitiveKind::UInt16S: { PUSH_INTEGER_SWAP(uint16_t); } break;
215
- case PrimitiveKind::Int32: { PUSH_INTEGER(int32_t); } break;
216
- case PrimitiveKind::Int32S: { PUSH_INTEGER_SWAP(int32_t); } break;
217
- case PrimitiveKind::UInt32: { PUSH_INTEGER(uint32_t); } break;
218
- case PrimitiveKind::UInt32S: { PUSH_INTEGER_SWAP(uint32_t); } break;
219
- case PrimitiveKind::Int64: { PUSH_INTEGER(int64_t); } break;
220
- case PrimitiveKind::Int64S: { PUSH_INTEGER_SWAP(int64_t); } break;
221
- case PrimitiveKind::UInt64: { PUSH_INTEGER(uint64_t); } break;
222
- case PrimitiveKind::UInt64S: { PUSH_INTEGER_SWAP(uint64_t); } break;
223
- case PrimitiveKind::String: {
224
- const char *str;
225
- if (!PushString(value, param.directions, &str)) [[unlikely]]
226
- return false;
242
+ const char *str;
243
+ if (!PushString(value, param.directions, &str)) [[unlikely]]
244
+ return false;
227
245
 
228
- *(const char **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str;
229
- } break;
230
- case PrimitiveKind::String16: {
231
- const char16_t *str16;
232
- if (!PushString16(value, param.directions, &str16)) [[unlikely]]
233
- return false;
246
+ *(const char **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str;
247
+ };
248
+ CASE(String16) {
249
+ const ParameterInfo &param = func->parameters[i];
250
+ Napi::Value value = info[param.offset];
234
251
 
235
- *(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str16;
236
- } break;
237
- case PrimitiveKind::String32: {
238
- const char32_t *str32;
239
- if (!PushString32(value, param.directions, &str32)) [[unlikely]]
240
- return false;
252
+ const char16_t *str16;
253
+ if (!PushString16(value, param.directions, &str16)) [[unlikely]]
254
+ return false;
241
255
 
242
- *(const char32_t **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str32;
243
- } break;
244
- case PrimitiveKind::Pointer: {
245
- void *ptr;
246
- if (!PushPointer(value, param.type, param.directions, &ptr)) [[unlikely]]
247
- return false;
256
+ *(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str16;
257
+ };
258
+ CASE(String32) {
259
+ const ParameterInfo &param = func->parameters[i];
260
+ Napi::Value value = info[param.offset];
248
261
 
249
- *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
250
- } break;
251
- case PrimitiveKind::Record:
252
- case PrimitiveKind::Union: {
253
- if (!IsObject(value)) [[unlikely]] {
254
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
255
- return false;
256
- }
262
+ const char32_t *str32;
263
+ if (!PushString32(value, param.directions, &str32)) [[unlikely]]
264
+ return false;
257
265
 
258
- Napi::Object obj = value.As<Napi::Object>();
266
+ *(const char32_t **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str32;
267
+ };
259
268
 
260
- if (!param.use_memory) {
261
- K_ASSERT(param.type->size <= 16);
262
-
263
- uint64_t regs[2] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull };
264
- {
265
- uint8_t buf[16] = {};
266
- if (!PushObject(obj, param.type, buf))
267
- return false;
268
- ExpandPair(buf, param.reg_size[0], param.reg_size[1], regs);
269
- }
269
+ CASE(Pointer) {
270
+ const ParameterInfo &param = func->parameters[i];
271
+ Napi::Value value = info[param.offset];
270
272
 
271
- if (param.gpr_first) {
272
- *(gpr_ptr++) = regs[0];
273
- if (param.gpr_count == 2) {
274
- *(gpr_ptr++) = regs[1];
275
- } else if (param.vec_count == 1) {
276
- *(vec_ptr++) = regs[1];
277
- }
278
-
279
- args_ptr = std::max(gpr_ptr, args_ptr);
280
- } else if (param.vec_count) {
281
- *(vec_ptr++) = regs[0];
282
- if (param.vec_count == 2) {
283
- *(vec_ptr++) = regs[1];
284
- } else if (param.gpr_count == 1) {
285
- *(gpr_ptr++) = regs[1];
286
- }
287
- } else {
288
- K_ASSERT(param.type->align <= 8);
273
+ void *ptr;
274
+ if (!PushPointer(value, param.type, param.directions, &ptr)) [[unlikely]]
275
+ return false;
289
276
 
290
- MemCpy(args_ptr, regs, param.type->size);
291
- args_ptr += (param.type->size + 7) / 8;
292
- }
293
- } else {
294
- uint8_t *ptr = AllocHeap(param.type->size, 16);
277
+ *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
278
+ };
295
279
 
296
- if (param.gpr_count) {
297
- K_ASSERT(param.gpr_count == 1);
298
- K_ASSERT(param.vec_count == 0);
280
+ CASE(Record) OR(Union) {
281
+ const ParameterInfo &param = func->parameters[i];
282
+ Napi::Value value = info[param.offset];
299
283
 
300
- *(uint8_t **)(gpr_ptr++) = ptr;
301
- } else {
302
- *(uint8_t **)(args_ptr++) = ptr;
303
- }
284
+ if (!IsObject(value)) [[unlikely]] {
285
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
286
+ return false;
287
+ }
304
288
 
305
- if (!PushObject(obj, param.type, ptr))
289
+ Napi::Object obj = value.As<Napi::Object>();
290
+
291
+ if (!param.use_memory) {
292
+ K_ASSERT(param.type->size <= 16);
293
+
294
+ uint64_t regs[2] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull };
295
+ {
296
+ uint8_t buf[16] = {};
297
+ if (!PushObject(obj, param.type, buf))
306
298
  return false;
307
- }
308
- } break;
309
- case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
310
- case PrimitiveKind::Float32: {
311
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
312
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
313
- return false;
299
+ ExpandPair(buf, param.reg_size[0], param.reg_size[1], regs);
314
300
  }
315
301
 
316
- float f = GetNumber<float>(value);
302
+ if (param.gpr_first) {
303
+ *(gpr_ptr++) = regs[0];
304
+ if (param.gpr_count == 2) {
305
+ *(gpr_ptr++) = regs[1];
306
+ } else if (param.vec_count == 1) {
307
+ *(vec_ptr++) = regs[1];
308
+ }
317
309
 
318
- if (param.vec_count) [[likely]] {
319
- memset((uint8_t *)vec_ptr + 4, 0xFF, 4);
320
- *(float *)(vec_ptr++) = f;
321
- } else if (param.gpr_count) {
322
- memset((uint8_t *)gpr_ptr + 4, 0xFF, 4);
323
- *(float *)(gpr_ptr++) = f;
310
+ args_ptr = std::max(gpr_ptr, args_ptr);
311
+ } else if (param.vec_count) {
312
+ *(vec_ptr++) = regs[0];
313
+ if (param.vec_count == 2) {
314
+ *(vec_ptr++) = regs[1];
315
+ } else if (param.gpr_count == 1) {
316
+ *(gpr_ptr++) = regs[1];
317
+ }
324
318
  } else {
325
- memset(args_ptr, 0xFF, 8);
326
- *(float *)(args_ptr++) = f;
327
- }
328
- } break;
329
- case PrimitiveKind::Float64: {
330
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
331
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
332
- return false;
319
+ K_ASSERT(param.type->align <= 8);
320
+
321
+ MemCpy(args_ptr, regs, param.type->size);
322
+ args_ptr += (param.type->size + 7) / 8;
333
323
  }
324
+ } else {
325
+ uint8_t *ptr = AllocHeap(param.type->size, 16);
334
326
 
335
- double d = GetNumber<double>(value);
327
+ if (param.gpr_count) {
328
+ K_ASSERT(param.gpr_count == 1);
329
+ K_ASSERT(param.vec_count == 0);
336
330
 
337
- if (param.vec_count) [[likely]] {
338
- *(double *)(vec_ptr++) = d;
339
- } else if (param.gpr_count) {
340
- *(double *)(gpr_ptr++) = d;
331
+ *(uint8_t **)(gpr_ptr++) = ptr;
341
332
  } else {
342
- *(double *)(args_ptr++) = d;
333
+ *(uint8_t **)(args_ptr++) = ptr;
343
334
  }
344
- } break;
345
- case PrimitiveKind::Callback: {
346
- void *ptr;
347
- if (!PushCallback(value, param.type, &ptr)) [[unlikely]]
335
+
336
+ if (!PushObject(obj, param.type, ptr))
348
337
  return false;
338
+ }
339
+ };
340
+ CASE(Array) { K_UNREACHABLE(); };
349
341
 
350
- *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
351
- } break;
342
+ CASE(Float32) {
343
+ const ParameterInfo &param = func->parameters[i];
344
+ Napi::Value value = info[param.offset];
352
345
 
353
- case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
354
- }
346
+ float f;
347
+ if (!TryNumber(value, &f)) [[unlikely]] {
348
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
349
+ return false;
350
+ }
351
+
352
+ if (param.vec_count) [[likely]] {
353
+ memset((uint8_t *)vec_ptr + 4, 0xFF, 4);
354
+ *(float *)(vec_ptr++) = f;
355
+ } else if (param.gpr_count) {
356
+ memset((uint8_t *)gpr_ptr + 4, 0xFF, 4);
357
+ *(float *)(gpr_ptr++) = f;
358
+ } else {
359
+ memset(args_ptr, 0xFF, 8);
360
+ *(float *)(args_ptr++) = f;
361
+ }
362
+ };
363
+ CASE(Float64) {
364
+ const ParameterInfo &param = func->parameters[i];
365
+ Napi::Value value = info[param.offset];
366
+
367
+ double d;
368
+ if (!TryNumber(value, &d)) [[unlikely]] {
369
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
370
+ return false;
371
+ }
372
+
373
+ if (param.vec_count) [[likely]] {
374
+ *(double *)(vec_ptr++) = d;
375
+ } else if (param.gpr_count) {
376
+ *(double *)(gpr_ptr++) = d;
377
+ } else {
378
+ *(double *)(args_ptr++) = d;
379
+ }
380
+ };
381
+
382
+ CASE(Callback) {
383
+ const ParameterInfo &param = func->parameters[i];
384
+ Napi::Value value = info[param.offset];
385
+
386
+ void *ptr;
387
+ if (!PushCallback(value, param.type, &ptr)) [[unlikely]]
388
+ return false;
389
+
390
+ *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
391
+ };
392
+
393
+ CASE(Prototype) { /* End loop */ };
355
394
  }
356
395
 
357
396
  #undef PUSH_INTEGER_SWAP
358
397
  #undef PUSH_INTEGER
359
398
 
399
+ #undef OR
400
+ #undef CASE
401
+ #undef LOOP
402
+
360
403
  new_sp = mem->stack.end();
361
404
 
362
405
  return true;
@@ -450,17 +493,8 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
450
493
  case PrimitiveKind::String: return result.ptr ? Napi::String::New(env, (const char *)result.ptr) : env.Null();
451
494
  case PrimitiveKind::String16: return result.ptr ? Napi::String::New(env, (const char16_t *)result.ptr) : env.Null();
452
495
  case PrimitiveKind::String32: return result.ptr ? MakeStringFromUTF32(env, (const char32_t *)result.ptr) : env.Null();
453
- case PrimitiveKind::Pointer:
454
- case PrimitiveKind::Callback: {
455
- if (result.ptr) {
456
- Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
457
- SetValueTag(external, func->ret.type->ref.marker);
458
-
459
- return external;
460
- } else {
461
- return env.Null();
462
- }
463
- } break;
496
+ case PrimitiveKind::Pointer: return result.ptr ? WrapPointer(env, func->ret.type->ref.type, result.ptr) : env.Null();
497
+ case PrimitiveKind::Callback: return result.ptr ? WrapCallback(env, func->ret.type->ref.type, result.ptr) : env.Null();
464
498
  case PrimitiveKind::Record:
465
499
  case PrimitiveKind::Union: {
466
500
  if (return_ptr) {
@@ -640,18 +674,21 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool switch_
640
674
  Napi::Value arg = str32 ? MakeStringFromUTF32(env, str32) : env.Null();
641
675
  arguments.Append(arg);
642
676
  } break;
643
- case PrimitiveKind::Pointer:
644
- case PrimitiveKind::Callback: {
677
+ case PrimitiveKind::Pointer: {
645
678
  void *ptr2 = *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++);
646
679
 
647
- if (ptr2) {
648
- Napi::External<void> external = Napi::External<void>::New(env, ptr2);
649
- SetValueTag(external, param.type->ref.marker);
680
+ Napi::Value p = ptr2 ? WrapPointer(env, param.type->ref.type, ptr2) : env.Null();
681
+ arguments.Append(p);
650
682
 
651
- arguments.Append(external);
652
- } else {
653
- arguments.Append(env.Null());
683
+ if (param.type->dispose) {
684
+ param.type->dispose(env, param.type, ptr2);
654
685
  }
686
+ } break;
687
+ case PrimitiveKind::Callback: {
688
+ void *ptr2 = *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++);
689
+
690
+ Napi::Value p = ptr2 ? WrapCallback(env, param.type->ref.type, ptr2) : env.Null();
691
+ arguments.Append(p);
655
692
 
656
693
  if (param.type->dispose) {
657
694
  param.type->dispose(env, param.type, ptr2);
@@ -737,22 +774,22 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool switch_
737
774
 
738
775
  #define RETURN_INTEGER(CType) \
739
776
  do { \
740
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
777
+ CType v; \
778
+ if (!TryNumber(value, &v)) [[unlikely]] { \
741
779
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
742
780
  return; \
743
781
  } \
744
782
  \
745
- CType v = GetNumber<CType>(value); \
746
783
  out_reg->a0 = (uint64_t)v; \
747
784
  } while (false)
748
785
  #define RETURN_INTEGER_SWAP(CType) \
749
786
  do { \
750
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
787
+ CType v; \
788
+ if (!TryNumber(value, &v)) [[unlikely]] { \
751
789
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
752
790
  return; \
753
791
  } \
754
792
  \
755
- CType v = GetNumber<CType>(value); \
756
793
  out_reg->a0 = (uint64_t)ReverseBytes(v); \
757
794
  } while (false)
758
795
 
@@ -760,12 +797,12 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool switch_
760
797
  switch (type->primitive) {
761
798
  case PrimitiveKind::Void: {} break;
762
799
  case PrimitiveKind::Bool: {
763
- if (!value.IsBoolean()) [[unlikely]] {
800
+ bool b;
801
+ if (napi_get_value_bool(env, value, &b) != napi_ok) [[unlikely]] {
764
802
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
765
803
  return;
766
804
  }
767
805
 
768
- bool b = value.As<Napi::Boolean>();
769
806
  out_reg->a0 = (uint64_t)b;
770
807
  } break;
771
808
  case PrimitiveKind::Int8: { RETURN_INTEGER(int8_t); } break;
@@ -804,24 +841,9 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool switch_
804
841
  out_reg->a0 = (uint64_t)str32;
805
842
  } break;
806
843
  case PrimitiveKind::Pointer: {
807
- uint8_t *ptr;
808
-
809
- if (CheckValueTag(value, type->ref.marker)) {
810
- ptr = value.As<Napi::External<uint8_t>>().Data();
811
- } else if (IsObject(value) && (type->ref.type->primitive == PrimitiveKind::Record ||
812
- type->ref.type->primitive == PrimitiveKind::Union)) {
813
- Napi::Object obj = value.As<Napi::Object>();
814
-
815
- ptr = AllocHeap(type->ref.type->size, 16);
816
-
817
- if (!PushObject(obj, type->ref.type, ptr))
818
- return;
819
- } else if (IsNullOrUndefined(value)) {
820
- ptr = nullptr;
821
- } else {
822
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
844
+ void *ptr;
845
+ if (!PushPointer(value, type, 1, &ptr)) [[unlikely]]
823
846
  return;
824
- }
825
847
 
826
848
  out_reg->a0 = (uint64_t)ptr;
827
849
  } break;
@@ -864,41 +886,28 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool switch_
864
886
  } break;
865
887
  case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
866
888
  case PrimitiveKind::Float32: {
867
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
889
+ float f;
890
+ if (!TryNumber(value, &f)) [[unlikely]] {
868
891
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
869
892
  return;
870
893
  }
871
894
 
872
- float f = GetNumber<float>(value);
873
895
  memset((uint8_t *)&out_reg->fa0 + 4, 0xFF, 4);
874
896
  memcpy(&out_reg->fa0, &f, 4);
875
897
  } break;
876
898
  case PrimitiveKind::Float64: {
877
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
899
+ double d;
900
+ if (!TryNumber(value, &d)) [[unlikely]] {
878
901
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
879
902
  return;
880
903
  }
881
904
 
882
- double d = GetNumber<double>(value);
883
905
  out_reg->fa0 = d;
884
906
  } break;
885
907
  case PrimitiveKind::Callback: {
886
908
  void *ptr;
887
-
888
- if (value.IsFunction()) {
889
- Napi::Function func2 = value.As<Napi::Function>();
890
-
891
- ptr = ReserveTrampoline(type->ref.proto, func2);
892
- if (!ptr) [[unlikely]]
893
- return;
894
- } else if (CheckValueTag(value, type->ref.marker)) {
895
- ptr = value.As<Napi::External<void>>().Data();
896
- } else if (IsNullOrUndefined(value)) {
897
- ptr = nullptr;
898
- } else {
899
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
909
+ if (!PushCallback(value, type, &ptr)) [[unlikely]]
900
910
  return;
901
- }
902
911
 
903
912
  out_reg->a0 = (uint64_t)ptr;
904
913
  } break;
@@ -912,12 +921,6 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool switch_
912
921
  err_guard.Disable();
913
922
  }
914
923
 
915
- void *GetTrampoline(int16_t idx, const FunctionInfo *proto)
916
- {
917
- bool fp = proto->forward_fp || proto->ret.vec_count;
918
- return Trampolines[idx][fp];
919
- }
920
-
921
924
  }
922
925
 
923
926
  #endif
@@ -131,36 +131,12 @@ ForwardCallXDD:
131
131
  .global RelayCallback
132
132
  .global CallSwitchStack
133
133
 
134
- # First, make a copy of the GPR argument registers (a0 to a7).
134
+ # First, make a copy of argument registers.
135
135
  # Then call the C function RelayCallback with the following arguments:
136
136
  # static trampoline ID, a pointer to the saved GPR array, a pointer to the stack
137
137
  # arguments of this call, and a pointer to a struct that will contain the result registers.
138
138
  # After the call, simply load these registers from the output struct.
139
139
  .macro trampoline id
140
- addi sp, sp, -176
141
- sd ra, 0(sp)
142
- sd a0, 8(sp)
143
- sd a1, 16(sp)
144
- sd a2, 24(sp)
145
- sd a3, 32(sp)
146
- sd a4, 40(sp)
147
- sd a5, 48(sp)
148
- sd a6, 56(sp)
149
- sd a7, 64(sp)
150
- li a0, \id
151
- addi a1, sp, 8
152
- addi a2, sp, 176
153
- addi a3, sp, 136
154
- call RelayCallback
155
- ld ra, 0(sp)
156
- ld a0, 136(sp)
157
- ld a1, 144(sp)
158
- addi sp, sp, 176
159
- ret
160
- .endm
161
-
162
- # Same thing, but also forwards the floating-point argument registers and loads them at the end.
163
- .macro trampoline_vec id
164
140
  addi sp, sp, -176
165
141
  sd ra, 0(sp)
166
142
  sd a0, 8(sp)