koffi 3.0.1 → 3.1.0
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 +32 -3
- package/cnoke.cjs +2 -2
- package/doc/benchmarks.md +1 -1
- package/doc/callbacks.md +7 -26
- package/doc/{input.md → composites.md} +161 -147
- package/doc/contribute.md +3 -2
- package/doc/index.md +0 -14
- package/doc/{functions.md → load.md} +54 -113
- package/doc/migration.md +4 -7
- package/doc/misc.md +0 -103
- package/doc/output.md +5 -11
- package/doc/pointers.md +76 -17
- package/doc/primitives.md +151 -0
- package/doc/start.md +3 -13
- package/doc/types.md +88 -0
- package/doc/unions.md +0 -186
- package/doc/values.md +134 -0
- package/index.d.ts +375 -308
- package/lib/native/base/base.cc +66 -24
- package/lib/native/base/base.hh +55 -153
- package/package.json +16 -16
- package/src/koffi/CMakeLists.txt +20 -17
- package/src/koffi/index.cjs +30 -111
- package/src/koffi/index.js +22 -96
- package/src/koffi/indirect.cjs +30 -111
- package/src/koffi/indirect.js +24 -24
- package/src/koffi/src/abi/arm64.cc +48 -62
- package/src/koffi/src/abi/riscv64.cc +39 -57
- package/src/koffi/src/abi/x64sysv.cc +39 -57
- package/src/koffi/src/abi/x64win.cc +48 -65
- package/src/koffi/src/abi/x86.cc +47 -59
- package/src/koffi/src/call.cc +426 -209
- package/src/koffi/src/call.hh +7 -11
- package/src/koffi/src/ffi.cc +534 -303
- package/src/koffi/src/ffi.hh +71 -15
- package/src/koffi/src/parser.cc +5 -3
- package/src/koffi/src/parser.hh +2 -2
- package/src/koffi/src/static.cjs +122 -0
- package/src/koffi/src/static.js +125 -0
- package/src/koffi/src/type.cc +725 -0
- package/src/koffi/src/type.hh +71 -0
- package/src/koffi/src/util.cc +117 -1202
- package/src/koffi/src/util.hh +158 -156
- package/src/koffi/src/uv.cc +17 -11
- package/src/koffi/src/uv.hh +2 -1
- package/vendor/node-addon-api/README.md +1 -1
- package/vendor/node-addon-api/napi-inl.h +213 -35
- package/vendor/node-addon-api/napi.h +118 -7
- package/doc/variables.md +0 -102
- package/indirect.d.ts +0 -322
package/src/koffi/src/call.cc
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#include "lib/native/base/base.hh"
|
|
5
5
|
#include "call.hh"
|
|
6
6
|
#include "ffi.hh"
|
|
7
|
+
#include "type.hh"
|
|
7
8
|
#include "util.hh"
|
|
8
9
|
#if defined(_WIN32)
|
|
9
10
|
#include "win32.hh"
|
|
@@ -44,6 +45,8 @@ static const Size TrampolineSize = ((const uint8_t *)&TrampolineEnd - Trampoline
|
|
|
44
45
|
|
|
45
46
|
#endif
|
|
46
47
|
|
|
48
|
+
static napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
|
|
49
|
+
|
|
47
50
|
#if defined(K_DEBUG)
|
|
48
51
|
CallData::~CallData()
|
|
49
52
|
{
|
|
@@ -71,21 +74,12 @@ void CallData::Finalize()
|
|
|
71
74
|
DecodeElements(instance, value, out.ptr, out.type, len);
|
|
72
75
|
} break;
|
|
73
76
|
|
|
74
|
-
case OutArgument::Kind::Buffer: {
|
|
75
|
-
Span<uint8_t> buffer;
|
|
76
|
-
|
|
77
|
-
bool success = TryBuffer(env, value, &buffer);
|
|
78
|
-
K_ASSERT(success);
|
|
79
|
-
|
|
80
|
-
DecodeBuffer(buffer, out.ptr, out.type);
|
|
81
|
-
} break;
|
|
82
|
-
|
|
83
77
|
case OutArgument::Kind::String: {
|
|
84
78
|
K_ASSERT(IsArray(env, value));
|
|
85
79
|
K_ASSERT(GetArrayLength(env, value) == 1);
|
|
86
80
|
|
|
87
81
|
Size len = strnlen((const char *)out.ptr, out.max_len);
|
|
88
|
-
|
|
82
|
+
napi_value str = NewString(env, (const char *)out.ptr, len);
|
|
89
83
|
|
|
90
84
|
napi_set_element(env, value, 0, str);
|
|
91
85
|
} break;
|
|
@@ -95,7 +89,7 @@ void CallData::Finalize()
|
|
|
95
89
|
K_ASSERT(GetArrayLength(env, value) == 1);
|
|
96
90
|
|
|
97
91
|
Size len = NullTerminatedLength((const char16_t *)out.ptr, out.max_len);
|
|
98
|
-
|
|
92
|
+
napi_value str = NewString(env, (const char16_t *)out.ptr, len);
|
|
99
93
|
|
|
100
94
|
napi_set_element(env, value, 0, str);
|
|
101
95
|
} break;
|
|
@@ -105,7 +99,7 @@ void CallData::Finalize()
|
|
|
105
99
|
K_ASSERT(GetArrayLength(env, value) == 1);
|
|
106
100
|
|
|
107
101
|
Size len = NullTerminatedLength((const char32_t *)out.ptr, out.max_len);
|
|
108
|
-
|
|
102
|
+
napi_value str = NewString(env, (const char32_t *)out.ptr, len);
|
|
109
103
|
|
|
110
104
|
napi_set_element(env, value, 0, str);
|
|
111
105
|
} break;
|
|
@@ -113,7 +107,7 @@ void CallData::Finalize()
|
|
|
113
107
|
case OutArgument::Kind::Object: {
|
|
114
108
|
if (CheckValueTag(env, value, &UnionValueMarker)) {
|
|
115
109
|
UnionValue *u = nullptr;
|
|
116
|
-
napi_unwrap(env, value, (void **)&u);
|
|
110
|
+
NAPI_OK(napi_unwrap(env, value, (void **)&u));
|
|
117
111
|
|
|
118
112
|
u->SetRaw(out.ptr);
|
|
119
113
|
} else {
|
|
@@ -125,7 +119,7 @@ void CallData::Finalize()
|
|
|
125
119
|
}
|
|
126
120
|
|
|
127
121
|
for (const OutArgument &out: out_arguments) {
|
|
128
|
-
|
|
122
|
+
node_api_delete_reference(env, out.ref);
|
|
129
123
|
}
|
|
130
124
|
}
|
|
131
125
|
|
|
@@ -140,7 +134,7 @@ void CallData::Finalize()
|
|
|
140
134
|
K_ASSERT(trampoline->func);
|
|
141
135
|
|
|
142
136
|
trampoline->state = 0;
|
|
143
|
-
|
|
137
|
+
node_api_delete_reference(env, trampoline->func);
|
|
144
138
|
trampoline->func = nullptr;
|
|
145
139
|
|
|
146
140
|
shared.available.Append(idx);
|
|
@@ -183,7 +177,7 @@ void CallData::RelayAsync(Size idx, uint8_t *sp)
|
|
|
183
177
|
.sp = sp
|
|
184
178
|
};
|
|
185
179
|
|
|
186
|
-
napi_call_threadsafe_function(instance->broker, &ctx, napi_tsfn_blocking);
|
|
180
|
+
NAPI_OK(napi_call_threadsafe_function(instance->broker, &ctx, napi_tsfn_blocking));
|
|
187
181
|
|
|
188
182
|
// Wait until it executes
|
|
189
183
|
std::unique_lock<std::mutex> lock(ctx.mutex);
|
|
@@ -198,8 +192,8 @@ napi_value CallData::CallCallback(const TrampolineInfo *trampoline, const napi_v
|
|
|
198
192
|
napi_value func;
|
|
199
193
|
napi_value value;
|
|
200
194
|
|
|
201
|
-
napi_get_undefined(env, &recv);
|
|
202
|
-
napi_get_reference_value(env, trampoline->func, &func);
|
|
195
|
+
NAPI_OK(napi_get_undefined(env, &recv));
|
|
196
|
+
NAPI_OK(napi_get_reference_value(env, trampoline->func, &func));
|
|
203
197
|
|
|
204
198
|
napi_status status = napi_call_function(env, recv, func, (size_t)count, args, &value);
|
|
205
199
|
if (status == napi_pending_exception) [[unlikely]]
|
|
@@ -257,16 +251,13 @@ bool CallData::PushString32(napi_value value, int directions, const char32_t **o
|
|
|
257
251
|
Size CallData::PushStringValue(napi_value value, const char **out_str)
|
|
258
252
|
{
|
|
259
253
|
size_t len;
|
|
260
|
-
napi_status status;
|
|
261
254
|
|
|
262
255
|
size_t available = (size_t)(mem->heap.end - mem->heap.ptr);
|
|
263
256
|
char *ptr = (char *)mem->heap.ptr;
|
|
264
257
|
|
|
265
258
|
// Fast path for small strings
|
|
266
259
|
if (available >= 4096) [[likely]] {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
status = napi_get_value_string_utf8(env, value, ptr, 4096, &len);
|
|
260
|
+
napi_status status = napi_get_value_string_utf8(env, value, ptr, 4096, &len);
|
|
270
261
|
if (status == napi_string_expected)
|
|
271
262
|
return -1;
|
|
272
263
|
K_ASSERT(status == napi_ok);
|
|
@@ -285,14 +276,12 @@ Size CallData::PushStringValue(napi_value value, const char **out_str)
|
|
|
285
276
|
}
|
|
286
277
|
}
|
|
287
278
|
|
|
288
|
-
|
|
289
|
-
K_ASSERT(status == napi_ok);
|
|
279
|
+
NAPI_OK(napi_get_value_string_utf8(env, value, nullptr, 0, &len));
|
|
290
280
|
|
|
291
281
|
len++;
|
|
292
282
|
|
|
293
283
|
if (len <= available) {
|
|
294
|
-
|
|
295
|
-
K_ASSERT(status == napi_ok);
|
|
284
|
+
NAPI_OK(napi_get_value_string_utf8(env, value, ptr, len, nullptr));
|
|
296
285
|
|
|
297
286
|
mem->heap.ptr += (Size)AlignLen(len, 16);
|
|
298
287
|
|
|
@@ -302,8 +291,7 @@ Size CallData::PushStringValue(napi_value value, const char **out_str)
|
|
|
302
291
|
Span<char> buf = AllocateSpan<char>(&mem->allocator, (Size)len);
|
|
303
292
|
release_alloc |= (prev_stack == mem->stack.end);
|
|
304
293
|
|
|
305
|
-
|
|
306
|
-
K_ASSERT(status == napi_ok);
|
|
294
|
+
NAPI_OK(napi_get_value_string_utf8(env, value, buf.ptr, len, nullptr));
|
|
307
295
|
|
|
308
296
|
*out_str = buf.ptr;
|
|
309
297
|
return (Size)len;
|
|
@@ -314,9 +302,8 @@ Size CallData::PushString16Value(napi_value value, const char16_t **out_str16)
|
|
|
314
302
|
{
|
|
315
303
|
size_t len = 0;
|
|
316
304
|
Span<char16_t> buf;
|
|
317
|
-
napi_status status;
|
|
318
305
|
|
|
319
|
-
status = napi_get_value_string_utf16(env, value, nullptr, 0, &len);
|
|
306
|
+
napi_status status = napi_get_value_string_utf16(env, value, nullptr, 0, &len);
|
|
320
307
|
if (status == napi_string_expected)
|
|
321
308
|
return -1;
|
|
322
309
|
K_ASSERT(status == napi_ok);
|
|
@@ -327,16 +314,14 @@ Size CallData::PushString16Value(napi_value value, const char16_t **out_str16)
|
|
|
327
314
|
buf.len = (mem->heap.end - mem->heap.ptr) / 2;
|
|
328
315
|
|
|
329
316
|
if (len <= (size_t)buf.len) {
|
|
330
|
-
|
|
331
|
-
K_ASSERT(status == napi_ok);
|
|
317
|
+
NAPI_OK(napi_get_value_string_utf16(env, value, buf.ptr, len, nullptr));
|
|
332
318
|
|
|
333
319
|
mem->heap.ptr += (Size)AlignLen(len * 2, 16);
|
|
334
320
|
} else {
|
|
335
321
|
buf = AllocateSpan<char16_t>(&mem->allocator, (Size)len);
|
|
336
322
|
release_alloc |= (prev_stack == mem->stack.end);
|
|
337
323
|
|
|
338
|
-
|
|
339
|
-
K_ASSERT(status == napi_ok);
|
|
324
|
+
NAPI_OK(napi_get_value_string_utf16(env, value, buf.ptr, len, nullptr));
|
|
340
325
|
}
|
|
341
326
|
|
|
342
327
|
*out_str16 = buf.ptr;
|
|
@@ -391,17 +376,16 @@ Size CallData::PushString32Value(napi_value value, const char32_t **out_str32)
|
|
|
391
376
|
return j;
|
|
392
377
|
}
|
|
393
378
|
|
|
394
|
-
static
|
|
379
|
+
static FORCE_INLINE napi_value GetMemberValue(napi_env env, napi_value obj, const RecordMember &member)
|
|
395
380
|
{
|
|
396
|
-
napi_value value
|
|
381
|
+
napi_value value;
|
|
397
382
|
|
|
398
383
|
if (member.key) {
|
|
399
|
-
napi_value key
|
|
400
|
-
napi_get_reference_value(env, member.key, &key);
|
|
401
|
-
|
|
402
|
-
napi_get_property(env, obj, key, &value);
|
|
384
|
+
napi_value key;
|
|
385
|
+
NAPI_OK(napi_get_reference_value(env, member.key, &key));
|
|
386
|
+
NAPI_OK(napi_get_property(env, obj, key, &value));
|
|
403
387
|
} else {
|
|
404
|
-
napi_get_named_property(env, obj, member.name, &value);
|
|
388
|
+
NAPI_OK(napi_get_named_property(env, obj, member.name, &value));
|
|
405
389
|
}
|
|
406
390
|
|
|
407
391
|
return value;
|
|
@@ -409,10 +393,14 @@ static inline napi_value GetMemberValue(napi_env env, napi_value obj, const Reco
|
|
|
409
393
|
|
|
410
394
|
bool CallData::PushObject(napi_value obj, const TypeInfo *type, uint8_t *origin)
|
|
411
395
|
{
|
|
412
|
-
K_ASSERT(IsObject(env, obj));
|
|
413
396
|
K_ASSERT(type->primitive == PrimitiveKind::Record ||
|
|
414
397
|
type->primitive == PrimitiveKind::Union);
|
|
415
398
|
|
|
399
|
+
if (GetKindOf(env, obj) != napi_object) [[unlikely]] {
|
|
400
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, obj));
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
|
|
416
404
|
Span<const RecordMember> members = type->members;
|
|
417
405
|
|
|
418
406
|
if (type->primitive == PrimitiveKind::Union) {
|
|
@@ -562,12 +550,7 @@ bool CallData::PushObject(napi_value obj, const TypeInfo *type, uint8_t *origin)
|
|
|
562
550
|
} break;
|
|
563
551
|
case PrimitiveKind::Record:
|
|
564
552
|
case PrimitiveKind::Union: {
|
|
565
|
-
if (!
|
|
566
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
567
|
-
return false;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
if (!PushObject(value, member.type, dest))
|
|
553
|
+
if (!PushObject(value, member.type, dest)) [[unlikely]]
|
|
571
554
|
return false;
|
|
572
555
|
} break;
|
|
573
556
|
case PrimitiveKind::Array: {
|
|
@@ -652,7 +635,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
652
635
|
#define PUSH_ARRAY(SetCode) \
|
|
653
636
|
do { \
|
|
654
637
|
for (Size i = 0; i < len; i++) { \
|
|
655
|
-
|
|
638
|
+
napi_value value = array[(uint32_t)i].AsValue(); \
|
|
656
639
|
\
|
|
657
640
|
uint8_t *dest = origin + offset; \
|
|
658
641
|
SetCode \
|
|
@@ -744,11 +727,6 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
744
727
|
} break;
|
|
745
728
|
case PrimitiveKind::Pointer: {
|
|
746
729
|
PUSH_ARRAY({
|
|
747
|
-
if (!IsObject(env, value)) [[unlikely]] {
|
|
748
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
749
|
-
return false;
|
|
750
|
-
}
|
|
751
|
-
|
|
752
730
|
void *ptr;
|
|
753
731
|
if (!PushPointer(value, ref, 1, &ptr)) [[unlikely]]
|
|
754
732
|
return false;
|
|
@@ -759,28 +737,23 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
759
737
|
case PrimitiveKind::Record:
|
|
760
738
|
case PrimitiveKind::Union: {
|
|
761
739
|
PUSH_ARRAY({
|
|
762
|
-
if (!
|
|
763
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
764
|
-
return false;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
if (!PushObject(value, ref, dest))
|
|
740
|
+
if (!PushObject(value, ref, dest)) [[unlikely]]
|
|
768
741
|
return false;
|
|
769
742
|
});
|
|
770
743
|
} break;
|
|
771
744
|
case PrimitiveKind::Array: {
|
|
772
745
|
for (Size i = 0; i < len; i++) {
|
|
773
|
-
|
|
746
|
+
napi_value value = array[(uint32_t)i].AsValue();
|
|
774
747
|
|
|
775
748
|
uint8_t *dest = origin + offset;
|
|
776
749
|
|
|
777
|
-
if (
|
|
778
|
-
Napi::Array
|
|
779
|
-
if (!PushNormalArray(
|
|
750
|
+
if (IsArray(env, value)) {
|
|
751
|
+
Napi::Array array = Napi::Array(env, value);
|
|
752
|
+
if (!PushNormalArray(array, ref, (Size)ref->size, dest))
|
|
780
753
|
return false;
|
|
781
754
|
} else if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
|
|
782
755
|
PushBuffer(buffer, ref, dest);
|
|
783
|
-
} else if (value
|
|
756
|
+
} else if (GetKindOf(env, value) == napi_string) {
|
|
784
757
|
if (!PushStringArray(value, ref, dest))
|
|
785
758
|
return false;
|
|
786
759
|
} else {
|
|
@@ -814,19 +787,13 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
814
787
|
});
|
|
815
788
|
} break;
|
|
816
789
|
case PrimitiveKind::Callback: {
|
|
817
|
-
|
|
818
|
-
Napi::Value value = array[(uint32_t)i];
|
|
819
|
-
|
|
820
|
-
uint8_t *dest = origin + offset;
|
|
821
|
-
|
|
790
|
+
PUSH_ARRAY({
|
|
822
791
|
void *ptr;
|
|
823
792
|
if (!PushCallback(value, ref, &ptr))
|
|
824
793
|
return false;
|
|
825
794
|
|
|
826
|
-
*(void **)dest = ptr;
|
|
827
|
-
|
|
828
|
-
offset += stride;
|
|
829
|
-
}
|
|
795
|
+
*(const void **)dest = ptr;
|
|
796
|
+
});
|
|
830
797
|
} break;
|
|
831
798
|
|
|
832
799
|
case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
|
|
@@ -893,14 +860,9 @@ bool CallData::PushStringArray(napi_value value, const TypeInfo *type, uint8_t *
|
|
|
893
860
|
size_t encoded = 0;
|
|
894
861
|
|
|
895
862
|
switch (type->ref.type->primitive) {
|
|
896
|
-
case PrimitiveKind::Int8: {
|
|
897
|
-
napi_status status = napi_get_value_string_utf8(env, value, (char *)origin, type->size, &encoded);
|
|
898
|
-
K_ASSERT(status == napi_ok);
|
|
899
|
-
} break;
|
|
863
|
+
case PrimitiveKind::Int8: { NAPI_OK(napi_get_value_string_utf8(env, value, (char *)origin, type->size, &encoded)); } break;
|
|
900
864
|
case PrimitiveKind::Int16: {
|
|
901
|
-
|
|
902
|
-
K_ASSERT(status == napi_ok);
|
|
903
|
-
|
|
865
|
+
NAPI_OK(napi_get_value_string_utf16(env, value, (char16_t *)origin, type->size / 2, &encoded));
|
|
904
866
|
encoded *= 2;
|
|
905
867
|
} break;
|
|
906
868
|
|
|
@@ -933,7 +895,7 @@ restart:
|
|
|
933
895
|
Napi::External<ValueCast> external = Napi::External<ValueCast>(env, value);
|
|
934
896
|
ValueCast *cast = external.Data();
|
|
935
897
|
|
|
936
|
-
napi_get_reference_value(env, cast->ref, &value);
|
|
898
|
+
NAPI_OK(napi_get_reference_value(env, cast->ref, &value));
|
|
937
899
|
type = cast->type;
|
|
938
900
|
|
|
939
901
|
goto restart;
|
|
@@ -1029,8 +991,7 @@ bool CallData::PushPointerSlow(napi_value value, napi_valuetype kind, const Type
|
|
|
1029
991
|
if (directions & 2) {
|
|
1030
992
|
OutArgument *out = out_arguments.AppendDefault();
|
|
1031
993
|
|
|
1032
|
-
|
|
1033
|
-
K_ASSERT(status == napi_ok);
|
|
994
|
+
NAPI_OK(napi_create_reference(env, value, 1, &out->ref));
|
|
1034
995
|
|
|
1035
996
|
out->kind = out_kind;
|
|
1036
997
|
out->ptr = (const uint8_t *)ptr;
|
|
@@ -1042,8 +1003,6 @@ bool CallData::PushPointerSlow(napi_value value, napi_valuetype kind, const Type
|
|
|
1042
1003
|
return true;
|
|
1043
1004
|
} else if (ref->primitive == PrimitiveKind::Record ||
|
|
1044
1005
|
ref->primitive == PrimitiveKind::Union) [[likely]] {
|
|
1045
|
-
K_ASSERT(IsObject(env, value));
|
|
1046
|
-
|
|
1047
1006
|
ptr = (void *)AllocHeap(ref->size);
|
|
1048
1007
|
|
|
1049
1008
|
if (ref->primitive == PrimitiveKind::Union &&
|
|
@@ -1053,17 +1012,19 @@ bool CallData::PushPointerSlow(napi_value value, napi_valuetype kind, const Type
|
|
|
1053
1012
|
}
|
|
1054
1013
|
|
|
1055
1014
|
if (directions & 1) {
|
|
1056
|
-
if (!PushObject(value, ref, (uint8_t *)ptr))
|
|
1015
|
+
if (!PushObject(value, ref, (uint8_t *)ptr)) [[unlikely]]
|
|
1057
1016
|
return false;
|
|
1058
1017
|
} else {
|
|
1018
|
+
if (kind != napi_object) [[unlikely]]
|
|
1019
|
+
return false;
|
|
1020
|
+
|
|
1059
1021
|
MemSet(ptr, 0, ref->size);
|
|
1060
1022
|
}
|
|
1061
1023
|
|
|
1062
1024
|
if (directions & 2) {
|
|
1063
1025
|
OutArgument *out = out_arguments.AppendDefault();
|
|
1064
1026
|
|
|
1065
|
-
|
|
1066
|
-
K_ASSERT(status == napi_ok);
|
|
1027
|
+
NAPI_OK(napi_create_reference(env, value, 1, &out->ref));
|
|
1067
1028
|
|
|
1068
1029
|
out->kind = OutArgument::Kind::Object;
|
|
1069
1030
|
out->ptr = (const uint8_t *)ptr;
|
|
@@ -1107,7 +1068,7 @@ restart:
|
|
|
1107
1068
|
Napi::External<ValueCast> external = Napi::External<ValueCast>(env, value);
|
|
1108
1069
|
ValueCast *cast = external.Data();
|
|
1109
1070
|
|
|
1110
|
-
napi_get_reference_value(env, cast->ref, &value);
|
|
1071
|
+
NAPI_OK(napi_get_reference_value(env, cast->ref, &value));
|
|
1111
1072
|
type = cast->type;
|
|
1112
1073
|
|
|
1113
1074
|
goto restart;
|
|
@@ -1132,7 +1093,7 @@ restart:
|
|
|
1132
1093
|
Napi::External<ValueCast> external = Napi::External<ValueCast>(env, value);
|
|
1133
1094
|
ValueCast *cast = external.Data();
|
|
1134
1095
|
|
|
1135
|
-
napi_get_reference_value(env, cast->ref, &value);
|
|
1096
|
+
NAPI_OK(napi_get_reference_value(env, cast->ref, &value));
|
|
1136
1097
|
type = cast->type;
|
|
1137
1098
|
|
|
1138
1099
|
goto restart;
|
|
@@ -1148,7 +1109,7 @@ Size CallData::PushIndirectString(Napi::Array array, const TypeInfo *ref, void *
|
|
|
1148
1109
|
if (array.Length() != 1)
|
|
1149
1110
|
return -1;
|
|
1150
1111
|
|
|
1151
|
-
|
|
1112
|
+
napi_value value = array[0u].AsValue();
|
|
1152
1113
|
|
|
1153
1114
|
if (ref == instance->void_type) {
|
|
1154
1115
|
return PushStringValue(value, (const char **)out_ptr);
|
|
@@ -1192,7 +1153,7 @@ void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func
|
|
|
1192
1153
|
trampoline->instance = instance;
|
|
1193
1154
|
trampoline->stack0 = instance->memories[0]->stack0;
|
|
1194
1155
|
trampoline->proto = proto;
|
|
1195
|
-
napi_create_reference(env, func, 1, &trampoline->func);
|
|
1156
|
+
NAPI_OK(napi_create_reference(env, func, 1, &trampoline->func));
|
|
1196
1157
|
|
|
1197
1158
|
void *ptr = GetTrampoline(idx);
|
|
1198
1159
|
|
|
@@ -1280,72 +1241,7 @@ void CallData::DebugForward()
|
|
|
1280
1241
|
|
|
1281
1242
|
#endif
|
|
1282
1243
|
|
|
1283
|
-
static
|
|
1284
|
-
{
|
|
1285
|
-
Napi::Value ret = env.RunScript("typeof Deno != 'undefined'");
|
|
1286
|
-
Napi::Boolean b = ret.ToBoolean();
|
|
1287
|
-
|
|
1288
|
-
return b.Value();
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
static bool DetectBun(Napi::Env env)
|
|
1292
|
-
{
|
|
1293
|
-
Napi::Value ret = env.RunScript("process.isBun");
|
|
1294
|
-
Napi::Boolean b = ret.ToBoolean();
|
|
1295
|
-
|
|
1296
|
-
return b.Value();
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
void InitTranslateZeroCall(Napi::Env env)
|
|
1300
|
-
{
|
|
1301
|
-
if (DetectDeno(env) || DetectBun(env)) {
|
|
1302
|
-
translate_zero_call = TranslateFastCall;
|
|
1303
|
-
return;
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
Napi::Object self = Napi::Object::New(env);
|
|
1307
|
-
|
|
1308
|
-
napi_status status;
|
|
1309
|
-
napi_value func;
|
|
1310
|
-
napi_value ret;
|
|
1311
|
-
|
|
1312
|
-
status = napi_create_function(env, nullptr, 0, [](napi_env env, napi_callback_info info) {
|
|
1313
|
-
napi_value self;
|
|
1314
|
-
napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr);
|
|
1315
|
-
|
|
1316
|
-
napi_value *ptr = (napi_value *)info;
|
|
1317
|
-
|
|
1318
|
-
if (ptr[0] != self && ptr[1] != self) {
|
|
1319
|
-
translate_zero_call = TranslateZeroCall;
|
|
1320
|
-
} else {
|
|
1321
|
-
translate_zero_call = TranslateFastCall;
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
return self;
|
|
1325
|
-
}, nullptr, &func);
|
|
1326
|
-
K_ASSERT(status == napi_ok);
|
|
1327
|
-
|
|
1328
|
-
status = napi_call_function(env, self, func, 0, nullptr, &ret);
|
|
1329
|
-
K_ASSERT(status == napi_ok);
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
bool InitAsyncBroker(Napi::Env env, InstanceData *instance)
|
|
1333
|
-
{
|
|
1334
|
-
if (!instance->broker) {
|
|
1335
|
-
if (napi_create_threadsafe_function(env, nullptr, nullptr,
|
|
1336
|
-
Napi::String::New(env, "Koffi Async Callback Broker"),
|
|
1337
|
-
0, 1, nullptr, nullptr, nullptr,
|
|
1338
|
-
PerformAsyncRelay, &instance->broker) != napi_ok) {
|
|
1339
|
-
LogError("Failed to create async callback broker");
|
|
1340
|
-
return false;
|
|
1341
|
-
}
|
|
1342
|
-
napi_unref_threadsafe_function(env, instance->broker);
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
return true;
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
napi_value TranslateZeroCall(napi_env env, napi_callback_info info)
|
|
1244
|
+
static napi_value TranslateZeroCall(napi_env env, napi_callback_info info)
|
|
1349
1245
|
{
|
|
1350
1246
|
struct CallbackBundle {
|
|
1351
1247
|
napi_env env;
|
|
@@ -1376,8 +1272,7 @@ napi_value TranslateFastCall(napi_env env, napi_callback_info info)
|
|
|
1376
1272
|
size_t count = 6;
|
|
1377
1273
|
FunctionInfo *func;
|
|
1378
1274
|
|
|
1379
|
-
|
|
1380
|
-
K_ASSERT(status == napi_ok);
|
|
1275
|
+
NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, (void **)&func));
|
|
1381
1276
|
|
|
1382
1277
|
if (count < (size_t)func->required_parameters) [[unlikely]] {
|
|
1383
1278
|
ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, count);
|
|
@@ -1421,7 +1316,7 @@ static FORCE_INLINE napi_value TranslateNormalCall(napi_env env, const FunctionI
|
|
|
1421
1316
|
return ret;
|
|
1422
1317
|
}
|
|
1423
1318
|
|
|
1424
|
-
napi_value TranslateNormalCall(napi_env env, napi_callback_info info)
|
|
1319
|
+
static napi_value TranslateNormalCall(napi_env env, napi_callback_info info)
|
|
1425
1320
|
{
|
|
1426
1321
|
static_assert(MaxParameters >= 8);
|
|
1427
1322
|
|
|
@@ -1429,13 +1324,10 @@ napi_value TranslateNormalCall(napi_env env, napi_callback_info info)
|
|
|
1429
1324
|
size_t count = 8;
|
|
1430
1325
|
FunctionInfo *func;
|
|
1431
1326
|
|
|
1432
|
-
|
|
1433
|
-
K_ASSERT(status == napi_ok);
|
|
1327
|
+
NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, (void **)&func));
|
|
1434
1328
|
|
|
1435
1329
|
if (count > 8) {
|
|
1436
|
-
|
|
1437
|
-
K_ASSERT(status == napi_ok);
|
|
1438
|
-
|
|
1330
|
+
NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, nullptr));
|
|
1439
1331
|
count = std::min(count, (size_t)MaxParameters);
|
|
1440
1332
|
}
|
|
1441
1333
|
|
|
@@ -1474,7 +1366,7 @@ static FORCE_INLINE napi_value TranslateNormalCallDebugAsync(napi_env env, const
|
|
|
1474
1366
|
return ret;
|
|
1475
1367
|
}
|
|
1476
1368
|
|
|
1477
|
-
napi_value TranslateNormalCallDebugAsync(napi_env env, napi_callback_info info)
|
|
1369
|
+
static napi_value TranslateNormalCallDebugAsync(napi_env env, napi_callback_info info)
|
|
1478
1370
|
{
|
|
1479
1371
|
static_assert(MaxParameters >= 8);
|
|
1480
1372
|
|
|
@@ -1482,13 +1374,10 @@ napi_value TranslateNormalCallDebugAsync(napi_env env, napi_callback_info info)
|
|
|
1482
1374
|
size_t count = 8;
|
|
1483
1375
|
FunctionInfo *func;
|
|
1484
1376
|
|
|
1485
|
-
|
|
1486
|
-
K_ASSERT(status == napi_ok);
|
|
1377
|
+
NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, (void **)&func));
|
|
1487
1378
|
|
|
1488
1379
|
if (count > 8) {
|
|
1489
|
-
|
|
1490
|
-
K_ASSERT(status == napi_ok);
|
|
1491
|
-
|
|
1380
|
+
NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, nullptr));
|
|
1492
1381
|
count = std::min(count, (size_t)MaxParameters);
|
|
1493
1382
|
}
|
|
1494
1383
|
|
|
@@ -1517,7 +1406,7 @@ static napi_value TranslateVariadicCall(napi_env env, const FunctionInfo *func,
|
|
|
1517
1406
|
|
|
1518
1407
|
for (Size i = prev->required_parameters, j = prev->required_parameters; i < (Size)count; i += 2, j++) {
|
|
1519
1408
|
int directions;
|
|
1520
|
-
const TypeInfo *type = ResolveType(
|
|
1409
|
+
const TypeInfo *type = ResolveType(instance, args[i], &directions);
|
|
1521
1410
|
|
|
1522
1411
|
if (type != prev->parameters[j].type || directions != prev->parameters[j].directions) [[unlikely]] {
|
|
1523
1412
|
match = false;
|
|
@@ -1558,7 +1447,7 @@ static napi_value TranslateVariadicCall(napi_env env, const FunctionInfo *func,
|
|
|
1558
1447
|
for (Size i = variadic->required_parameters; i < count; i += 2) {
|
|
1559
1448
|
ParameterInfo param = {};
|
|
1560
1449
|
|
|
1561
|
-
param.type = ResolveType(
|
|
1450
|
+
param.type = ResolveType(instance, args[i], ¶m.directions);
|
|
1562
1451
|
|
|
1563
1452
|
if (!param.type) [[unlikely]]
|
|
1564
1453
|
return Napi::Env(env).Null();
|
|
@@ -1599,7 +1488,7 @@ static napi_value TranslateVariadicCall(napi_env env, const FunctionInfo *func,
|
|
|
1599
1488
|
return ret;
|
|
1600
1489
|
}
|
|
1601
1490
|
|
|
1602
|
-
napi_value TranslateVariadicCall(napi_env env, napi_callback_info info)
|
|
1491
|
+
static napi_value TranslateVariadicCall(napi_env env, napi_callback_info info)
|
|
1603
1492
|
{
|
|
1604
1493
|
static_assert(MaxParameters >= 8);
|
|
1605
1494
|
|
|
@@ -1607,13 +1496,10 @@ napi_value TranslateVariadicCall(napi_env env, napi_callback_info info)
|
|
|
1607
1496
|
size_t count = 8;
|
|
1608
1497
|
FunctionInfo *func;
|
|
1609
1498
|
|
|
1610
|
-
|
|
1611
|
-
K_ASSERT(status == napi_ok);
|
|
1499
|
+
NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, (void **)&func));
|
|
1612
1500
|
|
|
1613
1501
|
if (count > 8) {
|
|
1614
|
-
|
|
1615
|
-
K_ASSERT(status == napi_ok);
|
|
1616
|
-
|
|
1502
|
+
NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, nullptr));
|
|
1617
1503
|
count = std::min(count, (size_t)MaxParameters);
|
|
1618
1504
|
}
|
|
1619
1505
|
|
|
@@ -1695,7 +1581,7 @@ void AsyncCall::OnError(const Napi::Error& err)
|
|
|
1695
1581
|
callback.Call(self, K_LEN(args), args);
|
|
1696
1582
|
}
|
|
1697
1583
|
|
|
1698
|
-
napi_value TranslateAsyncCall(napi_env env, napi_callback_info info)
|
|
1584
|
+
static napi_value TranslateAsyncCall(napi_env env, napi_callback_info info)
|
|
1699
1585
|
{
|
|
1700
1586
|
static_assert(MaxParameters >= 6);
|
|
1701
1587
|
|
|
@@ -1703,13 +1589,10 @@ napi_value TranslateAsyncCall(napi_env env, napi_callback_info info)
|
|
|
1703
1589
|
size_t count = 6;
|
|
1704
1590
|
FunctionInfo *func;
|
|
1705
1591
|
|
|
1706
|
-
|
|
1707
|
-
K_ASSERT(status == napi_ok);
|
|
1592
|
+
NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, (void **)&func));
|
|
1708
1593
|
|
|
1709
1594
|
if (count > 6) {
|
|
1710
|
-
|
|
1711
|
-
K_ASSERT(status == napi_ok);
|
|
1712
|
-
|
|
1595
|
+
NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, nullptr));
|
|
1713
1596
|
count = std::min(count, (size_t)MaxParameters);
|
|
1714
1597
|
}
|
|
1715
1598
|
|
|
@@ -1740,6 +1623,215 @@ napi_value TranslateAsyncCall(napi_env env, napi_callback_info info)
|
|
|
1740
1623
|
return Napi::Env(env).Undefined();
|
|
1741
1624
|
}
|
|
1742
1625
|
|
|
1626
|
+
static bool DetectDeno(Napi::Env env)
|
|
1627
|
+
{
|
|
1628
|
+
Napi::Value ret = env.RunScript("typeof Deno != 'undefined'");
|
|
1629
|
+
Napi::Boolean b = ret.ToBoolean();
|
|
1630
|
+
|
|
1631
|
+
return b.Value();
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
static bool DetectBun(Napi::Env env)
|
|
1635
|
+
{
|
|
1636
|
+
Napi::Value ret = env.RunScript("process.isBun");
|
|
1637
|
+
Napi::Boolean b = ret.ToBoolean();
|
|
1638
|
+
|
|
1639
|
+
return b.Value();
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
void InitTranslateZeroCall(Napi::Env env)
|
|
1643
|
+
{
|
|
1644
|
+
if (DetectDeno(env) || DetectBun(env)) {
|
|
1645
|
+
translate_zero_call = TranslateFastCall;
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
Napi::Object self = Napi::Object::New(env);
|
|
1650
|
+
|
|
1651
|
+
napi_value func;
|
|
1652
|
+
napi_value ret;
|
|
1653
|
+
|
|
1654
|
+
auto cb = [](napi_env env, napi_callback_info info) {
|
|
1655
|
+
napi_value self;
|
|
1656
|
+
NAPI_OK(napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
|
|
1657
|
+
|
|
1658
|
+
napi_value *ptr = (napi_value *)info;
|
|
1659
|
+
|
|
1660
|
+
if (ptr[0] != self && ptr[1] != self) {
|
|
1661
|
+
translate_zero_call = TranslateZeroCall;
|
|
1662
|
+
} else {
|
|
1663
|
+
translate_zero_call = TranslateFastCall;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
return self;
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1669
|
+
NAPI_OK(napi_create_function(env, nullptr, 0, cb, nullptr, &func));
|
|
1670
|
+
NAPI_OK(napi_call_function(env, self, func, 0, nullptr, &ret));
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
napi_value CallPointer(Napi::Env env, const FunctionInfo *proto, void *native, napi_value *args, Size count)
|
|
1674
|
+
{
|
|
1675
|
+
if (proto->variadic) {
|
|
1676
|
+
return TranslateVariadicCall(env, proto, native, args, count);
|
|
1677
|
+
} else {
|
|
1678
|
+
return TranslateNormalCall(env, proto, native, args, count);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
static void PerformAsyncRelay(napi_env, napi_value, void *, void *udata)
|
|
1683
|
+
{
|
|
1684
|
+
RelayContext *ctx = (RelayContext *)udata;
|
|
1685
|
+
CallData *call = ctx->call;
|
|
1686
|
+
|
|
1687
|
+
call->Relay(ctx->idx, ctx->sp);
|
|
1688
|
+
call->Finalize();
|
|
1689
|
+
|
|
1690
|
+
// We're done!
|
|
1691
|
+
std::lock_guard<std::mutex> lock(ctx->mutex);
|
|
1692
|
+
ctx->done = true;
|
|
1693
|
+
ctx->cv.notify_one();
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
bool InitAsyncBroker(Napi::Env env, InstanceData *instance)
|
|
1697
|
+
{
|
|
1698
|
+
if (!instance->broker) {
|
|
1699
|
+
if (napi_create_threadsafe_function(env, nullptr, nullptr,
|
|
1700
|
+
NewString(env, "Koffi Async Callback Broker"),
|
|
1701
|
+
0, 1, nullptr, nullptr, nullptr,
|
|
1702
|
+
PerformAsyncRelay, &instance->broker) != napi_ok) {
|
|
1703
|
+
LogError("Failed to create async callback broker");
|
|
1704
|
+
return false;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
NAPI_OK(napi_unref_threadsafe_function(env, instance->broker));
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
return true;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
void *GetTrampoline(int idx)
|
|
1714
|
+
{
|
|
1715
|
+
return (void *)(TrampolineStart + TrampolineSize * idx);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
static bool CanTypeAcceptCallbacks(const TypeInfo *type)
|
|
1719
|
+
{
|
|
1720
|
+
if (type->primitive == PrimitiveKind::Pointer)
|
|
1721
|
+
return true;
|
|
1722
|
+
if (type->primitive == PrimitiveKind::Callback)
|
|
1723
|
+
return true;
|
|
1724
|
+
|
|
1725
|
+
if (type->primitive == PrimitiveKind::Record ||
|
|
1726
|
+
type->primitive == PrimitiveKind::Union) {
|
|
1727
|
+
for (const RecordMember &member: type->members) {
|
|
1728
|
+
if (CanTypeAcceptCallbacks(member.type))
|
|
1729
|
+
return false;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
return true;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
static bool CanUseFastCall(const FunctionInfo *func)
|
|
1737
|
+
{
|
|
1738
|
+
if (func->parameters.len > 6)
|
|
1739
|
+
return false;
|
|
1740
|
+
|
|
1741
|
+
// Fast calls basically skip CallData::Finalize(), which handles output arguments
|
|
1742
|
+
// and temporary callback trampolines. If the function does not use any
|
|
1743
|
+
// output argument and cannot accept callbacks (so no pointer or callback arguments),
|
|
1744
|
+
// we can skip finalization!
|
|
1745
|
+
|
|
1746
|
+
for (const ParameterInfo ¶m: func->parameters) {
|
|
1747
|
+
if (param.directions & 2)
|
|
1748
|
+
return false;
|
|
1749
|
+
if (CanTypeAcceptCallbacks(param.type))
|
|
1750
|
+
return false;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
return true;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
napi_value DescribeFunction(InstanceData *instance, const FunctionInfo *func)
|
|
1757
|
+
{
|
|
1758
|
+
static const char *const DirectionNames[] = {
|
|
1759
|
+
nullptr,
|
|
1760
|
+
"Input",
|
|
1761
|
+
"Output",
|
|
1762
|
+
"Input/Output"
|
|
1763
|
+
};
|
|
1764
|
+
|
|
1765
|
+
Napi::Env env = instance->env;
|
|
1766
|
+
|
|
1767
|
+
Napi::Object meta = Napi::Object::New(env);
|
|
1768
|
+
Napi::Array arguments = Napi::Array::New(env, func->parameters.len);
|
|
1769
|
+
|
|
1770
|
+
meta.Set("name", NewString(env, func->name));
|
|
1771
|
+
meta.Set("arguments", arguments);
|
|
1772
|
+
meta.Set("result", WrapType(instance, func->ret.type));
|
|
1773
|
+
|
|
1774
|
+
for (Size i = 0; i < func->parameters.len; i++) {
|
|
1775
|
+
const ParameterInfo ¶m = func->parameters[i];
|
|
1776
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
1777
|
+
|
|
1778
|
+
obj.Set("type", WrapType(instance, param.type));
|
|
1779
|
+
obj.Set("direction", NewString(env, DirectionNames[param.directions]));
|
|
1780
|
+
|
|
1781
|
+
arguments.Set((uint32_t)i, obj);
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
meta.Freeze();
|
|
1785
|
+
|
|
1786
|
+
return meta;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
static bool IsDebugAsyncEnabled()
|
|
1790
|
+
{
|
|
1791
|
+
static bool debug = GetDebugFlag("DEBUG_ASYNC");
|
|
1792
|
+
return debug;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
napi_value WrapFunction(InstanceData *instance, const FunctionInfo *func)
|
|
1796
|
+
{
|
|
1797
|
+
Napi::Env env = instance->env;
|
|
1798
|
+
|
|
1799
|
+
Napi::Function wrapper;
|
|
1800
|
+
{
|
|
1801
|
+
napi_value value;
|
|
1802
|
+
|
|
1803
|
+
if (func->variadic) {
|
|
1804
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateVariadicCall, (void *)func->Ref(), &value));
|
|
1805
|
+
} else if (IsDebugAsyncEnabled()) {
|
|
1806
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCallDebugAsync, (void *)func->Ref(), &value));
|
|
1807
|
+
} else if (!func->parameters.len) {
|
|
1808
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, translate_zero_call, (void *)func->Ref(), &value));
|
|
1809
|
+
} else if (CanUseFastCall(func)) {
|
|
1810
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateFastCall, (void *)func->Ref(), &value));
|
|
1811
|
+
} else {
|
|
1812
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCall, (void *)func->Ref(), &value));
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
wrapper = Napi::Function(env, value);
|
|
1816
|
+
wrapper.AddFinalizer([](Napi::BasicEnv, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
if (!func->variadic) {
|
|
1820
|
+
napi_value value;
|
|
1821
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateAsyncCall, (void *)func->Ref(), &value));
|
|
1822
|
+
|
|
1823
|
+
Napi::Function async = Napi::Function(env, value);
|
|
1824
|
+
async.AddFinalizer([](Napi::BasicEnv, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
|
|
1825
|
+
|
|
1826
|
+
wrapper.Set("async", async);
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
napi_value meta = DescribeFunction(instance, func);
|
|
1830
|
+
wrapper.Set("info", meta);
|
|
1831
|
+
|
|
1832
|
+
return wrapper;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1743
1835
|
static FORCE_INLINE bool CheckTrampolineStatus(TrampolineInfo *trampoline)
|
|
1744
1836
|
{
|
|
1745
1837
|
if (trampoline->state == 1) [[likely]]
|
|
@@ -1800,7 +1892,7 @@ extern "C" void RelayCallback(Size idx, uint8_t *sp)
|
|
|
1800
1892
|
K_DEFER { call.Finalize(); };
|
|
1801
1893
|
|
|
1802
1894
|
napi_handle_scope scope;
|
|
1803
|
-
napi_open_handle_scope(env, &scope);
|
|
1895
|
+
NAPI_OK(napi_open_handle_scope(env, &scope));
|
|
1804
1896
|
K_DEFER { napi_close_handle_scope(env, scope); };
|
|
1805
1897
|
|
|
1806
1898
|
call.Relay(idx, sp);
|
|
@@ -1839,39 +1931,164 @@ extern "C" void RelayDirect(CallData *call, Size idx, uint8_t *sp)
|
|
|
1839
1931
|
// Relay the call
|
|
1840
1932
|
{
|
|
1841
1933
|
napi_handle_scope scope;
|
|
1842
|
-
napi_open_handle_scope(call->env, &scope);
|
|
1934
|
+
NAPI_OK(napi_open_handle_scope(call->env, &scope));
|
|
1843
1935
|
K_DEFER { napi_close_handle_scope(call->env, scope); };
|
|
1844
1936
|
|
|
1845
1937
|
call->Relay(idx, sp);
|
|
1846
1938
|
}
|
|
1847
1939
|
}
|
|
1848
1940
|
|
|
1849
|
-
|
|
1941
|
+
bool Encode(InstanceData *instance, uint8_t *origin, napi_value value, const TypeInfo *type)
|
|
1850
1942
|
{
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1943
|
+
Napi::Env env = instance->env;
|
|
1944
|
+
|
|
1945
|
+
InstanceMemory mem = {};
|
|
1946
|
+
CallData call(env, instance, &mem, nullptr);
|
|
1947
|
+
|
|
1948
|
+
#define PUSH_INTEGER(CType) \
|
|
1949
|
+
do { \
|
|
1950
|
+
CType v; \
|
|
1951
|
+
if (!TryNumber(env, value, &v)) [[unlikely]] { \
|
|
1952
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
1953
|
+
return false; \
|
|
1954
|
+
} \
|
|
1955
|
+
\
|
|
1956
|
+
*(CType *)origin = v; \
|
|
1957
|
+
} while (false)
|
|
1958
|
+
#define PUSH_INTEGER_SWAP(CType) \
|
|
1959
|
+
do { \
|
|
1960
|
+
CType v; \
|
|
1961
|
+
if (!TryNumber(env, value, &v)) [[unlikely]] { \
|
|
1962
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
1963
|
+
return false; \
|
|
1964
|
+
} \
|
|
1965
|
+
\
|
|
1966
|
+
*(CType *)origin = ReverseBytes(v); \
|
|
1967
|
+
} while (false)
|
|
1968
|
+
|
|
1969
|
+
switch (type->primitive) {
|
|
1970
|
+
case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
|
|
1971
|
+
|
|
1972
|
+
case PrimitiveKind::Bool: {
|
|
1973
|
+
bool b;
|
|
1974
|
+
napi_status status = napi_get_value_bool(env, value, &b);
|
|
1975
|
+
|
|
1976
|
+
if (status != napi_ok) [[unlikely]] {
|
|
1977
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
|
|
1978
|
+
return false;
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
*(bool *)origin = b;
|
|
1982
|
+
} break;
|
|
1983
|
+
case PrimitiveKind::Int8: { PUSH_INTEGER(int8_t); } break;
|
|
1984
|
+
case PrimitiveKind::UInt8: { PUSH_INTEGER(uint8_t); } break;
|
|
1985
|
+
case PrimitiveKind::Int16: { PUSH_INTEGER(int16_t); } break;
|
|
1986
|
+
case PrimitiveKind::Int16S: { PUSH_INTEGER_SWAP(int16_t); } break;
|
|
1987
|
+
case PrimitiveKind::UInt16: { PUSH_INTEGER(uint16_t); } break;
|
|
1988
|
+
case PrimitiveKind::UInt16S: { PUSH_INTEGER_SWAP(uint16_t); } break;
|
|
1989
|
+
case PrimitiveKind::Int32: { PUSH_INTEGER(int32_t); } break;
|
|
1990
|
+
case PrimitiveKind::Int32S: { PUSH_INTEGER_SWAP(int32_t); } break;
|
|
1991
|
+
case PrimitiveKind::UInt32: { PUSH_INTEGER(uint32_t); } break;
|
|
1992
|
+
case PrimitiveKind::UInt32S: { PUSH_INTEGER_SWAP(uint32_t); } break;
|
|
1993
|
+
case PrimitiveKind::Int64: { PUSH_INTEGER(int64_t); } break;
|
|
1994
|
+
case PrimitiveKind::Int64S: { PUSH_INTEGER_SWAP(int64_t); } break;
|
|
1995
|
+
case PrimitiveKind::UInt64: { PUSH_INTEGER(uint64_t); } break;
|
|
1996
|
+
case PrimitiveKind::UInt64S: { PUSH_INTEGER_SWAP(uint64_t); } break;
|
|
1997
|
+
case PrimitiveKind::String: {
|
|
1998
|
+
const char *str;
|
|
1999
|
+
if (!call.PushString(value, 1, &str)) [[unlikely]]
|
|
2000
|
+
return false;
|
|
2001
|
+
*(const char **)origin = str;
|
|
2002
|
+
} break;
|
|
2003
|
+
case PrimitiveKind::String16: {
|
|
2004
|
+
const char16_t *str16;
|
|
2005
|
+
if (!call.PushString16(value, 1, &str16)) [[unlikely]]
|
|
2006
|
+
return false;
|
|
2007
|
+
*(const char16_t **)origin = str16;
|
|
2008
|
+
} break;
|
|
2009
|
+
case PrimitiveKind::String32: {
|
|
2010
|
+
const char32_t *str32;
|
|
2011
|
+
if (!call.PushString32(value, 1, &str32)) [[unlikely]]
|
|
2012
|
+
return false;
|
|
2013
|
+
*(const char32_t **)origin = str32;
|
|
2014
|
+
} break;
|
|
2015
|
+
case PrimitiveKind::Pointer: {
|
|
2016
|
+
void *ptr;
|
|
2017
|
+
if (!call.PushPointer(value, type, 1, &ptr)) [[unlikely]]
|
|
2018
|
+
return false;
|
|
2019
|
+
*(void **)origin = ptr;
|
|
2020
|
+
} break;
|
|
2021
|
+
case PrimitiveKind::Record:
|
|
2022
|
+
case PrimitiveKind::Union: {
|
|
2023
|
+
if (!call.PushObject(value, type, origin)) [[unlikely]]
|
|
2024
|
+
return false;
|
|
2025
|
+
} break;
|
|
2026
|
+
case PrimitiveKind::Array: {
|
|
2027
|
+
if (IsArray(env, value)) {
|
|
2028
|
+
Napi::Array array = Napi::Array(env, value);
|
|
2029
|
+
if (!call.PushNormalArray(array, type, type->size, origin))
|
|
2030
|
+
return false;
|
|
2031
|
+
} else if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
|
|
2032
|
+
call.PushBuffer(buffer, type, origin);
|
|
2033
|
+
} else if (GetKindOf(env, value) == napi_string) {
|
|
2034
|
+
if (!call.PushStringArray(value, type, origin))
|
|
2035
|
+
return false;
|
|
2036
|
+
} else {
|
|
2037
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected array", GetValueType(instance, value));
|
|
2038
|
+
return false;
|
|
2039
|
+
}
|
|
2040
|
+
} break;
|
|
2041
|
+
case PrimitiveKind::Float32: {
|
|
2042
|
+
float f;
|
|
2043
|
+
if (!TryNumber(env, value, &f)) [[unlikely]] {
|
|
2044
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
2045
|
+
return false;
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
memcpy(origin, &f, 4);
|
|
2049
|
+
} break;
|
|
2050
|
+
case PrimitiveKind::Float64: {
|
|
2051
|
+
double d;
|
|
2052
|
+
if (!TryNumber(env, value, &d)) [[unlikely]] {
|
|
2053
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
2054
|
+
return false;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
memcpy(origin, &d, 8);
|
|
2058
|
+
} break;
|
|
2059
|
+
case PrimitiveKind::Callback: {
|
|
2060
|
+
void *ptr;
|
|
2061
|
+
if (!TryPointer(env, value, &ptr)) [[unlikely]] {
|
|
2062
|
+
if (GetKindOf(env, value) == napi_function) {
|
|
2063
|
+
ThrowError<Napi::Error>(env, "Cannot encode non-registered callback");
|
|
2064
|
+
} else {
|
|
2065
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
|
|
2066
|
+
}
|
|
2067
|
+
return false;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
*(void **)origin = ptr;
|
|
2071
|
+
} break;
|
|
2072
|
+
|
|
2073
|
+
case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
|
|
1855
2074
|
}
|
|
1856
|
-
}
|
|
1857
2075
|
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
RelayContext *ctx = (RelayContext *)udata;
|
|
1861
|
-
CallData *call = ctx->call;
|
|
2076
|
+
#undef PUSH_INTEGER_SWAP
|
|
2077
|
+
#undef PUSH_INTEGER
|
|
1862
2078
|
|
|
1863
|
-
|
|
1864
|
-
|
|
2079
|
+
// Keep memory around if any was allocated
|
|
2080
|
+
if (mem.allocator.IsUsed()) {
|
|
2081
|
+
LinkedAllocator *copy = instance->encode_map.FindValue(origin, nullptr);
|
|
1865
2082
|
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
}
|
|
2083
|
+
if (!copy) {
|
|
2084
|
+
copy = instance->encode_allocators.AppendDefault();
|
|
2085
|
+
instance->encode_map.Set(origin, copy);
|
|
2086
|
+
}
|
|
1871
2087
|
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
2088
|
+
std::swap(mem.allocator, *copy);
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
return true;
|
|
1875
2092
|
}
|
|
1876
2093
|
|
|
1877
2094
|
}
|