koffi 1.1.0 → 1.1.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 (43) hide show
  1. package/CMakeLists.txt +10 -7
  2. package/README.md +29 -28
  3. package/build/qemu/1.1.3/koffi_darwin_x64.tar.gz +0 -0
  4. package/build/qemu/1.1.3/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/build/qemu/1.1.3/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/build/qemu/1.1.3/koffi_freebsd_x64.tar.gz +0 -0
  7. package/build/qemu/1.1.3/koffi_linux_arm.tar.gz +0 -0
  8. package/build/qemu/1.1.3/koffi_linux_arm64.tar.gz +0 -0
  9. package/build/qemu/1.1.3/koffi_linux_ia32.tar.gz +0 -0
  10. package/build/qemu/1.1.3/koffi_linux_x64.tar.gz +0 -0
  11. package/build/qemu/1.1.3/koffi_openbsd_x64.tar.gz +0 -0
  12. package/build/qemu/1.1.3/koffi_win32_ia32.tar.gz +0 -0
  13. package/build/qemu/1.1.3/koffi_win32_x64.tar.gz +0 -0
  14. package/package.json +2 -2
  15. package/qemu/qemu.js +1 -1
  16. package/qemu/registry/machines.json +47 -3
  17. package/qemu/registry/sha256sum.txt +16 -12
  18. package/src/abi_arm32.cc +43 -4
  19. package/src/abi_arm64.cc +22 -5
  20. package/src/abi_x64_sysv.cc +1 -1
  21. package/src/abi_x64_win.cc +1 -1
  22. package/src/abi_x86.cc +10 -4
  23. package/src/call.cc +213 -44
  24. package/src/call.hh +2 -2
  25. package/src/ffi.cc +63 -36
  26. package/src/ffi.hh +10 -4
  27. package/src/parser.cc +46 -24
  28. package/src/parser.hh +3 -1
  29. package/src/util.hh +1 -1
  30. package/test/CMakeLists.txt +3 -0
  31. package/test/misc.c +17 -0
  32. package/vendor/libcc/libcc.cc +7 -7
  33. package/vendor/libcc/libcc.hh +4 -1
  34. package/build/qemu/1.1.0/koffi_darwin_x64.tar.gz +0 -0
  35. package/build/qemu/1.1.0/koffi_freebsd_arm64.tar.gz +0 -0
  36. package/build/qemu/1.1.0/koffi_freebsd_ia32.tar.gz +0 -0
  37. package/build/qemu/1.1.0/koffi_freebsd_x64.tar.gz +0 -0
  38. package/build/qemu/1.1.0/koffi_linux_arm.tar.gz +0 -0
  39. package/build/qemu/1.1.0/koffi_linux_arm64.tar.gz +0 -0
  40. package/build/qemu/1.1.0/koffi_linux_ia32.tar.gz +0 -0
  41. package/build/qemu/1.1.0/koffi_linux_x64.tar.gz +0 -0
  42. package/build/qemu/1.1.0/koffi_win32_ia32.tar.gz +0 -0
  43. package/build/qemu/1.1.0/koffi_win32_x64.tar.gz +0 -0
package/src/call.cc CHANGED
@@ -142,21 +142,77 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
142
142
  bool b = value.As<Napi::Boolean>();
143
143
  *(bool *)dest = b;
144
144
  } break;
145
- case PrimitiveKind::Int8:
146
- case PrimitiveKind::UInt8:
147
- case PrimitiveKind::Int16:
148
- case PrimitiveKind::UInt16:
149
- case PrimitiveKind::Int32:
150
- case PrimitiveKind::UInt32:
151
- case PrimitiveKind::Int64:
152
- case PrimitiveKind::UInt64: {
145
+ case PrimitiveKind::Int8: {
146
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
147
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
148
+ return false;
149
+ }
150
+
151
+ int8_t v = CopyNumber<int8_t>(value);
152
+ *(int8_t *)dest = v;
153
+ } break;
154
+ case PrimitiveKind::UInt8: {
155
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
156
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
157
+ return false;
158
+ }
159
+
160
+ uint8_t v = CopyNumber<uint8_t>(value);
161
+ *(uint8_t *)dest = v;
162
+ } break;
163
+ case PrimitiveKind::Int16: {
164
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
165
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
166
+ return false;
167
+ }
168
+
169
+ int16_t v = CopyNumber<int16_t>(value);
170
+ *(int16_t *)dest = v;
171
+ } break;
172
+ case PrimitiveKind::UInt16: {
173
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
174
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
175
+ return false;
176
+ }
177
+
178
+ uint16_t v = CopyNumber<uint16_t>(value);
179
+ *(uint16_t *)dest = v;
180
+ } break;
181
+ case PrimitiveKind::Int32: {
182
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
183
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
184
+ return false;
185
+ }
186
+
187
+ int32_t v = CopyNumber<int32_t>(value);
188
+ *(int32_t *)dest = v;
189
+ } break;
190
+ case PrimitiveKind::UInt32: {
191
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
192
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
193
+ return false;
194
+ }
195
+
196
+ uint32_t v = CopyNumber<uint32_t>(value);
197
+ *(uint32_t *)dest = v;
198
+ } break;
199
+ case PrimitiveKind::Int64: {
153
200
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
154
201
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
155
202
  return false;
156
203
  }
157
204
 
158
205
  int64_t v = CopyNumber<int64_t>(value);
159
- memcpy(dest, &v, member.type->size); // Little Endian
206
+ *(int64_t *)dest = v;
207
+ } break;
208
+ case PrimitiveKind::UInt64: {
209
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
210
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
211
+ return false;
212
+ }
213
+
214
+ uint64_t v = CopyNumber<uint64_t>(value);
215
+ *(uint64_t *)dest = v;
160
216
  } break;
161
217
  case PrimitiveKind::String: {
162
218
  if (RG_UNLIKELY(!value.IsString())) {
@@ -196,12 +252,12 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
196
252
  return false;
197
253
  }
198
254
 
199
- Napi::Object obj = value.As<Napi::Object>();
200
- if (!PushObject(obj, member.type, dest, realign))
255
+ Napi::Object obj2 = value.As<Napi::Object>();
256
+ if (!PushObject(obj2, member.type, dest, realign))
201
257
  return false;
202
258
  } break;
203
259
  case PrimitiveKind::Array: {
204
- if (RG_UNLIKELY(!value.IsArray() && !value.IsTypedArray())) {
260
+ if (RG_UNLIKELY(!value.IsArray() && !value.IsTypedArray() && !value.IsString())) {
205
261
  ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected array", GetValueType(instance, value), member.name);
206
262
  return false;
207
263
  }
@@ -236,9 +292,9 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
236
292
  return true;
237
293
  }
238
294
 
239
- bool CallData::PushArray(const Napi::Object &obj, 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)
240
296
  {
241
- RG_ASSERT(obj.IsArray() || obj.IsTypedArray());
297
+ RG_ASSERT(obj.IsArray() || obj.IsTypedArray() || obj.IsString());
242
298
  RG_ASSERT(type->primitive == PrimitiveKind::Array);
243
299
 
244
300
  uint32_t len = type->size / type->ref->size;
@@ -279,17 +335,52 @@ bool CallData::PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t
279
335
  *(bool *)dest = b;
280
336
  });
281
337
  } break;
282
- case PrimitiveKind::Int8:
283
- case PrimitiveKind::UInt8:
284
- case PrimitiveKind::Int16:
285
- case PrimitiveKind::UInt16:
286
- case PrimitiveKind::Int32:
287
- case PrimitiveKind::UInt32:
288
- case PrimitiveKind::Int64:
289
- case PrimitiveKind::UInt64: {
338
+ case PrimitiveKind::Int8: {
339
+ PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
340
+ int8_t v = CopyNumber<int8_t>(value);
341
+ *(int8_t *)dest = v;
342
+ });
343
+ } break;
344
+ case PrimitiveKind::UInt8: {
345
+ PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
346
+ uint8_t v = CopyNumber<uint8_t>(value);
347
+ *(uint8_t *)dest = v;
348
+ });
349
+ } break;
350
+ case PrimitiveKind::Int16: {
351
+ PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
352
+ int16_t v = CopyNumber<int16_t>(value);
353
+ *(int16_t *)dest = v;
354
+ });
355
+ } break;
356
+ case PrimitiveKind::UInt16: {
357
+ PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
358
+ uint16_t v = CopyNumber<uint16_t>(value);
359
+ *(uint16_t *)dest = v;
360
+ });
361
+ } break;
362
+ case PrimitiveKind::Int32: {
363
+ PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
364
+ int32_t v = CopyNumber<int32_t>(value);
365
+ *(int32_t *)dest = v;
366
+ });
367
+ } break;
368
+ case PrimitiveKind::UInt32: {
369
+ PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
370
+ uint32_t v = CopyNumber<uint32_t>(value);
371
+ *(uint32_t *)dest = v;
372
+ });
373
+ } break;
374
+ case PrimitiveKind::Int64: {
290
375
  PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
291
376
  int64_t v = CopyNumber<int64_t>(value);
292
- memcpy(dest, &v, type->ref->size); // Little Endian
377
+ *(int64_t *)dest = v;
378
+ });
379
+ } break;
380
+ case PrimitiveKind::UInt64: {
381
+ PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
382
+ uint64_t v = CopyNumber<uint64_t>(value);
383
+ *(uint64_t *)dest = v;
293
384
  });
294
385
  } break;
295
386
  case PrimitiveKind::String: {
@@ -316,15 +407,15 @@ bool CallData::PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t
316
407
  } break;
317
408
  case PrimitiveKind::Record: {
318
409
  PUSH_ARRAY(IsObject(value), "object", {
319
- Napi::Object obj = value.As<Napi::Object>();
320
- if (!PushObject(obj, type->ref, dest, realign))
410
+ Napi::Object obj2 = value.As<Napi::Object>();
411
+ if (!PushObject(obj2, type->ref, dest, realign))
321
412
  return false;
322
413
  });
323
414
  } break;
324
415
  case PrimitiveKind::Array: {
325
- PUSH_ARRAY(value.IsArray() || value.IsTypedArray(), "array", {
326
- Napi::Object array = value.As<Napi::Array>();
327
- if (!PushArray(array, type->ref, dest, realign))
416
+ PUSH_ARRAY(value.IsArray() || value.IsTypedArray() || value.IsString(), "array", {
417
+ Napi::Object array2 = value.As<Napi::Array>();
418
+ if (!PushArray(array2, type->ref, dest, realign))
328
419
  return false;
329
420
  });
330
421
  } break;
@@ -343,7 +434,7 @@ bool CallData::PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t
343
434
  }
344
435
 
345
436
  #undef PUSH_ARRAY
346
- } else {
437
+ } else if (obj.IsTypedArray()) {
347
438
  Napi::TypedArray array = obj.As<Napi::TypedArray>();
348
439
  const uint8_t *buf = (const uint8_t *)array.ArrayBuffer().Data();
349
440
 
@@ -378,6 +469,25 @@ bool CallData::PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t
378
469
 
379
470
  dest += type->ref->size;
380
471
  }
472
+ } else if (obj.IsString()) {
473
+ size_t encoded = 0;
474
+
475
+ if (type->ref->primitive == PrimitiveKind::Int8 || type->ref->primitive == PrimitiveKind::UInt8) {
476
+ napi_status status = napi_get_value_string_utf8(env, obj, (char *)dest, type->size, &encoded);
477
+ RG_ASSERT(status == napi_ok);
478
+ } else if (type->ref->primitive == PrimitiveKind::Int16 || type->ref->primitive == PrimitiveKind::UInt16) {
479
+ napi_status status = napi_get_value_string_utf16(env, obj, (char16_t *)dest, type->size / 2, &encoded);
480
+ RG_ASSERT(status == napi_ok);
481
+
482
+ encoded *= 2;
483
+ } else {
484
+ ThrowError<Napi::TypeError>(env, "Strings cannot be converted to %1 array", type->ref->name);
485
+ return false;
486
+ }
487
+
488
+ memset_safe(dest + encoded, 0, type->size - encoded);
489
+ } else {
490
+ RG_UNREACHABLE();
381
491
  }
382
492
 
383
493
  return true;
@@ -451,8 +561,8 @@ void CallData::PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *t
451
561
  obj.Set(member.name, obj2);
452
562
  } break;
453
563
  case PrimitiveKind::Array: {
454
- Napi::Object obj2 = PopArray(src, member.type, realign);
455
- obj.Set(member.name, obj2);
564
+ Napi::Value value = PopArray(src, member.type, realign);
565
+ obj.Set(member.name, value);
456
566
  } break;
457
567
  case PrimitiveKind::Float32: {
458
568
  float f;
@@ -477,7 +587,18 @@ Napi::Object CallData::PopObject(const uint8_t *src, const TypeInfo *type, int16
477
587
  return obj;
478
588
  }
479
589
 
480
- Napi::Object CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_t realign)
590
+ Size WideStringLength(const char16_t *str16, Size max)
591
+ {
592
+ Size len = 0;
593
+
594
+ while (len < max && str16[len]) {
595
+ len++;
596
+ }
597
+
598
+ return len;
599
+ }
600
+
601
+ Napi::Value CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_t realign)
481
602
  {
482
603
  RG_ASSERT(type->primitive == PrimitiveKind::Array);
483
604
 
@@ -500,7 +621,12 @@ Napi::Object CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_
500
621
  } while (false)
501
622
  #define POP_NUMBER_ARRAY(TypedArrayType, CType) \
502
623
  do { \
503
- if (type->hint == TypeInfo::ArrayHint::TypedArray) { \
624
+ if (type->hint == TypeInfo::ArrayHint::Array) { \
625
+ POP_ARRAY({ \
626
+ double d = (double)*(CType *)src; \
627
+ array.Set(i, Napi::Number::New(env, d)); \
628
+ }); \
629
+ } else { \
504
630
  Napi::TypedArrayType array = Napi::TypedArrayType::New(env, len); \
505
631
  \
506
632
  for (uint32_t i = 0; i < len; i++) { \
@@ -514,11 +640,6 @@ Napi::Object CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_
514
640
  } \
515
641
  \
516
642
  return array; \
517
- } else { \
518
- POP_ARRAY({ \
519
- double d = (double)*(CType *)src; \
520
- array.Set(i, Napi::Number::New(env, d)); \
521
- }); \
522
643
  } \
523
644
  } while (false)
524
645
 
@@ -531,10 +652,58 @@ Napi::Object CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_
531
652
  array.Set(i, Napi::Boolean::New(env, b));
532
653
  });
533
654
  } break;
534
- case PrimitiveKind::Int8: { POP_NUMBER_ARRAY(Int8Array, int8_t); } break;
535
- case PrimitiveKind::UInt8: { POP_NUMBER_ARRAY(Uint8Array, uint8_t); } break;
536
- case PrimitiveKind::Int16: { POP_NUMBER_ARRAY(Int16Array, int16_t); } break;
537
- case PrimitiveKind::UInt16: { POP_NUMBER_ARRAY(Uint16Array, uint16_t); } break;
655
+ case PrimitiveKind::Int8: {
656
+ if (type->hint == TypeInfo::ArrayHint::String) {
657
+ RG_ASSERT(!realign);
658
+
659
+ const char *ptr = (const char *)src;
660
+ size_t count = strnlen(ptr, (size_t)len);
661
+
662
+ Napi::String str = Napi::String::New(env, ptr, count);
663
+ return str;
664
+ }
665
+
666
+ POP_NUMBER_ARRAY(Int8Array, int8_t);
667
+ } break;
668
+ case PrimitiveKind::UInt8: {
669
+ if (type->hint == TypeInfo::ArrayHint::String) {
670
+ RG_ASSERT(!realign);
671
+
672
+ const char *ptr = (const char *)src;
673
+ size_t count = strnlen(ptr, (size_t)len);
674
+
675
+ Napi::String str = Napi::String::New(env, ptr, count);
676
+ return str;
677
+ }
678
+
679
+ POP_NUMBER_ARRAY(Uint8Array, uint8_t);
680
+ } break;
681
+ case PrimitiveKind::Int16: {
682
+ if (type->hint == TypeInfo::ArrayHint::String) {
683
+ RG_ASSERT(!realign);
684
+
685
+ const char16_t *ptr = (const char16_t *)src;
686
+ Size count = WideStringLength(ptr, len);
687
+
688
+ Napi::String str = Napi::String::New(env, ptr, count);
689
+ return str;
690
+ }
691
+
692
+ POP_NUMBER_ARRAY(Int16Array, int16_t);
693
+ } break;
694
+ case PrimitiveKind::UInt16: {
695
+ if (type->hint == TypeInfo::ArrayHint::String) {
696
+ RG_ASSERT(!realign);
697
+
698
+ const char16_t *ptr = (const char16_t *)src;
699
+ Size count = WideStringLength(ptr, len);
700
+
701
+ Napi::String str = Napi::String::New(env, ptr, count);
702
+ return str;
703
+ }
704
+
705
+ POP_NUMBER_ARRAY(Uint16Array, uint16_t);
706
+ } break;
538
707
  case PrimitiveKind::Int32: { POP_NUMBER_ARRAY(Int32Array, int32_t); } break;
539
708
  case PrimitiveKind::UInt32: { POP_NUMBER_ARRAY(Uint32Array, uint32_t); } break;
540
709
  case PrimitiveKind::Int64: {
@@ -579,8 +748,8 @@ Napi::Object CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_
579
748
  } break;
580
749
  case PrimitiveKind::Array: {
581
750
  POP_ARRAY({
582
- Napi::Object obj = PopArray(src, type->ref, realign);
583
- array.Set(i, obj);
751
+ Napi::Value value = PopArray(src, type->ref, realign);
752
+ array.Set(i, value);
584
753
  });
585
754
  } break;
586
755
  case PrimitiveKind::Float32: { POP_NUMBER_ARRAY(Float32Array, float); } break;
package/src/call.hh CHANGED
@@ -78,11 +78,11 @@ private:
78
78
  const char *PushString(const Napi::Value &value);
79
79
  const char16_t *PushString16(const Napi::Value &value);
80
80
  bool PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
81
- bool PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
81
+ bool PushArray(const Napi::Value &obj, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
82
82
 
83
83
  void PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
84
84
  Napi::Object PopObject(const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
85
- Napi::Object PopArray(const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
85
+ Napi::Value PopArray(const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
86
86
  };
87
87
 
88
88
  template <typename T>
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
 
@@ -274,6 +280,8 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
274
280
  hint = TypeInfo::ArrayHint::TypedArray;
275
281
  } else if (to == "array") {
276
282
  hint = TypeInfo::ArrayHint::Array;
283
+ } else if (to == "string") {
284
+ hint = TypeInfo::ArrayHint::String;
277
285
  } else {
278
286
  ThrowError<Napi::Error>(env, "Array conversion hint must be 'typed' or 'array'");
279
287
  return env.Null();
@@ -297,7 +305,6 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
297
305
  }
298
306
 
299
307
  TypeInfo *type = instance->types.AppendDefault();
300
- RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
301
308
 
302
309
  type->name = Fmt(&instance->str_alloc, "%1[%2]", ref->name, len).ptr;
303
310
 
@@ -307,13 +314,6 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
307
314
  type->ref = ref;
308
315
  type->hint = hint;
309
316
 
310
- // If the insert succeeds, we cannot fail anymore
311
- if (!instance->types_map.TrySet(type).second) {
312
- ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
313
- return env.Null();
314
- }
315
- err_guard.Disable();
316
-
317
317
  Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
318
318
  SetValueTag(instance, external, &TypeInfoMarker);
319
319
 
@@ -375,32 +375,34 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
375
375
  return type->defn.Value();
376
376
  }
377
377
 
378
- static Span<uint8_t> AllocateAndAlign16(Allocator *alloc, Size size)
378
+ static InstanceMemory *AllocateAsyncMemory(InstanceData *instance)
379
379
  {
380
- RG_ASSERT(AlignLen(size, 16) == size);
381
- RG_ASSERT(size >= Kibibytes(1));
380
+ for (Size i = 1; i < instance->memories.len; i++) {
381
+ InstanceMemory *mem = instance->memories[i];
382
382
 
383
- // Account for allocator overhead
384
- size -= 256;
385
-
386
- uint8_t *ptr = (uint8_t *)Allocator::Allocate(alloc, size);
387
- uint8_t *aligned = AlignUp(ptr, 16);
388
- Size delta = AlignLen(aligned - ptr, 16);
389
-
390
- return MakeSpan(aligned, size - delta);
391
- }
392
-
393
- static InstanceMemory *AllocateCallMemory(InstanceData *instance)
394
- {
395
- for (InstanceMemory *mem: instance->memories) {
396
383
  if (!mem->depth)
397
384
  return mem;
398
385
  }
399
386
 
400
387
  InstanceMemory *mem = new InstanceMemory();
401
388
 
402
- mem->stack = AllocateAndAlign16(&mem->mem_alloc, Mebibytes(1));
403
- mem->heap = AllocateAndAlign16(&mem->mem_alloc, Mebibytes(2));
389
+ mem->stack.len = AsyncStackSize;
390
+ #if defined(_WIN32)
391
+ mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
392
+ #elif defined(__APPLE__)
393
+ mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
394
+ #else
395
+ mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
396
+ #endif
397
+ RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
398
+
399
+ mem->heap.len = AsyncHeapSize;
400
+ #ifdef _WIN32
401
+ mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
402
+ #else
403
+ mem->heap.ptr = (uint8_t *)mmap(nullptr, mem->heap.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
404
+ #endif
405
+ RG_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
404
406
 
405
407
  if (instance->memories.Available()) {
406
408
  instance->memories.Append(mem);
@@ -422,7 +424,7 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
422
424
  return env.Null();
423
425
  }
424
426
 
425
- InstanceMemory *mem = AllocateCallMemory(instance);
427
+ InstanceMemory *mem = instance->memories[0];
426
428
  CallData call(env, instance, func, mem);
427
429
 
428
430
  return call.Run(info);
@@ -482,7 +484,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
482
484
  if (RG_UNLIKELY(!AnalyseFunction(instance, &func)))
483
485
  return env.Null();
484
486
 
485
- InstanceMemory *mem = AllocateCallMemory(instance);
487
+ InstanceMemory *mem = instance->memories[0];
486
488
  CallData call(env, instance, &func, mem);
487
489
 
488
490
  return call.Run(info);
@@ -558,7 +560,7 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
558
560
  return env.Null();
559
561
  }
560
562
 
561
- InstanceMemory *mem = AllocateCallMemory(instance);
563
+ InstanceMemory *mem = AllocateAsyncMemory(instance);
562
564
  AsyncCall *async = new AsyncCall(env, instance, func, mem, callback);
563
565
 
564
566
  if (async->Prepare(info) && instance->debug) {
@@ -601,10 +603,10 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
601
603
  return false;
602
604
  }
603
605
 
604
- Size parameters_len = parameters.Length();
606
+ uint32_t parameters_len = parameters.Length();
605
607
 
606
608
  if (parameters_len) {
607
- Napi::String str = ((Napi::Value)parameters[(uint32_t)(parameters_len - 1)]).As<Napi::String>();
609
+ Napi::String str = ((Napi::Value)parameters[parameters_len - 1]).As<Napi::String>();
608
610
 
609
611
  if (str.IsString() && str.Utf8Value() == "...") {
610
612
  func->variadic = true;
@@ -657,9 +659,13 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
657
659
  if (!ParseClassicFunction(env, info[0u].As<Napi::String>(), info[1u], info[2u].As<Napi::Array>(), func))
658
660
  return env.Null();
659
661
  } else if (info.Length() >= 1) {
660
- PrototypeParser parser(env);
662
+ if (!info[0].IsString()) {
663
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for prototype, expected string", GetValueType(instance, info[0]));
664
+ return env.Null();
665
+ }
661
666
 
662
- if (!parser.Parse(info[0u].As<Napi::String>(), func))
667
+ std::string proto = info[0u].As<Napi::String>();
668
+ if (!ParsePrototype(env, proto.c_str(), func))
663
669
  return env.Null();
664
670
  } else {
665
671
  ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, not %1", info.Length());
@@ -788,6 +794,7 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
788
794
  ADD_CONVENTION("cdecl", CallConvention::Cdecl);
789
795
  ADD_CONVENTION("stdcall", CallConvention::Stdcall);
790
796
  ADD_CONVENTION("fastcall", CallConvention::Fastcall);
797
+ ADD_CONVENTION("thiscall", CallConvention::Thiscall);
791
798
 
792
799
  #undef ADD_CONVENTION
793
800
 
@@ -930,8 +937,27 @@ void FunctionInfo::Unref() const
930
937
 
931
938
  InstanceData::InstanceData()
932
939
  {
933
- AllocateCallMemory(this);
934
- RG_ASSERT(memories.len == 1);
940
+ InstanceMemory *mem = new InstanceMemory();
941
+
942
+ mem->stack.len = SyncStackSize;
943
+ #if defined(_WIN32)
944
+ mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
945
+ #elif defined(__APPLE__)
946
+ mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
947
+ #else
948
+ mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
949
+ #endif
950
+ RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
951
+
952
+ mem->heap.len = SyncHeapSize;
953
+ #ifdef _WIN32
954
+ mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
955
+ #else
956
+ mem->heap.ptr = (uint8_t *)mmap(nullptr, mem->heap.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
957
+ #endif
958
+ RG_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
959
+
960
+ memories.Append(mem);
935
961
  }
936
962
 
937
963
  InstanceData::~InstanceData()
@@ -957,7 +983,6 @@ static void SetExports(Napi::Env env, Func func)
957
983
  func("out", Napi::Function::New(env, MarkOut));
958
984
  func("inout", Napi::Function::New(env, MarkInOut));
959
985
 
960
- func("internal", Napi::Boolean::New(env, true));
961
986
  #if defined(_WIN32)
962
987
  func("extension", Napi::String::New(env, ".dll"));
963
988
  #elif defined(__APPLE__)
@@ -1009,6 +1034,7 @@ static void InitInternal(v8::Local<v8::Object> target, v8::Local<v8::Value>,
1009
1034
  FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
1010
1035
 
1011
1036
  SetExports(env_napi, [&](const char *name, Napi::Value value) { SetValue(env, target, name, value); });
1037
+ SetValue(env, target, "internal", Napi::Boolean::New(env_cxx, true));
1012
1038
  }
1013
1039
 
1014
1040
  #else
@@ -1024,6 +1050,7 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
1024
1050
  FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
1025
1051
 
1026
1052
  SetExports(env, [&](const char *name, Napi::Value value) { exports.Set(name, value); });
1053
+ exports.Set("internal", Napi::Boolean::New(env, false));
1027
1054
 
1028
1055
  return exports;
1029
1056
  }
package/src/ffi.hh CHANGED
@@ -69,7 +69,8 @@ struct RecordMember;
69
69
  struct TypeInfo {
70
70
  enum class ArrayHint {
71
71
  Array,
72
- TypedArray
72
+ TypedArray,
73
+ String
73
74
  };
74
75
 
75
76
  const char *name;
@@ -108,12 +109,14 @@ struct LibraryHolder {
108
109
  enum class CallConvention {
109
110
  Cdecl,
110
111
  Stdcall,
111
- Fastcall
112
+ Fastcall,
113
+ Thiscall
112
114
  };
113
115
  static const char *const CallConventionNames[] = {
114
116
  "Cdecl",
115
117
  "Stdcall",
116
- "Fastcall"
118
+ "Fastcall",
119
+ "Thiscall"
117
120
  };
118
121
 
119
122
  struct ParameterInfo {
@@ -162,6 +165,9 @@ struct FunctionInfo {
162
165
  #if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__) || defined(_WIN64)
163
166
  bool forward_fp;
164
167
  #endif
168
+ #if defined(__i386__) || defined(_M_IX86)
169
+ bool fast;
170
+ #endif
165
171
 
166
172
  ~FunctionInfo();
167
173
 
@@ -189,7 +195,7 @@ struct InstanceData {
189
195
  bool debug;
190
196
  uint64_t tag_lower;
191
197
 
192
- LocalArray<InstanceMemory *, 8> memories;
198
+ LocalArray<InstanceMemory *, 6> memories;
193
199
 
194
200
  BlockAllocator str_alloc;
195
201
  };