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
@@ -22,7 +22,7 @@ struct BackRegisters {
22
22
  double d;
23
23
  float f;
24
24
  } x87;
25
- bool x87_double;
25
+ int ret_type;
26
26
  int ret_pop;
27
27
  };
28
28
 
@@ -37,8 +37,6 @@ extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_va
37
37
  uint8_t *old_sp, Span<uint8_t> *new_stack,
38
38
  napi_value (*call)(Napi::Function *func, size_t argc, napi_value *argv));
39
39
 
40
- #include "trampolines/prototypes.inc"
41
-
42
40
  bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func)
43
41
  {
44
42
  if (!func->lib && func->convention != CallConvention::Cdecl &&
@@ -113,11 +111,10 @@ bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func)
113
111
 
114
112
  bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
115
113
  {
116
- uint32_t *args_ptr = nullptr;
114
+ uint32_t *args_ptr = AllocStack<uint32_t>(func->args_size);
117
115
  uint32_t *fast_ptr = nullptr;
118
116
 
119
- // Pass return value in register or through memory
120
- if (!AllocStack(func->args_size, 16, &args_ptr)) [[unlikely]]
117
+ if (!args_ptr) [[unlikely]]
121
118
  return false;
122
119
  if (func->fast) {
123
120
  fast_ptr = args_ptr;
@@ -128,162 +125,224 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
128
125
  *((func->ret.fast ? fast_ptr : args_ptr)++) = (uint32_t)return_ptr;
129
126
  }
130
127
 
128
+ Size i = -1;
129
+
130
+ #if defined(__GNUC__) || defined(__clang__)
131
+ static const void *const DispatchTable[] = {
132
+ #define PRIMITIVE(Name) && Name,
133
+ #include "primitives.inc"
134
+ };
135
+
136
+ #define LOOP
137
+ #define CASE(Primitive) \
138
+ do { \
139
+ PrimitiveKind next = func->primitives[++i]; \
140
+ goto *DispatchTable[(int)next]; \
141
+ } while (false); \
142
+ Primitive:
143
+ #define OR(Primitive) \
144
+ Primitive:
145
+ #else
146
+ #define LOOP \
147
+ while (++i < func->parameters.len) \
148
+ switch (func->primitives[i])
149
+ #define CASE(Primitive) \
150
+ break; \
151
+ case PrimitiveKind::Primitive:
152
+ #define OR(Primitive) \
153
+ case PrimitiveKind::Primitive:
154
+ #endif
155
+
131
156
  #define PUSH_INTEGER_32(CType) \
132
157
  do { \
133
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
158
+ const ParameterInfo &param = func->parameters[i]; \
159
+ Napi::Value value = info[param.offset]; \
160
+ \
161
+ CType v; \
162
+ if (!TryNumber(value, &v)) [[unlikely]] { \
134
163
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
135
164
  return false; \
136
165
  } \
137
166
  \
138
- CType v = GetNumber<CType>(value); \
139
167
  *((param.fast ? fast_ptr : args_ptr)++) = (uint32_t)v; \
140
168
  } while (false)
141
169
  #define PUSH_INTEGER_32_SWAP(CType) \
142
170
  do { \
143
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
171
+ const ParameterInfo &param = func->parameters[i]; \
172
+ Napi::Value value = info[param.offset]; \
173
+ \
174
+ CType v; \
175
+ if (!TryNumber(value, &v)) [[unlikely]] { \
144
176
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
145
177
  return false; \
146
178
  } \
147
179
  \
148
- CType v = GetNumber<CType>(value); \
149
180
  *((param.fast ? fast_ptr : args_ptr)++) = (uint32_t)ReverseBytes(v); \
150
181
  } while (false)
151
182
  #define PUSH_INTEGER_64(CType) \
152
183
  do { \
153
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
184
+ const ParameterInfo &param = func->parameters[i]; \
185
+ Napi::Value value = info[param.offset]; \
186
+ \
187
+ CType v; \
188
+ if (!TryNumber(value, &v)) [[unlikely]] { \
154
189
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
155
190
  return false; \
156
191
  } \
157
192
  \
158
- CType v = GetNumber<CType>(value); \
159
- \
160
193
  *(uint64_t *)args_ptr = (uint64_t)v; \
161
194
  args_ptr += 2; \
162
195
  } while (false)
163
196
  #define PUSH_INTEGER_64_SWAP(CType) \
164
197
  do { \
165
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
198
+ const ParameterInfo &param = func->parameters[i]; \
199
+ Napi::Value value = info[param.offset]; \
200
+ \
201
+ CType v; \
202
+ if (!TryNumber(value, &v)) [[unlikely]] { \
166
203
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
167
204
  return false; \
168
205
  } \
169
206
  \
170
- CType v = GetNumber<CType>(value); \
171
- \
172
207
  *(uint64_t *)args_ptr = (uint64_t)ReverseBytes(v); \
173
208
  args_ptr += 2; \
174
209
  } while (false)
175
210
 
176
- // Push arguments
177
- for (Size i = 0; i < func->parameters.len; i++) {
178
- const ParameterInfo &param = func->parameters[i];
179
- K_ASSERT(param.directions >= 1 && param.directions <= 3);
211
+ LOOP {
212
+ CASE(Void) { K_UNREACHABLE(); };
180
213
 
181
- Napi::Value value = info[param.offset];
214
+ CASE(Bool) {
215
+ const ParameterInfo &param = func->parameters[i];
216
+ Napi::Value value = info[param.offset];
182
217
 
183
- switch (param.type->primitive) {
184
- case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
218
+ bool b;
219
+ if (napi_get_value_bool(env, value, &b) != napi_ok) [[unlikely]] {
220
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
221
+ return false;
222
+ }
185
223
 
186
- case PrimitiveKind::Bool: {
187
- if (!value.IsBoolean()) [[unlikely]] {
188
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
189
- return false;
190
- }
224
+ *(bool *)((param.fast ? fast_ptr : args_ptr)++) = b;
225
+ };
226
+
227
+ CASE(Int8) { PUSH_INTEGER_32(int8_t); };
228
+ CASE(UInt8) { PUSH_INTEGER_32(uint8_t); };
229
+ CASE(Int16) { PUSH_INTEGER_32(int16_t); };
230
+ CASE(Int16S) { PUSH_INTEGER_32_SWAP(int16_t); };
231
+ CASE(UInt16) { PUSH_INTEGER_32(uint16_t); };
232
+ CASE(UInt16S) { PUSH_INTEGER_32_SWAP(uint16_t); };
233
+ CASE(Int32) { PUSH_INTEGER_32(int32_t); };
234
+ CASE(Int32S) { PUSH_INTEGER_32_SWAP(int32_t); };
235
+ CASE(UInt32) { PUSH_INTEGER_32(uint32_t); };
236
+ CASE(UInt32S) { PUSH_INTEGER_32_SWAP(uint32_t); };
237
+ CASE(Int64) { PUSH_INTEGER_64(int64_t); };
238
+ CASE(Int64S) { PUSH_INTEGER_64_SWAP(int64_t); };
239
+ CASE(UInt64) { PUSH_INTEGER_64(uint64_t); };
240
+ CASE(UInt64S) { PUSH_INTEGER_64_SWAP(uint64_t); };
241
+
242
+ CASE(String) {
243
+ const ParameterInfo &param = func->parameters[i];
244
+ Napi::Value value = info[param.offset];
191
245
 
192
- bool b = value.As<Napi::Boolean>();
193
- *(bool *)((param.fast ? fast_ptr : args_ptr)++) = b;
194
- } break;
195
- case PrimitiveKind::Int8: { PUSH_INTEGER_32(int8_t); } break;
196
- case PrimitiveKind::UInt8: { PUSH_INTEGER_32(uint8_t); } break;
197
- case PrimitiveKind::Int16: { PUSH_INTEGER_32(int16_t); } break;
198
- case PrimitiveKind::Int16S: { PUSH_INTEGER_32_SWAP(int16_t); } break;
199
- case PrimitiveKind::UInt16: { PUSH_INTEGER_32(uint16_t); } break;
200
- case PrimitiveKind::UInt16S: { PUSH_INTEGER_32_SWAP(uint16_t); } break;
201
- case PrimitiveKind::Int32: { PUSH_INTEGER_32(int32_t); } break;
202
- case PrimitiveKind::Int32S: { PUSH_INTEGER_32_SWAP(int32_t); } break;
203
- case PrimitiveKind::UInt32: { PUSH_INTEGER_32(uint32_t); } break;
204
- case PrimitiveKind::UInt32S: { PUSH_INTEGER_32_SWAP(uint32_t); } break;
205
- case PrimitiveKind::Int64: { PUSH_INTEGER_64(int64_t); } break;
206
- case PrimitiveKind::Int64S: { PUSH_INTEGER_64_SWAP(int64_t); } break;
207
- case PrimitiveKind::UInt64: { PUSH_INTEGER_64(uint64_t); } break;
208
- case PrimitiveKind::UInt64S: { PUSH_INTEGER_64_SWAP(uint64_t); } break;
209
- case PrimitiveKind::String: {
210
- const char *str;
211
- if (!PushString(value, param.directions, &str)) [[unlikely]]
212
- return false;
246
+ const char *str;
247
+ if (!PushString(value, param.directions, &str)) [[unlikely]]
248
+ return false;
213
249
 
214
- *(const char **)((param.fast ? fast_ptr : args_ptr)++) = str;
215
- } break;
216
- case PrimitiveKind::String16: {
217
- const char16_t *str16;
218
- if (!PushString16(value, param.directions, &str16)) [[unlikely]]
219
- return false;
250
+ *(const char **)((param.fast ? fast_ptr : args_ptr)++) = str;
251
+ };
252
+ CASE(String16) {
253
+ const ParameterInfo &param = func->parameters[i];
254
+ Napi::Value value = info[param.offset];
220
255
 
221
- *(const char16_t **)((param.fast ? fast_ptr : args_ptr)++) = str16;
222
- } break;
223
- case PrimitiveKind::String32: {
224
- const char32_t *str32;
225
- if (!PushString32(value, param.directions, &str32)) [[unlikely]]
226
- return false;
256
+ const char16_t *str16;
257
+ if (!PushString16(value, param.directions, &str16)) [[unlikely]]
258
+ return false;
227
259
 
228
- *(const char32_t **)((param.fast ? fast_ptr : args_ptr)++) = str32;
229
- } break;
230
- case PrimitiveKind::Pointer: {
231
- void *ptr;
232
- if (!PushPointer(value, param.type, param.directions, &ptr)) [[unlikely]]
233
- return false;
260
+ *(const char16_t **)((param.fast ? fast_ptr : args_ptr)++) = str16;
261
+ };
262
+ CASE(String32) {
263
+ const ParameterInfo &param = func->parameters[i];
264
+ Napi::Value value = info[param.offset];
234
265
 
235
- *(void **)((param.fast ? fast_ptr : args_ptr)++) = ptr;
236
- } break;
237
- case PrimitiveKind::Record:
238
- case PrimitiveKind::Union: {
239
- if (!IsObject(value)) [[unlikely]] {
240
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
241
- return false;
242
- }
266
+ const char32_t *str32;
267
+ if (!PushString32(value, param.directions, &str32)) [[unlikely]]
268
+ return false;
243
269
 
244
- Napi::Object obj = value.As<Napi::Object>();
245
-
246
- if (param.fast) {
247
- uint8_t *ptr = (uint8_t *)(fast_ptr++);
248
- if (!PushObject(obj, param.type, ptr))
249
- return false;
250
- } else {
251
- uint8_t *ptr = (uint8_t *)args_ptr;
252
- if (!PushObject(obj, param.type, ptr))
253
- return false;
254
- args_ptr = (uint32_t *)AlignUp(ptr + param.type->size, 4);
255
- }
256
- } break;
257
- case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
258
- case PrimitiveKind::Float32: {
259
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
260
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
261
- return false;
262
- }
270
+ *(const char32_t **)((param.fast ? fast_ptr : args_ptr)++) = str32;
271
+ };
263
272
 
264
- float f = GetNumber<float>(value);
265
- *(float *)((param.fast ? fast_ptr : args_ptr)++) = f;
266
- } break;
267
- case PrimitiveKind::Float64: {
268
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
269
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
270
- return false;
271
- }
273
+ CASE(Pointer) {
274
+ const ParameterInfo &param = func->parameters[i];
275
+ Napi::Value value = info[param.offset];
272
276
 
273
- double d = GetNumber<double>(value);
274
- *(double *)args_ptr = d;
275
- args_ptr += 2;
276
- } break;
277
- case PrimitiveKind::Callback: {
278
- void *ptr;
279
- if (!PushCallback(value, param.type, &ptr)) [[unlikely]]
277
+ void *ptr;
278
+ if (!PushPointer(value, param.type, param.directions, &ptr)) [[unlikely]]
279
+ return false;
280
+
281
+ *(void **)((param.fast ? fast_ptr : args_ptr)++) = ptr;
282
+ };
283
+
284
+ CASE(Record) OR(Union) {
285
+ const ParameterInfo &param = func->parameters[i];
286
+ Napi::Value value = info[param.offset];
287
+
288
+ if (!IsObject(value)) [[unlikely]] {
289
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
290
+ return false;
291
+ }
292
+
293
+ Napi::Object obj = value.As<Napi::Object>();
294
+
295
+ if (param.fast) {
296
+ uint8_t *ptr = (uint8_t *)(fast_ptr++);
297
+ if (!PushObject(obj, param.type, ptr))
280
298
  return false;
299
+ } else {
300
+ uint8_t *ptr = (uint8_t *)args_ptr;
301
+ if (!PushObject(obj, param.type, ptr))
302
+ return false;
303
+ args_ptr = (uint32_t *)AlignUp(ptr + param.type->size, 4);
304
+ }
305
+ };
306
+ CASE(Array) { K_UNREACHABLE(); };
281
307
 
282
- *(void **)((param.fast ? fast_ptr : args_ptr)++) = ptr;
283
- } break;
308
+ CASE(Float32) {
309
+ const ParameterInfo &param = func->parameters[i];
310
+ Napi::Value value = info[param.offset];
284
311
 
285
- case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
286
- }
312
+ float f;
313
+ if (!TryNumber(value, &f)) [[unlikely]] {
314
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
315
+ return false;
316
+ }
317
+
318
+ *(float *)((param.fast ? fast_ptr : args_ptr)++) = f;
319
+ };
320
+ CASE(Float64) {
321
+ const ParameterInfo &param = func->parameters[i];
322
+ Napi::Value value = info[param.offset];
323
+
324
+ double d;
325
+ if (!TryNumber(value, &d)) [[unlikely]] {
326
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
327
+ return false;
328
+ }
329
+
330
+ *(double *)args_ptr = d;
331
+ args_ptr += 2;
332
+ };
333
+
334
+ CASE(Callback) {
335
+ const ParameterInfo &param = func->parameters[i];
336
+ Napi::Value value = info[param.offset];
337
+
338
+ void *ptr;
339
+ if (!PushCallback(value, param.type, &ptr)) [[unlikely]]
340
+ return false;
341
+
342
+ *(void **)((param.fast ? fast_ptr : args_ptr)++) = ptr;
343
+ };
344
+
345
+ CASE(Prototype) { /* End loop */ };
287
346
  }
288
347
 
289
348
  #undef PUSH_INTEGER_64_SWAP
@@ -291,6 +350,10 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
291
350
  #undef PUSH_INTEGER_32_SWAP
292
351
  #undef PUSH_INTEGER_32
293
352
 
353
+ #undef OR
354
+ #undef CASE
355
+ #undef LOOP
356
+
294
357
  new_sp = mem->stack.end();
295
358
 
296
359
  return true;
@@ -416,17 +479,8 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
416
479
  case PrimitiveKind::String: return result.ptr ? Napi::String::New(env, (const char *)result.ptr) : env.Null();
417
480
  case PrimitiveKind::String16: return result.ptr ? Napi::String::New(env, (const char16_t *)result.ptr) : env.Null();
418
481
  case PrimitiveKind::String32: return result.ptr ? MakeStringFromUTF32(env, (const char32_t *)result.ptr) : env.Null();
419
- case PrimitiveKind::Pointer:
420
- case PrimitiveKind::Callback: {
421
- if (result.ptr) {
422
- Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
423
- SetValueTag(external, func->ret.type->ref.marker);
424
-
425
- return external;
426
- } else {
427
- return env.Null();
428
- }
429
- } break;
482
+ case PrimitiveKind::Pointer: return result.ptr ? WrapPointer(env, func->ret.type->ref.type, result.ptr) : env.Null();
483
+ case PrimitiveKind::Callback: return result.ptr ? WrapCallback(env, func->ret.type->ref.type, result.ptr) : env.Null();
430
484
  case PrimitiveKind::Record:
431
485
  case PrimitiveKind::Union: {
432
486
  const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
@@ -491,7 +545,7 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
491
545
  K_DEFER_N(err_guard) {
492
546
  int pop = out_reg->ret_pop;
493
547
  memset(out_reg, 0, K_SIZE(*out_reg));
494
- out_reg->x87_double = true;
548
+ out_reg->ret_type = 0;
495
549
  out_reg->ret_pop = pop;
496
550
  };
497
551
 
@@ -636,18 +690,21 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
636
690
  Napi::Value arg = str32 ? MakeStringFromUTF32(env, str32) : env.Null();
637
691
  arguments.Append(arg);
638
692
  } break;
639
- case PrimitiveKind::Pointer:
640
- case PrimitiveKind::Callback: {
693
+ case PrimitiveKind::Pointer: {
641
694
  void *ptr2 = *(void **)(args_ptr++);
642
695
 
643
- if (ptr2) {
644
- Napi::External<void> external = Napi::External<void>::New(env, ptr2);
645
- SetValueTag(external, param.type->ref.marker);
696
+ Napi::Value p = ptr2 ? WrapPointer(env, param.type->ref.type, ptr2) : env.Null();
697
+ arguments.Append(p);
646
698
 
647
- arguments.Append(external);
648
- } else {
649
- arguments.Append(env.Null());
699
+ if (param.type->dispose) {
700
+ param.type->dispose(env, param.type, ptr2);
650
701
  }
702
+ } break;
703
+ case PrimitiveKind::Callback: {
704
+ void *ptr2 = *(void **)(args_ptr++);
705
+
706
+ Napi::Value p = ptr2 ? WrapCallback(env, param.type->ref.type, ptr2) : env.Null();
707
+ arguments.Append(p);
651
708
 
652
709
  if (param.type->dispose) {
653
710
  param.type->dispose(env, param.type, ptr2);
@@ -700,59 +757,62 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
700
757
 
701
758
  #define RETURN_INTEGER_32(CType) \
702
759
  do { \
703
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
760
+ CType v; \
761
+ if (!TryNumber(value, &v)) [[unlikely]] { \
704
762
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
705
763
  return; \
706
764
  } \
707
765
  \
708
- CType v = GetNumber<CType>(value); \
709
766
  out_reg->eax = (uint32_t)v; \
767
+ out_reg->ret_type = 0; \
710
768
  } while (false)
711
769
  #define RETURN_INTEGER_32_SWAP(CType) \
712
770
  do { \
713
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
771
+ CType v; \
772
+ if (!TryNumber(value, &v)) [[unlikely]] { \
714
773
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
715
774
  return; \
716
775
  } \
717
776
  \
718
- CType v = GetNumber<CType>(value); \
719
777
  out_reg->eax = (uint32_t)ReverseBytes(v); \
778
+ out_reg->ret_type = 0; \
720
779
  } while (false)
721
780
  #define RETURN_INTEGER_64(CType) \
722
781
  do { \
723
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
782
+ CType v; \
783
+ if (!TryNumber(value, &v)) [[unlikely]] { \
724
784
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
725
785
  return; \
726
786
  } \
727
787
  \
728
- CType v = GetNumber<CType>(value); \
729
- \
730
788
  out_reg->eax = (uint32_t)((uint64_t)v >> 32); \
731
789
  out_reg->edx = (uint32_t)((uint64_t)v & 0xFFFFFFFFu); \
790
+ out_reg->ret_type = 0; \
732
791
  } while (false)
733
792
  #define RETURN_INTEGER_64_SWAP(CType) \
734
793
  do { \
735
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] { \
794
+ CType v; \
795
+ if (!TryNumber(value, &v)) [[unlikely]] { \
736
796
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
737
797
  return; \
738
798
  } \
739
799
  \
740
- CType v = ReverseBytes(GetNumber<CType>(value)); \
741
- \
742
800
  out_reg->eax = (uint32_t)((uint64_t)v >> 32); \
743
801
  out_reg->edx = (uint32_t)((uint64_t)v & 0xFFFFFFFFu); \
802
+ out_reg->ret_type = 0; \
744
803
  } while (false)
745
804
 
746
805
  switch (type->primitive) {
747
- case PrimitiveKind::Void: {} break;
806
+ case PrimitiveKind::Void: { out_reg->ret_type = 0; } break;
748
807
  case PrimitiveKind::Bool: {
749
- if (!value.IsBoolean()) [[unlikely]] {
808
+ bool b;
809
+ if (napi_get_value_bool(env, value, &b) != napi_ok) [[unlikely]] {
750
810
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
751
811
  return;
752
812
  }
753
813
 
754
- bool b = value.As<Napi::Boolean>();
755
814
  out_reg->eax = (uint32_t)b;
815
+ out_reg->ret_type = 0;
756
816
  } break;
757
817
  case PrimitiveKind::Int8: { RETURN_INTEGER_32(int8_t); } break;
758
818
  case PrimitiveKind::UInt8: { RETURN_INTEGER_32(uint8_t); } break;
@@ -774,6 +834,7 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
774
834
  return;
775
835
 
776
836
  out_reg->eax = (uint32_t)str;
837
+ out_reg->ret_type = 0;
777
838
  } break;
778
839
  case PrimitiveKind::String16: {
779
840
  const char16_t *str16;
@@ -781,6 +842,7 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
781
842
  return;
782
843
 
783
844
  out_reg->eax = (uint32_t)str16;
845
+ out_reg->ret_type = 0;
784
846
  } break;
785
847
  case PrimitiveKind::String32: {
786
848
  const char32_t *str32;
@@ -788,28 +850,15 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
788
850
  return;
789
851
 
790
852
  out_reg->eax = (uint32_t)str32;
853
+ out_reg->ret_type = 0;
791
854
  } break;
792
855
  case PrimitiveKind::Pointer: {
793
- uint8_t *ptr;
794
-
795
- if (CheckValueTag(value, type->ref.marker)) {
796
- ptr = value.As<Napi::External<uint8_t>>().Data();
797
- } else if (IsObject(value) && (type->ref.type->primitive == PrimitiveKind::Record ||
798
- type->ref.type->primitive == PrimitiveKind::Union)) {
799
- Napi::Object obj = value.As<Napi::Object>();
800
-
801
- ptr = AllocHeap(type->ref.type->size, 16);
802
-
803
- if (!PushObject(obj, type->ref.type, ptr))
804
- return;
805
- } else if (IsNullOrUndefined(value)) {
806
- ptr = nullptr;
807
- } else {
808
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
856
+ void *ptr;
857
+ if (!PushPointer(value, type, 1, &ptr)) [[unlikely]]
809
858
  return;
810
- }
811
859
 
812
860
  out_reg->eax = (uint32_t)ptr;
861
+ out_reg->ret_type = 0;
813
862
  } break;
814
863
  case PrimitiveKind::Record:
815
864
  case PrimitiveKind::Union: {
@@ -827,45 +876,37 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
827
876
  } else {
828
877
  PushObject(obj, type, (uint8_t *)&out_reg->eax);
829
878
  }
879
+
880
+ out_reg->ret_type = 0;
830
881
  } break;
831
882
  case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
832
883
  case PrimitiveKind::Float32: {
833
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
884
+ float f;
885
+ if (!TryNumber(value, &f)) [[unlikely]] {
834
886
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
835
887
  return;
836
888
  }
837
889
 
838
- out_reg->x87.f = GetNumber<float>(value);
839
- out_reg->x87_double = false;
890
+ out_reg->x87.f = f;
891
+ out_reg->ret_type = 1;
840
892
  } break;
841
893
  case PrimitiveKind::Float64: {
842
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
894
+ double d;
895
+ if (!TryNumber(value, &d)) [[unlikely]] {
843
896
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
844
897
  return;
845
898
  }
846
899
 
847
- out_reg->x87.d = GetNumber<double>(value);
848
- out_reg->x87_double = true;
900
+ out_reg->x87.d = d;
901
+ out_reg->ret_type = 2;
849
902
  } break;
850
903
  case PrimitiveKind::Callback: {
851
904
  void *ptr;
852
-
853
- if (value.IsFunction()) {
854
- Napi::Function func2 = value.As<Napi::Function>();
855
-
856
- ptr = ReserveTrampoline(type->ref.proto, func2);
857
- if (!ptr) [[unlikely]]
858
- return;
859
- } else if (CheckValueTag(value, type->ref.marker)) {
860
- ptr = value.As<Napi::External<void>>().Data();
861
- } else if (IsNullOrUndefined(value)) {
862
- ptr = nullptr;
863
- } else {
864
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
905
+ if (!PushCallback(value, type, &ptr)) [[unlikely]]
865
906
  return;
866
- }
867
907
 
868
908
  out_reg->eax = (uint32_t)ptr;
909
+ out_reg->ret_type = 0;
869
910
  } break;
870
911
 
871
912
  case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
@@ -879,12 +920,6 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
879
920
  err_guard.Disable();
880
921
  }
881
922
 
882
- void *GetTrampoline(int16_t idx, const FunctionInfo *proto)
883
- {
884
- bool x87 = IsFloat(proto->ret.type);
885
- return Trampolines[idx][x87];
886
- }
887
-
888
923
  }
889
924
 
890
925
  #endif
@@ -90,6 +90,7 @@ ForwardCallRD:
90
90
  # Depending on ABI, call convention and return value size, we need to issue ret <something>. Since ret
91
91
  # only takes an immediate value, and I prefer not to branch, the return address is moved instead according
92
92
  # to BackRegisters::ret_pop before ret is issued.
93
+ # We need to branch at the end to avoid x87 stack imbalance.
93
94
  .macro trampoline id
94
95
  .cfi_startproc
95
96
  .cfi_def_cfa esp, 4
@@ -108,36 +109,16 @@ ForwardCallRD:
108
109
  movl 44(%esp), %edx
109
110
  movl 36(%esp), %ecx
110
111
  movl %edx, 44(%esp, %ecx)
112
+ cmpl $1, 32(%esp)
113
+ je 1f
114
+ cmpl $2, 32(%esp)
115
+ je 2f
116
+ 0:
111
117
  movl 16(%esp), %eax
112
118
  movl 20(%esp), %edx
113
119
  leal 44(%esp, %ecx), %esp
114
120
  .cfi_def_cfa esp, 4
115
121
  ret
116
- .cfi_endproc
117
- .endm
118
-
119
- # This version also loads the x87 stack with the result, if need be.
120
- # We have to branch to avoid x87 stack imbalance.
121
- .macro trampoline_vec id
122
- .cfi_startproc
123
- .cfi_def_cfa esp, 4
124
- ENDBR32
125
- sub $44, %esp
126
- .cfi_def_cfa esp, 48
127
- movl $\id, 0(%esp)
128
- movl %esp, 4(%esp)
129
- leal 48(%esp), %eax
130
- movl %eax, 8(%esp)
131
- leal 16(%esp), %eax
132
- movl %eax, 12(%esp)
133
- call GetEIP
134
- addl $_GLOBAL_OFFSET_TABLE_, %ecx
135
- call *RelayCallback@GOT(%ecx)
136
- movl 44(%esp), %edx
137
- movl 36(%esp), %ecx
138
- movl %edx, 44(%esp, %ecx, 4)
139
- cmpb $0, 32(%esp)
140
- jne 2f
141
122
  1:
142
123
  flds 24(%esp)
143
124
  leal 44(%esp, %ecx), %esp