koffi 1.0.0 → 1.0.3

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 (49) hide show
  1. package/CMakeLists.txt +12 -11
  2. package/README.md +19 -17
  3. package/build/qemu/1.0.3/koffi_darwin_x64.tar.gz +0 -0
  4. package/build/qemu/1.0.3/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/build/qemu/1.0.3/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/build/qemu/1.0.3/koffi_freebsd_x64.tar.gz +0 -0
  7. package/build/qemu/1.0.3/koffi_linux_arm.tar.gz +0 -0
  8. package/build/qemu/1.0.3/koffi_linux_arm64.tar.gz +0 -0
  9. package/build/qemu/1.0.3/koffi_linux_ia32.tar.gz +0 -0
  10. package/build/qemu/1.0.3/koffi_linux_x64.tar.gz +0 -0
  11. package/build/qemu/1.0.3/koffi_win32_ia32.tar.gz +0 -0
  12. package/build/qemu/1.0.3/koffi_win32_x64.tar.gz +0 -0
  13. package/package.json +8 -4
  14. package/qemu/qemu.js +794 -0
  15. package/qemu/registry/machines.json +415 -0
  16. package/qemu/registry/sha256sum.txt +45 -0
  17. package/src/{call_arm32.cc → abi_arm32.cc} +76 -50
  18. package/src/{call_arm32_fwd.S → abi_arm32_fwd.S} +0 -0
  19. package/src/{call_arm64.cc → abi_arm64.cc} +79 -51
  20. package/src/{call_arm64_fwd.S → abi_arm64_fwd.S} +0 -0
  21. package/src/{call_x64_sysv.cc → abi_x64_sysv.cc} +77 -49
  22. package/src/{call_x64_sysv_fwd.S → abi_x64_sysv_fwd.S} +0 -0
  23. package/src/{call_x64_win.cc → abi_x64_win.cc} +71 -47
  24. package/src/{call_x64_win_fwd.asm → abi_x64_win_fwd.asm} +0 -0
  25. package/src/{call_x86.cc → abi_x86.cc} +74 -56
  26. package/src/{call_x86_fwd.S → abi_x86_fwd.S} +0 -0
  27. package/src/{call_x86_fwd.asm → abi_x86_fwd.asm} +0 -0
  28. package/src/call.cc +228 -0
  29. package/src/call.hh +96 -4
  30. package/src/ffi.cc +8 -3
  31. package/src/ffi.hh +2 -0
  32. package/src/util.cc +11 -157
  33. package/src/util.hh +0 -91
  34. package/test/CMakeLists.txt +1 -0
  35. package/test/misc.c +289 -0
  36. package/test/misc.def +3 -0
  37. package/test/misc.js +180 -0
  38. package/test/raylib.js +165 -0
  39. package/test/sqlite.js +104 -0
  40. package/build/qemu/1.0.0/koffi_darwin_x64.tar.gz +0 -0
  41. package/build/qemu/1.0.0/koffi_freebsd_arm64.tar.gz +0 -0
  42. package/build/qemu/1.0.0/koffi_freebsd_ia32.tar.gz +0 -0
  43. package/build/qemu/1.0.0/koffi_freebsd_x64.tar.gz +0 -0
  44. package/build/qemu/1.0.0/koffi_linux_arm.tar.gz +0 -0
  45. package/build/qemu/1.0.0/koffi_linux_arm64.tar.gz +0 -0
  46. package/build/qemu/1.0.0/koffi_linux_ia32.tar.gz +0 -0
  47. package/build/qemu/1.0.0/koffi_linux_x64.tar.gz +0 -0
  48. package/build/qemu/1.0.0/koffi_win32_ia32.tar.gz +0 -0
  49. package/build/qemu/1.0.0/koffi_win32_x64.tar.gz +0 -0
File without changes
@@ -87,6 +87,7 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
87
87
  case PrimitiveKind::Int64:
88
88
  case PrimitiveKind::UInt64:
89
89
  case PrimitiveKind::String:
90
+ case PrimitiveKind::String16:
90
91
  case PrimitiveKind::Pointer: {
91
92
  #ifdef __APPLE__
92
93
  if (param.variadic)
@@ -215,11 +216,8 @@ static Napi::Object PopHFA(napi_env env, const uint8_t *ptr, const TypeInfo *typ
215
216
  return obj;
216
217
  }
217
218
 
218
- Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, const Napi::CallbackInfo &info)
219
+ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
219
220
  {
220
- Napi::Env env = info.Env();
221
- CallData call(env, instance, func);
222
-
223
221
  // Sanity checks
224
222
  if (info.Length() < (uint32_t)func->parameters.len) {
225
223
  ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
@@ -232,14 +230,14 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
232
230
  uint64_t *vec_ptr = nullptr;
233
231
 
234
232
  // Return through registers unless it's too big
235
- if (RG_UNLIKELY(!call.AllocStack(func->args_size, 16, &args_ptr)))
233
+ if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
236
234
  return env.Null();
237
- if (RG_UNLIKELY(!call.AllocStack(8 * 8, 8, &vec_ptr)))
235
+ if (RG_UNLIKELY(!AllocStack(8 * 8, 8, &vec_ptr)))
238
236
  return env.Null();
239
- if (RG_UNLIKELY(!call.AllocStack(9 * 8, 8, &gpr_ptr)))
237
+ if (RG_UNLIKELY(!AllocStack(9 * 8, 8, &gpr_ptr)))
240
238
  return env.Null();
241
239
  if (func->ret.use_memory) {
242
- if (RG_UNLIKELY(!call.AllocHeap(func->ret.type->size, 16, &return_ptr)))
240
+ if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
243
241
  return env.Null();
244
242
  gpr_ptr[8] = (uint64_t)return_ptr;
245
243
  }
@@ -341,7 +339,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
341
339
  case PrimitiveKind::String: {
342
340
  const char *str;
343
341
  if (RG_LIKELY(value.IsString())) {
344
- str = call.PushString(value);
342
+ str = PushString(value);
345
343
  if (RG_UNLIKELY(!str))
346
344
  return env.Null();
347
345
  } else if (IsNullOrUndefined(value)) {
@@ -359,6 +357,27 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
359
357
  args_ptr += 8;
360
358
  }
361
359
  } break;
360
+ case PrimitiveKind::String16: {
361
+ const char16_t *str16;
362
+ if (RG_LIKELY(value.IsString())) {
363
+ str16 = PushString16(value);
364
+ if (RG_UNLIKELY(!str16))
365
+ return env.Null();
366
+ } else if (IsNullOrUndefined(value)) {
367
+ str16 = nullptr;
368
+ } else {
369
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
370
+ return env.Null();
371
+ }
372
+
373
+ if (RG_LIKELY(param.gpr_count)) {
374
+ *(gpr_ptr++) = (uint64_t)str16;
375
+ } else {
376
+ args_ptr = AlignUp(args_ptr, 8);
377
+ *(uint64_t *)args_ptr = (uint64_t)str16;
378
+ args_ptr += 8;
379
+ }
380
+ } break;
362
381
  case PrimitiveKind::Pointer: {
363
382
  uint8_t *ptr;
364
383
 
@@ -367,11 +386,11 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
367
386
  } else if (IsObject(value) && param.type->ref->primitive == PrimitiveKind::Record) {
368
387
  Napi::Object obj = value.As<Napi::Object>();
369
388
 
370
- if (RG_UNLIKELY(!call.AllocHeap(param.type->ref->size, 16, &ptr)))
389
+ if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
371
390
  return env.Null();
372
391
 
373
392
  if (param.directions & 1) {
374
- if (!call.PushObject(obj, param.type->ref, ptr))
393
+ if (!PushObject(obj, param.type->ref, ptr))
375
394
  return env.Null();
376
395
  } else {
377
396
  memset(ptr, 0, param.type->size);
@@ -412,18 +431,18 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
412
431
  if (param.gpr_count) {
413
432
  RG_ASSERT(param.type->align <= 8);
414
433
 
415
- if (!call.PushObject(obj, param.type, (uint8_t *)gpr_ptr))
434
+ if (!PushObject(obj, param.type, (uint8_t *)gpr_ptr))
416
435
  return env.Null();
417
436
  gpr_ptr += param.gpr_count;
418
437
  } else if (param.type->size) {
419
438
  args_ptr = AlignUp(args_ptr, 8);
420
- if (!call.PushObject(obj, param.type, args_ptr))
439
+ if (!PushObject(obj, param.type, args_ptr))
421
440
  return env.Null();
422
441
  args_ptr += AlignLen(param.type->size, 8);
423
442
  }
424
443
  } else {
425
444
  uint8_t *ptr;
426
- if (RG_UNLIKELY(!call.AllocHeap(param.type->size, 16, &ptr)))
445
+ if (RG_UNLIKELY(!AllocHeap(param.type->size, 16, &ptr)))
427
446
  return env.Null();
428
447
 
429
448
  if (param.gpr_count) {
@@ -437,7 +456,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
437
456
  args_ptr += 8;
438
457
  }
439
458
 
440
- if (!call.PushObject(obj, param.type, ptr))
459
+ if (!PushObject(obj, param.type, ptr))
441
460
  return env.Null();
442
461
  }
443
462
  } break;
@@ -445,30 +464,69 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
445
464
  }
446
465
 
447
466
  if (instance->debug) {
448
- call.DumpDebug();
467
+ DumpDebug();
449
468
  }
450
469
 
451
470
  #define PERFORM_CALL(Suffix) \
452
471
  ([&]() { \
453
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, call.GetSP()) \
454
- : ForwardCall ## Suffix(func->func, call.GetSP())); \
472
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, GetSP()) \
473
+ : ForwardCall ## Suffix(func->func, GetSP())); \
455
474
  PopOutArguments(out_objects); \
456
475
  return ret; \
457
476
  })()
458
477
 
459
478
  // Execute and convert return value
460
479
  switch (func->ret.type->primitive) {
480
+ case PrimitiveKind::Void: {
481
+ PERFORM_CALL(GG);
482
+ return env.Null();
483
+ } break;
484
+ case PrimitiveKind::Bool: {
485
+ X0X1Ret ret = PERFORM_CALL(GG);
486
+ return Napi::Boolean::New(env, ret.x0);
487
+ } break;
488
+ case PrimitiveKind::Int8:
489
+ case PrimitiveKind::UInt8:
490
+ case PrimitiveKind::Int16:
491
+ case PrimitiveKind::UInt16:
492
+ case PrimitiveKind::Int32:
493
+ case PrimitiveKind::UInt32: {
494
+ X0X1Ret ret = PERFORM_CALL(GG);
495
+ return Napi::Number::New(env, (double)ret.x0);
496
+ } break;
497
+ case PrimitiveKind::Int64: {
498
+ X0X1Ret ret = PERFORM_CALL(GG);
499
+ return Napi::BigInt::New(env, (int64_t)ret.x0);
500
+ } break;
501
+ case PrimitiveKind::UInt64: {
502
+ X0X1Ret ret = PERFORM_CALL(GG);
503
+ return Napi::BigInt::New(env, ret.x0);
504
+ } break;
461
505
  case PrimitiveKind::Float32: {
462
506
  float f = PERFORM_CALL(F);
463
-
464
507
  return Napi::Number::New(env, (double)f);
465
508
  } break;
466
-
467
509
  case PrimitiveKind::Float64: {
468
510
  HfaRet ret = PERFORM_CALL(DDDD);
469
-
470
511
  return Napi::Number::New(env, (double)ret.d0);
471
512
  } break;
513
+ case PrimitiveKind::String: {
514
+ X0X1Ret ret = PERFORM_CALL(GG);
515
+ return Napi::String::New(env, (const char *)ret.x0);
516
+ } break;
517
+ case PrimitiveKind::String16: {
518
+ X0X1Ret ret = PERFORM_CALL(GG);
519
+ return Napi::String::New(env, (const char16_t *)ret.x0);
520
+ } break;
521
+ case PrimitiveKind::Pointer: {
522
+ X0X1Ret ret = PERFORM_CALL(GG);
523
+ void *ptr = (void *)ret.x0;
524
+
525
+ Napi::External<void> external = Napi::External<void>::New(env, ptr);
526
+ SetValueTag(instance, external, func->ret.type);
527
+
528
+ return external;
529
+ } break;
472
530
 
473
531
  case PrimitiveKind::Record: {
474
532
  if (func->ret.gpr_count) {
@@ -496,36 +554,6 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
496
554
  return obj;
497
555
  }
498
556
  } break;
499
-
500
- default: {
501
- X0X1Ret ret = PERFORM_CALL(GG);
502
-
503
- switch (func->ret.type->primitive) {
504
- case PrimitiveKind::Void: return env.Null();
505
- case PrimitiveKind::Bool: return Napi::Boolean::New(env, ret.x0);
506
- case PrimitiveKind::Int8: return Napi::Number::New(env, (double)ret.x0);
507
- case PrimitiveKind::UInt8: return Napi::Number::New(env, (double)ret.x0);
508
- case PrimitiveKind::Int16: return Napi::Number::New(env, (double)ret.x0);
509
- case PrimitiveKind::UInt16: return Napi::Number::New(env, (double)ret.x0);
510
- case PrimitiveKind::Int32: return Napi::Number::New(env, (double)ret.x0);
511
- case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)ret.x0);
512
- case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)ret.x0);
513
- case PrimitiveKind::UInt64: return Napi::BigInt::New(env, ret.x0);
514
- case PrimitiveKind::Float32: { RG_UNREACHABLE(); } break;
515
- case PrimitiveKind::Float64: { RG_UNREACHABLE(); } break;
516
- case PrimitiveKind::String: return Napi::String::New(env, (const char *)ret.x0);
517
- case PrimitiveKind::Pointer: {
518
- void *ptr = (void *)ret.x0;
519
-
520
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
521
- SetValueTag(instance, external, func->ret.type);
522
-
523
- return external;
524
- } break;
525
-
526
- case PrimitiveKind::Record: { RG_UNREACHABLE(); } break;
527
- }
528
- } break;
529
557
  }
530
558
 
531
559
  #undef PERFORM_CALL
File without changes
@@ -93,6 +93,7 @@ static Size ClassifyType(const TypeInfo *type, Size offset, Span<RegisterClass>
93
93
  case PrimitiveKind::Int64:
94
94
  case PrimitiveKind::UInt64:
95
95
  case PrimitiveKind::String:
96
+ case PrimitiveKind::String16:
96
97
  case PrimitiveKind::Pointer: {
97
98
  classes[0] = MergeClasses(classes[0], RegisterClass::Integer);
98
99
  return 1;
@@ -180,11 +181,8 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
180
181
  return true;
181
182
  }
182
183
 
183
- Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, const Napi::CallbackInfo &info)
184
+ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
184
185
  {
185
- Napi::Env env = info.Env();
186
- CallData call(env, instance, func);
187
-
188
186
  // Sanity checks
189
187
  if (info.Length() < (uint32_t)func->parameters.len) {
190
188
  ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
@@ -197,14 +195,14 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
197
195
  uint64_t *xmm_ptr = nullptr;
198
196
 
199
197
  // Return through registers unless it's too big
200
- if (RG_UNLIKELY(!call.AllocStack(func->args_size, 16, &args_ptr)))
198
+ if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
201
199
  return env.Null();
202
- if (RG_UNLIKELY(!call.AllocStack(8 * 8, 8, &xmm_ptr)))
200
+ if (RG_UNLIKELY(!AllocStack(8 * 8, 8, &xmm_ptr)))
203
201
  return env.Null();
204
- if (RG_UNLIKELY(!call.AllocStack(6 * 8, 8, &gpr_ptr)))
202
+ if (RG_UNLIKELY(!AllocStack(6 * 8, 8, &gpr_ptr)))
205
203
  return env.Null();
206
204
  if (func->ret.use_memory) {
207
- if (RG_UNLIKELY(!call.AllocHeap(func->ret.type->size, 16, &return_ptr)))
205
+ if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
208
206
  return env.Null();
209
207
  *(uint8_t **)(gpr_ptr++) = return_ptr;
210
208
  }
@@ -294,7 +292,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
294
292
  case PrimitiveKind::String: {
295
293
  const char *str;
296
294
  if (RG_LIKELY(value.IsString())) {
297
- str = call.PushString(value);
295
+ str = PushString(value);
298
296
  if (RG_UNLIKELY(!str))
299
297
  return env.Null();
300
298
  } else if (IsNullOrUndefined(value)) {
@@ -312,6 +310,27 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
312
310
  args_ptr += 8;
313
311
  }
314
312
  } break;
313
+ case PrimitiveKind::String16: {
314
+ const char16_t *str16;
315
+ if (RG_LIKELY(value.IsString())) {
316
+ str16 = PushString16(value);
317
+ if (RG_UNLIKELY(!str16))
318
+ return env.Null();
319
+ } else if (IsNullOrUndefined(value)) {
320
+ str16 = nullptr;
321
+ } else {
322
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
323
+ return env.Null();
324
+ }
325
+
326
+ if (RG_LIKELY(param.gpr_count)) {
327
+ *(gpr_ptr++) = (uint64_t)str16;
328
+ } else {
329
+ args_ptr = AlignUp(args_ptr, 8);
330
+ *(uint64_t *)args_ptr = (uint64_t)str16;
331
+ args_ptr += 8;
332
+ }
333
+ } break;
315
334
  case PrimitiveKind::Pointer: {
316
335
  uint8_t *ptr;
317
336
 
@@ -320,11 +339,11 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
320
339
  } else if (IsObject(value) && param.type->ref->primitive == PrimitiveKind::Record) {
321
340
  Napi::Object obj = value.As<Napi::Object>();
322
341
 
323
- if (RG_UNLIKELY(!call.AllocHeap(param.type->ref->size, 16, &ptr)))
342
+ if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
324
343
  return env.Null();
325
344
 
326
345
  if (param.directions & 1) {
327
- if (!call.PushObject(obj, param.type->ref, ptr))
346
+ if (!PushObject(obj, param.type->ref, ptr))
328
347
  return env.Null();
329
348
  } else {
330
349
  memset(ptr, 0, param.type->size);
@@ -361,7 +380,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
361
380
  RG_ASSERT(param.type->size <= 16);
362
381
 
363
382
  uint64_t buf[2] = {};
364
- if (!call.PushObject(obj, param.type, (uint8_t *)buf))
383
+ if (!PushObject(obj, param.type, (uint8_t *)buf))
365
384
  return env.Null();
366
385
 
367
386
  if (param.gpr_first) {
@@ -385,7 +404,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
385
404
  }
386
405
  } else if (param.use_memory) {
387
406
  args_ptr = AlignUp(args_ptr, param.type->align);
388
- if (!call.PushObject(obj, param.type, args_ptr))
407
+ if (!PushObject(obj, param.type, args_ptr))
389
408
  return env.Null();
390
409
  args_ptr += AlignLen(param.type->size, 8);
391
410
  }
@@ -394,30 +413,69 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
394
413
  }
395
414
 
396
415
  if (instance->debug) {
397
- call.DumpDebug();
416
+ DumpDebug();
398
417
  }
399
418
 
400
419
  #define PERFORM_CALL(Suffix) \
401
420
  ([&]() { \
402
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, call.GetSP()) \
403
- : ForwardCall ## Suffix(func->func, call.GetSP())); \
421
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, GetSP()) \
422
+ : ForwardCall ## Suffix(func->func, GetSP())); \
404
423
  PopOutArguments(out_objects); \
405
424
  return ret; \
406
425
  })()
407
426
 
408
427
  // Execute and convert return value
409
428
  switch (func->ret.type->primitive) {
429
+ case PrimitiveKind::Void: {
430
+ PERFORM_CALL(GG);
431
+ return env.Null();
432
+ } break;
433
+ case PrimitiveKind::Bool: {
434
+ RaxRdxRet ret = PERFORM_CALL(GG);
435
+ return Napi::Boolean::New(env, ret.rax);
436
+ } break;
437
+ case PrimitiveKind::Int8:
438
+ case PrimitiveKind::UInt8:
439
+ case PrimitiveKind::Int16:
440
+ case PrimitiveKind::UInt16:
441
+ case PrimitiveKind::Int32:
442
+ case PrimitiveKind::UInt32: {
443
+ RaxRdxRet ret = PERFORM_CALL(GG);
444
+ return Napi::Number::New(env, (double)ret.rax);
445
+ } break;
446
+ case PrimitiveKind::Int64: {
447
+ RaxRdxRet ret = PERFORM_CALL(GG);
448
+ return Napi::BigInt::New(env, (int64_t)ret.rax);
449
+ } break;
450
+ case PrimitiveKind::UInt64: {
451
+ RaxRdxRet ret = PERFORM_CALL(GG);
452
+ return Napi::BigInt::New(env, ret.rax);
453
+ } break;
410
454
  case PrimitiveKind::Float32: {
411
455
  float f = PERFORM_CALL(F);
412
-
413
456
  return Napi::Number::New(env, (double)f);
414
457
  } break;
415
-
416
458
  case PrimitiveKind::Float64: {
417
459
  Xmm0RaxRet ret = PERFORM_CALL(DG);
418
-
419
460
  return Napi::Number::New(env, ret.xmm0);
420
461
  } break;
462
+ case PrimitiveKind::String: {
463
+ RaxRdxRet ret = PERFORM_CALL(GG);
464
+ return Napi::String::New(env, (const char *)ret.rax);
465
+ } break;
466
+ case PrimitiveKind::String16: {
467
+ RaxRdxRet ret = PERFORM_CALL(GG);
468
+ return Napi::String::New(env, (const char16_t *)ret.rax);
469
+ } break;
470
+ case PrimitiveKind::Pointer: {
471
+ RaxRdxRet ret = PERFORM_CALL(GG);
472
+ void *ptr = (void *)ret.rax;
473
+
474
+ Napi::External<void> external = Napi::External<void>::New(env, ptr);
475
+ SetValueTag(instance, external, func->ret.type);
476
+
477
+ return external;
478
+ } break;
421
479
 
422
480
  case PrimitiveKind::Record: {
423
481
  if (func->ret.gpr_first && !func->ret.xmm_count) {
@@ -450,36 +508,6 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
450
508
  return obj;
451
509
  }
452
510
  } break;
453
-
454
- default: {
455
- RaxRdxRet ret = PERFORM_CALL(GG);
456
-
457
- switch (func->ret.type->primitive) {
458
- case PrimitiveKind::Void: return env.Null();
459
- case PrimitiveKind::Bool: return Napi::Boolean::New(env, ret.rax);
460
- case PrimitiveKind::Int8: return Napi::Number::New(env, (double)ret.rax);
461
- case PrimitiveKind::UInt8: return Napi::Number::New(env, (double)ret.rax);
462
- case PrimitiveKind::Int16: return Napi::Number::New(env, (double)ret.rax);
463
- case PrimitiveKind::UInt16: return Napi::Number::New(env, (double)ret.rax);
464
- case PrimitiveKind::Int32: return Napi::Number::New(env, (double)ret.rax);
465
- case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)ret.rax);
466
- case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)ret.rax);
467
- case PrimitiveKind::UInt64: return Napi::BigInt::New(env, ret.rax);
468
- case PrimitiveKind::Float32: { RG_UNREACHABLE(); } break;
469
- case PrimitiveKind::Float64: { RG_UNREACHABLE(); } break;
470
- case PrimitiveKind::String: return Napi::String::New(env, (const char *)ret.rax);
471
- case PrimitiveKind::Pointer: {
472
- void *ptr = (void *)ret.rax;
473
-
474
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
475
- SetValueTag(instance, external, func->ret.type);
476
-
477
- return external;
478
- } break;
479
-
480
- case PrimitiveKind::Record: { RG_UNREACHABLE(); } break;
481
- }
482
- } break;
483
511
  }
484
512
 
485
513
  #undef PERFORM_CALL
File without changes
@@ -51,11 +51,8 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
51
51
  return true;
52
52
  }
53
53
 
54
- Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, const Napi::CallbackInfo &info)
54
+ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
55
55
  {
56
- Napi::Env env = info.Env();
57
- CallData call(env, instance, func);
58
-
59
56
  // Sanity checks
60
57
  if (info.Length() < (uint32_t)func->parameters.len) {
61
58
  ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
@@ -66,10 +63,10 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
66
63
  uint64_t *args_ptr = nullptr;
67
64
 
68
65
  // Pass return value in register or through memory
69
- if (RG_UNLIKELY(!call.AllocStack(func->args_size, 16, &args_ptr)))
66
+ if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
70
67
  return env.Null();
71
68
  if (!func->ret.regular) {
72
- if (RG_UNLIKELY(!call.AllocHeap(func->ret.type->size, 16, &return_ptr)))
69
+ if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
73
70
  return env.Null();
74
71
  *(uint8_t **)(args_ptr++) = return_ptr;
75
72
  }
@@ -133,7 +130,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
133
130
  case PrimitiveKind::String: {
134
131
  const char *str;
135
132
  if (RG_LIKELY(value.IsString())) {
136
- str = call.PushString(value);
133
+ str = PushString(value);
137
134
  if (RG_UNLIKELY(!str))
138
135
  return env.Null();
139
136
  } else if (IsNullOrUndefined(value)) {
@@ -145,7 +142,21 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
145
142
 
146
143
  *(const char **)(args_ptr++) = str;
147
144
  } break;
145
+ case PrimitiveKind::String16: {
146
+ const char16_t *str16;
147
+ if (RG_LIKELY(value.IsString())) {
148
+ str16 = PushString16(value);
149
+ if (RG_UNLIKELY(!str16))
150
+ return env.Null();
151
+ } else if (IsNullOrUndefined(value)) {
152
+ str16 = nullptr;
153
+ } else {
154
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
155
+ return env.Null();
156
+ }
148
157
 
158
+ *(const char16_t **)(args_ptr++) = str16;
159
+ } break;
149
160
  case PrimitiveKind::Pointer: {
150
161
  uint8_t *ptr;
151
162
 
@@ -154,11 +165,11 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
154
165
  } else if (IsObject(value) && param.type->ref->primitive == PrimitiveKind::Record) {
155
166
  Napi::Object obj = value.As<Napi::Object>();
156
167
 
157
- if (RG_UNLIKELY(!call.AllocHeap(param.type->ref->size, 16, &ptr)))
168
+ if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
158
169
  return env.Null();
159
170
 
160
171
  if (param.directions & 1) {
161
- if (!call.PushObject(obj, param.type->ref, ptr))
172
+ if (!PushObject(obj, param.type->ref, ptr))
162
173
  return env.Null();
163
174
  } else {
164
175
  memset(ptr, 0, param.type->size);
@@ -187,76 +198,89 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
187
198
  if (param.regular) {
188
199
  ptr = (uint8_t *)(args_ptr++);
189
200
  } else {
190
- if (RG_UNLIKELY(!call.AllocHeap(param.type->size, 16, &ptr)))
201
+ if (RG_UNLIKELY(!AllocHeap(param.type->size, 16, &ptr)))
191
202
  return env.Null();
192
203
  *(uint8_t **)(args_ptr++) = ptr;
193
204
  }
194
205
 
195
206
  Napi::Object obj = value.As<Napi::Object>();
196
- if (!call.PushObject(obj, param.type, ptr))
207
+ if (!PushObject(obj, param.type, ptr))
197
208
  return env.Null();
198
209
  } break;
199
210
  }
200
211
  }
201
212
 
202
213
  if (instance->debug) {
203
- call.DumpDebug();
214
+ DumpDebug();
204
215
  }
205
216
 
206
217
  #define PERFORM_CALL(Suffix) \
207
218
  ([&]() { \
208
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, call.GetSP()) \
209
- : ForwardCall ## Suffix(func->func, call.GetSP())); \
219
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, GetSP()) \
220
+ : ForwardCall ## Suffix(func->func, GetSP())); \
210
221
  PopOutArguments(out_objects); \
211
222
  return ret; \
212
223
  })()
213
224
 
214
225
  // Execute and convert return value
215
226
  switch (func->ret.type->primitive) {
227
+ case PrimitiveKind::Void: {
228
+ PERFORM_CALL(G);
229
+ return env.Null();
230
+ } break;
231
+ case PrimitiveKind::Bool: {
232
+ uint64_t rax = PERFORM_CALL(G);
233
+ return Napi::Boolean::New(env, rax);
234
+ } break;
235
+ case PrimitiveKind::Int8:
236
+ case PrimitiveKind::UInt8:
237
+ case PrimitiveKind::Int16:
238
+ case PrimitiveKind::UInt16:
239
+ case PrimitiveKind::Int32:
240
+ case PrimitiveKind::UInt32: {
241
+ uint64_t rax = PERFORM_CALL(G);
242
+ return Napi::Number::New(env, (double)rax);
243
+ } break;
244
+ case PrimitiveKind::Int64: {
245
+ uint64_t rax = PERFORM_CALL(G);
246
+ return Napi::BigInt::New(env, (int64_t)rax);
247
+ } break;
248
+ case PrimitiveKind::UInt64: {
249
+ uint64_t rax = PERFORM_CALL(G);
250
+ return Napi::BigInt::New(env, rax);
251
+ } break;
216
252
  case PrimitiveKind::Float32: {
217
253
  float f = PERFORM_CALL(F);
218
-
219
254
  return Napi::Number::New(env, (double)f);
220
255
  } break;
221
-
222
256
  case PrimitiveKind::Float64: {
223
257
  double d = PERFORM_CALL(D);
224
-
225
258
  return Napi::Number::New(env, d);
226
259
  } break;
260
+ case PrimitiveKind::String: {
261
+ uint64_t rax = PERFORM_CALL(G);
262
+ return Napi::String::New(env, (const char *)rax);
263
+ } break;
264
+ case PrimitiveKind::String16: {
265
+ uint64_t rax = PERFORM_CALL(G);
266
+ return Napi::String::New(env, (const char16_t *)rax);
267
+ } break;
268
+ case PrimitiveKind::Pointer: {
269
+ uint64_t rax = PERFORM_CALL(G);
270
+ void *ptr = (void *)rax;
271
+
272
+ Napi::External<void> external = Napi::External<void>::New(env, ptr);
273
+ SetValueTag(instance, external, func->ret.type);
274
+
275
+ return external;
276
+ } break;
227
277
 
228
- default: {
278
+ case PrimitiveKind::Record: {
229
279
  uint64_t rax = PERFORM_CALL(G);
280
+ const uint8_t *ptr = return_ptr ? return_ptr : (const uint8_t *)&rax;
230
281
 
231
- switch (func->ret.type->primitive) {
232
- case PrimitiveKind::Void: return env.Null();
233
- case PrimitiveKind::Bool: return Napi::Boolean::New(env, rax);
234
- case PrimitiveKind::Int8: return Napi::Number::New(env, (double)rax);
235
- case PrimitiveKind::UInt8: return Napi::Number::New(env, (double)rax);
236
- case PrimitiveKind::Int16: return Napi::Number::New(env, (double)rax);
237
- case PrimitiveKind::UInt16: return Napi::Number::New(env, (double)rax);
238
- case PrimitiveKind::Int32: return Napi::Number::New(env, (double)rax);
239
- case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)rax);
240
- case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)rax);
241
- case PrimitiveKind::UInt64: return Napi::BigInt::New(env, rax);
242
- case PrimitiveKind::Float32: { RG_UNREACHABLE(); } break;
243
- case PrimitiveKind::Float64: { RG_UNREACHABLE(); } break;
244
- case PrimitiveKind::String: return Napi::String::New(env, (const char *)rax);
245
- case PrimitiveKind::Pointer: {
246
- void *ptr = (void *)rax;
247
-
248
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
249
- SetValueTag(instance, external, func->ret.type);
250
-
251
- return external;
252
- } break;
253
-
254
- case PrimitiveKind::Record: {
255
- const uint8_t *ptr = return_ptr ? return_ptr : (const uint8_t *)&rax;
256
- Napi::Object obj = PopObject(env, ptr, func->ret.type);
257
- return obj;
258
- } break;
259
- }
282
+ Napi::Object obj = PopObject(env, ptr, func->ret.type);
283
+ return obj;
260
284
  } break;
261
285
  }
262
286