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
@@ -24,6 +24,8 @@ struct RelayContext {
24
24
  bool done = false;
25
25
  };
26
26
 
27
+ #include "trampolines/prototypes.inc"
28
+
27
29
  CallData::CallData(Napi::Env env, InstanceData *instance, InstanceMemory *mem)
28
30
  : env(env), instance(instance),
29
31
  mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
@@ -343,6 +345,29 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
343
345
 
344
346
  MemSet(origin, 0, type->size);
345
347
 
348
+ #define PUSH_NUMBER(CType) \
349
+ do { \
350
+ CType v; \
351
+ \
352
+ if (!TryNumber(value, &v)) [[unlikely]] { \
353
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
354
+ return false; \
355
+ } \
356
+ \
357
+ *(CType *)dest = v; \
358
+ } while (false)
359
+ #define PUSH_NUMBER_SWAP(CType) \
360
+ do { \
361
+ CType v; \
362
+ \
363
+ if (!TryNumber(value, &v)) [[unlikely]] { \
364
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
365
+ return false; \
366
+ } \
367
+ \
368
+ *(CType *)dest = ReverseBytes(v); \
369
+ } while (false)
370
+
346
371
  for (Size i = 0; i < members.len; i++) {
347
372
  const RecordMember &member = members[i];
348
373
  Napi::Value value = obj.Get(member.name);
@@ -363,140 +388,30 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
363
388
  case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
364
389
 
365
390
  case PrimitiveKind::Bool: {
366
- if (!value.IsBoolean()) [[unlikely]] {
391
+ bool b;
392
+ napi_status status = napi_get_value_bool(env, value, &b);
393
+
394
+ if (status != napi_ok) [[unlikely]] {
367
395
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
368
396
  return false;
369
397
  }
370
398
 
371
- bool b = value.As<Napi::Boolean>();
372
399
  *(bool *)dest = b;
373
400
  } break;
374
- case PrimitiveKind::Int8: {
375
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
376
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
377
- return false;
378
- }
379
-
380
- int8_t v = GetNumber<int8_t>(value);
381
- *(int8_t *)dest = v;
382
- } break;
383
- case PrimitiveKind::UInt8: {
384
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
385
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
386
- return false;
387
- }
388
-
389
- uint8_t v = GetNumber<uint8_t>(value);
390
- *(uint8_t *)dest = v;
391
- } break;
392
- case PrimitiveKind::Int16: {
393
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
394
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
395
- return false;
396
- }
397
-
398
- int16_t v = GetNumber<int16_t>(value);
399
- *(int16_t *)dest = v;
400
- } break;
401
- case PrimitiveKind::Int16S: {
402
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
403
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
404
- return false;
405
- }
406
-
407
- int16_t v = GetNumber<int16_t>(value);
408
- *(int16_t *)dest = ReverseBytes(v);
409
- } break;
410
- case PrimitiveKind::UInt16: {
411
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
412
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
413
- return false;
414
- }
415
-
416
- uint16_t v = GetNumber<uint16_t>(value);
417
- *(uint16_t *)dest = v;
418
- } break;
419
- case PrimitiveKind::UInt16S: {
420
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
421
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
422
- return false;
423
- }
424
-
425
- uint16_t v = GetNumber<uint16_t>(value);
426
- *(uint16_t *)dest = ReverseBytes(v);
427
- } break;
428
- case PrimitiveKind::Int32: {
429
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
430
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
431
- return false;
432
- }
433
-
434
- int32_t v = GetNumber<int32_t>(value);
435
- *(int32_t *)dest = v;
436
- } break;
437
- case PrimitiveKind::Int32S: {
438
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
439
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
440
- return false;
441
- }
442
-
443
- int32_t v = GetNumber<int32_t>(value);
444
- *(int32_t *)dest = ReverseBytes(v);
445
- } break;
446
- case PrimitiveKind::UInt32: {
447
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
448
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
449
- return false;
450
- }
451
-
452
- uint32_t v = GetNumber<uint32_t>(value);
453
- *(uint32_t *)dest = v;
454
- } break;
455
- case PrimitiveKind::UInt32S: {
456
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
457
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
458
- return false;
459
- }
460
-
461
- uint32_t v = GetNumber<uint32_t>(value);
462
- *(uint32_t *)dest = ReverseBytes(v);
463
- } break;
464
- case PrimitiveKind::Int64: {
465
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
466
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
467
- return false;
468
- }
469
-
470
- int64_t v = GetNumber<int64_t>(value);
471
- *(int64_t *)dest = v;
472
- } break;
473
- case PrimitiveKind::Int64S: {
474
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
475
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
476
- return false;
477
- }
478
-
479
- int64_t v = GetNumber<int64_t>(value);
480
- *(int64_t *)dest = ReverseBytes(v);
481
- } break;
482
- case PrimitiveKind::UInt64: {
483
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
484
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
485
- return false;
486
- }
487
-
488
- uint64_t v = GetNumber<uint64_t>(value);
489
- *(uint64_t *)dest = v;
490
- } break;
491
- case PrimitiveKind::UInt64S: {
492
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
493
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
494
- return false;
495
- }
496
-
497
- uint64_t v = GetNumber<uint64_t>(value);
498
- *(uint64_t *)dest = ReverseBytes(v);
499
- } break;
401
+ case PrimitiveKind::Int8: { PUSH_NUMBER(int8_t); } break;
402
+ case PrimitiveKind::UInt8: { PUSH_NUMBER(uint8_t); } break;
403
+ case PrimitiveKind::Int16: { PUSH_NUMBER(int16_t); } break;
404
+ case PrimitiveKind::Int16S: { PUSH_NUMBER_SWAP(int16_t); } break;
405
+ case PrimitiveKind::UInt16: { PUSH_NUMBER(uint16_t); } break;
406
+ case PrimitiveKind::UInt16S: { PUSH_NUMBER_SWAP(uint16_t); } break;
407
+ case PrimitiveKind::Int32: { PUSH_NUMBER(int32_t); } break;
408
+ case PrimitiveKind::Int32S: { PUSH_NUMBER_SWAP(int32_t); } break;
409
+ case PrimitiveKind::UInt32: { PUSH_NUMBER(uint32_t); } break;
410
+ case PrimitiveKind::UInt32S: { PUSH_NUMBER_SWAP(uint32_t); } break;
411
+ case PrimitiveKind::Int64: { PUSH_NUMBER(int64_t); } break;
412
+ case PrimitiveKind::Int64S: { PUSH_NUMBER_SWAP(int64_t); } break;
413
+ case PrimitiveKind::UInt64: { PUSH_NUMBER(uint64_t); } break;
414
+ case PrimitiveKind::UInt64S: { PUSH_NUMBER_SWAP(uint64_t); } break;
500
415
  case PrimitiveKind::String: {
501
416
  const char *str;
502
417
  if (!PushString(value, 1, &str)) [[unlikely]]
@@ -541,8 +456,7 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
541
456
  Napi::Array array = value.As<Napi::Array>();
542
457
  if (!PushNormalArray(array, member.type, member.type->size, dest))
543
458
  return false;
544
- } else if (IsRawBuffer(value)) {
545
- Span<const uint8_t> buffer = GetRawBuffer(value);
459
+ } else if (Span<uint8_t> buffer = {}; TryBuffer(value, &buffer)) {
546
460
  PushBuffer(buffer, member.type, dest);
547
461
  } else if (value.IsString()) {
548
462
  if (!PushStringArray(value, member.type, dest))
@@ -552,24 +466,8 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
552
466
  return false;
553
467
  }
554
468
  } break;
555
- case PrimitiveKind::Float32: {
556
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
557
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
558
- return false;
559
- }
560
-
561
- float f = GetNumber<float>(value);
562
- *(float *)dest = f;
563
- } break;
564
- case PrimitiveKind::Float64: {
565
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
566
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
567
- return false;
568
- }
569
-
570
- double d = GetNumber<double>(value);
571
- *(double *)dest = d;
572
- } break;
469
+ case PrimitiveKind::Float32: { PUSH_NUMBER(float); } break;
470
+ case PrimitiveKind::Float64: { PUSH_NUMBER(double); } break;
573
471
  case PrimitiveKind::Callback: {
574
472
  void *ptr;
575
473
  if (!PushCallback(value, member.type, &ptr))
@@ -582,6 +480,9 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
582
480
  }
583
481
  }
584
482
 
483
+ #undef PUSH_NUMBER_SWAP
484
+ #undef PUSH_NUMBER
485
+
585
486
  return true;
586
487
  }
587
488
 
@@ -601,7 +502,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
601
502
 
602
503
  Size offset = 0;
603
504
 
604
- #define PUSH_ARRAY(Check, Expected, GetCode) \
505
+ #define PUSH_ARRAY(Code) \
605
506
  do { \
606
507
  for (Size i = 0; i < len; i++) { \
607
508
  Napi::Value value = array[(uint32_t)i]; \
@@ -609,16 +510,33 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
609
510
  offset = AlignLen(offset, ref->align); \
610
511
  uint8_t *dest = origin + offset; \
611
512
  \
612
- if (!(Check)) [[unlikely]] { \
613
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), (Expected)); \
614
- return false; \
615
- } \
616
- \
617
- GetCode \
513
+ Code \
618
514
  \
619
515
  offset += ref->size; \
620
516
  } \
621
517
  } while (false)
518
+ #define PUSH_NUMBERS(CType) \
519
+ PUSH_ARRAY({ \
520
+ CType v; \
521
+ \
522
+ if (!TryNumber(value, &v)) [[unlikely]] { \
523
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
524
+ return false; \
525
+ } \
526
+ \
527
+ *(CType *)dest = v; \
528
+ })
529
+ #define PUSH_NUMBERS_SWAP(CType) \
530
+ PUSH_ARRAY({ \
531
+ CType v; \
532
+ \
533
+ if (!TryNumber(value, &v)) [[unlikely]] { \
534
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
535
+ return false; \
536
+ } \
537
+ \
538
+ *(CType *)dest = ReverseBytes(v); \
539
+ })
622
540
 
623
541
  switch (ref->primitive) {
624
542
  case PrimitiveKind::Void: {
@@ -627,97 +545,34 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
627
545
  } break;
628
546
 
629
547
  case PrimitiveKind::Bool: {
630
- PUSH_ARRAY(value.IsBoolean(), "boolean", {
631
- bool b = value.As<Napi::Boolean>();
548
+ PUSH_ARRAY({
549
+ bool b;
550
+ napi_status status = napi_get_value_bool(env, value, &b);
551
+
552
+ if (status != napi_ok) [[unlikely]] {
553
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
554
+ return false;
555
+ }
556
+
632
557
  *(bool *)dest = b;
633
558
  });
634
559
  } break;
635
- case PrimitiveKind::Int8: {
636
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
637
- int8_t v = GetNumber<int8_t>(value);
638
- *(int8_t *)dest = v;
639
- });
640
- } break;
641
- case PrimitiveKind::UInt8: {
642
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
643
- uint8_t v = GetNumber<uint8_t>(value);
644
- *(uint8_t *)dest = v;
645
- });
646
- } break;
647
- case PrimitiveKind::Int16: {
648
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
649
- int16_t v = GetNumber<int16_t>(value);
650
- *(int16_t *)dest = v;
651
- });
652
- } break;
653
- case PrimitiveKind::Int16S: {
654
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
655
- int16_t v = GetNumber<int16_t>(value);
656
- *(int16_t *)dest = ReverseBytes(v);
657
- });
658
- } break;
659
- case PrimitiveKind::UInt16: {
660
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
661
- uint16_t v = GetNumber<uint16_t>(value);
662
- *(uint16_t *)dest = v;
663
- });
664
- } break;
665
- case PrimitiveKind::UInt16S: {
666
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
667
- uint16_t v = GetNumber<uint16_t>(value);
668
- *(uint16_t *)dest = ReverseBytes(v);
669
- });
670
- } break;
671
- case PrimitiveKind::Int32: {
672
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
673
- int32_t v = GetNumber<int32_t>(value);
674
- *(int32_t *)dest = v;
675
- });
676
- } break;
677
- case PrimitiveKind::Int32S: {
678
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
679
- int32_t v = GetNumber<int32_t>(value);
680
- *(int32_t *)dest = ReverseBytes(v);
681
- });
682
- } break;
683
- case PrimitiveKind::UInt32: {
684
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
685
- uint32_t v = GetNumber<uint32_t>(value);
686
- *(uint32_t *)dest = v;
687
- });
688
- } break;
689
- case PrimitiveKind::UInt32S: {
690
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
691
- uint32_t v = GetNumber<uint32_t>(value);
692
- *(uint32_t *)dest = ReverseBytes(v);
693
- });
694
- } break;
695
- case PrimitiveKind::Int64: {
696
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
697
- int64_t v = GetNumber<int64_t>(value);
698
- *(int64_t *)dest = v;
699
- });
700
- } break;
701
- case PrimitiveKind::Int64S: {
702
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
703
- int64_t v = GetNumber<int64_t>(value);
704
- *(int64_t *)dest = ReverseBytes(v);
705
- });
706
- } break;
707
- case PrimitiveKind::UInt64: {
708
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
709
- uint64_t v = GetNumber<uint64_t>(value);
710
- *(uint64_t *)dest = v;
711
- });
712
- } break;
713
- case PrimitiveKind::UInt64S: {
714
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
715
- uint64_t v = GetNumber<uint64_t>(value);
716
- *(uint64_t *)dest = ReverseBytes(v);
717
- });
718
- } break;
560
+ case PrimitiveKind::Int8: { PUSH_NUMBERS(int8_t); } break;
561
+ case PrimitiveKind::UInt8: { PUSH_NUMBERS(uint8_t); } break;
562
+ case PrimitiveKind::Int16: { PUSH_NUMBERS(int16_t); } break;
563
+ case PrimitiveKind::Int16S: { PUSH_NUMBERS_SWAP(int16_t); } break;
564
+ case PrimitiveKind::UInt16: { PUSH_NUMBERS(uint16_t); } break;
565
+ case PrimitiveKind::UInt16S: { PUSH_NUMBERS_SWAP(uint16_t); } break;
566
+ case PrimitiveKind::Int32: { PUSH_NUMBERS(int32_t); } break;
567
+ case PrimitiveKind::Int32S: { PUSH_NUMBERS_SWAP(int32_t); } break;
568
+ case PrimitiveKind::UInt32: { PUSH_NUMBERS(uint32_t); } break;
569
+ case PrimitiveKind::UInt32S: { PUSH_NUMBERS_SWAP(uint32_t); } break;
570
+ case PrimitiveKind::Int64: { PUSH_NUMBERS(int64_t); } break;
571
+ case PrimitiveKind::Int64S: { PUSH_NUMBERS_SWAP(int64_t); } break;
572
+ case PrimitiveKind::UInt64: { PUSH_NUMBERS(uint64_t); } break;
573
+ case PrimitiveKind::UInt64S: { PUSH_NUMBERS_SWAP(uint64_t); } break;
719
574
  case PrimitiveKind::String: {
720
- PUSH_ARRAY(true, "string", {
575
+ PUSH_ARRAY({
721
576
  const char *str;
722
577
  if (!PushString(value, 1, &str)) [[unlikely]]
723
578
  return false;
@@ -726,7 +581,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
726
581
  });
727
582
  } break;
728
583
  case PrimitiveKind::String16: {
729
- PUSH_ARRAY(true, "string", {
584
+ PUSH_ARRAY({
730
585
  const char16_t *str16;
731
586
  if (!PushString16(value, 1, &str16)) [[unlikely]]
732
587
  return false;
@@ -735,7 +590,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
735
590
  });
736
591
  } break;
737
592
  case PrimitiveKind::String32: {
738
- PUSH_ARRAY(true, "string", {
593
+ PUSH_ARRAY({
739
594
  const char32_t *str32;
740
595
  if (!PushString32(value, 1, &str32)) [[unlikely]]
741
596
  return false;
@@ -744,7 +599,12 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
744
599
  });
745
600
  } break;
746
601
  case PrimitiveKind::Pointer: {
747
- PUSH_ARRAY(true, ref->name, {
602
+ PUSH_ARRAY({
603
+ if (!IsObject(value)) [[unlikely]] {
604
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
605
+ return false;
606
+ }
607
+
748
608
  void *ptr;
749
609
  if (!PushPointer(value, ref, 1, &ptr)) [[unlikely]]
750
610
  return false;
@@ -754,7 +614,12 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
754
614
  } break;
755
615
  case PrimitiveKind::Record:
756
616
  case PrimitiveKind::Union: {
757
- PUSH_ARRAY(IsObject(value), "object", {
617
+ PUSH_ARRAY({
618
+ if (!IsObject(value)) [[unlikely]] {
619
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
620
+ return false;
621
+ }
622
+
758
623
  Napi::Object obj2 = value.As<Napi::Object>();
759
624
  if (!PushObject(obj2, ref, dest))
760
625
  return false;
@@ -772,8 +637,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
772
637
  Napi::Array array2 = value.As<Napi::Array>();
773
638
  if (!PushNormalArray(array2, ref, (Size)ref->size, dest))
774
639
  return false;
775
- } else if (IsRawBuffer(value)) {
776
- Span<const uint8_t> buffer = GetRawBuffer(value);
640
+ } else if (Span<uint8_t> buffer = {}; TryBuffer(value, &buffer)) {
777
641
  PushBuffer(buffer, ref, dest);
778
642
  } else if (value.IsString()) {
779
643
  if (!PushStringArray(value, ref, dest))
@@ -786,18 +650,8 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
786
650
  offset += ref->size;
787
651
  }
788
652
  } break;
789
- case PrimitiveKind::Float32: {
790
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
791
- float f = GetNumber<float>(value);
792
- *(float *)dest = f;
793
- });
794
- } break;
795
- case PrimitiveKind::Float64: {
796
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
797
- double d = GetNumber<double>(value);
798
- *(double *)dest = d;
799
- });
800
- } break;
653
+ case PrimitiveKind::Float32: { PUSH_NUMBERS(float); } break;
654
+ case PrimitiveKind::Float64: { PUSH_NUMBERS(double); } break;
801
655
  case PrimitiveKind::Callback: {
802
656
  for (Size i = 0; i < len; i++) {
803
657
  Napi::Value value = array[(uint32_t)i];
@@ -819,6 +673,8 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
819
673
  case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
820
674
  }
821
675
 
676
+ #undef PUSH_NUMBERS_SWAP
677
+ #undef PUSH_NUMBERS
822
678
  #undef PUSH_ARRAY
823
679
 
824
680
  return true;
@@ -899,178 +755,140 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
899
755
 
900
756
  const TypeInfo *ref = type->ref.type;
901
757
 
902
- switch (value.Type()) {
903
- case napi_undefined:
904
- case napi_null: {
905
- *out_ptr = nullptr;
906
- return true;
907
- } break;
908
-
909
- case napi_external: {
910
- K_ASSERT(type->primitive == PrimitiveKind::Pointer ||
911
- type->primitive == PrimitiveKind::String ||
912
- type->primitive == PrimitiveKind::String16 ||
913
- type->primitive == PrimitiveKind::String32);
914
-
915
- if (!CheckValueTag(value, type->ref.marker) &&
916
- !CheckValueTag(value, instance->void_type) &&
917
- ref != instance->void_type) [[unlikely]]
918
- goto unexpected;
919
-
920
- *out_ptr = value.As<Napi::External<uint8_t>>().Data();
921
- return true;
922
- } break;
923
-
924
- case napi_object: {
925
- uint8_t *ptr = nullptr;
926
-
927
- OutArgument::Kind out_kind;
928
- Size out_max_len = -1;
758
+ // In the past we were naively using napi_typeof() and a switch to "reduce" branching,
759
+ // but it did not match the common types very well (so there was still various if tests),
760
+ // and it turns out that napi_typeof() is made of successive type tests anyway so it
761
+ // just made things worse. Oh, well.
929
762
 
930
- if (value.IsArray()) {
931
- Napi::Array array = value.As<Napi::Array>();
932
- Size len = PushIndirectString(array, ref, &ptr);
933
-
934
- if (len >= 0) {
935
- if (!ref->size && ref != instance->void_type) [[unlikely]] {
936
- ThrowError<Napi::TypeError>(env, "Cannot pass [string] value to %1", type->name);
937
- return false;
938
- }
939
-
940
- switch (ref->size) {
941
- default: { out_kind = OutArgument::Kind::String; } break;
942
- case 2: { out_kind = OutArgument::Kind::String16; } break;
943
- case 4: { out_kind = OutArgument::Kind::String32; } break;
944
- }
945
- out_max_len = len;
946
- } else {
947
- if (!ref->size) [[unlikely]] {
948
- ThrowError<Napi::TypeError>(env, "Cannot pass %1 value to %2, use koffi.as()",
949
- ref != instance->void_type ? "opaque" : "ambiguous", type->name);
950
- return false;
951
- }
952
-
953
- Size len = (Size)array.Length();
954
- Size size = len * ref->size;
763
+ if (void *ptr = nullptr; TryPointer(value, &ptr)) {
764
+ *out_ptr = ptr;
765
+ return true;
766
+ } else if (value.IsArray()) {
767
+ uint8_t *ptr = nullptr;
955
768
 
956
- ptr = AllocHeap(size, 16);
769
+ Napi::Array array = value.As<Napi::Array>();
770
+ Size len = PushIndirectString(array, ref, &ptr);
957
771
 
958
- if (directions & 1) {
959
- if (!PushNormalArray(array, type, size, ptr))
960
- return false;
961
- } else {
962
- MemSet(ptr, 0, size);
963
- }
772
+ OutArgument::Kind out_kind;
773
+ Size out_max_len = -1;
964
774
 
965
- out_kind = OutArgument::Kind::Array;
966
- }
967
- } else if (IsRawBuffer(value)) {
968
- Span<uint8_t> buffer = GetRawBuffer(value);
775
+ if (len >= 0) {
776
+ if (!ref->size && ref != instance->void_type) [[unlikely]] {
777
+ ThrowError<Napi::TypeError>(env, "Cannot pass [string] value to %1", type->name);
778
+ return false;
779
+ }
969
780
 
970
- // We can fast path
971
- ptr = buffer.ptr;
972
- directions = 1;
781
+ switch (ref->size) {
782
+ default: { out_kind = OutArgument::Kind::String; } break;
783
+ case 2: { out_kind = OutArgument::Kind::String16; } break;
784
+ case 4: { out_kind = OutArgument::Kind::String32; } break;
785
+ }
786
+ out_max_len = len;
787
+ } else {
788
+ if (!ref->size) [[unlikely]] {
789
+ ThrowError<Napi::TypeError>(env, "Cannot pass %1 value to %2, use koffi.as()",
790
+ ref != instance->void_type ? "opaque" : "ambiguous", type->name);
791
+ return false;
792
+ }
973
793
 
974
- out_kind = OutArgument::Kind::Buffer;
975
- } else if (ref->primitive == PrimitiveKind::Record ||
976
- ref->primitive == PrimitiveKind::Union) [[likely]] {
977
- Napi::Object obj = value.As<Napi::Object>();
978
- K_ASSERT(IsObject(value));
794
+ Size len = (Size)array.Length();
795
+ Size size = len * ref->size;
979
796
 
980
- ptr = AllocHeap(ref->size, 16);
797
+ ptr = AllocHeap(size, 16);
981
798
 
982
- if (ref->primitive == PrimitiveKind::Union &&
983
- (directions & 2) && !CheckValueTag(obj, &MagicUnionMarker)) [[unlikely]] {
984
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected union value", GetValueType(instance, obj));
799
+ if (directions & 1) {
800
+ if (!PushNormalArray(array, type, size, ptr))
985
801
  return false;
986
- }
987
-
988
- if (directions & 1) {
989
- if (!PushObject(obj, ref, ptr))
990
- return false;
991
- } else {
992
- MemSet(ptr, 0, ref->size);
993
- }
994
-
995
- out_kind = OutArgument::Kind::Object;
996
802
  } else {
997
- goto unexpected;
803
+ MemSet(ptr, 0, size);
998
804
  }
999
805
 
1000
- if (directions & 2) {
1001
- OutArgument *out = out_arguments.AppendDefault();
806
+ out_kind = OutArgument::Kind::Array;
807
+ }
1002
808
 
1003
- napi_status status = napi_create_reference(env, value, 1, &out->ref);
1004
- K_ASSERT(status == napi_ok);
809
+ if (directions & 2) {
810
+ OutArgument *out = out_arguments.AppendDefault();
1005
811
 
1006
- out->kind = out_kind;
1007
- out->ptr = ptr;
1008
- out->type = ref;
1009
- out->max_len = out_max_len;
1010
- }
812
+ napi_status status = napi_create_reference(env, value, 1, &out->ref);
813
+ K_ASSERT(status == napi_ok);
1011
814
 
1012
- *out_ptr = ptr;
1013
- return true;
1014
- } break;
815
+ out->kind = out_kind;
816
+ out->ptr = ptr;
817
+ out->type = ref;
818
+ out->max_len = out_max_len;
819
+ }
1015
820
 
1016
- case napi_string: {
1017
- K_ASSERT(type->primitive == PrimitiveKind::Pointer);
821
+ *out_ptr = ptr;
822
+ return true;
823
+ } else if (ref->primitive == PrimitiveKind::Record ||
824
+ ref->primitive == PrimitiveKind::Union) [[likely]] {
825
+ Napi::Object obj = value.As<Napi::Object>();
826
+ K_ASSERT(IsObject(value));
1018
827
 
1019
- if (directions & 2) [[unlikely]]
1020
- goto unexpected;
828
+ uint8_t *ptr = AllocHeap(ref->size, 16);
1021
829
 
1022
- if (ref == instance->void_type) {
1023
- PushStringValue(value, (const char **)out_ptr);
1024
- return true;
1025
- } else if (ref->primitive == PrimitiveKind::Int8) {
1026
- PushStringValue(value, (const char **)out_ptr);
1027
- return true;
1028
- } else if (ref->primitive == PrimitiveKind::Int16) {
1029
- PushString16Value(value, (const char16_t **)out_ptr);
1030
- return true;
1031
- } else if (ref->primitive == PrimitiveKind::Int32) {
1032
- PushString32Value(value, (const char32_t **)out_ptr);
1033
- return true;
1034
- } else {
1035
- goto unexpected;
1036
- }
1037
- } break;
830
+ if (ref->primitive == PrimitiveKind::Union &&
831
+ (directions & 2) && !CheckValueTag(obj, &MagicUnionMarker)) [[unlikely]] {
832
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected union value", GetValueType(instance, obj));
833
+ return false;
834
+ }
1038
835
 
1039
- case napi_function: {
1040
- if (type->primitive != PrimitiveKind::Callback) [[unlikely]] {
1041
- ThrowError<Napi::TypeError>(env, "Cannot pass function to type %1", type->name);
836
+ if (directions & 1) {
837
+ if (!PushObject(obj, ref, ptr))
1042
838
  return false;
1043
- }
839
+ } else {
840
+ MemSet(ptr, 0, ref->size);
841
+ }
1044
842
 
1045
- Napi::Function func = value.As<Napi::Function>();
843
+ if (directions & 2) {
844
+ OutArgument *out = out_arguments.AppendDefault();
1046
845
 
1047
- void *ptr = ReserveTrampoline(type->ref.proto, func);
1048
- if (!ptr) [[unlikely]]
1049
- return false;
846
+ napi_status status = napi_create_reference(env, value, 1, &out->ref);
847
+ K_ASSERT(status == napi_ok);
1050
848
 
1051
- *out_ptr = (void *)ptr;
1052
- return true;
1053
- } break;
849
+ out->kind = OutArgument::Kind::Object;
850
+ out->ptr = ptr;
851
+ out->type = ref;
852
+ out->max_len = -1;
853
+ }
1054
854
 
1055
- case napi_number: {
1056
- Napi::Number number = value.As<Napi::Number>();
1057
- intptr_t ptr = (intptr_t)number.Int32Value();
855
+ *out_ptr = ptr;
856
+ return true;
857
+ } else if (value.IsString()) {
858
+ K_ASSERT(type->primitive == PrimitiveKind::Pointer);
1058
859
 
1059
- *out_ptr = (void *)ptr;
1060
- return true;
1061
- } break;
860
+ if (directions & 2) [[unlikely]]
861
+ goto unexpected;
1062
862
 
1063
- case napi_bigint: {
1064
- Napi::BigInt bigint = value.As<Napi::BigInt>();
863
+ if (ref == instance->void_type) {
864
+ PushStringValue(value, (const char **)out_ptr);
865
+ return true;
866
+ } else if (ref->primitive == PrimitiveKind::Int8) {
867
+ PushStringValue(value, (const char **)out_ptr);
868
+ return true;
869
+ } else if (ref->primitive == PrimitiveKind::Int16) {
870
+ PushString16Value(value, (const char16_t **)out_ptr);
871
+ return true;
872
+ } else if (ref->primitive == PrimitiveKind::Int32) {
873
+ PushString32Value(value, (const char32_t **)out_ptr);
874
+ return true;
875
+ } else {
876
+ goto unexpected;
877
+ }
878
+ } else if (value.IsFunction()) {
879
+ if (type->primitive != PrimitiveKind::Callback) [[unlikely]] {
880
+ ThrowError<Napi::TypeError>(env, "Cannot pass function to type %1", type->name);
881
+ return false;
882
+ }
1065
883
 
1066
- bool lossless;
1067
- intptr_t ptr = (intptr_t)bigint.Int64Value(&lossless);
884
+ Napi::Function func = value.As<Napi::Function>();
1068
885
 
1069
- *out_ptr = (void *)ptr;
1070
- return true;
1071
- } break;
886
+ void *ptr = ReserveTrampoline(type->ref.proto, func);
887
+ if (!ptr) [[unlikely]]
888
+ return false;
1072
889
 
1073
- default: {} break;
890
+ *out_ptr = (void *)ptr;
891
+ return true;
1074
892
  }
1075
893
 
1076
894
  unexpected:
@@ -1080,7 +898,18 @@ unexpected:
1080
898
 
1081
899
  bool CallData::PushCallback(Napi::Value value, const TypeInfo *type, void **out_ptr)
1082
900
  {
1083
- if (value.IsFunction()) {
901
+ if (CheckValueTag(value, &CastMarker)) {
902
+ Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
903
+ ValueCast *cast = external.Data();
904
+
905
+ value = cast->ref.Value();
906
+ type = cast->type;
907
+ }
908
+
909
+ if (void *ptr = nullptr; TryPointer(value, &ptr)) {
910
+ *out_ptr = ptr;
911
+ return true;
912
+ } else if (value.IsFunction()) {
1084
913
  Napi::Function func = value.As<Napi::Function>();
1085
914
 
1086
915
  void *ptr = ReserveTrampoline(type->ref.proto, func);
@@ -1088,27 +917,9 @@ bool CallData::PushCallback(Napi::Value value, const TypeInfo *type, void **out_
1088
917
  return false;
1089
918
 
1090
919
  *out_ptr = ptr;
1091
- } else if (CheckValueTag(value, type->ref.marker)) {
1092
- *out_ptr = value.As<Napi::External<void>>().Data();
1093
- } else if (CheckValueTag(value, &CastMarker)) {
1094
- Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
1095
- ValueCast *cast = external.Data();
1096
-
1097
- value = cast->ref.Value();
1098
-
1099
- if (!value.IsExternal() || cast->type != type)
1100
- goto unexpected;
1101
-
1102
- *out_ptr = value.As<Napi::External<void>>().Data();
1103
- } else if (IsNullOrUndefined(value)) {
1104
- *out_ptr = nullptr;
1105
- } else {
1106
- goto unexpected;
920
+ return true;
1107
921
  }
1108
922
 
1109
- return true;
1110
-
1111
- unexpected:
1112
923
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
1113
924
  return false;
1114
925
  }
@@ -1166,7 +977,7 @@ void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func
1166
977
  trampoline->recv.Reset();
1167
978
  trampoline->generation = (int32_t)mem->generation;
1168
979
 
1169
- void *ptr = GetTrampoline(idx, proto);
980
+ void *ptr = GetTrampoline(idx);
1170
981
 
1171
982
  return ptr;
1172
983
  }
@@ -1200,14 +1011,14 @@ bool CallData::CheckDynamicLength(Napi::Object obj, Size element, const char *co
1200
1011
  {
1201
1012
  Napi::Value by = obj.Get(countedby);
1202
1013
 
1203
- if (!by.IsNumber() && !by.IsBigInt()) [[unlikely]] {
1014
+ if (!TryNumber(by, &expected)) [[unlikely]] {
1204
1015
  ThrowError<Napi::Error>(env, "Unexpected %1 value for dynamic length, expected number", GetValueType(instance, by));
1205
1016
  return false;
1206
1017
  }
1207
1018
 
1208
1019
  // If we get anywhere near overflow there are other problems to worry about.
1209
1020
  // So let's not worry about that.
1210
- expected = GetNumber<int64_t>(by) * element;
1021
+ expected *= element;
1211
1022
  }
1212
1023
 
1213
1024
  // Get actual size
@@ -1259,9 +1070,11 @@ void CallData::PopOutArguments()
1259
1070
  } break;
1260
1071
 
1261
1072
  case OutArgument::Kind::Buffer: {
1262
- K_ASSERT(IsRawBuffer(value));
1073
+ Span<uint8_t> buffer;
1074
+
1075
+ bool success = TryBuffer(value, &buffer);
1076
+ K_ASSERT(success);
1263
1077
 
1264
- Span<uint8_t> buffer = GetRawBuffer(value);
1265
1078
  DecodeBuffer(buffer, out.ptr, out.type);
1266
1079
  } break;
1267
1080
 
@@ -1315,4 +1128,9 @@ void CallData::PopOutArguments()
1315
1128
  }
1316
1129
  }
1317
1130
 
1131
+ void *GetTrampoline(int16_t idx)
1132
+ {
1133
+ return Trampolines[idx];
1134
+ }
1135
+
1318
1136
  }