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/call.cc
CHANGED
|
@@ -21,37 +21,108 @@ struct RelayContext {
|
|
|
21
21
|
bool done = false;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
#if defined(_WIN32)
|
|
25
|
+
|
|
24
26
|
extern "C" void *FindTrampolineStart();
|
|
25
27
|
extern "C" void *FindTrampolineEnd();
|
|
26
28
|
|
|
27
29
|
static const uint8_t *TrampolineStart = (const uint8_t *)FindTrampolineStart();
|
|
28
30
|
static const Size TrampolineSize = ((const uint8_t *)FindTrampolineEnd() - TrampolineStart) / MaxTrampolines;
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
: env(env), instance(instance),
|
|
32
|
-
mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
|
|
33
|
-
{
|
|
34
|
-
mem->depth++;
|
|
32
|
+
#else
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
extern "C" uint8_t Trampoline0;
|
|
35
|
+
extern "C" uint8_t TrampolineEnd;
|
|
38
36
|
|
|
37
|
+
static const uint8_t *TrampolineStart = (const uint8_t *)&Trampoline0;
|
|
38
|
+
static const Size TrampolineSize = ((const uint8_t *)&TrampolineEnd - TrampolineStart) / MaxTrampolines;
|
|
39
|
+
|
|
40
|
+
#endif
|
|
41
|
+
|
|
42
|
+
#if defined(K_DEBUG)
|
|
39
43
|
CallData::~CallData()
|
|
40
44
|
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
K_ASSERT(mem->stack.end == prev_stack);
|
|
46
|
+
K_ASSERT(mem->heap.ptr == prev_heap);
|
|
47
|
+
K_ASSERT(!out_arguments.len);
|
|
48
|
+
K_ASSERT(!used_trampolines.len);
|
|
45
49
|
}
|
|
50
|
+
#endif
|
|
46
51
|
|
|
47
|
-
void CallData::
|
|
52
|
+
void CallData::Finalize()
|
|
48
53
|
{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
FinalizeFast();
|
|
55
|
+
|
|
56
|
+
if (out_arguments.len) {
|
|
57
|
+
if (!env.IsExceptionPending()) {
|
|
58
|
+
for (const OutArgument &out: out_arguments) {
|
|
59
|
+
napi_value value = GetReferenceValue(env, out.ref);
|
|
60
|
+
|
|
61
|
+
switch (out.kind) {
|
|
62
|
+
case OutArgument::Kind::Array: {
|
|
63
|
+
K_ASSERT(IsArray(env, value));
|
|
64
|
+
|
|
65
|
+
uint32_t len = GetArrayLength(env, value);
|
|
66
|
+
DecodeElements(env, value, out.ptr, out.type, len);
|
|
67
|
+
} break;
|
|
68
|
+
|
|
69
|
+
case OutArgument::Kind::Buffer: {
|
|
70
|
+
Span<uint8_t> buffer;
|
|
71
|
+
|
|
72
|
+
bool success = TryBuffer(env, value, &buffer);
|
|
73
|
+
K_ASSERT(success);
|
|
74
|
+
|
|
75
|
+
DecodeBuffer(buffer, out.ptr, out.type);
|
|
76
|
+
} break;
|
|
77
|
+
|
|
78
|
+
case OutArgument::Kind::String: {
|
|
79
|
+
K_ASSERT(IsArray(env, value));
|
|
80
|
+
K_ASSERT(GetArrayLength(env, value) == 1);
|
|
81
|
+
|
|
82
|
+
Size len = strnlen((const char *)out.ptr, out.max_len);
|
|
83
|
+
Napi::String str = Napi::String::New(env, (const char *)out.ptr, len);
|
|
84
|
+
|
|
85
|
+
napi_set_element(env, value, 0, str);
|
|
86
|
+
} break;
|
|
87
|
+
|
|
88
|
+
case OutArgument::Kind::String16: {
|
|
89
|
+
K_ASSERT(IsArray(env, value));
|
|
90
|
+
K_ASSERT(GetArrayLength(env, value) == 1);
|
|
91
|
+
|
|
92
|
+
Size len = NullTerminatedLength((const char16_t *)out.ptr, out.max_len);
|
|
93
|
+
Napi::String str = Napi::String::New(env, (const char16_t *)out.ptr, len);
|
|
94
|
+
|
|
95
|
+
napi_set_element(env, value, 0, str);
|
|
96
|
+
} break;
|
|
97
|
+
|
|
98
|
+
case OutArgument::Kind::String32: {
|
|
99
|
+
K_ASSERT(IsArray(env, value));
|
|
100
|
+
K_ASSERT(GetArrayLength(env, value) == 1);
|
|
101
|
+
|
|
102
|
+
Size len = NullTerminatedLength((const char32_t *)out.ptr, out.max_len);
|
|
103
|
+
Napi::String str = MakeStringFromUTF32(env, (const char32_t *)out.ptr, len);
|
|
52
104
|
|
|
53
|
-
|
|
54
|
-
|
|
105
|
+
napi_set_element(env, value, 0, str);
|
|
106
|
+
} break;
|
|
107
|
+
|
|
108
|
+
case OutArgument::Kind::Object: {
|
|
109
|
+
if (CheckValueTag(env, value, &UnionClassMarker)) {
|
|
110
|
+
Napi::Object obj = Napi::Object(env, value);
|
|
111
|
+
|
|
112
|
+
UnionClass *u = UnionClass::Unwrap(obj);
|
|
113
|
+
u->SetRaw(out.ptr);
|
|
114
|
+
} else {
|
|
115
|
+
DecodeObject(env, value, out.ptr, out.type);
|
|
116
|
+
}
|
|
117
|
+
} break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const OutArgument &out: out_arguments) {
|
|
123
|
+
napi_delete_reference(env, out.ref);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
55
126
|
|
|
56
127
|
if (used_trampolines.len) {
|
|
57
128
|
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
@@ -63,17 +134,37 @@ void CallData::Dispose()
|
|
|
63
134
|
K_ASSERT(trampoline->instance == instance);
|
|
64
135
|
K_ASSERT(!trampoline->func.IsEmpty());
|
|
65
136
|
|
|
137
|
+
trampoline->state = 0;
|
|
66
138
|
trampoline->func.Reset();
|
|
67
139
|
trampoline->recv.Reset();
|
|
68
|
-
trampoline->used = false;
|
|
69
140
|
|
|
70
141
|
shared.available.Append(idx);
|
|
71
142
|
}
|
|
72
143
|
}
|
|
73
144
|
|
|
74
|
-
|
|
145
|
+
#if defined(K_DEBUG)
|
|
146
|
+
out_arguments.len = 0;
|
|
147
|
+
used_trampolines.len = 0;
|
|
148
|
+
#endif
|
|
149
|
+
}
|
|
75
150
|
|
|
76
|
-
|
|
151
|
+
void CallData::FinalizeFast()
|
|
152
|
+
{
|
|
153
|
+
#if defined(K_DEBUG)
|
|
154
|
+
K_ASSERT(!finalized);
|
|
155
|
+
K_DEFER { finalized = true; };
|
|
156
|
+
#endif
|
|
157
|
+
|
|
158
|
+
mem->stack.end = prev_stack;
|
|
159
|
+
mem->heap.ptr = prev_heap;
|
|
160
|
+
|
|
161
|
+
if (release_alloc) {
|
|
162
|
+
// We could check for prev_stack == mem->stack.len and call ReleaseAll() if true, but
|
|
163
|
+
// it is a virtual method. Which means it could be slow (unless devirtualized), and
|
|
164
|
+
// most of the time there's nothing to release.
|
|
165
|
+
// So instead, take note of the need to call ReleaseAll() when big chunks are allocated.
|
|
166
|
+
mem->allocator.ReleaseAll();
|
|
167
|
+
}
|
|
77
168
|
}
|
|
78
169
|
|
|
79
170
|
void CallData::RelayAsync(Size idx, uint8_t *sp)
|
|
@@ -96,77 +187,76 @@ void CallData::RelayAsync(Size idx, uint8_t *sp)
|
|
|
96
187
|
}
|
|
97
188
|
}
|
|
98
189
|
|
|
99
|
-
bool CallData::PushString(
|
|
190
|
+
bool CallData::PushString(napi_value value, int directions, const char **out_str)
|
|
100
191
|
{
|
|
101
192
|
// Fast path
|
|
102
|
-
if (value
|
|
193
|
+
if (PushStringValue(value, out_str) >= 0) {
|
|
103
194
|
if (directions & 2) [[unlikely]] {
|
|
104
195
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
|
|
105
196
|
return false;
|
|
106
197
|
}
|
|
107
198
|
|
|
108
|
-
PushStringValue(value, out_str);
|
|
109
199
|
return true;
|
|
110
200
|
}
|
|
111
201
|
|
|
112
202
|
return PushPointer(value, instance->str_type, directions, (void **)out_str);
|
|
113
203
|
}
|
|
114
204
|
|
|
115
|
-
bool CallData::PushString16(
|
|
205
|
+
bool CallData::PushString16(napi_value value, int directions, const char16_t **out_str16)
|
|
116
206
|
{
|
|
117
207
|
// Fast path
|
|
118
|
-
if (value
|
|
208
|
+
if (PushString16Value(value, out_str16) >= 0) {
|
|
119
209
|
if (directions & 2) [[unlikely]] {
|
|
120
210
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
|
|
121
211
|
return false;
|
|
122
212
|
}
|
|
123
213
|
|
|
124
|
-
PushString16Value(value, out_str16);
|
|
125
214
|
return true;
|
|
126
215
|
}
|
|
127
216
|
|
|
128
217
|
return PushPointer(value, instance->str16_type, directions, (void **)out_str16);
|
|
129
218
|
}
|
|
130
219
|
|
|
131
|
-
bool CallData::PushString32(
|
|
220
|
+
bool CallData::PushString32(napi_value value, int directions, const char32_t **out_str32)
|
|
132
221
|
{
|
|
133
222
|
// Fast path
|
|
134
|
-
if (value
|
|
223
|
+
if (PushString32Value(value, out_str32) >= 0) {
|
|
135
224
|
if (directions & 2) [[unlikely]] {
|
|
136
225
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
|
|
137
226
|
return false;
|
|
138
227
|
}
|
|
139
228
|
|
|
140
|
-
PushString32Value(value, out_str32);
|
|
141
229
|
return true;
|
|
142
230
|
}
|
|
143
231
|
|
|
144
232
|
return PushPointer(value, instance->str32_type, directions, (void **)out_str32);
|
|
145
233
|
}
|
|
146
234
|
|
|
147
|
-
Size CallData::PushStringValue(
|
|
235
|
+
Size CallData::PushStringValue(napi_value value, const char **out_str)
|
|
148
236
|
{
|
|
149
237
|
Span<char> buf;
|
|
150
238
|
size_t len = 0;
|
|
151
239
|
napi_status status;
|
|
152
240
|
|
|
153
241
|
buf.ptr = (char *)mem->heap.ptr;
|
|
154
|
-
buf.len =
|
|
242
|
+
buf.len = mem->heap.end - mem->heap.ptr;
|
|
155
243
|
|
|
156
244
|
status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
245
|
+
if (status == napi_string_expected)
|
|
246
|
+
return -1;
|
|
157
247
|
K_ASSERT(status == napi_ok);
|
|
158
248
|
|
|
159
249
|
len++;
|
|
160
250
|
|
|
161
251
|
if (len < (size_t)buf.len) [[likely]] {
|
|
162
|
-
mem->heap.ptr += (Size)len;
|
|
163
|
-
mem->heap.len -= (Size)len;
|
|
252
|
+
mem->heap.ptr += (Size)AlignLen(len, 16);
|
|
164
253
|
} else {
|
|
165
254
|
status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
|
|
166
255
|
K_ASSERT(status == napi_ok);
|
|
167
256
|
|
|
168
257
|
len++;
|
|
169
|
-
buf = AllocateSpan<char>(&
|
|
258
|
+
buf = AllocateSpan<char>(&mem->allocator, (Size)len);
|
|
259
|
+
release_alloc |= (prev_stack == mem->stack.end);
|
|
170
260
|
|
|
171
261
|
status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
172
262
|
K_ASSERT(status == napi_ok);
|
|
@@ -178,30 +268,31 @@ Size CallData::PushStringValue(Napi::Value value, const char **out_str)
|
|
|
178
268
|
return (Size)len;
|
|
179
269
|
}
|
|
180
270
|
|
|
181
|
-
Size CallData::PushString16Value(
|
|
271
|
+
Size CallData::PushString16Value(napi_value value, const char16_t **out_str16)
|
|
182
272
|
{
|
|
183
273
|
Span<char16_t> buf;
|
|
184
274
|
size_t len = 0;
|
|
185
275
|
napi_status status;
|
|
186
276
|
|
|
187
|
-
mem->heap.ptr = AlignUp(mem->heap.ptr, 2);
|
|
188
277
|
buf.ptr = (char16_t *)mem->heap.ptr;
|
|
189
|
-
buf.len =
|
|
278
|
+
buf.len = (mem->heap.end - mem->heap.ptr) / 2;
|
|
190
279
|
|
|
191
280
|
status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
281
|
+
if (status == napi_string_expected)
|
|
282
|
+
return -1;
|
|
192
283
|
K_ASSERT(status == napi_ok);
|
|
193
284
|
|
|
194
285
|
len++;
|
|
195
286
|
|
|
196
287
|
if (len < (size_t)buf.len) [[likely]] {
|
|
197
|
-
mem->heap.ptr += (Size)len * 2;
|
|
198
|
-
mem->heap.len -= (Size)len * 2;
|
|
288
|
+
mem->heap.ptr += (Size)AlignLen(len * 2, 16);
|
|
199
289
|
} else {
|
|
200
290
|
status = napi_get_value_string_utf16(env, value, nullptr, 0, &len);
|
|
201
291
|
K_ASSERT(status == napi_ok);
|
|
202
292
|
|
|
203
293
|
len++;
|
|
204
|
-
buf = AllocateSpan<char16_t>(&
|
|
294
|
+
buf = AllocateSpan<char16_t>(&mem->allocator, (Size)len);
|
|
295
|
+
release_alloc |= (prev_stack == mem->stack.end);
|
|
205
296
|
|
|
206
297
|
status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
207
298
|
K_ASSERT(status == napi_ok);
|
|
@@ -213,7 +304,7 @@ Size CallData::PushString16Value(Napi::Value value, const char16_t **out_str16)
|
|
|
213
304
|
return (Size)len;
|
|
214
305
|
}
|
|
215
306
|
|
|
216
|
-
Size CallData::PushString32Value(
|
|
307
|
+
Size CallData::PushString32Value(napi_value value, const char32_t **out_str32)
|
|
217
308
|
{
|
|
218
309
|
static const char32_t ReplacementChar = 0x0000FFFD;
|
|
219
310
|
|
|
@@ -224,15 +315,14 @@ Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
|
|
|
224
315
|
if (buf16.len < 0) [[unlikely]]
|
|
225
316
|
return -1;
|
|
226
317
|
|
|
227
|
-
mem->heap.ptr = AlignUp(mem->heap.ptr, 4);
|
|
228
318
|
buf.ptr = (char32_t *)mem->heap.ptr;
|
|
229
|
-
buf.len =
|
|
319
|
+
buf.len = (mem->heap.end - mem->heap.ptr) / 4;
|
|
230
320
|
|
|
231
321
|
if (buf16.len < buf.len) [[likely]] {
|
|
232
|
-
mem->heap.ptr += buf16.len * 4;
|
|
233
|
-
mem->heap.len -= buf16.len * 4;
|
|
322
|
+
mem->heap.ptr += AlignLen(buf16.len * 4, 16);
|
|
234
323
|
} else {
|
|
235
|
-
buf = AllocateSpan<char32_t>(&
|
|
324
|
+
buf = AllocateSpan<char32_t>(&mem->allocator, buf16.len);
|
|
325
|
+
release_alloc |= (prev_stack == mem->stack.end);
|
|
236
326
|
}
|
|
237
327
|
|
|
238
328
|
Size j = 0;
|
|
@@ -262,9 +352,25 @@ Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
|
|
|
262
352
|
return j;
|
|
263
353
|
}
|
|
264
354
|
|
|
265
|
-
|
|
355
|
+
static inline napi_value GetMemberValue(napi_env env, napi_value obj, const RecordMember &member)
|
|
356
|
+
{
|
|
357
|
+
napi_value value = nullptr;
|
|
358
|
+
|
|
359
|
+
if (member.key) {
|
|
360
|
+
napi_value key = nullptr;
|
|
361
|
+
napi_get_reference_value(env, member.key, &key);
|
|
362
|
+
|
|
363
|
+
napi_get_property(env, obj, key, &value);
|
|
364
|
+
} else {
|
|
365
|
+
napi_get_named_property(env, obj, member.name, &value);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return value;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
bool CallData::PushObject(napi_value obj, const TypeInfo *type, uint8_t *origin)
|
|
266
372
|
{
|
|
267
|
-
K_ASSERT(IsObject(obj));
|
|
373
|
+
K_ASSERT(IsObject(env, obj));
|
|
268
374
|
K_ASSERT(type->primitive == PrimitiveKind::Record ||
|
|
269
375
|
type->primitive == PrimitiveKind::Union);
|
|
270
376
|
|
|
@@ -273,8 +379,8 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
|
|
|
273
379
|
if (type->primitive == PrimitiveKind::Record) {
|
|
274
380
|
members = type->members;
|
|
275
381
|
} else if (type->primitive == PrimitiveKind::Union) {
|
|
276
|
-
if (CheckValueTag(obj, &
|
|
277
|
-
|
|
382
|
+
if (CheckValueTag(env, obj, &UnionClassMarker)) {
|
|
383
|
+
UnionClass *u = UnionClass::Unwrap(Napi::Object(env, obj));
|
|
278
384
|
const uint8_t *raw = u->GetRaw();
|
|
279
385
|
|
|
280
386
|
if (u->GetType() != type) [[unlikely]] {
|
|
@@ -296,7 +402,7 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
|
|
|
296
402
|
return false;
|
|
297
403
|
}
|
|
298
404
|
} else {
|
|
299
|
-
Napi::Array properties = GetOwnPropertyNames(obj);
|
|
405
|
+
Napi::Array properties = GetOwnPropertyNames(env, obj);
|
|
300
406
|
|
|
301
407
|
if (properties.Length() != 1 || !properties.Get(0u).IsString()) [[unlikely]] {
|
|
302
408
|
ThrowError<Napi::Error>(env, "Expected object with single property name for union");
|
|
@@ -320,9 +426,34 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
|
|
|
320
426
|
|
|
321
427
|
MemSet(origin, 0, type->size);
|
|
322
428
|
|
|
429
|
+
#define PUSH_INTEGER(CType) \
|
|
430
|
+
do { \
|
|
431
|
+
CType v; \
|
|
432
|
+
if (!TryNumber(env, value, &v)) [[unlikely]] { \
|
|
433
|
+
abort(); \
|
|
434
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
435
|
+
return false; \
|
|
436
|
+
} \
|
|
437
|
+
\
|
|
438
|
+
*(CType *)dest = v; \
|
|
439
|
+
} while (false)
|
|
440
|
+
#define PUSH_INTEGER_SWAP(CType) \
|
|
441
|
+
do { \
|
|
442
|
+
CType v; \
|
|
443
|
+
if (!TryNumber(env, value, &v)) [[unlikely]] { \
|
|
444
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
445
|
+
return false; \
|
|
446
|
+
} \
|
|
447
|
+
\
|
|
448
|
+
*(CType *)dest = ReverseBytes(v); \
|
|
449
|
+
} while (false)
|
|
450
|
+
|
|
323
451
|
for (Size i = 0; i < members.len; i++) {
|
|
324
452
|
const RecordMember &member = members[i];
|
|
325
|
-
|
|
453
|
+
napi_value value = GetMemberValue(env, obj, member);
|
|
454
|
+
|
|
455
|
+
if (GetKindOf(env, value) == napi_undefined)
|
|
456
|
+
continue;
|
|
326
457
|
|
|
327
458
|
if (member.countedby >= 0) {
|
|
328
459
|
const char *countedby = members[member.countedby].name;
|
|
@@ -331,149 +462,36 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
|
|
|
331
462
|
return false;
|
|
332
463
|
}
|
|
333
464
|
|
|
334
|
-
if (value.IsUndefined())
|
|
335
|
-
continue;
|
|
336
|
-
|
|
337
465
|
uint8_t *dest = origin + member.offset;
|
|
338
466
|
|
|
339
467
|
switch (member.type->primitive) {
|
|
340
468
|
case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
|
|
341
469
|
|
|
342
470
|
case PrimitiveKind::Bool: {
|
|
343
|
-
|
|
471
|
+
bool b;
|
|
472
|
+
napi_status status = napi_get_value_bool(env, value, &b);
|
|
473
|
+
|
|
474
|
+
if (status != napi_ok) [[unlikely]] {
|
|
344
475
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
|
|
345
476
|
return false;
|
|
346
477
|
}
|
|
347
478
|
|
|
348
|
-
bool b = value.As<Napi::Boolean>();
|
|
349
479
|
*(bool *)dest = b;
|
|
350
480
|
} break;
|
|
351
|
-
case PrimitiveKind::Int8: {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
} break;
|
|
360
|
-
case PrimitiveKind::
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
uint8_t v = GetNumber<uint8_t>(value);
|
|
367
|
-
*(uint8_t *)dest = v;
|
|
368
|
-
} break;
|
|
369
|
-
case PrimitiveKind::Int16: {
|
|
370
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
371
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
372
|
-
return false;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
int16_t v = GetNumber<int16_t>(value);
|
|
376
|
-
*(int16_t *)dest = v;
|
|
377
|
-
} break;
|
|
378
|
-
case PrimitiveKind::Int16S: {
|
|
379
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
380
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
381
|
-
return false;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
int16_t v = GetNumber<int16_t>(value);
|
|
385
|
-
*(int16_t *)dest = ReverseBytes(v);
|
|
386
|
-
} break;
|
|
387
|
-
case PrimitiveKind::UInt16: {
|
|
388
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
389
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
390
|
-
return false;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
uint16_t v = GetNumber<uint16_t>(value);
|
|
394
|
-
*(uint16_t *)dest = v;
|
|
395
|
-
} break;
|
|
396
|
-
case PrimitiveKind::UInt16S: {
|
|
397
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
398
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
399
|
-
return false;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
uint16_t v = GetNumber<uint16_t>(value);
|
|
403
|
-
*(uint16_t *)dest = ReverseBytes(v);
|
|
404
|
-
} break;
|
|
405
|
-
case PrimitiveKind::Int32: {
|
|
406
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
407
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
408
|
-
return false;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
int32_t v = GetNumber<int32_t>(value);
|
|
412
|
-
*(int32_t *)dest = v;
|
|
413
|
-
} break;
|
|
414
|
-
case PrimitiveKind::Int32S: {
|
|
415
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
416
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
417
|
-
return false;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
int32_t v = GetNumber<int32_t>(value);
|
|
421
|
-
*(int32_t *)dest = ReverseBytes(v);
|
|
422
|
-
} break;
|
|
423
|
-
case PrimitiveKind::UInt32: {
|
|
424
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
425
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
426
|
-
return false;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
uint32_t v = GetNumber<uint32_t>(value);
|
|
430
|
-
*(uint32_t *)dest = v;
|
|
431
|
-
} break;
|
|
432
|
-
case PrimitiveKind::UInt32S: {
|
|
433
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
434
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
435
|
-
return false;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
uint32_t v = GetNumber<uint32_t>(value);
|
|
439
|
-
*(uint32_t *)dest = ReverseBytes(v);
|
|
440
|
-
} break;
|
|
441
|
-
case PrimitiveKind::Int64: {
|
|
442
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
443
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
444
|
-
return false;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
int64_t v = GetNumber<int64_t>(value);
|
|
448
|
-
*(int64_t *)dest = v;
|
|
449
|
-
} break;
|
|
450
|
-
case PrimitiveKind::Int64S: {
|
|
451
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
452
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
453
|
-
return false;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
int64_t v = GetNumber<int64_t>(value);
|
|
457
|
-
*(int64_t *)dest = ReverseBytes(v);
|
|
458
|
-
} break;
|
|
459
|
-
case PrimitiveKind::UInt64: {
|
|
460
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
461
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
462
|
-
return false;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
uint64_t v = GetNumber<uint64_t>(value);
|
|
466
|
-
*(uint64_t *)dest = v;
|
|
467
|
-
} break;
|
|
468
|
-
case PrimitiveKind::UInt64S: {
|
|
469
|
-
if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
|
|
470
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
471
|
-
return false;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
uint64_t v = GetNumber<uint64_t>(value);
|
|
475
|
-
*(uint64_t *)dest = ReverseBytes(v);
|
|
476
|
-
} break;
|
|
481
|
+
case PrimitiveKind::Int8: { PUSH_INTEGER(int8_t); } break;
|
|
482
|
+
case PrimitiveKind::UInt8: { PUSH_INTEGER(uint8_t); } break;
|
|
483
|
+
case PrimitiveKind::Int16: { PUSH_INTEGER(int16_t); } break;
|
|
484
|
+
case PrimitiveKind::Int16S: { PUSH_INTEGER_SWAP(int16_t); } break;
|
|
485
|
+
case PrimitiveKind::UInt16: { PUSH_INTEGER(uint16_t); } break;
|
|
486
|
+
case PrimitiveKind::UInt16S: { PUSH_INTEGER_SWAP(uint16_t); } break;
|
|
487
|
+
case PrimitiveKind::Int32: { PUSH_INTEGER(int32_t); } break;
|
|
488
|
+
case PrimitiveKind::Int32S: { PUSH_INTEGER_SWAP(int32_t); } break;
|
|
489
|
+
case PrimitiveKind::UInt32: { PUSH_INTEGER(uint32_t); } break;
|
|
490
|
+
case PrimitiveKind::UInt32S: { PUSH_INTEGER_SWAP(uint32_t); } break;
|
|
491
|
+
case PrimitiveKind::Int64: { PUSH_INTEGER(int64_t); } break;
|
|
492
|
+
case PrimitiveKind::Int64S: { PUSH_INTEGER_SWAP(int64_t); } break;
|
|
493
|
+
case PrimitiveKind::UInt64: { PUSH_INTEGER(uint64_t); } break;
|
|
494
|
+
case PrimitiveKind::UInt64S: { PUSH_INTEGER_SWAP(uint64_t); } break;
|
|
477
495
|
case PrimitiveKind::String: {
|
|
478
496
|
const char *str;
|
|
479
497
|
if (!PushString(value, 1, &str)) [[unlikely]]
|
|
@@ -504,24 +522,22 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
|
|
|
504
522
|
} break;
|
|
505
523
|
case PrimitiveKind::Record:
|
|
506
524
|
case PrimitiveKind::Union: {
|
|
507
|
-
if (!IsObject(value)) [[unlikely]] {
|
|
525
|
+
if (!IsObject(env, value)) [[unlikely]] {
|
|
508
526
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
509
527
|
return false;
|
|
510
528
|
}
|
|
511
529
|
|
|
512
|
-
|
|
513
|
-
if (!PushObject(obj2, member.type, dest))
|
|
530
|
+
if (!PushObject(value, member.type, dest))
|
|
514
531
|
return false;
|
|
515
532
|
} break;
|
|
516
533
|
case PrimitiveKind::Array: {
|
|
517
|
-
if (
|
|
518
|
-
Napi::Array array =
|
|
534
|
+
if (IsArray(env, value)) {
|
|
535
|
+
Napi::Array array = Napi::Array(env, value);
|
|
519
536
|
if (!PushNormalArray(array, member.type, member.type->size, dest))
|
|
520
537
|
return false;
|
|
521
|
-
} else if (
|
|
522
|
-
Span<const uint8_t> buffer = GetRawBuffer(value);
|
|
538
|
+
} else if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
|
|
523
539
|
PushBuffer(buffer, member.type, dest);
|
|
524
|
-
} else if (value
|
|
540
|
+
} else if (GetKindOf(env, value) == napi_string) {
|
|
525
541
|
if (!PushStringArray(value, member.type, dest))
|
|
526
542
|
return false;
|
|
527
543
|
} else {
|
|
@@ -530,22 +546,22 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
|
|
|
530
546
|
}
|
|
531
547
|
} break;
|
|
532
548
|
case PrimitiveKind::Float32: {
|
|
533
|
-
|
|
549
|
+
float f;
|
|
550
|
+
if (!TryNumber(env, value, &f)) [[unlikely]] {
|
|
534
551
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
535
552
|
return false;
|
|
536
553
|
}
|
|
537
554
|
|
|
538
|
-
|
|
539
|
-
*(float *)dest = f;
|
|
555
|
+
memcpy(dest, &f, 4);
|
|
540
556
|
} break;
|
|
541
557
|
case PrimitiveKind::Float64: {
|
|
542
|
-
|
|
558
|
+
double d;
|
|
559
|
+
if (!TryNumber(env, value, &d)) [[unlikely]] {
|
|
543
560
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
544
561
|
return false;
|
|
545
562
|
}
|
|
546
563
|
|
|
547
|
-
|
|
548
|
-
*(double *)dest = d;
|
|
564
|
+
memcpy(dest, &d, 8);
|
|
549
565
|
} break;
|
|
550
566
|
case PrimitiveKind::Callback: {
|
|
551
567
|
void *ptr;
|
|
@@ -559,6 +575,9 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
|
|
|
559
575
|
}
|
|
560
576
|
}
|
|
561
577
|
|
|
578
|
+
#undef PUSH_INTEGER_SWAP
|
|
579
|
+
#undef PUSH_INTEGER
|
|
580
|
+
|
|
562
581
|
return true;
|
|
563
582
|
}
|
|
564
583
|
|
|
@@ -578,7 +597,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
578
597
|
|
|
579
598
|
Size offset = 0;
|
|
580
599
|
|
|
581
|
-
#define PUSH_ARRAY(
|
|
600
|
+
#define PUSH_ARRAY(Code) \
|
|
582
601
|
do { \
|
|
583
602
|
for (Size i = 0; i < len; i++) { \
|
|
584
603
|
Napi::Value value = array[(uint32_t)i]; \
|
|
@@ -586,16 +605,33 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
586
605
|
offset = AlignLen(offset, ref->align); \
|
|
587
606
|
uint8_t *dest = origin + offset; \
|
|
588
607
|
\
|
|
589
|
-
|
|
590
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), (Expected)); \
|
|
591
|
-
return false; \
|
|
592
|
-
} \
|
|
593
|
-
\
|
|
594
|
-
GetCode \
|
|
608
|
+
Code \
|
|
595
609
|
\
|
|
596
610
|
offset += ref->size; \
|
|
597
611
|
} \
|
|
598
612
|
} while (false)
|
|
613
|
+
#define PUSH_INTEGERS(CType) \
|
|
614
|
+
PUSH_ARRAY({ \
|
|
615
|
+
CType v; \
|
|
616
|
+
\
|
|
617
|
+
if (!TryNumber(env, value, &v)) [[unlikely]] { \
|
|
618
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
619
|
+
return false; \
|
|
620
|
+
} \
|
|
621
|
+
\
|
|
622
|
+
*(CType *)dest = v; \
|
|
623
|
+
})
|
|
624
|
+
#define PUSH_INTEGERS_SWAP(CType) \
|
|
625
|
+
PUSH_ARRAY({ \
|
|
626
|
+
CType v; \
|
|
627
|
+
\
|
|
628
|
+
if (!TryNumber(env, value, &v)) [[unlikely]] { \
|
|
629
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
630
|
+
return false; \
|
|
631
|
+
} \
|
|
632
|
+
\
|
|
633
|
+
*(CType *)dest = ReverseBytes(v); \
|
|
634
|
+
})
|
|
599
635
|
|
|
600
636
|
switch (ref->primitive) {
|
|
601
637
|
case PrimitiveKind::Void: {
|
|
@@ -604,97 +640,34 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
604
640
|
} break;
|
|
605
641
|
|
|
606
642
|
case PrimitiveKind::Bool: {
|
|
607
|
-
PUSH_ARRAY(
|
|
608
|
-
bool b
|
|
643
|
+
PUSH_ARRAY({
|
|
644
|
+
bool b;
|
|
645
|
+
napi_status status = napi_get_value_bool(env, value, &b);
|
|
646
|
+
|
|
647
|
+
if (status != napi_ok) [[unlikely]] {
|
|
648
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
|
|
649
|
+
return false;
|
|
650
|
+
}
|
|
651
|
+
|
|
609
652
|
*(bool *)dest = b;
|
|
610
653
|
});
|
|
611
654
|
} break;
|
|
612
|
-
case PrimitiveKind::Int8: {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
} break;
|
|
618
|
-
case PrimitiveKind::
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
} break;
|
|
624
|
-
case PrimitiveKind::
|
|
625
|
-
|
|
626
|
-
int16_t v = GetNumber<int16_t>(value);
|
|
627
|
-
*(int16_t *)dest = v;
|
|
628
|
-
});
|
|
629
|
-
} break;
|
|
630
|
-
case PrimitiveKind::Int16S: {
|
|
631
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
632
|
-
int16_t v = GetNumber<int16_t>(value);
|
|
633
|
-
*(int16_t *)dest = ReverseBytes(v);
|
|
634
|
-
});
|
|
635
|
-
} break;
|
|
636
|
-
case PrimitiveKind::UInt16: {
|
|
637
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
638
|
-
uint16_t v = GetNumber<uint16_t>(value);
|
|
639
|
-
*(uint16_t *)dest = v;
|
|
640
|
-
});
|
|
641
|
-
} break;
|
|
642
|
-
case PrimitiveKind::UInt16S: {
|
|
643
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
644
|
-
uint16_t v = GetNumber<uint16_t>(value);
|
|
645
|
-
*(uint16_t *)dest = ReverseBytes(v);
|
|
646
|
-
});
|
|
647
|
-
} break;
|
|
648
|
-
case PrimitiveKind::Int32: {
|
|
649
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
650
|
-
int32_t v = GetNumber<int32_t>(value);
|
|
651
|
-
*(int32_t *)dest = v;
|
|
652
|
-
});
|
|
653
|
-
} break;
|
|
654
|
-
case PrimitiveKind::Int32S: {
|
|
655
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
656
|
-
int32_t v = GetNumber<int32_t>(value);
|
|
657
|
-
*(int32_t *)dest = ReverseBytes(v);
|
|
658
|
-
});
|
|
659
|
-
} break;
|
|
660
|
-
case PrimitiveKind::UInt32: {
|
|
661
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
662
|
-
uint32_t v = GetNumber<uint32_t>(value);
|
|
663
|
-
*(uint32_t *)dest = v;
|
|
664
|
-
});
|
|
665
|
-
} break;
|
|
666
|
-
case PrimitiveKind::UInt32S: {
|
|
667
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
668
|
-
uint32_t v = GetNumber<uint32_t>(value);
|
|
669
|
-
*(uint32_t *)dest = ReverseBytes(v);
|
|
670
|
-
});
|
|
671
|
-
} break;
|
|
672
|
-
case PrimitiveKind::Int64: {
|
|
673
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
674
|
-
int64_t v = GetNumber<int64_t>(value);
|
|
675
|
-
*(int64_t *)dest = v;
|
|
676
|
-
});
|
|
677
|
-
} break;
|
|
678
|
-
case PrimitiveKind::Int64S: {
|
|
679
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
680
|
-
int64_t v = GetNumber<int64_t>(value);
|
|
681
|
-
*(int64_t *)dest = ReverseBytes(v);
|
|
682
|
-
});
|
|
683
|
-
} break;
|
|
684
|
-
case PrimitiveKind::UInt64: {
|
|
685
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
686
|
-
uint64_t v = GetNumber<uint64_t>(value);
|
|
687
|
-
*(uint64_t *)dest = v;
|
|
688
|
-
});
|
|
689
|
-
} break;
|
|
690
|
-
case PrimitiveKind::UInt64S: {
|
|
691
|
-
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
692
|
-
uint64_t v = GetNumber<uint64_t>(value);
|
|
693
|
-
*(uint64_t *)dest = ReverseBytes(v);
|
|
694
|
-
});
|
|
695
|
-
} break;
|
|
655
|
+
case PrimitiveKind::Int8: { PUSH_INTEGERS(int8_t); } break;
|
|
656
|
+
case PrimitiveKind::UInt8: { PUSH_INTEGERS(uint8_t); } break;
|
|
657
|
+
case PrimitiveKind::Int16: { PUSH_INTEGERS(int16_t); } break;
|
|
658
|
+
case PrimitiveKind::Int16S: { PUSH_INTEGERS_SWAP(int16_t); } break;
|
|
659
|
+
case PrimitiveKind::UInt16: { PUSH_INTEGERS(uint16_t); } break;
|
|
660
|
+
case PrimitiveKind::UInt16S: { PUSH_INTEGERS_SWAP(uint16_t); } break;
|
|
661
|
+
case PrimitiveKind::Int32: { PUSH_INTEGERS(int32_t); } break;
|
|
662
|
+
case PrimitiveKind::Int32S: { PUSH_INTEGERS_SWAP(int32_t); } break;
|
|
663
|
+
case PrimitiveKind::UInt32: { PUSH_INTEGERS(uint32_t); } break;
|
|
664
|
+
case PrimitiveKind::UInt32S: { PUSH_INTEGERS_SWAP(uint32_t); } break;
|
|
665
|
+
case PrimitiveKind::Int64: { PUSH_INTEGERS(int64_t); } break;
|
|
666
|
+
case PrimitiveKind::Int64S: { PUSH_INTEGERS_SWAP(int64_t); } break;
|
|
667
|
+
case PrimitiveKind::UInt64: { PUSH_INTEGERS(uint64_t); } break;
|
|
668
|
+
case PrimitiveKind::UInt64S: { PUSH_INTEGERS_SWAP(uint64_t); } break;
|
|
696
669
|
case PrimitiveKind::String: {
|
|
697
|
-
PUSH_ARRAY(
|
|
670
|
+
PUSH_ARRAY({
|
|
698
671
|
const char *str;
|
|
699
672
|
if (!PushString(value, 1, &str)) [[unlikely]]
|
|
700
673
|
return false;
|
|
@@ -703,7 +676,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
703
676
|
});
|
|
704
677
|
} break;
|
|
705
678
|
case PrimitiveKind::String16: {
|
|
706
|
-
PUSH_ARRAY(
|
|
679
|
+
PUSH_ARRAY({
|
|
707
680
|
const char16_t *str16;
|
|
708
681
|
if (!PushString16(value, 1, &str16)) [[unlikely]]
|
|
709
682
|
return false;
|
|
@@ -712,7 +685,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
712
685
|
});
|
|
713
686
|
} break;
|
|
714
687
|
case PrimitiveKind::String32: {
|
|
715
|
-
PUSH_ARRAY(
|
|
688
|
+
PUSH_ARRAY({
|
|
716
689
|
const char32_t *str32;
|
|
717
690
|
if (!PushString32(value, 1, &str32)) [[unlikely]]
|
|
718
691
|
return false;
|
|
@@ -721,7 +694,12 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
721
694
|
});
|
|
722
695
|
} break;
|
|
723
696
|
case PrimitiveKind::Pointer: {
|
|
724
|
-
PUSH_ARRAY(
|
|
697
|
+
PUSH_ARRAY({
|
|
698
|
+
if (!IsObject(env, value)) [[unlikely]] {
|
|
699
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
|
|
725
703
|
void *ptr;
|
|
726
704
|
if (!PushPointer(value, ref, 1, &ptr)) [[unlikely]]
|
|
727
705
|
return false;
|
|
@@ -731,7 +709,12 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
731
709
|
} break;
|
|
732
710
|
case PrimitiveKind::Record:
|
|
733
711
|
case PrimitiveKind::Union: {
|
|
734
|
-
PUSH_ARRAY(
|
|
712
|
+
PUSH_ARRAY({
|
|
713
|
+
if (!IsObject(env, value)) [[unlikely]] {
|
|
714
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
|
|
735
718
|
Napi::Object obj2 = value.As<Napi::Object>();
|
|
736
719
|
if (!PushObject(obj2, ref, dest))
|
|
737
720
|
return false;
|
|
@@ -749,8 +732,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
749
732
|
Napi::Array array2 = value.As<Napi::Array>();
|
|
750
733
|
if (!PushNormalArray(array2, ref, (Size)ref->size, dest))
|
|
751
734
|
return false;
|
|
752
|
-
} else if (
|
|
753
|
-
Span<const uint8_t> buffer = GetRawBuffer(value);
|
|
735
|
+
} else if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
|
|
754
736
|
PushBuffer(buffer, ref, dest);
|
|
755
737
|
} else if (value.IsString()) {
|
|
756
738
|
if (!PushStringArray(value, ref, dest))
|
|
@@ -764,15 +746,25 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
764
746
|
}
|
|
765
747
|
} break;
|
|
766
748
|
case PrimitiveKind::Float32: {
|
|
767
|
-
PUSH_ARRAY(
|
|
768
|
-
float f
|
|
769
|
-
|
|
749
|
+
PUSH_ARRAY({
|
|
750
|
+
float f;
|
|
751
|
+
if (!TryNumber(env, value, &f)) [[unlikely]] {
|
|
752
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
memcpy(dest, &f, 4);
|
|
770
757
|
});
|
|
771
758
|
} break;
|
|
772
759
|
case PrimitiveKind::Float64: {
|
|
773
|
-
PUSH_ARRAY(
|
|
774
|
-
double d
|
|
775
|
-
|
|
760
|
+
PUSH_ARRAY({
|
|
761
|
+
double d;
|
|
762
|
+
if (!TryNumber(env, value, &d)) [[unlikely]] {
|
|
763
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
764
|
+
return false;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
memcpy(dest, &d, 8);
|
|
776
768
|
});
|
|
777
769
|
} break;
|
|
778
770
|
case PrimitiveKind::Callback: {
|
|
@@ -796,6 +788,8 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
796
788
|
case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
|
|
797
789
|
}
|
|
798
790
|
|
|
791
|
+
#undef PUSH_INTEGERS_SWAP
|
|
792
|
+
#undef PUSH_INTEGERS
|
|
799
793
|
#undef PUSH_ARRAY
|
|
800
794
|
|
|
801
795
|
return true;
|
|
@@ -834,20 +828,20 @@ void CallData::PushBuffer(Span<const uint8_t> buffer, const TypeInfo *type, uint
|
|
|
834
828
|
#undef SWAP
|
|
835
829
|
}
|
|
836
830
|
|
|
837
|
-
bool CallData::PushStringArray(
|
|
831
|
+
bool CallData::PushStringArray(napi_value value, const TypeInfo *type, uint8_t *origin)
|
|
838
832
|
{
|
|
839
|
-
K_ASSERT(
|
|
833
|
+
K_ASSERT(GetKindOf(env, value) == napi_string);
|
|
840
834
|
K_ASSERT(type->primitive == PrimitiveKind::Array);
|
|
841
835
|
|
|
842
836
|
size_t encoded = 0;
|
|
843
837
|
|
|
844
838
|
switch (type->ref.type->primitive) {
|
|
845
839
|
case PrimitiveKind::Int8: {
|
|
846
|
-
napi_status status = napi_get_value_string_utf8(env,
|
|
840
|
+
napi_status status = napi_get_value_string_utf8(env, value, (char *)origin, type->size, &encoded);
|
|
847
841
|
K_ASSERT(status == napi_ok);
|
|
848
842
|
} break;
|
|
849
843
|
case PrimitiveKind::Int16: {
|
|
850
|
-
napi_status status = napi_get_value_string_utf16(env,
|
|
844
|
+
napi_status status = napi_get_value_string_utf16(env, value, (char16_t *)origin, type->size / 2, &encoded);
|
|
851
845
|
K_ASSERT(status == napi_ok);
|
|
852
846
|
|
|
853
847
|
encoded *= 2;
|
|
@@ -864,190 +858,164 @@ bool CallData::PushStringArray(Napi::Value obj, const TypeInfo *type, uint8_t *o
|
|
|
864
858
|
return true;
|
|
865
859
|
}
|
|
866
860
|
|
|
867
|
-
bool CallData::PushPointer(
|
|
861
|
+
bool CallData::PushPointer(napi_value value, const TypeInfo *type, int directions, void **out_ptr)
|
|
868
862
|
{
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
value = cast->ref.Value();
|
|
874
|
-
type = cast->type;
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
const TypeInfo *ref = type->ref.type;
|
|
863
|
+
// In the past we were naively using napi_typeof() and a switch to "reduce" branching,
|
|
864
|
+
// but it did not match the common types very well (so there was still various if tests),
|
|
865
|
+
// and it turns out that napi_typeof() is made of successive type tests anyway so it
|
|
866
|
+
// just made things worse. Oh, well.
|
|
878
867
|
|
|
879
|
-
|
|
880
|
-
case napi_undefined:
|
|
881
|
-
case napi_null: {
|
|
882
|
-
*out_ptr = nullptr;
|
|
883
|
-
return true;
|
|
884
|
-
} break;
|
|
868
|
+
void *ptr = nullptr;
|
|
885
869
|
|
|
886
|
-
|
|
887
|
-
K_ASSERT(type->primitive == PrimitiveKind::Pointer ||
|
|
888
|
-
type->primitive == PrimitiveKind::String ||
|
|
889
|
-
type->primitive == PrimitiveKind::String16 ||
|
|
890
|
-
type->primitive == PrimitiveKind::String32);
|
|
870
|
+
restart:
|
|
891
871
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
872
|
+
// Fast path
|
|
873
|
+
if (bool external = false; TryPointer(env, value, &ptr, &external)) {
|
|
874
|
+
if (external && CheckValueTag(env, value, &CastMarker)) {
|
|
875
|
+
Napi::External<ValueCast> external = Napi::External<ValueCast>(env, value);
|
|
876
|
+
ValueCast *cast = external.Data();
|
|
896
877
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
} break;
|
|
878
|
+
napi_get_reference_value(env, cast->ref, &value);
|
|
879
|
+
type = cast->type;
|
|
900
880
|
|
|
901
|
-
|
|
902
|
-
|
|
881
|
+
goto restart;
|
|
882
|
+
}
|
|
903
883
|
|
|
904
|
-
|
|
905
|
-
|
|
884
|
+
*out_ptr = ptr;
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
906
887
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
Size len = PushIndirectString(array, ref, &ptr);
|
|
888
|
+
return PushPointerSlow(value, type, directions, out_ptr);
|
|
889
|
+
}
|
|
910
890
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
return false;
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
switch (ref->size) {
|
|
918
|
-
default: { out_kind = OutArgument::Kind::String; } break;
|
|
919
|
-
case 2: { out_kind = OutArgument::Kind::String16; } break;
|
|
920
|
-
case 4: { out_kind = OutArgument::Kind::String32; } break;
|
|
921
|
-
}
|
|
922
|
-
out_max_len = len;
|
|
923
|
-
} else {
|
|
924
|
-
if (!ref->size) [[unlikely]] {
|
|
925
|
-
ThrowError<Napi::TypeError>(env, "Cannot pass %1 value to %2, use koffi.as()",
|
|
926
|
-
ref != instance->void_type ? "opaque" : "ambiguous", type->name);
|
|
927
|
-
return false;
|
|
928
|
-
}
|
|
891
|
+
bool CallData::PushPointerSlow(napi_value value, const TypeInfo *type, int directions, void **out_ptr)
|
|
892
|
+
{
|
|
893
|
+
const TypeInfo *ref = type->ref.type;
|
|
929
894
|
|
|
930
|
-
|
|
931
|
-
Size size = len * ref->size;
|
|
895
|
+
void *ptr = nullptr;
|
|
932
896
|
|
|
933
|
-
|
|
897
|
+
if (IsArray(env, value)) {
|
|
898
|
+
Napi::Array array = Napi::Array(env, value);
|
|
899
|
+
Size len = PushIndirectString(array, ref, &ptr);
|
|
934
900
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
return false;
|
|
938
|
-
} else {
|
|
939
|
-
MemSet(ptr, 0, size);
|
|
940
|
-
}
|
|
901
|
+
OutArgument::Kind out_kind;
|
|
902
|
+
Size out_max_len = -1;
|
|
941
903
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
904
|
+
if (len >= 0) {
|
|
905
|
+
if (!ref->size && ref != instance->void_type) [[unlikely]] {
|
|
906
|
+
ThrowError<Napi::TypeError>(env, "Cannot pass [string] value to %1", type->name);
|
|
907
|
+
return false;
|
|
908
|
+
}
|
|
946
909
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
910
|
+
switch (ref->size) {
|
|
911
|
+
default: { out_kind = OutArgument::Kind::String; } break;
|
|
912
|
+
case 2: { out_kind = OutArgument::Kind::String16; } break;
|
|
913
|
+
case 4: { out_kind = OutArgument::Kind::String32; } break;
|
|
914
|
+
}
|
|
915
|
+
out_max_len = len;
|
|
916
|
+
} else {
|
|
917
|
+
Size size = (Size)array.Length() * ref->size;
|
|
950
918
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
919
|
+
if (!ref->size) [[unlikely]] {
|
|
920
|
+
ThrowError<Napi::TypeError>(env, "Cannot pass %1 value to %2, use koffi.as()",
|
|
921
|
+
ref != instance->void_type ? "opaque" : "ambiguous", type->name);
|
|
922
|
+
return false;
|
|
923
|
+
}
|
|
956
924
|
|
|
957
|
-
|
|
925
|
+
ptr = AllocHeap(size);
|
|
958
926
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected union value", GetValueType(instance, obj));
|
|
927
|
+
if (directions & 1) {
|
|
928
|
+
if (!PushNormalArray(array, type, size, (uint8_t *)ptr))
|
|
962
929
|
return false;
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
if (directions & 1) {
|
|
966
|
-
if (!PushObject(obj, ref, ptr))
|
|
967
|
-
return false;
|
|
968
|
-
} else {
|
|
969
|
-
MemSet(ptr, 0, ref->size);
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
out_kind = OutArgument::Kind::Object;
|
|
973
930
|
} else {
|
|
974
|
-
|
|
931
|
+
MemSet(ptr, 0, size);
|
|
975
932
|
}
|
|
976
933
|
|
|
977
|
-
|
|
978
|
-
|
|
934
|
+
out_kind = OutArgument::Kind::Array;
|
|
935
|
+
}
|
|
979
936
|
|
|
980
|
-
|
|
981
|
-
|
|
937
|
+
if (directions & 2) {
|
|
938
|
+
OutArgument *out = out_arguments.AppendDefault();
|
|
982
939
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
out->type = ref;
|
|
986
|
-
out->max_len = out_max_len;
|
|
987
|
-
}
|
|
940
|
+
napi_status status = napi_create_reference(env, value, 1, &out->ref);
|
|
941
|
+
K_ASSERT(status == napi_ok);
|
|
988
942
|
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
943
|
+
out->kind = out_kind;
|
|
944
|
+
out->ptr = (const uint8_t *)ptr;
|
|
945
|
+
out->type = ref;
|
|
946
|
+
out->max_len = out_max_len;
|
|
947
|
+
}
|
|
992
948
|
|
|
993
|
-
|
|
994
|
-
|
|
949
|
+
*out_ptr = ptr;
|
|
950
|
+
return true;
|
|
951
|
+
} else if (ref->primitive == PrimitiveKind::Record ||
|
|
952
|
+
ref->primitive == PrimitiveKind::Union) [[likely]] {
|
|
953
|
+
K_ASSERT(IsObject(env, value));
|
|
995
954
|
|
|
996
|
-
|
|
997
|
-
goto unexpected;
|
|
955
|
+
ptr = (void *)AllocHeap(ref->size);
|
|
998
956
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
return true;
|
|
1005
|
-
} else if (ref->primitive == PrimitiveKind::Int16) {
|
|
1006
|
-
PushString16Value(value, (const char16_t **)out_ptr);
|
|
1007
|
-
return true;
|
|
1008
|
-
} else if (ref->primitive == PrimitiveKind::Int32) {
|
|
1009
|
-
PushString32Value(value, (const char32_t **)out_ptr);
|
|
1010
|
-
return true;
|
|
1011
|
-
} else {
|
|
1012
|
-
goto unexpected;
|
|
1013
|
-
}
|
|
1014
|
-
} break;
|
|
957
|
+
if (ref->primitive == PrimitiveKind::Union &&
|
|
958
|
+
(directions & 2) && !CheckValueTag(env, value, &UnionClassMarker)) [[unlikely]] {
|
|
959
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected union value", GetValueType(instance, value));
|
|
960
|
+
return false;
|
|
961
|
+
}
|
|
1015
962
|
|
|
1016
|
-
|
|
1017
|
-
if (
|
|
1018
|
-
ThrowError<Napi::TypeError>(env, "Cannot pass function to type %1", type->name);
|
|
963
|
+
if (directions & 1) {
|
|
964
|
+
if (!PushObject(value, ref, (uint8_t *)ptr))
|
|
1019
965
|
return false;
|
|
1020
|
-
|
|
966
|
+
} else {
|
|
967
|
+
MemSet(ptr, 0, ref->size);
|
|
968
|
+
}
|
|
1021
969
|
|
|
1022
|
-
|
|
970
|
+
if (directions & 2) {
|
|
971
|
+
OutArgument *out = out_arguments.AppendDefault();
|
|
1023
972
|
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
return false;
|
|
973
|
+
napi_status status = napi_create_reference(env, value, 1, &out->ref);
|
|
974
|
+
K_ASSERT(status == napi_ok);
|
|
1027
975
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
976
|
+
out->kind = OutArgument::Kind::Object;
|
|
977
|
+
out->ptr = (const uint8_t *)ptr;
|
|
978
|
+
out->type = ref;
|
|
979
|
+
out->max_len = -1;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
*out_ptr = ptr;
|
|
983
|
+
return true;
|
|
984
|
+
} else if (napi_valuetype kind = GetKindOf(env, value); kind == napi_string) {
|
|
985
|
+
K_ASSERT(type->primitive == PrimitiveKind::Pointer);
|
|
1031
986
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
intptr_t ptr = (intptr_t)number.Int32Value();
|
|
987
|
+
if (directions & 2) [[unlikely]]
|
|
988
|
+
goto unexpected;
|
|
1035
989
|
|
|
1036
|
-
|
|
990
|
+
if (ref == instance->void_type) {
|
|
991
|
+
PushStringValue(value, (const char **)out_ptr);
|
|
1037
992
|
return true;
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
993
|
+
} else if (ref->primitive == PrimitiveKind::Int8) {
|
|
994
|
+
PushStringValue(value, (const char **)out_ptr);
|
|
995
|
+
return true;
|
|
996
|
+
} else if (ref->primitive == PrimitiveKind::Int16) {
|
|
997
|
+
PushString16Value(value, (const char16_t **)out_ptr);
|
|
998
|
+
return true;
|
|
999
|
+
} else if (ref->primitive == PrimitiveKind::Int32) {
|
|
1000
|
+
PushString32Value(value, (const char32_t **)out_ptr);
|
|
1001
|
+
return true;
|
|
1002
|
+
} else {
|
|
1003
|
+
goto unexpected;
|
|
1004
|
+
}
|
|
1005
|
+
} else if (kind == napi_function) {
|
|
1006
|
+
if (type->primitive != PrimitiveKind::Callback) [[unlikely]] {
|
|
1007
|
+
ThrowError<Napi::TypeError>(env, "Cannot pass function to type %1", type->name);
|
|
1008
|
+
return false;
|
|
1009
|
+
}
|
|
1042
1010
|
|
|
1043
|
-
|
|
1044
|
-
intptr_t ptr = (intptr_t)bigint.Int64Value(&lossless);
|
|
1011
|
+
Napi::Function func = Napi::Function(env, value);
|
|
1045
1012
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1013
|
+
ptr = ReserveTrampoline(type->ref.proto, func);
|
|
1014
|
+
if (!ptr) [[unlikely]]
|
|
1015
|
+
return false;
|
|
1049
1016
|
|
|
1050
|
-
|
|
1017
|
+
*out_ptr = (void *)ptr;
|
|
1018
|
+
return true;
|
|
1051
1019
|
}
|
|
1052
1020
|
|
|
1053
1021
|
unexpected:
|
|
@@ -1055,51 +1023,47 @@ unexpected:
|
|
|
1055
1023
|
return false;
|
|
1056
1024
|
}
|
|
1057
1025
|
|
|
1058
|
-
bool CallData::PushCallback(
|
|
1026
|
+
bool CallData::PushCallback(napi_value value, const TypeInfo *type, void **out_ptr)
|
|
1059
1027
|
{
|
|
1060
|
-
|
|
1061
|
-
Napi::Function func = value.As<Napi::Function>();
|
|
1028
|
+
void *ptr = nullptr;
|
|
1062
1029
|
|
|
1063
|
-
|
|
1064
|
-
if (!ptr) [[unlikely]]
|
|
1065
|
-
return false;
|
|
1030
|
+
restart:
|
|
1066
1031
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
|
|
1072
|
-
ValueCast *cast = external.Data();
|
|
1032
|
+
if (bool external = false; TryPointer(env, value, &ptr, &external)) {
|
|
1033
|
+
if (external && CheckValueTag(env, value, &CastMarker)) {
|
|
1034
|
+
Napi::External<ValueCast> external = Napi::External<ValueCast>(env, value);
|
|
1035
|
+
ValueCast *cast = external.Data();
|
|
1073
1036
|
|
|
1074
|
-
|
|
1037
|
+
napi_get_reference_value(env, cast->ref, &value);
|
|
1038
|
+
type = cast->type;
|
|
1075
1039
|
|
|
1076
|
-
|
|
1077
|
-
|
|
1040
|
+
goto restart;
|
|
1041
|
+
}
|
|
1078
1042
|
|
|
1079
|
-
*out_ptr =
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
goto unexpected;
|
|
1084
|
-
}
|
|
1043
|
+
*out_ptr = ptr;
|
|
1044
|
+
return true;
|
|
1045
|
+
} else if (GetKindOf(env, value) == napi_function) {
|
|
1046
|
+
Napi::Function func = Napi::Function(env, value);
|
|
1085
1047
|
|
|
1086
|
-
|
|
1048
|
+
ptr = ReserveTrampoline(type->ref.proto, func);
|
|
1049
|
+
if (!ptr) [[unlikely]]
|
|
1050
|
+
return false;
|
|
1051
|
+
|
|
1052
|
+
*out_ptr = ptr;
|
|
1053
|
+
return true;
|
|
1054
|
+
}
|
|
1087
1055
|
|
|
1088
|
-
unexpected:
|
|
1089
1056
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
|
|
1090
1057
|
return false;
|
|
1091
1058
|
}
|
|
1092
1059
|
|
|
1093
|
-
Size CallData::PushIndirectString(Napi::Array array, const TypeInfo *ref,
|
|
1060
|
+
Size CallData::PushIndirectString(Napi::Array array, const TypeInfo *ref, void **out_ptr)
|
|
1094
1061
|
{
|
|
1095
1062
|
if (array.Length() != 1)
|
|
1096
1063
|
return -1;
|
|
1097
1064
|
|
|
1098
1065
|
Napi::Value value = array[0u];
|
|
1099
1066
|
|
|
1100
|
-
if (!value.IsString())
|
|
1101
|
-
return -1;
|
|
1102
|
-
|
|
1103
1067
|
if (ref == instance->void_type) {
|
|
1104
1068
|
return PushStringValue(value, (const char **)out_ptr);
|
|
1105
1069
|
} else if (ref->primitive == PrimitiveKind::Int8) {
|
|
@@ -1137,67 +1101,48 @@ void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func
|
|
|
1137
1101
|
|
|
1138
1102
|
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1139
1103
|
|
|
1104
|
+
trampoline->state = 1;
|
|
1140
1105
|
trampoline->instance = instance;
|
|
1141
1106
|
trampoline->proto = proto;
|
|
1142
1107
|
trampoline->func.Reset(func, 1);
|
|
1143
1108
|
trampoline->recv.Reset();
|
|
1144
|
-
trampoline->used = true;
|
|
1145
1109
|
|
|
1146
1110
|
void *ptr = GetTrampoline(idx);
|
|
1147
1111
|
|
|
1148
1112
|
return ptr;
|
|
1149
1113
|
}
|
|
1150
1114
|
|
|
1151
|
-
|
|
1152
|
-
{
|
|
1153
|
-
PrintLn(StdErr, "%!..+---- %1 (%2) ----%!0", func->name, CallConventionNames[(int)func->convention]);
|
|
1154
|
-
|
|
1155
|
-
if (func->parameters.len) {
|
|
1156
|
-
PrintLn(StdErr, "Parameters:");
|
|
1157
|
-
for (Size i = 0; i < func->parameters.len; i++) {
|
|
1158
|
-
const ParameterInfo ¶m = func->parameters[i];
|
|
1159
|
-
PrintLn(StdErr, " %1 = %2 (%3)", i, param.type->name, FmtMemSize(param.type->size));
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
PrintLn(StdErr, "Return: %1 (%2)", func->ret.type->name, FmtMemSize(func->ret.type->size));
|
|
1163
|
-
|
|
1164
|
-
Span<const uint8_t> stack = MakeSpan(mem->stack.end(), old_stack_mem.end() - mem->stack.end());
|
|
1165
|
-
Span<const uint8_t> heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
|
|
1166
|
-
|
|
1167
|
-
DumpMemory("Stack", stack);
|
|
1168
|
-
DumpMemory("Heap", heap);
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
bool CallData::CheckDynamicLength(Napi::Object obj, Size element, const char *countedby, Napi::Value value)
|
|
1115
|
+
bool CallData::CheckDynamicLength(napi_value obj, Size element, const char *countedby, napi_value value)
|
|
1172
1116
|
{
|
|
1173
1117
|
int64_t expected = -1;
|
|
1174
1118
|
int64_t size = -1;
|
|
1175
1119
|
|
|
1176
1120
|
// Get expected size
|
|
1177
1121
|
{
|
|
1178
|
-
|
|
1122
|
+
napi_value by;
|
|
1123
|
+
napi_status status = napi_get_named_property(env, obj, countedby, &by);
|
|
1179
1124
|
|
|
1180
|
-
if (!
|
|
1125
|
+
if (status != napi_ok || !TryNumber(env, by, &expected)) [[unlikely]] {
|
|
1181
1126
|
ThrowError<Napi::Error>(env, "Unexpected %1 value for dynamic length, expected number", GetValueType(instance, by));
|
|
1182
1127
|
return false;
|
|
1183
1128
|
}
|
|
1184
1129
|
|
|
1185
1130
|
// If we get anywhere near overflow there are other problems to worry about.
|
|
1186
1131
|
// So let's not worry about that.
|
|
1187
|
-
expected
|
|
1132
|
+
expected *= element;
|
|
1188
1133
|
}
|
|
1189
1134
|
|
|
1190
1135
|
// Get actual size
|
|
1191
|
-
if (
|
|
1192
|
-
Napi::Array array =
|
|
1136
|
+
if (IsArray(env, value)) {
|
|
1137
|
+
Napi::Array array = Napi::Array(env, value);
|
|
1193
1138
|
size = array.Length() * element;
|
|
1194
|
-
} else if (
|
|
1195
|
-
Napi::TypedArray typed =
|
|
1139
|
+
} else if (IsTypedArray(env, value)) {
|
|
1140
|
+
Napi::TypedArray typed = Napi::TypedArray(env, value);
|
|
1196
1141
|
size = typed.ByteLength();
|
|
1197
|
-
} else if (
|
|
1198
|
-
Napi::ArrayBuffer buffer =
|
|
1142
|
+
} else if (IsArrayBuffer(env, value)) {
|
|
1143
|
+
Napi::ArrayBuffer buffer = Napi::ArrayBuffer(env, value);
|
|
1199
1144
|
size = buffer.ByteLength();
|
|
1200
|
-
} else if (!IsNullOrUndefined(value)) {
|
|
1145
|
+
} else if (!IsNullOrUndefined(env, value)) {
|
|
1201
1146
|
size = element;
|
|
1202
1147
|
} else {
|
|
1203
1148
|
size = 0;
|
|
@@ -1211,98 +1156,13 @@ bool CallData::CheckDynamicLength(Napi::Object obj, Size element, const char *co
|
|
|
1211
1156
|
return true;
|
|
1212
1157
|
}
|
|
1213
1158
|
|
|
1214
|
-
static inline Napi::Value GetReferenceValue(Napi::Env env, napi_ref ref)
|
|
1215
|
-
{
|
|
1216
|
-
napi_value value;
|
|
1217
|
-
|
|
1218
|
-
napi_status status = napi_get_reference_value(env, ref, &value);
|
|
1219
|
-
K_ASSERT(status == napi_ok);
|
|
1220
|
-
|
|
1221
|
-
return Napi::Value(env, value);
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
void CallData::PopOutArguments()
|
|
1225
|
-
{
|
|
1226
|
-
for (const OutArgument &out: out_arguments) {
|
|
1227
|
-
Napi::Value value = GetReferenceValue(env, out.ref);
|
|
1228
|
-
K_ASSERT(!value.IsEmpty());
|
|
1229
|
-
|
|
1230
|
-
switch (out.kind) {
|
|
1231
|
-
case OutArgument::Kind::Array: {
|
|
1232
|
-
K_ASSERT(value.IsArray());
|
|
1233
|
-
|
|
1234
|
-
Napi::Array array(env, value);
|
|
1235
|
-
DecodeNormalArray(array, out.ptr, out.type);
|
|
1236
|
-
} break;
|
|
1237
|
-
|
|
1238
|
-
case OutArgument::Kind::Buffer: {
|
|
1239
|
-
K_ASSERT(IsRawBuffer(value));
|
|
1240
|
-
|
|
1241
|
-
Span<uint8_t> buffer = GetRawBuffer(value);
|
|
1242
|
-
DecodeBuffer(buffer, out.ptr, out.type);
|
|
1243
|
-
} break;
|
|
1244
|
-
|
|
1245
|
-
case OutArgument::Kind::String: {
|
|
1246
|
-
Napi::Array array(env, value);
|
|
1247
|
-
|
|
1248
|
-
K_ASSERT(array.IsArray());
|
|
1249
|
-
K_ASSERT(array.Length() == 1);
|
|
1250
|
-
|
|
1251
|
-
Size len = strnlen((const char *)out.ptr, out.max_len);
|
|
1252
|
-
Napi::String str = Napi::String::New(env, (const char *)out.ptr, len);
|
|
1253
|
-
|
|
1254
|
-
array.Set(0u, str);
|
|
1255
|
-
} break;
|
|
1256
|
-
|
|
1257
|
-
case OutArgument::Kind::String16: {
|
|
1258
|
-
Napi::Array array(env, value);
|
|
1259
|
-
|
|
1260
|
-
K_ASSERT(array.IsArray());
|
|
1261
|
-
K_ASSERT(array.Length() == 1);
|
|
1262
|
-
|
|
1263
|
-
Size len = NullTerminatedLength((const char16_t *)out.ptr, out.max_len);
|
|
1264
|
-
Napi::String str = Napi::String::New(env, (const char16_t *)out.ptr, len);
|
|
1265
|
-
|
|
1266
|
-
array.Set(0u, str);
|
|
1267
|
-
} break;
|
|
1268
|
-
|
|
1269
|
-
case OutArgument::Kind::String32: {
|
|
1270
|
-
Napi::Array array(env, value);
|
|
1271
|
-
|
|
1272
|
-
K_ASSERT(array.IsArray());
|
|
1273
|
-
K_ASSERT(array.Length() == 1);
|
|
1274
|
-
|
|
1275
|
-
Size len = NullTerminatedLength((const char32_t *)out.ptr, out.max_len);
|
|
1276
|
-
Napi::String str = MakeStringFromUTF32(env, (const char32_t *)out.ptr, len);
|
|
1277
|
-
|
|
1278
|
-
array.Set(0u, str);
|
|
1279
|
-
} break;
|
|
1280
|
-
|
|
1281
|
-
case OutArgument::Kind::Object: {
|
|
1282
|
-
Napi::Object obj = value.As<Napi::Object>();
|
|
1283
|
-
|
|
1284
|
-
if (CheckValueTag(value, &MagicUnionMarker)) {
|
|
1285
|
-
MagicUnion *u = MagicUnion::Unwrap(obj);
|
|
1286
|
-
u->SetRaw(out.ptr);
|
|
1287
|
-
} else {
|
|
1288
|
-
DecodeObject(obj, out.ptr, out.type);
|
|
1289
|
-
}
|
|
1290
|
-
} break;
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
1159
|
void PerformAsyncRelay(napi_env, napi_value, void *, void *udata)
|
|
1296
1160
|
{
|
|
1297
1161
|
RelayContext *ctx = (RelayContext *)udata;
|
|
1298
1162
|
CallData *call = ctx->call;
|
|
1299
1163
|
|
|
1300
1164
|
call->Relay(ctx->idx, ctx->sp);
|
|
1301
|
-
|
|
1302
|
-
// This CallData was created artificially just to perform the callback. Which means the
|
|
1303
|
-
// creator may not run on the main thread, and cannot properly destroy it, because some
|
|
1304
|
-
// members are managed by Node.
|
|
1305
|
-
call->Dispose();
|
|
1165
|
+
call->Finalize();
|
|
1306
1166
|
|
|
1307
1167
|
// We're done!
|
|
1308
1168
|
std::lock_guard<std::mutex> lock(ctx->mutex);
|