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/util.cc
CHANGED
|
@@ -4,53 +4,19 @@
|
|
|
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
|
|
|
9
10
|
#include <napi.h>
|
|
10
11
|
|
|
11
12
|
namespace K {
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
const napi_type_tag LibraryHandleMarker = { 0xdb9b066e6f700474, 0x0aecd7e4c63fbda9 };
|
|
15
|
-
const napi_type_tag TypeObjectMarker = { 0x1cc449675b294374, 0xbb13a50e97dcb017 };
|
|
16
|
-
const napi_type_tag DirectionMarker = { 0xf9c306238b480580, 0xc2e168524a0823f5 };
|
|
17
|
-
const napi_type_tag UnionValueMarker = { 0x5eaf2245526a4c7d, 0x8c86c9ee2b96ffc8 };
|
|
18
|
-
const napi_type_tag CastMarker = { 0x77f459614a0a412f, 0x80b3dda1341dc8df };
|
|
19
|
-
|
|
20
|
-
#if !defined(EXTERNAL_TYPES)
|
|
21
|
-
|
|
22
|
-
Napi::Function TypeObject::InitClass(Napi::Env env)
|
|
23
|
-
{
|
|
24
|
-
Napi::Function constructor = DefineClass(env, "TypeObject", {});
|
|
25
|
-
return constructor;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
TypeObject::TypeObject(const Napi::CallbackInfo &info)
|
|
29
|
-
: Napi::ObjectWrap<TypeObject>(info)
|
|
30
|
-
{
|
|
31
|
-
Napi::Env env = info.Env();
|
|
32
|
-
|
|
33
|
-
if (info.Length() < 1 || !info[0u].IsExternal()) [[unlikely]] {
|
|
34
|
-
ThrowError<Napi::Error>(env, "Type objects cannot be constructed manually");
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
Napi::External<TypeInfo> external = info[0u].As<Napi::External<TypeInfo>>();
|
|
39
|
-
type = external.Data();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
void TypeObject::Finalize(Napi::BasicEnv env)
|
|
43
|
-
{
|
|
44
|
-
DeleteReferenceSafe(env, *this);
|
|
45
|
-
SuppressDestruct();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
#endif
|
|
49
|
-
|
|
50
|
-
Napi::Function UnionValue::InitClass(Napi::Env env, const TypeInfo *type)
|
|
14
|
+
Napi::Function UnionValue::InitClass(InstanceData *instance, const TypeInfo *type)
|
|
51
15
|
{
|
|
52
16
|
K_ASSERT(type->primitive == PrimitiveKind::Union);
|
|
53
17
|
|
|
18
|
+
Napi::Env env = instance->env;
|
|
19
|
+
|
|
54
20
|
// node-addon-api wants std::vector
|
|
55
21
|
std::vector<Napi::ClassPropertyDescriptor<UnionValue>> properties;
|
|
56
22
|
properties.reserve(type->members.len);
|
|
@@ -73,7 +39,9 @@ UnionValue::UnionValue(const Napi::CallbackInfo &info)
|
|
|
73
39
|
: Napi::ObjectWrap<UnionValue>(info), type((const TypeInfo *)info.Data())
|
|
74
40
|
{
|
|
75
41
|
Napi::Env env = info.Env();
|
|
76
|
-
|
|
42
|
+
|
|
43
|
+
K_ASSERT(type->instance);
|
|
44
|
+
instance = type->instance;
|
|
77
45
|
|
|
78
46
|
if (info.Length() >= 1) {
|
|
79
47
|
if (!info[0].IsExternal()) [[unlikely]] {
|
|
@@ -90,7 +58,7 @@ UnionValue::UnionValue(const Napi::CallbackInfo &info)
|
|
|
90
58
|
|
|
91
59
|
void UnionValue::Finalize(Napi::BasicEnv env)
|
|
92
60
|
{
|
|
93
|
-
|
|
61
|
+
node_api_delete_reference(env, *this);
|
|
94
62
|
SuppressDestruct();
|
|
95
63
|
}
|
|
96
64
|
|
|
@@ -140,669 +108,6 @@ void UnionValue::Setter(const Napi::CallbackInfo &info, const Napi::Value &value
|
|
|
140
108
|
raw.Clear();
|
|
141
109
|
}
|
|
142
110
|
|
|
143
|
-
static inline bool IsIdentifierStart(char c)
|
|
144
|
-
{
|
|
145
|
-
return IsAsciiAlpha(c) || c == '_';
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
static inline bool IsIdentifierChar(char c)
|
|
149
|
-
{
|
|
150
|
-
return IsAsciiAlphaOrDigit(c) || c == '_';
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
static inline Span<const char> SplitIdentifier(Span<const char> str)
|
|
154
|
-
{
|
|
155
|
-
Size offset = 0;
|
|
156
|
-
|
|
157
|
-
if (str.len && IsIdentifierStart(str[0])) {
|
|
158
|
-
offset++;
|
|
159
|
-
|
|
160
|
-
while (offset < str.len && IsIdentifierChar(str[offset])) {
|
|
161
|
-
offset++;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
Span<const char> token = str.Take(0, offset);
|
|
166
|
-
return token;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
int ResolveDirections(Span<const char> str)
|
|
170
|
-
{
|
|
171
|
-
if (str == "_In_") {
|
|
172
|
-
return 1;
|
|
173
|
-
} else if (str == "_Out_") {
|
|
174
|
-
return 2;
|
|
175
|
-
} else if (str == "_Inout_") {
|
|
176
|
-
return 3;
|
|
177
|
-
} else {
|
|
178
|
-
return 0;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const TypeInfo *ResolveType(Napi::Value value, int *out_directions)
|
|
183
|
-
{
|
|
184
|
-
Napi::Env env = value.Env();
|
|
185
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
186
|
-
|
|
187
|
-
if (value.IsString()) {
|
|
188
|
-
std::string str = value.As<Napi::String>();
|
|
189
|
-
Span<const char> remain = str.c_str();
|
|
190
|
-
|
|
191
|
-
// Quick path for known types (int, float *, etc.)
|
|
192
|
-
const TypeInfo *type = instance->types_map.FindValue(remain.ptr, nullptr);
|
|
193
|
-
|
|
194
|
-
if (!type) {
|
|
195
|
-
if (out_directions) {
|
|
196
|
-
Span<const char> prefix = SplitIdentifier(remain);
|
|
197
|
-
int directions = ResolveDirections(prefix);
|
|
198
|
-
|
|
199
|
-
if (directions) {
|
|
200
|
-
remain = remain.Take(prefix.len, remain.len - prefix.len);
|
|
201
|
-
remain = TrimStrLeft(remain);
|
|
202
|
-
|
|
203
|
-
*out_directions = directions;
|
|
204
|
-
} else {
|
|
205
|
-
*out_directions = 1;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
type = ResolveType(env, remain.ptr);
|
|
210
|
-
|
|
211
|
-
if (!type) {
|
|
212
|
-
if (!env.IsExceptionPending()) {
|
|
213
|
-
ThrowError<Napi::TypeError>(env, "Unknown or invalid type name '%1'", str.c_str());
|
|
214
|
-
}
|
|
215
|
-
return nullptr;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Cache for quick future access
|
|
219
|
-
bool inserted;
|
|
220
|
-
auto bucket = instance->types_map.InsertOrGetDefault(remain.ptr, &inserted);
|
|
221
|
-
|
|
222
|
-
if (inserted) {
|
|
223
|
-
bucket->key = DuplicateString(remain, &instance->str_alloc).ptr;
|
|
224
|
-
bucket->value = type;
|
|
225
|
-
}
|
|
226
|
-
} else if (out_directions) {
|
|
227
|
-
*out_directions = 1;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return type;
|
|
231
|
-
} else {
|
|
232
|
-
napi_valuetype kind = GetKindOf(env, value);
|
|
233
|
-
|
|
234
|
-
if (kind == napi_external && CheckValueTag(env, value, &DirectionMarker)) {
|
|
235
|
-
Napi::External<TypeInfo> external = Napi::External<TypeInfo>(env, value);
|
|
236
|
-
const TypeInfo *raw = external.Data();
|
|
237
|
-
|
|
238
|
-
const TypeInfo *type = AlignDown(raw, 4);
|
|
239
|
-
K_ASSERT(type);
|
|
240
|
-
|
|
241
|
-
if (out_directions) {
|
|
242
|
-
Size delta = (uint8_t *)raw - (uint8_t *)type;
|
|
243
|
-
*out_directions = 1 + (int)delta;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return type;
|
|
247
|
-
#if defined(EXTERNAL_TYPES)
|
|
248
|
-
} else if (kind == napi_external && CheckValueTag(env, value, &TypeObjectMarker)) {
|
|
249
|
-
Napi::External<TypeInfo> external = Napi::External<TypeInfo>(env, value);
|
|
250
|
-
const TypeInfo *type = external.Data();
|
|
251
|
-
|
|
252
|
-
if (out_directions) {
|
|
253
|
-
*out_directions = 1;
|
|
254
|
-
}
|
|
255
|
-
return type;
|
|
256
|
-
#else
|
|
257
|
-
} else if (kind == napi_object && CheckValueTag(env, value, &TypeObjectMarker)) {
|
|
258
|
-
TypeObject *defn = nullptr;
|
|
259
|
-
napi_unwrap(env, value, (void **)&defn);
|
|
260
|
-
|
|
261
|
-
if (out_directions) {
|
|
262
|
-
*out_directions = 1;
|
|
263
|
-
}
|
|
264
|
-
return defn->GetType();
|
|
265
|
-
#endif
|
|
266
|
-
} else {
|
|
267
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value as type specifier, expected string or type", GetValueType(instance, value));
|
|
268
|
-
return nullptr;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const TypeInfo *ResolveType(Napi::Env env, Span<const char> str)
|
|
274
|
-
{
|
|
275
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
276
|
-
|
|
277
|
-
// Each item can be > 0 for array or 0 for a pointer
|
|
278
|
-
LocalArray<Size, 8> arrays;
|
|
279
|
-
uint8_t disposables = 0;
|
|
280
|
-
|
|
281
|
-
Span<const char> name;
|
|
282
|
-
Span<const char> after;
|
|
283
|
-
{
|
|
284
|
-
Span<const char> remain = str;
|
|
285
|
-
|
|
286
|
-
// Skip initial const qualifiers
|
|
287
|
-
remain = TrimStrLeft(remain);
|
|
288
|
-
while (SplitIdentifier(remain) == "const") {
|
|
289
|
-
remain = remain.Take(6, remain.len - 6);
|
|
290
|
-
remain = TrimStrLeft(remain);
|
|
291
|
-
}
|
|
292
|
-
remain = TrimStrLeft(remain);
|
|
293
|
-
|
|
294
|
-
after = remain;
|
|
295
|
-
|
|
296
|
-
// Consume one or more identifiers (e.g. unsigned int)
|
|
297
|
-
for (;;) {
|
|
298
|
-
after = TrimStrLeft(after);
|
|
299
|
-
|
|
300
|
-
Span<const char> token = SplitIdentifier(after);
|
|
301
|
-
if (!token.len)
|
|
302
|
-
break;
|
|
303
|
-
after = after.Take(token.len, after.len - token.len);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
name = TrimStr(MakeSpan(remain.ptr, after.ptr - remain.ptr));
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Consume type indirections (pointer, array, etc.)
|
|
310
|
-
while (after.len) {
|
|
311
|
-
if (after[0] == '*') {
|
|
312
|
-
after = after.Take(1, after.len - 1);
|
|
313
|
-
|
|
314
|
-
if (!arrays.Available()) [[unlikely]] {
|
|
315
|
-
ThrowError<Napi::Error>(env, "Too many type indirections");
|
|
316
|
-
return nullptr;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
arrays.Append(0);
|
|
320
|
-
} else if (after[0] == '!') {
|
|
321
|
-
after = after.Take(1, after.len - 1);
|
|
322
|
-
disposables |= (1u << arrays.len);
|
|
323
|
-
} else if (after[0] == '[') {
|
|
324
|
-
after = after.Take(1, after.len - 1);
|
|
325
|
-
|
|
326
|
-
Size len = 0;
|
|
327
|
-
|
|
328
|
-
after = TrimStrLeft(after);
|
|
329
|
-
if (!ParseInt(after, &len, 0, &after) || len < 0) [[unlikely]] {
|
|
330
|
-
ThrowError<Napi::Error>(env, "Invalid array length");
|
|
331
|
-
return nullptr;
|
|
332
|
-
}
|
|
333
|
-
after = TrimStrLeft(after);
|
|
334
|
-
if (!after.len || after[0] != ']') [[unlikely]] {
|
|
335
|
-
ThrowError<Napi::Error>(env, "Expected ']' after array length");
|
|
336
|
-
return nullptr;
|
|
337
|
-
}
|
|
338
|
-
after = after.Take(1, after.len - 1);
|
|
339
|
-
|
|
340
|
-
if (!arrays.Available()) [[unlikely]] {
|
|
341
|
-
ThrowError<Napi::Error>(env, "Too many type indirections");
|
|
342
|
-
return nullptr;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
arrays.Append(len);
|
|
346
|
-
} else if (SplitIdentifier(after) == "const") {
|
|
347
|
-
after = after.Take(6, after.len - 6);
|
|
348
|
-
} else {
|
|
349
|
-
after = TrimStrRight(after);
|
|
350
|
-
|
|
351
|
-
if (after.len) [[unlikely]] {
|
|
352
|
-
ThrowError<Napi::Error>(env, "Unexpected character '%1' in type specifier", after[0]);
|
|
353
|
-
return nullptr;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
break;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
after = TrimStrLeft(after);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
const TypeInfo *type = instance->types_map.FindValue(name, nullptr);
|
|
363
|
-
|
|
364
|
-
if (!type) {
|
|
365
|
-
// Try with cleaned up spaces
|
|
366
|
-
if (name.len < 256) {
|
|
367
|
-
LocalArray<char, 256> buf;
|
|
368
|
-
for (Size i = 0; i < name.len; i++) {
|
|
369
|
-
char c = name[i];
|
|
370
|
-
|
|
371
|
-
if (IsAsciiWhite(c)) {
|
|
372
|
-
buf.Append(' ');
|
|
373
|
-
while (++i < name.len && IsAsciiWhite(name[i]));
|
|
374
|
-
i--;
|
|
375
|
-
} else {
|
|
376
|
-
buf.Append(c);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
type = instance->types_map.FindValue(buf, nullptr);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
if (!type)
|
|
384
|
-
return nullptr;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
for (int i = 0;; i++) {
|
|
388
|
-
if (disposables & (1u << i)) {
|
|
389
|
-
if (type->primitive != PrimitiveKind::Pointer &&
|
|
390
|
-
type->primitive != PrimitiveKind::String &&
|
|
391
|
-
type->primitive != PrimitiveKind::String16 &&
|
|
392
|
-
type->primitive != PrimitiveKind::String32) [[unlikely]] {
|
|
393
|
-
ThrowError<Napi::Error>(env, "Cannot create disposable type for non-pointer");
|
|
394
|
-
return nullptr;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
TypeInfo *copy = instance->types.AppendDefault();
|
|
398
|
-
|
|
399
|
-
memcpy((void *)copy, (const void *)type, K_SIZE(*type));
|
|
400
|
-
copy->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
|
|
401
|
-
copy->members.allocator = GetNullAllocator();
|
|
402
|
-
copy->members.allocator = GetNullAllocator();
|
|
403
|
-
memset((void *)©->defn, 0, K_SIZE(copy->defn));
|
|
404
|
-
|
|
405
|
-
static_assert(!std::is_polymorphic_v<Napi::ObjectReference>);
|
|
406
|
-
|
|
407
|
-
copy->dispose = [](Napi::Env env, const TypeInfo *, const void *ptr) {
|
|
408
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
409
|
-
|
|
410
|
-
free((void *)ptr);
|
|
411
|
-
instance->stats.disposed++;
|
|
412
|
-
};
|
|
413
|
-
|
|
414
|
-
type = copy;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
if (i >= arrays.len)
|
|
418
|
-
break;
|
|
419
|
-
Size len = arrays[i];
|
|
420
|
-
|
|
421
|
-
if (len > 0) {
|
|
422
|
-
if (type->primitive == PrimitiveKind::Void) [[unlikely]] {
|
|
423
|
-
ThrowError<Napi::TypeError>(env, "Cannot make array of empty or incomplete type");
|
|
424
|
-
return nullptr;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (len > instance->config.max_type_size / type->size) {
|
|
428
|
-
ThrowError<Napi::TypeError>(env, "Array length is too high (max = %1)", instance->config.max_type_size / type->size);
|
|
429
|
-
return nullptr;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
type = MakeArrayType(instance, type, len);
|
|
433
|
-
K_ASSERT(type);
|
|
434
|
-
} else {
|
|
435
|
-
K_ASSERT(!len);
|
|
436
|
-
|
|
437
|
-
type = MakePointerType(instance, type);
|
|
438
|
-
K_ASSERT(type);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
return type;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *ref, int count)
|
|
446
|
-
{
|
|
447
|
-
K_ASSERT(count >= 1);
|
|
448
|
-
|
|
449
|
-
for (int i = 0; i < count; i++) {
|
|
450
|
-
char name_buf[256];
|
|
451
|
-
Fmt(name_buf, "%1%2*", ref->name, EndsWith(ref->name, "*") ? "" : " ");
|
|
452
|
-
|
|
453
|
-
bool inserted;
|
|
454
|
-
auto bucket = instance->types_map.InsertOrGetDefault(name_buf, &inserted);
|
|
455
|
-
|
|
456
|
-
if (inserted) {
|
|
457
|
-
TypeInfo *type = instance->types.AppendDefault();
|
|
458
|
-
|
|
459
|
-
type->name = DuplicateString(name_buf, &instance->str_alloc).ptr;
|
|
460
|
-
|
|
461
|
-
if (ref->primitive != PrimitiveKind::Prototype) {
|
|
462
|
-
type->primitive = PrimitiveKind::Pointer;
|
|
463
|
-
type->size = K_SIZE(void *);
|
|
464
|
-
type->align = K_SIZE(void *);
|
|
465
|
-
type->ref.type = ref;
|
|
466
|
-
type->ref.stride = ref->size;
|
|
467
|
-
type->hint = (ref->flags & (int)TypeFlag::HasTypedArray) ? ArrayHint::Typed : ArrayHint::Array;
|
|
468
|
-
} else {
|
|
469
|
-
type->primitive = PrimitiveKind::Callback;
|
|
470
|
-
type->size = K_SIZE(void *);
|
|
471
|
-
type->align = K_SIZE(void *);
|
|
472
|
-
type->ref.type = instance->void_type; // Dummy
|
|
473
|
-
type->proto = ref->proto;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
bucket->key = type->name;
|
|
477
|
-
bucket->value = type;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
ref = bucket->value;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
return (TypeInfo *)ref;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
static TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, ArrayHint hint, bool insert)
|
|
487
|
-
{
|
|
488
|
-
K_ASSERT(len >= 0);
|
|
489
|
-
K_ASSERT(len <= instance->config.max_type_size / ref->size);
|
|
490
|
-
|
|
491
|
-
TypeInfo *type = instance->types.AppendDefault();
|
|
492
|
-
|
|
493
|
-
type->name = Fmt(&instance->str_alloc, "%1[%2]", ref->name, len).ptr;
|
|
494
|
-
|
|
495
|
-
type->primitive = PrimitiveKind::Array;
|
|
496
|
-
type->align = ref->align;
|
|
497
|
-
type->size = (int32_t)(len * ref->size);
|
|
498
|
-
type->ref.type = ref;
|
|
499
|
-
type->ref.stride = ref->size;
|
|
500
|
-
type->hint = hint;
|
|
501
|
-
|
|
502
|
-
if (insert) {
|
|
503
|
-
bool inserted;
|
|
504
|
-
type = (TypeInfo *)*instance->types_map.InsertOrGet(type->name, type, &inserted);
|
|
505
|
-
instance->types.RemoveLast(!inserted);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
return type;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len)
|
|
512
|
-
{
|
|
513
|
-
ArrayHint hint = {};
|
|
514
|
-
|
|
515
|
-
if (ref->flags & (int)TypeFlag::IsCharLike) {
|
|
516
|
-
hint = ArrayHint::String;
|
|
517
|
-
} else if (ref->flags & (int)TypeFlag::HasTypedArray) {
|
|
518
|
-
hint = ArrayHint::Typed;
|
|
519
|
-
} else {
|
|
520
|
-
hint = ArrayHint::Array;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
return MakeArrayType(instance, ref, len, hint, true);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, ArrayHint hint)
|
|
527
|
-
{
|
|
528
|
-
return MakeArrayType(instance, ref, len, hint, false);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
Napi::Value WrapType(Napi::Env env, const TypeInfo *type, bool freeze)
|
|
532
|
-
{
|
|
533
|
-
if (type->defn.IsEmpty()) {
|
|
534
|
-
#if defined(EXTERNAL_TYPES)
|
|
535
|
-
Napi::Object defn = Napi::Object::New(env);
|
|
536
|
-
#else
|
|
537
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
538
|
-
|
|
539
|
-
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
|
|
540
|
-
Napi::Object defn = instance->construct_type.New({ external });
|
|
541
|
-
SetValueTag(env, defn, &TypeObjectMarker);
|
|
542
|
-
#endif
|
|
543
|
-
|
|
544
|
-
defn.Set("name", Napi::String::New(env, type->name));
|
|
545
|
-
defn.Set("primitive", PrimitiveKindNames[(int)type->primitive]);
|
|
546
|
-
defn.Set("size", Napi::Number::New(env, (double)type->size));
|
|
547
|
-
defn.Set("alignment", Napi::Number::New(env, (double)type->align));
|
|
548
|
-
defn.Set("disposable", Napi::Boolean::New(env, !!type->dispose));
|
|
549
|
-
|
|
550
|
-
// Assign before to avoid possible recursion crash
|
|
551
|
-
type->defn = Napi::Persistent(defn);
|
|
552
|
-
|
|
553
|
-
switch (type->primitive) {
|
|
554
|
-
case PrimitiveKind::Void:
|
|
555
|
-
case PrimitiveKind::Bool:
|
|
556
|
-
case PrimitiveKind::Int8:
|
|
557
|
-
case PrimitiveKind::UInt8:
|
|
558
|
-
case PrimitiveKind::Int16:
|
|
559
|
-
case PrimitiveKind::Int16S:
|
|
560
|
-
case PrimitiveKind::UInt16:
|
|
561
|
-
case PrimitiveKind::UInt16S:
|
|
562
|
-
case PrimitiveKind::Int32:
|
|
563
|
-
case PrimitiveKind::Int32S:
|
|
564
|
-
case PrimitiveKind::UInt32:
|
|
565
|
-
case PrimitiveKind::UInt32S:
|
|
566
|
-
case PrimitiveKind::Int64:
|
|
567
|
-
case PrimitiveKind::Int64S:
|
|
568
|
-
case PrimitiveKind::UInt64:
|
|
569
|
-
case PrimitiveKind::UInt64S:
|
|
570
|
-
case PrimitiveKind::String:
|
|
571
|
-
case PrimitiveKind::String16:
|
|
572
|
-
case PrimitiveKind::String32:
|
|
573
|
-
case PrimitiveKind::Float32:
|
|
574
|
-
case PrimitiveKind::Float64: {} break;
|
|
575
|
-
|
|
576
|
-
case PrimitiveKind::Array: {
|
|
577
|
-
uint32_t len = type->size / type->ref.type->size;
|
|
578
|
-
defn.Set("length", Napi::Number::New(env, (double)len));
|
|
579
|
-
defn.Set("hint", ArrayHintNames[(int)type->hint]);
|
|
580
|
-
} [[fallthrough]];
|
|
581
|
-
case PrimitiveKind::Pointer: {
|
|
582
|
-
Napi::Value value = WrapType(env, type->ref.type);
|
|
583
|
-
defn.Set("ref", value);
|
|
584
|
-
} break;
|
|
585
|
-
case PrimitiveKind::Record:
|
|
586
|
-
case PrimitiveKind::Union: {
|
|
587
|
-
Napi::Object members = Napi::Object::New(env);
|
|
588
|
-
|
|
589
|
-
for (const RecordMember &member: type->members) {
|
|
590
|
-
Napi::Object obj = Napi::Object::New(env);
|
|
591
|
-
|
|
592
|
-
obj.Set("name", member.name);
|
|
593
|
-
obj.Set("type", WrapType(env, member.type));
|
|
594
|
-
obj.Set("offset", member.offset);
|
|
595
|
-
|
|
596
|
-
members.Set(member.name, obj);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
members.Freeze();
|
|
600
|
-
defn.Set("members", members);
|
|
601
|
-
} break;
|
|
602
|
-
|
|
603
|
-
case PrimitiveKind::Prototype:
|
|
604
|
-
case PrimitiveKind::Callback: {
|
|
605
|
-
defn.Set("proto", DescribeFunction(env, type->proto));
|
|
606
|
-
} break;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
if (freeze) {
|
|
610
|
-
defn.Freeze();
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
#if defined(EXTERNAL_TYPES)
|
|
615
|
-
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
|
|
616
|
-
SetValueTag(env, external, &TypeObjectMarker);
|
|
617
|
-
|
|
618
|
-
return external;
|
|
619
|
-
#else
|
|
620
|
-
return type->defn.Value();
|
|
621
|
-
#endif
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
const TypeInfo *ReshapeType(InstanceData *instance, const TypeInfo *type, int32_t stride, uint16_t flags)
|
|
625
|
-
{
|
|
626
|
-
K_ASSERT(!type->defn.IsEmpty());
|
|
627
|
-
|
|
628
|
-
if (!type->reshaped) {
|
|
629
|
-
TypeInfo *reshaped = nullptr;
|
|
630
|
-
|
|
631
|
-
switch (type->primitive) {
|
|
632
|
-
case PrimitiveKind::Record: {
|
|
633
|
-
reshaped = instance->types.AppendDefault();
|
|
634
|
-
|
|
635
|
-
memcpy((void *)reshaped, (const void *)type, K_SIZE(*type));
|
|
636
|
-
memset((void *)&reshaped->members, 0, K_SIZE(reshaped->members));
|
|
637
|
-
reshaped->members.Reserve(type->members.len);
|
|
638
|
-
reshaped->size = 0;
|
|
639
|
-
reshaped->flags |= flags;
|
|
640
|
-
memset((void *)&reshaped->defn, 0, K_SIZE(reshaped->defn));
|
|
641
|
-
|
|
642
|
-
Napi::Object defn = type->defn.Value();
|
|
643
|
-
reshaped->defn = Napi::Persistent(defn);
|
|
644
|
-
|
|
645
|
-
for (RecordMember member: type->members) {
|
|
646
|
-
member.offset = reshaped->size;
|
|
647
|
-
member.type = ReshapeType(instance, member.type, stride, flags);
|
|
648
|
-
|
|
649
|
-
reshaped->members.Append(member);
|
|
650
|
-
reshaped->size += AlignLen(member.type->size, stride);
|
|
651
|
-
}
|
|
652
|
-
} break;
|
|
653
|
-
|
|
654
|
-
case PrimitiveKind::Array: {
|
|
655
|
-
reshaped = instance->types.AppendDefault();
|
|
656
|
-
|
|
657
|
-
memcpy((void *)reshaped, (const void *)type, K_SIZE(*type));
|
|
658
|
-
reshaped->ref.stride = stride;
|
|
659
|
-
reshaped->size = (type->size / type->ref.stride) * stride;
|
|
660
|
-
memset((void *)&reshaped->defn, 0, K_SIZE(reshaped->defn));
|
|
661
|
-
reshaped->flags |= flags;
|
|
662
|
-
|
|
663
|
-
Napi::Object defn = type->defn.Value();
|
|
664
|
-
reshaped->defn = Napi::Persistent(defn);
|
|
665
|
-
} break;
|
|
666
|
-
|
|
667
|
-
default: { reshaped = (TypeInfo *)type; } break;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
type->reshaped = reshaped;
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
return type->reshaped;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
bool CanPassType(const TypeInfo *type, int directions)
|
|
677
|
-
{
|
|
678
|
-
if (type->countedby)
|
|
679
|
-
return false;
|
|
680
|
-
|
|
681
|
-
if (directions & 2) {
|
|
682
|
-
if (type->primitive == PrimitiveKind::Pointer)
|
|
683
|
-
return true;
|
|
684
|
-
if (type->primitive == PrimitiveKind::String)
|
|
685
|
-
return true;
|
|
686
|
-
if (type->primitive == PrimitiveKind::String16)
|
|
687
|
-
return true;
|
|
688
|
-
if (type->primitive == PrimitiveKind::String32)
|
|
689
|
-
return true;
|
|
690
|
-
|
|
691
|
-
return false;
|
|
692
|
-
} else {
|
|
693
|
-
if (type->primitive == PrimitiveKind::Void)
|
|
694
|
-
return false;
|
|
695
|
-
if (type->primitive == PrimitiveKind::Array)
|
|
696
|
-
return false;
|
|
697
|
-
if (type->primitive == PrimitiveKind::Prototype)
|
|
698
|
-
return false;
|
|
699
|
-
if (type->primitive == PrimitiveKind::Callback && type->proto->variadic)
|
|
700
|
-
return false;
|
|
701
|
-
|
|
702
|
-
return true;
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
bool CanReturnType(const TypeInfo *type)
|
|
707
|
-
{
|
|
708
|
-
if (type->countedby)
|
|
709
|
-
return false;
|
|
710
|
-
|
|
711
|
-
if (type->primitive == PrimitiveKind::Void && !TestStr(type->name, "void"))
|
|
712
|
-
return false;
|
|
713
|
-
if (type->primitive == PrimitiveKind::Array)
|
|
714
|
-
return false;
|
|
715
|
-
if (type->primitive == PrimitiveKind::Prototype)
|
|
716
|
-
return false;
|
|
717
|
-
|
|
718
|
-
return true;
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
bool CanStoreType(const TypeInfo *type)
|
|
722
|
-
{
|
|
723
|
-
if (type->primitive == PrimitiveKind::Void)
|
|
724
|
-
return false;
|
|
725
|
-
if (type->primitive == PrimitiveKind::Prototype)
|
|
726
|
-
return false;
|
|
727
|
-
if (type->primitive == PrimitiveKind::Callback && type->proto->variadic)
|
|
728
|
-
return false;
|
|
729
|
-
|
|
730
|
-
return true;
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
const char *GetValueType(const InstanceData *instance, napi_value value)
|
|
734
|
-
{
|
|
735
|
-
Napi::Env env = instance->env;
|
|
736
|
-
napi_valuetype kind = GetKindOf(env, value);
|
|
737
|
-
|
|
738
|
-
if (kind == napi_external) {
|
|
739
|
-
if (CheckValueTag(env, value, &CastMarker)) {
|
|
740
|
-
Napi::External<ValueCast> external = Napi::External<ValueCast>(env, value);
|
|
741
|
-
ValueCast *cast = external.Data();
|
|
742
|
-
|
|
743
|
-
return cast->type->name;
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
if (CheckValueTag(env, value, &LibraryHandleMarker))
|
|
747
|
-
return "LibraryHandle";
|
|
748
|
-
if (CheckValueTag(env, value, &TypeObjectMarker))
|
|
749
|
-
return "TypeObject";
|
|
750
|
-
|
|
751
|
-
if (CheckValueTag(env, value, &UnionValueMarker)) {
|
|
752
|
-
UnionValue *u = nullptr;
|
|
753
|
-
napi_unwrap(env, value, (void **)&u);
|
|
754
|
-
|
|
755
|
-
return u->GetType()->name;
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
for (const TypeInfo &type: instance->types) {
|
|
759
|
-
if (type.ref.type && CheckValueTag(env, value, type.ref.type))
|
|
760
|
-
return type.name;
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
if (IsArray(env, value)) {
|
|
765
|
-
return "Array";
|
|
766
|
-
} else if (IsTypedArray(env, value)) {
|
|
767
|
-
Napi::TypedArray array = Napi::TypedArray(env, value);
|
|
768
|
-
|
|
769
|
-
switch (array.TypedArrayType()) {
|
|
770
|
-
case napi_int8_array: return "Int8Array";
|
|
771
|
-
case napi_uint8_array: return "Uint8Array";
|
|
772
|
-
case napi_uint8_clamped_array: return "Uint8ClampedArray";
|
|
773
|
-
case napi_int16_array: return "Int16Array";
|
|
774
|
-
case napi_uint16_array: return "Uint16Array";
|
|
775
|
-
case napi_int32_array: return "Int32Array";
|
|
776
|
-
case napi_uint32_array: return "Uint32Array";
|
|
777
|
-
case napi_float16_array: return "Float16Array";
|
|
778
|
-
case napi_float32_array: return "Float32Array";
|
|
779
|
-
case napi_float64_array: return "Float64Array";
|
|
780
|
-
case napi_bigint64_array: return "BigInt64Array";
|
|
781
|
-
case napi_biguint64_array: return "BigUint64Array";
|
|
782
|
-
}
|
|
783
|
-
} else if (IsArrayBuffer(env, value)) {
|
|
784
|
-
return "ArrayBuffer";
|
|
785
|
-
} else if (IsBuffer(env, value)) {
|
|
786
|
-
return "Buffer";
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
switch (kind) {
|
|
790
|
-
case napi_undefined: return "Undefined";
|
|
791
|
-
case napi_null: return "Null";
|
|
792
|
-
case napi_boolean: return "Boolean";
|
|
793
|
-
case napi_number: return "Number";
|
|
794
|
-
case napi_string: return "String";
|
|
795
|
-
case napi_symbol: return "Symbol";
|
|
796
|
-
case napi_object: return "Object";
|
|
797
|
-
case napi_function: return "Function";
|
|
798
|
-
case napi_external: return "External";
|
|
799
|
-
case napi_bigint: return "BigInt";
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
// This should not be possible, but who knows...
|
|
803
|
-
return "Unknown";
|
|
804
|
-
}
|
|
805
|
-
|
|
806
111
|
void SetValueTag(napi_env env, napi_value value, const void *marker)
|
|
807
112
|
{
|
|
808
113
|
static_assert(K_SIZE(TypeInfo) >= 16);
|
|
@@ -818,8 +123,7 @@ void SetValueTag(napi_env env, napi_value value, const void *marker)
|
|
|
818
123
|
// and the few other markers we use, such as CastMarker, are actual const napi_type_tag structs.
|
|
819
124
|
const napi_type_tag *tag = (const napi_type_tag *)marker;
|
|
820
125
|
|
|
821
|
-
|
|
822
|
-
K_ASSERT(status == napi_ok);
|
|
126
|
+
NAPI_OK(napi_type_tag_object(env, value, tag));
|
|
823
127
|
}
|
|
824
128
|
|
|
825
129
|
bool CheckValueTag(napi_env env, napi_value value, const void *marker)
|
|
@@ -834,18 +138,6 @@ bool CheckValueTag(napi_env env, napi_value value, const void *marker)
|
|
|
834
138
|
return match;
|
|
835
139
|
}
|
|
836
140
|
|
|
837
|
-
void DeleteReferenceSafe(napi_env env, napi_ref ref)
|
|
838
|
-
{
|
|
839
|
-
if (node_api_post_finalizer) {
|
|
840
|
-
node_api_post_finalizer(env, [](napi_env env, void *data, void *) {
|
|
841
|
-
napi_ref ref = (napi_ref)data;
|
|
842
|
-
napi_delete_reference(env, ref);
|
|
843
|
-
}, (void *)ref, nullptr);
|
|
844
|
-
} else {
|
|
845
|
-
napi_delete_reference(env, ref);
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
|
|
849
141
|
int GetTypedArrayType(const TypeInfo *type)
|
|
850
142
|
{
|
|
851
143
|
switch (type->primitive) {
|
|
@@ -864,7 +156,7 @@ int GetTypedArrayType(const TypeInfo *type)
|
|
|
864
156
|
K_UNREACHABLE();
|
|
865
157
|
}
|
|
866
158
|
|
|
867
|
-
|
|
159
|
+
static FORCE_INLINE napi_value NewStringUTF32(Napi::Env env, const char32_t *ptr, Size len)
|
|
868
160
|
{
|
|
869
161
|
static const char16_t ReplacementChar = 0xFFFD;
|
|
870
162
|
|
|
@@ -890,8 +182,30 @@ Napi::String MakeStringFromUTF32(Napi::Env env, const char32_t *ptr, Size len)
|
|
|
890
182
|
}
|
|
891
183
|
}
|
|
892
184
|
|
|
893
|
-
|
|
894
|
-
|
|
185
|
+
return NewString(env, buf.ptr, buf.len);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
napi_value NewString(Napi::Env env, const char32_t *ptr, Size len)
|
|
189
|
+
{
|
|
190
|
+
if (ptr) {
|
|
191
|
+
return NewStringUTF32(env, ptr, len);
|
|
192
|
+
} else {
|
|
193
|
+
napi_value value;
|
|
194
|
+
NAPI_OK(napi_get_null(env, &value));
|
|
195
|
+
return value;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
napi_value NewString(Napi::Env env, const char32_t *ptr)
|
|
200
|
+
{
|
|
201
|
+
if (ptr) {
|
|
202
|
+
Size len = NullTerminatedLength(ptr);
|
|
203
|
+
return NewStringUTF32(env, ptr, len);
|
|
204
|
+
} else {
|
|
205
|
+
napi_value value;
|
|
206
|
+
NAPI_OK(napi_get_null(env, &value));
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
895
209
|
}
|
|
896
210
|
|
|
897
211
|
static uint32_t DecodeDynamicLength(const uint8_t *origin, const RecordMember &by)
|
|
@@ -1076,25 +390,25 @@ static FORCE_INLINE void DecodeObject(InstanceData *instance, const uint8_t *ori
|
|
|
1076
390
|
case PrimitiveKind::String: {
|
|
1077
391
|
const char *str;
|
|
1078
392
|
memcpy(&str, src, K_SIZE(void *));
|
|
1079
|
-
set(i, member,
|
|
393
|
+
set(i, member, NewString(env, str));
|
|
1080
394
|
|
|
1081
395
|
if (member.type->dispose) {
|
|
1082
|
-
member.type->dispose(
|
|
396
|
+
member.type->dispose(instance, member.type, str);
|
|
1083
397
|
}
|
|
1084
398
|
} break;
|
|
1085
399
|
case PrimitiveKind::String16: {
|
|
1086
400
|
const char16_t *str16;
|
|
1087
401
|
memcpy(&str16, src, K_SIZE(void *));
|
|
1088
|
-
set(i, member,
|
|
402
|
+
set(i, member, NewString(env, str16));
|
|
1089
403
|
|
|
1090
404
|
if (member.type->dispose) {
|
|
1091
|
-
member.type->dispose(
|
|
405
|
+
member.type->dispose(instance, member.type, str16);
|
|
1092
406
|
}
|
|
1093
407
|
} break;
|
|
1094
408
|
case PrimitiveKind::String32: {
|
|
1095
409
|
const char32_t *str32;
|
|
1096
410
|
memcpy(&str32, src, K_SIZE(void *));
|
|
1097
|
-
set(i, member,
|
|
411
|
+
set(i, member, NewString(env, str32));
|
|
1098
412
|
} break;
|
|
1099
413
|
case PrimitiveKind::Pointer: {
|
|
1100
414
|
void *ptr2;
|
|
@@ -1107,23 +421,23 @@ static FORCE_INLINE void DecodeObject(InstanceData *instance, const uint8_t *ori
|
|
|
1107
421
|
napi_value value = DecodeArray(instance, (const uint8_t *)ptr2, member.type, len);
|
|
1108
422
|
set(i, member, value);
|
|
1109
423
|
} else {
|
|
1110
|
-
napi_value p =
|
|
424
|
+
napi_value p = WrapPointer(env, member.type->ref.type, ptr2);
|
|
1111
425
|
set(i, member, p);
|
|
1112
426
|
}
|
|
1113
427
|
|
|
1114
428
|
if (member.type->dispose) {
|
|
1115
|
-
member.type->dispose(
|
|
429
|
+
member.type->dispose(instance, member.type, ptr2);
|
|
1116
430
|
}
|
|
1117
431
|
} break;
|
|
1118
432
|
case PrimitiveKind::Callback: {
|
|
1119
433
|
void *ptr2;
|
|
1120
434
|
memcpy(&ptr2, src, K_SIZE(void *));
|
|
1121
435
|
|
|
1122
|
-
napi_value p =
|
|
436
|
+
napi_value p = WrapPointer(env, member.type->ref.type, ptr2);
|
|
1123
437
|
set(i, member, p);
|
|
1124
438
|
|
|
1125
439
|
if (member.type->dispose) {
|
|
1126
|
-
member.type->dispose(
|
|
440
|
+
member.type->dispose(instance, member.type, ptr2);
|
|
1127
441
|
}
|
|
1128
442
|
} break;
|
|
1129
443
|
case PrimitiveKind::Record:
|
|
@@ -1151,12 +465,12 @@ static FORCE_INLINE void DecodeObject(InstanceData *instance, const uint8_t *ori
|
|
|
1151
465
|
case PrimitiveKind::Float32: {
|
|
1152
466
|
float f;
|
|
1153
467
|
memcpy(&f, src, 4);
|
|
1154
|
-
set(i, member,
|
|
468
|
+
set(i, member, NewFloat(env, f));
|
|
1155
469
|
} break;
|
|
1156
470
|
case PrimitiveKind::Float64: {
|
|
1157
471
|
double d;
|
|
1158
472
|
memcpy(&d, src, 8);
|
|
1159
|
-
set(i, member,
|
|
473
|
+
set(i, member, NewFloat(env, d));
|
|
1160
474
|
} break;
|
|
1161
475
|
|
|
1162
476
|
case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
|
|
@@ -1170,8 +484,16 @@ napi_value DecodeObject(InstanceData *instance, const uint8_t *origin, const Typ
|
|
|
1170
484
|
|
|
1171
485
|
// We can't decode unions because we don't know which member is valid
|
|
1172
486
|
if (type->primitive == PrimitiveKind::Union) {
|
|
487
|
+
Napi::Function construct;
|
|
488
|
+
{
|
|
489
|
+
napi_value value;
|
|
490
|
+
NAPI_OK(napi_get_reference_value(env, type->construct, &value));
|
|
491
|
+
|
|
492
|
+
construct = Napi::Function(env, value);
|
|
493
|
+
}
|
|
494
|
+
|
|
1173
495
|
Napi::External<void> external = Napi::External<void>::New(env, (void *)origin);
|
|
1174
|
-
Napi::Object wrapper =
|
|
496
|
+
Napi::Object wrapper = construct.New({ external }).As<Napi::Object>();
|
|
1175
497
|
SetValueTag(env, wrapper, &UnionValueMarker);
|
|
1176
498
|
|
|
1177
499
|
return wrapper;
|
|
@@ -1183,15 +505,12 @@ napi_value DecodeObject(InstanceData *instance, const uint8_t *origin, const Typ
|
|
|
1183
505
|
napi_value values[256];
|
|
1184
506
|
|
|
1185
507
|
DecodeObject(instance, origin, type, [&](Size i, const RecordMember &member, napi_value value) {
|
|
1186
|
-
|
|
1187
|
-
K_ASSERT(status == napi_ok);
|
|
1188
|
-
|
|
508
|
+
NAPI_OK(napi_get_reference_value(env, member.key, &properties[i]));
|
|
1189
509
|
values[i] = value;
|
|
1190
510
|
});
|
|
1191
511
|
|
|
1192
512
|
napi_value obj;
|
|
1193
|
-
|
|
1194
|
-
K_ASSERT(status == napi_ok);
|
|
513
|
+
NAPI_OK(node_api_create_object_with_properties(env, instance->object_constructor.Value(), properties, values, type->members.len, &obj));
|
|
1195
514
|
|
|
1196
515
|
return obj;
|
|
1197
516
|
}
|
|
@@ -1207,17 +526,15 @@ void DecodeObject(InstanceData *instance, napi_value obj, const uint8_t *origin,
|
|
|
1207
526
|
Napi::Env env = instance->env;
|
|
1208
527
|
|
|
1209
528
|
if (node_api_create_property_key_utf8) {
|
|
1210
|
-
DecodeObject(instance, origin, type, [&](Size
|
|
529
|
+
DecodeObject(instance, origin, type, [&](Size, const RecordMember &member, napi_value value) {
|
|
1211
530
|
napi_value key = nullptr;
|
|
1212
531
|
napi_get_reference_value(env, member.key, &key);
|
|
1213
532
|
|
|
1214
|
-
|
|
1215
|
-
K_ASSERT(status == napi_ok);
|
|
533
|
+
NAPI_OK(napi_set_property(env, obj, key, value));
|
|
1216
534
|
});
|
|
1217
535
|
} else {
|
|
1218
|
-
DecodeObject(instance, origin, type, [&](Size
|
|
1219
|
-
|
|
1220
|
-
K_ASSERT(status == napi_ok);
|
|
536
|
+
DecodeObject(instance, origin, type, [&](Size, const RecordMember &member, napi_value value) {
|
|
537
|
+
NAPI_OK(napi_set_named_property(env, obj, member.name, value));
|
|
1221
538
|
});
|
|
1222
539
|
}
|
|
1223
540
|
}
|
|
@@ -1241,27 +558,32 @@ napi_value DecodeArray(InstanceData *instance, const uint8_t *origin, const Type
|
|
|
1241
558
|
if (type->hint == ArrayHint::Typed) {
|
|
1242
559
|
#define POP_TYPEDARRAY(TypedArrayType, CType) \
|
|
1243
560
|
do { \
|
|
1244
|
-
|
|
1245
|
-
|
|
561
|
+
napi_value buffer = nullptr; \
|
|
562
|
+
napi_value array = nullptr; \
|
|
563
|
+
void *data; \
|
|
1246
564
|
\
|
|
1247
|
-
|
|
565
|
+
NAPI_OK(napi_create_arraybuffer(env, (size_t)len * K_SIZE(CType), &data, &buffer)); \
|
|
566
|
+
NAPI_OK(napi_create_typedarray(env, (TypedArrayType), (size_t)len, buffer, 0, &array)); \
|
|
567
|
+
\
|
|
568
|
+
Span<uint8_t> view = MakeSpan((uint8_t *)data, (Size)len * K_SIZE(CType)); \
|
|
569
|
+
DecodeBuffer(view, origin, type); \
|
|
1248
570
|
\
|
|
1249
571
|
return array; \
|
|
1250
572
|
} while (false)
|
|
1251
573
|
|
|
1252
574
|
switch (ref->primitive) {
|
|
1253
|
-
case PrimitiveKind::Int8: { POP_TYPEDARRAY(
|
|
1254
|
-
case PrimitiveKind::UInt8: { POP_TYPEDARRAY(
|
|
1255
|
-
case PrimitiveKind::Int16: { POP_TYPEDARRAY(
|
|
1256
|
-
case PrimitiveKind::Int16S: { POP_TYPEDARRAY(
|
|
1257
|
-
case PrimitiveKind::UInt16: { POP_TYPEDARRAY(
|
|
1258
|
-
case PrimitiveKind::UInt16S: { POP_TYPEDARRAY(
|
|
1259
|
-
case PrimitiveKind::Int32: { POP_TYPEDARRAY(
|
|
1260
|
-
case PrimitiveKind::Int32S: { POP_TYPEDARRAY(
|
|
1261
|
-
case PrimitiveKind::UInt32: { POP_TYPEDARRAY(
|
|
1262
|
-
case PrimitiveKind::UInt32S: { POP_TYPEDARRAY(
|
|
1263
|
-
case PrimitiveKind::Float32: { POP_TYPEDARRAY(
|
|
1264
|
-
case PrimitiveKind::Float64: { POP_TYPEDARRAY(
|
|
575
|
+
case PrimitiveKind::Int8: { POP_TYPEDARRAY(napi_int8_array, int8_t); } break;
|
|
576
|
+
case PrimitiveKind::UInt8: { POP_TYPEDARRAY(napi_uint8_array, uint8_t); } break;
|
|
577
|
+
case PrimitiveKind::Int16: { POP_TYPEDARRAY(napi_int16_array, int16_t); } break;
|
|
578
|
+
case PrimitiveKind::Int16S: { POP_TYPEDARRAY(napi_int16_array, int16_t); } break;
|
|
579
|
+
case PrimitiveKind::UInt16: { POP_TYPEDARRAY(napi_uint16_array, uint16_t); } break;
|
|
580
|
+
case PrimitiveKind::UInt16S: { POP_TYPEDARRAY(napi_uint16_array, uint16_t); } break;
|
|
581
|
+
case PrimitiveKind::Int32: { POP_TYPEDARRAY(napi_int32_array, int32_t); } break;
|
|
582
|
+
case PrimitiveKind::Int32S: { POP_TYPEDARRAY(napi_int32_array, int32_t); } break;
|
|
583
|
+
case PrimitiveKind::UInt32: { POP_TYPEDARRAY(napi_uint32_array, uint32_t); } break;
|
|
584
|
+
case PrimitiveKind::UInt32S: { POP_TYPEDARRAY(napi_uint32_array, uint32_t); } break;
|
|
585
|
+
case PrimitiveKind::Float32: { POP_TYPEDARRAY(napi_float32_array, float); } break;
|
|
586
|
+
case PrimitiveKind::Float64: { POP_TYPEDARRAY(napi_float64_array, double); } break;
|
|
1265
587
|
|
|
1266
588
|
case PrimitiveKind::Void:
|
|
1267
589
|
case PrimitiveKind::Bool:
|
|
@@ -1281,6 +603,16 @@ napi_value DecodeArray(InstanceData *instance, const uint8_t *origin, const Type
|
|
|
1281
603
|
}
|
|
1282
604
|
|
|
1283
605
|
#undef POP_TYPEDARRAY
|
|
606
|
+
} else if (type->hint == ArrayHint::Buffer) {
|
|
607
|
+
napi_value buffer;
|
|
608
|
+
void *data;
|
|
609
|
+
|
|
610
|
+
NAPI_OK(napi_create_buffer(env, (size_t)len * ref->size, &data, &buffer));
|
|
611
|
+
|
|
612
|
+
Span<uint8_t> view = MakeSpan((uint8_t *)data, (Size)len * ref->size);
|
|
613
|
+
DecodeBuffer(view, origin, type);
|
|
614
|
+
|
|
615
|
+
return buffer;
|
|
1284
616
|
} else if (type->hint == ArrayHint::String) {
|
|
1285
617
|
K_ASSERT(stride == ref->size);
|
|
1286
618
|
|
|
@@ -1289,22 +621,19 @@ napi_value DecodeArray(InstanceData *instance, const uint8_t *origin, const Type
|
|
|
1289
621
|
const char *ptr = (const char *)origin;
|
|
1290
622
|
size_t count = strnlen(ptr, (size_t)len);
|
|
1291
623
|
|
|
1292
|
-
|
|
1293
|
-
return str;
|
|
624
|
+
return NewString(env, ptr, count);
|
|
1294
625
|
} break;
|
|
1295
626
|
case PrimitiveKind::Int16: {
|
|
1296
627
|
const char16_t *ptr = (const char16_t *)origin;
|
|
1297
628
|
Size count = NullTerminatedLength(ptr, len);
|
|
1298
629
|
|
|
1299
|
-
|
|
1300
|
-
return str;
|
|
630
|
+
return NewString(env, ptr, count);
|
|
1301
631
|
} break;
|
|
1302
632
|
case PrimitiveKind::Int32: {
|
|
1303
633
|
const char32_t *ptr = (const char32_t *)origin;
|
|
1304
634
|
Size count = NullTerminatedLength(ptr, len);
|
|
1305
635
|
|
|
1306
|
-
|
|
1307
|
-
return str;
|
|
636
|
+
return NewString(env, ptr, count);
|
|
1308
637
|
} break;
|
|
1309
638
|
|
|
1310
639
|
case PrimitiveKind::Void:
|
|
@@ -1404,30 +733,30 @@ void DecodeElements(InstanceData *instance, napi_value array, const uint8_t *ori
|
|
|
1404
733
|
case PrimitiveKind::String: {
|
|
1405
734
|
POP_ARRAY({
|
|
1406
735
|
const char *str = *(const char **)src;
|
|
1407
|
-
napi_set_element(env, array, i,
|
|
736
|
+
napi_set_element(env, array, i, NewString(env, str));
|
|
1408
737
|
|
|
1409
738
|
if (ref->dispose) {
|
|
1410
|
-
ref->dispose(
|
|
739
|
+
ref->dispose(instance, ref, str);
|
|
1411
740
|
}
|
|
1412
741
|
});
|
|
1413
742
|
} break;
|
|
1414
743
|
case PrimitiveKind::String16: {
|
|
1415
744
|
POP_ARRAY({
|
|
1416
745
|
const char16_t *str16 = *(const char16_t **)src;
|
|
1417
|
-
napi_set_element(env, array, i,
|
|
746
|
+
napi_set_element(env, array, i, NewString(env, str16));
|
|
1418
747
|
|
|
1419
748
|
if (ref->dispose) {
|
|
1420
|
-
ref->dispose(
|
|
749
|
+
ref->dispose(instance, ref, str16);
|
|
1421
750
|
}
|
|
1422
751
|
});
|
|
1423
752
|
} break;
|
|
1424
753
|
case PrimitiveKind::String32: {
|
|
1425
754
|
POP_ARRAY({
|
|
1426
755
|
const char32_t *str32 = *(const char32_t **)src;
|
|
1427
|
-
napi_set_element(env, array, i,
|
|
756
|
+
napi_set_element(env, array, i, NewString(env, str32));
|
|
1428
757
|
|
|
1429
758
|
if (ref->dispose) {
|
|
1430
|
-
ref->dispose(
|
|
759
|
+
ref->dispose(instance, ref, str32);
|
|
1431
760
|
}
|
|
1432
761
|
});
|
|
1433
762
|
} break;
|
|
@@ -1435,11 +764,11 @@ void DecodeElements(InstanceData *instance, napi_value array, const uint8_t *ori
|
|
|
1435
764
|
POP_ARRAY({
|
|
1436
765
|
void *ptr2 = *(void **)src;
|
|
1437
766
|
|
|
1438
|
-
napi_value p =
|
|
767
|
+
napi_value p = WrapPointer(env, ref->ref.type, ptr2);
|
|
1439
768
|
napi_set_element(env, array, i, p);
|
|
1440
769
|
|
|
1441
770
|
if (ref->dispose) {
|
|
1442
|
-
ref->dispose(
|
|
771
|
+
ref->dispose(instance, ref, ptr2);
|
|
1443
772
|
}
|
|
1444
773
|
});
|
|
1445
774
|
} break;
|
|
@@ -1447,11 +776,11 @@ void DecodeElements(InstanceData *instance, napi_value array, const uint8_t *ori
|
|
|
1447
776
|
POP_ARRAY({
|
|
1448
777
|
void *ptr2 = *(void **)src;
|
|
1449
778
|
|
|
1450
|
-
napi_value p =
|
|
779
|
+
napi_value p = WrapPointer(env, ref->ref.type, ptr2);
|
|
1451
780
|
napi_set_element(env, array, i, p);
|
|
1452
781
|
|
|
1453
782
|
if (ref->dispose) {
|
|
1454
|
-
ref->dispose(
|
|
783
|
+
ref->dispose(instance, ref, ptr2);
|
|
1455
784
|
}
|
|
1456
785
|
});
|
|
1457
786
|
} break;
|
|
@@ -1473,7 +802,7 @@ void DecodeElements(InstanceData *instance, napi_value array, const uint8_t *ori
|
|
|
1473
802
|
float f;
|
|
1474
803
|
memcpy(&f, src, 4);
|
|
1475
804
|
|
|
1476
|
-
napi_set_element(env, array, i,
|
|
805
|
+
napi_set_element(env, array, i, NewFloat(env, f));
|
|
1477
806
|
});
|
|
1478
807
|
} break;
|
|
1479
808
|
case PrimitiveKind::Float64: {
|
|
@@ -1481,7 +810,7 @@ void DecodeElements(InstanceData *instance, napi_value array, const uint8_t *ori
|
|
|
1481
810
|
double d;
|
|
1482
811
|
memcpy(&d, src, 8);
|
|
1483
812
|
|
|
1484
|
-
napi_set_element(env, array, i,
|
|
813
|
+
napi_set_element(env, array, i, NewFloat(env, d));
|
|
1485
814
|
});
|
|
1486
815
|
} break;
|
|
1487
816
|
|
|
@@ -1534,80 +863,10 @@ void DecodeBuffer(Span<uint8_t> buffer, const uint8_t *origin, const TypeInfo *t
|
|
|
1534
863
|
#undef SWAP
|
|
1535
864
|
}
|
|
1536
865
|
|
|
1537
|
-
napi_value Decode(
|
|
1538
|
-
{
|
|
1539
|
-
Napi::Env env = value.Env();
|
|
1540
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1541
|
-
|
|
1542
|
-
const uint8_t *src = nullptr;
|
|
1543
|
-
|
|
1544
|
-
if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
|
|
1545
|
-
if (offset < 0) [[unlikely]] {
|
|
1546
|
-
ThrowError<Napi::Error>(env, "Offset must be >= 0");
|
|
1547
|
-
return env.Null();
|
|
1548
|
-
}
|
|
1549
|
-
if (buffer.len - offset < type->size) [[unlikely]] {
|
|
1550
|
-
ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
|
|
1551
|
-
type->name, type->size + offset);
|
|
1552
|
-
return env.Null();
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1555
|
-
src = (const uint8_t *)buffer.ptr;
|
|
1556
|
-
} else if (void *ptr = nullptr; TryPointer(env, value, &ptr)) {
|
|
1557
|
-
src = (const uint8_t *)ptr;
|
|
1558
|
-
} else {
|
|
1559
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for variable, expected pointer", GetValueType(instance, value));
|
|
1560
|
-
return env.Null();
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
if (!src)
|
|
1564
|
-
return env.Null();
|
|
1565
|
-
src += offset;
|
|
1566
|
-
|
|
1567
|
-
return Decode(instance, src, type, len);
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
napi_value Decode(InstanceData *instance, const uint8_t *ptr, const TypeInfo *type, const Size *len)
|
|
866
|
+
napi_value Decode(InstanceData *instance, const uint8_t *ptr, const TypeInfo *type)
|
|
1571
867
|
{
|
|
1572
868
|
Napi::Env env = instance->env;
|
|
1573
869
|
|
|
1574
|
-
if (len && type->primitive != PrimitiveKind::String &&
|
|
1575
|
-
type->primitive != PrimitiveKind::String16 &&
|
|
1576
|
-
type->primitive != PrimitiveKind::String32 &&
|
|
1577
|
-
type->primitive != PrimitiveKind::Prototype) {
|
|
1578
|
-
if (*len >= 0) {
|
|
1579
|
-
type = MakeArrayType(instance, type, *len);
|
|
1580
|
-
} else {
|
|
1581
|
-
switch (type->primitive) {
|
|
1582
|
-
case PrimitiveKind::Int8:
|
|
1583
|
-
case PrimitiveKind::UInt8: {
|
|
1584
|
-
Size count = strlen((const char *)ptr);
|
|
1585
|
-
type = MakeArrayType(instance, type, count);
|
|
1586
|
-
} break;
|
|
1587
|
-
case PrimitiveKind::Int16:
|
|
1588
|
-
case PrimitiveKind::UInt16: {
|
|
1589
|
-
Size count = NullTerminatedLength((const char16_t *)ptr);
|
|
1590
|
-
type = MakeArrayType(instance, type, count);
|
|
1591
|
-
} break;
|
|
1592
|
-
case PrimitiveKind::Int32:
|
|
1593
|
-
case PrimitiveKind::UInt32: {
|
|
1594
|
-
Size count = NullTerminatedLength((const char32_t *)ptr);
|
|
1595
|
-
type = MakeArrayType(instance, type, count);
|
|
1596
|
-
} break;
|
|
1597
|
-
|
|
1598
|
-
case PrimitiveKind::Pointer: {
|
|
1599
|
-
Size count = NullTerminatedLength((const void **)ptr);
|
|
1600
|
-
type = MakeArrayType(instance, type, count);
|
|
1601
|
-
} break;
|
|
1602
|
-
|
|
1603
|
-
default: {
|
|
1604
|
-
ThrowError<Napi::TypeError>(env, "Cannot determine null-terminated length for type %1", type->name);
|
|
1605
|
-
return env.Null();
|
|
1606
|
-
} break;
|
|
1607
|
-
}
|
|
1608
|
-
}
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
870
|
#define RETURN_INT(Type, NewCall) \
|
|
1612
871
|
do { \
|
|
1613
872
|
Type v = *(Type *)ptr; \
|
|
@@ -1644,39 +903,24 @@ napi_value Decode(InstanceData *instance, const uint8_t *ptr, const TypeInfo *ty
|
|
|
1644
903
|
case PrimitiveKind::UInt64: { RETURN_INT(uint64_t, NewInt); } break;
|
|
1645
904
|
case PrimitiveKind::UInt64S: { RETURN_INT_SWAP(uint64_t, NewInt); } break;
|
|
1646
905
|
case PrimitiveKind::String: {
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
return str ? Napi::String::New(env, str, *len) : env.Null();
|
|
1650
|
-
} else {
|
|
1651
|
-
const char *str = *(const char **)ptr;
|
|
1652
|
-
return str ? Napi::String::New(env, str) : env.Null();
|
|
1653
|
-
}
|
|
906
|
+
const char *str = *(const char **)ptr;
|
|
907
|
+
return NewString(env, str);
|
|
1654
908
|
} break;
|
|
1655
909
|
case PrimitiveKind::String16: {
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
return str16 ? Napi::String::New(env, str16, *len) : env.Null();
|
|
1659
|
-
} else {
|
|
1660
|
-
const char16_t *str16 = *(const char16_t **)ptr;
|
|
1661
|
-
return str16 ? Napi::String::New(env, str16) : env.Null();
|
|
1662
|
-
}
|
|
910
|
+
const char16_t *str16 = *(const char16_t **)ptr;
|
|
911
|
+
return NewString(env, str16);
|
|
1663
912
|
} break;
|
|
1664
913
|
case PrimitiveKind::String32: {
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
return str32 ? MakeStringFromUTF32(env, str32, *len) : env.Null();
|
|
1668
|
-
} else {
|
|
1669
|
-
const char32_t *str32 = *(const char32_t **)ptr;
|
|
1670
|
-
return str32 ? MakeStringFromUTF32(env, str32) : env.Null();
|
|
1671
|
-
}
|
|
914
|
+
const char32_t *str32 = *(const char32_t **)ptr;
|
|
915
|
+
return NewString(env, str32);
|
|
1672
916
|
} break;
|
|
1673
917
|
case PrimitiveKind::Pointer: {
|
|
1674
918
|
void *ptr2 = *(void **)ptr;
|
|
1675
|
-
return
|
|
919
|
+
return WrapPointer(env, type->ref.type, ptr2);
|
|
1676
920
|
} break;
|
|
1677
921
|
case PrimitiveKind::Callback: {
|
|
1678
922
|
void *ptr2 = *(void **)ptr;
|
|
1679
|
-
return
|
|
923
|
+
return WrapPointer(env, type->ref.type, ptr2);
|
|
1680
924
|
} break;
|
|
1681
925
|
case PrimitiveKind::Record:
|
|
1682
926
|
case PrimitiveKind::Union: { return DecodeObject(instance, ptr, type); } break;
|
|
@@ -1688,13 +932,13 @@ napi_value Decode(InstanceData *instance, const uint8_t *ptr, const TypeInfo *ty
|
|
|
1688
932
|
float f;
|
|
1689
933
|
memcpy(&f, ptr, 4);
|
|
1690
934
|
|
|
1691
|
-
return
|
|
935
|
+
return NewFloat(env, f);
|
|
1692
936
|
} break;
|
|
1693
937
|
case PrimitiveKind::Float64: {
|
|
1694
938
|
double d;
|
|
1695
939
|
memcpy(&d, ptr, 8);
|
|
1696
940
|
|
|
1697
|
-
return
|
|
941
|
+
return NewFloat(env, d);
|
|
1698
942
|
} break;
|
|
1699
943
|
|
|
1700
944
|
case PrimitiveKind::Prototype: {
|
|
@@ -1716,7 +960,7 @@ napi_value Decode(InstanceData *instance, const uint8_t *ptr, const TypeInfo *ty
|
|
|
1716
960
|
func->sync = proto->sync;
|
|
1717
961
|
func->async = proto->async;
|
|
1718
962
|
|
|
1719
|
-
return WrapFunction(
|
|
963
|
+
return WrapFunction(instance, func);
|
|
1720
964
|
} break;
|
|
1721
965
|
}
|
|
1722
966
|
|
|
@@ -1726,335 +970,6 @@ napi_value Decode(InstanceData *instance, const uint8_t *ptr, const TypeInfo *ty
|
|
|
1726
970
|
return env.Null();
|
|
1727
971
|
}
|
|
1728
972
|
|
|
1729
|
-
bool Encode(Napi::Value ref, Size offset, Napi::Value value, const TypeInfo *type, const Size *len)
|
|
1730
|
-
{
|
|
1731
|
-
Napi::Env env = ref.Env();
|
|
1732
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1733
|
-
|
|
1734
|
-
uint8_t *dest = nullptr;
|
|
1735
|
-
|
|
1736
|
-
if (Span<uint8_t> buffer = {}; TryBuffer(env, ref, &buffer)) {
|
|
1737
|
-
if (offset < 0) [[unlikely]] {
|
|
1738
|
-
ThrowError<Napi::Error>(env, "Offset must be >= 0");
|
|
1739
|
-
return env.Null();
|
|
1740
|
-
}
|
|
1741
|
-
if (buffer.len - offset < type->size) [[unlikely]] {
|
|
1742
|
-
ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
|
|
1743
|
-
type->name, type->size + offset);
|
|
1744
|
-
return env.Null();
|
|
1745
|
-
}
|
|
1746
|
-
|
|
1747
|
-
dest = (uint8_t *)buffer.ptr;
|
|
1748
|
-
} else if (void *ptr = nullptr; TryPointer(env, ref, &ptr)) {
|
|
1749
|
-
dest = (uint8_t *)ptr;
|
|
1750
|
-
} else {
|
|
1751
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for reference, expected pointer", GetValueType(instance, ref));
|
|
1752
|
-
return env.Null();
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
if (!dest) [[unlikely]] {
|
|
1756
|
-
ThrowError<Napi::Error>(env, "Cannot encode data in NULL pointer");
|
|
1757
|
-
return env.Null();
|
|
1758
|
-
}
|
|
1759
|
-
dest += offset;
|
|
1760
|
-
|
|
1761
|
-
return Encode(instance, dest, value, type, len);
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
|
-
bool Encode(InstanceData *instance, uint8_t *origin, Napi::Value value, const TypeInfo *type, const Size *len)
|
|
1765
|
-
{
|
|
1766
|
-
Napi::Env env = instance->env;
|
|
1767
|
-
|
|
1768
|
-
if (len && type->primitive != PrimitiveKind::String &&
|
|
1769
|
-
type->primitive != PrimitiveKind::String16 &&
|
|
1770
|
-
type->primitive != PrimitiveKind::String32 &&
|
|
1771
|
-
type->primitive != PrimitiveKind::Prototype) {
|
|
1772
|
-
if (*len < 0) [[unlikely]] {
|
|
1773
|
-
ThrowError<Napi::TypeError>(env, "Automatic (negative) length is only supported when decoding");
|
|
1774
|
-
return env.Null();
|
|
1775
|
-
}
|
|
1776
|
-
|
|
1777
|
-
type = MakeArrayType(instance, type, *len);
|
|
1778
|
-
}
|
|
1779
|
-
|
|
1780
|
-
InstanceMemory mem = {};
|
|
1781
|
-
CallData call(env, instance, &mem, nullptr);
|
|
1782
|
-
|
|
1783
|
-
#define PUSH_INTEGER(CType) \
|
|
1784
|
-
do { \
|
|
1785
|
-
CType v; \
|
|
1786
|
-
if (!TryNumber(env, value, &v)) [[unlikely]] { \
|
|
1787
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
1788
|
-
return false; \
|
|
1789
|
-
} \
|
|
1790
|
-
\
|
|
1791
|
-
*(CType *)origin = v; \
|
|
1792
|
-
} while (false)
|
|
1793
|
-
#define PUSH_INTEGER_SWAP(CType) \
|
|
1794
|
-
do { \
|
|
1795
|
-
CType v; \
|
|
1796
|
-
if (!TryNumber(env, value, &v)) [[unlikely]] { \
|
|
1797
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
1798
|
-
return false; \
|
|
1799
|
-
} \
|
|
1800
|
-
\
|
|
1801
|
-
*(CType *)origin = ReverseBytes(v); \
|
|
1802
|
-
} while (false)
|
|
1803
|
-
|
|
1804
|
-
switch (type->primitive) {
|
|
1805
|
-
case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
|
|
1806
|
-
|
|
1807
|
-
case PrimitiveKind::Bool: {
|
|
1808
|
-
bool b;
|
|
1809
|
-
napi_status status = napi_get_value_bool(env, value, &b);
|
|
1810
|
-
|
|
1811
|
-
if (status != napi_ok) [[unlikely]] {
|
|
1812
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
|
|
1813
|
-
return false;
|
|
1814
|
-
}
|
|
1815
|
-
|
|
1816
|
-
*(bool *)origin = b;
|
|
1817
|
-
} break;
|
|
1818
|
-
case PrimitiveKind::Int8: { PUSH_INTEGER(int8_t); } break;
|
|
1819
|
-
case PrimitiveKind::UInt8: { PUSH_INTEGER(uint8_t); } break;
|
|
1820
|
-
case PrimitiveKind::Int16: { PUSH_INTEGER(int16_t); } break;
|
|
1821
|
-
case PrimitiveKind::Int16S: { PUSH_INTEGER_SWAP(int16_t); } break;
|
|
1822
|
-
case PrimitiveKind::UInt16: { PUSH_INTEGER(uint16_t); } break;
|
|
1823
|
-
case PrimitiveKind::UInt16S: { PUSH_INTEGER_SWAP(uint16_t); } break;
|
|
1824
|
-
case PrimitiveKind::Int32: { PUSH_INTEGER(int32_t); } break;
|
|
1825
|
-
case PrimitiveKind::Int32S: { PUSH_INTEGER_SWAP(int32_t); } break;
|
|
1826
|
-
case PrimitiveKind::UInt32: { PUSH_INTEGER(uint32_t); } break;
|
|
1827
|
-
case PrimitiveKind::UInt32S: { PUSH_INTEGER_SWAP(uint32_t); } break;
|
|
1828
|
-
case PrimitiveKind::Int64: { PUSH_INTEGER(int64_t); } break;
|
|
1829
|
-
case PrimitiveKind::Int64S: { PUSH_INTEGER_SWAP(int64_t); } break;
|
|
1830
|
-
case PrimitiveKind::UInt64: { PUSH_INTEGER(uint64_t); } break;
|
|
1831
|
-
case PrimitiveKind::UInt64S: { PUSH_INTEGER_SWAP(uint64_t); } break;
|
|
1832
|
-
case PrimitiveKind::String: {
|
|
1833
|
-
const char *str;
|
|
1834
|
-
if (!call.PushString(value, 1, &str)) [[unlikely]]
|
|
1835
|
-
return false;
|
|
1836
|
-
*(const char **)origin = str;
|
|
1837
|
-
} break;
|
|
1838
|
-
case PrimitiveKind::String16: {
|
|
1839
|
-
const char16_t *str16;
|
|
1840
|
-
if (!call.PushString16(value, 1, &str16)) [[unlikely]]
|
|
1841
|
-
return false;
|
|
1842
|
-
*(const char16_t **)origin = str16;
|
|
1843
|
-
} break;
|
|
1844
|
-
case PrimitiveKind::String32: {
|
|
1845
|
-
const char32_t *str32;
|
|
1846
|
-
if (!call.PushString32(value, 1, &str32)) [[unlikely]]
|
|
1847
|
-
return false;
|
|
1848
|
-
*(const char32_t **)origin = str32;
|
|
1849
|
-
} break;
|
|
1850
|
-
case PrimitiveKind::Pointer: {
|
|
1851
|
-
void *ptr;
|
|
1852
|
-
if (!call.PushPointer(value, type, 1, &ptr)) [[unlikely]]
|
|
1853
|
-
return false;
|
|
1854
|
-
*(void **)origin = ptr;
|
|
1855
|
-
} break;
|
|
1856
|
-
case PrimitiveKind::Record:
|
|
1857
|
-
case PrimitiveKind::Union: {
|
|
1858
|
-
if (!IsObject(env, value)) [[unlikely]] {
|
|
1859
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
1860
|
-
return false;
|
|
1861
|
-
}
|
|
1862
|
-
|
|
1863
|
-
Napi::Object obj = value.As<Napi::Object>();
|
|
1864
|
-
|
|
1865
|
-
if (!call.PushObject(obj, type, origin))
|
|
1866
|
-
return false;
|
|
1867
|
-
} break;
|
|
1868
|
-
case PrimitiveKind::Array: {
|
|
1869
|
-
if (value.IsArray()) {
|
|
1870
|
-
Napi::Array array = Napi::Array(env, value);
|
|
1871
|
-
if (!call.PushNormalArray(array, type, type->size, origin))
|
|
1872
|
-
return false;
|
|
1873
|
-
} else if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
|
|
1874
|
-
call.PushBuffer(buffer, type, origin);
|
|
1875
|
-
} else if (value.IsString()) {
|
|
1876
|
-
if (!call.PushStringArray(value, type, origin))
|
|
1877
|
-
return false;
|
|
1878
|
-
} else {
|
|
1879
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected array", GetValueType(instance, value));
|
|
1880
|
-
return false;
|
|
1881
|
-
}
|
|
1882
|
-
} break;
|
|
1883
|
-
case PrimitiveKind::Float32: {
|
|
1884
|
-
float f;
|
|
1885
|
-
if (!TryNumber(env, value, &f)) [[unlikely]] {
|
|
1886
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
1887
|
-
return false;
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
memcpy(origin, &f, 4);
|
|
1891
|
-
} break;
|
|
1892
|
-
case PrimitiveKind::Float64: {
|
|
1893
|
-
double d;
|
|
1894
|
-
if (!TryNumber(env, value, &d)) [[unlikely]] {
|
|
1895
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
1896
|
-
return false;
|
|
1897
|
-
}
|
|
1898
|
-
|
|
1899
|
-
memcpy(origin, &d, 8);
|
|
1900
|
-
} break;
|
|
1901
|
-
case PrimitiveKind::Callback: {
|
|
1902
|
-
void *ptr;
|
|
1903
|
-
if (!TryPointer(env, value, &ptr)) [[unlikely]] {
|
|
1904
|
-
if (value.IsFunction()) {
|
|
1905
|
-
ThrowError<Napi::Error>(env, "Cannot encode non-registered callback");
|
|
1906
|
-
} else {
|
|
1907
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
|
|
1908
|
-
}
|
|
1909
|
-
return false;
|
|
1910
|
-
}
|
|
1911
|
-
|
|
1912
|
-
*(void **)origin = ptr;
|
|
1913
|
-
} break;
|
|
1914
|
-
|
|
1915
|
-
case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
|
|
1916
|
-
}
|
|
1917
|
-
|
|
1918
|
-
#undef PUSH_INTEGER_SWAP
|
|
1919
|
-
#undef PUSH_INTEGER
|
|
1920
|
-
|
|
1921
|
-
// Keep memory around if any was allocated
|
|
1922
|
-
if (mem.allocator.IsUsed()) {
|
|
1923
|
-
LinkedAllocator *copy = instance->encode_map.FindValue(origin, nullptr);
|
|
1924
|
-
|
|
1925
|
-
if (!copy) {
|
|
1926
|
-
copy = instance->encode_allocators.AppendDefault();
|
|
1927
|
-
instance->encode_map.Set(origin, copy);
|
|
1928
|
-
}
|
|
1929
|
-
|
|
1930
|
-
std::swap(mem.allocator, *copy);
|
|
1931
|
-
}
|
|
1932
|
-
|
|
1933
|
-
return true;
|
|
1934
|
-
}
|
|
1935
|
-
|
|
1936
|
-
static bool CanTypeAcceptCallbacks(const TypeInfo *type)
|
|
1937
|
-
{
|
|
1938
|
-
if (type->primitive == PrimitiveKind::Pointer)
|
|
1939
|
-
return true;
|
|
1940
|
-
if (type->primitive == PrimitiveKind::Callback)
|
|
1941
|
-
return true;
|
|
1942
|
-
|
|
1943
|
-
if (type->primitive == PrimitiveKind::Record ||
|
|
1944
|
-
type->primitive == PrimitiveKind::Union) {
|
|
1945
|
-
for (const RecordMember &member: type->members) {
|
|
1946
|
-
if (CanTypeAcceptCallbacks(member.type))
|
|
1947
|
-
return false;
|
|
1948
|
-
}
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
|
-
return true;
|
|
1952
|
-
}
|
|
1953
|
-
|
|
1954
|
-
static bool CanUseFastCall(const FunctionInfo *func)
|
|
1955
|
-
{
|
|
1956
|
-
if (func->parameters.len > 6)
|
|
1957
|
-
return false;
|
|
1958
|
-
|
|
1959
|
-
// Fast calls basically skip CallData::Finalize(), which handles output arguments
|
|
1960
|
-
// and temporary callback trampolines. If the function does not use any
|
|
1961
|
-
// output argument and cannot accept callbacks (so no pointer or callback arguments),
|
|
1962
|
-
// we can skip finalization!
|
|
1963
|
-
|
|
1964
|
-
for (const ParameterInfo ¶m: func->parameters) {
|
|
1965
|
-
if (param.directions & 2)
|
|
1966
|
-
return false;
|
|
1967
|
-
if (CanTypeAcceptCallbacks(param.type))
|
|
1968
|
-
return false;
|
|
1969
|
-
}
|
|
1970
|
-
|
|
1971
|
-
return true;
|
|
1972
|
-
}
|
|
1973
|
-
|
|
1974
|
-
Napi::Object DescribeFunction(Napi::Env env, const FunctionInfo *func)
|
|
1975
|
-
{
|
|
1976
|
-
static const char *const DirectionNames[] = {
|
|
1977
|
-
nullptr,
|
|
1978
|
-
"Input",
|
|
1979
|
-
"Output",
|
|
1980
|
-
"Input/Output"
|
|
1981
|
-
};
|
|
1982
|
-
|
|
1983
|
-
Napi::Object meta = Napi::Object::New(env);
|
|
1984
|
-
Napi::Array arguments = Napi::Array::New(env, func->parameters.len);
|
|
1985
|
-
|
|
1986
|
-
meta.Set("name", Napi::String::New(env, func->name));
|
|
1987
|
-
meta.Set("arguments", arguments);
|
|
1988
|
-
meta.Set("result", WrapType(env, func->ret.type));
|
|
1989
|
-
|
|
1990
|
-
for (Size i = 0; i < func->parameters.len; i++) {
|
|
1991
|
-
const ParameterInfo ¶m = func->parameters[i];
|
|
1992
|
-
Napi::Object obj = Napi::Object::New(env);
|
|
1993
|
-
|
|
1994
|
-
obj.Set("type", WrapType(env, param.type));
|
|
1995
|
-
obj.Set("direction", Napi::String::New(env, DirectionNames[param.directions]));
|
|
1996
|
-
|
|
1997
|
-
arguments.Set((uint32_t)i, obj);
|
|
1998
|
-
}
|
|
1999
|
-
|
|
2000
|
-
meta.Freeze();
|
|
2001
|
-
|
|
2002
|
-
return meta;
|
|
2003
|
-
}
|
|
2004
|
-
|
|
2005
|
-
static bool IsDebugAsyncEnabled()
|
|
2006
|
-
{
|
|
2007
|
-
static bool debug = GetDebugFlag("DEBUG_ASYNC");
|
|
2008
|
-
return debug;
|
|
2009
|
-
}
|
|
2010
|
-
|
|
2011
|
-
Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
2012
|
-
{
|
|
2013
|
-
Napi::Function wrapper;
|
|
2014
|
-
|
|
2015
|
-
// Pick appropriate wrapper
|
|
2016
|
-
{
|
|
2017
|
-
napi_value value;
|
|
2018
|
-
|
|
2019
|
-
if (func->variadic) {
|
|
2020
|
-
napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateVariadicCall, (void *)func->Ref(), &value);
|
|
2021
|
-
K_ASSERT(status == napi_ok);
|
|
2022
|
-
} else if (IsDebugAsyncEnabled()) {
|
|
2023
|
-
napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCallDebugAsync, (void *)func->Ref(), &value);
|
|
2024
|
-
K_ASSERT(status == napi_ok);
|
|
2025
|
-
} else if (!func->parameters.len) {
|
|
2026
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
2027
|
-
napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, instance->translate_zero_call, (void *)func->Ref(), &value);
|
|
2028
|
-
K_ASSERT(status == napi_ok);
|
|
2029
|
-
} else if (CanUseFastCall(func)) {
|
|
2030
|
-
napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateFastCall, (void *)func->Ref(), &value);
|
|
2031
|
-
K_ASSERT(status == napi_ok);
|
|
2032
|
-
} else {
|
|
2033
|
-
napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCall, (void *)func->Ref(), &value);
|
|
2034
|
-
K_ASSERT(status == napi_ok);
|
|
2035
|
-
}
|
|
2036
|
-
|
|
2037
|
-
wrapper = Napi::Function(env, value);
|
|
2038
|
-
wrapper.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
|
|
2039
|
-
}
|
|
2040
|
-
|
|
2041
|
-
if (!func->variadic) {
|
|
2042
|
-
napi_value value;
|
|
2043
|
-
napi_status status = napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateAsyncCall, (void *)func->Ref(), &value);
|
|
2044
|
-
K_ASSERT(status == napi_ok);
|
|
2045
|
-
|
|
2046
|
-
Napi::Function async = Napi::Function(env, value);
|
|
2047
|
-
async.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
|
|
2048
|
-
|
|
2049
|
-
wrapper.Set("async", async);
|
|
2050
|
-
}
|
|
2051
|
-
|
|
2052
|
-
Napi::Object meta = DescribeFunction(env, func);
|
|
2053
|
-
wrapper.Set("info", meta);
|
|
2054
|
-
|
|
2055
|
-
return wrapper;
|
|
2056
|
-
}
|
|
2057
|
-
|
|
2058
973
|
bool DetectCallConvention(Span<const char> name, CallConvention *out_convention)
|
|
2059
974
|
{
|
|
2060
975
|
if (name == "__cdecl") {
|