koffi 3.0.2 → 3.1.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/CHANGELOG.md +32 -7
- package/cnoke.cjs +2 -2
- package/doc/benchmarks.md +2 -2
- package/doc/callbacks.md +8 -27
- package/doc/{input.md → composites.md} +161 -147
- package/doc/contribute.md +2 -1
- package/doc/index.md +0 -14
- package/doc/{functions.md → load.md} +54 -113
- package/doc/migration.md +4 -7
- package/doc/misc.md +0 -103
- package/doc/output.md +5 -11
- package/doc/pointers.md +76 -17
- package/doc/primitives.md +151 -0
- package/doc/start.md +3 -13
- package/doc/types.md +88 -0
- package/doc/unions.md +0 -186
- package/doc/values.md +134 -0
- package/index.d.ts +23 -4
- package/lib/native/base/base.cc +142 -90
- package/lib/native/base/base.hh +69 -165
- package/package.json +16 -15
- package/src/koffi/CMakeLists.txt +19 -17
- package/src/koffi/index.cjs +8 -3
- package/src/koffi/index.js +1 -1
- package/src/koffi/indirect.cjs +8 -3
- package/src/koffi/indirect.js +1 -1
- package/src/koffi/src/abi/arm64.cc +47 -62
- package/src/koffi/src/abi/riscv64.cc +38 -57
- package/src/koffi/src/abi/x64sysv.cc +38 -57
- package/src/koffi/src/abi/x64win.cc +47 -65
- package/src/koffi/src/abi/x86.cc +46 -59
- package/src/koffi/src/call.cc +239 -133
- package/src/koffi/src/call.hh +5 -10
- package/src/koffi/src/ffi.cc +211 -90
- package/src/koffi/src/ffi.hh +36 -16
- package/src/koffi/src/parser.cc +3 -3
- package/src/koffi/src/parser.hh +2 -2
- package/src/koffi/src/static.cjs +8 -0
- package/src/koffi/src/static.js +11 -0
- package/src/koffi/src/type.cc +43 -33
- package/src/koffi/src/type.hh +1 -1
- package/src/koffi/src/util.cc +73 -173
- package/src/koffi/src/util.hh +84 -43
- package/src/koffi/src/uv.cc +1 -1
- package/vendor/node-addon-api/README.md +1 -1
- package/vendor/node-addon-api/napi-inl.h +213 -35
- package/vendor/node-addon-api/napi.h +118 -7
- package/doc/variables.md +0 -102
package/src/koffi/src/call.cc
CHANGED
|
@@ -45,6 +45,8 @@ static const Size TrampolineSize = ((const uint8_t *)&TrampolineEnd - Trampoline
|
|
|
45
45
|
|
|
46
46
|
#endif
|
|
47
47
|
|
|
48
|
+
static napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
|
|
49
|
+
|
|
48
50
|
#if defined(K_DEBUG)
|
|
49
51
|
CallData::~CallData()
|
|
50
52
|
{
|
|
@@ -77,7 +79,7 @@ void CallData::Finalize()
|
|
|
77
79
|
K_ASSERT(GetArrayLength(env, value) == 1);
|
|
78
80
|
|
|
79
81
|
Size len = strnlen((const char *)out.ptr, out.max_len);
|
|
80
|
-
|
|
82
|
+
napi_value str = NewString(env, (const char *)out.ptr, len);
|
|
81
83
|
|
|
82
84
|
napi_set_element(env, value, 0, str);
|
|
83
85
|
} break;
|
|
@@ -87,7 +89,7 @@ void CallData::Finalize()
|
|
|
87
89
|
K_ASSERT(GetArrayLength(env, value) == 1);
|
|
88
90
|
|
|
89
91
|
Size len = NullTerminatedLength((const char16_t *)out.ptr, out.max_len);
|
|
90
|
-
|
|
92
|
+
napi_value str = NewString(env, (const char16_t *)out.ptr, len);
|
|
91
93
|
|
|
92
94
|
napi_set_element(env, value, 0, str);
|
|
93
95
|
} break;
|
|
@@ -97,7 +99,7 @@ void CallData::Finalize()
|
|
|
97
99
|
K_ASSERT(GetArrayLength(env, value) == 1);
|
|
98
100
|
|
|
99
101
|
Size len = NullTerminatedLength((const char32_t *)out.ptr, out.max_len);
|
|
100
|
-
|
|
102
|
+
napi_value str = NewString(env, (const char32_t *)out.ptr, len);
|
|
101
103
|
|
|
102
104
|
napi_set_element(env, value, 0, str);
|
|
103
105
|
} break;
|
|
@@ -117,7 +119,7 @@ void CallData::Finalize()
|
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
for (const OutArgument &out: out_arguments) {
|
|
120
|
-
|
|
122
|
+
node_api_delete_reference(env, out.ref);
|
|
121
123
|
}
|
|
122
124
|
}
|
|
123
125
|
|
|
@@ -132,7 +134,7 @@ void CallData::Finalize()
|
|
|
132
134
|
K_ASSERT(trampoline->func);
|
|
133
135
|
|
|
134
136
|
trampoline->state = 0;
|
|
135
|
-
|
|
137
|
+
node_api_delete_reference(env, trampoline->func);
|
|
136
138
|
trampoline->func = nullptr;
|
|
137
139
|
|
|
138
140
|
shared.available.Append(idx);
|
|
@@ -255,8 +257,6 @@ Size CallData::PushStringValue(napi_value value, const char **out_str)
|
|
|
255
257
|
|
|
256
258
|
// Fast path for small strings
|
|
257
259
|
if (available >= 4096) [[likely]] {
|
|
258
|
-
char *ptr = (char *)mem->heap.ptr;
|
|
259
|
-
|
|
260
260
|
napi_status status = napi_get_value_string_utf8(env, value, ptr, 4096, &len);
|
|
261
261
|
if (status == napi_string_expected)
|
|
262
262
|
return -1;
|
|
@@ -376,17 +376,16 @@ Size CallData::PushString32Value(napi_value value, const char32_t **out_str32)
|
|
|
376
376
|
return j;
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
static
|
|
379
|
+
static FORCE_INLINE napi_value GetMemberValue(napi_env env, napi_value obj, const RecordMember &member)
|
|
380
380
|
{
|
|
381
|
-
napi_value value
|
|
381
|
+
napi_value value;
|
|
382
382
|
|
|
383
383
|
if (member.key) {
|
|
384
|
-
napi_value key
|
|
385
|
-
napi_get_reference_value(env, member.key, &key);
|
|
386
|
-
|
|
387
|
-
napi_get_property(env, obj, key, &value);
|
|
384
|
+
napi_value key;
|
|
385
|
+
NAPI_OK(napi_get_reference_value(env, member.key, &key));
|
|
386
|
+
NAPI_OK(napi_get_property(env, obj, key, &value));
|
|
388
387
|
} else {
|
|
389
|
-
napi_get_named_property(env, obj, member.name, &value);
|
|
388
|
+
NAPI_OK(napi_get_named_property(env, obj, member.name, &value));
|
|
390
389
|
}
|
|
391
390
|
|
|
392
391
|
return value;
|
|
@@ -394,10 +393,14 @@ static inline napi_value GetMemberValue(napi_env env, napi_value obj, const Reco
|
|
|
394
393
|
|
|
395
394
|
bool CallData::PushObject(napi_value obj, const TypeInfo *type, uint8_t *origin)
|
|
396
395
|
{
|
|
397
|
-
K_ASSERT(IsObject(env, obj));
|
|
398
396
|
K_ASSERT(type->primitive == PrimitiveKind::Record ||
|
|
399
397
|
type->primitive == PrimitiveKind::Union);
|
|
400
398
|
|
|
399
|
+
if (GetKindOf(env, obj) != napi_object) [[unlikely]] {
|
|
400
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, obj));
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
|
|
401
404
|
Span<const RecordMember> members = type->members;
|
|
402
405
|
|
|
403
406
|
if (type->primitive == PrimitiveKind::Union) {
|
|
@@ -547,12 +550,7 @@ bool CallData::PushObject(napi_value obj, const TypeInfo *type, uint8_t *origin)
|
|
|
547
550
|
} break;
|
|
548
551
|
case PrimitiveKind::Record:
|
|
549
552
|
case PrimitiveKind::Union: {
|
|
550
|
-
if (!
|
|
551
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
552
|
-
return false;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
if (!PushObject(value, member.type, dest))
|
|
553
|
+
if (!PushObject(value, member.type, dest)) [[unlikely]]
|
|
556
554
|
return false;
|
|
557
555
|
} break;
|
|
558
556
|
case PrimitiveKind::Array: {
|
|
@@ -739,12 +737,7 @@ bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size siz
|
|
|
739
737
|
case PrimitiveKind::Record:
|
|
740
738
|
case PrimitiveKind::Union: {
|
|
741
739
|
PUSH_ARRAY({
|
|
742
|
-
if (!
|
|
743
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
744
|
-
return false;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
if (!PushObject(value, ref, dest))
|
|
740
|
+
if (!PushObject(value, ref, dest)) [[unlikely]]
|
|
748
741
|
return false;
|
|
749
742
|
});
|
|
750
743
|
} break;
|
|
@@ -1010,8 +1003,6 @@ bool CallData::PushPointerSlow(napi_value value, napi_valuetype kind, const Type
|
|
|
1010
1003
|
return true;
|
|
1011
1004
|
} else if (ref->primitive == PrimitiveKind::Record ||
|
|
1012
1005
|
ref->primitive == PrimitiveKind::Union) [[likely]] {
|
|
1013
|
-
K_ASSERT(IsObject(env, value));
|
|
1014
|
-
|
|
1015
1006
|
ptr = (void *)AllocHeap(ref->size);
|
|
1016
1007
|
|
|
1017
1008
|
if (ref->primitive == PrimitiveKind::Union &&
|
|
@@ -1021,9 +1012,12 @@ bool CallData::PushPointerSlow(napi_value value, napi_valuetype kind, const Type
|
|
|
1021
1012
|
}
|
|
1022
1013
|
|
|
1023
1014
|
if (directions & 1) {
|
|
1024
|
-
if (!PushObject(value, ref, (uint8_t *)ptr))
|
|
1015
|
+
if (!PushObject(value, ref, (uint8_t *)ptr)) [[unlikely]]
|
|
1025
1016
|
return false;
|
|
1026
1017
|
} else {
|
|
1018
|
+
if (kind != napi_object) [[unlikely]]
|
|
1019
|
+
return false;
|
|
1020
|
+
|
|
1027
1021
|
MemSet(ptr, 0, ref->size);
|
|
1028
1022
|
}
|
|
1029
1023
|
|
|
@@ -1247,71 +1241,7 @@ void CallData::DebugForward()
|
|
|
1247
1241
|
|
|
1248
1242
|
#endif
|
|
1249
1243
|
|
|
1250
|
-
static
|
|
1251
|
-
{
|
|
1252
|
-
Napi::Value ret = env.RunScript("typeof Deno != 'undefined'");
|
|
1253
|
-
Napi::Boolean b = ret.ToBoolean();
|
|
1254
|
-
|
|
1255
|
-
return b.Value();
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
static bool DetectBun(Napi::Env env)
|
|
1259
|
-
{
|
|
1260
|
-
Napi::Value ret = env.RunScript("process.isBun");
|
|
1261
|
-
Napi::Boolean b = ret.ToBoolean();
|
|
1262
|
-
|
|
1263
|
-
return b.Value();
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
void InitTranslateZeroCall(Napi::Env env)
|
|
1267
|
-
{
|
|
1268
|
-
if (DetectDeno(env) || DetectBun(env)) {
|
|
1269
|
-
translate_zero_call = TranslateFastCall;
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
Napi::Object self = Napi::Object::New(env);
|
|
1274
|
-
|
|
1275
|
-
napi_value func;
|
|
1276
|
-
napi_value ret;
|
|
1277
|
-
|
|
1278
|
-
auto cb = [](napi_env env, napi_callback_info info) {
|
|
1279
|
-
napi_value self;
|
|
1280
|
-
NAPI_OK(napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
|
|
1281
|
-
|
|
1282
|
-
napi_value *ptr = (napi_value *)info;
|
|
1283
|
-
|
|
1284
|
-
if (ptr[0] != self && ptr[1] != self) {
|
|
1285
|
-
translate_zero_call = TranslateZeroCall;
|
|
1286
|
-
} else {
|
|
1287
|
-
translate_zero_call = TranslateFastCall;
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
return self;
|
|
1291
|
-
};
|
|
1292
|
-
|
|
1293
|
-
NAPI_OK(napi_create_function(env, nullptr, 0, cb, nullptr, &func));
|
|
1294
|
-
NAPI_OK(napi_call_function(env, self, func, 0, nullptr, &ret));
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
bool InitAsyncBroker(Napi::Env env, InstanceData *instance)
|
|
1298
|
-
{
|
|
1299
|
-
if (!instance->broker) {
|
|
1300
|
-
if (napi_create_threadsafe_function(env, nullptr, nullptr,
|
|
1301
|
-
Napi::String::New(env, "Koffi Async Callback Broker"),
|
|
1302
|
-
0, 1, nullptr, nullptr, nullptr,
|
|
1303
|
-
PerformAsyncRelay, &instance->broker) != napi_ok) {
|
|
1304
|
-
LogError("Failed to create async callback broker");
|
|
1305
|
-
return false;
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
NAPI_OK(napi_unref_threadsafe_function(env, instance->broker));
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
return true;
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
|
-
napi_value TranslateZeroCall(napi_env env, napi_callback_info info)
|
|
1244
|
+
static napi_value TranslateZeroCall(napi_env env, napi_callback_info info)
|
|
1315
1245
|
{
|
|
1316
1246
|
struct CallbackBundle {
|
|
1317
1247
|
napi_env env;
|
|
@@ -1386,7 +1316,7 @@ static FORCE_INLINE napi_value TranslateNormalCall(napi_env env, const FunctionI
|
|
|
1386
1316
|
return ret;
|
|
1387
1317
|
}
|
|
1388
1318
|
|
|
1389
|
-
napi_value TranslateNormalCall(napi_env env, napi_callback_info info)
|
|
1319
|
+
static napi_value TranslateNormalCall(napi_env env, napi_callback_info info)
|
|
1390
1320
|
{
|
|
1391
1321
|
static_assert(MaxParameters >= 8);
|
|
1392
1322
|
|
|
@@ -1436,7 +1366,7 @@ static FORCE_INLINE napi_value TranslateNormalCallDebugAsync(napi_env env, const
|
|
|
1436
1366
|
return ret;
|
|
1437
1367
|
}
|
|
1438
1368
|
|
|
1439
|
-
napi_value TranslateNormalCallDebugAsync(napi_env env, napi_callback_info info)
|
|
1369
|
+
static napi_value TranslateNormalCallDebugAsync(napi_env env, napi_callback_info info)
|
|
1440
1370
|
{
|
|
1441
1371
|
static_assert(MaxParameters >= 8);
|
|
1442
1372
|
|
|
@@ -1558,7 +1488,7 @@ static napi_value TranslateVariadicCall(napi_env env, const FunctionInfo *func,
|
|
|
1558
1488
|
return ret;
|
|
1559
1489
|
}
|
|
1560
1490
|
|
|
1561
|
-
napi_value TranslateVariadicCall(napi_env env, napi_callback_info info)
|
|
1491
|
+
static napi_value TranslateVariadicCall(napi_env env, napi_callback_info info)
|
|
1562
1492
|
{
|
|
1563
1493
|
static_assert(MaxParameters >= 8);
|
|
1564
1494
|
|
|
@@ -1651,7 +1581,7 @@ void AsyncCall::OnError(const Napi::Error& err)
|
|
|
1651
1581
|
callback.Call(self, K_LEN(args), args);
|
|
1652
1582
|
}
|
|
1653
1583
|
|
|
1654
|
-
napi_value TranslateAsyncCall(napi_env env, napi_callback_info info)
|
|
1584
|
+
static napi_value TranslateAsyncCall(napi_env env, napi_callback_info info)
|
|
1655
1585
|
{
|
|
1656
1586
|
static_assert(MaxParameters >= 6);
|
|
1657
1587
|
|
|
@@ -1693,6 +1623,215 @@ napi_value TranslateAsyncCall(napi_env env, napi_callback_info info)
|
|
|
1693
1623
|
return Napi::Env(env).Undefined();
|
|
1694
1624
|
}
|
|
1695
1625
|
|
|
1626
|
+
static bool DetectDeno(Napi::Env env)
|
|
1627
|
+
{
|
|
1628
|
+
Napi::Value ret = env.RunScript("typeof Deno != 'undefined'");
|
|
1629
|
+
Napi::Boolean b = ret.ToBoolean();
|
|
1630
|
+
|
|
1631
|
+
return b.Value();
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
static bool DetectBun(Napi::Env env)
|
|
1635
|
+
{
|
|
1636
|
+
Napi::Value ret = env.RunScript("process.isBun");
|
|
1637
|
+
Napi::Boolean b = ret.ToBoolean();
|
|
1638
|
+
|
|
1639
|
+
return b.Value();
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
void InitTranslateZeroCall(Napi::Env env)
|
|
1643
|
+
{
|
|
1644
|
+
if (DetectDeno(env) || DetectBun(env)) {
|
|
1645
|
+
translate_zero_call = TranslateFastCall;
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
Napi::Object self = Napi::Object::New(env);
|
|
1650
|
+
|
|
1651
|
+
napi_value func;
|
|
1652
|
+
napi_value ret;
|
|
1653
|
+
|
|
1654
|
+
auto cb = [](napi_env env, napi_callback_info info) {
|
|
1655
|
+
napi_value self;
|
|
1656
|
+
NAPI_OK(napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
|
|
1657
|
+
|
|
1658
|
+
napi_value *ptr = (napi_value *)info;
|
|
1659
|
+
|
|
1660
|
+
if (ptr[0] != self && ptr[1] != self) {
|
|
1661
|
+
translate_zero_call = TranslateZeroCall;
|
|
1662
|
+
} else {
|
|
1663
|
+
translate_zero_call = TranslateFastCall;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
return self;
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1669
|
+
NAPI_OK(napi_create_function(env, nullptr, 0, cb, nullptr, &func));
|
|
1670
|
+
NAPI_OK(napi_call_function(env, self, func, 0, nullptr, &ret));
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
napi_value CallPointer(Napi::Env env, const FunctionInfo *proto, void *native, napi_value *args, Size count)
|
|
1674
|
+
{
|
|
1675
|
+
if (proto->variadic) {
|
|
1676
|
+
return TranslateVariadicCall(env, proto, native, args, count);
|
|
1677
|
+
} else {
|
|
1678
|
+
return TranslateNormalCall(env, proto, native, args, count);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
static void PerformAsyncRelay(napi_env, napi_value, void *, void *udata)
|
|
1683
|
+
{
|
|
1684
|
+
RelayContext *ctx = (RelayContext *)udata;
|
|
1685
|
+
CallData *call = ctx->call;
|
|
1686
|
+
|
|
1687
|
+
call->Relay(ctx->idx, ctx->sp);
|
|
1688
|
+
call->Finalize();
|
|
1689
|
+
|
|
1690
|
+
// We're done!
|
|
1691
|
+
std::lock_guard<std::mutex> lock(ctx->mutex);
|
|
1692
|
+
ctx->done = true;
|
|
1693
|
+
ctx->cv.notify_one();
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
bool InitAsyncBroker(Napi::Env env, InstanceData *instance)
|
|
1697
|
+
{
|
|
1698
|
+
if (!instance->broker) {
|
|
1699
|
+
if (napi_create_threadsafe_function(env, nullptr, nullptr,
|
|
1700
|
+
NewString(env, "Koffi Async Callback Broker"),
|
|
1701
|
+
0, 1, nullptr, nullptr, nullptr,
|
|
1702
|
+
PerformAsyncRelay, &instance->broker) != napi_ok) {
|
|
1703
|
+
LogError("Failed to create async callback broker");
|
|
1704
|
+
return false;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
NAPI_OK(napi_unref_threadsafe_function(env, instance->broker));
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
return true;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
void *GetTrampoline(int idx)
|
|
1714
|
+
{
|
|
1715
|
+
return (void *)(TrampolineStart + TrampolineSize * idx);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
static bool CanTypeAcceptCallbacks(const TypeInfo *type)
|
|
1719
|
+
{
|
|
1720
|
+
if (type->primitive == PrimitiveKind::Pointer)
|
|
1721
|
+
return true;
|
|
1722
|
+
if (type->primitive == PrimitiveKind::Callback)
|
|
1723
|
+
return true;
|
|
1724
|
+
|
|
1725
|
+
if (type->primitive == PrimitiveKind::Record ||
|
|
1726
|
+
type->primitive == PrimitiveKind::Union) {
|
|
1727
|
+
for (const RecordMember &member: type->members) {
|
|
1728
|
+
if (CanTypeAcceptCallbacks(member.type))
|
|
1729
|
+
return false;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
return true;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
static bool CanUseFastCall(const FunctionInfo *func)
|
|
1737
|
+
{
|
|
1738
|
+
if (func->parameters.len > 6)
|
|
1739
|
+
return false;
|
|
1740
|
+
|
|
1741
|
+
// Fast calls basically skip CallData::Finalize(), which handles output arguments
|
|
1742
|
+
// and temporary callback trampolines. If the function does not use any
|
|
1743
|
+
// output argument and cannot accept callbacks (so no pointer or callback arguments),
|
|
1744
|
+
// we can skip finalization!
|
|
1745
|
+
|
|
1746
|
+
for (const ParameterInfo ¶m: func->parameters) {
|
|
1747
|
+
if (param.directions & 2)
|
|
1748
|
+
return false;
|
|
1749
|
+
if (CanTypeAcceptCallbacks(param.type))
|
|
1750
|
+
return false;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
return true;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
napi_value DescribeFunction(InstanceData *instance, const FunctionInfo *func)
|
|
1757
|
+
{
|
|
1758
|
+
static const char *const DirectionNames[] = {
|
|
1759
|
+
nullptr,
|
|
1760
|
+
"Input",
|
|
1761
|
+
"Output",
|
|
1762
|
+
"Input/Output"
|
|
1763
|
+
};
|
|
1764
|
+
|
|
1765
|
+
Napi::Env env = instance->env;
|
|
1766
|
+
|
|
1767
|
+
Napi::Object meta = Napi::Object::New(env);
|
|
1768
|
+
Napi::Array arguments = Napi::Array::New(env, func->parameters.len);
|
|
1769
|
+
|
|
1770
|
+
meta.Set("name", NewString(env, func->name));
|
|
1771
|
+
meta.Set("arguments", arguments);
|
|
1772
|
+
meta.Set("result", WrapType(instance, func->ret.type));
|
|
1773
|
+
|
|
1774
|
+
for (Size i = 0; i < func->parameters.len; i++) {
|
|
1775
|
+
const ParameterInfo ¶m = func->parameters[i];
|
|
1776
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
1777
|
+
|
|
1778
|
+
obj.Set("type", WrapType(instance, param.type));
|
|
1779
|
+
obj.Set("direction", NewString(env, DirectionNames[param.directions]));
|
|
1780
|
+
|
|
1781
|
+
arguments.Set((uint32_t)i, obj);
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
meta.Freeze();
|
|
1785
|
+
|
|
1786
|
+
return meta;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
static bool IsDebugAsyncEnabled()
|
|
1790
|
+
{
|
|
1791
|
+
static bool debug = GetDebugFlag("DEBUG_ASYNC");
|
|
1792
|
+
return debug;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
napi_value WrapFunction(InstanceData *instance, const FunctionInfo *func)
|
|
1796
|
+
{
|
|
1797
|
+
Napi::Env env = instance->env;
|
|
1798
|
+
|
|
1799
|
+
Napi::Function wrapper;
|
|
1800
|
+
{
|
|
1801
|
+
napi_value value;
|
|
1802
|
+
|
|
1803
|
+
if (func->variadic) {
|
|
1804
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateVariadicCall, (void *)func->Ref(), &value));
|
|
1805
|
+
} else if (IsDebugAsyncEnabled()) {
|
|
1806
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCallDebugAsync, (void *)func->Ref(), &value));
|
|
1807
|
+
} else if (!func->parameters.len) {
|
|
1808
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, translate_zero_call, (void *)func->Ref(), &value));
|
|
1809
|
+
} else if (CanUseFastCall(func)) {
|
|
1810
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateFastCall, (void *)func->Ref(), &value));
|
|
1811
|
+
} else {
|
|
1812
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateNormalCall, (void *)func->Ref(), &value));
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
wrapper = Napi::Function(env, value);
|
|
1816
|
+
wrapper.AddFinalizer([](Napi::BasicEnv, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
if (!func->variadic) {
|
|
1820
|
+
napi_value value;
|
|
1821
|
+
NAPI_OK(napi_create_function(env, func->name, NAPI_AUTO_LENGTH, TranslateAsyncCall, (void *)func->Ref(), &value));
|
|
1822
|
+
|
|
1823
|
+
Napi::Function async = Napi::Function(env, value);
|
|
1824
|
+
async.AddFinalizer([](Napi::BasicEnv, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
|
|
1825
|
+
|
|
1826
|
+
wrapper.Set("async", async);
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
napi_value meta = DescribeFunction(instance, func);
|
|
1830
|
+
wrapper.Set("info", meta);
|
|
1831
|
+
|
|
1832
|
+
return wrapper;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1696
1835
|
static FORCE_INLINE bool CheckTrampolineStatus(TrampolineInfo *trampoline)
|
|
1697
1836
|
{
|
|
1698
1837
|
if (trampoline->state == 1) [[likely]]
|
|
@@ -1799,34 +1938,6 @@ extern "C" void RelayDirect(CallData *call, Size idx, uint8_t *sp)
|
|
|
1799
1938
|
}
|
|
1800
1939
|
}
|
|
1801
1940
|
|
|
1802
|
-
napi_value CallPointer(napi_env env, const FunctionInfo *proto, void *native, napi_value *args, Size count)
|
|
1803
|
-
{
|
|
1804
|
-
if (proto->variadic) {
|
|
1805
|
-
return TranslateVariadicCall(env, proto, native, args, count);
|
|
1806
|
-
} else {
|
|
1807
|
-
return TranslateNormalCall(env, proto, native, args, count);
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
|
|
1811
|
-
void PerformAsyncRelay(napi_env, napi_value, void *, void *udata)
|
|
1812
|
-
{
|
|
1813
|
-
RelayContext *ctx = (RelayContext *)udata;
|
|
1814
|
-
CallData *call = ctx->call;
|
|
1815
|
-
|
|
1816
|
-
call->Relay(ctx->idx, ctx->sp);
|
|
1817
|
-
call->Finalize();
|
|
1818
|
-
|
|
1819
|
-
// We're done!
|
|
1820
|
-
std::lock_guard<std::mutex> lock(ctx->mutex);
|
|
1821
|
-
ctx->done = true;
|
|
1822
|
-
ctx->cv.notify_one();
|
|
1823
|
-
}
|
|
1824
|
-
|
|
1825
|
-
void *GetTrampoline(int idx)
|
|
1826
|
-
{
|
|
1827
|
-
return (void *)(TrampolineStart + TrampolineSize * idx);
|
|
1828
|
-
}
|
|
1829
|
-
|
|
1830
1941
|
bool Encode(InstanceData *instance, uint8_t *origin, napi_value value, const TypeInfo *type)
|
|
1831
1942
|
{
|
|
1832
1943
|
Napi::Env env = instance->env;
|
|
@@ -1909,12 +2020,7 @@ bool Encode(InstanceData *instance, uint8_t *origin, napi_value value, const Typ
|
|
|
1909
2020
|
} break;
|
|
1910
2021
|
case PrimitiveKind::Record:
|
|
1911
2022
|
case PrimitiveKind::Union: {
|
|
1912
|
-
if (!
|
|
1913
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
|
|
1914
|
-
return false;
|
|
1915
|
-
}
|
|
1916
|
-
|
|
1917
|
-
if (!call.PushObject(value, type, origin))
|
|
2023
|
+
if (!call.PushObject(value, type, origin)) [[unlikely]]
|
|
1918
2024
|
return false;
|
|
1919
2025
|
} break;
|
|
1920
2026
|
case PrimitiveKind::Array: {
|
package/src/koffi/src/call.hh
CHANGED
|
@@ -164,19 +164,14 @@ inline T *CallData::AllocHeap(Size size)
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
void InitTranslateZeroCall(Napi::Env env);
|
|
167
|
-
bool InitAsyncBroker(Napi::Env env, InstanceData *instance);
|
|
168
|
-
|
|
169
|
-
napi_value TranslateZeroCall(napi_env env, napi_callback_info info);
|
|
170
|
-
napi_value TranslateFastCall(napi_env env, napi_callback_info info);
|
|
171
|
-
napi_value TranslateNormalCall(napi_env env, napi_callback_info info);
|
|
172
|
-
napi_value TranslateNormalCallDebugAsync(napi_env env, napi_callback_info info);
|
|
173
|
-
napi_value TranslateVariadicCall(napi_env env, napi_callback_info info);
|
|
174
|
-
napi_value TranslateAsyncCall(napi_env env, napi_callback_info info);
|
|
175
167
|
|
|
176
|
-
napi_value
|
|
168
|
+
napi_value DescribeFunction(InstanceData *instance, const FunctionInfo *func);
|
|
169
|
+
napi_value WrapFunction(InstanceData *instance, const FunctionInfo *func);
|
|
170
|
+
bool DetectCallConvention(Span<const char> name, CallConvention *out_convention);
|
|
177
171
|
|
|
178
|
-
|
|
172
|
+
napi_value CallPointer(Napi::Env env, const FunctionInfo *proto, void *native, napi_value *args, Size count);
|
|
179
173
|
|
|
174
|
+
bool InitAsyncBroker(Napi::Env env, InstanceData *instance);
|
|
180
175
|
void *GetTrampoline(int idx);
|
|
181
176
|
|
|
182
177
|
bool Encode(InstanceData *instance, uint8_t *ptr, napi_value value, const TypeInfo *type);
|