koffi 1.1.1 → 1.1.4

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 (53) hide show
  1. package/CMakeLists.txt +13 -7
  2. package/README.md +15 -26
  3. package/build/qemu/1.1.4/koffi_darwin_x64.tar.gz +0 -0
  4. package/build/qemu/1.1.4/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/build/qemu/1.1.4/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/build/qemu/1.1.4/koffi_freebsd_x64.tar.gz +0 -0
  7. package/build/qemu/1.1.4/koffi_linux_arm.tar.gz +0 -0
  8. package/build/qemu/1.1.4/koffi_linux_arm64.tar.gz +0 -0
  9. package/build/qemu/1.1.4/koffi_linux_ia32.tar.gz +0 -0
  10. package/build/qemu/1.1.4/koffi_linux_riscv64.tar.gz +0 -0
  11. package/build/qemu/1.1.4/koffi_linux_x64.tar.gz +0 -0
  12. package/build/qemu/1.1.4/koffi_openbsd_ia32.tar.gz +0 -0
  13. package/build/qemu/1.1.4/koffi_openbsd_x64.tar.gz +0 -0
  14. package/build/qemu/1.1.4/koffi_win32_ia32.tar.gz +0 -0
  15. package/build/qemu/1.1.4/koffi_win32_x64.tar.gz +0 -0
  16. package/package.json +2 -2
  17. package/qemu/qemu.js +13 -10
  18. package/qemu/registry/machines.json +138 -3
  19. package/qemu/registry/sha256sum.txt +27 -12
  20. package/src/abi_arm32.cc +29 -16
  21. package/src/abi_arm64.cc +33 -17
  22. package/src/abi_riscv64.cc +468 -0
  23. package/src/abi_riscv64_fwd.S +129 -0
  24. package/src/abi_x64_sysv.cc +9 -10
  25. package/src/abi_x64_win.cc +5 -8
  26. package/src/abi_x86.cc +11 -6
  27. package/src/call.cc +24 -36
  28. package/src/call.hh +14 -24
  29. package/src/ffi.cc +75 -27
  30. package/src/ffi.hh +13 -5
  31. package/src/parser.cc +48 -26
  32. package/src/parser.hh +3 -1
  33. package/src/util.cc +26 -57
  34. package/src/util.hh +17 -1
  35. package/test/CMakeLists.txt +3 -0
  36. package/test/misc.c +34 -0
  37. package/vendor/_patches/glfw_001_fix_openbsd_xlib_soname.patch +145 -0
  38. package/vendor/libcc/libcc.cc +7 -7
  39. package/vendor/libcc/libcc.hh +8 -2
  40. package/vendor/raylib/src/external/glfw/src/egl_context.c +6 -0
  41. package/vendor/raylib/src/external/glfw/src/osmesa_context.c +2 -0
  42. package/vendor/raylib/src/external/glfw/src/vulkan.c +2 -0
  43. package/vendor/raylib/src/external/glfw/src/x11_init.c +20 -0
  44. package/build/qemu/1.1.1/koffi_darwin_x64.tar.gz +0 -0
  45. package/build/qemu/1.1.1/koffi_freebsd_arm64.tar.gz +0 -0
  46. package/build/qemu/1.1.1/koffi_freebsd_ia32.tar.gz +0 -0
  47. package/build/qemu/1.1.1/koffi_freebsd_x64.tar.gz +0 -0
  48. package/build/qemu/1.1.1/koffi_linux_arm.tar.gz +0 -0
  49. package/build/qemu/1.1.1/koffi_linux_arm64.tar.gz +0 -0
  50. package/build/qemu/1.1.1/koffi_linux_ia32.tar.gz +0 -0
  51. package/build/qemu/1.1.1/koffi_linux_x64.tar.gz +0 -0
  52. package/build/qemu/1.1.1/koffi_win32_ia32.tar.gz +0 -0
  53. package/build/qemu/1.1.1/koffi_win32_x64.tar.gz +0 -0
package/src/abi_x86.cc CHANGED
@@ -37,7 +37,9 @@ static inline bool IsRegular(Size size)
37
37
 
38
38
  bool AnalyseFunction(InstanceData *instance, FunctionInfo *func)
39
39
  {
40
- int fast = (func->convention == CallConvention::Fastcall) ? 2 : 0;
40
+ int fast = (func->convention == CallConvention::Fastcall) ? 2 :
41
+ (func->convention == CallConvention::Thiscall) ? 1 : 0;
42
+ func->fast = fast;
41
43
 
42
44
  if (func->ret.type->primitive != PrimitiveKind::Record) {
43
45
  func->ret.trivial = true;
@@ -77,6 +79,10 @@ bool AnalyseFunction(InstanceData *instance, FunctionInfo *func)
77
79
  func->decorated_name = Fmt(&instance->str_alloc, "@%1@%2", func->name, params_size).ptr;
78
80
  func->args_size += 16;
79
81
  } break;
82
+ case CallConvention::Thiscall: {
83
+ RG_ASSERT(!func->variadic);
84
+ func->args_size += 16;
85
+ } break;
80
86
  }
81
87
 
82
88
  return true;
@@ -90,7 +96,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
90
96
  // Pass return value in register or through memory
91
97
  if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
92
98
  return false;
93
- if (func->convention == CallConvention::Fastcall) {
99
+ if (func->fast) {
94
100
  fast_ptr = args_ptr;
95
101
  args_ptr += 4;
96
102
  }
@@ -249,8 +255,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
249
255
  }
250
256
  }
251
257
 
252
- stack = MakeSpan(mem->stack.end(), old_stack_mem.end() - mem->stack.end());
253
- heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
258
+ sp = mem->stack.end();
254
259
 
255
260
  return true;
256
261
  }
@@ -259,8 +264,8 @@ void CallData::Execute()
259
264
  {
260
265
  #define PERFORM_CALL(Suffix) \
261
266
  ([&]() { \
262
- auto ret = (func->convention == CallConvention::Fastcall ? ForwardCallR ## Suffix(func->func, stack.ptr) \
263
- : ForwardCall ## Suffix(func->func, stack.ptr)); \
267
+ auto ret = (func->fast ? ForwardCallR ## Suffix(func->func, sp) \
268
+ : ForwardCall ## Suffix(func->func, sp)); \
264
269
  return ret; \
265
270
  })()
266
271
 
package/src/call.cc CHANGED
@@ -21,7 +21,7 @@
21
21
  namespace RG {
22
22
 
23
23
  CallData::CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func, InstanceMemory *mem)
24
- : env(env), instance(instance), func(func), debug(instance->debug),
24
+ : env(env), instance(instance), func(func),
25
25
  mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
26
26
  {
27
27
  mem->depth++;
@@ -252,8 +252,8 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
252
252
  return false;
253
253
  }
254
254
 
255
- Napi::Object obj = value.As<Napi::Object>();
256
- if (!PushObject(obj, member.type, dest, realign))
255
+ Napi::Object obj2 = value.As<Napi::Object>();
256
+ if (!PushObject(obj2, member.type, dest, realign))
257
257
  return false;
258
258
  } break;
259
259
  case PrimitiveKind::Array: {
@@ -292,15 +292,15 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
292
292
  return true;
293
293
  }
294
294
 
295
- bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t *dest, int16_t realign)
295
+ bool CallData::PushArray(const Napi::Value &obj, const TypeInfo *type, uint8_t *dest, int16_t realign)
296
296
  {
297
- RG_ASSERT(value.IsArray() || value.IsTypedArray() || value.IsString());
297
+ RG_ASSERT(obj.IsArray() || obj.IsTypedArray() || obj.IsString());
298
298
  RG_ASSERT(type->primitive == PrimitiveKind::Array);
299
299
 
300
300
  uint32_t len = type->size / type->ref->size;
301
301
 
302
- if (value.IsArray()) {
303
- Napi::Array array = value.As<Napi::Array>();
302
+ if (obj.IsArray()) {
303
+ Napi::Array array = obj.As<Napi::Array>();
304
304
 
305
305
  if (RG_UNLIKELY(array.Length() != len)) {
306
306
  ThrowError<Napi::Error>(env, "Expected array of length %1, got %2", len, array.Length());
@@ -407,15 +407,15 @@ bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t
407
407
  } break;
408
408
  case PrimitiveKind::Record: {
409
409
  PUSH_ARRAY(IsObject(value), "object", {
410
- Napi::Object obj = value.As<Napi::Object>();
411
- if (!PushObject(obj, type->ref, dest, realign))
410
+ Napi::Object obj2 = value.As<Napi::Object>();
411
+ if (!PushObject(obj2, type->ref, dest, realign))
412
412
  return false;
413
413
  });
414
414
  } break;
415
415
  case PrimitiveKind::Array: {
416
416
  PUSH_ARRAY(value.IsArray() || value.IsTypedArray() || value.IsString(), "array", {
417
- Napi::Object array = value.As<Napi::Array>();
418
- if (!PushArray(array, type->ref, dest, realign))
417
+ Napi::Object array2 = value.As<Napi::Array>();
418
+ if (!PushArray(array2, type->ref, dest, realign))
419
419
  return false;
420
420
  });
421
421
  } break;
@@ -434,8 +434,8 @@ bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t
434
434
  }
435
435
 
436
436
  #undef PUSH_ARRAY
437
- } else if (value.IsTypedArray()) {
438
- Napi::TypedArray array = value.As<Napi::TypedArray>();
437
+ } else if (obj.IsTypedArray()) {
438
+ Napi::TypedArray array = obj.As<Napi::TypedArray>();
439
439
  const uint8_t *buf = (const uint8_t *)array.ArrayBuffer().Data();
440
440
 
441
441
  if (RG_UNLIKELY(array.ElementLength() != len)) {
@@ -469,23 +469,23 @@ bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t
469
469
 
470
470
  dest += type->ref->size;
471
471
  }
472
- } else if (value.IsString()) {
473
- size_t len = 0;
472
+ } else if (obj.IsString()) {
473
+ size_t encoded = 0;
474
474
 
475
475
  if (type->ref->primitive == PrimitiveKind::Int8 || type->ref->primitive == PrimitiveKind::UInt8) {
476
- napi_status status = napi_get_value_string_utf8(env, value, (char *)dest, type->size, &len);
476
+ napi_status status = napi_get_value_string_utf8(env, obj, (char *)dest, type->size, &encoded);
477
477
  RG_ASSERT(status == napi_ok);
478
478
  } else if (type->ref->primitive == PrimitiveKind::Int16 || type->ref->primitive == PrimitiveKind::UInt16) {
479
- napi_status status = napi_get_value_string_utf16(env, value, (char16_t *)dest, type->size / 2, &len);
479
+ napi_status status = napi_get_value_string_utf16(env, obj, (char16_t *)dest, type->size / 2, &encoded);
480
480
  RG_ASSERT(status == napi_ok);
481
481
 
482
- len *= 2;
482
+ encoded *= 2;
483
483
  } else {
484
484
  ThrowError<Napi::TypeError>(env, "Strings cannot be converted to %1 array", type->ref->name);
485
485
  return false;
486
486
  }
487
487
 
488
- memset_safe(dest + len, 0, type->size - len);
488
+ memset_safe(dest + encoded, 0, type->size - encoded);
489
489
  } else {
490
490
  RG_UNREACHABLE();
491
491
  }
@@ -565,13 +565,11 @@ void CallData::PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *t
565
565
  obj.Set(member.name, value);
566
566
  } break;
567
567
  case PrimitiveKind::Float32: {
568
- float f;
569
- memcpy(&f, src, 4);
568
+ float f = *(float *)src;
570
569
  obj.Set(member.name, Napi::Number::New(env, (double)f));
571
570
  } break;
572
571
  case PrimitiveKind::Float64: {
573
- double d;
574
- memcpy(&d, src, 8);
572
+ double d = *(double *)src;
575
573
  obj.Set(member.name, Napi::Number::New(env, d));
576
574
  } break;
577
575
  }
@@ -762,19 +760,6 @@ Napi::Value CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_t
762
760
  RG_UNREACHABLE();
763
761
  }
764
762
 
765
- Napi::Value CallData::Run(const Napi::CallbackInfo &info)
766
- {
767
- if (!RG_UNLIKELY(Prepare(info)))
768
- return env.Null();
769
-
770
- if (debug) {
771
- DumpDebug();
772
- }
773
- Execute();
774
-
775
- return Complete();
776
- }
777
-
778
763
  static void DumpMemory(const char *type, Span<const uint8_t> bytes)
779
764
  {
780
765
  if (bytes.len) {
@@ -805,6 +790,9 @@ void CallData::DumpDebug() const
805
790
  }
806
791
  PrintLn(stderr, "Return: %1 (%2)", func->ret.type->name, FmtMemSize(func->ret.type->size));
807
792
 
793
+ Span<const uint8_t> stack = MakeSpan(mem->stack.end(), old_stack_mem.end() - mem->stack.end());
794
+ Span<const uint8_t> heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
795
+
808
796
  DumpMemory("Stack", stack);
809
797
  DumpMemory("Heap", heap);
810
798
  }
package/src/call.hh CHANGED
@@ -34,16 +34,12 @@ class CallData {
34
34
  InstanceData *instance;
35
35
  const FunctionInfo *func;
36
36
 
37
- bool debug;
38
-
39
37
  InstanceMemory *mem;
40
38
  Span<uint8_t> old_stack_mem;
41
39
  Span<uint8_t> old_heap_mem;
42
40
 
43
41
  LocalArray<OutObject, MaxOutParameters> out_objects;
44
-
45
- Span<uint8_t> heap;
46
- Span<uint8_t> stack;
42
+ uint8_t *sp;
47
43
 
48
44
  union {
49
45
  uint32_t u32;
@@ -65,20 +61,18 @@ public:
65
61
  void Execute();
66
62
  Napi::Value Complete();
67
63
 
68
- Napi::Value Run(const Napi::CallbackInfo &info);
69
-
70
64
  void DumpDebug() const;
71
65
 
72
66
  private:
73
67
  template <typename T = void>
74
- bool AllocStack(Size size, Size align, T **out_ptr = nullptr);
68
+ bool AllocStack(Size size, Size align, T **out_ptr);
75
69
  template <typename T = void>
76
- bool AllocHeap(Size size, Size align, T **out_ptr = nullptr);
70
+ bool AllocHeap(Size size, Size align, T **out_ptr);
77
71
 
78
72
  const char *PushString(const Napi::Value &value);
79
73
  const char16_t *PushString16(const Napi::Value &value);
80
74
  bool PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
81
- bool PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
75
+ bool PushArray(const Napi::Value &obj, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
82
76
 
83
77
  void PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
84
78
  Napi::Object PopObject(const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
@@ -86,7 +80,7 @@ private:
86
80
  };
87
81
 
88
82
  template <typename T>
89
- bool CallData::AllocStack(Size size, Size align, T **out_ptr)
83
+ inline bool CallData::AllocStack(Size size, Size align, T **out_ptr)
90
84
  {
91
85
  uint8_t *ptr = AlignDown(mem->stack.end() - size, align);
92
86
  Size delta = mem->stack.end() - ptr;
@@ -96,20 +90,18 @@ bool CallData::AllocStack(Size size, Size align, T **out_ptr)
96
90
  return false;
97
91
  }
98
92
 
99
- if (debug) {
100
- memset(ptr, 0, delta);
101
- }
93
+ #ifdef RG_DEBUG
94
+ memset(ptr, 0, delta);
95
+ #endif
102
96
 
103
97
  mem->stack.len -= delta;
104
98
 
105
- if (out_ptr) {
106
- *out_ptr = (T *)ptr;
107
- }
99
+ *out_ptr = (T *)ptr;
108
100
  return true;
109
101
  }
110
102
 
111
103
  template <typename T>
112
- bool CallData::AllocHeap(Size size, Size align, T **out_ptr)
104
+ inline bool CallData::AllocHeap(Size size, Size align, T **out_ptr)
113
105
  {
114
106
  uint8_t *ptr = AlignUp(mem->heap.ptr, align);
115
107
  Size delta = size + (ptr - mem->heap.ptr);
@@ -119,16 +111,14 @@ bool CallData::AllocHeap(Size size, Size align, T **out_ptr)
119
111
  return false;
120
112
  }
121
113
 
122
- if (debug) {
123
- memset(mem->heap.ptr, 0, (size_t)delta);
124
- }
114
+ #ifdef RG_DEBUG
115
+ memset(mem->heap.ptr, 0, (size_t)delta);
116
+ #endif
125
117
 
126
118
  mem->heap.ptr += delta;
127
119
  mem->heap.len -= delta;
128
120
 
129
- if (out_ptr) {
130
- *out_ptr = (T *)ptr;
131
- }
121
+ *out_ptr = (T *)ptr;
132
122
  return true;
133
123
  }
134
124
 
package/src/ffi.cc CHANGED
@@ -29,6 +29,7 @@
29
29
  #else
30
30
  #include <dlfcn.h>
31
31
  #include <unistd.h>
32
+ #include <sys/mman.h>
32
33
  #endif
33
34
 
34
35
  #include <napi.h>
@@ -39,6 +40,11 @@
39
40
 
40
41
  namespace RG {
41
42
 
43
+ const Size SyncStackSize = Mebibytes(2);
44
+ const Size SyncHeapSize = Mebibytes(4);
45
+ const Size AsyncStackSize = Mebibytes(1);
46
+ const Size AsyncHeapSize = Mebibytes(2);
47
+
42
48
  // Value does not matter, the tag system uses memory addresses
43
49
  const int TypeInfoMarker = 0xDEADBEEF;
44
50
 
@@ -100,6 +106,11 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
100
106
  type->members.Append(member);
101
107
  }
102
108
 
109
+ if (!type->size) {
110
+ ThrowError<Napi::TypeError>(env, "Empty struct '%1' is not allowed in C", type->name);
111
+ return env.Null();
112
+ }
113
+
103
114
  type->size = (int16_t)AlignLen(type->size, type->align);
104
115
 
105
116
  // If the insert succeeds, we cannot fail anymore
@@ -290,7 +301,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
290
301
  if (!ref)
291
302
  return env.Null();
292
303
  if (len <= 0) {
293
- ThrowError<Napi::TypeError>(env, "Array length must be non-zero positive");
304
+ ThrowError<Napi::TypeError>(env, "Array length must be positive and non-zero");
294
305
  return env.Null();
295
306
  }
296
307
  if (len > INT16_MAX / ref->size) {
@@ -369,21 +380,6 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
369
380
  return type->defn.Value();
370
381
  }
371
382
 
372
- static Span<uint8_t> AllocateAndAlign16(Allocator *alloc, Size size)
373
- {
374
- RG_ASSERT(AlignLen(size, 16) == size);
375
- RG_ASSERT(size >= Kibibytes(1));
376
-
377
- // Account for allocator overhead
378
- size -= 256;
379
-
380
- uint8_t *ptr = (uint8_t *)Allocator::Allocate(alloc, size);
381
- uint8_t *aligned = AlignUp(ptr, 16);
382
- Size delta = AlignLen(aligned - ptr, 16);
383
-
384
- return MakeSpan(aligned, size - delta);
385
- }
386
-
387
383
  static InstanceMemory *AllocateAsyncMemory(InstanceData *instance)
388
384
  {
389
385
  for (Size i = 1; i < instance->memories.len; i++) {
@@ -395,8 +391,23 @@ static InstanceMemory *AllocateAsyncMemory(InstanceData *instance)
395
391
 
396
392
  InstanceMemory *mem = new InstanceMemory();
397
393
 
398
- mem->stack = AllocateAndAlign16(&mem->mem_alloc, Mebibytes(1));
399
- mem->heap = AllocateAndAlign16(&mem->mem_alloc, Mebibytes(2));
394
+ mem->stack.len = AsyncStackSize;
395
+ #if defined(_WIN32)
396
+ mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
397
+ #elif defined(__APPLE__)
398
+ mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
399
+ #else
400
+ mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
401
+ #endif
402
+ RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
403
+
404
+ mem->heap.len = AsyncHeapSize;
405
+ #ifdef _WIN32
406
+ mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
407
+ #else
408
+ mem->heap.ptr = (uint8_t *)mmap(nullptr, mem->heap.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
409
+ #endif
410
+ RG_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
400
411
 
401
412
  if (instance->memories.Available()) {
402
413
  instance->memories.Append(mem);
@@ -421,7 +432,15 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
421
432
  InstanceMemory *mem = instance->memories[0];
422
433
  CallData call(env, instance, func, mem);
423
434
 
424
- return call.Run(info);
435
+ if (!RG_UNLIKELY(call.Prepare(info)))
436
+ return env.Null();
437
+
438
+ if (instance->debug) {
439
+ call.DumpDebug();
440
+ }
441
+ call.Execute();
442
+
443
+ return call.Complete();
425
444
  }
426
445
 
427
446
  static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
@@ -481,7 +500,15 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
481
500
  InstanceMemory *mem = instance->memories[0];
482
501
  CallData call(env, instance, &func, mem);
483
502
 
484
- return call.Run(info);
503
+ if (!RG_UNLIKELY(call.Prepare(info)))
504
+ return env.Null();
505
+
506
+ if (instance->debug) {
507
+ call.DumpDebug();
508
+ }
509
+ call.Execute();
510
+
511
+ return call.Complete();
485
512
  }
486
513
 
487
514
  class AsyncCall: public Napi::AsyncWorker {
@@ -597,10 +624,10 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
597
624
  return false;
598
625
  }
599
626
 
600
- Size parameters_len = parameters.Length();
627
+ uint32_t parameters_len = parameters.Length();
601
628
 
602
629
  if (parameters_len) {
603
- Napi::String str = ((Napi::Value)parameters[(uint32_t)(parameters_len - 1)]).As<Napi::String>();
630
+ Napi::String str = ((Napi::Value)parameters[parameters_len - 1]).As<Napi::String>();
604
631
 
605
632
  if (str.IsString() && str.Utf8Value() == "...") {
606
633
  func->variadic = true;
@@ -653,9 +680,13 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
653
680
  if (!ParseClassicFunction(env, info[0u].As<Napi::String>(), info[1u], info[2u].As<Napi::Array>(), func))
654
681
  return env.Null();
655
682
  } else if (info.Length() >= 1) {
656
- PrototypeParser parser(env);
683
+ if (!info[0].IsString()) {
684
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for prototype, expected string", GetValueType(instance, info[0]));
685
+ return env.Null();
686
+ }
657
687
 
658
- if (!parser.Parse(info[0u].As<Napi::String>(), func))
688
+ std::string proto = info[0u].As<Napi::String>();
689
+ if (!ParsePrototype(env, proto.c_str(), func))
659
690
  return env.Null();
660
691
  } else {
661
692
  ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, not %1", info.Length());
@@ -784,6 +815,7 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
784
815
  ADD_CONVENTION("cdecl", CallConvention::Cdecl);
785
816
  ADD_CONVENTION("stdcall", CallConvention::Stdcall);
786
817
  ADD_CONVENTION("fastcall", CallConvention::Fastcall);
818
+ ADD_CONVENTION("thiscall", CallConvention::Thiscall);
787
819
 
788
820
  #undef ADD_CONVENTION
789
821
 
@@ -928,8 +960,23 @@ InstanceData::InstanceData()
928
960
  {
929
961
  InstanceMemory *mem = new InstanceMemory();
930
962
 
931
- mem->stack = AllocateAndAlign16(&mem->mem_alloc, Mebibytes(2));
932
- mem->heap = AllocateAndAlign16(&mem->mem_alloc, Mebibytes(4));
963
+ mem->stack.len = SyncStackSize;
964
+ #if defined(_WIN32)
965
+ mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
966
+ #elif defined(__APPLE__)
967
+ mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
968
+ #else
969
+ mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
970
+ #endif
971
+ RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
972
+
973
+ mem->heap.len = SyncHeapSize;
974
+ #ifdef _WIN32
975
+ mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
976
+ #else
977
+ mem->heap.ptr = (uint8_t *)mmap(nullptr, mem->heap.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
978
+ #endif
979
+ RG_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
933
980
 
934
981
  memories.Append(mem);
935
982
  }
@@ -957,7 +1004,6 @@ static void SetExports(Napi::Env env, Func func)
957
1004
  func("out", Napi::Function::New(env, MarkOut));
958
1005
  func("inout", Napi::Function::New(env, MarkInOut));
959
1006
 
960
- func("internal", Napi::Boolean::New(env, true));
961
1007
  #if defined(_WIN32)
962
1008
  func("extension", Napi::String::New(env, ".dll"));
963
1009
  #elif defined(__APPLE__)
@@ -1009,6 +1055,7 @@ static void InitInternal(v8::Local<v8::Object> target, v8::Local<v8::Value>,
1009
1055
  FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
1010
1056
 
1011
1057
  SetExports(env_napi, [&](const char *name, Napi::Value value) { SetValue(env, target, name, value); });
1058
+ SetValue(env, target, "internal", Napi::Boolean::New(env_cxx, true));
1012
1059
  }
1013
1060
 
1014
1061
  #else
@@ -1024,6 +1071,7 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
1024
1071
  FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
1025
1072
 
1026
1073
  SetExports(env, [&](const char *name, Napi::Value value) { exports.Set(name, value); });
1074
+ exports.Set("internal", Napi::Boolean::New(env, false));
1027
1075
 
1028
1076
  return exports;
1029
1077
  }
package/src/ffi.hh CHANGED
@@ -109,12 +109,14 @@ struct LibraryHolder {
109
109
  enum class CallConvention {
110
110
  Cdecl,
111
111
  Stdcall,
112
- Fastcall
112
+ Fastcall,
113
+ Thiscall
113
114
  };
114
115
  static const char *const CallConventionNames[] = {
115
116
  "Cdecl",
116
117
  "Stdcall",
117
- "Fastcall"
118
+ "Fastcall",
119
+ "Thiscall"
118
120
  };
119
121
 
120
122
  struct ParameterInfo {
@@ -139,6 +141,11 @@ struct ParameterInfo {
139
141
  #elif defined(__i386__) || defined(_M_IX86)
140
142
  bool trivial; // Only matters for return value
141
143
  bool fast;
144
+ #elif __riscv_xlen == 64
145
+ bool use_memory;
146
+ int8_t gpr_count;
147
+ int8_t vec_count;
148
+ bool gpr_first; // Only for structs
142
149
  #endif
143
150
  };
144
151
 
@@ -160,9 +167,12 @@ struct FunctionInfo {
160
167
  // ABI-specific part
161
168
 
162
169
  Size args_size;
163
- #if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__) || defined(_WIN64)
170
+ #if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__) || defined(_WIN64) || defined(__riscv)
164
171
  bool forward_fp;
165
172
  #endif
173
+ #if defined(__i386__) || defined(_M_IX86)
174
+ bool fast;
175
+ #endif
166
176
 
167
177
  ~FunctionInfo();
168
178
 
@@ -171,8 +181,6 @@ struct FunctionInfo {
171
181
  };
172
182
 
173
183
  struct InstanceMemory {
174
- LinkedAllocator mem_alloc;
175
-
176
184
  Span<uint8_t> stack;
177
185
  Span<uint8_t> heap;
178
186