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.
- package/CMakeLists.txt +1 -1
- package/ChangeLog.md +13 -1
- package/build/qemu/1.3.5/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_x64.tar.gz +0 -0
- package/doc/dist/doctrees/changes.doctree +0 -0
- package/doc/dist/doctrees/environment.pickle +0 -0
- package/doc/dist/doctrees/functions.doctree +0 -0
- package/doc/dist/doctrees/index.doctree +0 -0
- package/doc/dist/doctrees/memory.doctree +0 -0
- package/doc/dist/doctrees/start.doctree +0 -0
- package/doc/dist/doctrees/types.doctree +0 -0
- package/doc/dist/html/_sources/functions.md.txt +16 -14
- package/doc/dist/html/_sources/memory.md.txt +6 -3
- package/doc/dist/html/_sources/start.md.txt +3 -3
- package/doc/dist/html/_sources/types.md.txt +10 -8
- package/doc/dist/html/changes.html +15 -1
- package/doc/dist/html/functions.html +16 -19
- package/doc/dist/html/index.html +4 -2
- package/doc/dist/html/memory.html +8 -3
- package/doc/dist/html/objects.inv +0 -0
- package/doc/dist/html/platforms.html +1 -1
- package/doc/dist/html/searchindex.js +1 -1
- package/doc/dist/html/start.html +3 -3
- package/doc/dist/html/types.html +9 -8
- package/doc/functions.md +16 -14
- package/doc/memory.md +6 -3
- package/doc/start.md +3 -3
- package/doc/types.md +10 -8
- package/package.json +2 -2
- package/qemu/registry/machines.json +6 -11
- package/src/abi_x86.cc +0 -5
- package/src/call.cc +2 -1
- package/src/ffi.cc +71 -22
- package/src/ffi.hh +11 -4
- package/test/async.js +1 -1
- package/build/qemu/1.3.4/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.4/koffi_win32_ia32.tar.gz +0 -0
- 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
|
-
|
|
55
|
-
|
|
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, "
|
|
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, &
|
|
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, &
|
|
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, &
|
|
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, &
|
|
133
|
+
if (!ChangeMemorySize(key.c_str(), value, &async_heap_size))
|
|
103
134
|
return env.Null();
|
|
104
135
|
} else if (key == "resident_async_pools") {
|
|
105
|
-
|
|
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
|
|
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(
|
|
25
|
-
static const Size DefaultAsyncHeapSize =
|
|
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 *,
|
|
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(
|
|
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 <
|
|
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) => {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|