koffi 3.0.0 → 3.0.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 +20 -1
- package/README.md +5 -4
- package/cnoke.cjs +10 -10
- package/doc/benchmarks.md +24 -47
- package/doc/callbacks.md +4 -13
- package/doc/contribute.md +4 -4
- package/doc/index.md +3 -2
- package/doc/migration.md +100 -0
- package/doc/start.md +7 -5
- package/index.d.ts +53 -5
- package/index.js +2 -1
- package/indirect.js +2 -1
- package/package.json +20 -18
- package/src/koffi/CMakeLists.txt +20 -12
- package/src/koffi/index.cjs +92 -129
- package/src/koffi/index.js +128 -113
- package/src/koffi/indirect.cjs +91 -128
- package/src/koffi/indirect.js +129 -40
- package/src/koffi/src/abi/arm64.cc +30 -29
- package/src/koffi/src/abi/riscv64.cc +30 -29
- package/src/koffi/src/abi/x64sysv.cc +26 -25
- package/src/koffi/src/abi/x64win.cc +64 -63
- package/src/koffi/src/abi/x86.cc +67 -65
- package/src/koffi/src/call.cc +210 -99
- package/src/koffi/src/call.hh +2 -1
- package/src/koffi/src/ffi.cc +403 -237
- package/src/koffi/src/ffi.hh +46 -7
- package/src/koffi/src/parser.cc +3 -1
- package/src/koffi/src/primitives.inc +1 -4
- package/src/koffi/src/static.cjs +122 -0
- package/src/koffi/src/static.js +122 -0
- package/src/koffi/src/type.cc +715 -0
- package/src/koffi/src/type.hh +71 -0
- package/src/koffi/src/util.cc +189 -1120
- package/src/koffi/src/util.hh +85 -125
- package/src/koffi/src/uv.cc +16 -10
- package/src/koffi/src/uv.hh +2 -1
package/src/koffi/src/util.cc
CHANGED
|
@@ -4,49 +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
|
-
Napi::Function TypeObject::InitClass(Napi::Env env)
|
|
21
|
-
{
|
|
22
|
-
Napi::Function constructor = DefineClass(env, "TypeObject", {});
|
|
23
|
-
return constructor;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
TypeObject::TypeObject(const Napi::CallbackInfo &info)
|
|
27
|
-
: Napi::ObjectWrap<TypeObject>(info)
|
|
28
|
-
{
|
|
29
|
-
Napi::Env env = info.Env();
|
|
30
|
-
|
|
31
|
-
if (info.Length() < 1 || !info[0u].IsExternal()) [[unlikely]] {
|
|
32
|
-
ThrowError<Napi::Error>(env, "Type objects cannot be constructed manually");
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
Napi::External<TypeInfo> external = info[0u].As<Napi::External<TypeInfo>>();
|
|
37
|
-
type = external.Data();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
void TypeObject::Finalize(Napi::BasicEnv env)
|
|
41
|
-
{
|
|
42
|
-
DeleteReferenceSafe(env, *this);
|
|
43
|
-
SuppressDestruct();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
Napi::Function UnionValue::InitClass(Napi::Env env, const TypeInfo *type)
|
|
14
|
+
Napi::Function UnionValue::InitClass(InstanceData *instance, const TypeInfo *type)
|
|
47
15
|
{
|
|
48
16
|
K_ASSERT(type->primitive == PrimitiveKind::Union);
|
|
49
17
|
|
|
18
|
+
Napi::Env env = instance->env;
|
|
19
|
+
|
|
50
20
|
// node-addon-api wants std::vector
|
|
51
21
|
std::vector<Napi::ClassPropertyDescriptor<UnionValue>> properties;
|
|
52
22
|
properties.reserve(type->members.len);
|
|
@@ -69,6 +39,7 @@ UnionValue::UnionValue(const Napi::CallbackInfo &info)
|
|
|
69
39
|
: Napi::ObjectWrap<UnionValue>(info), type((const TypeInfo *)info.Data())
|
|
70
40
|
{
|
|
71
41
|
Napi::Env env = info.Env();
|
|
42
|
+
|
|
72
43
|
instance = env.GetInstanceData<InstanceData>();
|
|
73
44
|
|
|
74
45
|
if (info.Length() >= 1) {
|
|
@@ -104,7 +75,7 @@ Napi::Value UnionValue::Getter(const Napi::CallbackInfo &info)
|
|
|
104
75
|
Size idx = (Size)info.Data();
|
|
105
76
|
const RecordMember &member = type->members[idx];
|
|
106
77
|
|
|
107
|
-
|
|
78
|
+
napi_value value = nullptr;
|
|
108
79
|
|
|
109
80
|
if (idx == active_idx) {
|
|
110
81
|
value = Value().Get(instance->active_symbol.Value());
|
|
@@ -116,14 +87,14 @@ Napi::Value UnionValue::Getter(const Napi::CallbackInfo &info)
|
|
|
116
87
|
return env.Null();
|
|
117
88
|
}
|
|
118
89
|
|
|
119
|
-
value = Decode(
|
|
90
|
+
value = Decode(instance, raw.ptr, member.type);
|
|
120
91
|
|
|
121
92
|
Value().Set(instance->active_symbol.Value(), value);
|
|
122
93
|
active_idx = idx;
|
|
123
94
|
}
|
|
124
95
|
|
|
125
|
-
K_ASSERT(
|
|
126
|
-
return value;
|
|
96
|
+
K_ASSERT(value);
|
|
97
|
+
return Napi::Value(info.Env(), value);
|
|
127
98
|
}
|
|
128
99
|
|
|
129
100
|
void UnionValue::Setter(const Napi::CallbackInfo &info, const Napi::Value &value)
|
|
@@ -136,647 +107,6 @@ void UnionValue::Setter(const Napi::CallbackInfo &info, const Napi::Value &value
|
|
|
136
107
|
raw.Clear();
|
|
137
108
|
}
|
|
138
109
|
|
|
139
|
-
static inline bool IsIdentifierStart(char c)
|
|
140
|
-
{
|
|
141
|
-
return IsAsciiAlpha(c) || c == '_';
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
static inline bool IsIdentifierChar(char c)
|
|
145
|
-
{
|
|
146
|
-
return IsAsciiAlphaOrDigit(c) || c == '_';
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
static inline Span<const char> SplitIdentifier(Span<const char> str)
|
|
150
|
-
{
|
|
151
|
-
Size offset = 0;
|
|
152
|
-
|
|
153
|
-
if (str.len && IsIdentifierStart(str[0])) {
|
|
154
|
-
offset++;
|
|
155
|
-
|
|
156
|
-
while (offset < str.len && IsIdentifierChar(str[offset])) {
|
|
157
|
-
offset++;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
Span<const char> token = str.Take(0, offset);
|
|
162
|
-
return token;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
int ResolveDirections(Span<const char> str)
|
|
166
|
-
{
|
|
167
|
-
if (str == "_In_") {
|
|
168
|
-
return 1;
|
|
169
|
-
} else if (str == "_Out_") {
|
|
170
|
-
return 2;
|
|
171
|
-
} else if (str == "_Inout_") {
|
|
172
|
-
return 3;
|
|
173
|
-
} else {
|
|
174
|
-
return 0;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const TypeInfo *ResolveType(Napi::Value value, int *out_directions)
|
|
179
|
-
{
|
|
180
|
-
Napi::Env env = value.Env();
|
|
181
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
182
|
-
|
|
183
|
-
if (value.IsString()) {
|
|
184
|
-
std::string str = value.As<Napi::String>();
|
|
185
|
-
Span<const char> remain = str.c_str();
|
|
186
|
-
|
|
187
|
-
// Quick path for known types (int, float *, etc.)
|
|
188
|
-
const TypeInfo *type = instance->types_map.FindValue(remain.ptr, nullptr);
|
|
189
|
-
|
|
190
|
-
if (!type) {
|
|
191
|
-
if (out_directions) {
|
|
192
|
-
Span<const char> prefix = SplitIdentifier(remain);
|
|
193
|
-
int directions = ResolveDirections(prefix);
|
|
194
|
-
|
|
195
|
-
if (directions) {
|
|
196
|
-
remain = remain.Take(prefix.len, remain.len - prefix.len);
|
|
197
|
-
remain = TrimStrLeft(remain);
|
|
198
|
-
|
|
199
|
-
*out_directions = directions;
|
|
200
|
-
} else {
|
|
201
|
-
*out_directions = 1;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
type = ResolveType(env, remain.ptr);
|
|
206
|
-
|
|
207
|
-
if (!type) {
|
|
208
|
-
if (!env.IsExceptionPending()) {
|
|
209
|
-
ThrowError<Napi::TypeError>(env, "Unknown or invalid type name '%1'", str.c_str());
|
|
210
|
-
}
|
|
211
|
-
return nullptr;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Cache for quick future access
|
|
215
|
-
bool inserted;
|
|
216
|
-
auto bucket = instance->types_map.InsertOrGetDefault(remain.ptr, &inserted);
|
|
217
|
-
|
|
218
|
-
if (inserted) {
|
|
219
|
-
bucket->key = DuplicateString(remain, &instance->str_alloc).ptr;
|
|
220
|
-
bucket->value = type;
|
|
221
|
-
}
|
|
222
|
-
} else if (out_directions) {
|
|
223
|
-
*out_directions = 1;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return type;
|
|
227
|
-
} else {
|
|
228
|
-
napi_valuetype kind = GetKindOf(env, value);
|
|
229
|
-
|
|
230
|
-
if (kind == napi_external && CheckValueTag(env, value, &DirectionMarker)) {
|
|
231
|
-
Napi::External<TypeInfo> external = Napi::External<TypeInfo>(env, value);
|
|
232
|
-
const TypeInfo *raw = external.Data();
|
|
233
|
-
|
|
234
|
-
const TypeInfo *type = AlignDown(raw, 4);
|
|
235
|
-
K_ASSERT(type);
|
|
236
|
-
|
|
237
|
-
if (out_directions) {
|
|
238
|
-
Size delta = (uint8_t *)raw - (uint8_t *)type;
|
|
239
|
-
*out_directions = 1 + (int)delta;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return type;
|
|
243
|
-
} else if (kind == napi_object && CheckValueTag(env, value, &TypeObjectMarker)) {
|
|
244
|
-
TypeObject *defn = nullptr;
|
|
245
|
-
napi_unwrap(env, value, (void **)&defn);
|
|
246
|
-
|
|
247
|
-
if (out_directions) {
|
|
248
|
-
*out_directions = 1;
|
|
249
|
-
}
|
|
250
|
-
return defn->GetType();
|
|
251
|
-
} else {
|
|
252
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value as type specifier, expected string or type", GetValueType(instance, value));
|
|
253
|
-
return nullptr;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const TypeInfo *ResolveType(Napi::Env env, Span<const char> str)
|
|
259
|
-
{
|
|
260
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
261
|
-
|
|
262
|
-
// Each item can be > 0 for array or 0 for a pointer
|
|
263
|
-
LocalArray<Size, 8> arrays;
|
|
264
|
-
uint8_t disposables = 0;
|
|
265
|
-
|
|
266
|
-
Span<const char> name;
|
|
267
|
-
Span<const char> after;
|
|
268
|
-
{
|
|
269
|
-
Span<const char> remain = str;
|
|
270
|
-
|
|
271
|
-
// Skip initial const qualifiers
|
|
272
|
-
remain = TrimStrLeft(remain);
|
|
273
|
-
while (SplitIdentifier(remain) == "const") {
|
|
274
|
-
remain = remain.Take(6, remain.len - 6);
|
|
275
|
-
remain = TrimStrLeft(remain);
|
|
276
|
-
}
|
|
277
|
-
remain = TrimStrLeft(remain);
|
|
278
|
-
|
|
279
|
-
after = remain;
|
|
280
|
-
|
|
281
|
-
// Consume one or more identifiers (e.g. unsigned int)
|
|
282
|
-
for (;;) {
|
|
283
|
-
after = TrimStrLeft(after);
|
|
284
|
-
|
|
285
|
-
Span<const char> token = SplitIdentifier(after);
|
|
286
|
-
if (!token.len)
|
|
287
|
-
break;
|
|
288
|
-
after = after.Take(token.len, after.len - token.len);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
name = TrimStr(MakeSpan(remain.ptr, after.ptr - remain.ptr));
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// Consume type indirections (pointer, array, etc.)
|
|
295
|
-
while (after.len) {
|
|
296
|
-
if (after[0] == '*') {
|
|
297
|
-
after = after.Take(1, after.len - 1);
|
|
298
|
-
|
|
299
|
-
if (!arrays.Available()) [[unlikely]] {
|
|
300
|
-
ThrowError<Napi::Error>(env, "Too many type indirections");
|
|
301
|
-
return nullptr;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
arrays.Append(0);
|
|
305
|
-
} else if (after[0] == '!') {
|
|
306
|
-
after = after.Take(1, after.len - 1);
|
|
307
|
-
disposables |= (1u << arrays.len);
|
|
308
|
-
} else if (after[0] == '[') {
|
|
309
|
-
after = after.Take(1, after.len - 1);
|
|
310
|
-
|
|
311
|
-
Size len = 0;
|
|
312
|
-
|
|
313
|
-
after = TrimStrLeft(after);
|
|
314
|
-
if (!ParseInt(after, &len, 0, &after) || len < 0) [[unlikely]] {
|
|
315
|
-
ThrowError<Napi::Error>(env, "Invalid array length");
|
|
316
|
-
return nullptr;
|
|
317
|
-
}
|
|
318
|
-
after = TrimStrLeft(after);
|
|
319
|
-
if (!after.len || after[0] != ']') [[unlikely]] {
|
|
320
|
-
ThrowError<Napi::Error>(env, "Expected ']' after array length");
|
|
321
|
-
return nullptr;
|
|
322
|
-
}
|
|
323
|
-
after = after.Take(1, after.len - 1);
|
|
324
|
-
|
|
325
|
-
if (!arrays.Available()) [[unlikely]] {
|
|
326
|
-
ThrowError<Napi::Error>(env, "Too many type indirections");
|
|
327
|
-
return nullptr;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
arrays.Append(len);
|
|
331
|
-
} else if (SplitIdentifier(after) == "const") {
|
|
332
|
-
after = after.Take(6, after.len - 6);
|
|
333
|
-
} else {
|
|
334
|
-
after = TrimStrRight(after);
|
|
335
|
-
|
|
336
|
-
if (after.len) [[unlikely]] {
|
|
337
|
-
ThrowError<Napi::Error>(env, "Unexpected character '%1' in type specifier", after[0]);
|
|
338
|
-
return nullptr;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
break;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
after = TrimStrLeft(after);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const TypeInfo *type = instance->types_map.FindValue(name, nullptr);
|
|
348
|
-
|
|
349
|
-
if (!type) {
|
|
350
|
-
// Try with cleaned up spaces
|
|
351
|
-
if (name.len < 256) {
|
|
352
|
-
LocalArray<char, 256> buf;
|
|
353
|
-
for (Size i = 0; i < name.len; i++) {
|
|
354
|
-
char c = name[i];
|
|
355
|
-
|
|
356
|
-
if (IsAsciiWhite(c)) {
|
|
357
|
-
buf.Append(' ');
|
|
358
|
-
while (++i < name.len && IsAsciiWhite(name[i]));
|
|
359
|
-
i--;
|
|
360
|
-
} else {
|
|
361
|
-
buf.Append(c);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
type = instance->types_map.FindValue(buf, nullptr);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (!type)
|
|
369
|
-
return nullptr;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
for (int i = 0;; i++) {
|
|
373
|
-
if (disposables & (1u << i)) {
|
|
374
|
-
if (type->primitive != PrimitiveKind::Pointer &&
|
|
375
|
-
type->primitive != PrimitiveKind::String &&
|
|
376
|
-
type->primitive != PrimitiveKind::String16 &&
|
|
377
|
-
type->primitive != PrimitiveKind::String32) [[unlikely]] {
|
|
378
|
-
ThrowError<Napi::Error>(env, "Cannot create disposable type for non-pointer");
|
|
379
|
-
return nullptr;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
TypeInfo *copy = instance->types.AppendDefault();
|
|
383
|
-
|
|
384
|
-
memcpy((void *)copy, (const void *)type, K_SIZE(*type));
|
|
385
|
-
copy->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
|
|
386
|
-
copy->members.allocator = GetNullAllocator();
|
|
387
|
-
copy->members.allocator = GetNullAllocator();
|
|
388
|
-
memset((void *)©->defn, 0, K_SIZE(copy->defn));
|
|
389
|
-
|
|
390
|
-
static_assert(!std::is_polymorphic_v<Napi::ObjectReference>);
|
|
391
|
-
|
|
392
|
-
copy->dispose = [](Napi::Env env, const TypeInfo *, const void *ptr) {
|
|
393
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
394
|
-
|
|
395
|
-
free((void *)ptr);
|
|
396
|
-
instance->stats.disposed++;
|
|
397
|
-
};
|
|
398
|
-
|
|
399
|
-
type = copy;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (i >= arrays.len)
|
|
403
|
-
break;
|
|
404
|
-
Size len = arrays[i];
|
|
405
|
-
|
|
406
|
-
if (len > 0) {
|
|
407
|
-
if (type->primitive == PrimitiveKind::Void) [[unlikely]] {
|
|
408
|
-
ThrowError<Napi::TypeError>(env, "Cannot make array of empty or incomplete type");
|
|
409
|
-
return nullptr;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
if (len > instance->config.max_type_size / type->size) {
|
|
413
|
-
ThrowError<Napi::TypeError>(env, "Array length is too high (max = %1)", instance->config.max_type_size / type->size);
|
|
414
|
-
return nullptr;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
type = MakeArrayType(instance, type, len);
|
|
418
|
-
K_ASSERT(type);
|
|
419
|
-
} else {
|
|
420
|
-
K_ASSERT(!len);
|
|
421
|
-
|
|
422
|
-
type = MakePointerType(instance, type);
|
|
423
|
-
K_ASSERT(type);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
return type;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *ref, int count)
|
|
431
|
-
{
|
|
432
|
-
K_ASSERT(count >= 1);
|
|
433
|
-
|
|
434
|
-
for (int i = 0; i < count; i++) {
|
|
435
|
-
char name_buf[256];
|
|
436
|
-
Fmt(name_buf, "%1%2*", ref->name, EndsWith(ref->name, "*") ? "" : " ");
|
|
437
|
-
|
|
438
|
-
bool inserted;
|
|
439
|
-
auto bucket = instance->types_map.InsertOrGetDefault(name_buf, &inserted);
|
|
440
|
-
|
|
441
|
-
if (inserted) {
|
|
442
|
-
TypeInfo *type = instance->types.AppendDefault();
|
|
443
|
-
|
|
444
|
-
type->name = DuplicateString(name_buf, &instance->str_alloc).ptr;
|
|
445
|
-
|
|
446
|
-
if (ref->primitive != PrimitiveKind::Prototype) {
|
|
447
|
-
type->primitive = PrimitiveKind::Pointer;
|
|
448
|
-
type->size = K_SIZE(void *);
|
|
449
|
-
type->align = K_SIZE(void *);
|
|
450
|
-
type->ref.type = ref;
|
|
451
|
-
type->ref.stride = ref->size;
|
|
452
|
-
type->hint = (ref->flags & (int)TypeFlag::HasTypedArray) ? ArrayHint::Typed : ArrayHint::Array;
|
|
453
|
-
} else {
|
|
454
|
-
type->primitive = PrimitiveKind::Callback;
|
|
455
|
-
type->size = K_SIZE(void *);
|
|
456
|
-
type->align = K_SIZE(void *);
|
|
457
|
-
type->ref.type = instance->void_type; // Dummy
|
|
458
|
-
type->proto = ref->proto;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
bucket->key = type->name;
|
|
462
|
-
bucket->value = type;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
ref = bucket->value;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
return (TypeInfo *)ref;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
static TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, ArrayHint hint, bool insert)
|
|
472
|
-
{
|
|
473
|
-
K_ASSERT(len >= 0);
|
|
474
|
-
K_ASSERT(len <= instance->config.max_type_size / ref->size);
|
|
475
|
-
|
|
476
|
-
TypeInfo *type = instance->types.AppendDefault();
|
|
477
|
-
|
|
478
|
-
type->name = Fmt(&instance->str_alloc, "%1[%2]", ref->name, len).ptr;
|
|
479
|
-
|
|
480
|
-
type->primitive = PrimitiveKind::Array;
|
|
481
|
-
type->align = ref->align;
|
|
482
|
-
type->size = (int32_t)(len * ref->size);
|
|
483
|
-
type->ref.type = ref;
|
|
484
|
-
type->ref.stride = ref->size;
|
|
485
|
-
type->hint = hint;
|
|
486
|
-
|
|
487
|
-
if (insert) {
|
|
488
|
-
bool inserted;
|
|
489
|
-
type = (TypeInfo *)*instance->types_map.InsertOrGet(type->name, type, &inserted);
|
|
490
|
-
instance->types.RemoveLast(!inserted);
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
return type;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len)
|
|
497
|
-
{
|
|
498
|
-
ArrayHint hint = {};
|
|
499
|
-
|
|
500
|
-
if (ref->flags & (int)TypeFlag::IsCharLike) {
|
|
501
|
-
hint = ArrayHint::String;
|
|
502
|
-
} else if (ref->flags & (int)TypeFlag::HasTypedArray) {
|
|
503
|
-
hint = ArrayHint::Typed;
|
|
504
|
-
} else {
|
|
505
|
-
hint = ArrayHint::Array;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
return MakeArrayType(instance, ref, len, hint, true);
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, ArrayHint hint)
|
|
512
|
-
{
|
|
513
|
-
return MakeArrayType(instance, ref, len, hint, false);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
Napi::Object WrapType(Napi::Env env, const TypeInfo *type, bool freeze)
|
|
517
|
-
{
|
|
518
|
-
if (type->defn.IsEmpty()) {
|
|
519
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
520
|
-
|
|
521
|
-
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
|
|
522
|
-
Napi::Object defn = instance->construct_type.New({ external });
|
|
523
|
-
SetValueTag(env, defn, &TypeObjectMarker);
|
|
524
|
-
|
|
525
|
-
defn.Set("name", Napi::String::New(env, type->name));
|
|
526
|
-
defn.Set("primitive", PrimitiveKindNames[(int)type->primitive]);
|
|
527
|
-
defn.Set("size", Napi::Number::New(env, (double)type->size));
|
|
528
|
-
defn.Set("alignment", Napi::Number::New(env, (double)type->align));
|
|
529
|
-
defn.Set("disposable", Napi::Boolean::New(env, !!type->dispose));
|
|
530
|
-
|
|
531
|
-
// Assign before to avoid possible recursion crash
|
|
532
|
-
type->defn = Napi::Persistent(defn);
|
|
533
|
-
|
|
534
|
-
switch (type->primitive) {
|
|
535
|
-
case PrimitiveKind::Void:
|
|
536
|
-
case PrimitiveKind::Bool:
|
|
537
|
-
case PrimitiveKind::Int8:
|
|
538
|
-
case PrimitiveKind::UInt8:
|
|
539
|
-
case PrimitiveKind::Int16:
|
|
540
|
-
case PrimitiveKind::Int16S:
|
|
541
|
-
case PrimitiveKind::UInt16:
|
|
542
|
-
case PrimitiveKind::UInt16S:
|
|
543
|
-
case PrimitiveKind::Int32:
|
|
544
|
-
case PrimitiveKind::Int32S:
|
|
545
|
-
case PrimitiveKind::UInt32:
|
|
546
|
-
case PrimitiveKind::UInt32S:
|
|
547
|
-
case PrimitiveKind::Int64:
|
|
548
|
-
case PrimitiveKind::Int64S:
|
|
549
|
-
case PrimitiveKind::UInt64:
|
|
550
|
-
case PrimitiveKind::UInt64S:
|
|
551
|
-
case PrimitiveKind::String:
|
|
552
|
-
case PrimitiveKind::String16:
|
|
553
|
-
case PrimitiveKind::String32:
|
|
554
|
-
case PrimitiveKind::Float32:
|
|
555
|
-
case PrimitiveKind::Float64: {} break;
|
|
556
|
-
|
|
557
|
-
case PrimitiveKind::Array: {
|
|
558
|
-
uint32_t len = type->size / type->ref.type->size;
|
|
559
|
-
defn.Set("length", Napi::Number::New(env, (double)len));
|
|
560
|
-
defn.Set("hint", ArrayHintNames[(int)type->hint]);
|
|
561
|
-
} [[fallthrough]];
|
|
562
|
-
case PrimitiveKind::Pointer: {
|
|
563
|
-
Napi::Value value = WrapType(env, type->ref.type);
|
|
564
|
-
defn.Set("ref", value);
|
|
565
|
-
} break;
|
|
566
|
-
case PrimitiveKind::Record:
|
|
567
|
-
case PrimitiveKind::Union: {
|
|
568
|
-
Napi::Object members = Napi::Object::New(env);
|
|
569
|
-
|
|
570
|
-
for (const RecordMember &member: type->members) {
|
|
571
|
-
Napi::Object obj = Napi::Object::New(env);
|
|
572
|
-
|
|
573
|
-
obj.Set("name", member.name);
|
|
574
|
-
obj.Set("type", WrapType(env, member.type));
|
|
575
|
-
obj.Set("offset", member.offset);
|
|
576
|
-
|
|
577
|
-
members.Set(member.name, obj);
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
members.Freeze();
|
|
581
|
-
defn.Set("members", members);
|
|
582
|
-
} break;
|
|
583
|
-
|
|
584
|
-
case PrimitiveKind::Prototype:
|
|
585
|
-
case PrimitiveKind::Callback: {
|
|
586
|
-
defn.Set("proto", DescribeFunction(env, type->proto));
|
|
587
|
-
} break;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (freeze) {
|
|
591
|
-
defn.Freeze();
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
return type->defn.Value();
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const TypeInfo *ReshapeType(InstanceData *instance, const TypeInfo *type, int32_t stride, uint16_t flags)
|
|
599
|
-
{
|
|
600
|
-
K_ASSERT(!type->defn.IsEmpty());
|
|
601
|
-
|
|
602
|
-
if (!type->reshaped) {
|
|
603
|
-
TypeInfo *reshaped = nullptr;
|
|
604
|
-
|
|
605
|
-
switch (type->primitive) {
|
|
606
|
-
case PrimitiveKind::Record: {
|
|
607
|
-
reshaped = instance->types.AppendDefault();
|
|
608
|
-
|
|
609
|
-
memcpy((void *)reshaped, (const void *)type, K_SIZE(*type));
|
|
610
|
-
memset((void *)&reshaped->members, 0, K_SIZE(reshaped->members));
|
|
611
|
-
reshaped->members.Reserve(type->members.len);
|
|
612
|
-
reshaped->size = 0;
|
|
613
|
-
reshaped->flags |= flags;
|
|
614
|
-
memset((void *)&reshaped->defn, 0, K_SIZE(reshaped->defn));
|
|
615
|
-
|
|
616
|
-
Napi::Object defn = type->defn.Value();
|
|
617
|
-
reshaped->defn = Napi::Persistent(defn);
|
|
618
|
-
|
|
619
|
-
for (RecordMember member: type->members) {
|
|
620
|
-
member.offset = reshaped->size;
|
|
621
|
-
member.type = ReshapeType(instance, member.type, stride, flags);
|
|
622
|
-
|
|
623
|
-
reshaped->members.Append(member);
|
|
624
|
-
reshaped->size += AlignLen(member.type->size, stride);
|
|
625
|
-
}
|
|
626
|
-
} break;
|
|
627
|
-
|
|
628
|
-
case PrimitiveKind::Array: {
|
|
629
|
-
reshaped = instance->types.AppendDefault();
|
|
630
|
-
|
|
631
|
-
memcpy((void *)reshaped, (const void *)type, K_SIZE(*type));
|
|
632
|
-
reshaped->ref.stride = stride;
|
|
633
|
-
reshaped->size = (type->size / type->ref.stride) * stride;
|
|
634
|
-
memset((void *)&reshaped->defn, 0, K_SIZE(reshaped->defn));
|
|
635
|
-
reshaped->flags |= flags;
|
|
636
|
-
|
|
637
|
-
Napi::Object defn = type->defn.Value();
|
|
638
|
-
reshaped->defn = Napi::Persistent(defn);
|
|
639
|
-
} break;
|
|
640
|
-
|
|
641
|
-
default: { reshaped = (TypeInfo *)type; } break;
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
type->reshaped = reshaped;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
return type->reshaped;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
bool CanPassType(const TypeInfo *type, int directions)
|
|
651
|
-
{
|
|
652
|
-
if (type->countedby)
|
|
653
|
-
return false;
|
|
654
|
-
|
|
655
|
-
if (directions & 2) {
|
|
656
|
-
if (type->primitive == PrimitiveKind::Pointer)
|
|
657
|
-
return true;
|
|
658
|
-
if (type->primitive == PrimitiveKind::String)
|
|
659
|
-
return true;
|
|
660
|
-
if (type->primitive == PrimitiveKind::String16)
|
|
661
|
-
return true;
|
|
662
|
-
if (type->primitive == PrimitiveKind::String32)
|
|
663
|
-
return true;
|
|
664
|
-
|
|
665
|
-
return false;
|
|
666
|
-
} else {
|
|
667
|
-
if (type->primitive == PrimitiveKind::Void)
|
|
668
|
-
return false;
|
|
669
|
-
if (type->primitive == PrimitiveKind::Array)
|
|
670
|
-
return false;
|
|
671
|
-
if (type->primitive == PrimitiveKind::Prototype)
|
|
672
|
-
return false;
|
|
673
|
-
if (type->primitive == PrimitiveKind::Callback && type->proto->variadic)
|
|
674
|
-
return false;
|
|
675
|
-
|
|
676
|
-
return true;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
bool CanReturnType(const TypeInfo *type)
|
|
681
|
-
{
|
|
682
|
-
if (type->countedby)
|
|
683
|
-
return false;
|
|
684
|
-
|
|
685
|
-
if (type->primitive == PrimitiveKind::Void && !TestStr(type->name, "void"))
|
|
686
|
-
return false;
|
|
687
|
-
if (type->primitive == PrimitiveKind::Array)
|
|
688
|
-
return false;
|
|
689
|
-
if (type->primitive == PrimitiveKind::Prototype)
|
|
690
|
-
return false;
|
|
691
|
-
|
|
692
|
-
return true;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
bool CanStoreType(const TypeInfo *type)
|
|
696
|
-
{
|
|
697
|
-
if (type->primitive == PrimitiveKind::Void)
|
|
698
|
-
return false;
|
|
699
|
-
if (type->primitive == PrimitiveKind::Prototype)
|
|
700
|
-
return false;
|
|
701
|
-
if (type->primitive == PrimitiveKind::Callback && type->proto->variadic)
|
|
702
|
-
return false;
|
|
703
|
-
|
|
704
|
-
return true;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
const char *GetValueType(const InstanceData *instance, napi_value value)
|
|
708
|
-
{
|
|
709
|
-
Napi::Env env = instance->env;
|
|
710
|
-
napi_valuetype kind = GetKindOf(env, value);
|
|
711
|
-
|
|
712
|
-
if (kind == napi_external) {
|
|
713
|
-
if (CheckValueTag(env, value, &CastMarker)) {
|
|
714
|
-
Napi::External<ValueCast> external = Napi::External<ValueCast>(env, value);
|
|
715
|
-
ValueCast *cast = external.Data();
|
|
716
|
-
|
|
717
|
-
return cast->type->name;
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
if (CheckValueTag(env, value, &LibraryHandleMarker))
|
|
721
|
-
return "LibraryHandle";
|
|
722
|
-
if (CheckValueTag(env, value, &TypeObjectMarker))
|
|
723
|
-
return "TypeObject";
|
|
724
|
-
|
|
725
|
-
if (CheckValueTag(env, value, &UnionValueMarker)) {
|
|
726
|
-
UnionValue *u = nullptr;
|
|
727
|
-
napi_unwrap(env, value, (void **)&u);
|
|
728
|
-
|
|
729
|
-
return u->GetType()->name;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
for (const TypeInfo &type: instance->types) {
|
|
733
|
-
if (type.ref.type && CheckValueTag(env, value, type.ref.type))
|
|
734
|
-
return type.name;
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
if (IsArray(env, value)) {
|
|
739
|
-
return "Array";
|
|
740
|
-
} else if (IsTypedArray(env, value)) {
|
|
741
|
-
Napi::TypedArray array = Napi::TypedArray(env, value);
|
|
742
|
-
|
|
743
|
-
switch (array.TypedArrayType()) {
|
|
744
|
-
case napi_int8_array: return "Int8Array";
|
|
745
|
-
case napi_uint8_array: return "Uint8Array";
|
|
746
|
-
case napi_uint8_clamped_array: return "Uint8ClampedArray";
|
|
747
|
-
case napi_int16_array: return "Int16Array";
|
|
748
|
-
case napi_uint16_array: return "Uint16Array";
|
|
749
|
-
case napi_int32_array: return "Int32Array";
|
|
750
|
-
case napi_uint32_array: return "Uint32Array";
|
|
751
|
-
case napi_float16_array: return "Float16Array";
|
|
752
|
-
case napi_float32_array: return "Float32Array";
|
|
753
|
-
case napi_float64_array: return "Float64Array";
|
|
754
|
-
case napi_bigint64_array: return "BigInt64Array";
|
|
755
|
-
case napi_biguint64_array: return "BigUint64Array";
|
|
756
|
-
}
|
|
757
|
-
} else if (IsArrayBuffer(env, value)) {
|
|
758
|
-
return "ArrayBuffer";
|
|
759
|
-
} else if (IsBuffer(env, value)) {
|
|
760
|
-
return "Buffer";
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
switch (kind) {
|
|
764
|
-
case napi_undefined: return "Undefined";
|
|
765
|
-
case napi_null: return "Null";
|
|
766
|
-
case napi_boolean: return "Boolean";
|
|
767
|
-
case napi_number: return "Number";
|
|
768
|
-
case napi_string: return "String";
|
|
769
|
-
case napi_symbol: return "Symbol";
|
|
770
|
-
case napi_object: return "Object";
|
|
771
|
-
case napi_function: return "Function";
|
|
772
|
-
case napi_external: return "External";
|
|
773
|
-
case napi_bigint: return "BigInt";
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
// This should not be possible, but who knows...
|
|
777
|
-
return "Unknown";
|
|
778
|
-
}
|
|
779
|
-
|
|
780
110
|
void SetValueTag(napi_env env, napi_value value, const void *marker)
|
|
781
111
|
{
|
|
782
112
|
static_assert(K_SIZE(TypeInfo) >= 16);
|
|
@@ -792,8 +122,7 @@ void SetValueTag(napi_env env, napi_value value, const void *marker)
|
|
|
792
122
|
// and the few other markers we use, such as CastMarker, are actual const napi_type_tag structs.
|
|
793
123
|
const napi_type_tag *tag = (const napi_type_tag *)marker;
|
|
794
124
|
|
|
795
|
-
|
|
796
|
-
K_ASSERT(status == napi_ok);
|
|
125
|
+
NAPI_OK(napi_type_tag_object(env, value, tag));
|
|
797
126
|
}
|
|
798
127
|
|
|
799
128
|
bool CheckValueTag(napi_env env, napi_value value, const void *marker)
|
|
@@ -868,23 +197,6 @@ Napi::String MakeStringFromUTF32(Napi::Env env, const char32_t *ptr, Size len)
|
|
|
868
197
|
return str;
|
|
869
198
|
}
|
|
870
199
|
|
|
871
|
-
Napi::Object DecodeObject(Napi::Env env, const uint8_t *origin, const TypeInfo *type)
|
|
872
|
-
{
|
|
873
|
-
// We can't decode unions because we don't know which member is valid
|
|
874
|
-
if (type->primitive == PrimitiveKind::Union) {
|
|
875
|
-
Napi::External<void> external = Napi::External<void>::New(env, (void *)origin);
|
|
876
|
-
Napi::Object wrapper = type->construct.New({ external }).As<Napi::Object>();
|
|
877
|
-
SetValueTag(env, wrapper, &UnionValueMarker);
|
|
878
|
-
|
|
879
|
-
return wrapper;
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
Napi::Object obj = Napi::Object::New(env);
|
|
883
|
-
DecodeObject(env, obj, origin, type);
|
|
884
|
-
|
|
885
|
-
return obj;
|
|
886
|
-
}
|
|
887
|
-
|
|
888
200
|
static uint32_t DecodeDynamicLength(const uint8_t *origin, const RecordMember &by)
|
|
889
201
|
{
|
|
890
202
|
const uint8_t *src = origin + by.offset;
|
|
@@ -977,27 +289,16 @@ static uint32_t DecodeDynamicLength(const uint8_t *origin, const RecordMember &b
|
|
|
977
289
|
K_UNREACHABLE();
|
|
978
290
|
}
|
|
979
291
|
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
if (member.key) {
|
|
983
|
-
napi_value key = nullptr;
|
|
984
|
-
napi_get_reference_value(env, member.key, &key);
|
|
985
|
-
|
|
986
|
-
napi_status status = napi_set_property(env, obj, key, value);
|
|
987
|
-
K_ASSERT(status == napi_ok);
|
|
988
|
-
} else {
|
|
989
|
-
napi_status status = napi_set_named_property(env, obj, member.name, value);
|
|
990
|
-
K_ASSERT(status == napi_ok);
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
void DecodeObject(Napi::Env env, napi_value obj, const uint8_t *origin, const TypeInfo *type)
|
|
292
|
+
template <typename SetFunc>
|
|
293
|
+
static FORCE_INLINE void DecodeObject(InstanceData *instance, const uint8_t *origin, const TypeInfo *type, SetFunc set)
|
|
995
294
|
{
|
|
996
295
|
K_ASSERT(type->primitive == PrimitiveKind::Record);
|
|
997
296
|
|
|
297
|
+
Napi::Env env = instance->env;
|
|
998
298
|
Span<const RecordMember> members = type->members;
|
|
999
299
|
|
|
1000
|
-
for (
|
|
300
|
+
for (Size i = 0; i < members.len; i++) {
|
|
301
|
+
const RecordMember &member = members[i];
|
|
1001
302
|
const uint8_t *src = origin + member.offset;
|
|
1002
303
|
|
|
1003
304
|
switch (member.type->primitive) {
|
|
@@ -1005,80 +306,80 @@ void DecodeObject(Napi::Env env, napi_value obj, const uint8_t *origin, const Ty
|
|
|
1005
306
|
|
|
1006
307
|
case PrimitiveKind::Bool: {
|
|
1007
308
|
bool b = *(bool *)src;
|
|
1008
|
-
|
|
309
|
+
set(i, member, Napi::Boolean::New(env, b));
|
|
1009
310
|
} break;
|
|
1010
311
|
case PrimitiveKind::Int8: {
|
|
1011
|
-
int8_t
|
|
1012
|
-
|
|
312
|
+
int8_t v = *(int8_t *)src;
|
|
313
|
+
set(i, member, NewInt(env, v));
|
|
1013
314
|
} break;
|
|
1014
315
|
case PrimitiveKind::UInt8: {
|
|
1015
|
-
uint8_t
|
|
1016
|
-
|
|
316
|
+
uint8_t v = *(uint8_t *)src;
|
|
317
|
+
set(i, member, NewInt(env, v));
|
|
1017
318
|
} break;
|
|
1018
319
|
case PrimitiveKind::Int16: {
|
|
1019
|
-
int16_t
|
|
1020
|
-
memcpy(&
|
|
1021
|
-
|
|
320
|
+
int16_t v;
|
|
321
|
+
memcpy(&v, src, 2);
|
|
322
|
+
set(i, member, NewInt(env, v));
|
|
1022
323
|
} break;
|
|
1023
324
|
case PrimitiveKind::Int16S: {
|
|
1024
|
-
int16_t
|
|
1025
|
-
memcpy(&
|
|
1026
|
-
|
|
325
|
+
int16_t v;
|
|
326
|
+
memcpy(&v, src, 2);
|
|
327
|
+
set(i, member, NewInt(env, ReverseBytes(v)));
|
|
1027
328
|
} break;
|
|
1028
329
|
case PrimitiveKind::UInt16: {
|
|
1029
|
-
uint16_t
|
|
1030
|
-
memcpy(&
|
|
1031
|
-
|
|
330
|
+
uint16_t v;
|
|
331
|
+
memcpy(&v, src, 2);
|
|
332
|
+
set(i, member, NewInt(env, v));
|
|
1032
333
|
} break;
|
|
1033
334
|
case PrimitiveKind::UInt16S: {
|
|
1034
|
-
uint16_t
|
|
1035
|
-
memcpy(&
|
|
1036
|
-
|
|
335
|
+
uint16_t v;
|
|
336
|
+
memcpy(&v, src, 2);
|
|
337
|
+
set(i, member, NewInt(env, ReverseBytes(v)));
|
|
1037
338
|
} break;
|
|
1038
339
|
case PrimitiveKind::Int32: {
|
|
1039
|
-
int32_t
|
|
1040
|
-
memcpy(&
|
|
1041
|
-
|
|
340
|
+
int32_t v;
|
|
341
|
+
memcpy(&v, src, 4);
|
|
342
|
+
set(i, member, NewInt(env, v));
|
|
1042
343
|
} break;
|
|
1043
344
|
case PrimitiveKind::Int32S: {
|
|
1044
|
-
int32_t
|
|
1045
|
-
memcpy(&
|
|
1046
|
-
|
|
345
|
+
int32_t v;
|
|
346
|
+
memcpy(&v, src, 4);
|
|
347
|
+
set(i, member, NewInt(env, ReverseBytes(v)));
|
|
1047
348
|
} break;
|
|
1048
349
|
case PrimitiveKind::UInt32: {
|
|
1049
|
-
uint32_t
|
|
1050
|
-
memcpy(&
|
|
1051
|
-
|
|
350
|
+
uint32_t v;
|
|
351
|
+
memcpy(&v, src, 4);
|
|
352
|
+
set(i, member, NewInt(env, v));
|
|
1052
353
|
} break;
|
|
1053
354
|
case PrimitiveKind::UInt32S: {
|
|
1054
|
-
uint32_t
|
|
1055
|
-
memcpy(&
|
|
1056
|
-
|
|
355
|
+
uint32_t v;
|
|
356
|
+
memcpy(&v, src, 4);
|
|
357
|
+
set(i, member, NewInt(env, ReverseBytes(v)));
|
|
1057
358
|
} break;
|
|
1058
359
|
case PrimitiveKind::Int64: {
|
|
1059
|
-
int64_t
|
|
1060
|
-
memcpy(&
|
|
1061
|
-
|
|
360
|
+
int64_t v;
|
|
361
|
+
memcpy(&v, src, 8);
|
|
362
|
+
set(i, member, NewInt(env, v));
|
|
1062
363
|
} break;
|
|
1063
364
|
case PrimitiveKind::Int64S: {
|
|
1064
|
-
int64_t
|
|
1065
|
-
memcpy(&
|
|
1066
|
-
|
|
365
|
+
int64_t v;
|
|
366
|
+
memcpy(&v, src, 8);
|
|
367
|
+
set(i, member, NewInt(env, ReverseBytes(v)));
|
|
1067
368
|
} break;
|
|
1068
369
|
case PrimitiveKind::UInt64: {
|
|
1069
|
-
uint64_t
|
|
1070
|
-
memcpy(&
|
|
1071
|
-
|
|
370
|
+
uint64_t v;
|
|
371
|
+
memcpy(&v, src, 8);
|
|
372
|
+
set(i, member, NewInt(env, v));
|
|
1072
373
|
} break;
|
|
1073
374
|
case PrimitiveKind::UInt64S: {
|
|
1074
|
-
uint64_t
|
|
1075
|
-
memcpy(&
|
|
1076
|
-
|
|
375
|
+
uint64_t v;
|
|
376
|
+
memcpy(&v, src, 8);
|
|
377
|
+
set(i, member, NewInt(env, ReverseBytes(v)));
|
|
1077
378
|
} break;
|
|
1078
379
|
case PrimitiveKind::String: {
|
|
1079
380
|
const char *str;
|
|
1080
381
|
memcpy(&str, src, K_SIZE(void *));
|
|
1081
|
-
|
|
382
|
+
set(i, member, str ? Napi::String::New(env, str) : env.Null());
|
|
1082
383
|
|
|
1083
384
|
if (member.type->dispose) {
|
|
1084
385
|
member.type->dispose(env, member.type, str);
|
|
@@ -1087,7 +388,7 @@ void DecodeObject(Napi::Env env, napi_value obj, const uint8_t *origin, const Ty
|
|
|
1087
388
|
case PrimitiveKind::String16: {
|
|
1088
389
|
const char16_t *str16;
|
|
1089
390
|
memcpy(&str16, src, K_SIZE(void *));
|
|
1090
|
-
|
|
391
|
+
set(i, member, str16 ? Napi::String::New(env, str16) : env.Null());
|
|
1091
392
|
|
|
1092
393
|
if (member.type->dispose) {
|
|
1093
394
|
member.type->dispose(env, member.type, str16);
|
|
@@ -1096,7 +397,7 @@ void DecodeObject(Napi::Env env, napi_value obj, const uint8_t *origin, const Ty
|
|
|
1096
397
|
case PrimitiveKind::String32: {
|
|
1097
398
|
const char32_t *str32;
|
|
1098
399
|
memcpy(&str32, src, K_SIZE(void *));
|
|
1099
|
-
|
|
400
|
+
set(i, member, str32 ? MakeStringFromUTF32(env, str32) : env.Null());
|
|
1100
401
|
} break;
|
|
1101
402
|
case PrimitiveKind::Pointer: {
|
|
1102
403
|
void *ptr2;
|
|
@@ -1106,11 +407,11 @@ void DecodeObject(Napi::Env env, napi_value obj, const uint8_t *origin, const Ty
|
|
|
1106
407
|
const RecordMember &by = members[member.countedby];
|
|
1107
408
|
uint32_t len = DecodeDynamicLength(origin, by);
|
|
1108
409
|
|
|
1109
|
-
|
|
1110
|
-
|
|
410
|
+
napi_value value = DecodeArray(instance, (const uint8_t *)ptr2, member.type, len);
|
|
411
|
+
set(i, member, value);
|
|
1111
412
|
} else {
|
|
1112
|
-
|
|
1113
|
-
|
|
413
|
+
napi_value p = ptr2 ? WrapPointer(env, member.type->ref.type, ptr2) : env.Null();
|
|
414
|
+
set(i, member, p);
|
|
1114
415
|
}
|
|
1115
416
|
|
|
1116
417
|
if (member.type->dispose) {
|
|
@@ -1121,8 +422,8 @@ void DecodeObject(Napi::Env env, napi_value obj, const uint8_t *origin, const Ty
|
|
|
1121
422
|
void *ptr2;
|
|
1122
423
|
memcpy(&ptr2, src, K_SIZE(void *));
|
|
1123
424
|
|
|
1124
|
-
|
|
1125
|
-
|
|
425
|
+
napi_value p = ptr2 ? WrapPointer(env, member.type->ref.type, ptr2) : env.Null();
|
|
426
|
+
set(i, member, p);
|
|
1126
427
|
|
|
1127
428
|
if (member.type->dispose) {
|
|
1128
429
|
member.type->dispose(env, member.type, ptr2);
|
|
@@ -1130,8 +431,8 @@ void DecodeObject(Napi::Env env, napi_value obj, const uint8_t *origin, const Ty
|
|
|
1130
431
|
} break;
|
|
1131
432
|
case PrimitiveKind::Record:
|
|
1132
433
|
case PrimitiveKind::Union: {
|
|
1133
|
-
|
|
1134
|
-
|
|
434
|
+
napi_value obj2 = DecodeObject(instance, src, member.type);
|
|
435
|
+
set(i, member, obj2);
|
|
1135
436
|
} break;
|
|
1136
437
|
case PrimitiveKind::Array: {
|
|
1137
438
|
if (member.countedby >= 0) {
|
|
@@ -1143,22 +444,22 @@ void DecodeObject(Napi::Env env, napi_value obj, const uint8_t *origin, const Ty
|
|
|
1143
444
|
// Silently truncate result
|
|
1144
445
|
len = std::min(len, max);
|
|
1145
446
|
|
|
1146
|
-
|
|
1147
|
-
|
|
447
|
+
napi_value value = DecodeArray(instance, src, member.type, len);
|
|
448
|
+
set(i, member, value);
|
|
1148
449
|
} else {
|
|
1149
|
-
|
|
1150
|
-
|
|
450
|
+
napi_value value = DecodeArray(instance, src, member.type);
|
|
451
|
+
set(i, member, value);
|
|
1151
452
|
}
|
|
1152
453
|
} break;
|
|
1153
454
|
case PrimitiveKind::Float32: {
|
|
1154
455
|
float f;
|
|
1155
456
|
memcpy(&f, src, 4);
|
|
1156
|
-
|
|
457
|
+
set(i, member, Napi::Number::New(env, (double)f));
|
|
1157
458
|
} break;
|
|
1158
459
|
case PrimitiveKind::Float64: {
|
|
1159
460
|
double d;
|
|
1160
461
|
memcpy(&d, src, 8);
|
|
1161
|
-
|
|
462
|
+
set(i, member, Napi::Number::New(env, d));
|
|
1162
463
|
} break;
|
|
1163
464
|
|
|
1164
465
|
case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
|
|
@@ -1166,45 +467,104 @@ void DecodeObject(Napi::Env env, napi_value obj, const uint8_t *origin, const Ty
|
|
|
1166
467
|
}
|
|
1167
468
|
}
|
|
1168
469
|
|
|
1169
|
-
|
|
470
|
+
napi_value DecodeObject(InstanceData *instance, const uint8_t *origin, const TypeInfo *type)
|
|
471
|
+
{
|
|
472
|
+
Napi::Env env = instance->env;
|
|
473
|
+
|
|
474
|
+
// We can't decode unions because we don't know which member is valid
|
|
475
|
+
if (type->primitive == PrimitiveKind::Union) {
|
|
476
|
+
Napi::External<void> external = Napi::External<void>::New(env, (void *)origin);
|
|
477
|
+
Napi::Object wrapper = type->construct.New({ external }).As<Napi::Object>();
|
|
478
|
+
SetValueTag(env, wrapper, &UnionValueMarker);
|
|
479
|
+
|
|
480
|
+
return wrapper;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Only supported in recent Node versions, and still experimental at this time
|
|
484
|
+
if (node_api_create_object_with_properties && type->members.len <= 256) {
|
|
485
|
+
napi_value properties[256];
|
|
486
|
+
napi_value values[256];
|
|
487
|
+
|
|
488
|
+
DecodeObject(instance, origin, type, [&](Size i, const RecordMember &member, napi_value value) {
|
|
489
|
+
NAPI_OK(napi_get_reference_value(env, member.key, &properties[i]));
|
|
490
|
+
values[i] = value;
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
napi_value obj;
|
|
494
|
+
NAPI_OK(node_api_create_object_with_properties(env, instance->object_constructor.Value(), properties, values, type->members.len, &obj));
|
|
495
|
+
|
|
496
|
+
return obj;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
500
|
+
DecodeObject(instance, obj, origin, type);
|
|
501
|
+
|
|
502
|
+
return obj;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
void DecodeObject(InstanceData *instance, napi_value obj, const uint8_t *origin, const TypeInfo *type)
|
|
506
|
+
{
|
|
507
|
+
Napi::Env env = instance->env;
|
|
508
|
+
|
|
509
|
+
if (node_api_create_property_key_utf8) {
|
|
510
|
+
DecodeObject(instance, origin, type, [&](Size i, const RecordMember &member, napi_value value) {
|
|
511
|
+
napi_value key = nullptr;
|
|
512
|
+
napi_get_reference_value(env, member.key, &key);
|
|
513
|
+
|
|
514
|
+
NAPI_OK(napi_set_property(env, obj, key, value));
|
|
515
|
+
});
|
|
516
|
+
} else {
|
|
517
|
+
DecodeObject(instance, origin, type, [&](Size i, const RecordMember &member, napi_value value) {
|
|
518
|
+
NAPI_OK(napi_set_named_property(env, obj, member.name, value));
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
napi_value DecodeArray(InstanceData *instance, const uint8_t *origin, const TypeInfo *type)
|
|
1170
524
|
{
|
|
1171
525
|
K_ASSERT(type->primitive == PrimitiveKind::Array);
|
|
1172
526
|
|
|
1173
527
|
uint32_t len = type->size / type->ref.stride;
|
|
1174
|
-
return DecodeArray(
|
|
528
|
+
return DecodeArray(instance, origin, type, len);
|
|
1175
529
|
}
|
|
1176
530
|
|
|
1177
|
-
|
|
531
|
+
napi_value DecodeArray(InstanceData *instance, const uint8_t *origin, const TypeInfo *type, uint32_t len)
|
|
1178
532
|
{
|
|
1179
533
|
K_ASSERT(type->primitive == PrimitiveKind::Array || type->primitive == PrimitiveKind::Pointer);
|
|
1180
534
|
|
|
535
|
+
Napi::Env env = instance->env;
|
|
1181
536
|
const TypeInfo *ref = type->ref.type;
|
|
1182
537
|
int32_t stride = type->ref.stride;
|
|
1183
538
|
|
|
1184
539
|
if (type->hint == ArrayHint::Typed) {
|
|
1185
540
|
#define POP_TYPEDARRAY(TypedArrayType, CType) \
|
|
1186
541
|
do { \
|
|
1187
|
-
|
|
1188
|
-
|
|
542
|
+
napi_value buffer = nullptr; \
|
|
543
|
+
napi_value array = nullptr; \
|
|
544
|
+
void *data; \
|
|
545
|
+
\
|
|
546
|
+
NAPI_OK(napi_create_arraybuffer(env, (size_t)len * K_SIZE(CType), &data, &buffer)); \
|
|
547
|
+
NAPI_OK(napi_create_typedarray(env, (TypedArrayType), (size_t)len, buffer, 0, &array)); \
|
|
1189
548
|
\
|
|
1190
|
-
|
|
549
|
+
Span<uint8_t> view = MakeSpan((uint8_t *)data, (Size)len * K_SIZE(CType)); \
|
|
550
|
+
DecodeBuffer(view, origin, type); \
|
|
1191
551
|
\
|
|
1192
552
|
return array; \
|
|
1193
553
|
} while (false)
|
|
1194
554
|
|
|
1195
555
|
switch (ref->primitive) {
|
|
1196
|
-
case PrimitiveKind::Int8: { POP_TYPEDARRAY(
|
|
1197
|
-
case PrimitiveKind::UInt8: { POP_TYPEDARRAY(
|
|
1198
|
-
case PrimitiveKind::Int16: { POP_TYPEDARRAY(
|
|
1199
|
-
case PrimitiveKind::Int16S: { POP_TYPEDARRAY(
|
|
1200
|
-
case PrimitiveKind::UInt16: { POP_TYPEDARRAY(
|
|
1201
|
-
case PrimitiveKind::UInt16S: { POP_TYPEDARRAY(
|
|
1202
|
-
case PrimitiveKind::Int32: { POP_TYPEDARRAY(
|
|
1203
|
-
case PrimitiveKind::Int32S: { POP_TYPEDARRAY(
|
|
1204
|
-
case PrimitiveKind::UInt32: { POP_TYPEDARRAY(
|
|
1205
|
-
case PrimitiveKind::UInt32S: { POP_TYPEDARRAY(
|
|
1206
|
-
case PrimitiveKind::Float32: { POP_TYPEDARRAY(
|
|
1207
|
-
case PrimitiveKind::Float64: { POP_TYPEDARRAY(
|
|
556
|
+
case PrimitiveKind::Int8: { POP_TYPEDARRAY(napi_int8_array, int8_t); } break;
|
|
557
|
+
case PrimitiveKind::UInt8: { POP_TYPEDARRAY(napi_uint8_array, uint8_t); } break;
|
|
558
|
+
case PrimitiveKind::Int16: { POP_TYPEDARRAY(napi_int16_array, int16_t); } break;
|
|
559
|
+
case PrimitiveKind::Int16S: { POP_TYPEDARRAY(napi_int16_array, int16_t); } break;
|
|
560
|
+
case PrimitiveKind::UInt16: { POP_TYPEDARRAY(napi_uint16_array, uint16_t); } break;
|
|
561
|
+
case PrimitiveKind::UInt16S: { POP_TYPEDARRAY(napi_uint16_array, uint16_t); } break;
|
|
562
|
+
case PrimitiveKind::Int32: { POP_TYPEDARRAY(napi_int32_array, int32_t); } break;
|
|
563
|
+
case PrimitiveKind::Int32S: { POP_TYPEDARRAY(napi_int32_array, int32_t); } break;
|
|
564
|
+
case PrimitiveKind::UInt32: { POP_TYPEDARRAY(napi_uint32_array, uint32_t); } break;
|
|
565
|
+
case PrimitiveKind::UInt32S: { POP_TYPEDARRAY(napi_uint32_array, uint32_t); } break;
|
|
566
|
+
case PrimitiveKind::Float32: { POP_TYPEDARRAY(napi_float32_array, float); } break;
|
|
567
|
+
case PrimitiveKind::Float64: { POP_TYPEDARRAY(napi_float64_array, double); } break;
|
|
1208
568
|
|
|
1209
569
|
case PrimitiveKind::Void:
|
|
1210
570
|
case PrimitiveKind::Bool:
|
|
@@ -1224,6 +584,16 @@ Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *ty
|
|
|
1224
584
|
}
|
|
1225
585
|
|
|
1226
586
|
#undef POP_TYPEDARRAY
|
|
587
|
+
} else if (type->hint == ArrayHint::Buffer) {
|
|
588
|
+
napi_value buffer;
|
|
589
|
+
void *data;
|
|
590
|
+
|
|
591
|
+
NAPI_OK(napi_create_buffer(env, (size_t)len * ref->size, &data, &buffer));
|
|
592
|
+
|
|
593
|
+
Span<uint8_t> view = MakeSpan((uint8_t *)data, (Size)len * ref->size);
|
|
594
|
+
DecodeBuffer(view, origin, type);
|
|
595
|
+
|
|
596
|
+
return buffer;
|
|
1227
597
|
} else if (type->hint == ArrayHint::String) {
|
|
1228
598
|
K_ASSERT(stride == ref->size);
|
|
1229
599
|
|
|
@@ -1279,7 +649,7 @@ Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *ty
|
|
|
1279
649
|
K_ASSERT(type->hint == ArrayHint::Array);
|
|
1280
650
|
|
|
1281
651
|
Napi::Array array = Napi::Array::New(env);
|
|
1282
|
-
DecodeElements(
|
|
652
|
+
DecodeElements(instance, array, origin, type, len);
|
|
1283
653
|
|
|
1284
654
|
return array;
|
|
1285
655
|
}
|
|
@@ -1287,10 +657,11 @@ Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *ty
|
|
|
1287
657
|
K_UNREACHABLE();
|
|
1288
658
|
}
|
|
1289
659
|
|
|
1290
|
-
void DecodeElements(
|
|
660
|
+
void DecodeElements(InstanceData *instance, napi_value array, const uint8_t *origin, const TypeInfo *type, uint32_t len)
|
|
1291
661
|
{
|
|
1292
|
-
K_ASSERT(IsArray(env, array));
|
|
662
|
+
K_ASSERT(IsArray(instance->env, array));
|
|
1293
663
|
|
|
664
|
+
Napi::Env env = instance->env;
|
|
1294
665
|
const TypeInfo *ref = type->ref.type;
|
|
1295
666
|
int32_t stride = type->ref.stride;
|
|
1296
667
|
|
|
@@ -1377,7 +748,7 @@ void DecodeElements(Napi::Env env, napi_value array, const uint8_t *origin, cons
|
|
|
1377
748
|
POP_ARRAY({
|
|
1378
749
|
void *ptr2 = *(void **)src;
|
|
1379
750
|
|
|
1380
|
-
|
|
751
|
+
napi_value p = ptr2 ? WrapPointer(env, ref->ref.type, ptr2) : env.Null();
|
|
1381
752
|
napi_set_element(env, array, i, p);
|
|
1382
753
|
|
|
1383
754
|
if (ref->dispose) {
|
|
@@ -1389,7 +760,7 @@ void DecodeElements(Napi::Env env, napi_value array, const uint8_t *origin, cons
|
|
|
1389
760
|
POP_ARRAY({
|
|
1390
761
|
void *ptr2 = *(void **)src;
|
|
1391
762
|
|
|
1392
|
-
|
|
763
|
+
napi_value p = ptr2 ? WrapPointer(env, ref->ref.type, ptr2) : env.Null();
|
|
1393
764
|
napi_set_element(env, array, i, p);
|
|
1394
765
|
|
|
1395
766
|
if (ref->dispose) {
|
|
@@ -1400,13 +771,13 @@ void DecodeElements(Napi::Env env, napi_value array, const uint8_t *origin, cons
|
|
|
1400
771
|
case PrimitiveKind::Record:
|
|
1401
772
|
case PrimitiveKind::Union: {
|
|
1402
773
|
POP_ARRAY({
|
|
1403
|
-
|
|
774
|
+
napi_value obj = DecodeObject(instance, src, ref);
|
|
1404
775
|
napi_set_element(env, array, i, obj);
|
|
1405
776
|
});
|
|
1406
777
|
} break;
|
|
1407
778
|
case PrimitiveKind::Array: {
|
|
1408
779
|
POP_ARRAY({
|
|
1409
|
-
|
|
780
|
+
napi_value value = DecodeArray(instance, src, ref);
|
|
1410
781
|
napi_set_element(env, array, i, value);
|
|
1411
782
|
});
|
|
1412
783
|
} break;
|
|
@@ -1476,90 +847,19 @@ void DecodeBuffer(Span<uint8_t> buffer, const uint8_t *origin, const TypeInfo *t
|
|
|
1476
847
|
#undef SWAP
|
|
1477
848
|
}
|
|
1478
849
|
|
|
1479
|
-
|
|
850
|
+
napi_value Decode(InstanceData *instance, const uint8_t *ptr, const TypeInfo *type)
|
|
1480
851
|
{
|
|
1481
|
-
Napi::Env env =
|
|
1482
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1483
|
-
|
|
1484
|
-
const uint8_t *src = nullptr;
|
|
1485
|
-
|
|
1486
|
-
if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
|
|
1487
|
-
if (offset < 0) [[unlikely]] {
|
|
1488
|
-
ThrowError<Napi::Error>(env, "Offset must be >= 0");
|
|
1489
|
-
return env.Null();
|
|
1490
|
-
}
|
|
1491
|
-
if (buffer.len - offset < type->size) [[unlikely]] {
|
|
1492
|
-
ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
|
|
1493
|
-
type->name, type->size + offset);
|
|
1494
|
-
return env.Null();
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
src = (const uint8_t *)buffer.ptr;
|
|
1498
|
-
} else if (void *ptr = nullptr; TryPointer(env, value, &ptr)) {
|
|
1499
|
-
src = (const uint8_t *)ptr;
|
|
1500
|
-
} else {
|
|
1501
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for variable, expected pointer", GetValueType(instance, value));
|
|
1502
|
-
return env.Null();
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
if (!src)
|
|
1506
|
-
return env.Null();
|
|
1507
|
-
src += offset;
|
|
1508
|
-
|
|
1509
|
-
Napi::Value ret = Decode(env, src, type, len);
|
|
1510
|
-
return ret;
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, const Size *len)
|
|
1514
|
-
{
|
|
1515
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1516
|
-
|
|
1517
|
-
if (len && type->primitive != PrimitiveKind::String &&
|
|
1518
|
-
type->primitive != PrimitiveKind::String16 &&
|
|
1519
|
-
type->primitive != PrimitiveKind::String32 &&
|
|
1520
|
-
type->primitive != PrimitiveKind::Prototype) {
|
|
1521
|
-
if (*len >= 0) {
|
|
1522
|
-
type = MakeArrayType(instance, type, *len);
|
|
1523
|
-
} else {
|
|
1524
|
-
switch (type->primitive) {
|
|
1525
|
-
case PrimitiveKind::Int8:
|
|
1526
|
-
case PrimitiveKind::UInt8: {
|
|
1527
|
-
Size count = strlen((const char *)ptr);
|
|
1528
|
-
type = MakeArrayType(instance, type, count);
|
|
1529
|
-
} break;
|
|
1530
|
-
case PrimitiveKind::Int16:
|
|
1531
|
-
case PrimitiveKind::UInt16: {
|
|
1532
|
-
Size count = NullTerminatedLength((const char16_t *)ptr);
|
|
1533
|
-
type = MakeArrayType(instance, type, count);
|
|
1534
|
-
} break;
|
|
1535
|
-
case PrimitiveKind::Int32:
|
|
1536
|
-
case PrimitiveKind::UInt32: {
|
|
1537
|
-
Size count = NullTerminatedLength((const char32_t *)ptr);
|
|
1538
|
-
type = MakeArrayType(instance, type, count);
|
|
1539
|
-
} break;
|
|
1540
|
-
|
|
1541
|
-
case PrimitiveKind::Pointer: {
|
|
1542
|
-
Size count = NullTerminatedLength((const void **)ptr);
|
|
1543
|
-
type = MakeArrayType(instance, type, count);
|
|
1544
|
-
} break;
|
|
1545
|
-
|
|
1546
|
-
default: {
|
|
1547
|
-
ThrowError<Napi::TypeError>(env, "Cannot determine null-terminated length for type %1", type->name);
|
|
1548
|
-
return env.Null();
|
|
1549
|
-
} break;
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
852
|
+
Napi::Env env = instance->env;
|
|
1553
853
|
|
|
1554
854
|
#define RETURN_INT(Type, NewCall) \
|
|
1555
855
|
do { \
|
|
1556
856
|
Type v = *(Type *)ptr; \
|
|
1557
|
-
return
|
|
857
|
+
return NewCall(env, v); \
|
|
1558
858
|
} while (false)
|
|
1559
859
|
#define RETURN_INT_SWAP(Type, NewCall) \
|
|
1560
860
|
do { \
|
|
1561
861
|
Type v = ReverseBytes(*(Type *)ptr); \
|
|
1562
|
-
return
|
|
862
|
+
return NewCall(env, v); \
|
|
1563
863
|
} while (false)
|
|
1564
864
|
|
|
1565
865
|
switch (type->primitive) {
|
|
@@ -1587,31 +887,16 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
|
|
|
1587
887
|
case PrimitiveKind::UInt64: { RETURN_INT(uint64_t, NewInt); } break;
|
|
1588
888
|
case PrimitiveKind::UInt64S: { RETURN_INT_SWAP(uint64_t, NewInt); } break;
|
|
1589
889
|
case PrimitiveKind::String: {
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
return str ? Napi::String::New(env, str, *len) : env.Null();
|
|
1593
|
-
} else {
|
|
1594
|
-
const char *str = *(const char **)ptr;
|
|
1595
|
-
return str ? Napi::String::New(env, str) : env.Null();
|
|
1596
|
-
}
|
|
890
|
+
const char *str = *(const char **)ptr;
|
|
891
|
+
return str ? Napi::String::New(env, str) : env.Null();
|
|
1597
892
|
} break;
|
|
1598
893
|
case PrimitiveKind::String16: {
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
return str16 ? Napi::String::New(env, str16, *len) : env.Null();
|
|
1602
|
-
} else {
|
|
1603
|
-
const char16_t *str16 = *(const char16_t **)ptr;
|
|
1604
|
-
return str16 ? Napi::String::New(env, str16) : env.Null();
|
|
1605
|
-
}
|
|
894
|
+
const char16_t *str16 = *(const char16_t **)ptr;
|
|
895
|
+
return str16 ? Napi::String::New(env, str16) : env.Null();
|
|
1606
896
|
} break;
|
|
1607
897
|
case PrimitiveKind::String32: {
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
return str32 ? MakeStringFromUTF32(env, str32, *len) : env.Null();
|
|
1611
|
-
} else {
|
|
1612
|
-
const char32_t *str32 = *(const char32_t **)ptr;
|
|
1613
|
-
return str32 ? MakeStringFromUTF32(env, str32) : env.Null();
|
|
1614
|
-
}
|
|
898
|
+
const char32_t *str32 = *(const char32_t **)ptr;
|
|
899
|
+
return str32 ? MakeStringFromUTF32(env, str32) : env.Null();
|
|
1615
900
|
} break;
|
|
1616
901
|
case PrimitiveKind::Pointer: {
|
|
1617
902
|
void *ptr2 = *(void **)ptr;
|
|
@@ -1622,12 +907,9 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
|
|
|
1622
907
|
return ptr2 ? WrapPointer(env, type->ref.type, ptr2) : env.Null();
|
|
1623
908
|
} break;
|
|
1624
909
|
case PrimitiveKind::Record:
|
|
1625
|
-
case PrimitiveKind::Union: {
|
|
1626
|
-
Napi::Object obj = DecodeObject(env, ptr, type);
|
|
1627
|
-
return obj;
|
|
1628
|
-
} break;
|
|
910
|
+
case PrimitiveKind::Union: { return DecodeObject(instance, ptr, type); } break;
|
|
1629
911
|
case PrimitiveKind::Array: {
|
|
1630
|
-
|
|
912
|
+
napi_value array = DecodeArray(instance, ptr, type);
|
|
1631
913
|
return array;
|
|
1632
914
|
} break;
|
|
1633
915
|
case PrimitiveKind::Float32: {
|
|
@@ -1672,213 +954,6 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
|
|
|
1672
954
|
return env.Null();
|
|
1673
955
|
}
|
|
1674
956
|
|
|
1675
|
-
bool Encode(Napi::Value ref, Size offset, Napi::Value value, const TypeInfo *type, const Size *len)
|
|
1676
|
-
{
|
|
1677
|
-
Napi::Env env = ref.Env();
|
|
1678
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1679
|
-
|
|
1680
|
-
uint8_t *dest = nullptr;
|
|
1681
|
-
|
|
1682
|
-
if (Span<uint8_t> buffer = {}; TryBuffer(env, ref, &buffer)) {
|
|
1683
|
-
if (offset < 0) [[unlikely]] {
|
|
1684
|
-
ThrowError<Napi::Error>(env, "Offset must be >= 0");
|
|
1685
|
-
return env.Null();
|
|
1686
|
-
}
|
|
1687
|
-
if (buffer.len - offset < type->size) [[unlikely]] {
|
|
1688
|
-
ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
|
|
1689
|
-
type->name, type->size + offset);
|
|
1690
|
-
return env.Null();
|
|
1691
|
-
}
|
|
1692
|
-
|
|
1693
|
-
dest = (uint8_t *)buffer.ptr;
|
|
1694
|
-
} else if (void *ptr = nullptr; TryPointer(env, ref, &ptr)) {
|
|
1695
|
-
dest = (uint8_t *)ptr;
|
|
1696
|
-
} else {
|
|
1697
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for reference, expected pointer", GetValueType(instance, ref));
|
|
1698
|
-
return env.Null();
|
|
1699
|
-
}
|
|
1700
|
-
|
|
1701
|
-
if (!dest) [[unlikely]] {
|
|
1702
|
-
ThrowError<Napi::Error>(env, "Cannot encode data in NULL pointer");
|
|
1703
|
-
return env.Null();
|
|
1704
|
-
}
|
|
1705
|
-
dest += offset;
|
|
1706
|
-
|
|
1707
|
-
return Encode(env, dest, value, type, len);
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *type, const Size *len)
|
|
1711
|
-
{
|
|
1712
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1713
|
-
|
|
1714
|
-
if (len && type->primitive != PrimitiveKind::String &&
|
|
1715
|
-
type->primitive != PrimitiveKind::String16 &&
|
|
1716
|
-
type->primitive != PrimitiveKind::String32 &&
|
|
1717
|
-
type->primitive != PrimitiveKind::Prototype) {
|
|
1718
|
-
if (*len < 0) [[unlikely]] {
|
|
1719
|
-
ThrowError<Napi::TypeError>(env, "Automatic (negative) length is only supported when decoding");
|
|
1720
|
-
return env.Null();
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
|
-
type = MakeArrayType(instance, type, *len);
|
|
1724
|
-
}
|
|
1725
|
-
|
|
1726
|
-
InstanceMemory mem = {};
|
|
1727
|
-
CallData call(env, instance, &mem, nullptr);
|
|
1728
|
-
|
|
1729
|
-
#define PUSH_INTEGER(CType) \
|
|
1730
|
-
do { \
|
|
1731
|
-
CType v; \
|
|
1732
|
-
if (!TryNumber(env, value, &v)) [[unlikely]] { \
|
|
1733
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
1734
|
-
return false; \
|
|
1735
|
-
} \
|
|
1736
|
-
\
|
|
1737
|
-
*(CType *)origin = v; \
|
|
1738
|
-
} while (false)
|
|
1739
|
-
#define PUSH_INTEGER_SWAP(CType) \
|
|
1740
|
-
do { \
|
|
1741
|
-
CType v; \
|
|
1742
|
-
if (!TryNumber(env, value, &v)) [[unlikely]] { \
|
|
1743
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
|
|
1744
|
-
return false; \
|
|
1745
|
-
} \
|
|
1746
|
-
\
|
|
1747
|
-
*(CType *)origin = ReverseBytes(v); \
|
|
1748
|
-
} while (false)
|
|
1749
|
-
|
|
1750
|
-
switch (type->primitive) {
|
|
1751
|
-
case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
|
|
1752
|
-
|
|
1753
|
-
case PrimitiveKind::Bool: {
|
|
1754
|
-
bool b;
|
|
1755
|
-
napi_status status = napi_get_value_bool(env, value, &b);
|
|
1756
|
-
|
|
1757
|
-
if (status != napi_ok) [[unlikely]] {
|
|
1758
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
|
|
1759
|
-
return false;
|
|
1760
|
-
}
|
|
1761
|
-
|
|
1762
|
-
*(bool *)origin = b;
|
|
1763
|
-
} break;
|
|
1764
|
-
case PrimitiveKind::Int8: { PUSH_INTEGER(int8_t); } break;
|
|
1765
|
-
case PrimitiveKind::UInt8: { PUSH_INTEGER(uint8_t); } break;
|
|
1766
|
-
case PrimitiveKind::Int16: { PUSH_INTEGER(int16_t); } break;
|
|
1767
|
-
case PrimitiveKind::Int16S: { PUSH_INTEGER_SWAP(int16_t); } break;
|
|
1768
|
-
case PrimitiveKind::UInt16: { PUSH_INTEGER(uint16_t); } break;
|
|
1769
|
-
case PrimitiveKind::UInt16S: { PUSH_INTEGER_SWAP(uint16_t); } break;
|
|
1770
|
-
case PrimitiveKind::Int32: { PUSH_INTEGER(int32_t); } break;
|
|
1771
|
-
case PrimitiveKind::Int32S: { PUSH_INTEGER_SWAP(int32_t); } break;
|
|
1772
|
-
case PrimitiveKind::UInt32: { PUSH_INTEGER(uint32_t); } break;
|
|
1773
|
-
case PrimitiveKind::UInt32S: { PUSH_INTEGER_SWAP(uint32_t); } break;
|
|
1774
|
-
case PrimitiveKind::Int64: { PUSH_INTEGER(int64_t); } break;
|
|
1775
|
-
case PrimitiveKind::Int64S: { PUSH_INTEGER_SWAP(int64_t); } break;
|
|
1776
|
-
case PrimitiveKind::UInt64: { PUSH_INTEGER(uint64_t); } break;
|
|
1777
|
-
case PrimitiveKind::UInt64S: { PUSH_INTEGER_SWAP(uint64_t); } break;
|
|
1778
|
-
case PrimitiveKind::String: {
|
|
1779
|
-
const char *str;
|
|
1780
|
-
if (!call.PushString(value, 1, &str)) [[unlikely]]
|
|
1781
|
-
return false;
|
|
1782
|
-
*(const char **)origin = str;
|
|
1783
|
-
} break;
|
|
1784
|
-
case PrimitiveKind::String16: {
|
|
1785
|
-
const char16_t *str16;
|
|
1786
|
-
if (!call.PushString16(value, 1, &str16)) [[unlikely]]
|
|
1787
|
-
return false;
|
|
1788
|
-
*(const char16_t **)origin = str16;
|
|
1789
|
-
} break;
|
|
1790
|
-
case PrimitiveKind::String32: {
|
|
1791
|
-
const char32_t *str32;
|
|
1792
|
-
if (!call.PushString32(value, 1, &str32)) [[unlikely]]
|
|
1793
|
-
return false;
|
|
1794
|
-
*(const char32_t **)origin = str32;
|
|
1795
|
-
} break;
|
|
1796
|
-
case PrimitiveKind::Pointer: {
|
|
1797
|
-
void *ptr;
|
|
1798
|
-
if (!call.PushPointer(value, type, 1, &ptr)) [[unlikely]]
|
|
1799
|
-
return false;
|
|
1800
|
-
*(void **)origin = ptr;
|
|
1801
|
-
} break;
|
|
1802
|
-
case PrimitiveKind::Record:
|
|
1803
|
-
case PrimitiveKind::Union: {
|
|
1804
|
-
if (!IsObject(env, value)) [[unlikely]] {
|
|
1805
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
1806
|
-
return false;
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
|
-
Napi::Object obj = value.As<Napi::Object>();
|
|
1810
|
-
|
|
1811
|
-
if (!call.PushObject(obj, type, origin))
|
|
1812
|
-
return false;
|
|
1813
|
-
} break;
|
|
1814
|
-
case PrimitiveKind::Array: {
|
|
1815
|
-
if (value.IsArray()) {
|
|
1816
|
-
Napi::Array array = Napi::Array(env, value);
|
|
1817
|
-
if (!call.PushNormalArray(array, type, type->size, origin))
|
|
1818
|
-
return false;
|
|
1819
|
-
} else if (Span<uint8_t> buffer = {}; TryBuffer(env, value, &buffer)) {
|
|
1820
|
-
call.PushBuffer(buffer, type, origin);
|
|
1821
|
-
} else if (value.IsString()) {
|
|
1822
|
-
if (!call.PushStringArray(value, type, origin))
|
|
1823
|
-
return false;
|
|
1824
|
-
} else {
|
|
1825
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected array", GetValueType(instance, value));
|
|
1826
|
-
return false;
|
|
1827
|
-
}
|
|
1828
|
-
} break;
|
|
1829
|
-
case PrimitiveKind::Float32: {
|
|
1830
|
-
float f;
|
|
1831
|
-
if (!TryNumber(env, value, &f)) [[unlikely]] {
|
|
1832
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
1833
|
-
return false;
|
|
1834
|
-
}
|
|
1835
|
-
|
|
1836
|
-
memcpy(origin, &f, 4);
|
|
1837
|
-
} break;
|
|
1838
|
-
case PrimitiveKind::Float64: {
|
|
1839
|
-
double d;
|
|
1840
|
-
if (!TryNumber(env, value, &d)) [[unlikely]] {
|
|
1841
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
|
|
1842
|
-
return false;
|
|
1843
|
-
}
|
|
1844
|
-
|
|
1845
|
-
memcpy(origin, &d, 8);
|
|
1846
|
-
} break;
|
|
1847
|
-
case PrimitiveKind::Callback: {
|
|
1848
|
-
void *ptr;
|
|
1849
|
-
if (!TryPointer(env, value, &ptr)) [[unlikely]] {
|
|
1850
|
-
if (value.IsFunction()) {
|
|
1851
|
-
ThrowError<Napi::Error>(env, "Cannot encode non-registered callback");
|
|
1852
|
-
} else {
|
|
1853
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
|
|
1854
|
-
}
|
|
1855
|
-
return false;
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
*(void **)origin = ptr;
|
|
1859
|
-
} break;
|
|
1860
|
-
|
|
1861
|
-
case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
#undef PUSH_INTEGER_SWAP
|
|
1865
|
-
#undef PUSH_INTEGER
|
|
1866
|
-
|
|
1867
|
-
// Keep memory around if any was allocated
|
|
1868
|
-
if (mem.allocator.IsUsed()) {
|
|
1869
|
-
LinkedAllocator *copy = instance->encode_map.FindValue(origin, nullptr);
|
|
1870
|
-
|
|
1871
|
-
if (!copy) {
|
|
1872
|
-
copy = instance->encode_allocators.AppendDefault();
|
|
1873
|
-
instance->encode_map.Set(origin, copy);
|
|
1874
|
-
}
|
|
1875
|
-
|
|
1876
|
-
std::swap(mem.allocator, *copy);
|
|
1877
|
-
}
|
|
1878
|
-
|
|
1879
|
-
return true;
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
957
|
static bool CanTypeAcceptCallbacks(const TypeInfo *type)
|
|
1883
958
|
{
|
|
1884
959
|
if (type->primitive == PrimitiveKind::Pointer)
|
|
@@ -1917,7 +992,7 @@ static bool CanUseFastCall(const FunctionInfo *func)
|
|
|
1917
992
|
return true;
|
|
1918
993
|
}
|
|
1919
994
|
|
|
1920
|
-
|
|
995
|
+
napi_value DescribeFunction(Napi::Env env, const FunctionInfo *func)
|
|
1921
996
|
{
|
|
1922
997
|
static const char *const DirectionNames[] = {
|
|
1923
998
|
nullptr,
|
|
@@ -1954,7 +1029,7 @@ static bool IsDebugAsyncEnabled()
|
|
|
1954
1029
|
return debug;
|
|
1955
1030
|
}
|
|
1956
1031
|
|
|
1957
|
-
|
|
1032
|
+
napi_value WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
1958
1033
|
{
|
|
1959
1034
|
Napi::Function wrapper;
|
|
1960
1035
|
|
|
@@ -1963,21 +1038,16 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
|
1963
1038
|
napi_value value;
|
|
1964
1039
|
|
|
1965
1040
|
if (func->variadic) {
|
|
1966
|
-
|
|
1967
|
-
K_ASSERT(status == napi_ok);
|
|
1041
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateVariadicCall, (void *)func->Ref(), &value));
|
|
1968
1042
|
} else if (IsDebugAsyncEnabled()) {
|
|
1969
|
-
|
|
1970
|
-
K_ASSERT(status == napi_ok);
|
|
1043
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCallDebugAsync, (void *)func->Ref(), &value));
|
|
1971
1044
|
} else if (!func->parameters.len) {
|
|
1972
1045
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1973
|
-
|
|
1974
|
-
K_ASSERT(status == napi_ok);
|
|
1046
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, instance->translate_zero_call, (void *)func->Ref(), &value));
|
|
1975
1047
|
} else if (CanUseFastCall(func)) {
|
|
1976
|
-
|
|
1977
|
-
K_ASSERT(status == napi_ok);
|
|
1048
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateFastCall, (void *)func->Ref(), &value));
|
|
1978
1049
|
} else {
|
|
1979
|
-
|
|
1980
|
-
K_ASSERT(status == napi_ok);
|
|
1050
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCall, (void *)func->Ref(), &value));
|
|
1981
1051
|
}
|
|
1982
1052
|
|
|
1983
1053
|
wrapper = Napi::Function(env, value);
|
|
@@ -1986,8 +1056,7 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
|
1986
1056
|
|
|
1987
1057
|
if (!func->variadic) {
|
|
1988
1058
|
napi_value value;
|
|
1989
|
-
|
|
1990
|
-
K_ASSERT(status == napi_ok);
|
|
1059
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateAsyncCall, (void *)func->Ref(), &value));
|
|
1991
1060
|
|
|
1992
1061
|
Napi::Function async = Napi::Function(env, value);
|
|
1993
1062
|
async.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
|
|
@@ -1995,7 +1064,7 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
|
1995
1064
|
wrapper.Set("async", async);
|
|
1996
1065
|
}
|
|
1997
1066
|
|
|
1998
|
-
|
|
1067
|
+
napi_value meta = DescribeFunction(env, func);
|
|
1999
1068
|
wrapper.Set("info", meta);
|
|
2000
1069
|
|
|
2001
1070
|
return wrapper;
|