koffi 1.3.12 → 2.1.0-beta.1
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/CMakeLists.txt +8 -10
- package/ChangeLog.md +48 -16
- package/README.md +6 -0
- package/benchmark/atoi_koffi.js +12 -8
- package/benchmark/atoi_napi.js +12 -8
- package/benchmark/atoi_node_ffi.js +11 -10
- package/benchmark/raylib_cc.cc +12 -9
- package/benchmark/raylib_koffi.js +15 -13
- package/benchmark/raylib_node_ffi.js +15 -13
- package/benchmark/raylib_node_raylib.js +14 -11
- package/build/qemu/2.1.0-beta.1/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_win32_x64.tar.gz +0 -0
- package/doc/changes.md +160 -1
- package/doc/conf.py +14 -1
- package/doc/contribute.md +0 -1
- package/doc/dist/doctrees/benchmarks.doctree +0 -0
- package/doc/dist/doctrees/changes.doctree +0 -0
- package/doc/dist/doctrees/environment.pickle +0 -0
- package/doc/dist/doctrees/functions.doctree +0 -0
- package/doc/dist/doctrees/index.doctree +0 -0
- package/doc/dist/doctrees/types.doctree +0 -0
- package/doc/dist/html/.buildinfo +1 -1
- package/doc/dist/html/_sources/benchmarks.md.txt +2 -2
- package/doc/dist/html/_sources/changes.md.txt +160 -1
- package/doc/dist/html/_sources/functions.md.txt +17 -13
- package/doc/dist/html/_sources/types.md.txt +87 -35
- package/doc/dist/html/benchmarks.html +7 -3
- package/doc/dist/html/changes.html +241 -14
- package/doc/dist/html/contribute.html +5 -1
- package/doc/dist/html/functions.html +30 -23
- package/doc/dist/html/genindex.html +5 -1
- package/doc/dist/html/index.html +13 -19
- package/doc/dist/html/memory.html +7 -3
- package/doc/dist/html/objects.inv +0 -0
- package/doc/dist/html/platforms.html +6 -2
- package/doc/dist/html/search.html +5 -1
- package/doc/dist/html/searchindex.js +1 -1
- package/doc/dist/html/start.html +5 -1
- package/doc/dist/html/types.html +104 -43
- package/doc/functions.md +139 -15
- package/doc/templates/badges.html +5 -0
- package/doc/types.md +108 -40
- package/package.json +2 -2
- package/qemu/qemu.js +1 -1
- package/qemu/registry/machines.json +5 -5
- package/qemu/registry/sha256sum.txt +16 -16
- package/src/abi_arm32.cc +91 -19
- package/src/abi_arm32_fwd.S +121 -57
- package/src/abi_arm64.cc +91 -19
- package/src/abi_arm64_fwd.S +96 -0
- package/src/abi_arm64_fwd.asm +128 -0
- package/src/abi_riscv64.cc +89 -19
- package/src/abi_riscv64_fwd.S +96 -0
- package/src/abi_x64_sysv.cc +94 -22
- package/src/abi_x64_sysv_fwd.S +96 -0
- package/src/abi_x64_win.cc +89 -19
- package/src/abi_x64_win_fwd.asm +128 -0
- package/src/abi_x86.cc +94 -19
- package/src/abi_x86_fwd.S +96 -0
- package/src/abi_x86_fwd.asm +128 -0
- package/src/call.cc +128 -78
- package/src/call.hh +17 -4
- package/src/ffi.cc +514 -145
- package/src/ffi.hh +30 -9
- package/src/index.js +4 -2
- package/src/parser.cc +19 -44
- package/src/util.cc +160 -27
- package/src/util.hh +7 -2
- package/test/async.js +1 -2
- package/test/callbacks.js +56 -11
- package/test/misc.c +50 -15
- package/test/raylib.js +2 -2
- package/test/sqlite.js +27 -19
- package/test/sync.js +71 -35
- package/vendor/libcc/libcc.cc +18 -5
- package/vendor/libcc/libcc.hh +70 -23
- package/build/qemu/1.3.12/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_win32_x64.tar.gz +0 -0
package/src/ffi.cc
CHANGED
|
@@ -42,6 +42,7 @@ namespace RG {
|
|
|
42
42
|
|
|
43
43
|
// Value does not matter, the tag system uses memory addresses
|
|
44
44
|
const int TypeInfoMarker = 0xDEADBEEF;
|
|
45
|
+
const int CastMarker = 0xDEADBEEF;
|
|
45
46
|
|
|
46
47
|
static bool ChangeMemorySize(const char *name, Napi::Value value, Size *out_size)
|
|
47
48
|
{
|
|
@@ -199,8 +200,6 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
199
200
|
|
|
200
201
|
type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
|
|
201
202
|
|
|
202
|
-
type->defn.Reset(obj, 1);
|
|
203
|
-
|
|
204
203
|
type->primitive = PrimitiveKind::Record;
|
|
205
204
|
type->align = 1;
|
|
206
205
|
|
|
@@ -211,20 +210,44 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
211
210
|
|
|
212
211
|
std::string key = ((Napi::Value)keys[i]).As<Napi::String>();
|
|
213
212
|
Napi::Value value = obj[key];
|
|
213
|
+
int16_t align = 0;
|
|
214
214
|
|
|
215
215
|
member.name = DuplicateString(key.c_str(), &instance->str_alloc).ptr;
|
|
216
|
-
|
|
216
|
+
|
|
217
|
+
if (value.IsArray()) {
|
|
218
|
+
Napi::Array array = value.As<Napi::Array>();
|
|
219
|
+
|
|
220
|
+
if (array.Length() != 2 || !((Napi::Value)array[0u]).IsNumber()) {
|
|
221
|
+
ThrowError<Napi::Error>(env, "Member specifier array must contain alignement value and type");
|
|
222
|
+
return env.Null();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
int64_t align64 = ((Napi::Value)array[0u]).As<Napi::Number>().Int64Value();
|
|
226
|
+
|
|
227
|
+
if (align64 < 1 || align64 > 64) {
|
|
228
|
+
ThrowError<Napi::Error>(env, "Alignment value must be between 1 and 64");
|
|
229
|
+
return env.Null();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
value = array[1u];
|
|
233
|
+
align = (int16_t)align64;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
member.type = ResolveType(value);
|
|
217
237
|
if (!member.type)
|
|
218
238
|
return env.Null();
|
|
219
|
-
if (member.type
|
|
220
|
-
ThrowError<Napi::TypeError>(env, "Type
|
|
239
|
+
if (!CanStoreType(member.type)) {
|
|
240
|
+
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a member (maybe try %1 *)", member.type->name);
|
|
221
241
|
return env.Null();
|
|
222
242
|
}
|
|
223
243
|
|
|
224
|
-
|
|
244
|
+
if (!align) {
|
|
245
|
+
align = pad ? member.type->align : 1;
|
|
246
|
+
}
|
|
247
|
+
member.offset = (int16_t)AlignLen(type->size, align);
|
|
225
248
|
|
|
226
|
-
type->size = (int16_t)(
|
|
227
|
-
type->align = std::max(type->align,
|
|
249
|
+
type->size = (int16_t)(member.offset + member.type->size);
|
|
250
|
+
type->align = std::max(type->align, align);
|
|
228
251
|
|
|
229
252
|
if (!members.TrySet(member.name).second) {
|
|
230
253
|
ThrowError<Napi::Error>(env, "Duplicate member '%1' in struct '%2'", member.name, type->name);
|
|
@@ -242,7 +265,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
242
265
|
type->size = (int16_t)AlignLen(type->size, type->align);
|
|
243
266
|
|
|
244
267
|
// If the insert succeeds, we cannot fail anymore
|
|
245
|
-
if (named && !instance->types_map.TrySet(type).second) {
|
|
268
|
+
if (named && !instance->types_map.TrySet(type->name, type).second) {
|
|
246
269
|
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
247
270
|
return env.Null();
|
|
248
271
|
}
|
|
@@ -264,45 +287,31 @@ static Napi::Value CreatePackedStructType(const Napi::CallbackInfo &info)
|
|
|
264
287
|
return CreateStructType(info, false);
|
|
265
288
|
}
|
|
266
289
|
|
|
267
|
-
static Napi::Value
|
|
290
|
+
static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
|
|
268
291
|
{
|
|
269
292
|
Napi::Env env = info.Env();
|
|
270
293
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
271
294
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
276
|
-
if (!info[0].IsString()) {
|
|
295
|
+
bool named = (info.Length() >= 1);
|
|
296
|
+
|
|
297
|
+
if (named && !info[0].IsString()) {
|
|
277
298
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
278
299
|
return env.Null();
|
|
279
300
|
}
|
|
280
301
|
|
|
302
|
+
std::string name = named ? info[0].As<Napi::String>() : std::string("<anonymous>");
|
|
303
|
+
|
|
281
304
|
TypeInfo *type = instance->types.AppendDefault();
|
|
282
305
|
RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
|
|
283
306
|
|
|
284
|
-
std::string name = info[0].As<Napi::String>();
|
|
285
|
-
|
|
286
307
|
type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
|
|
287
308
|
|
|
288
|
-
type->primitive = PrimitiveKind::
|
|
289
|
-
type->
|
|
290
|
-
type->
|
|
291
|
-
|
|
292
|
-
// Add single handle member
|
|
293
|
-
{
|
|
294
|
-
RecordMember member = {};
|
|
295
|
-
|
|
296
|
-
member.name = "value";
|
|
297
|
-
member.type = instance->types_map.FindValue("void *", nullptr);
|
|
298
|
-
RG_ASSERT(member.type);
|
|
299
|
-
member.align = type->align;
|
|
300
|
-
|
|
301
|
-
type->members.Append(member);
|
|
302
|
-
}
|
|
309
|
+
type->primitive = PrimitiveKind::Void;
|
|
310
|
+
type->size = 0;
|
|
311
|
+
type->align = 0;
|
|
303
312
|
|
|
304
313
|
// If the insert succeeds, we cannot fail anymore
|
|
305
|
-
if (!instance->types_map.TrySet(type).second) {
|
|
314
|
+
if (named && !instance->types_map.TrySet(type->name, type).second) {
|
|
306
315
|
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
307
316
|
return env.Null();
|
|
308
317
|
}
|
|
@@ -320,18 +329,65 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
|
|
|
320
329
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
321
330
|
|
|
322
331
|
if (info.Length() < 1) {
|
|
323
|
-
ThrowError<Napi::TypeError>(env, "Expected 1
|
|
332
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 to 3 arguments, got %1", info.Length());
|
|
324
333
|
return env.Null();
|
|
325
334
|
}
|
|
326
335
|
|
|
327
|
-
|
|
328
|
-
|
|
336
|
+
bool named = (info.Length() >= 2 && !info[1].IsNumber());
|
|
337
|
+
|
|
338
|
+
if (named && !info[0].IsString()) {
|
|
339
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
329
340
|
return env.Null();
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
std::string name = named ? info[0].As<Napi::String>() : std::string();
|
|
344
|
+
|
|
345
|
+
const TypeInfo *type = ResolveType(info[named]);
|
|
346
|
+
if (!type)
|
|
347
|
+
return env.Null();
|
|
348
|
+
if (type->dispose) {
|
|
349
|
+
ThrowError<Napi::TypeError>(env, "Cannot create pointer to disposable type '%1'", type->name);
|
|
350
|
+
return env.Null();
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
int count = 0;
|
|
354
|
+
if (info.Length() >= 2u + named) {
|
|
355
|
+
if (!info[1 + named].IsNumber()) {
|
|
356
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for count, expected number", GetValueType(instance, info[1 + named]));
|
|
357
|
+
return env.Null();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
count = info[1 + named].As<Napi::Number>();
|
|
361
|
+
|
|
362
|
+
if (count < 1 || count > 4) {
|
|
363
|
+
ThrowError<Napi::TypeError>(env, "Value of count must be between 1 and 4");
|
|
364
|
+
return env.Null();
|
|
365
|
+
}
|
|
366
|
+
} else {
|
|
367
|
+
count = 1;
|
|
368
|
+
}
|
|
330
369
|
|
|
331
|
-
|
|
370
|
+
type = MakePointerType(instance, type, count);
|
|
332
371
|
RG_ASSERT(type);
|
|
333
372
|
|
|
334
|
-
|
|
373
|
+
if (named) {
|
|
374
|
+
TypeInfo *copy = instance->types.AppendDefault();
|
|
375
|
+
RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
|
|
376
|
+
|
|
377
|
+
memcpy((void *)copy, type, RG_SIZE(*type));
|
|
378
|
+
copy->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
|
|
379
|
+
|
|
380
|
+
// If the insert succeeds, we cannot fail anymore
|
|
381
|
+
if (!instance->types_map.TrySet(copy->name, copy).second) {
|
|
382
|
+
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", copy->name);
|
|
383
|
+
return env.Null();
|
|
384
|
+
}
|
|
385
|
+
err_guard.Disable();
|
|
386
|
+
|
|
387
|
+
type = copy;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
|
|
335
391
|
SetValueTag(instance, external, &TypeInfoMarker);
|
|
336
392
|
|
|
337
393
|
return external;
|
|
@@ -349,7 +405,7 @@ static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int di
|
|
|
349
405
|
return env.Null();
|
|
350
406
|
}
|
|
351
407
|
|
|
352
|
-
const TypeInfo *type = ResolveType(
|
|
408
|
+
const TypeInfo *type = ResolveType(info[0]);
|
|
353
409
|
if (!type)
|
|
354
410
|
return env.Null();
|
|
355
411
|
|
|
@@ -382,6 +438,112 @@ static Napi::Value MarkInOut(const Napi::CallbackInfo &info)
|
|
|
382
438
|
return EncodePointerDirection(info, 3);
|
|
383
439
|
}
|
|
384
440
|
|
|
441
|
+
static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
442
|
+
{
|
|
443
|
+
Napi::Env env = info.Env();
|
|
444
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
445
|
+
|
|
446
|
+
if (info.Length() < 1) {
|
|
447
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
|
|
448
|
+
return env.Null();
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
bool named = (info.Length() >= 2 && !info[1].IsFunction());
|
|
452
|
+
|
|
453
|
+
if (named && !info[0].IsString()) {
|
|
454
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
455
|
+
return env.Null();
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
std::string name = named ? info[0].As<Napi::String>() : std::string("<anonymous>");
|
|
459
|
+
|
|
460
|
+
const TypeInfo *src = ResolveType(info[named]);
|
|
461
|
+
if (!src)
|
|
462
|
+
return env.Null();
|
|
463
|
+
if (src->primitive != PrimitiveKind::String &&
|
|
464
|
+
src->primitive != PrimitiveKind::String16 &&
|
|
465
|
+
src->primitive != PrimitiveKind::Pointer) {
|
|
466
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type", PrimitiveKindNames[(int)src->primitive]);
|
|
467
|
+
return env.Null();
|
|
468
|
+
}
|
|
469
|
+
if (src->dispose) {
|
|
470
|
+
ThrowError<Napi::TypeError>(env, "Cannot use disposable type '%1' to create new disposable", src->name);
|
|
471
|
+
return env.Null();
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
DisposeFunc *dispose;
|
|
475
|
+
Napi::Function dispose_func;
|
|
476
|
+
if (info.Length() >= 2u + named && !IsNullOrUndefined(info[1 + named])) {
|
|
477
|
+
Napi::Function func = info[1 + named].As<Napi::Function>();
|
|
478
|
+
|
|
479
|
+
if (!func.IsFunction()) {
|
|
480
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, func));
|
|
481
|
+
return env.Null();
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
dispose = [](Napi::Env env, const TypeInfo *type, const void *ptr) {
|
|
485
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
486
|
+
const Napi::FunctionReference &ref = type->dispose_ref;
|
|
487
|
+
|
|
488
|
+
Napi::External<void> external = Napi::External<void>::New(env, (void *)ptr);
|
|
489
|
+
SetValueTag(instance, external, type->ref.marker);
|
|
490
|
+
|
|
491
|
+
Napi::Value self = env.Null();
|
|
492
|
+
napi_value args[] = {
|
|
493
|
+
external
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
ref.Call(self, RG_LEN(args), args);
|
|
497
|
+
};
|
|
498
|
+
dispose_func = func;
|
|
499
|
+
} else {
|
|
500
|
+
dispose = [](Napi::Env, const TypeInfo *, const void *ptr) { free((void *)ptr); };
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
TypeInfo *type = instance->types.AppendDefault();
|
|
504
|
+
RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
|
|
505
|
+
|
|
506
|
+
memcpy((void *)type, (const void *)src, RG_SIZE(*src));
|
|
507
|
+
type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
|
|
508
|
+
type->members.allocator = GetNullAllocator();
|
|
509
|
+
type->dispose = dispose;
|
|
510
|
+
type->dispose_ref = Napi::Persistent(dispose_func);
|
|
511
|
+
|
|
512
|
+
// If the insert succeeds, we cannot fail anymore
|
|
513
|
+
if (named && !instance->types_map.TrySet(type->name, type).second) {
|
|
514
|
+
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
515
|
+
return env.Null();
|
|
516
|
+
}
|
|
517
|
+
err_guard.Disable();
|
|
518
|
+
|
|
519
|
+
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
|
|
520
|
+
SetValueTag(instance, external, &TypeInfoMarker);
|
|
521
|
+
|
|
522
|
+
return external;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
static Napi::Value CallFree(const Napi::CallbackInfo &info)
|
|
526
|
+
{
|
|
527
|
+
Napi::Env env = info.Env();
|
|
528
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
529
|
+
|
|
530
|
+
if (info.Length() < 1) {
|
|
531
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
|
|
532
|
+
return env.Null();
|
|
533
|
+
}
|
|
534
|
+
if (!info[0].IsExternal() || CheckValueTag(instance, info[0], &TypeInfoMarker)) {
|
|
535
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected external", GetValueType(instance, info[0]));
|
|
536
|
+
return env.Null();
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
Napi::External<void> external = info[0].As<Napi::External<void>>();
|
|
540
|
+
void *ptr = external.Data();
|
|
541
|
+
|
|
542
|
+
free(ptr);
|
|
543
|
+
|
|
544
|
+
return env.Undefined();
|
|
545
|
+
}
|
|
546
|
+
|
|
385
547
|
static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
386
548
|
{
|
|
387
549
|
Napi::Env env = info.Env();
|
|
@@ -396,7 +558,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
396
558
|
return env.Null();
|
|
397
559
|
}
|
|
398
560
|
|
|
399
|
-
const TypeInfo *ref = ResolveType(
|
|
561
|
+
const TypeInfo *ref = ResolveType(info[0]);
|
|
400
562
|
int64_t len = (uint16_t)info[1].As<Napi::Number>().Int64Value();
|
|
401
563
|
|
|
402
564
|
if (!ref)
|
|
@@ -448,7 +610,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
448
610
|
type->primitive = PrimitiveKind::Array;
|
|
449
611
|
type->align = ref->align;
|
|
450
612
|
type->size = (int16_t)(len * ref->size);
|
|
451
|
-
type->ref = ref;
|
|
613
|
+
type->ref.type = ref;
|
|
452
614
|
type->hint = hint;
|
|
453
615
|
|
|
454
616
|
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
|
|
@@ -476,11 +638,11 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
476
638
|
|
|
477
639
|
func->name = DuplicateString(name.ToString().Utf8Value().c_str(), &instance->str_alloc).ptr;
|
|
478
640
|
|
|
479
|
-
func->ret.type = ResolveType(
|
|
641
|
+
func->ret.type = ResolveType(ret);
|
|
480
642
|
if (!func->ret.type)
|
|
481
643
|
return false;
|
|
482
|
-
if (func->ret.type
|
|
483
|
-
ThrowError<Napi::
|
|
644
|
+
if (!CanReturnType(func->ret.type)) {
|
|
645
|
+
ThrowError<Napi::TypeError>(env, "You are not allowed to directly return %1 values (maybe try %1 *)", func->ret.type->name);
|
|
484
646
|
return false;
|
|
485
647
|
}
|
|
486
648
|
|
|
@@ -503,12 +665,11 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
503
665
|
for (uint32_t j = 0; j < parameters_len; j++) {
|
|
504
666
|
ParameterInfo param = {};
|
|
505
667
|
|
|
506
|
-
param.type = ResolveType(
|
|
668
|
+
param.type = ResolveType(parameters[j], ¶m.directions);
|
|
507
669
|
if (!param.type)
|
|
508
670
|
return false;
|
|
509
|
-
if (param.type
|
|
510
|
-
|
|
511
|
-
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
|
|
671
|
+
if (!CanPassType(param.type)) {
|
|
672
|
+
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
|
|
512
673
|
return false;
|
|
513
674
|
}
|
|
514
675
|
|
|
@@ -573,12 +734,12 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
|
|
|
573
734
|
|
|
574
735
|
type->name = func->name;
|
|
575
736
|
|
|
576
|
-
type->primitive = PrimitiveKind::
|
|
737
|
+
type->primitive = PrimitiveKind::Prototype;
|
|
577
738
|
type->align = alignof(void *);
|
|
578
739
|
type->size = RG_SIZE(void *);
|
|
579
|
-
type->proto = func;
|
|
740
|
+
type->ref.proto = func;
|
|
580
741
|
|
|
581
|
-
instance->types_map.Set(type);
|
|
742
|
+
instance->types_map.Set(type->name, type);
|
|
582
743
|
|
|
583
744
|
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
|
|
584
745
|
SetValueTag(instance, external, &TypeInfoMarker);
|
|
@@ -586,17 +747,50 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
|
|
|
586
747
|
return external;
|
|
587
748
|
}
|
|
588
749
|
|
|
589
|
-
static Napi::Value
|
|
750
|
+
static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
|
|
590
751
|
{
|
|
591
752
|
Napi::Env env = info.Env();
|
|
592
753
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
593
754
|
|
|
755
|
+
if (info.Length() < 2) {
|
|
756
|
+
ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
|
|
757
|
+
return env.Null();
|
|
758
|
+
}
|
|
759
|
+
if (!info[0].IsString()) {
|
|
760
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
761
|
+
return env.Null();
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
std::string name = info[0].As<Napi::String>();
|
|
765
|
+
const char *alias = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
|
|
766
|
+
|
|
767
|
+
const TypeInfo *type = ResolveType(info[1]);
|
|
768
|
+
if (!type)
|
|
769
|
+
return env.Null();
|
|
770
|
+
|
|
771
|
+
std::pair<const TypeInfo **, bool> ret = instance->types_map.TrySet(alias, type);
|
|
772
|
+
|
|
773
|
+
if (!ret.second) {
|
|
774
|
+
ThrowError<Napi::Error>(env, "Type name '%1' already exists", alias);
|
|
775
|
+
return env.Null();
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
|
|
779
|
+
SetValueTag(instance, external, &TypeInfoMarker);
|
|
780
|
+
|
|
781
|
+
return external;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
|
|
785
|
+
{
|
|
786
|
+
Napi::Env env = info.Env();
|
|
787
|
+
|
|
594
788
|
if (info.Length() < 1) {
|
|
595
789
|
ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
|
|
596
790
|
return env.Null();
|
|
597
791
|
}
|
|
598
792
|
|
|
599
|
-
const TypeInfo *type = ResolveType(
|
|
793
|
+
const TypeInfo *type = ResolveType(info[0]);
|
|
600
794
|
if (!type)
|
|
601
795
|
return env.Null();
|
|
602
796
|
|
|
@@ -606,20 +800,39 @@ static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
|
|
|
606
800
|
static Napi::Value GetTypeAlign(const Napi::CallbackInfo &info)
|
|
607
801
|
{
|
|
608
802
|
Napi::Env env = info.Env();
|
|
609
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
610
803
|
|
|
611
804
|
if (info.Length() < 1) {
|
|
612
805
|
ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
|
|
613
806
|
return env.Null();
|
|
614
807
|
}
|
|
615
808
|
|
|
616
|
-
const TypeInfo *type = ResolveType(
|
|
809
|
+
const TypeInfo *type = ResolveType(info[0]);
|
|
617
810
|
if (!type)
|
|
618
811
|
return env.Null();
|
|
619
812
|
|
|
620
813
|
return Napi::Number::New(env, type->align);
|
|
621
814
|
}
|
|
622
815
|
|
|
816
|
+
static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
|
|
817
|
+
{
|
|
818
|
+
Napi::Env env = info.Env();
|
|
819
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
820
|
+
|
|
821
|
+
if (info.Length() < 1) {
|
|
822
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
|
|
823
|
+
return env.Null();
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
const TypeInfo *type = ResolveType(info[0]);
|
|
827
|
+
if (!type)
|
|
828
|
+
return env.Null();
|
|
829
|
+
|
|
830
|
+
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
|
|
831
|
+
SetValueTag(instance, external, &TypeInfoMarker);
|
|
832
|
+
|
|
833
|
+
return external;
|
|
834
|
+
}
|
|
835
|
+
|
|
623
836
|
static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
624
837
|
{
|
|
625
838
|
Napi::Env env = info.Env();
|
|
@@ -630,12 +843,62 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
|
630
843
|
return env.Null();
|
|
631
844
|
}
|
|
632
845
|
|
|
633
|
-
const TypeInfo *type = ResolveType(
|
|
846
|
+
const TypeInfo *type = ResolveType(info[0]);
|
|
634
847
|
if (!type)
|
|
635
848
|
return env.Null();
|
|
849
|
+
|
|
636
850
|
if (type->defn.IsEmpty()) {
|
|
637
|
-
|
|
638
|
-
|
|
851
|
+
Napi::Object defn = Napi::Object::New(env);
|
|
852
|
+
|
|
853
|
+
defn.Set("name", Napi::String::New(env, type->name));
|
|
854
|
+
defn.Set("primitive", PrimitiveKindNames[(int)type->primitive]);
|
|
855
|
+
defn.Set("size", Napi::Number::New(env, (double)type->size));
|
|
856
|
+
defn.Set("alignment", Napi::Number::New(env, (double)type->align));
|
|
857
|
+
|
|
858
|
+
switch (type->primitive) {
|
|
859
|
+
case PrimitiveKind::Void:
|
|
860
|
+
case PrimitiveKind::Bool:
|
|
861
|
+
case PrimitiveKind::Int8:
|
|
862
|
+
case PrimitiveKind::UInt8:
|
|
863
|
+
case PrimitiveKind::Int16:
|
|
864
|
+
case PrimitiveKind::UInt16:
|
|
865
|
+
case PrimitiveKind::Int32:
|
|
866
|
+
case PrimitiveKind::UInt32:
|
|
867
|
+
case PrimitiveKind::Int64:
|
|
868
|
+
case PrimitiveKind::UInt64:
|
|
869
|
+
case PrimitiveKind::String:
|
|
870
|
+
case PrimitiveKind::String16:
|
|
871
|
+
case PrimitiveKind::Float32:
|
|
872
|
+
case PrimitiveKind::Float64:
|
|
873
|
+
case PrimitiveKind::Prototype:
|
|
874
|
+
case PrimitiveKind::Callback: {} break;
|
|
875
|
+
|
|
876
|
+
case PrimitiveKind::Array: {
|
|
877
|
+
uint32_t len = type->size / type->ref.type->size;
|
|
878
|
+
defn.Set("length", Napi::Number::New(env, (double)len));
|
|
879
|
+
} [[fallthrough]];
|
|
880
|
+
case PrimitiveKind::Pointer: {
|
|
881
|
+
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type->ref.type);
|
|
882
|
+
SetValueTag(instance, external, &TypeInfoMarker);
|
|
883
|
+
|
|
884
|
+
defn.Set("ref", external);
|
|
885
|
+
} break;
|
|
886
|
+
case PrimitiveKind::Record: {
|
|
887
|
+
Napi::Object members = Napi::Object::New(env);
|
|
888
|
+
|
|
889
|
+
for (const RecordMember &member: type->members) {
|
|
890
|
+
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)member.type);
|
|
891
|
+
SetValueTag(instance, external, &TypeInfoMarker);
|
|
892
|
+
|
|
893
|
+
members.Set(member.name, external);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
defn.Set("members", members);
|
|
897
|
+
} break;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
defn.Freeze();
|
|
901
|
+
type->defn.Reset(defn, 1);
|
|
639
902
|
}
|
|
640
903
|
|
|
641
904
|
return type->defn.Value();
|
|
@@ -743,12 +1006,11 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
|
743
1006
|
for (Size i = func.parameters.len; i < (Size)info.Length(); i += 2) {
|
|
744
1007
|
ParameterInfo param = {};
|
|
745
1008
|
|
|
746
|
-
param.type = ResolveType(
|
|
1009
|
+
param.type = ResolveType(info[i], ¶m.directions);
|
|
747
1010
|
if (RG_UNLIKELY(!param.type))
|
|
748
1011
|
return env.Null();
|
|
749
|
-
if (RG_UNLIKELY(param.type
|
|
750
|
-
|
|
751
|
-
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", PrimitiveKindNames[(int)param.type->primitive]);
|
|
1012
|
+
if (RG_UNLIKELY(!CanPassType(param.type))) {
|
|
1013
|
+
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", PrimitiveKindNames[(int)param.type->primitive]);
|
|
752
1014
|
return env.Null();
|
|
753
1015
|
}
|
|
754
1016
|
|
|
@@ -866,7 +1128,7 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
|
|
|
866
1128
|
}
|
|
867
1129
|
async->Queue();
|
|
868
1130
|
|
|
869
|
-
return env.
|
|
1131
|
+
return env.Undefined();
|
|
870
1132
|
}
|
|
871
1133
|
|
|
872
1134
|
static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConvention convention)
|
|
@@ -923,7 +1185,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
923
1185
|
uint16_t ordinal = (uint16_t)info[0].As<Napi::Number>().Uint32Value();
|
|
924
1186
|
|
|
925
1187
|
func->decorated_name = nullptr;
|
|
926
|
-
func->func = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)ordinal);
|
|
1188
|
+
func->func = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
|
|
927
1189
|
}
|
|
928
1190
|
#else
|
|
929
1191
|
if (func->decorated_name) {
|
|
@@ -1032,6 +1294,89 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
1032
1294
|
return obj;
|
|
1033
1295
|
}
|
|
1034
1296
|
|
|
1297
|
+
static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
|
|
1298
|
+
{
|
|
1299
|
+
Napi::Env env = info.Env();
|
|
1300
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1301
|
+
|
|
1302
|
+
if (info.Length() < 2) {
|
|
1303
|
+
ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
|
|
1304
|
+
return env.Null();
|
|
1305
|
+
}
|
|
1306
|
+
if (!info[0].IsFunction()) {
|
|
1307
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, info[0]));
|
|
1308
|
+
return env.Null();
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
Napi::Function func = info[0].As<Napi::Function>();
|
|
1312
|
+
|
|
1313
|
+
const TypeInfo *type = ResolveType(info[1]);
|
|
1314
|
+
if (!type)
|
|
1315
|
+
return env.Null();
|
|
1316
|
+
if (type->primitive != PrimitiveKind::Callback) {
|
|
1317
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected <callback> * type", type->name);
|
|
1318
|
+
return env.Null();
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
int idx = CountTrailingZeros(~instance->registered_trampolines);
|
|
1322
|
+
|
|
1323
|
+
if (RG_UNLIKELY(idx >= MaxTrampolines)) {
|
|
1324
|
+
ThrowError<Napi::Error>(env, "Too many registered callbacks are in use (max = %1)", MaxTrampolines);
|
|
1325
|
+
return env.Null();
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
instance->registered_trampolines |= 1u << idx;
|
|
1329
|
+
idx += MaxTrampolines;
|
|
1330
|
+
|
|
1331
|
+
TrampolineInfo *trampoline = &instance->trampolines[idx];
|
|
1332
|
+
|
|
1333
|
+
trampoline->proto = type->ref.proto;
|
|
1334
|
+
trampoline->func.Reset(func, 1);
|
|
1335
|
+
trampoline->generation = -1;
|
|
1336
|
+
|
|
1337
|
+
void *ptr = GetTrampoline(idx, type->ref.proto);
|
|
1338
|
+
|
|
1339
|
+
Napi::External<void> external = Napi::External<void>::New(env, ptr);
|
|
1340
|
+
SetValueTag(instance, external, type->ref.marker);
|
|
1341
|
+
|
|
1342
|
+
return external;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
|
|
1346
|
+
{
|
|
1347
|
+
Napi::Env env = info.Env();
|
|
1348
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1349
|
+
|
|
1350
|
+
if (info.Length() < 1) {
|
|
1351
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
|
|
1352
|
+
return env.Null();
|
|
1353
|
+
}
|
|
1354
|
+
if (!info[0].IsExternal()) {
|
|
1355
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for id, expected registered callback", GetValueType(instance, info[0]));
|
|
1356
|
+
return env.Null();
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
Napi::External<void> external = info[0].As<Napi::External<void>>();
|
|
1360
|
+
void *ptr = external.Data();
|
|
1361
|
+
|
|
1362
|
+
for (Size i = 0; i < MaxTrampolines; i++) {
|
|
1363
|
+
Size idx = i + MaxTrampolines;
|
|
1364
|
+
|
|
1365
|
+
if (!(instance->registered_trampolines & (1u << i)))
|
|
1366
|
+
continue;
|
|
1367
|
+
|
|
1368
|
+
const TrampolineInfo &trampoline = instance->trampolines[idx];
|
|
1369
|
+
|
|
1370
|
+
if (GetTrampoline(idx, trampoline.proto) == ptr) {
|
|
1371
|
+
instance->registered_trampolines &= ~(1u << i);
|
|
1372
|
+
return env.Undefined();
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
ThrowError<Napi::Error>(env, "Could not find matching registered callback");
|
|
1377
|
+
return env.Null();
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1035
1380
|
LibraryHolder::~LibraryHolder()
|
|
1036
1381
|
{
|
|
1037
1382
|
#ifdef _WIN32
|
|
@@ -1058,108 +1403,91 @@ void LibraryHolder::Unref() const
|
|
|
1058
1403
|
}
|
|
1059
1404
|
}
|
|
1060
1405
|
|
|
1061
|
-
static
|
|
1062
|
-
int16_t size, int16_t align)
|
|
1406
|
+
static inline PrimitiveKind GetIntegerPrimitive(Size len, bool sign)
|
|
1063
1407
|
{
|
|
1408
|
+
switch (len) {
|
|
1409
|
+
case 1: return sign ? PrimitiveKind::Int8 : PrimitiveKind::UInt8;
|
|
1410
|
+
case 2: return sign ? PrimitiveKind::Int16 : PrimitiveKind::UInt16;
|
|
1411
|
+
case 4: return sign ? PrimitiveKind::Int32 : PrimitiveKind::UInt32;
|
|
1412
|
+
case 8: return sign ? PrimitiveKind::Int64 : PrimitiveKind::UInt64;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
RG_UNREACHABLE();
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initializer_list<const char *> names,
|
|
1419
|
+
PrimitiveKind primitive, int16_t size, int16_t align, const char *ref = nullptr)
|
|
1420
|
+
{
|
|
1421
|
+
RG_ASSERT(names.size() > 0);
|
|
1064
1422
|
RG_ASSERT(align <= size);
|
|
1065
1423
|
|
|
1424
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1425
|
+
|
|
1066
1426
|
TypeInfo *type = instance->types.AppendDefault();
|
|
1067
1427
|
|
|
1068
|
-
type->name =
|
|
1428
|
+
type->name = *names.begin();
|
|
1069
1429
|
|
|
1070
1430
|
type->primitive = primitive;
|
|
1071
1431
|
type->size = size;
|
|
1072
1432
|
type->align = align;
|
|
1073
1433
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1434
|
+
if (ref) {
|
|
1435
|
+
const TypeInfo *marker = instance->types_map.FindValue(ref, nullptr);
|
|
1436
|
+
RG_ASSERT(marker);
|
|
1077
1437
|
|
|
1078
|
-
|
|
1079
|
-
static inline PrimitiveKind GetIntegerPrimitive(bool sign)
|
|
1080
|
-
{
|
|
1081
|
-
switch (RG_SIZE(T)) {
|
|
1082
|
-
case 1: return sign ? PrimitiveKind::Int8 : PrimitiveKind::UInt8;
|
|
1083
|
-
case 2: return sign ? PrimitiveKind::Int16 : PrimitiveKind::UInt16;
|
|
1084
|
-
case 4: return sign ? PrimitiveKind::Int32 : PrimitiveKind::UInt32;
|
|
1085
|
-
case 8: return sign ? PrimitiveKind::Int64 : PrimitiveKind::UInt64;
|
|
1438
|
+
type->ref.marker = marker;
|
|
1086
1439
|
}
|
|
1087
1440
|
|
|
1088
|
-
|
|
1441
|
+
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
|
|
1442
|
+
SetValueTag(instance, external, &TypeInfoMarker);
|
|
1443
|
+
|
|
1444
|
+
for (const char *name: names) {
|
|
1445
|
+
std::pair<const TypeInfo **, bool> ret = instance->types_map.TrySet(name, type);
|
|
1446
|
+
RG_ASSERT(ret.second);
|
|
1447
|
+
|
|
1448
|
+
if (!EndsWith(name, "*")) {
|
|
1449
|
+
map.Set(name, external);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1089
1452
|
}
|
|
1090
1453
|
|
|
1091
1454
|
static Napi::Object InitBaseTypes(Napi::Env env)
|
|
1092
1455
|
{
|
|
1093
1456
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1094
1457
|
|
|
1095
|
-
RG_ASSERT(!instance->types.len);
|
|
1096
|
-
|
|
1097
|
-
RegisterPrimitiveType(instance, "void", PrimitiveKind::Void, 0, 0);
|
|
1098
|
-
RegisterPrimitiveType(instance, "void *", PrimitiveKind::Pointer, RG_SIZE(void *), alignof(void *));
|
|
1099
|
-
RegisterPrimitiveType(instance, "bool", PrimitiveKind::Bool, RG_SIZE(bool), alignof(bool));
|
|
1100
|
-
RegisterPrimitiveType(instance, "int8", PrimitiveKind::Int8, 1, 1);
|
|
1101
|
-
RegisterPrimitiveType(instance, "int8_t", PrimitiveKind::Int8, 1, 1);
|
|
1102
|
-
RegisterPrimitiveType(instance, "uint8", PrimitiveKind::UInt8, 1, 1);
|
|
1103
|
-
RegisterPrimitiveType(instance, "uint8_t", PrimitiveKind::UInt8, 1, 1);
|
|
1104
|
-
RegisterPrimitiveType(instance, "char", PrimitiveKind::Int8, 1, 1);
|
|
1105
|
-
RegisterPrimitiveType(instance, "uchar", PrimitiveKind::UInt8, 1, 1);
|
|
1106
|
-
RegisterPrimitiveType(instance, "unsigned char", PrimitiveKind::UInt8, 1, 1);
|
|
1107
|
-
RegisterPrimitiveType(instance, "char16", PrimitiveKind::Int16, 2, 2);
|
|
1108
|
-
RegisterPrimitiveType(instance, "char16_t", PrimitiveKind::Int16, 2, 2);
|
|
1109
|
-
RegisterPrimitiveType(instance, "int16", PrimitiveKind::Int16, 2, 2);
|
|
1110
|
-
RegisterPrimitiveType(instance, "int16_t", PrimitiveKind::Int16, 2, 2);
|
|
1111
|
-
RegisterPrimitiveType(instance, "uint16", PrimitiveKind::UInt16, 2, 2);
|
|
1112
|
-
RegisterPrimitiveType(instance, "uint16_t", PrimitiveKind::UInt16, 2, 2);
|
|
1113
|
-
RegisterPrimitiveType(instance, "short", PrimitiveKind::Int16, 2, 2);
|
|
1114
|
-
RegisterPrimitiveType(instance, "ushort", PrimitiveKind::UInt16, 2, 2);
|
|
1115
|
-
RegisterPrimitiveType(instance, "unsigned short", PrimitiveKind::UInt16, 2, 2);
|
|
1116
|
-
RegisterPrimitiveType(instance, "int32", PrimitiveKind::Int32, 4, 4);
|
|
1117
|
-
RegisterPrimitiveType(instance, "int32_t", PrimitiveKind::Int32, 4, 4);
|
|
1118
|
-
RegisterPrimitiveType(instance, "uint32", PrimitiveKind::UInt32, 4, 4);
|
|
1119
|
-
RegisterPrimitiveType(instance, "uint32_t", PrimitiveKind::UInt32, 4, 4);
|
|
1120
|
-
RegisterPrimitiveType(instance, "int", PrimitiveKind::Int32, 4, 4);
|
|
1121
|
-
RegisterPrimitiveType(instance, "uint", PrimitiveKind::UInt32, 4, 4);
|
|
1122
|
-
RegisterPrimitiveType(instance, "unsigned int", PrimitiveKind::UInt32, 4, 4);
|
|
1123
|
-
RegisterPrimitiveType(instance, "int64", PrimitiveKind::Int64, 8, alignof(int64_t));
|
|
1124
|
-
RegisterPrimitiveType(instance, "int64_t", PrimitiveKind::Int64, 8, alignof(int64_t));
|
|
1125
|
-
RegisterPrimitiveType(instance, "uint64", PrimitiveKind::UInt64, 8, alignof(int64_t));
|
|
1126
|
-
RegisterPrimitiveType(instance, "uint64_t", PrimitiveKind::UInt64, 8, alignof(int64_t));
|
|
1127
|
-
RegisterPrimitiveType(instance, "intptr", GetIntegerPrimitive<intptr_t>(true), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1128
|
-
RegisterPrimitiveType(instance, "intptr_t", GetIntegerPrimitive<intptr_t>(true), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1129
|
-
RegisterPrimitiveType(instance, "uintptr", GetIntegerPrimitive<intptr_t>(false), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1130
|
-
RegisterPrimitiveType(instance, "uintptr_t", GetIntegerPrimitive<intptr_t>(false), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1131
|
-
RegisterPrimitiveType(instance, "long", GetIntegerPrimitive<long>(true), RG_SIZE(long), alignof(long));
|
|
1132
|
-
RegisterPrimitiveType(instance, "ulong", GetIntegerPrimitive<long>(false), RG_SIZE(long), alignof(long));
|
|
1133
|
-
RegisterPrimitiveType(instance, "unsigned long", GetIntegerPrimitive<long>(false), RG_SIZE(long), alignof(long));
|
|
1134
|
-
RegisterPrimitiveType(instance, "longlong", PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
|
|
1135
|
-
RegisterPrimitiveType(instance, "long long", PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
|
|
1136
|
-
RegisterPrimitiveType(instance, "ulonglong", PrimitiveKind::UInt64, RG_SIZE(uint64_t), alignof(uint64_t));
|
|
1137
|
-
RegisterPrimitiveType(instance, "unsigned long long", PrimitiveKind::UInt64, RG_SIZE(uint64_t), alignof(uint64_t));
|
|
1138
|
-
RegisterPrimitiveType(instance, "float32", PrimitiveKind::Float32, 4, alignof(float));
|
|
1139
|
-
RegisterPrimitiveType(instance, "float64", PrimitiveKind::Float64, 8, alignof(double));
|
|
1140
|
-
RegisterPrimitiveType(instance, "float", PrimitiveKind::Float32, 4, alignof(float));
|
|
1141
|
-
RegisterPrimitiveType(instance, "double", PrimitiveKind::Float64, 8, alignof(double));
|
|
1142
|
-
RegisterPrimitiveType(instance, "string", PrimitiveKind::String, RG_SIZE(void *), alignof(void *));
|
|
1143
|
-
RegisterPrimitiveType(instance, "string16", PrimitiveKind::String16, RG_SIZE(void *), alignof(void *));
|
|
1144
|
-
RegisterPrimitiveType(instance, "str", PrimitiveKind::String, RG_SIZE(void *), alignof(void *));
|
|
1145
|
-
RegisterPrimitiveType(instance, "str16", PrimitiveKind::String16, RG_SIZE(void *), alignof(void *));
|
|
1146
|
-
|
|
1147
1458
|
Napi::Object types = Napi::Object::New(env);
|
|
1148
|
-
for (TypeInfo &type: instance->types) {
|
|
1149
|
-
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, &type);
|
|
1150
|
-
SetValueTag(instance, external, &TypeInfoMarker);
|
|
1151
1459
|
|
|
1152
|
-
|
|
1460
|
+
RegisterPrimitiveType(env, types, {"void"}, PrimitiveKind::Void, 0, 0);
|
|
1461
|
+
RegisterPrimitiveType(env, types, {"bool"}, PrimitiveKind::Bool, RG_SIZE(bool), alignof(bool));
|
|
1462
|
+
RegisterPrimitiveType(env, types, {"int8_t", "int8"}, PrimitiveKind::Int8, 1, 1);
|
|
1463
|
+
RegisterPrimitiveType(env, types, {"uint8_t", "uint8"}, PrimitiveKind::UInt8, 1, 1);
|
|
1464
|
+
RegisterPrimitiveType(env, types, {"char"}, PrimitiveKind::Int8, 1, 1);
|
|
1465
|
+
RegisterPrimitiveType(env, types, {"unsigned char", "uchar"}, PrimitiveKind::UInt8, 1, 1);
|
|
1466
|
+
RegisterPrimitiveType(env, types, {"char16_t", "char16"}, PrimitiveKind::Int16, 2, 2);
|
|
1467
|
+
RegisterPrimitiveType(env, types, {"int16_t", "int16"}, PrimitiveKind::Int16, 2, 2);
|
|
1468
|
+
RegisterPrimitiveType(env, types, {"uint16_t", "uint16"}, PrimitiveKind::UInt16, 2, 2);
|
|
1469
|
+
RegisterPrimitiveType(env, types, {"short"}, PrimitiveKind::Int16, 2, 2);
|
|
1470
|
+
RegisterPrimitiveType(env, types, {"unsigned short", "ushort"}, PrimitiveKind::UInt16, 2, 2);
|
|
1471
|
+
RegisterPrimitiveType(env, types, {"int32_t", "int32"}, PrimitiveKind::Int32, 4, 4);
|
|
1472
|
+
RegisterPrimitiveType(env, types, {"uint32_t", "uint32"}, PrimitiveKind::UInt32, 4, 4);
|
|
1473
|
+
RegisterPrimitiveType(env, types, {"int"}, PrimitiveKind::Int32, 4, 4);
|
|
1474
|
+
RegisterPrimitiveType(env, types, {"unsigned int", "uint"}, PrimitiveKind::UInt32, 4, 4);
|
|
1475
|
+
RegisterPrimitiveType(env, types, {"int64_t", "int64"}, PrimitiveKind::Int64, 8, alignof(int64_t));
|
|
1476
|
+
RegisterPrimitiveType(env, types, {"uint64_t", "uint64"}, PrimitiveKind::UInt64, 8, alignof(int64_t));
|
|
1477
|
+
RegisterPrimitiveType(env, types, {"intptr_t", "intptr"}, GetIntegerPrimitive(RG_SIZE(intptr_t), true), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1478
|
+
RegisterPrimitiveType(env, types, {"uintptr_t", "uintptr"}, GetIntegerPrimitive(RG_SIZE(intptr_t), false), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1479
|
+
RegisterPrimitiveType(env, types, {"long"}, GetIntegerPrimitive(RG_SIZE(long), true), RG_SIZE(long), alignof(long));
|
|
1480
|
+
RegisterPrimitiveType(env, types, {"unsigned long", "ulong"}, GetIntegerPrimitive(RG_SIZE(long), false), RG_SIZE(long), alignof(long));
|
|
1481
|
+
RegisterPrimitiveType(env, types, {"long long", "longlong"}, PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
|
|
1482
|
+
RegisterPrimitiveType(env, types, {"unsigned long long", "ulonglong"}, PrimitiveKind::UInt64, RG_SIZE(uint64_t), alignof(uint64_t));
|
|
1483
|
+
RegisterPrimitiveType(env, types, {"float", "float32"}, PrimitiveKind::Float32, 4, alignof(float));
|
|
1484
|
+
RegisterPrimitiveType(env, types, {"double", "float64"}, PrimitiveKind::Float64, 8, alignof(double));
|
|
1485
|
+
RegisterPrimitiveType(env, types, {"char *", "str", "string"}, PrimitiveKind::String, RG_SIZE(void *), alignof(void *), "char");
|
|
1486
|
+
RegisterPrimitiveType(env, types, {"char16_t *", "char16 *", "str16", "string16"}, PrimitiveKind::String16, RG_SIZE(void *), alignof(void *), "char16_t");
|
|
1487
|
+
|
|
1488
|
+
instance->void_type = instance->types_map.FindValue("void", nullptr);
|
|
1489
|
+
RG_ASSERT(instance->void_type);
|
|
1153
1490
|
|
|
1154
|
-
if (strchr(type.name, ' ')) {
|
|
1155
|
-
char name_buf[64] = {};
|
|
1156
|
-
for (Size i = 0; type.name[i]; i++) {
|
|
1157
|
-
RG_ASSERT(i < RG_SIZE(name_buf) - 1);
|
|
1158
|
-
name_buf[i] = type.name[i] != ' ' ? type.name[i] : '_';
|
|
1159
|
-
}
|
|
1160
|
-
types.Set(name_buf, external);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
1491
|
types.Freeze();
|
|
1164
1492
|
|
|
1165
1493
|
return types;
|
|
@@ -1211,6 +1539,37 @@ InstanceData::~InstanceData()
|
|
|
1211
1539
|
}
|
|
1212
1540
|
}
|
|
1213
1541
|
|
|
1542
|
+
static Napi::Value CastValue(const Napi::CallbackInfo &info)
|
|
1543
|
+
{
|
|
1544
|
+
Napi::Env env = info.Env();
|
|
1545
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1546
|
+
|
|
1547
|
+
if (RG_UNLIKELY(info.Length() < 2)) {
|
|
1548
|
+
ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
|
|
1549
|
+
return env.Null();
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
Napi::Value value = info[0];
|
|
1553
|
+
|
|
1554
|
+
const TypeInfo *type = ResolveType(info[1]);
|
|
1555
|
+
if (RG_UNLIKELY(!type))
|
|
1556
|
+
return env.Null();
|
|
1557
|
+
if (type->primitive != PrimitiveKind::Pointer) {
|
|
1558
|
+
ThrowError<Napi::TypeError>(env, "Only pointer types can be used for casting");
|
|
1559
|
+
return env.Null();
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
ValueCast *cast = new ValueCast;
|
|
1563
|
+
|
|
1564
|
+
cast->ref.Reset(value, 1);
|
|
1565
|
+
cast->type = type;
|
|
1566
|
+
|
|
1567
|
+
Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::Env, ValueCast *cast) { delete cast; });
|
|
1568
|
+
SetValueTag(instance, external, &CastMarker);
|
|
1569
|
+
|
|
1570
|
+
return external;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1214
1573
|
template <typename Func>
|
|
1215
1574
|
static void SetExports(Napi::Env env, Func func)
|
|
1216
1575
|
{
|
|
@@ -1218,13 +1577,15 @@ static void SetExports(Napi::Env env, Func func)
|
|
|
1218
1577
|
|
|
1219
1578
|
func("struct", Napi::Function::New(env, CreatePaddedStructType));
|
|
1220
1579
|
func("pack", Napi::Function::New(env, CreatePackedStructType));
|
|
1221
|
-
func("
|
|
1580
|
+
func("opaque", Napi::Function::New(env, CreateOpaqueType));
|
|
1222
1581
|
func("pointer", Napi::Function::New(env, CreatePointerType));
|
|
1223
1582
|
func("array", Napi::Function::New(env, CreateArrayType));
|
|
1224
1583
|
func("callback", Napi::Function::New(env, CreateCallbackType));
|
|
1584
|
+
func("alias", Napi::Function::New(env, CreateTypeAlias));
|
|
1225
1585
|
|
|
1226
1586
|
func("sizeof", Napi::Function::New(env, GetTypeSize));
|
|
1227
1587
|
func("alignof", Napi::Function::New(env, GetTypeAlign));
|
|
1588
|
+
func("resolve", Napi::Function::New(env, GetResolvedType));
|
|
1228
1589
|
func("introspect", Napi::Function::New(env, GetTypeDefinition));
|
|
1229
1590
|
|
|
1230
1591
|
func("load", Napi::Function::New(env, LoadSharedLibrary));
|
|
@@ -1233,6 +1594,14 @@ static void SetExports(Napi::Env env, Func func)
|
|
|
1233
1594
|
func("out", Napi::Function::New(env, MarkOut));
|
|
1234
1595
|
func("inout", Napi::Function::New(env, MarkInOut));
|
|
1235
1596
|
|
|
1597
|
+
func("disposable", Napi::Function::New(env, CreateDisposableType));
|
|
1598
|
+
func("free", Napi::Function::New(env, CallFree));
|
|
1599
|
+
|
|
1600
|
+
func("register", Napi::Function::New(env, RegisterCallback));
|
|
1601
|
+
func("unregister", Napi::Function::New(env, UnregisterCallback));
|
|
1602
|
+
|
|
1603
|
+
func("as", Napi::Function::New(env, CastValue));
|
|
1604
|
+
|
|
1236
1605
|
#if defined(_WIN32)
|
|
1237
1606
|
func("extension", Napi::String::New(env, ".dll"));
|
|
1238
1607
|
#elif defined(__APPLE__)
|