koffi 2.3.21-beta.2 → 2.3.21-beta.4

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 (49) hide show
  1. package/build/2.3.21-beta.4/koffi_darwin_arm64/koffi.node +0 -0
  2. package/build/2.3.21-beta.4/koffi_darwin_x64/koffi.node +0 -0
  3. package/build/2.3.21-beta.4/koffi_freebsd_arm64/koffi.node +0 -0
  4. package/build/2.3.21-beta.4/koffi_freebsd_ia32/koffi.node +0 -0
  5. package/build/2.3.21-beta.4/koffi_freebsd_x64/koffi.node +0 -0
  6. package/build/2.3.21-beta.4/koffi_linux_arm32hf/koffi.node +0 -0
  7. package/build/2.3.21-beta.4/koffi_linux_arm64/koffi.node +0 -0
  8. package/build/2.3.21-beta.4/koffi_linux_ia32/koffi.node +0 -0
  9. package/build/2.3.21-beta.4/koffi_linux_riscv64hf64/koffi.node +0 -0
  10. package/build/2.3.21-beta.4/koffi_linux_x64/koffi.node +0 -0
  11. package/build/2.3.21-beta.4/koffi_openbsd_ia32/koffi.node +0 -0
  12. package/build/2.3.21-beta.4/koffi_openbsd_x64/koffi.node +0 -0
  13. package/build/2.3.21-beta.4/koffi_win32_arm64/koffi.node +0 -0
  14. package/build/{2.3.21-beta.2 → 2.3.21-beta.4}/koffi_win32_ia32/koffi.node +0 -0
  15. package/build/{2.3.21-beta.2 → 2.3.21-beta.4}/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 +104 -78
  27. package/src/koffi/src/ffi.hh +6 -1
  28. package/src/koffi/src/parser.cc +2 -0
  29. package/src/koffi/src/util.cc +74 -3
  30. package/src/koffi/src/util.hh +4 -0
  31. package/build/2.3.21-beta.2/koffi_darwin_arm64/koffi.node +0 -0
  32. package/build/2.3.21-beta.2/koffi_darwin_x64/koffi.node +0 -0
  33. package/build/2.3.21-beta.2/koffi_freebsd_arm64/koffi.node +0 -0
  34. package/build/2.3.21-beta.2/koffi_freebsd_ia32/koffi.node +0 -0
  35. package/build/2.3.21-beta.2/koffi_freebsd_x64/koffi.node +0 -0
  36. package/build/2.3.21-beta.2/koffi_linux_arm32hf/koffi.node +0 -0
  37. package/build/2.3.21-beta.2/koffi_linux_arm64/koffi.node +0 -0
  38. package/build/2.3.21-beta.2/koffi_linux_ia32/koffi.node +0 -0
  39. package/build/2.3.21-beta.2/koffi_linux_riscv64hf64/koffi.node +0 -0
  40. package/build/2.3.21-beta.2/koffi_linux_x64/koffi.node +0 -0
  41. package/build/2.3.21-beta.2/koffi_openbsd_ia32/koffi.node +0 -0
  42. package/build/2.3.21-beta.2/koffi_openbsd_x64/koffi.node +0 -0
  43. package/build/2.3.21-beta.2/koffi_win32_arm64/koffi.node +0 -0
  44. /package/build/{2.3.21-beta.2 → 2.3.21-beta.4}/koffi_win32_arm64/koffi.exp +0 -0
  45. /package/build/{2.3.21-beta.2 → 2.3.21-beta.4}/koffi_win32_arm64/koffi.lib +0 -0
  46. /package/build/{2.3.21-beta.2 → 2.3.21-beta.4}/koffi_win32_ia32/koffi.exp +0 -0
  47. /package/build/{2.3.21-beta.2 → 2.3.21-beta.4}/koffi_win32_ia32/koffi.lib +0 -0
  48. /package/build/{2.3.21-beta.2 → 2.3.21-beta.4}/koffi_win32_x64/koffi.exp +0 -0
  49. /package/build/{2.3.21-beta.2 → 2.3.21-beta.4}/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.4",
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
@@ -204,14 +204,6 @@ static inline bool CheckAlignment(int64_t align)
204
204
  return valid;
205
205
  }
206
206
 
207
- static inline Napi::External<TypeInfo> WrapType(Napi::Env env, InstanceData *instance, const TypeInfo *type)
208
- {
209
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
210
- SetValueTag(instance, external, &TypeInfoMarker);
211
-
212
- return external;
213
- }
214
-
215
207
  static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
216
208
  {
217
209
  Napi::Env env = info.Env();
@@ -275,7 +267,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
275
267
  value = array[1u];
276
268
  align = (int16_t)align64;
277
269
  }
278
-
270
+
279
271
  member.type = ResolveType(value);
280
272
  if (!member.type)
281
273
  return env.Null();
@@ -403,7 +395,7 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
403
395
  value = array[1u];
404
396
  align = (int16_t)align64;
405
397
  }
406
-
398
+
407
399
  member.type = ResolveType(value);
408
400
  if (!member.type)
409
401
  return env.Null();
@@ -920,10 +912,12 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
920
912
  func->parameters.Append(param);
921
913
  }
922
914
 
915
+ func->required_parameters = (int8_t)func->parameters.len;
916
+
923
917
  return true;
924
918
  }
925
919
 
926
- static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
920
+ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
927
921
  {
928
922
  Napi::Env env = info.Env();
929
923
  InstanceData *instance = env.GetInstanceData<InstanceData>();
@@ -956,6 +950,12 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
956
950
  if (!AnalyseFunction(env, instance, func))
957
951
  return env.Null();
958
952
 
953
+ // Adjust parameter offsets for koffi.call()
954
+ for (ParameterInfo &param: func->parameters) {
955
+ param.offset += 2;
956
+ }
957
+ func->required_parameters += 2;
958
+
959
959
  // We cannot fail after this check
960
960
  if (instance->types_map.Find(func->name)) {
961
961
  ThrowError<Napi::Error>(env, "Duplicate type name '%1'", func->name);
@@ -1239,13 +1239,13 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
1239
1239
  return mem;
1240
1240
  }
1241
1241
 
1242
- static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1242
+ static Napi::Value TranslateNormalCall(const FunctionInfo *func, void *native,
1243
+ const Napi::CallbackInfo &info)
1243
1244
  {
1244
1245
  Napi::Env env = info.Env();
1245
1246
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1246
- FunctionInfo *func = (FunctionInfo *)info.Data();
1247
1247
 
1248
- if (RG_UNLIKELY(info.Length() < (uint32_t)func->parameters.len)) {
1248
+ if (RG_UNLIKELY(info.Length() < (uint32_t)func->required_parameters)) {
1249
1249
  ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
1250
1250
  return env.Null();
1251
1251
  }
@@ -1265,37 +1265,44 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1265
1265
  RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1266
1266
  exec_call = &call;
1267
1267
 
1268
- call.Execute(func);
1268
+ call.Execute(func, native);
1269
1269
  }
1270
1270
 
1271
1271
  return call.Complete(func);
1272
1272
  }
1273
1273
 
1274
- static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1274
+ Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1275
+ {
1276
+ FunctionInfo *func = (FunctionInfo *)info.Data();
1277
+ return TranslateNormalCall(func, func->native, info);
1278
+ }
1279
+
1280
+ static Napi::Value TranslateVariadicCall(const FunctionInfo *func, void *native,
1281
+ const Napi::CallbackInfo &info)
1275
1282
  {
1276
1283
  Napi::Env env = info.Env();
1277
1284
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1278
1285
 
1279
- FunctionInfo func;
1280
- memcpy((void *)&func, info.Data(), RG_SIZE(FunctionInfo));
1281
- func.lib = nullptr;
1286
+ FunctionInfo copy;
1287
+ memcpy((void *)&copy, func, RG_SIZE(*func));
1288
+ copy.lib = nullptr;
1282
1289
 
1283
1290
  // This makes variadic calls non-reentrant
1284
- RG_DEFER_C(len = func.parameters.len) {
1285
- func.parameters.RemoveFrom(len);
1286
- func.parameters.Leak();
1291
+ RG_DEFER_C(len = copy.parameters.len) {
1292
+ copy.parameters.RemoveFrom(len);
1293
+ copy.parameters.Leak();
1287
1294
  };
1288
1295
 
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());
1296
+ if (RG_UNLIKELY(info.Length() < (uint32_t)copy.required_parameters)) {
1297
+ ThrowError<Napi::TypeError>(env, "Expected %1 arguments or more, got %2", copy.parameters.len, info.Length());
1291
1298
  return env.Null();
1292
1299
  }
1293
- if (RG_UNLIKELY((info.Length() - func.parameters.len) % 2)) {
1300
+ if (RG_UNLIKELY((info.Length() - copy.required_parameters) % 2)) {
1294
1301
  ThrowError<Napi::Error>(env, "Missing value argument for variadic call");
1295
1302
  return env.Null();
1296
1303
  }
1297
1304
 
1298
- for (Size i = func.parameters.len; i < (Size)info.Length(); i += 2) {
1305
+ for (Size i = copy.required_parameters; i < (Size)info.Length(); i += 2) {
1299
1306
  ParameterInfo param = {};
1300
1307
 
1301
1308
  param.type = ResolveType(info[(uint32_t)i], &param.directions);
@@ -1306,11 +1313,11 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1306
1313
  ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
1307
1314
  return env.Null();
1308
1315
  }
1309
- if (RG_UNLIKELY(func.parameters.len >= MaxParameters)) {
1316
+ if (RG_UNLIKELY(copy.parameters.len >= MaxParameters)) {
1310
1317
  ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
1311
1318
  return env.Null();
1312
1319
  }
1313
- if (RG_UNLIKELY((param.directions & 2) && ++func.out_parameters >= MaxOutParameters)) {
1320
+ if (RG_UNLIKELY((param.directions & 2) && ++copy.out_parameters >= MaxOutParameters)) {
1314
1321
  ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 output parameters", MaxOutParameters);
1315
1322
  return env.Null();
1316
1323
  }
@@ -1318,20 +1325,20 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1318
1325
  param.variadic = true;
1319
1326
  param.offset = (int8_t)(i + 1);
1320
1327
 
1321
- func.parameters.Append(param);
1328
+ copy.parameters.Append(param);
1322
1329
  }
1323
1330
 
1324
- if (RG_UNLIKELY(!AnalyseFunction(env, instance, &func)))
1331
+ if (RG_UNLIKELY(!AnalyseFunction(env, instance, &copy)))
1325
1332
  return env.Null();
1326
1333
 
1327
1334
  InstanceMemory *mem = instance->memories[0];
1328
1335
  CallData call(env, instance, mem);
1329
1336
 
1330
- if (!RG_UNLIKELY(call.Prepare(&func, info)))
1337
+ if (!RG_UNLIKELY(call.Prepare(&copy, info)))
1331
1338
  return env.Null();
1332
1339
 
1333
1340
  if (instance->debug) {
1334
- call.DumpForward(&func);
1341
+ call.DumpForward(&copy);
1335
1342
  }
1336
1343
 
1337
1344
  // Execute call
@@ -1339,23 +1346,31 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1339
1346
  RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1340
1347
  exec_call = &call;
1341
1348
 
1342
- call.Execute(&func);
1349
+ call.Execute(&copy, native);
1343
1350
  }
1344
1351
 
1345
- return call.Complete(&func);
1352
+ return call.Complete(&copy);
1353
+ }
1354
+
1355
+ Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1356
+ {
1357
+ FunctionInfo *func = (FunctionInfo *)info.Data();
1358
+ return TranslateVariadicCall(func, func->native, info);
1346
1359
  }
1347
1360
 
1348
1361
  class AsyncCall: public Napi::AsyncWorker {
1349
1362
  Napi::Env env;
1363
+
1350
1364
  const FunctionInfo *func;
1365
+ void *native;
1351
1366
 
1352
1367
  CallData call;
1353
1368
  bool prepared = false;
1354
1369
 
1355
1370
  public:
1356
1371
  AsyncCall(Napi::Env env, InstanceData *instance, const FunctionInfo *func,
1357
- InstanceMemory *mem, Napi::Function &callback)
1358
- : Napi::AsyncWorker(callback), env(env), func(func->Ref()),
1372
+ void *native, InstanceMemory *mem, Napi::Function &callback)
1373
+ : Napi::AsyncWorker(callback), env(env), func(func->Ref()), native(native),
1359
1374
  call(env, instance, mem) {}
1360
1375
  ~AsyncCall() { func->Unref(); }
1361
1376
 
@@ -1381,7 +1396,7 @@ void AsyncCall::Execute()
1381
1396
  RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1382
1397
  exec_call = &call;
1383
1398
 
1384
- call.Execute(func);
1399
+ call.Execute(func, native);
1385
1400
  }
1386
1401
  }
1387
1402
 
@@ -1400,18 +1415,20 @@ void AsyncCall::OnOK()
1400
1415
  callback.Call(self, RG_LEN(args), args);
1401
1416
  }
1402
1417
 
1403
- static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1418
+ static Napi::Value TranslateAsyncCall(const FunctionInfo *func, void *native,
1419
+ const Napi::CallbackInfo &info)
1404
1420
  {
1421
+ RG_ASSERT(!func->variadic);
1422
+
1405
1423
  Napi::Env env = info.Env();
1406
1424
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1407
- FunctionInfo *func = (FunctionInfo *)info.Data();
1408
1425
 
1409
- if (info.Length() <= (uint32_t)func->parameters.len) {
1426
+ if (info.Length() <= (uint32_t)func->required_parameters) {
1410
1427
  ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len + 1, info.Length());
1411
1428
  return env.Null();
1412
1429
  }
1413
1430
 
1414
- Napi::Function callback = info[(uint32_t)func->parameters.len].As<Napi::Function>();
1431
+ Napi::Function callback = info[(uint32_t)func->required_parameters].As<Napi::Function>();
1415
1432
 
1416
1433
  if (!callback.IsFunction()) {
1417
1434
  ThrowError<Napi::TypeError>(env, "Expected callback function as last argument, got %1", GetValueType(instance, callback));
@@ -1423,7 +1440,7 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1423
1440
  ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
1424
1441
  return env.Null();
1425
1442
  }
1426
- AsyncCall *async = new AsyncCall(env, instance, func, mem, callback);
1443
+ AsyncCall *async = new AsyncCall(env, instance, func, native, mem, callback);
1427
1444
 
1428
1445
  if (async->Prepare(info) && instance->debug) {
1429
1446
  async->DumpForward();
@@ -1433,6 +1450,12 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1433
1450
  return env.Undefined();
1434
1451
  }
1435
1452
 
1453
+ Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1454
+ {
1455
+ FunctionInfo *func = (FunctionInfo *)info.Data();
1456
+ return TranslateAsyncCall(func, func->native, info);
1457
+ }
1458
+
1436
1459
  static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConvention convention)
1437
1460
  {
1438
1461
  Napi::Env env = info.Env();
@@ -1478,57 +1501,31 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
1478
1501
  #ifdef _WIN32
1479
1502
  if (info[0].IsString()) {
1480
1503
  if (func->decorated_name) {
1481
- func->func = (void *)GetProcAddress((HMODULE)lib->module, func->decorated_name);
1504
+ func->native = (void *)GetProcAddress((HMODULE)lib->module, func->decorated_name);
1482
1505
  }
1483
- if (!func->func) {
1484
- func->func = (void *)GetProcAddress((HMODULE)lib->module, func->name);
1506
+ if (!func->native) {
1507
+ func->native = (void *)GetProcAddress((HMODULE)lib->module, func->name);
1485
1508
  }
1486
1509
  } else {
1487
1510
  uint16_t ordinal = (uint16_t)info[0].As<Napi::Number>().Uint32Value();
1488
1511
 
1489
1512
  func->decorated_name = nullptr;
1490
- func->func = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
1513
+ func->native = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
1491
1514
  }
1492
1515
  #else
1493
1516
  if (func->decorated_name) {
1494
- func->func = dlsym(lib->module, func->decorated_name);
1517
+ func->native = dlsym(lib->module, func->decorated_name);
1495
1518
  }
1496
- if (!func->func) {
1497
- func->func = dlsym(lib->module, func->name);
1519
+ if (!func->native) {
1520
+ func->native = dlsym(lib->module, func->name);
1498
1521
  }
1499
1522
  #endif
1500
- if (!func->func) {
1523
+ if (!func->native) {
1501
1524
  ThrowError<Napi::Error>(env, "Cannot find function '%1' in shared library", func->name);
1502
1525
  return env.Null();
1503
1526
  }
1504
1527
 
1505
- Napi::Function::Callback call = func->variadic ? TranslateVariadicCall : TranslateNormalCall;
1506
- Napi::Function wrapper = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1507
- wrapper.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, func);
1508
-
1509
- if (!func->variadic) {
1510
- Napi::Function async = Napi::Function::New(env, TranslateAsyncCall, func->name, (void *)func->Ref());
1511
- async.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, func);
1512
- wrapper.Set("async", async);
1513
- }
1514
-
1515
- // Create info object
1516
- {
1517
- Napi::Object meta = Napi::Object::New(env);
1518
- Napi::Array arguments = Napi::Array::New(env, func->parameters.len);
1519
-
1520
- meta.Set("name", Napi::String::New(env, func->name));
1521
- meta.Set("arguments", arguments);
1522
- meta.Set("result", WrapType(env, instance, func->ret.type));
1523
-
1524
- for (Size i = 0; i < func->parameters.len; i++) {
1525
- const ParameterInfo &param = func->parameters[i];
1526
- arguments.Set((uint32_t)i, WrapType(env, instance, param.type));
1527
- }
1528
-
1529
- wrapper.Set("info", meta);
1530
- }
1531
-
1528
+ Napi::Function wrapper = WrapFunction(env, func);
1532
1529
  return wrapper;
1533
1530
  }
1534
1531
 
@@ -2064,6 +2061,34 @@ static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
2064
2061
  return bigint;
2065
2062
  }
2066
2063
 
2064
+ static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
2065
+ {
2066
+ Napi::Env env = info.Env();
2067
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
2068
+
2069
+ if (RG_UNLIKELY(info.Length() < 2)) {
2070
+ ThrowError<Napi::TypeError>(env, "Expected 2 or more arguments, got %1", info.Length());
2071
+ return env.Null();
2072
+ }
2073
+
2074
+ void *ptr = nullptr;
2075
+ if (RG_UNLIKELY(!GetExternalPointer(env, info[0], &ptr)))
2076
+ return env.Null();
2077
+
2078
+ const TypeInfo *type = ResolveType(info[1]);
2079
+ if (RG_UNLIKELY(!type))
2080
+ return env.Null();
2081
+ if (RG_UNLIKELY(type->primitive != PrimitiveKind::Prototype)) {
2082
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for type, expected function type", GetValueType(instance, info[1]));
2083
+ return env.Null();
2084
+ }
2085
+
2086
+ const FunctionInfo *proto = type->ref.proto;
2087
+ RG_ASSERT(!proto->variadic);
2088
+
2089
+ return TranslateNormalCall(proto, ptr, info);
2090
+ }
2091
+
2067
2092
  extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
2068
2093
  {
2069
2094
  if (RG_LIKELY(exec_call)) {
@@ -2106,7 +2131,7 @@ static void SetExports(Napi::Env env, Func func)
2106
2131
  func("opaque", Napi::Function::New(env, CreateOpaqueType));
2107
2132
  func("pointer", Napi::Function::New(env, CreatePointerType));
2108
2133
  func("array", Napi::Function::New(env, CreateArrayType));
2109
- func("callback", Napi::Function::New(env, CreateCallbackType));
2134
+ func("proto", Napi::Function::New(env, CreateFunctionType));
2110
2135
  func("alias", Napi::Function::New(env, CreateTypeAlias));
2111
2136
 
2112
2137
  func("sizeof", Napi::Function::New(env, GetTypeSize));
@@ -2130,6 +2155,7 @@ static void SetExports(Napi::Env env, Func func)
2130
2155
  func("as", Napi::Function::New(env, CastValue));
2131
2156
  func("decode", Napi::Function::New(env, DecodeValue));
2132
2157
  func("address", Napi::Function::New(env, GetPointerAddress));
2158
+ func("call", Napi::Function::New(env, CallPointerSync));
2133
2159
 
2134
2160
  func("errno", Napi::Function::New(env, GetOrSetErrNo));
2135
2161
 
@@ -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
 
@@ -335,4 +336,8 @@ RG_STATIC_ASSERT(MaxTrampolines <= INT16_MAX);
335
336
 
336
337
  extern SharedData shared;
337
338
 
339
+ Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info);
340
+ Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info);
341
+ Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info);
342
+
338
343
  }
@@ -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]);
@@ -345,6 +345,14 @@ const TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size
345
345
  return MakeArrayType(instance, ref, len, hint, false);
346
346
  }
347
347
 
348
+ Napi::External<TypeInfo> WrapType(Napi::Env env, InstanceData *instance, const TypeInfo *type)
349
+ {
350
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
351
+ SetValueTag(instance, external, &TypeInfoMarker);
352
+
353
+ return external;
354
+ }
355
+
348
356
  bool CanPassType(const TypeInfo *type, int directions)
349
357
  {
350
358
  if (directions & 2) {
@@ -1041,7 +1049,8 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
1041
1049
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1042
1050
 
1043
1051
  if (len && type->primitive != PrimitiveKind::String &&
1044
- type->primitive != PrimitiveKind::String16) {
1052
+ type->primitive != PrimitiveKind::String16 &&
1053
+ type->primitive != PrimitiveKind::Prototype) {
1045
1054
  if (*len >= 0) {
1046
1055
  type = MakeArrayType(instance, type, *len);
1047
1056
  } else {
@@ -1144,8 +1153,28 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
1144
1153
  } break;
1145
1154
 
1146
1155
  case PrimitiveKind::Prototype: {
1147
- ThrowError<Napi::TypeError>(env, "Cannot decode value of type %1", type->name);
1148
- return env.Null();
1156
+ const FunctionInfo *proto = type->ref.proto;
1157
+ RG_ASSERT(!proto->variadic);
1158
+ RG_ASSERT(!proto->lib);
1159
+
1160
+ FunctionInfo *func = new FunctionInfo();
1161
+ RG_DEFER { func->Unref(); };
1162
+
1163
+ memcpy((void *)func, proto, RG_SIZE(*proto));
1164
+ memset((void *)&func->parameters, 0, RG_SIZE(func->parameters));
1165
+ func->parameters = proto->parameters;
1166
+
1167
+ func->name = "<anonymous>";
1168
+ func->native = (void *)ptr;
1169
+
1170
+ // Fix back parameter offset
1171
+ for (ParameterInfo &param: func->parameters) {
1172
+ param.offset -= 2;
1173
+ }
1174
+ func->required_parameters -= 2;
1175
+
1176
+ Napi::Function wrapper = WrapFunction(env, func);
1177
+ return wrapper;
1149
1178
  } break;
1150
1179
  }
1151
1180
 
@@ -1155,6 +1184,48 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, cons
1155
1184
  return env.Null();
1156
1185
  }
1157
1186
 
1187
+ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
1188
+ {
1189
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1190
+
1191
+ Napi::Function wrapper;
1192
+ if (func->variadic) {
1193
+ Napi::Function::Callback call = TranslateVariadicCall;
1194
+ wrapper = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1195
+ } else {
1196
+ Napi::Function::Callback call = TranslateNormalCall;
1197
+ wrapper = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1198
+ }
1199
+ wrapper.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
1200
+
1201
+ if (!func->variadic) {
1202
+ Napi::Function::Callback call = TranslateAsyncCall;
1203
+ Napi::Function async = Napi::Function::New(env, call, func->name, (void *)func->Ref());
1204
+
1205
+ async.AddFinalizer([](Napi::Env, FunctionInfo *func) { func->Unref(); }, (FunctionInfo *)func);
1206
+ wrapper.Set("async", async);
1207
+ }
1208
+
1209
+ // Create info object
1210
+ {
1211
+ Napi::Object meta = Napi::Object::New(env);
1212
+ Napi::Array arguments = Napi::Array::New(env, func->parameters.len);
1213
+
1214
+ meta.Set("name", Napi::String::New(env, func->name));
1215
+ meta.Set("arguments", arguments);
1216
+ meta.Set("result", WrapType(env, instance, func->ret.type));
1217
+
1218
+ for (Size i = 0; i < func->parameters.len; i++) {
1219
+ const ParameterInfo &param = func->parameters[i];
1220
+ arguments.Set((uint32_t)i, WrapType(env, instance, param.type));
1221
+ }
1222
+
1223
+ wrapper.Set("info", meta);
1224
+ }
1225
+
1226
+ return wrapper;
1227
+ }
1228
+
1158
1229
  static int AnalyseFlatRec(const TypeInfo *type, int offset, int count, FunctionRef<void(const TypeInfo *type, int offset, int count)> func)
1159
1230
  {
1160
1231
  if (type->primitive == PrimitiveKind::Record) {
@@ -93,6 +93,8 @@ const TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *ref, int
93
93
  const TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len);
94
94
  const TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, ArrayHint hint);
95
95
 
96
+ Napi::External<TypeInfo> WrapType(Napi::Env env, InstanceData *instance, const TypeInfo *type);
97
+
96
98
  bool CanPassType(const TypeInfo *type, int directions);
97
99
  bool CanReturnType(const TypeInfo *type);
98
100
  bool CanStoreType(const TypeInfo *type);
@@ -185,6 +187,8 @@ static inline Napi::Value NewBigInt(Napi::Env env, uint64_t value)
185
187
  }
186
188
  }
187
189
 
190
+ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func);
191
+
188
192
  int AnalyseFlat(const TypeInfo *type, FunctionRef<void(const TypeInfo *type, int offset, int count)> func);
189
193
 
190
194
  void DumpMemory(const char *type, Span<const uint8_t> bytes);