koffi 1.3.4 → 1.3.5

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 (63) hide show
  1. package/CMakeLists.txt +1 -1
  2. package/ChangeLog.md +13 -1
  3. package/build/qemu/1.3.5/koffi_darwin_arm64.tar.gz +0 -0
  4. package/build/qemu/1.3.5/koffi_darwin_x64.tar.gz +0 -0
  5. package/build/qemu/1.3.5/koffi_freebsd_arm64.tar.gz +0 -0
  6. package/build/qemu/1.3.5/koffi_freebsd_ia32.tar.gz +0 -0
  7. package/build/qemu/1.3.5/koffi_freebsd_x64.tar.gz +0 -0
  8. package/build/qemu/1.3.5/koffi_linux_arm32hf.tar.gz +0 -0
  9. package/build/qemu/1.3.5/koffi_linux_arm64.tar.gz +0 -0
  10. package/build/qemu/1.3.5/koffi_linux_ia32.tar.gz +0 -0
  11. package/build/qemu/1.3.5/koffi_linux_riscv64hf64.tar.gz +0 -0
  12. package/build/qemu/1.3.5/koffi_linux_x64.tar.gz +0 -0
  13. package/build/qemu/1.3.5/koffi_openbsd_ia32.tar.gz +0 -0
  14. package/build/qemu/1.3.5/koffi_openbsd_x64.tar.gz +0 -0
  15. package/build/qemu/1.3.5/koffi_win32_arm64.tar.gz +0 -0
  16. package/build/qemu/1.3.5/koffi_win32_ia32.tar.gz +0 -0
  17. package/build/qemu/1.3.5/koffi_win32_x64.tar.gz +0 -0
  18. package/doc/dist/doctrees/changes.doctree +0 -0
  19. package/doc/dist/doctrees/environment.pickle +0 -0
  20. package/doc/dist/doctrees/functions.doctree +0 -0
  21. package/doc/dist/doctrees/index.doctree +0 -0
  22. package/doc/dist/doctrees/memory.doctree +0 -0
  23. package/doc/dist/doctrees/start.doctree +0 -0
  24. package/doc/dist/doctrees/types.doctree +0 -0
  25. package/doc/dist/html/_sources/functions.md.txt +16 -14
  26. package/doc/dist/html/_sources/memory.md.txt +6 -3
  27. package/doc/dist/html/_sources/start.md.txt +3 -3
  28. package/doc/dist/html/_sources/types.md.txt +10 -8
  29. package/doc/dist/html/changes.html +15 -1
  30. package/doc/dist/html/functions.html +16 -19
  31. package/doc/dist/html/index.html +4 -2
  32. package/doc/dist/html/memory.html +8 -3
  33. package/doc/dist/html/objects.inv +0 -0
  34. package/doc/dist/html/platforms.html +1 -1
  35. package/doc/dist/html/searchindex.js +1 -1
  36. package/doc/dist/html/start.html +3 -3
  37. package/doc/dist/html/types.html +9 -8
  38. package/doc/functions.md +16 -14
  39. package/doc/memory.md +6 -3
  40. package/doc/start.md +3 -3
  41. package/doc/types.md +10 -8
  42. package/package.json +2 -2
  43. package/qemu/registry/machines.json +6 -11
  44. package/src/abi_x86.cc +0 -5
  45. package/src/call.cc +2 -1
  46. package/src/ffi.cc +71 -22
  47. package/src/ffi.hh +11 -4
  48. package/test/async.js +1 -1
  49. package/build/qemu/1.3.4/koffi_darwin_arm64.tar.gz +0 -0
  50. package/build/qemu/1.3.4/koffi_darwin_x64.tar.gz +0 -0
  51. package/build/qemu/1.3.4/koffi_freebsd_arm64.tar.gz +0 -0
  52. package/build/qemu/1.3.4/koffi_freebsd_ia32.tar.gz +0 -0
  53. package/build/qemu/1.3.4/koffi_freebsd_x64.tar.gz +0 -0
  54. package/build/qemu/1.3.4/koffi_linux_arm32hf.tar.gz +0 -0
  55. package/build/qemu/1.3.4/koffi_linux_arm64.tar.gz +0 -0
  56. package/build/qemu/1.3.4/koffi_linux_ia32.tar.gz +0 -0
  57. package/build/qemu/1.3.4/koffi_linux_riscv64hf64.tar.gz +0 -0
  58. package/build/qemu/1.3.4/koffi_linux_x64.tar.gz +0 -0
  59. package/build/qemu/1.3.4/koffi_openbsd_ia32.tar.gz +0 -0
  60. package/build/qemu/1.3.4/koffi_openbsd_x64.tar.gz +0 -0
  61. package/build/qemu/1.3.4/koffi_win32_arm64.tar.gz +0 -0
  62. package/build/qemu/1.3.4/koffi_win32_ia32.tar.gz +0 -0
  63. package/build/qemu/1.3.4/koffi_win32_x64.tar.gz +0 -0
package/src/ffi.cc CHANGED
@@ -43,7 +43,7 @@ namespace RG {
43
43
  // Value does not matter, the tag system uses memory addresses
44
44
  const int TypeInfoMarker = 0xDEADBEEF;
45
45
 
46
- static bool ChangeMemorySize(Napi::Value value, Size *out_size)
46
+ static bool ChangeMemorySize(const char *name, Napi::Value value, Size *out_size)
47
47
  {
48
48
  const Size MinSize = Kibibytes(1);
49
49
  const Size MaxSize = Mebibytes(16);
@@ -51,14 +51,16 @@ static bool ChangeMemorySize(Napi::Value value, Size *out_size)
51
51
  Napi::Env env = value.Env();
52
52
 
53
53
  if (!value.IsNumber()) {
54
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for memory size, expected number");
55
- return env.Null();
54
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
55
+
56
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for '%2', expected number", GetValueType(instance, value), name);
57
+ return false;
56
58
  }
57
59
 
58
60
  int64_t size = value.As<Napi::Number>().Int64Value();
59
61
 
60
62
  if (size < MinSize || size > MaxSize) {
61
- ThrowError<Napi::Error>(env, "Memory size must be between %1 and %2", FmtMemSize(MinSize), FmtMemSize(MaxSize));
63
+ ThrowError<Napi::Error>(env, "Setting '%1' must be between %2 and %3", name, FmtMemSize(MinSize), FmtMemSize(MaxSize));
62
64
  return false;
63
65
  }
64
66
 
@@ -66,6 +68,28 @@ static bool ChangeMemorySize(Napi::Value value, Size *out_size)
66
68
  return true;
67
69
  }
68
70
 
71
+ static bool ChangeAsyncLimit(const char *name, Napi::Value value, int max, int *out_limit)
72
+ {
73
+ Napi::Env env = value.Env();
74
+
75
+ if (!value.IsNumber()) {
76
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
77
+
78
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for '%2', expected number", GetValueType(instance, value), name);
79
+ return false;
80
+ }
81
+
82
+ int64_t n = value.As<Napi::Number>().Int64Value();
83
+
84
+ if (n < 0 || n > max) {
85
+ ThrowError<Napi::Error>(env, "Setting '%1' must be between 0 and %2", name, max);
86
+ return false;
87
+ }
88
+
89
+ *out_limit = (int)n;
90
+ return true;
91
+ }
92
+
69
93
  static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
70
94
  {
71
95
  Napi::Env env = info.Env();
@@ -82,6 +106,13 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
82
106
  return env.Null();
83
107
  }
84
108
 
109
+ Size sync_stack_size = instance->sync_stack_size;
110
+ Size sync_heap_size = instance->sync_heap_size;
111
+ Size async_stack_size = instance->async_stack_size;
112
+ Size async_heap_size = instance->async_heap_size;
113
+ int resident_async_pools = instance->resident_async_pools;
114
+ int max_async_calls = resident_async_pools + instance->max_temporaries;
115
+
85
116
  Napi::Object obj = info[0].As<Napi::Object>();
86
117
  Napi::Array keys = obj.GetPropertyNames();
87
118
 
@@ -90,38 +121,40 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
90
121
  Napi::Value value = obj[key];
91
122
 
92
123
  if (key == "sync_stack_size") {
93
- if (!ChangeMemorySize(value, &instance->sync_stack_size))
124
+ if (!ChangeMemorySize(key.c_str(), value, &sync_stack_size))
94
125
  return env.Null();
95
126
  } else if (key == "sync_heap_size") {
96
- if (!ChangeMemorySize(value, &instance->sync_heap_size))
127
+ if (!ChangeMemorySize(key.c_str(), value, &sync_heap_size))
97
128
  return env.Null();
98
129
  } else if (key == "async_stack_size") {
99
- if (!ChangeMemorySize(value, &instance->async_stack_size))
130
+ if (!ChangeMemorySize(key.c_str(), value, &async_stack_size))
100
131
  return env.Null();
101
132
  } else if (key == "async_heap_size") {
102
- if (!ChangeMemorySize(value, &instance->async_heap_size))
133
+ if (!ChangeMemorySize(key.c_str(), value, &async_heap_size))
103
134
  return env.Null();
104
135
  } else if (key == "resident_async_pools") {
105
- RG_STATIC_ASSERT(DefaultResidentAsyncPools <= RG_LEN(instance->memories.data));
106
-
107
- if (!value.IsNumber()) {
108
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for resident_async_pools, expected number");
136
+ if (!ChangeAsyncLimit(key.c_str(), value, RG_LEN(instance->memories.data) - 1, &resident_async_pools))
109
137
  return env.Null();
110
- }
111
-
112
- int64_t n = value.As<Napi::Number>().Int64Value();
113
-
114
- if (n < 0 || n > RG_LEN(instance->memories.data)) {
115
- ThrowError<Napi::Error>(env, "Parameter resident_async_pools must be between 0 and %1", RG_LEN(instance->memories.data));
138
+ } else if (key == "max_async_calls") {
139
+ if (!ChangeAsyncLimit(key.c_str(), value, MaxAsyncCalls, &max_async_calls))
116
140
  return env.Null();
117
- }
118
-
119
- instance->resident_async_pools = (int)n;
120
141
  } else {
121
142
  ThrowError<Napi::Error>(env, "Unexpected config member '%1'", key.c_str());
122
143
  return env.Null();
123
144
  }
124
145
  }
146
+
147
+ if (max_async_calls < resident_async_pools) {
148
+ ThrowError<Napi::Error>(env, "Setting max_async_calls must be >= to resident_async_pools");
149
+ return env.Null();
150
+ }
151
+
152
+ instance->sync_stack_size = sync_stack_size;
153
+ instance->sync_heap_size = sync_heap_size;
154
+ instance->async_stack_size = async_stack_size;
155
+ instance->async_heap_size = async_heap_size;
156
+ instance->resident_async_pools = resident_async_pools;
157
+ instance->max_temporaries = max_async_calls - resident_async_pools;
125
158
  }
126
159
 
127
160
  Napi::Object obj = Napi::Object::New(env);
@@ -131,6 +164,7 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
131
164
  obj.Set("async_stack_size", instance->async_stack_size);
132
165
  obj.Set("async_heap_size", instance->async_heap_size);
133
166
  obj.Set("resident_async_pools", instance->resident_async_pools);
167
+ obj.Set("max_async_calls", instance->resident_async_pools + instance->max_temporaries);
134
168
 
135
169
  return obj;
136
170
  }
@@ -616,6 +650,9 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
616
650
  return mem;
617
651
  }
618
652
 
653
+ if (RG_UNLIKELY(instance->temporaries >= instance->max_temporaries))
654
+ return nullptr;
655
+
619
656
  InstanceMemory *mem = new InstanceMemory();
620
657
 
621
658
  mem->stack.len = stack_size;
@@ -628,6 +665,11 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
628
665
  #endif
629
666
  RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
630
667
 
668
+ #ifdef __OpenBSD__
669
+ // Make sure the SP points inside the MAP_STACK area, or (void) functions may crash on OpenBSD i386
670
+ mem->stack.len -= 16;
671
+ #endif
672
+
631
673
  mem->heap.len = heap_size;
632
674
  #ifdef _WIN32
633
675
  mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
@@ -640,7 +682,9 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
640
682
 
641
683
  if (instance->memories.len <= instance->resident_async_pools) {
642
684
  instance->memories.Append(mem);
685
+ mem->temporary = false;
643
686
  } else {
687
+ instance->temporaries++;
644
688
  mem->temporary = true;
645
689
  }
646
690
 
@@ -806,11 +850,15 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
806
850
  Napi::Function callback = info[(uint32_t)func->parameters.len].As<Napi::Function>();
807
851
 
808
852
  if (!callback.IsFunction()) {
809
- ThrowError<Napi::TypeError>(env, "Expected callback function as last arguments, got %1", GetValueType(instance, callback));
853
+ ThrowError<Napi::TypeError>(env, "Expected callback function as last argument, got %1", GetValueType(instance, callback));
810
854
  return env.Null();
811
855
  }
812
856
 
813
857
  InstanceMemory *mem = AllocateMemory(instance, instance->async_stack_size, instance->async_heap_size);
858
+ if (RG_UNLIKELY(!mem)) {
859
+ ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
860
+ return env.Null();
861
+ }
814
862
  AsyncCall *async = new AsyncCall(env, instance, func, mem, callback);
815
863
 
816
864
  if (async->Prepare(info) && instance->debug) {
@@ -919,6 +967,7 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
919
967
 
920
968
  if (!instance->memories.len) {
921
969
  AllocateMemory(instance, instance->sync_stack_size, instance->sync_heap_size);
970
+ RG_ASSERT(instance->memories.len);
922
971
  }
923
972
 
924
973
  // Load shared library
package/src/ffi.hh CHANGED
@@ -21,10 +21,12 @@ namespace RG {
21
21
 
22
22
  static const Size DefaultSyncStackSize = Mebibytes(1);
23
23
  static const Size DefaultSyncHeapSize = Mebibytes(2);
24
- static const Size DefaultAsyncStackSize = Kibibytes(512);
25
- static const Size DefaultAsyncHeapSize = Mebibytes(1);
24
+ static const Size DefaultAsyncStackSize = Kibibytes(256);
25
+ static const Size DefaultAsyncHeapSize = Kibibytes(512);
26
26
  static const int DefaultResidentAsyncPools = 2;
27
+ static const int DefaultMaxAsyncCalls = 64;
27
28
 
29
+ static const int MaxAsyncCalls = 256;
28
30
  static const Size MaxParameters = 32;
29
31
  static const Size MaxOutParameters = 4;
30
32
  static const Size MaxTrampolines = 16;
@@ -216,7 +218,8 @@ struct InstanceData {
216
218
  bool debug;
217
219
  uint64_t tag_lower;
218
220
 
219
- LocalArray<InstanceMemory *, 16> memories;
221
+ LocalArray<InstanceMemory *, 9> memories;
222
+ int temporaries = 0;
220
223
 
221
224
  TrampolineInfo trampolines[MaxTrampolines];
222
225
  uint32_t free_trampolines = UINT32_MAX;
@@ -228,7 +231,11 @@ struct InstanceData {
228
231
  Size async_stack_size = DefaultAsyncStackSize;
229
232
  Size async_heap_size = DefaultAsyncHeapSize;
230
233
  int resident_async_pools = DefaultResidentAsyncPools;
234
+ int max_temporaries = DefaultMaxAsyncCalls - DefaultResidentAsyncPools;
231
235
  };
232
- RG_STATIC_ASSERT(MaxTrampolines <= 32);
236
+ RG_STATIC_ASSERT(DefaultResidentAsyncPools <= RG_LEN(InstanceData::memories.data) - 1);
237
+ RG_STATIC_ASSERT(DefaultMaxAsyncCalls >= DefaultResidentAsyncPools);
238
+ RG_STATIC_ASSERT(MaxAsyncCalls >= DefaultMaxAsyncCalls);
239
+ RG_STATIC_ASSERT(MaxTrampolines <= 16);
233
240
 
234
241
  }
package/test/async.js CHANGED
@@ -51,7 +51,7 @@ async function test() {
51
51
  let promises = [];
52
52
 
53
53
  // Issue several async calls
54
- for (let i = 0; i < 64; i++) {
54
+ for (let i = 0; i < 32; i++) {
55
55
  let p = new Promise((resolve, reject) => {
56
56
  try {
57
57
  ConcatenateToInt1.async(5, 6, 1, 2, 3, 9, 4, 4, 0, 6, 8, 7, (err, res) => {