koffi 2.16.1 → 3.0.0-alpha.2
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/CHANGELOG.md +2 -2
- package/README.md +8 -8
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/musl_arm64/koffi.node +0 -0
- package/build/koffi/musl_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/doc/benchmarks.md +33 -33
- package/doc/benchmarks.xlsx +0 -0
- package/doc/contribute.md +37 -25
- package/doc/index.md +8 -8
- package/doc/variables.md +1 -1
- package/index.d.ts +11 -9
- package/index.js +1 -634
- package/indirect.js +1 -533
- package/lib/native/base/base.cc +63 -85
- package/lib/native/base/base.hh +178 -151
- package/package.json +3 -4
- package/src/build.js +1178 -0
- package/src/koffi/CMakeLists.txt +97 -34
- package/src/koffi/index.js +359 -0
- package/src/koffi/indirect.js +216 -0
- package/src/koffi/src/{abi_arm32.cc → abi/arm32.cc} +279 -275
- package/src/koffi/src/{abi_arm32_asm.S → abi/arm32_asm.S} +2 -5
- package/src/koffi/src/abi/arm64.cc +1511 -0
- package/src/koffi/src/{abi_arm64_asm.S → abi/arm64_asm.S} +44 -23
- package/src/koffi/src/{abi_arm64_asm.asm → abi/arm64_asm.asm} +32 -25
- package/src/koffi/src/{abi_loong64_asm.S → abi/loong64_asm.S} +1 -5
- package/src/koffi/src/{abi_riscv64.cc → abi/riscv64.cc} +279 -273
- package/src/koffi/src/{abi_riscv64_asm.S → abi/riscv64_asm.S} +1 -4
- package/src/koffi/src/abi/x64sysv.cc +1456 -0
- package/src/koffi/src/{abi_x64_sysv_asm.S → abi/x64sysv_asm.S} +30 -33
- package/src/koffi/src/abi/x64win.cc +1121 -0
- package/src/koffi/src/{abi_x64_win_asm.S → abi/x64win_asm.S} +8 -12
- package/src/koffi/src/{abi_x64_win_asm.asm → abi/x64win_asm.asm} +11 -14
- package/src/koffi/src/abi/x86.cc +1233 -0
- package/src/koffi/src/{abi_x86_asm.S → abi/x86_asm.S} +49 -25
- package/src/koffi/src/{abi_x86_asm.asm → abi/x86_asm.asm} +11 -14
- package/src/koffi/src/call.cc +458 -598
- package/src/koffi/src/call.hh +61 -82
- package/src/koffi/src/ffi.cc +595 -309
- package/src/koffi/src/ffi.hh +103 -89
- package/src/koffi/src/parser.cc +0 -4
- package/src/koffi/src/primitives.inc +39 -0
- package/src/koffi/{tools/write_trampolines.js → src/trampolines.js} +1 -1
- package/src/koffi/src/util.cc +503 -446
- package/src/koffi/src/util.hh +269 -57
- package/src/koffi/src/uv.cc +2 -2
- package/src/koffi/src/uv.def +3 -0
- package/src/koffi/src/win32.hh +30 -1
- package/vendor/node-addon-api/napi-inl.h +4 -0
- package/vendor/node-addon-api/napi.h +1 -0
- package/build/koffi/linux_armhf/koffi.node +0 -0
- package/build/koffi/linux_loong64/koffi.node +0 -0
- package/build/koffi/linux_riscv64d/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.exp +0 -0
- package/build/koffi/win32_arm64/koffi.lib +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/doc/platforms.md +0 -36
- package/src/cnoke/LICENSE.txt +0 -22
- package/src/cnoke/README.md +0 -99
- package/src/cnoke/assets/FindCNoke.cmake +0 -127
- package/src/cnoke/assets/toolchains.json +0 -126
- package/src/cnoke/assets/win_delay_hook.c +0 -36
- package/src/cnoke/cnoke.js +0 -170
- package/src/cnoke/package.json +0 -24
- package/src/cnoke/src/builder.js +0 -511
- package/src/cnoke/src/index.js +0 -10
- package/src/cnoke/src/tools.js +0 -407
- package/src/koffi/src/abi_arm64.cc +0 -1295
- package/src/koffi/src/abi_x64_sysv.cc +0 -939
- package/src/koffi/src/abi_x64_win.cc +0 -715
- package/src/koffi/src/abi_x86.cc +0 -860
- package/src/koffi/src/init.js +0 -105
- /package/src/koffi/src/{abi_loong64.cc → abi/loong64.cc} +0 -0
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -32,14 +32,18 @@
|
|
|
32
32
|
#include <wchar.h>
|
|
33
33
|
|
|
34
34
|
#include <napi.h>
|
|
35
|
+
#include <uv.h>
|
|
35
36
|
|
|
36
37
|
namespace K {
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
extern "C" napi_value SwitchAndRelay(CallData *call, Size idx, uint8_t *sp, uint8_t *saved_sp, MemoryRange<uint8_t> *new_stack);
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
SharedData shared;
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
// Recent N-API functions are loaded dynamically
|
|
44
|
+
napi_status (NAPI_CDECL *node_api_create_property_key_utf8)(napi_env env, const char* str, size_t length, napi_value* result);
|
|
45
|
+
napi_status (NAPI_CDECL *node_api_post_finalizer)(node_api_basic_env env, napi_finalize finalize_cb, void* finalize_data, void* finalize_hint);
|
|
46
|
+
napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
|
|
43
47
|
|
|
44
48
|
static bool ChangeSize(const char *name, Napi::Value value, Size min_size, Size max_size, Size *out_size)
|
|
45
49
|
{
|
|
@@ -104,7 +108,7 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
|
|
|
104
108
|
return env.Null();
|
|
105
109
|
}
|
|
106
110
|
|
|
107
|
-
if (!info[0]
|
|
111
|
+
if (!IsObject(env, info[0])) {
|
|
108
112
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for config, expected object", GetValueType(instance, info[0]));
|
|
109
113
|
return env.Null();
|
|
110
114
|
}
|
|
@@ -113,7 +117,7 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
|
|
|
113
117
|
int max_async_calls = new_config.resident_async_pools + new_config.max_temporaries;
|
|
114
118
|
|
|
115
119
|
Napi::Object obj = info[0].As<Napi::Object>();
|
|
116
|
-
Napi::Array keys = GetOwnPropertyNames(obj);
|
|
120
|
+
Napi::Array keys = GetOwnPropertyNames(env, obj);
|
|
117
121
|
|
|
118
122
|
for (uint32_t i = 0; i < keys.Length(); i++) {
|
|
119
123
|
std::string key = keys.Get(i).As<Napi::String>();
|
|
@@ -140,6 +144,20 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
|
|
|
140
144
|
} else if (key == "max_type_size") {
|
|
141
145
|
if (!ChangeSize(key.c_str(), value, 32, Mebibytes(512), &new_config.max_type_size))
|
|
142
146
|
return env.Null();
|
|
147
|
+
} else if (key == "fast_pointers") {
|
|
148
|
+
if (!value.IsBoolean()) {
|
|
149
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for '%2', expected boolean", GetValueType(instance, value), key.c_str());
|
|
150
|
+
return env.Null();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
new_config.fast_pointers = value.As<Napi::Boolean>();
|
|
154
|
+
} else if (key == "fast_callbacks") {
|
|
155
|
+
if (!value.IsBoolean()) {
|
|
156
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for '%2', expected boolean", GetValueType(instance, value), key.c_str());
|
|
157
|
+
return env.Null();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
new_config.fast_callbacks = value.As<Napi::Boolean>();
|
|
143
161
|
} else {
|
|
144
162
|
ThrowError<Napi::Error>(env, "Unexpected config member '%1'", key.c_str());
|
|
145
163
|
return env.Null();
|
|
@@ -164,6 +182,8 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
|
|
|
164
182
|
obj.Set("resident_async_pools", instance->config.resident_async_pools);
|
|
165
183
|
obj.Set("max_async_calls", instance->config.resident_async_pools + instance->config.max_temporaries);
|
|
166
184
|
obj.Set("max_type_size", instance->config.max_type_size);
|
|
185
|
+
obj.Set("fast_pointers", instance->config.fast_pointers);
|
|
186
|
+
obj.Set("fast_callbacks", instance->config.fast_callbacks);
|
|
167
187
|
|
|
168
188
|
return obj;
|
|
169
189
|
}
|
|
@@ -217,6 +237,29 @@ static bool MapType(Napi::Env env, InstanceData *instance, const TypeInfo *type,
|
|
|
217
237
|
return true;
|
|
218
238
|
}
|
|
219
239
|
|
|
240
|
+
static bool FinalizeCompositeType(Napi::Env env, TypeInfo *type, Size size)
|
|
241
|
+
{
|
|
242
|
+
if (node_api_create_property_key_utf8) {
|
|
243
|
+
for (RecordMember &member: type->members) {
|
|
244
|
+
napi_value key = nullptr;
|
|
245
|
+
node_api_create_property_key_utf8(env, member.name, NAPI_AUTO_LENGTH, &key);
|
|
246
|
+
|
|
247
|
+
napi_create_reference(env, key, 1, &member.key);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
size = AlignLen(size, type->align);
|
|
252
|
+
if (!size) {
|
|
253
|
+
ThrowError<Napi::Error>(env, "Empty type '%1' is not allowed in C", type->name);
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
type->size = (int32_t)size;
|
|
257
|
+
|
|
258
|
+
type->flags &= ~(int)TypeFlag::IsIncomplete;
|
|
259
|
+
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
|
|
220
263
|
static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
221
264
|
{
|
|
222
265
|
Napi::Env env = info.Env();
|
|
@@ -228,21 +271,21 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
228
271
|
}
|
|
229
272
|
|
|
230
273
|
bool skip = (info.Length() > 1);
|
|
231
|
-
bool named = skip && !IsNullOrUndefined(info[0]);
|
|
232
|
-
bool redefine = named && CheckValueTag(info[0], &TypeInfoMarker);
|
|
274
|
+
bool named = skip && !IsNullOrUndefined(env, info[0]);
|
|
275
|
+
bool redefine = named && info[0].IsExternal() && CheckValueTag(env, info[0], &TypeInfoMarker);
|
|
233
276
|
|
|
234
277
|
if (named && !info[0].IsString() && !redefine) {
|
|
235
278
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
236
279
|
return env.Null();
|
|
237
280
|
}
|
|
238
|
-
if (!IsObject(info[skip])) {
|
|
281
|
+
if (!IsObject(env, info[skip])) {
|
|
239
282
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for members, expected object", GetValueType(instance, info[1]));
|
|
240
283
|
return env.Null();
|
|
241
284
|
}
|
|
242
285
|
|
|
243
286
|
Napi::String name = info[0].As<Napi::String>();
|
|
244
287
|
Napi::Object obj = info[skip].As<Napi::Object>();
|
|
245
|
-
Napi::Array keys = GetOwnPropertyNames(obj);
|
|
288
|
+
Napi::Array keys = GetOwnPropertyNames(env, obj);
|
|
246
289
|
|
|
247
290
|
K_DEFER_NC(err_guard, count = instance->types.count) {
|
|
248
291
|
Size start = count + !skip;
|
|
@@ -287,7 +330,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
287
330
|
type->flags = (int)TypeFlag::IsIncomplete;
|
|
288
331
|
|
|
289
332
|
HashSet<const char *> members;
|
|
290
|
-
|
|
333
|
+
Size size = 0;
|
|
291
334
|
|
|
292
335
|
for (uint32_t i = 0; i < keys.Length(); i++) {
|
|
293
336
|
RecordMember member = {};
|
|
@@ -384,14 +427,8 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
384
427
|
}
|
|
385
428
|
}
|
|
386
429
|
|
|
387
|
-
|
|
388
|
-
if (!size) {
|
|
389
|
-
ThrowError<Napi::Error>(env, "Empty struct '%1' is not allowed in C", type->name);
|
|
430
|
+
if (!FinalizeCompositeType(env, type, size))
|
|
390
431
|
return env.Null();
|
|
391
|
-
}
|
|
392
|
-
type->size = (int32_t)size;
|
|
393
|
-
|
|
394
|
-
type->flags &= ~(int)TypeFlag::IsIncomplete;
|
|
395
432
|
err_guard.Disable();
|
|
396
433
|
|
|
397
434
|
if (replace) {
|
|
@@ -423,21 +460,21 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
|
|
|
423
460
|
}
|
|
424
461
|
|
|
425
462
|
bool skip = (info.Length() > 1);
|
|
426
|
-
bool named = skip && !IsNullOrUndefined(info[0]);
|
|
427
|
-
bool redefine = named && CheckValueTag(info[0], &TypeInfoMarker);
|
|
463
|
+
bool named = skip && !IsNullOrUndefined(env, info[0]);
|
|
464
|
+
bool redefine = named && info[0].IsExternal() && CheckValueTag(env, info[0], &TypeInfoMarker);
|
|
428
465
|
|
|
429
466
|
if (named && !info[0].IsString() && !redefine) {
|
|
430
467
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
431
468
|
return env.Null();
|
|
432
469
|
}
|
|
433
|
-
if (!IsObject(info[skip])) {
|
|
470
|
+
if (!IsObject(env, info[skip])) {
|
|
434
471
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for members, expected object", GetValueType(instance, info[1]));
|
|
435
472
|
return env.Null();
|
|
436
473
|
}
|
|
437
474
|
|
|
438
475
|
Napi::String name = info[0].As<Napi::String>();
|
|
439
476
|
Napi::Object obj = info[skip].As<Napi::Object>();
|
|
440
|
-
Napi::Array keys = GetOwnPropertyNames(obj);
|
|
477
|
+
Napi::Array keys = GetOwnPropertyNames(env, obj);
|
|
441
478
|
|
|
442
479
|
K_DEFER_NC(err_guard, count = instance->types.count) {
|
|
443
480
|
Size start = count + !skip;
|
|
@@ -549,18 +586,12 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
|
|
|
549
586
|
type->members.Append(member);
|
|
550
587
|
}
|
|
551
588
|
|
|
552
|
-
|
|
553
|
-
if (!size) {
|
|
554
|
-
ThrowError<Napi::Error>(env, "Empty union '%1' is not allowed in C", type->name);
|
|
589
|
+
if (!FinalizeCompositeType(env, type, size))
|
|
555
590
|
return env.Null();
|
|
556
|
-
}
|
|
557
|
-
type->size = (int32_t)size;
|
|
558
|
-
|
|
559
|
-
type->flags &= ~(int)TypeFlag::IsIncomplete;
|
|
560
591
|
err_guard.Disable();
|
|
561
592
|
|
|
562
593
|
// Union constructor
|
|
563
|
-
Napi::Function constructor =
|
|
594
|
+
Napi::Function constructor = UnionClass::InitClass(env, type);
|
|
564
595
|
type->construct.Reset(constructor, 1);
|
|
565
596
|
|
|
566
597
|
if (replace) {
|
|
@@ -593,7 +624,7 @@ Napi::Value InstantiateUnion(const Napi::CallbackInfo &info)
|
|
|
593
624
|
}
|
|
594
625
|
|
|
595
626
|
Napi::Object wrapper = type->construct.New({}).As<Napi::Object>();
|
|
596
|
-
SetValueTag(wrapper, &
|
|
627
|
+
SetValueTag(env, wrapper, &UnionClassMarker);
|
|
597
628
|
|
|
598
629
|
return wrapper;
|
|
599
630
|
}
|
|
@@ -603,7 +634,7 @@ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
|
|
|
603
634
|
Napi::Env env = info.Env();
|
|
604
635
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
605
636
|
|
|
606
|
-
bool named = (info.Length() >= 1) && !IsNullOrUndefined(info[0]);
|
|
637
|
+
bool named = (info.Length() >= 1) && !IsNullOrUndefined(env, info[0]);
|
|
607
638
|
|
|
608
639
|
if (named && !info[0].IsString()) {
|
|
609
640
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
@@ -641,7 +672,7 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
|
|
|
641
672
|
}
|
|
642
673
|
|
|
643
674
|
bool skip = (info.Length() > 1) && !info[1].IsNumber();
|
|
644
|
-
bool named = skip && !IsNullOrUndefined(info[0]);
|
|
675
|
+
bool named = skip && !IsNullOrUndefined(env, info[0]);
|
|
645
676
|
|
|
646
677
|
if (named && !info[0].IsString()) {
|
|
647
678
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
@@ -754,7 +785,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
|
754
785
|
}
|
|
755
786
|
|
|
756
787
|
bool skip = (info.Length() > 1) && !info[1].IsFunction();
|
|
757
|
-
bool named = skip && !IsNullOrUndefined(info[0]);
|
|
788
|
+
bool named = skip && !IsNullOrUndefined(env, info[0]);
|
|
758
789
|
|
|
759
790
|
if (named && !info[0].IsString()) {
|
|
760
791
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
@@ -780,7 +811,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
|
780
811
|
|
|
781
812
|
DisposeFunc *dispose;
|
|
782
813
|
Napi::Function dispose_func;
|
|
783
|
-
if (info.Length() >= 2u + skip && !IsNullOrUndefined(info[1 + skip])) {
|
|
814
|
+
if (info.Length() >= 2u + skip && !IsNullOrUndefined(env, info[1 + skip])) {
|
|
784
815
|
Napi::Function func = info[1 + skip].As<Napi::Function>();
|
|
785
816
|
|
|
786
817
|
if (!func.IsFunction()) {
|
|
@@ -792,13 +823,10 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
|
792
823
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
793
824
|
const Napi::FunctionReference &ref = type->dispose_ref;
|
|
794
825
|
|
|
795
|
-
Napi::
|
|
796
|
-
SetValueTag(external, type->ref.marker);
|
|
826
|
+
Napi::Value p = WrapPointer(env, type->ref.type, (void *)ptr);
|
|
797
827
|
|
|
798
|
-
|
|
799
|
-
napi_value args[] = {
|
|
800
|
-
external
|
|
801
|
-
};
|
|
828
|
+
napi_value self = env.Null();
|
|
829
|
+
napi_value args[] = { p };
|
|
802
830
|
|
|
803
831
|
ref.Call(self, K_LEN(args), args);
|
|
804
832
|
instance->stats.disposed++;
|
|
@@ -826,37 +854,30 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
|
826
854
|
type->dispose_ref = Napi::Persistent(dispose_func);
|
|
827
855
|
|
|
828
856
|
// If the insert succeeds, we cannot fail anymore
|
|
829
|
-
if (named
|
|
830
|
-
|
|
857
|
+
if (named) {
|
|
858
|
+
bool inserted;
|
|
859
|
+
instance->types_map.InsertOrGet(type->name, type, &inserted);
|
|
860
|
+
|
|
861
|
+
if (!inserted) {
|
|
862
|
+
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
863
|
+
return env.Null();
|
|
864
|
+
}
|
|
865
|
+
}
|
|
831
866
|
err_guard.Disable();
|
|
832
867
|
|
|
833
868
|
return WrapType(env, type);
|
|
834
869
|
}
|
|
835
870
|
|
|
836
|
-
static inline bool GetExternalPointer(
|
|
871
|
+
static inline bool GetExternalPointer(napi_env env, napi_value value, void **out_ptr)
|
|
837
872
|
{
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
if (IsNullOrUndefined(value)) {
|
|
841
|
-
*out_ptr = 0;
|
|
842
|
-
return true;
|
|
843
|
-
} else if (IsRawBuffer(value)) {
|
|
844
|
-
Span<uint8_t> buffer = GetRawBuffer(value);
|
|
873
|
+
if (!TryPointer(env, value, out_ptr)) {
|
|
874
|
+
InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
|
|
845
875
|
|
|
846
|
-
|
|
847
|
-
return true;
|
|
848
|
-
} else if (value.IsExternal() && !CheckValueTag(value, &TypeInfoMarker) &&
|
|
849
|
-
!CheckValueTag(value, &CastMarker) &&
|
|
850
|
-
!CheckValueTag(value, &MagicUnionMarker)) {
|
|
851
|
-
Napi::External<void> external = value.As<Napi::External<void>>();
|
|
852
|
-
void *ptr = external.Data();
|
|
853
|
-
|
|
854
|
-
*out_ptr = ptr;
|
|
855
|
-
return true;
|
|
856
|
-
} else {
|
|
857
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected external pointer", GetValueType(instance, value));
|
|
876
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, value));
|
|
858
877
|
return false;
|
|
859
878
|
}
|
|
879
|
+
|
|
880
|
+
return true;
|
|
860
881
|
}
|
|
861
882
|
|
|
862
883
|
static Napi::Value CallAlloc(const Napi::CallbackInfo &info)
|
|
@@ -902,10 +923,7 @@ static Napi::Value CallAlloc(const Napi::CallbackInfo &info)
|
|
|
902
923
|
return env.Null();
|
|
903
924
|
}
|
|
904
925
|
|
|
905
|
-
|
|
906
|
-
SetValueTag(external, type);
|
|
907
|
-
|
|
908
|
-
return external;
|
|
926
|
+
return WrapPointer(env, type, ptr);
|
|
909
927
|
}
|
|
910
928
|
|
|
911
929
|
static Napi::Value CallFree(const Napi::CallbackInfo &info)
|
|
@@ -942,8 +960,7 @@ static Napi::Value GetOrSetErrNo(const Napi::CallbackInfo &info)
|
|
|
942
960
|
errno = value;
|
|
943
961
|
}
|
|
944
962
|
|
|
945
|
-
|
|
946
|
-
return ret;
|
|
963
|
+
return NewInt(env, (int32_t)errno);
|
|
947
964
|
}
|
|
948
965
|
|
|
949
966
|
static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
@@ -988,7 +1005,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
988
1005
|
|
|
989
1006
|
TypeInfo *type = nullptr;
|
|
990
1007
|
|
|
991
|
-
if (info.Length() >= 3u + dynamic && !IsNullOrUndefined(info[2 + dynamic])) {
|
|
1008
|
+
if (info.Length() >= 3u + dynamic && !IsNullOrUndefined(env, info[2 + dynamic])) {
|
|
992
1009
|
if (!info[2 + dynamic].IsString()) {
|
|
993
1010
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for hint, expected string", GetValueType(instance, info[2]));
|
|
994
1011
|
return env.Null();
|
|
@@ -1008,7 +1025,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
1008
1025
|
hint = ArrayHint::Array;
|
|
1009
1026
|
} else if (str == "String" || str == "string") {
|
|
1010
1027
|
if (ref->primitive != PrimitiveKind::Int8 && ref->primitive != PrimitiveKind::Int16) {
|
|
1011
|
-
ThrowError<Napi::Error>(env, "Array hint 'String' can only be used with 8 and
|
|
1028
|
+
ThrowError<Napi::Error>(env, "Array hint 'String' can only be used with 8, 16 and 32-bit signed integer types");
|
|
1012
1029
|
return env.Null();
|
|
1013
1030
|
}
|
|
1014
1031
|
|
|
@@ -1018,9 +1035,9 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
1018
1035
|
return env.Null();
|
|
1019
1036
|
}
|
|
1020
1037
|
|
|
1021
|
-
type = MakeArrayType(instance, ref, len, hint);
|
|
1038
|
+
type = MakeArrayType(instance, ref, (Size)len, hint);
|
|
1022
1039
|
} else {
|
|
1023
|
-
type = MakeArrayType(instance, ref, len);
|
|
1040
|
+
type = MakeArrayType(instance, ref, (Size)len);
|
|
1024
1041
|
}
|
|
1025
1042
|
|
|
1026
1043
|
if (dynamic) {
|
|
@@ -1064,7 +1081,7 @@ static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete,
|
|
|
1064
1081
|
}
|
|
1065
1082
|
#endif
|
|
1066
1083
|
if (!name.IsString()) {
|
|
1067
|
-
if (!concrete && IsNullOrUndefined(name)) {
|
|
1084
|
+
if (!concrete && IsNullOrUndefined(env, name)) {
|
|
1068
1085
|
named = false;
|
|
1069
1086
|
} else {
|
|
1070
1087
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
|
|
@@ -1118,10 +1135,6 @@ static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete,
|
|
|
1118
1135
|
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
|
|
1119
1136
|
return false;
|
|
1120
1137
|
}
|
|
1121
|
-
if ((param.directions & 2) && ++out_func->out_parameters >= MaxParameters) {
|
|
1122
|
-
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 output parameters", MaxParameters);
|
|
1123
|
-
return false;
|
|
1124
|
-
}
|
|
1125
1138
|
|
|
1126
1139
|
param.offset = (int8_t)j;
|
|
1127
1140
|
|
|
@@ -1139,12 +1152,10 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
|
|
|
1139
1152
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1140
1153
|
|
|
1141
1154
|
FunctionInfo *func = instance->callbacks.AppendDefault();
|
|
1142
|
-
|
|
1155
|
+
K_DEFER_N(err_guard) { instance->callbacks.RemoveLast(1); };
|
|
1143
1156
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
instance->types.RemoveLast(1);
|
|
1147
|
-
};
|
|
1157
|
+
func->env = env;
|
|
1158
|
+
func->instance = instance;
|
|
1148
1159
|
|
|
1149
1160
|
if (info.Length() >= 2) {
|
|
1150
1161
|
if (!ParseClassicFunction(info, false, func))
|
|
@@ -1172,11 +1183,14 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
|
|
|
1172
1183
|
if (!AnalyseFunction(env, instance, func))
|
|
1173
1184
|
return env.Null();
|
|
1174
1185
|
|
|
1175
|
-
//
|
|
1176
|
-
|
|
1177
|
-
|
|
1186
|
+
// We cannot fail after this check
|
|
1187
|
+
if (named && instance->types_map.Find(func->name)) {
|
|
1188
|
+
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", func->name);
|
|
1189
|
+
return env.Null();
|
|
1178
1190
|
}
|
|
1179
|
-
|
|
1191
|
+
err_guard.Disable();
|
|
1192
|
+
|
|
1193
|
+
TypeInfo *type = instance->types.AppendDefault();
|
|
1180
1194
|
|
|
1181
1195
|
type->name = func->name;
|
|
1182
1196
|
|
|
@@ -1185,10 +1199,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
|
|
|
1185
1199
|
type->size = K_SIZE(void *);
|
|
1186
1200
|
type->ref.proto = func;
|
|
1187
1201
|
|
|
1188
|
-
|
|
1189
|
-
if (named && !MapType(env, instance, type, type->name))
|
|
1190
|
-
return env.Null();
|
|
1191
|
-
err_guard.Disable();
|
|
1202
|
+
instance->types_map.Set(type->name, type);
|
|
1192
1203
|
|
|
1193
1204
|
return WrapType(env, type);
|
|
1194
1205
|
}
|
|
@@ -1234,7 +1245,7 @@ static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
|
|
|
1234
1245
|
if (!type)
|
|
1235
1246
|
return env.Null();
|
|
1236
1247
|
|
|
1237
|
-
return
|
|
1248
|
+
return NewInt(env, type->size);
|
|
1238
1249
|
}
|
|
1239
1250
|
|
|
1240
1251
|
static Napi::Value GetTypeAlign(const Napi::CallbackInfo &info)
|
|
@@ -1250,7 +1261,7 @@ static Napi::Value GetTypeAlign(const Napi::CallbackInfo &info)
|
|
|
1250
1261
|
if (!type)
|
|
1251
1262
|
return env.Null();
|
|
1252
1263
|
|
|
1253
|
-
return
|
|
1264
|
+
return NewInt(env, type->align);
|
|
1254
1265
|
}
|
|
1255
1266
|
|
|
1256
1267
|
static Napi::Value GetMemberOffset(const Napi::CallbackInfo &info)
|
|
@@ -1284,7 +1295,7 @@ static Napi::Value GetMemberOffset(const Napi::CallbackInfo &info)
|
|
|
1284
1295
|
return env.Null();
|
|
1285
1296
|
}
|
|
1286
1297
|
|
|
1287
|
-
return
|
|
1298
|
+
return NewInt(env, member->offset);
|
|
1288
1299
|
}
|
|
1289
1300
|
|
|
1290
1301
|
static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
|
|
@@ -1321,8 +1332,8 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
|
1321
1332
|
|
|
1322
1333
|
defn.Set("name", Napi::String::New(env, type->name));
|
|
1323
1334
|
defn.Set("primitive", PrimitiveKindNames[(int)type->primitive]);
|
|
1324
|
-
defn.Set("size",
|
|
1325
|
-
defn.Set("alignment",
|
|
1335
|
+
defn.Set("size", NewInt(env, type->size));
|
|
1336
|
+
defn.Set("alignment", NewInt(env, type->align));
|
|
1326
1337
|
defn.Set("disposable", Napi::Boolean::New(env, !!type->dispose));
|
|
1327
1338
|
|
|
1328
1339
|
switch (type->primitive) {
|
|
@@ -1352,7 +1363,7 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
|
1352
1363
|
|
|
1353
1364
|
case PrimitiveKind::Array: {
|
|
1354
1365
|
uint32_t len = type->size / type->ref.type->size;
|
|
1355
|
-
defn.Set("length",
|
|
1366
|
+
defn.Set("length", NewInt(env, len));
|
|
1356
1367
|
defn.Set("hint", ArrayHintNames[(int)type->hint]);
|
|
1357
1368
|
} [[fallthrough]];
|
|
1358
1369
|
case PrimitiveKind::Pointer: {
|
|
@@ -1412,44 +1423,48 @@ InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size hea
|
|
|
1412
1423
|
|
|
1413
1424
|
#if defined(_WIN32)
|
|
1414
1425
|
// Allocate stack memory
|
|
1415
|
-
mem->stack.
|
|
1416
|
-
mem->stack.
|
|
1426
|
+
mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, stack_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
1427
|
+
mem->stack.end = mem->stack.ptr + stack_size;
|
|
1417
1428
|
|
|
1418
|
-
K_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory",
|
|
1429
|
+
K_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", stack_size);
|
|
1419
1430
|
#else
|
|
1420
|
-
mem->stack.
|
|
1421
|
-
mem->stack.
|
|
1431
|
+
mem->stack.ptr = (uint8_t *)mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
|
|
1432
|
+
mem->stack.end = mem->stack.ptr + stack_size;
|
|
1422
1433
|
|
|
1423
|
-
K_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory",
|
|
1434
|
+
K_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", stack_size);
|
|
1424
1435
|
#endif
|
|
1425
1436
|
|
|
1426
1437
|
#if defined(__OpenBSD__)
|
|
1427
1438
|
// Make sure the SP points inside the MAP_STACK area, or (void) functions may crash on OpenBSD i386
|
|
1428
|
-
mem->stack.
|
|
1439
|
+
mem->stack.end -= 16;
|
|
1429
1440
|
#endif
|
|
1430
1441
|
|
|
1431
1442
|
// Keep real stack limits intact, in case we need them
|
|
1432
1443
|
mem->stack0 = mem->stack;
|
|
1433
1444
|
|
|
1434
1445
|
#if defined(_WIN32) && !defined(_WIN64)
|
|
1435
|
-
mem->stack.
|
|
1446
|
+
mem->stack.end -= K_SIZE(SehFrame);
|
|
1436
1447
|
|
|
1437
1448
|
// Prepare at the top SEH frame record
|
|
1438
1449
|
{
|
|
1439
|
-
SehFrame *seh = (SehFrame *)mem->stack.end
|
|
1450
|
+
SehFrame *seh = (SehFrame *)mem->stack.end;
|
|
1440
1451
|
|
|
1441
1452
|
seh->Next = (void *)-1;
|
|
1442
1453
|
seh->Handler = (void *)SehHandler;
|
|
1443
1454
|
}
|
|
1444
1455
|
#endif
|
|
1445
1456
|
|
|
1446
|
-
mem->heap.len = heap_size;
|
|
1447
1457
|
#if defined(_WIN32)
|
|
1448
|
-
mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr,
|
|
1458
|
+
mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, heap_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
1459
|
+
mem->heap.end = mem->heap.ptr + heap_size;
|
|
1460
|
+
|
|
1461
|
+
K_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", heap_size);
|
|
1449
1462
|
#else
|
|
1450
|
-
mem->heap.ptr = (uint8_t *)mmap(nullptr,
|
|
1463
|
+
mem->heap.ptr = (uint8_t *)mmap(nullptr, heap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
1464
|
+
mem->heap.end = mem->heap.ptr + heap_size;
|
|
1465
|
+
|
|
1466
|
+
K_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", heap_size);
|
|
1451
1467
|
#endif
|
|
1452
|
-
K_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
|
|
1453
1468
|
|
|
1454
1469
|
if (temporary) {
|
|
1455
1470
|
instance->temporaries++;
|
|
@@ -1467,13 +1482,6 @@ InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size hea
|
|
|
1467
1482
|
|
|
1468
1483
|
void ReleaseMemory(InstanceData *instance, InstanceMemory *mem)
|
|
1469
1484
|
{
|
|
1470
|
-
if (--mem->depth)
|
|
1471
|
-
return;
|
|
1472
|
-
|
|
1473
|
-
// The first InstanceMemory is used for sync calls, no need to manage the async stuff
|
|
1474
|
-
if (mem == instance->memories[0])
|
|
1475
|
-
return;
|
|
1476
|
-
|
|
1477
1485
|
std::lock_guard<std::mutex> lock(instance->mem_mutex);
|
|
1478
1486
|
|
|
1479
1487
|
if (mem->temporary) {
|
|
@@ -1484,164 +1492,282 @@ void ReleaseMemory(InstanceData *instance, InstanceMemory *mem)
|
|
|
1484
1492
|
}
|
|
1485
1493
|
}
|
|
1486
1494
|
|
|
1487
|
-
static
|
|
1488
|
-
const Napi::CallbackInfo &info)
|
|
1495
|
+
static napi_value TranslateZeroCallNode(napi_env env, napi_callback_info info)
|
|
1489
1496
|
{
|
|
1490
|
-
|
|
1491
|
-
|
|
1497
|
+
struct CallbackBundle {
|
|
1498
|
+
napi_env env;
|
|
1499
|
+
void *data;
|
|
1500
|
+
};
|
|
1492
1501
|
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
return env.Null();
|
|
1496
|
-
}
|
|
1502
|
+
CallbackBundle **ptr = (CallbackBundle **)((uint8_t *)info + K_SIZE(void *));
|
|
1503
|
+
FunctionInfo *func = (FunctionInfo *)(*ptr)->data;
|
|
1497
1504
|
|
|
1505
|
+
InstanceData *instance = func->instance;
|
|
1498
1506
|
InstanceMemory *mem = instance->memories[0];
|
|
1499
|
-
CallData call(env, instance, mem);
|
|
1507
|
+
CallData call(env, instance, mem, func->native);
|
|
1500
1508
|
|
|
1501
|
-
|
|
1502
|
-
|
|
1509
|
+
K_DEFER_C(prev_call = instance->sync_call) { instance->sync_call = prev_call; };
|
|
1510
|
+
instance->sync_call = &call;
|
|
1503
1511
|
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
}
|
|
1512
|
+
napi_value ret = call.Run(func, nullptr);
|
|
1513
|
+
call.FinalizeFast();
|
|
1507
1514
|
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1515
|
+
return ret;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
static napi_value TranslateZeroCallBun(napi_env env, napi_callback_info info)
|
|
1519
|
+
{
|
|
1520
|
+
FunctionInfo *func = *(FunctionInfo **)((uint8_t *)info + K_SIZE(void *));
|
|
1521
|
+
|
|
1522
|
+
InstanceData *instance = func->instance;
|
|
1523
|
+
InstanceMemory *mem = instance->memories[0];
|
|
1524
|
+
CallData call(env, instance, mem, func->native);
|
|
1525
|
+
|
|
1526
|
+
K_DEFER_C(prev_call = instance->sync_call) { instance->sync_call = prev_call; };
|
|
1527
|
+
instance->sync_call = &call;
|
|
1528
|
+
|
|
1529
|
+
napi_value ret = call.Run(func, nullptr);
|
|
1530
|
+
call.FinalizeFast();
|
|
1531
|
+
|
|
1532
|
+
return ret;
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
napi_value TranslateFastCall(napi_env env, napi_callback_info info)
|
|
1536
|
+
{
|
|
1537
|
+
napi_value args[6];
|
|
1538
|
+
size_t count = 6;
|
|
1539
|
+
FunctionInfo *func;
|
|
1540
|
+
|
|
1541
|
+
napi_status status = napi_get_cb_info(env, info, &count, args, nullptr, (void **)&func);
|
|
1542
|
+
K_ASSERT(status == napi_ok);
|
|
1543
|
+
|
|
1544
|
+
InstanceData *instance = func->instance;
|
|
1512
1545
|
|
|
1513
|
-
|
|
1546
|
+
if (count < (size_t)func->required_parameters) [[unlikely]] {
|
|
1547
|
+
ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, count);
|
|
1548
|
+
return Napi::Env(env).Null();
|
|
1514
1549
|
}
|
|
1515
1550
|
|
|
1516
|
-
|
|
1551
|
+
InstanceMemory *mem = instance->memories[0];
|
|
1552
|
+
CallData call(env, instance, mem, func->native);
|
|
1553
|
+
|
|
1554
|
+
K_DEFER_C(prev_call = instance->sync_call) { instance->sync_call = prev_call; };
|
|
1555
|
+
instance->sync_call = &call;
|
|
1556
|
+
|
|
1557
|
+
napi_value ret = call.Run(func, args);
|
|
1558
|
+
call.FinalizeFast();
|
|
1559
|
+
|
|
1560
|
+
return ret;
|
|
1517
1561
|
}
|
|
1518
1562
|
|
|
1519
|
-
|
|
1563
|
+
static FORCE_INLINE napi_value TranslateNormalCall(napi_env env, const FunctionInfo *func, void *native, napi_value *args, Size count)
|
|
1520
1564
|
{
|
|
1521
|
-
|
|
1522
|
-
|
|
1565
|
+
static_assert(MaxParameters >= 6);
|
|
1566
|
+
|
|
1567
|
+
InstanceData *instance = func->instance;
|
|
1568
|
+
|
|
1569
|
+
if (count < func->required_parameters) [[unlikely]] {
|
|
1570
|
+
ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, count);
|
|
1571
|
+
return Napi::Env(env).Null();
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
InstanceMemory *mem = instance->memories[0];
|
|
1575
|
+
CallData call(env, instance, mem, native);
|
|
1576
|
+
|
|
1577
|
+
K_DEFER_C(prev_call = instance->sync_call) { instance->sync_call = prev_call; };
|
|
1578
|
+
instance->sync_call = &call;
|
|
1579
|
+
|
|
1580
|
+
napi_value ret = call.Run(func, args);
|
|
1581
|
+
call.Finalize();
|
|
1582
|
+
|
|
1583
|
+
return ret;
|
|
1523
1584
|
}
|
|
1524
1585
|
|
|
1525
|
-
|
|
1526
|
-
const Napi::CallbackInfo &info)
|
|
1586
|
+
napi_value TranslateNormalCall(napi_env env, napi_callback_info info)
|
|
1527
1587
|
{
|
|
1528
|
-
|
|
1529
|
-
|
|
1588
|
+
napi_value args[MaxParameters];
|
|
1589
|
+
size_t count = 6;
|
|
1590
|
+
FunctionInfo *func;
|
|
1530
1591
|
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
copy.lib = nullptr;
|
|
1592
|
+
napi_status status = napi_get_cb_info(env, info, &count, args, nullptr, (void **)&func);
|
|
1593
|
+
K_ASSERT(status == napi_ok);
|
|
1534
1594
|
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
copy.parameters.Leak();
|
|
1539
|
-
};
|
|
1595
|
+
if (count > 6) {
|
|
1596
|
+
napi_status status = napi_get_cb_info(env, info, &count, args, nullptr, nullptr);
|
|
1597
|
+
K_ASSERT(status == napi_ok);
|
|
1540
1598
|
|
|
1541
|
-
|
|
1542
|
-
ThrowError<Napi::TypeError>(env, "Expected %1 arguments or more, got %2", copy.parameters.len, info.Length());
|
|
1543
|
-
return env.Null();
|
|
1544
|
-
}
|
|
1545
|
-
if ((info.Length() - copy.required_parameters) % 2) [[unlikely]] {
|
|
1546
|
-
ThrowError<Napi::Error>(env, "Missing value argument for variadic call");
|
|
1547
|
-
return env.Null();
|
|
1599
|
+
count = std::min(count, (size_t)MaxParameters);
|
|
1548
1600
|
}
|
|
1549
1601
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1602
|
+
return TranslateNormalCall(env, func, func->native, args, (Size)count);
|
|
1603
|
+
}
|
|
1552
1604
|
|
|
1553
|
-
|
|
1605
|
+
static napi_value TranslateVariadicCall(napi_env env, const FunctionInfo *func, void *native, napi_value *args, Size count)
|
|
1606
|
+
{
|
|
1607
|
+
static_assert(MaxParameters >= 6);
|
|
1554
1608
|
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1609
|
+
InstanceData *instance = func->instance;
|
|
1610
|
+
|
|
1611
|
+
FunctionInfo *variadic = nullptr;
|
|
1612
|
+
K_DEFER_N(err_guard) { delete variadic; };
|
|
1613
|
+
|
|
1614
|
+
// Try cached function
|
|
1615
|
+
{
|
|
1616
|
+
FunctionInfo *prev = instance->variadic_func;
|
|
1617
|
+
|
|
1618
|
+
if (prev && prev->native == native) {
|
|
1619
|
+
Size specified = (count - prev->required_parameters);
|
|
1620
|
+
Size processed = (prev->parameters.len - prev->required_parameters) * 2;
|
|
1621
|
+
|
|
1622
|
+
if (specified == processed) {
|
|
1623
|
+
bool match = true;
|
|
1624
|
+
|
|
1625
|
+
for (Size i = prev->required_parameters, j = prev->required_parameters; i < (Size)count; i += 2, j++) {
|
|
1626
|
+
int directions;
|
|
1627
|
+
const TypeInfo *type = ResolveType(Napi::Value(env, args[i]), &directions);
|
|
1628
|
+
|
|
1629
|
+
if (type != prev->parameters[j].type || directions != prev->parameters[j].directions) [[unlikely]] {
|
|
1630
|
+
match = false;
|
|
1631
|
+
break;
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
if (match) [[likely]] {
|
|
1636
|
+
variadic = prev;
|
|
1637
|
+
|
|
1638
|
+
// If an error happens it'll get destroyed, so don't keep it around
|
|
1639
|
+
instance->variadic_func = nullptr;
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1560
1642
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
if (!variadic) {
|
|
1646
|
+
variadic = new FunctionInfo();
|
|
1647
|
+
|
|
1648
|
+
memcpy((void *)variadic, func, K_SIZE(*func));
|
|
1649
|
+
memset((void *)&variadic->parameters, 0, K_SIZE(variadic->parameters));
|
|
1650
|
+
memset((void *)&variadic->sync, 0, K_SIZE(variadic->sync));
|
|
1651
|
+
memset((void *)&variadic->async, 0, K_SIZE(variadic->async));
|
|
1652
|
+
|
|
1653
|
+
variadic->parameters = func->parameters;
|
|
1654
|
+
variadic->lib = nullptr;
|
|
1655
|
+
|
|
1656
|
+
if (count < variadic->required_parameters) [[unlikely]] {
|
|
1657
|
+
ThrowError<Napi::TypeError>(env, "Expected %1 arguments or more, got %2", variadic->parameters.len, count);
|
|
1658
|
+
return Napi::Env(env).Null();
|
|
1564
1659
|
}
|
|
1565
|
-
if ((
|
|
1566
|
-
ThrowError<Napi::
|
|
1567
|
-
return env.Null();
|
|
1660
|
+
if ((count - variadic->required_parameters) % 2) [[unlikely]] {
|
|
1661
|
+
ThrowError<Napi::Error>(env, "Missing value argument for variadic call");
|
|
1662
|
+
return Napi::Env(env).Null();
|
|
1568
1663
|
}
|
|
1569
1664
|
|
|
1570
|
-
|
|
1571
|
-
|
|
1665
|
+
for (Size i = variadic->required_parameters; i < count; i += 2) {
|
|
1666
|
+
ParameterInfo param = {};
|
|
1572
1667
|
|
|
1573
|
-
|
|
1574
|
-
}
|
|
1668
|
+
param.type = ResolveType(Napi::Value(env, args[i]), ¶m.directions);
|
|
1575
1669
|
|
|
1576
|
-
|
|
1577
|
-
|
|
1670
|
+
if (!param.type) [[unlikely]]
|
|
1671
|
+
return Napi::Env(env).Null();
|
|
1672
|
+
if (!CanPassType(param.type, param.directions)) [[unlikely]] {
|
|
1673
|
+
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
|
|
1674
|
+
return Napi::Env(env).Null();
|
|
1675
|
+
}
|
|
1676
|
+
if (variadic->parameters.len >= MaxParameters) [[unlikely]] {
|
|
1677
|
+
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
|
|
1678
|
+
return Napi::Env(env).Null();
|
|
1679
|
+
}
|
|
1578
1680
|
|
|
1579
|
-
|
|
1580
|
-
|
|
1681
|
+
param.variadic = true;
|
|
1682
|
+
param.offset = (int8_t)(i + 1);
|
|
1581
1683
|
|
|
1582
|
-
|
|
1583
|
-
|
|
1684
|
+
variadic->parameters.Append(param);
|
|
1685
|
+
}
|
|
1584
1686
|
|
|
1585
|
-
|
|
1586
|
-
|
|
1687
|
+
if (!AnalyseFunction(env, instance, variadic)) [[unlikely]]
|
|
1688
|
+
return Napi::Env(env).Null();
|
|
1587
1689
|
}
|
|
1588
1690
|
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1691
|
+
InstanceMemory *mem = instance->memories[0];
|
|
1692
|
+
CallData call(env, instance, mem, native);
|
|
1693
|
+
|
|
1694
|
+
K_DEFER_C(prev_call = instance->sync_call) { instance->sync_call = prev_call; };
|
|
1695
|
+
instance->sync_call = &call;
|
|
1696
|
+
|
|
1697
|
+
napi_value ret = call.Run(variadic, args);
|
|
1698
|
+
call.Finalize();
|
|
1593
1699
|
|
|
1594
|
-
|
|
1700
|
+
if (variadic != instance->variadic_func) {
|
|
1701
|
+
err_guard.Disable();
|
|
1702
|
+
|
|
1703
|
+
delete instance->variadic_func;
|
|
1704
|
+
instance->variadic_func = variadic;
|
|
1595
1705
|
}
|
|
1596
1706
|
|
|
1597
|
-
return
|
|
1707
|
+
return ret;
|
|
1598
1708
|
}
|
|
1599
1709
|
|
|
1600
|
-
|
|
1710
|
+
napi_value TranslateVariadicCall(napi_env env, napi_callback_info info)
|
|
1601
1711
|
{
|
|
1602
|
-
|
|
1603
|
-
|
|
1712
|
+
napi_value args[MaxParameters];
|
|
1713
|
+
size_t count = 6;
|
|
1714
|
+
FunctionInfo *func;
|
|
1715
|
+
|
|
1716
|
+
napi_status status = napi_get_cb_info(env, info, &count, args, nullptr, (void **)&func);
|
|
1717
|
+
K_ASSERT(status == napi_ok);
|
|
1718
|
+
|
|
1719
|
+
if (count > 6) {
|
|
1720
|
+
napi_status status = napi_get_cb_info(env, info, &count, args, nullptr, nullptr);
|
|
1721
|
+
K_ASSERT(status == napi_ok);
|
|
1722
|
+
|
|
1723
|
+
count = std::min(count, (size_t)MaxParameters);
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
return TranslateVariadicCall(env, func, func->native, args, (Size)count);
|
|
1604
1727
|
}
|
|
1605
1728
|
|
|
1606
1729
|
class AsyncCall: public Napi::AsyncWorker {
|
|
1607
1730
|
Napi::Env env;
|
|
1608
1731
|
|
|
1609
1732
|
const FunctionInfo *func;
|
|
1610
|
-
|
|
1733
|
+
NoDestroy<CallData> call;
|
|
1611
1734
|
|
|
1612
|
-
CallData call;
|
|
1613
1735
|
bool prepared = false;
|
|
1614
1736
|
|
|
1615
1737
|
public:
|
|
1616
|
-
AsyncCall(Napi::Env env, InstanceData *instance, const FunctionInfo *func,
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
call(env, instance, mem) {}
|
|
1620
|
-
~AsyncCall() { func->Unref(); }
|
|
1738
|
+
AsyncCall(Napi::Env env, InstanceData *instance, InstanceMemory *mem, const FunctionInfo *func, Napi::Function &callback)
|
|
1739
|
+
: Napi::AsyncWorker(callback), env(env), func(func->Ref()), call(env, instance, mem, func->native) {}
|
|
1740
|
+
~AsyncCall();
|
|
1621
1741
|
|
|
1622
|
-
bool Prepare(
|
|
1623
|
-
prepared = call
|
|
1742
|
+
bool Prepare(napi_value *args) {
|
|
1743
|
+
prepared = call->PrepareAsync(func, args);
|
|
1624
1744
|
|
|
1625
|
-
if (!prepared) {
|
|
1745
|
+
if (!prepared) [[unlikely]] {
|
|
1626
1746
|
Napi::Error err = env.GetAndClearPendingException();
|
|
1627
1747
|
SetError(err.Message());
|
|
1628
1748
|
}
|
|
1629
1749
|
|
|
1630
1750
|
return prepared;
|
|
1631
1751
|
}
|
|
1632
|
-
void DumpForward() { call.DumpForward(func); }
|
|
1633
1752
|
|
|
1634
1753
|
void Execute() override;
|
|
1635
1754
|
void OnOK() override;
|
|
1755
|
+
void OnError(const Napi::Error& err) override;
|
|
1636
1756
|
};
|
|
1637
1757
|
|
|
1638
|
-
|
|
1758
|
+
AsyncCall::~AsyncCall()
|
|
1639
1759
|
{
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1760
|
+
#if defined(K_DEBUG)
|
|
1761
|
+
call->~CallData();
|
|
1762
|
+
#endif
|
|
1763
|
+
|
|
1764
|
+
ReleaseMemory(call->instance, call->mem);
|
|
1765
|
+
}
|
|
1643
1766
|
|
|
1644
|
-
|
|
1767
|
+
void AsyncCall::Execute()
|
|
1768
|
+
{
|
|
1769
|
+
if (prepared) [[likely]] {
|
|
1770
|
+
call->ExecuteAsync();
|
|
1645
1771
|
}
|
|
1646
1772
|
}
|
|
1647
1773
|
|
|
@@ -1651,90 +1777,138 @@ void AsyncCall::OnOK()
|
|
|
1651
1777
|
|
|
1652
1778
|
Napi::FunctionReference &callback = Callback();
|
|
1653
1779
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
};
|
|
1780
|
+
napi_value ret = call->EndAsync();
|
|
1781
|
+
call->Finalize();
|
|
1782
|
+
|
|
1783
|
+
napi_value self = env.Null();
|
|
1784
|
+
napi_value args[] = { env.Null(), ret };
|
|
1659
1785
|
|
|
1660
1786
|
callback.Call(self, K_LEN(args), args);
|
|
1661
1787
|
}
|
|
1662
1788
|
|
|
1663
|
-
|
|
1664
|
-
const Napi::CallbackInfo &info)
|
|
1789
|
+
void AsyncCall::OnError(const Napi::Error& err)
|
|
1665
1790
|
{
|
|
1666
|
-
|
|
1791
|
+
Napi::FunctionReference &callback = Callback();
|
|
1667
1792
|
|
|
1668
|
-
|
|
1669
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1793
|
+
call->Finalize();
|
|
1670
1794
|
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1795
|
+
napi_value self = env.Null();
|
|
1796
|
+
napi_value args[] = { err.Value(), env.Undefined() };
|
|
1797
|
+
|
|
1798
|
+
callback.Call(self, K_LEN(args), args);
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
napi_value TranslateAsyncCall(napi_env env, napi_callback_info info)
|
|
1802
|
+
{
|
|
1803
|
+
static_assert(MaxParameters >= 6);
|
|
1804
|
+
|
|
1805
|
+
napi_value args[MaxParameters];
|
|
1806
|
+
size_t count = 6;
|
|
1807
|
+
FunctionInfo *func;
|
|
1808
|
+
|
|
1809
|
+
napi_status status = napi_get_cb_info(env, info, &count, args, nullptr, (void **)&func);
|
|
1810
|
+
K_ASSERT(status == napi_ok);
|
|
1811
|
+
|
|
1812
|
+
if (count > 6) {
|
|
1813
|
+
napi_status status = napi_get_cb_info(env, info, &count, args, nullptr, nullptr);
|
|
1814
|
+
K_ASSERT(status == napi_ok);
|
|
1815
|
+
|
|
1816
|
+
count = std::min(count, (size_t)MaxParameters);
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
InstanceData *instance = func->instance;
|
|
1820
|
+
|
|
1821
|
+
if (count <= (size_t)func->required_parameters) {
|
|
1822
|
+
ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->required_parameters + 1, count);
|
|
1823
|
+
return Napi::Env(env).Null();
|
|
1674
1824
|
}
|
|
1675
1825
|
|
|
1676
|
-
Napi::Function callback =
|
|
1826
|
+
Napi::Function callback = Napi::Value(env, args[func->required_parameters]).As<Napi::Function>();
|
|
1677
1827
|
|
|
1678
1828
|
if (!callback.IsFunction()) {
|
|
1679
1829
|
ThrowError<Napi::TypeError>(env, "Expected callback function as last argument, got %1", GetValueType(instance, callback));
|
|
1680
|
-
return env.Null();
|
|
1830
|
+
return Napi::Env(env).Null();
|
|
1681
1831
|
}
|
|
1682
1832
|
|
|
1683
1833
|
InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
|
|
1684
1834
|
if (!mem) [[unlikely]] {
|
|
1685
1835
|
ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
|
|
1686
|
-
return env.Null();
|
|
1836
|
+
return Napi::Env(env).Null();
|
|
1687
1837
|
}
|
|
1688
|
-
AsyncCall *async = new AsyncCall(env, instance,
|
|
1838
|
+
AsyncCall *async = new AsyncCall(env, instance, mem, func, callback);
|
|
1689
1839
|
|
|
1690
|
-
|
|
1691
|
-
async->DumpForward();
|
|
1692
|
-
}
|
|
1840
|
+
async->Prepare(args);
|
|
1693
1841
|
async->Queue();
|
|
1694
1842
|
|
|
1695
|
-
return env.Undefined();
|
|
1843
|
+
return Napi::Env(env).Undefined();
|
|
1696
1844
|
}
|
|
1697
1845
|
|
|
1698
|
-
|
|
1846
|
+
static FORCE_INLINE bool CheckTrampolineStatus(TrampolineInfo *trampoline)
|
|
1699
1847
|
{
|
|
1700
|
-
|
|
1701
|
-
|
|
1848
|
+
if (trampoline->state == 1) [[likely]]
|
|
1849
|
+
return true;
|
|
1850
|
+
|
|
1851
|
+
Napi::Env env = trampoline->func.Env();
|
|
1852
|
+
|
|
1853
|
+
if (!trampoline->state) {
|
|
1854
|
+
ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
|
|
1855
|
+
trampoline->state = -1;
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
// We use trampoline->state < 0 as a signal than an exception has occured, because we want
|
|
1859
|
+
// to avoid calling IsExceptionPending() in the happy path. But trampolines get reused, so
|
|
1860
|
+
// there might not be an exception anymore!
|
|
1861
|
+
if (!env.IsExceptionPending()) {
|
|
1862
|
+
trampoline->state = 1;
|
|
1863
|
+
return true;
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
return false;
|
|
1702
1867
|
}
|
|
1703
1868
|
|
|
1704
1869
|
extern "C" void RelayCallback(Size idx, uint8_t *sp)
|
|
1705
1870
|
{
|
|
1706
|
-
|
|
1871
|
+
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1872
|
+
InstanceData *instance = trampoline->instance;
|
|
1707
1873
|
|
|
1708
|
-
//
|
|
1709
|
-
//
|
|
1710
|
-
// Node and V8
|
|
1711
|
-
if (
|
|
1712
|
-
|
|
1874
|
+
// Fast path: main thread and we are running a native call through Koffi.
|
|
1875
|
+
// But this means we are running on the custom Koffi stack, which could trip up
|
|
1876
|
+
// Node and V8, so we need to stwich back to the normal/main stack.
|
|
1877
|
+
if (InstanceMemory *mem0 = instance->memories[0]; sp >= mem0->stack0.ptr && sp <= mem0->stack0.end) {
|
|
1878
|
+
CallData *call = instance->sync_call;
|
|
1879
|
+
|
|
1880
|
+
SwitchAndRelay(call, idx, sp, call->saved_sp, &call->mem->stack);
|
|
1713
1881
|
return;
|
|
1714
1882
|
}
|
|
1715
1883
|
|
|
1884
|
+
if (!CheckTrampolineStatus(trampoline))
|
|
1885
|
+
return;
|
|
1886
|
+
|
|
1716
1887
|
// Otherwise, we need to allocate memory to perform the callback.
|
|
1717
1888
|
// Since the necessary machinery live in CallData, just use a temporary instance.
|
|
1718
|
-
// In some cases we would reuse the existing call
|
|
1719
|
-
//
|
|
1889
|
+
// In some cases we would reuse the existing call, but it is rare so let's ignore
|
|
1890
|
+
// this for simplicity.
|
|
1720
1891
|
|
|
1721
|
-
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1722
1892
|
Napi::Env env = trampoline->func.Env();
|
|
1723
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1724
1893
|
|
|
1725
1894
|
InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
|
|
1726
1895
|
if (!mem) [[unlikely]] {
|
|
1727
1896
|
ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
|
|
1728
1897
|
return;
|
|
1729
1898
|
}
|
|
1899
|
+
K_DEFER { ReleaseMemory(instance, mem); };
|
|
1730
1900
|
|
|
1731
1901
|
if (std::this_thread::get_id() == instance->main_thread_id) {
|
|
1732
|
-
CallData call(env, instance, mem);
|
|
1902
|
+
CallData call(env, instance, mem, nullptr);
|
|
1903
|
+
K_DEFER { call.Finalize(); };
|
|
1904
|
+
|
|
1905
|
+
napi_handle_scope scope;
|
|
1906
|
+
napi_open_handle_scope(env, &scope);
|
|
1907
|
+
K_DEFER { napi_close_handle_scope(env, scope); };
|
|
1733
1908
|
|
|
1734
|
-
Napi::HandleScope scope(env);
|
|
1735
1909
|
call.Relay(idx, sp);
|
|
1736
1910
|
} else {
|
|
1737
|
-
CallData call(env, instance, mem);
|
|
1911
|
+
CallData call(env, instance, mem, nullptr);
|
|
1738
1912
|
call.RelayAsync(idx, sp);
|
|
1739
1913
|
}
|
|
1740
1914
|
}
|
|
@@ -1742,7 +1916,6 @@ extern "C" void RelayCallback(Size idx, uint8_t *sp)
|
|
|
1742
1916
|
extern "C" void RelayDirect(CallData *call, Size idx, uint8_t *sp)
|
|
1743
1917
|
{
|
|
1744
1918
|
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1745
|
-
Napi::Env env = trampoline->func.Env();
|
|
1746
1919
|
|
|
1747
1920
|
#if defined(_WIN32)
|
|
1748
1921
|
TEB *teb = GetTEB();
|
|
@@ -1763,15 +1936,17 @@ extern "C" void RelayDirect(CallData *call, Size idx, uint8_t *sp)
|
|
|
1763
1936
|
teb->DeallocationStack = instance->main_stack_min;
|
|
1764
1937
|
#endif
|
|
1765
1938
|
|
|
1766
|
-
if (
|
|
1767
|
-
return;
|
|
1768
|
-
if (!trampoline->used) [[unlikely]] {
|
|
1769
|
-
ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
|
|
1939
|
+
if (!CheckTrampolineStatus(trampoline))
|
|
1770
1940
|
return;
|
|
1771
|
-
}
|
|
1772
1941
|
|
|
1773
|
-
|
|
1774
|
-
|
|
1942
|
+
// Relay the call
|
|
1943
|
+
{
|
|
1944
|
+
napi_handle_scope scope;
|
|
1945
|
+
napi_open_handle_scope(call->env, &scope);
|
|
1946
|
+
K_DEFER { napi_close_handle_scope(call->env, scope); };
|
|
1947
|
+
|
|
1948
|
+
call->Relay(idx, sp);
|
|
1949
|
+
}
|
|
1775
1950
|
}
|
|
1776
1951
|
|
|
1777
1952
|
static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
|
|
@@ -1783,6 +1958,8 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
|
|
|
1783
1958
|
FunctionInfo *func = new FunctionInfo();
|
|
1784
1959
|
K_DEFER { func->Unref(); };
|
|
1785
1960
|
|
|
1961
|
+
func->env = env;
|
|
1962
|
+
func->instance = instance;
|
|
1786
1963
|
func->lib = lib->Ref();
|
|
1787
1964
|
|
|
1788
1965
|
if (info.Length() >= 2) {
|
|
@@ -1810,10 +1987,6 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
|
|
|
1810
1987
|
|
|
1811
1988
|
if (!AnalyseFunction(env, instance, func))
|
|
1812
1989
|
return env.Null();
|
|
1813
|
-
if (func->variadic) {
|
|
1814
|
-
// Minimize reallocations
|
|
1815
|
-
func->parameters.Grow(32);
|
|
1816
|
-
}
|
|
1817
1990
|
|
|
1818
1991
|
#if defined(_WIN32)
|
|
1819
1992
|
if (func->ordinal_name < 0) {
|
|
@@ -1877,10 +2050,7 @@ static Napi::Value FindSymbol(const Napi::CallbackInfo &info)
|
|
|
1877
2050
|
return env.Null();
|
|
1878
2051
|
}
|
|
1879
2052
|
|
|
1880
|
-
|
|
1881
|
-
SetValueTag(external, &type);
|
|
1882
|
-
|
|
1883
|
-
return external;
|
|
2053
|
+
return WrapPointer(env, type, ptr);
|
|
1884
2054
|
}
|
|
1885
2055
|
|
|
1886
2056
|
static Napi::Value UnloadLibrary(const Napi::CallbackInfo &info)
|
|
@@ -1902,11 +2072,11 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
1902
2072
|
ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
|
|
1903
2073
|
return env.Null();
|
|
1904
2074
|
}
|
|
1905
|
-
if (!info[0].IsString() && !IsNullOrUndefined(info[0])) {
|
|
2075
|
+
if (!info[0].IsString() && !IsNullOrUndefined(env, info[0])) {
|
|
1906
2076
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for filename, expected string or null", GetValueType(instance, info[0]));
|
|
1907
2077
|
return env.Null();
|
|
1908
2078
|
}
|
|
1909
|
-
if (info.Length() >= 2 && !IsObject(info[1])) {
|
|
2079
|
+
if (info.Length() >= 2 && !IsObject(env, info[1])) {
|
|
1910
2080
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for options, expected object", GetValueType(instance, info[1]));
|
|
1911
2081
|
return env.Null();
|
|
1912
2082
|
}
|
|
@@ -2037,25 +2207,22 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
|
|
|
2037
2207
|
|
|
2038
2208
|
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
2039
2209
|
|
|
2210
|
+
trampoline->state = 1;
|
|
2040
2211
|
trampoline->instance = instance;
|
|
2041
2212
|
trampoline->proto = type->ref.proto;
|
|
2042
2213
|
trampoline->func.Reset(func, 1);
|
|
2043
|
-
if (!IsNullOrUndefined(recv)) {
|
|
2214
|
+
if (!IsNullOrUndefined(env, recv)) {
|
|
2044
2215
|
trampoline->recv.Reset(recv, 1);
|
|
2045
2216
|
} else {
|
|
2046
2217
|
trampoline->recv.Reset();
|
|
2047
2218
|
}
|
|
2048
|
-
trampoline->used = true;
|
|
2049
2219
|
|
|
2050
2220
|
void *ptr = GetTrampoline(idx);
|
|
2051
2221
|
|
|
2052
|
-
Napi::External<void> external = Napi::External<void>::New(env, ptr);
|
|
2053
|
-
SetValueTag(external, type->ref.marker);
|
|
2054
|
-
|
|
2055
2222
|
// Cache index for fast unregistration
|
|
2056
2223
|
instance->trampolines_map.Set(ptr, idx);
|
|
2057
2224
|
|
|
2058
|
-
return
|
|
2225
|
+
return WrapCallback(env, type->ref.type, ptr);
|
|
2059
2226
|
}
|
|
2060
2227
|
|
|
2061
2228
|
static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
|
|
@@ -2067,14 +2234,13 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
|
|
|
2067
2234
|
ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
|
|
2068
2235
|
return env.Null();
|
|
2069
2236
|
}
|
|
2070
|
-
|
|
2237
|
+
|
|
2238
|
+
void *ptr;
|
|
2239
|
+
if (!TryPointer(env, info[0], &ptr)) {
|
|
2071
2240
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for id, expected registered callback", GetValueType(instance, info[0]));
|
|
2072
2241
|
return env.Null();
|
|
2073
2242
|
}
|
|
2074
2243
|
|
|
2075
|
-
Napi::External<void> external = info[0].As<Napi::External<void>>();
|
|
2076
|
-
void *ptr = external.Data();
|
|
2077
|
-
|
|
2078
2244
|
int16_t idx;
|
|
2079
2245
|
{
|
|
2080
2246
|
int16_t *it = instance->trampolines_map.Find(ptr);
|
|
@@ -2095,9 +2261,9 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
|
|
|
2095
2261
|
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
2096
2262
|
K_ASSERT(!trampoline->func.IsEmpty());
|
|
2097
2263
|
|
|
2264
|
+
trampoline->state = 0;
|
|
2098
2265
|
trampoline->func.Reset();
|
|
2099
2266
|
trampoline->recv.Reset();
|
|
2100
|
-
trampoline->used = false;
|
|
2101
2267
|
|
|
2102
2268
|
shared.available.Append(idx);
|
|
2103
2269
|
}
|
|
@@ -2128,13 +2294,14 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
|
|
|
2128
2294
|
return env.Null();
|
|
2129
2295
|
}
|
|
2130
2296
|
|
|
2131
|
-
ValueCast *cast = new ValueCast;
|
|
2297
|
+
ValueCast *cast = new ValueCast();
|
|
2132
2298
|
|
|
2133
|
-
cast->
|
|
2299
|
+
cast->env = env;
|
|
2300
|
+
napi_create_reference(env, value, 1, &cast->ref);
|
|
2134
2301
|
cast->type = type;
|
|
2135
2302
|
|
|
2136
2303
|
Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::Env, ValueCast *cast) { delete cast; });
|
|
2137
|
-
SetValueTag(external, &CastMarker);
|
|
2304
|
+
SetValueTag(env, external, &CastMarker);
|
|
2138
2305
|
|
|
2139
2306
|
return external;
|
|
2140
2307
|
}
|
|
@@ -2161,10 +2328,10 @@ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
|
|
|
2161
2328
|
if (has_len) {
|
|
2162
2329
|
Size len = info[2 + has_offset].As<Napi::Number>();
|
|
2163
2330
|
|
|
2164
|
-
Napi::Value ret = Decode(value, offset, type, &len);
|
|
2331
|
+
Napi::Value ret = Decode(value, (Size)offset, type, &len);
|
|
2165
2332
|
return ret;
|
|
2166
2333
|
} else {
|
|
2167
|
-
Napi::Value ret = Decode(value, offset, type);
|
|
2334
|
+
Napi::Value ret = Decode(value, (Size)offset, type);
|
|
2168
2335
|
return ret;
|
|
2169
2336
|
}
|
|
2170
2337
|
}
|
|
@@ -2212,8 +2379,10 @@ static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
|
|
|
2212
2379
|
|
|
2213
2380
|
const FunctionInfo *proto = type->ref.proto;
|
|
2214
2381
|
|
|
2215
|
-
|
|
2216
|
-
|
|
2382
|
+
napi_value ret = proto->variadic ? TranslateVariadicCall(env, proto, ptr, info.First() + 2, info.Length() - 2)
|
|
2383
|
+
: TranslateNormalCall(env, proto, ptr, info.First() + 2, info.Length() - 2);
|
|
2384
|
+
|
|
2385
|
+
return Napi::Value(env, ret);
|
|
2217
2386
|
}
|
|
2218
2387
|
|
|
2219
2388
|
static Napi::Value EncodeValue(const Napi::CallbackInfo &info)
|
|
@@ -2239,10 +2408,10 @@ static Napi::Value EncodeValue(const Napi::CallbackInfo &info)
|
|
|
2239
2408
|
if (has_len) {
|
|
2240
2409
|
Size len = info[3 + has_offset].As<Napi::Number>();
|
|
2241
2410
|
|
|
2242
|
-
if (!Encode(ref, offset, value, type, &len))
|
|
2411
|
+
if (!Encode(ref, (Size)offset, value, type, &len))
|
|
2243
2412
|
return env.Null();
|
|
2244
2413
|
} else {
|
|
2245
|
-
if (!Encode(ref, offset, value, type))
|
|
2414
|
+
if (!Encode(ref, (Size)offset, value, type))
|
|
2246
2415
|
return env.Null();
|
|
2247
2416
|
}
|
|
2248
2417
|
|
|
@@ -2318,6 +2487,11 @@ static Napi::Value ResetKoffi(const Napi::CallbackInfo &info)
|
|
|
2318
2487
|
|
|
2319
2488
|
instance->callbacks.Clear();
|
|
2320
2489
|
|
|
2490
|
+
for (InstanceMemory *mem: instance->memories) {
|
|
2491
|
+
delete mem;
|
|
2492
|
+
}
|
|
2493
|
+
instance->memories.Clear();
|
|
2494
|
+
|
|
2321
2495
|
return env.Undefined();
|
|
2322
2496
|
}
|
|
2323
2497
|
|
|
@@ -2349,6 +2523,18 @@ void LibraryHolder::Unref() const
|
|
|
2349
2523
|
}
|
|
2350
2524
|
}
|
|
2351
2525
|
|
|
2526
|
+
ValueCast::~ValueCast()
|
|
2527
|
+
{
|
|
2528
|
+
if (node_api_post_finalizer) {
|
|
2529
|
+
node_api_post_finalizer(env, [](napi_env env, void *data, void *) {
|
|
2530
|
+
napi_ref ref = (napi_ref)data;
|
|
2531
|
+
napi_delete_reference(env, ref);
|
|
2532
|
+
}, (void *)ref, nullptr);
|
|
2533
|
+
} else {
|
|
2534
|
+
napi_delete_reference(env, ref);
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2352
2538
|
FunctionInfo::~FunctionInfo()
|
|
2353
2539
|
{
|
|
2354
2540
|
if (lib) {
|
|
@@ -2380,10 +2566,10 @@ InstanceMemory::~InstanceMemory()
|
|
|
2380
2566
|
}
|
|
2381
2567
|
#else
|
|
2382
2568
|
if (stack.ptr) {
|
|
2383
|
-
munmap(stack.ptr, stack.
|
|
2569
|
+
munmap(stack.ptr, stack.end - stack.ptr);
|
|
2384
2570
|
}
|
|
2385
2571
|
if (heap.ptr) {
|
|
2386
|
-
munmap(heap.ptr, heap.
|
|
2572
|
+
munmap(heap.ptr, heap.end - heap.ptr);
|
|
2387
2573
|
}
|
|
2388
2574
|
#endif
|
|
2389
2575
|
}
|
|
@@ -2431,10 +2617,8 @@ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initiali
|
|
|
2431
2617
|
}
|
|
2432
2618
|
|
|
2433
2619
|
if (ref) {
|
|
2434
|
-
|
|
2435
|
-
K_ASSERT(
|
|
2436
|
-
|
|
2437
|
-
type->ref.marker = marker;
|
|
2620
|
+
type->ref.type = instance->types_map.FindValue(ref, nullptr);
|
|
2621
|
+
K_ASSERT(type->ref.type);
|
|
2438
2622
|
}
|
|
2439
2623
|
|
|
2440
2624
|
Napi::Value wrapper = WrapType(env, type);
|
|
@@ -2480,33 +2664,124 @@ static inline PrimitiveKind GetBigEndianPrimitive(PrimitiveKind kind)
|
|
|
2480
2664
|
#endif
|
|
2481
2665
|
}
|
|
2482
2666
|
|
|
2483
|
-
static
|
|
2667
|
+
static bool DetectBun(Napi::Env env)
|
|
2484
2668
|
{
|
|
2485
|
-
|
|
2486
|
-
|
|
2669
|
+
Napi::Value ret = env.RunScript("process.isBun");
|
|
2670
|
+
Napi::Boolean b = ret.ToBoolean();
|
|
2487
2671
|
|
|
2488
|
-
|
|
2672
|
+
return b.Value();
|
|
2673
|
+
}
|
|
2489
2674
|
|
|
2490
|
-
|
|
2675
|
+
static void PickTranslateZeroCallVariant(Napi::Env env)
|
|
2676
|
+
{
|
|
2677
|
+
static int BunTrap = 42;
|
|
2491
2678
|
|
|
2492
|
-
|
|
2493
|
-
TEB *teb = GetTEB();
|
|
2679
|
+
Napi::Object self = Napi::Object::New(env);
|
|
2494
2680
|
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2681
|
+
napi_status status;
|
|
2682
|
+
napi_value func;
|
|
2683
|
+
napi_value ret;
|
|
2498
2684
|
|
|
2499
|
-
|
|
2500
|
-
|
|
2685
|
+
status = napi_create_function(env, nullptr, 0, [](napi_env env, napi_callback_info info) {
|
|
2686
|
+
napi_value self;
|
|
2687
|
+
napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr);
|
|
2688
|
+
|
|
2689
|
+
void **ptr1 = (void **)info;
|
|
2690
|
+
napi_value *ptr2 = (napi_value *)info;
|
|
2691
|
+
|
|
2692
|
+
if (ptr1[0] == &BunTrap || ptr1[1] == &BunTrap) {
|
|
2693
|
+
translate_zero_call = TranslateZeroCallBun;
|
|
2694
|
+
} else if (ptr2[0] != self && ptr2[1] != self) {
|
|
2695
|
+
translate_zero_call = TranslateZeroCallNode;
|
|
2696
|
+
} else {
|
|
2697
|
+
translate_zero_call = TranslateFastCall;
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
return self;
|
|
2701
|
+
}, &BunTrap, &func);
|
|
2702
|
+
K_ASSERT(status == napi_ok);
|
|
2703
|
+
|
|
2704
|
+
status = napi_call_function(env, self, func, 0, nullptr, &ret);
|
|
2705
|
+
K_ASSERT(status == napi_ok);
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
static bool CanReferencePrimitiveValues(napi_env env)
|
|
2709
|
+
{
|
|
2710
|
+
uint32_t version = 0;
|
|
2711
|
+
napi_get_version(env, &version);
|
|
2712
|
+
|
|
2713
|
+
return version >= 10;
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
static bool CanDeleteReferenceInFinalizer(napi_env env)
|
|
2717
|
+
{
|
|
2718
|
+
const napi_node_version *version = nullptr;
|
|
2719
|
+
napi_get_node_version(env, &version);
|
|
2720
|
+
|
|
2721
|
+
if (version->major >= 24)
|
|
2722
|
+
return true;
|
|
2723
|
+
|
|
2724
|
+
// Made by looking at the git history of each release branch
|
|
2725
|
+
if (version->major == 23 && version->minor >= 5)
|
|
2726
|
+
return true;
|
|
2727
|
+
if (version->major == 22 && version->minor >= 13)
|
|
2728
|
+
return true;
|
|
2729
|
+
if (version->major == 20 && version->minor >= 19)
|
|
2730
|
+
return true;
|
|
2731
|
+
if (version->major == 20 && version->minor == 18 && version->patch >= 3)
|
|
2732
|
+
return true;
|
|
2733
|
+
|
|
2734
|
+
return false;
|
|
2501
2735
|
}
|
|
2502
2736
|
|
|
2503
2737
|
static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
2504
2738
|
{
|
|
2505
|
-
|
|
2739
|
+
// Load recent N-API functions (version >= 9) functions dynamically
|
|
2740
|
+
{
|
|
2741
|
+
static std::once_flag flag;
|
|
2742
|
+
|
|
2743
|
+
std::call_once(flag, [&]() {
|
|
2744
|
+
PickTranslateZeroCallVariant(env);
|
|
2745
|
+
|
|
2746
|
+
if (DetectBun(env))
|
|
2747
|
+
return;
|
|
2748
|
+
|
|
2749
|
+
uv_lib_t lib = {};
|
|
2750
|
+
|
|
2751
|
+
#if defined(_WIN32)
|
|
2752
|
+
lib.handle = GetModuleHandle(nullptr);
|
|
2753
|
+
#else
|
|
2754
|
+
uv_dlopen(nullptr, &lib);
|
|
2755
|
+
K_DEFER { uv_dlclose(&lib); };
|
|
2756
|
+
#endif
|
|
2757
|
+
|
|
2758
|
+
if (CanReferencePrimitiveValues(env)) {
|
|
2759
|
+
// We can't use optimized property keys in older versions because we need to create
|
|
2760
|
+
// references to them, but napi_create_reference() was not usable with primitive values.
|
|
2761
|
+
uv_dlsym(&lib, "node_api_create_property_key_utf8", (void **)&node_api_create_property_key_utf8);
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
if (!CanDeleteReferenceInFinalizer(env)) {
|
|
2765
|
+
// napi_delete_reference cannot be safely used in older Node versions because it
|
|
2766
|
+
// errors out (or even asserts) if it gets called in a finalizer. In this case,
|
|
2767
|
+
// use experimental API to try to run it later.
|
|
2768
|
+
uv_dlsym(&lib, "node_api_post_finalizer", (void **)&node_api_post_finalizer);
|
|
2769
|
+
}
|
|
2770
|
+
});
|
|
2771
|
+
}
|
|
2772
|
+
|
|
2773
|
+
InstanceData *instance = new InstanceData();
|
|
2506
2774
|
K_CRITICAL(instance, "Failed to initialize Koffi");
|
|
2507
2775
|
|
|
2776
|
+
instance->env = env;
|
|
2508
2777
|
env.SetInstanceData(instance);
|
|
2509
2778
|
|
|
2779
|
+
#if defined(__clang__)
|
|
2780
|
+
// First call to napi_create_double() does some weird stuff I can't explain
|
|
2781
|
+
// in clang-cl builds. I don't like this... but this fixes it, somehow ><
|
|
2782
|
+
Napi::Number::New(env, 0.0);
|
|
2783
|
+
#endif
|
|
2784
|
+
|
|
2510
2785
|
exports.Set("config", Napi::Function::New(env, GetSetConfig, "config"));
|
|
2511
2786
|
exports.Set("stats", Napi::Function::New(env, GetStats, "stats"));
|
|
2512
2787
|
|
|
@@ -2558,7 +2833,7 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2558
2833
|
Napi::Object codes = Napi::Object::New(env);
|
|
2559
2834
|
|
|
2560
2835
|
for (const ErrnoCodeInfo &info: ErrnoCodes) {
|
|
2561
|
-
codes.Set(info.name,
|
|
2836
|
+
codes.Set(info.name, NewInt(env, (int32_t)info.value));
|
|
2562
2837
|
}
|
|
2563
2838
|
|
|
2564
2839
|
os.Set("errno", codes);
|
|
@@ -2649,10 +2924,7 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2649
2924
|
Napi::Object node = Napi::Object::New(env);
|
|
2650
2925
|
exports.Set("node", node);
|
|
2651
2926
|
|
|
2652
|
-
|
|
2653
|
-
SetValueTag(external, instance->void_type);
|
|
2654
|
-
|
|
2655
|
-
node.Set("env", external);
|
|
2927
|
+
node.Set("env", WrapPointer(env, instance->void_type, (napi_env)env));
|
|
2656
2928
|
|
|
2657
2929
|
node.Set("poll", Napi::Function::New(env, &Poll, "poll"));
|
|
2658
2930
|
node.Set("PollHandle", PollHandle::Define(env));
|
|
@@ -2660,6 +2932,18 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2660
2932
|
|
|
2661
2933
|
exports.Set("version", Napi::String::New(env, K_STRINGIFY(VERSION)));
|
|
2662
2934
|
|
|
2935
|
+
#if defined(_WIN32)
|
|
2936
|
+
{
|
|
2937
|
+
TEB *teb = GetTEB();
|
|
2938
|
+
|
|
2939
|
+
instance->main_stack_max = teb->StackBase;
|
|
2940
|
+
instance->main_stack_min = teb->DeallocationStack;
|
|
2941
|
+
}
|
|
2942
|
+
#endif
|
|
2943
|
+
|
|
2944
|
+
instance->translate_zero_call = translate_zero_call;
|
|
2945
|
+
instance->main_thread_id = std::this_thread::get_id();
|
|
2946
|
+
|
|
2663
2947
|
napi_add_env_cleanup_hook(env, [](void *udata) {
|
|
2664
2948
|
InstanceData *instance = (InstanceData *)udata;
|
|
2665
2949
|
|
|
@@ -2676,6 +2960,8 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2676
2960
|
|
|
2677
2961
|
InstanceData::~InstanceData()
|
|
2678
2962
|
{
|
|
2963
|
+
delete variadic_func;
|
|
2964
|
+
|
|
2679
2965
|
for (InstanceMemory *mem: memories) {
|
|
2680
2966
|
delete mem;
|
|
2681
2967
|
}
|
|
@@ -2691,7 +2977,7 @@ InstanceData::~InstanceData()
|
|
|
2691
2977
|
trampoline->instance = nullptr;
|
|
2692
2978
|
trampoline->func.Reset();
|
|
2693
2979
|
trampoline->recv.Reset();
|
|
2694
|
-
trampoline->
|
|
2980
|
+
trampoline->state = 0;
|
|
2695
2981
|
}
|
|
2696
2982
|
}
|
|
2697
2983
|
}
|