koffi 3.0.1 → 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 +11 -0
- package/cnoke.cjs +7 -7
- package/doc/benchmarks.md +1 -1
- package/doc/contribute.md +1 -1
- package/index.d.ts +356 -308
- package/package.json +16 -16
- package/src/koffi/CMakeLists.txt +1 -0
- package/src/koffi/index.cjs +30 -116
- package/src/koffi/index.js +27 -101
- package/src/koffi/indirect.cjs +29 -115
- package/src/koffi/indirect.js +28 -28
- package/src/koffi/src/abi/arm64.cc +1 -0
- package/src/koffi/src/abi/riscv64.cc +1 -0
- package/src/koffi/src/abi/x64sysv.cc +1 -0
- package/src/koffi/src/abi/x64win.cc +1 -0
- package/src/koffi/src/abi/x86.cc +1 -0
- package/src/koffi/src/call.cc +208 -97
- package/src/koffi/src/call.hh +2 -1
- package/src/koffi/src/ffi.cc +347 -237
- package/src/koffi/src/ffi.hh +37 -1
- package/src/koffi/src/parser.cc +3 -1
- 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 +56 -1041
- package/src/koffi/src/util.hh +80 -119
- package/src/koffi/src/uv.cc +16 -10
- package/src/koffi/src/uv.hh +2 -1
- 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,6 +39,7 @@ 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();
|
|
42
|
+
|
|
76
43
|
instance = env.GetInstanceData<InstanceData>();
|
|
77
44
|
|
|
78
45
|
if (info.Length() >= 1) {
|
|
@@ -140,669 +107,6 @@ void UnionValue::Setter(const Napi::CallbackInfo &info, const Napi::Value &value
|
|
|
140
107
|
raw.Clear();
|
|
141
108
|
}
|
|
142
109
|
|
|
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
110
|
void SetValueTag(napi_env env, napi_value value, const void *marker)
|
|
807
111
|
{
|
|
808
112
|
static_assert(K_SIZE(TypeInfo) >= 16);
|
|
@@ -818,8 +122,7 @@ void SetValueTag(napi_env env, napi_value value, const void *marker)
|
|
|
818
122
|
// and the few other markers we use, such as CastMarker, are actual const napi_type_tag structs.
|
|
819
123
|
const napi_type_tag *tag = (const napi_type_tag *)marker;
|
|
820
124
|
|
|
821
|
-
|
|
822
|
-
K_ASSERT(status == napi_ok);
|
|
125
|
+
NAPI_OK(napi_type_tag_object(env, value, tag));
|
|
823
126
|
}
|
|
824
127
|
|
|
825
128
|
bool CheckValueTag(napi_env env, napi_value value, const void *marker)
|
|
@@ -1183,15 +486,12 @@ napi_value DecodeObject(InstanceData *instance, const uint8_t *origin, const Typ
|
|
|
1183
486
|
napi_value values[256];
|
|
1184
487
|
|
|
1185
488
|
DecodeObject(instance, origin, type, [&](Size i, const RecordMember &member, napi_value value) {
|
|
1186
|
-
|
|
1187
|
-
K_ASSERT(status == napi_ok);
|
|
1188
|
-
|
|
489
|
+
NAPI_OK(napi_get_reference_value(env, member.key, &properties[i]));
|
|
1189
490
|
values[i] = value;
|
|
1190
491
|
});
|
|
1191
492
|
|
|
1192
493
|
napi_value obj;
|
|
1193
|
-
|
|
1194
|
-
K_ASSERT(status == napi_ok);
|
|
494
|
+
NAPI_OK(node_api_create_object_with_properties(env, instance->object_constructor.Value(), properties, values, type->members.len, &obj));
|
|
1195
495
|
|
|
1196
496
|
return obj;
|
|
1197
497
|
}
|
|
@@ -1211,13 +511,11 @@ void DecodeObject(InstanceData *instance, napi_value obj, const uint8_t *origin,
|
|
|
1211
511
|
napi_value key = nullptr;
|
|
1212
512
|
napi_get_reference_value(env, member.key, &key);
|
|
1213
513
|
|
|
1214
|
-
|
|
1215
|
-
K_ASSERT(status == napi_ok);
|
|
514
|
+
NAPI_OK(napi_set_property(env, obj, key, value));
|
|
1216
515
|
});
|
|
1217
516
|
} else {
|
|
1218
517
|
DecodeObject(instance, origin, type, [&](Size i, const RecordMember &member, napi_value value) {
|
|
1219
|
-
|
|
1220
|
-
K_ASSERT(status == napi_ok);
|
|
518
|
+
NAPI_OK(napi_set_named_property(env, obj, member.name, value));
|
|
1221
519
|
});
|
|
1222
520
|
}
|
|
1223
521
|
}
|
|
@@ -1241,27 +539,32 @@ napi_value DecodeArray(InstanceData *instance, const uint8_t *origin, const Type
|
|
|
1241
539
|
if (type->hint == ArrayHint::Typed) {
|
|
1242
540
|
#define POP_TYPEDARRAY(TypedArrayType, CType) \
|
|
1243
541
|
do { \
|
|
1244
|
-
|
|
1245
|
-
|
|
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)); \
|
|
1246
548
|
\
|
|
1247
|
-
|
|
549
|
+
Span<uint8_t> view = MakeSpan((uint8_t *)data, (Size)len * K_SIZE(CType)); \
|
|
550
|
+
DecodeBuffer(view, origin, type); \
|
|
1248
551
|
\
|
|
1249
552
|
return array; \
|
|
1250
553
|
} while (false)
|
|
1251
554
|
|
|
1252
555
|
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(
|
|
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;
|
|
1265
568
|
|
|
1266
569
|
case PrimitiveKind::Void:
|
|
1267
570
|
case PrimitiveKind::Bool:
|
|
@@ -1281,6 +584,16 @@ napi_value DecodeArray(InstanceData *instance, const uint8_t *origin, const Type
|
|
|
1281
584
|
}
|
|
1282
585
|
|
|
1283
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;
|
|
1284
597
|
} else if (type->hint == ArrayHint::String) {
|
|
1285
598
|
K_ASSERT(stride == ref->size);
|
|
1286
599
|
|
|
@@ -1534,80 +847,10 @@ void DecodeBuffer(Span<uint8_t> buffer, const uint8_t *origin, const TypeInfo *t
|
|
|
1534
847
|
#undef SWAP
|
|
1535
848
|
}
|
|
1536
849
|
|
|
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)
|
|
850
|
+
napi_value Decode(InstanceData *instance, const uint8_t *ptr, const TypeInfo *type)
|
|
1571
851
|
{
|
|
1572
852
|
Napi::Env env = instance->env;
|
|
1573
853
|
|
|
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
854
|
#define RETURN_INT(Type, NewCall) \
|
|
1612
855
|
do { \
|
|
1613
856
|
Type v = *(Type *)ptr; \
|
|
@@ -1644,31 +887,16 @@ napi_value Decode(InstanceData *instance, const uint8_t *ptr, const TypeInfo *ty
|
|
|
1644
887
|
case PrimitiveKind::UInt64: { RETURN_INT(uint64_t, NewInt); } break;
|
|
1645
888
|
case PrimitiveKind::UInt64S: { RETURN_INT_SWAP(uint64_t, NewInt); } break;
|
|
1646
889
|
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
|
-
}
|
|
890
|
+
const char *str = *(const char **)ptr;
|
|
891
|
+
return str ? Napi::String::New(env, str) : env.Null();
|
|
1654
892
|
} break;
|
|
1655
893
|
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
|
-
}
|
|
894
|
+
const char16_t *str16 = *(const char16_t **)ptr;
|
|
895
|
+
return str16 ? Napi::String::New(env, str16) : env.Null();
|
|
1663
896
|
} break;
|
|
1664
897
|
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
|
-
}
|
|
898
|
+
const char32_t *str32 = *(const char32_t **)ptr;
|
|
899
|
+
return str32 ? MakeStringFromUTF32(env, str32) : env.Null();
|
|
1672
900
|
} break;
|
|
1673
901
|
case PrimitiveKind::Pointer: {
|
|
1674
902
|
void *ptr2 = *(void **)ptr;
|
|
@@ -1726,213 +954,6 @@ napi_value Decode(InstanceData *instance, const uint8_t *ptr, const TypeInfo *ty
|
|
|
1726
954
|
return env.Null();
|
|
1727
955
|
}
|
|
1728
956
|
|
|
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
957
|
static bool CanTypeAcceptCallbacks(const TypeInfo *type)
|
|
1937
958
|
{
|
|
1938
959
|
if (type->primitive == PrimitiveKind::Pointer)
|
|
@@ -1971,7 +992,7 @@ static bool CanUseFastCall(const FunctionInfo *func)
|
|
|
1971
992
|
return true;
|
|
1972
993
|
}
|
|
1973
994
|
|
|
1974
|
-
|
|
995
|
+
napi_value DescribeFunction(Napi::Env env, const FunctionInfo *func)
|
|
1975
996
|
{
|
|
1976
997
|
static const char *const DirectionNames[] = {
|
|
1977
998
|
nullptr,
|
|
@@ -2008,7 +1029,7 @@ static bool IsDebugAsyncEnabled()
|
|
|
2008
1029
|
return debug;
|
|
2009
1030
|
}
|
|
2010
1031
|
|
|
2011
|
-
|
|
1032
|
+
napi_value WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
2012
1033
|
{
|
|
2013
1034
|
Napi::Function wrapper;
|
|
2014
1035
|
|
|
@@ -2017,21 +1038,16 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
|
2017
1038
|
napi_value value;
|
|
2018
1039
|
|
|
2019
1040
|
if (func->variadic) {
|
|
2020
|
-
|
|
2021
|
-
K_ASSERT(status == napi_ok);
|
|
1041
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateVariadicCall, (void *)func->Ref(), &value));
|
|
2022
1042
|
} else if (IsDebugAsyncEnabled()) {
|
|
2023
|
-
|
|
2024
|
-
K_ASSERT(status == napi_ok);
|
|
1043
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCallDebugAsync, (void *)func->Ref(), &value));
|
|
2025
1044
|
} else if (!func->parameters.len) {
|
|
2026
1045
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
2027
|
-
|
|
2028
|
-
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));
|
|
2029
1047
|
} else if (CanUseFastCall(func)) {
|
|
2030
|
-
|
|
2031
|
-
K_ASSERT(status == napi_ok);
|
|
1048
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateFastCall, (void *)func->Ref(), &value));
|
|
2032
1049
|
} else {
|
|
2033
|
-
|
|
2034
|
-
K_ASSERT(status == napi_ok);
|
|
1050
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCall, (void *)func->Ref(), &value));
|
|
2035
1051
|
}
|
|
2036
1052
|
|
|
2037
1053
|
wrapper = Napi::Function(env, value);
|
|
@@ -2040,8 +1056,7 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
|
2040
1056
|
|
|
2041
1057
|
if (!func->variadic) {
|
|
2042
1058
|
napi_value value;
|
|
2043
|
-
|
|
2044
|
-
K_ASSERT(status == napi_ok);
|
|
1059
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateAsyncCall, (void *)func->Ref(), &value));
|
|
2045
1060
|
|
|
2046
1061
|
Napi::Function async = Napi::Function(env, value);
|
|
2047
1062
|
async.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
|
|
@@ -2049,7 +1064,7 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
|
2049
1064
|
wrapper.Set("async", async);
|
|
2050
1065
|
}
|
|
2051
1066
|
|
|
2052
|
-
|
|
1067
|
+
napi_value meta = DescribeFunction(env, func);
|
|
2053
1068
|
wrapper.Set("info", meta);
|
|
2054
1069
|
|
|
2055
1070
|
return wrapper;
|