koffi 2.3.21-beta.2 → 2.3.21-beta.3

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.
Files changed (43) hide show
  1. package/build/2.3.21-beta.3/koffi_darwin_arm64/koffi.node +0 -0
  2. package/build/2.3.21-beta.3/koffi_darwin_x64/koffi.node +0 -0
  3. package/build/2.3.21-beta.3/koffi_freebsd_arm64/koffi.node +0 -0
  4. package/build/2.3.21-beta.3/koffi_freebsd_ia32/koffi.node +0 -0
  5. package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_freebsd_x64/koffi.node +0 -0
  6. package/build/2.3.21-beta.3/koffi_linux_arm32hf/koffi.node +0 -0
  7. package/build/2.3.21-beta.3/koffi_linux_arm64/koffi.node +0 -0
  8. package/build/2.3.21-beta.3/koffi_linux_ia32/koffi.node +0 -0
  9. package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_linux_riscv64hf64/koffi.node +0 -0
  10. package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_linux_x64/koffi.node +0 -0
  11. package/build/2.3.21-beta.3/koffi_openbsd_ia32/koffi.node +0 -0
  12. package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_openbsd_x64/koffi.node +0 -0
  13. package/build/2.3.21-beta.3/koffi_win32_arm64/koffi.node +0 -0
  14. package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_win32_ia32/koffi.node +0 -0
  15. package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_win32_x64/koffi.node +0 -0
  16. package/package.json +1 -1
  17. package/src/index.d.ts +6 -2
  18. package/src/index.js +2 -1
  19. package/src/koffi/src/abi_arm32.cc +3 -3
  20. package/src/koffi/src/abi_arm64.cc +3 -3
  21. package/src/koffi/src/abi_riscv64.cc +3 -3
  22. package/src/koffi/src/abi_x64_sysv.cc +3 -3
  23. package/src/koffi/src/abi_x64_win.cc +3 -3
  24. package/src/koffi/src/abi_x86.cc +3 -3
  25. package/src/koffi/src/call.hh +1 -1
  26. package/src/koffi/src/ffi.cc +150 -46
  27. package/src/koffi/src/ffi.hh +2 -1
  28. package/src/koffi/src/parser.cc +2 -0
  29. package/build/2.3.21-beta.2/koffi_darwin_arm64/koffi.node +0 -0
  30. package/build/2.3.21-beta.2/koffi_darwin_x64/koffi.node +0 -0
  31. package/build/2.3.21-beta.2/koffi_freebsd_arm64/koffi.node +0 -0
  32. package/build/2.3.21-beta.2/koffi_freebsd_ia32/koffi.node +0 -0
  33. package/build/2.3.21-beta.2/koffi_linux_arm32hf/koffi.node +0 -0
  34. package/build/2.3.21-beta.2/koffi_linux_arm64/koffi.node +0 -0
  35. package/build/2.3.21-beta.2/koffi_linux_ia32/koffi.node +0 -0
  36. package/build/2.3.21-beta.2/koffi_openbsd_ia32/koffi.node +0 -0
  37. package/build/2.3.21-beta.2/koffi_win32_arm64/koffi.node +0 -0
  38. /package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_win32_arm64/koffi.exp +0 -0
  39. /package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_win32_arm64/koffi.lib +0 -0
  40. /package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_win32_ia32/koffi.exp +0 -0
  41. /package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_win32_ia32/koffi.lib +0 -0
  42. /package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_win32_x64/koffi.exp +0 -0
  43. /package/build/{2.3.21-beta.2 → 2.3.21-beta.3}/koffi_win32_x64/koffi.lib +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.3.21-beta.2",
3
+ "version": "2.3.21-beta.3",
4
4
  "stable": "2.3.20",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
package/src/index.d.ts CHANGED
@@ -93,6 +93,8 @@ declare module 'koffi' {
93
93
 
94
94
  export function opaque(name: string): IKoffiCType;
95
95
  export function opaque(): IKoffiCType;
96
+ /** @deprecated */ export function handle(name: string): IKoffiCType;
97
+ /** @deprecated */ export function handle(): IKoffiCType;
96
98
 
97
99
  export function pointer(value: TypeSpec): IKoffiCType;
98
100
  export function pointer(value: TypeSpec, asteriskCount: number): IKoffiCType;
@@ -105,8 +107,10 @@ declare module 'koffi' {
105
107
  export function disposable(name: string, type: TypeSpec): IKoffiCType;
106
108
  export function disposable(name: string, type: TypeSpec, freeFunction: Function): IKoffiCType;
107
109
 
108
- export function callback(definition: string): IKoffiCType;
109
- export function callback(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
110
+ export function proto(definition: string): IKoffiCType;
111
+ export function proto(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
112
+ /** @deprecated */ export function callback(definition: string): IKoffiCType;
113
+ /** @deprecated */ export function callback(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
110
114
 
111
115
  export function register(callback: Function, type: TypeSpec): IKoffiRegisteredCallback;
112
116
  export function register(thisValue: any, callback: Function, type: TypeSpec): IKoffiRegisteredCallback;
package/src/index.js CHANGED
@@ -57,5 +57,6 @@ module.exports = {
57
57
  ...native,
58
58
 
59
59
  // Deprecated functions
60
- handle: util.deprecate(native.opaque, 'The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead', 'KOFFI001')
60
+ handle: util.deprecate(native.opaque, 'The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead', 'KOFFI001'),
61
+ callback: util.deprecate(native.proto, 'The koffi.callback() function was deprecated in Koffi 2.4, use koffi.proto() instead', 'KOFFI002')
61
62
  };
@@ -456,12 +456,12 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
456
456
  return true;
457
457
  }
458
458
 
459
- void CallData::Execute(const FunctionInfo *func)
459
+ void CallData::Execute(const FunctionInfo *func, void *native)
460
460
  {
461
461
  #define PERFORM_CALL(Suffix) \
462
462
  ([&]() { \
463
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
464
- : ForwardCall ## Suffix(func->func, new_sp, &old_sp)); \
463
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(native, new_sp, &old_sp) \
464
+ : ForwardCall ## Suffix(native, new_sp, &old_sp)); \
465
465
  return ret; \
466
466
  })()
467
467
 
@@ -561,7 +561,7 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
561
561
  return true;
562
562
  }
563
563
 
564
- void CallData::Execute(const FunctionInfo *func)
564
+ void CallData::Execute(const FunctionInfo *func, void *native)
565
565
  {
566
566
  #ifdef _WIN32
567
567
  TEB *teb = GetTEB();
@@ -589,8 +589,8 @@ void CallData::Execute(const FunctionInfo *func)
589
589
 
590
590
  #define PERFORM_CALL(Suffix) \
591
591
  ([&]() { \
592
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
593
- : ForwardCall ## Suffix(func->func, new_sp, &old_sp)); \
592
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(native, new_sp, &old_sp) \
593
+ : ForwardCall ## Suffix(native, new_sp, &old_sp)); \
594
594
  return ret; \
595
595
  })()
596
596
 
@@ -386,12 +386,12 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
386
386
  return true;
387
387
  }
388
388
 
389
- void CallData::Execute(const FunctionInfo *func)
389
+ void CallData::Execute(const FunctionInfo *func, void *native)
390
390
  {
391
391
  #define PERFORM_CALL(Suffix) \
392
392
  ([&]() { \
393
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
394
- : ForwardCall ## Suffix(func->func, new_sp, &old_sp)); \
393
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(native, new_sp, &old_sp) \
394
+ : ForwardCall ## Suffix(native, new_sp, &old_sp)); \
395
395
  return ret; \
396
396
  })()
397
397
 
@@ -425,12 +425,12 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
425
425
  return true;
426
426
  }
427
427
 
428
- void CallData::Execute(const FunctionInfo *func)
428
+ void CallData::Execute(const FunctionInfo *func, void *native)
429
429
  {
430
430
  #define PERFORM_CALL(Suffix) \
431
431
  ([&]() { \
432
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
433
- : ForwardCall ## Suffix(func->func, new_sp, &old_sp)); \
432
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(native, new_sp, &old_sp) \
433
+ : ForwardCall ## Suffix(native, new_sp, &old_sp)); \
434
434
  return ret; \
435
435
  })()
436
436
 
@@ -224,7 +224,7 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
224
224
  return true;
225
225
  }
226
226
 
227
- void CallData::Execute(const FunctionInfo *func)
227
+ void CallData::Execute(const FunctionInfo *func, void *native)
228
228
  {
229
229
  TEB *teb = GetTEB();
230
230
 
@@ -250,8 +250,8 @@ void CallData::Execute(const FunctionInfo *func)
250
250
 
251
251
  #define PERFORM_CALL(Suffix) \
252
252
  ([&]() { \
253
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
254
- : ForwardCall ## Suffix(func->func, new_sp, &old_sp)); \
253
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(native, new_sp, &old_sp) \
254
+ : ForwardCall ## Suffix(native, new_sp, &old_sp)); \
255
255
  return ret; \
256
256
  })()
257
257
 
@@ -308,7 +308,7 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
308
308
  return true;
309
309
  }
310
310
 
311
- void CallData::Execute(const FunctionInfo *func)
311
+ void CallData::Execute(const FunctionInfo *func, void *native)
312
312
  {
313
313
  #ifdef _WIN32
314
314
  TEB *teb = GetTEB();
@@ -336,8 +336,8 @@ void CallData::Execute(const FunctionInfo *func)
336
336
 
337
337
  #define PERFORM_CALL(Suffix) \
338
338
  ([&]() { \
339
- auto ret = (func->fast ? ForwardCallR ## Suffix(func->func, new_sp, &old_sp) \
340
- : ForwardCall ## Suffix(func->func, new_sp, &old_sp)); \
339
+ auto ret = (func->fast ? ForwardCallR ## Suffix(native, new_sp, &old_sp) \
340
+ : ForwardCall ## Suffix(native, new_sp, &old_sp)); \
341
341
  return ret; \
342
342
  })()
343
343
 
@@ -102,7 +102,7 @@ public:
102
102
  #endif
103
103
 
104
104
  INLINE_IF_UNITY bool Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info);
105
- INLINE_IF_UNITY void Execute(const FunctionInfo *func);
105
+ INLINE_IF_UNITY void Execute(const FunctionInfo *func, void *native);
106
106
  INLINE_IF_UNITY Napi::Value Complete(const FunctionInfo *func);
107
107
 
108
108
  #undef INLINE_IF_UNITY
@@ -275,7 +275,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
275
275
  value = array[1u];
276
276
  align = (int16_t)align64;
277
277
  }
278
-
278
+
279
279
  member.type = ResolveType(value);
280
280
  if (!member.type)
281
281
  return env.Null();
@@ -403,7 +403,7 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
403
403
  value = array[1u];
404
404
  align = (int16_t)align64;
405
405
  }
406
-
406
+
407
407
  member.type = ResolveType(value);
408
408
  if (!member.type)
409
409
  return env.Null();
@@ -920,10 +920,12 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
920
920
  func->parameters.Append(param);
921
921
  }
922
922
 
923
+ func->required_parameters = (int8_t)func->parameters.len;
924
+
923
925
  return true;
924
926
  }
925
927
 
926
- static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
928
+ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
927
929
  {
928
930
  Napi::Env env = info.Env();
929
931
  InstanceData *instance = env.GetInstanceData<InstanceData>();
@@ -956,6 +958,12 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
956
958
  if (!AnalyseFunction(env, instance, func))
957
959
  return env.Null();
958
960
 
961
+ // Adjust parameter offsets for koffi.call()
962
+ for (ParameterInfo &param: func->parameters) {
963
+ param.offset += 2;
964
+ }
965
+ func->required_parameters += 2;
966
+
959
967
  // We cannot fail after this check
960
968
  if (instance->types_map.Find(func->name)) {
961
969
  ThrowError<Napi::Error>(env, "Duplicate type name '%1'", func->name);
@@ -1239,13 +1247,13 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
1239
1247
  return mem;
1240
1248
  }
1241
1249
 
1242
- static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1250
+ static Napi::Value TranslateNormalCall(const FunctionInfo *func, void *native,
1251
+ const Napi::CallbackInfo &info)
1243
1252
  {
1244
1253
  Napi::Env env = info.Env();
1245
1254
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1246
- FunctionInfo *func = (FunctionInfo *)info.Data();
1247
1255
 
1248
- if (RG_UNLIKELY(info.Length() < (uint32_t)func->parameters.len)) {
1256
+ if (RG_UNLIKELY(info.Length() < (uint32_t)func->required_parameters)) {
1249
1257
  ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
1250
1258
  return env.Null();
1251
1259
  }
@@ -1265,37 +1273,44 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1265
1273
  RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1266
1274
  exec_call = &call;
1267
1275
 
1268
- call.Execute(func);
1276
+ call.Execute(func, native);
1269
1277
  }
1270
1278
 
1271
1279
  return call.Complete(func);
1272
1280
  }
1273
1281
 
1274
- static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1282
+ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1283
+ {
1284
+ FunctionInfo *func = (FunctionInfo *)info.Data();
1285
+ return TranslateNormalCall(func, func->native, info);
1286
+ }
1287
+
1288
+ static Napi::Value TranslateVariadicCall(const FunctionInfo *func, void *native,
1289
+ const Napi::CallbackInfo &info)
1275
1290
  {
1276
1291
  Napi::Env env = info.Env();
1277
1292
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1278
1293
 
1279
- FunctionInfo func;
1280
- memcpy((void *)&func, info.Data(), RG_SIZE(FunctionInfo));
1281
- func.lib = nullptr;
1294
+ FunctionInfo copy;
1295
+ memcpy((void *)&copy, func, RG_SIZE(*func));
1296
+ copy.lib = nullptr;
1282
1297
 
1283
1298
  // This makes variadic calls non-reentrant
1284
- RG_DEFER_C(len = func.parameters.len) {
1285
- func.parameters.RemoveFrom(len);
1286
- func.parameters.Leak();
1299
+ RG_DEFER_C(len = copy.parameters.len) {
1300
+ copy.parameters.RemoveFrom(len);
1301
+ copy.parameters.Leak();
1287
1302
  };
1288
1303
 
1289
- if (RG_UNLIKELY(info.Length() < (uint32_t)func.parameters.len)) {
1290
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments or more, got %2", func.parameters.len, info.Length());
1304
+ if (RG_UNLIKELY(info.Length() < (uint32_t)copy.required_parameters)) {
1305
+ ThrowError<Napi::TypeError>(env, "Expected %1 arguments or more, got %2", copy.parameters.len, info.Length());
1291
1306
  return env.Null();
1292
1307
  }
1293
- if (RG_UNLIKELY((info.Length() - func.parameters.len) % 2)) {
1308
+ if (RG_UNLIKELY((info.Length() - copy.required_parameters) % 2)) {
1294
1309
  ThrowError<Napi::Error>(env, "Missing value argument for variadic call");
1295
1310
  return env.Null();
1296
1311
  }
1297
1312
 
1298
- for (Size i = func.parameters.len; i < (Size)info.Length(); i += 2) {
1313
+ for (Size i = copy.required_parameters; i < (Size)info.Length(); i += 2) {
1299
1314
  ParameterInfo param = {};
1300
1315
 
1301
1316
  param.type = ResolveType(info[(uint32_t)i], &param.directions);
@@ -1306,11 +1321,11 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1306
1321
  ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
1307
1322
  return env.Null();
1308
1323
  }
1309
- if (RG_UNLIKELY(func.parameters.len >= MaxParameters)) {
1324
+ if (RG_UNLIKELY(copy.parameters.len >= MaxParameters)) {
1310
1325
  ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
1311
1326
  return env.Null();
1312
1327
  }
1313
- if (RG_UNLIKELY((param.directions & 2) && ++func.out_parameters >= MaxOutParameters)) {
1328
+ if (RG_UNLIKELY((param.directions & 2) && ++copy.out_parameters >= MaxOutParameters)) {
1314
1329
  ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 output parameters", MaxOutParameters);
1315
1330
  return env.Null();
1316
1331
  }
@@ -1318,20 +1333,20 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1318
1333
  param.variadic = true;
1319
1334
  param.offset = (int8_t)(i + 1);
1320
1335
 
1321
- func.parameters.Append(param);
1336
+ copy.parameters.Append(param);
1322
1337
  }
1323
1338
 
1324
- if (RG_UNLIKELY(!AnalyseFunction(env, instance, &func)))
1339
+ if (RG_UNLIKELY(!AnalyseFunction(env, instance, &copy)))
1325
1340
  return env.Null();
1326
1341
 
1327
1342
  InstanceMemory *mem = instance->memories[0];
1328
1343
  CallData call(env, instance, mem);
1329
1344
 
1330
- if (!RG_UNLIKELY(call.Prepare(&func, info)))
1345
+ if (!RG_UNLIKELY(call.Prepare(&copy, info)))
1331
1346
  return env.Null();
1332
1347
 
1333
1348
  if (instance->debug) {
1334
- call.DumpForward(&func);
1349
+ call.DumpForward(&copy);
1335
1350
  }
1336
1351
 
1337
1352
  // Execute call
@@ -1339,23 +1354,31 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1339
1354
  RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1340
1355
  exec_call = &call;
1341
1356
 
1342
- call.Execute(&func);
1357
+ call.Execute(&copy, native);
1343
1358
  }
1344
1359
 
1345
- return call.Complete(&func);
1360
+ return call.Complete(&copy);
1361
+ }
1362
+
1363
+ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1364
+ {
1365
+ FunctionInfo *func = (FunctionInfo *)info.Data();
1366
+ return TranslateVariadicCall(func, func->native, info);
1346
1367
  }
1347
1368
 
1348
1369
  class AsyncCall: public Napi::AsyncWorker {
1349
1370
  Napi::Env env;
1371
+
1350
1372
  const FunctionInfo *func;
1373
+ void *native;
1351
1374
 
1352
1375
  CallData call;
1353
1376
  bool prepared = false;
1354
1377
 
1355
1378
  public:
1356
1379
  AsyncCall(Napi::Env env, InstanceData *instance, const FunctionInfo *func,
1357
- InstanceMemory *mem, Napi::Function &callback)
1358
- : Napi::AsyncWorker(callback), env(env), func(func->Ref()),
1380
+ void *native, InstanceMemory *mem, Napi::Function &callback)
1381
+ : Napi::AsyncWorker(callback), env(env), func(func->Ref()), native(native),
1359
1382
  call(env, instance, mem) {}
1360
1383
  ~AsyncCall() { func->Unref(); }
1361
1384
 
@@ -1381,7 +1404,7 @@ void AsyncCall::Execute()
1381
1404
  RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1382
1405
  exec_call = &call;
1383
1406
 
1384
- call.Execute(func);
1407
+ call.Execute(func, native);
1385
1408
  }
1386
1409
  }
1387
1410
 
@@ -1400,18 +1423,20 @@ void AsyncCall::OnOK()
1400
1423
  callback.Call(self, RG_LEN(args), args);
1401
1424
  }
1402
1425
 
1403
- static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1426
+ static Napi::Value TranslateAsyncCall(const FunctionInfo *func, void *native,
1427
+ const Napi::CallbackInfo &info)
1404
1428
  {
1429
+ RG_ASSERT(!func->variadic);
1430
+
1405
1431
  Napi::Env env = info.Env();
1406
1432
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1407
- FunctionInfo *func = (FunctionInfo *)info.Data();
1408
1433
 
1409
- if (info.Length() <= (uint32_t)func->parameters.len) {
1434
+ if (info.Length() <= (uint32_t)func->required_parameters) {
1410
1435
  ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len + 1, info.Length());
1411
1436
  return env.Null();
1412
1437
  }
1413
1438
 
1414
- Napi::Function callback = info[(uint32_t)func->parameters.len].As<Napi::Function>();
1439
+ Napi::Function callback = info[(uint32_t)func->required_parameters].As<Napi::Function>();
1415
1440
 
1416
1441
  if (!callback.IsFunction()) {
1417
1442
  ThrowError<Napi::TypeError>(env, "Expected callback function as last argument, got %1", GetValueType(instance, callback));
@@ -1423,7 +1448,7 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1423
1448
  ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
1424
1449
  return env.Null();
1425
1450
  }
1426
- AsyncCall *async = new AsyncCall(env, instance, func, mem, callback);
1451
+ AsyncCall *async = new AsyncCall(env, instance, func, native, mem, callback);
1427
1452
 
1428
1453
  if (async->Prepare(info) && instance->debug) {
1429
1454
  async->DumpForward();
@@ -1433,6 +1458,12 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1433
1458
  return env.Undefined();
1434
1459
  }
1435
1460
 
1461
+ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1462
+ {
1463
+ FunctionInfo *func = (FunctionInfo *)info.Data();
1464
+ return TranslateAsyncCall(func, func->native, info);
1465
+ }
1466
+
1436
1467
  static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConvention convention)
1437
1468
  {
1438
1469
  Napi::Env env = info.Env();
@@ -1478,36 +1509,44 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
1478
1509
  #ifdef _WIN32
1479
1510
  if (info[0].IsString()) {
1480
1511
  if (func->decorated_name) {
1481
- func->func = (void *)GetProcAddress((HMODULE)lib->module, func->decorated_name);
1512
+ func->native = (void *)GetProcAddress((HMODULE)lib->module, func->decorated_name);
1482
1513
  }
1483
- if (!func->func) {
1484
- func->func = (void *)GetProcAddress((HMODULE)lib->module, func->name);
1514
+ if (!func->native) {
1515
+ func->native = (void *)GetProcAddress((HMODULE)lib->module, func->name);
1485
1516
  }
1486
1517
  } else {
1487
1518
  uint16_t ordinal = (uint16_t)info[0].As<Napi::Number>().Uint32Value();
1488
1519
 
1489
1520
  func->decorated_name = nullptr;
1490
- func->func = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
1521
+ func->native = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
1491
1522
  }
1492
1523
  #else
1493
1524
  if (func->decorated_name) {
1494
- func->func = dlsym(lib->module, func->decorated_name);
1525
+ func->native = dlsym(lib->module, func->decorated_name);
1495
1526
  }
1496
- if (!func->func) {
1497
- func->func = dlsym(lib->module, func->name);
1527
+ if (!func->native) {
1528
+ func->native = dlsym(lib->module, func->name);
1498
1529
  }
1499
1530
  #endif
1500
- if (!func->func) {
1531
+ if (!func->native) {
1501
1532
  ThrowError<Napi::Error>(env, "Cannot find function '%1' in shared library", func->name);
1502
1533
  return env.Null();
1503
1534
  }
1504
1535
 
1505
- Napi::Function::Callback call = func->variadic ? TranslateVariadicCall : TranslateNormalCall;
1506
- Napi::Function wrapper = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1536
+ Napi::Function wrapper;
1537
+ if (func->variadic) {
1538
+ Napi::Function::Callback call = TranslateVariadicCall;
1539
+ wrapper = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1540
+ } else {
1541
+ Napi::Function::Callback call = TranslateNormalCall;
1542
+ wrapper = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1543
+ }
1507
1544
  wrapper.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, func);
1508
1545
 
1509
1546
  if (!func->variadic) {
1510
- Napi::Function async = Napi::Function::New(env, TranslateAsyncCall, func->name, (void *)func->Ref());
1547
+ Napi::Function::Callback call = TranslateAsyncCall;
1548
+ Napi::Function async = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1549
+
1511
1550
  async.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, func);
1512
1551
  wrapper.Set("async", async);
1513
1552
  }
@@ -2064,6 +2103,69 @@ static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
2064
2103
  return bigint;
2065
2104
  }
2066
2105
 
2106
+ static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
2107
+ {
2108
+ Napi::Env env = info.Env();
2109
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
2110
+
2111
+ if (RG_UNLIKELY(info.Length() < 2)) {
2112
+ ThrowError<Napi::TypeError>(env, "Expected 2 or more arguments, got %1", info.Length());
2113
+ return env.Null();
2114
+ }
2115
+
2116
+ void *ptr = nullptr;
2117
+ if (RG_UNLIKELY(!GetExternalPointer(env, info[0], &ptr)))
2118
+ return env.Null();
2119
+
2120
+ const TypeInfo *type = ResolveType(info[1]);
2121
+ if (RG_UNLIKELY(!type))
2122
+ return env.Null();
2123
+ if (RG_UNLIKELY(type->primitive != PrimitiveKind::Callback)) {
2124
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for type, expected function pointer type", GetValueType(instance, info[1]));
2125
+ return env.Null();
2126
+ }
2127
+
2128
+ const FunctionInfo *proto = type->ref.proto;
2129
+
2130
+ if (proto->variadic) {
2131
+ return TranslateVariadicCall(proto, ptr, info);
2132
+ } else {
2133
+ return TranslateNormalCall(proto, ptr, info);
2134
+ }
2135
+ }
2136
+
2137
+ static Napi::Value CallPointerAsync(const Napi::CallbackInfo &info)
2138
+ {
2139
+ Napi::Env env = info.Env();
2140
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
2141
+
2142
+ if (RG_UNLIKELY(info.Length() < 2)) {
2143
+ ThrowError<Napi::TypeError>(env, "Expected 2 or more arguments, got %1", info.Length());
2144
+ return env.Null();
2145
+ }
2146
+
2147
+ void *ptr = nullptr;
2148
+ if (RG_UNLIKELY(!GetExternalPointer(env, info[0], &ptr)))
2149
+ return env.Null();
2150
+
2151
+ const TypeInfo *type = ResolveType(info[1]);
2152
+ if (RG_UNLIKELY(!type))
2153
+ return env.Null();
2154
+ if (RG_UNLIKELY(type->primitive != PrimitiveKind::Callback)) {
2155
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for type, expected function pointer type", GetValueType(instance, info[1]));
2156
+ return env.Null();
2157
+ }
2158
+
2159
+ const FunctionInfo *proto = type->ref.proto;
2160
+
2161
+ if (RG_UNLIKELY(proto->variadic)) {
2162
+ ThrowError<Napi::TypeError>(env, "Cannot call variadic function asynchronously");
2163
+ return env.Null();
2164
+ }
2165
+
2166
+ return TranslateAsyncCall(proto, ptr, info);
2167
+ }
2168
+
2067
2169
  extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
2068
2170
  {
2069
2171
  if (RG_LIKELY(exec_call)) {
@@ -2106,7 +2208,7 @@ static void SetExports(Napi::Env env, Func func)
2106
2208
  func("opaque", Napi::Function::New(env, CreateOpaqueType));
2107
2209
  func("pointer", Napi::Function::New(env, CreatePointerType));
2108
2210
  func("array", Napi::Function::New(env, CreateArrayType));
2109
- func("callback", Napi::Function::New(env, CreateCallbackType));
2211
+ func("proto", Napi::Function::New(env, CreateFunctionType));
2110
2212
  func("alias", Napi::Function::New(env, CreateTypeAlias));
2111
2213
 
2112
2214
  func("sizeof", Napi::Function::New(env, GetTypeSize));
@@ -2130,6 +2232,8 @@ static void SetExports(Napi::Env env, Func func)
2130
2232
  func("as", Napi::Function::New(env, CastValue));
2131
2233
  func("decode", Napi::Function::New(env, DecodeValue));
2132
2234
  func("address", Napi::Function::New(env, GetPointerAddress));
2235
+ func("call", Napi::Function::New(env, CallPointerSync));
2236
+ func("callAsync", Napi::Function::New(env, CallPointerAsync));
2133
2237
 
2134
2238
  func("errno", Napi::Function::New(env, GetOrSetErrNo));
2135
2239
 
@@ -221,11 +221,12 @@ struct FunctionInfo {
221
221
  const char *decorated_name; // Only set for some platforms/calling conventions
222
222
  const LibraryHolder *lib = nullptr;
223
223
 
224
- void *func;
224
+ void *native;
225
225
  CallConvention convention;
226
226
 
227
227
  ParameterInfo ret;
228
228
  HeapArray<ParameterInfo> parameters;
229
+ int8_t required_parameters;
229
230
  int8_t out_parameters;
230
231
  bool variadic;
231
232
 
@@ -99,6 +99,8 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
99
99
  }
100
100
  Consume(")");
101
101
 
102
+ out_func->required_parameters = (int8_t)out_func->parameters.len;
103
+
102
104
  Match(";");
103
105
  if (offset < tokens.len) {
104
106
  MarkError("Unexpected token '%1' after prototype", tokens[offset]);