koffi 2.2.2-beta.5 → 2.2.2-beta.6

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 (59) hide show
  1. package/doc/callbacks.md +1 -1
  2. package/doc/contribute.md +1 -1
  3. package/package.json +1 -1
  4. package/src/koffi/build/2.2.2-beta.6/koffi_darwin_arm64.tar.gz +0 -0
  5. package/src/koffi/build/2.2.2-beta.6/koffi_darwin_x64.tar.gz +0 -0
  6. package/src/koffi/build/2.2.2-beta.6/koffi_freebsd_arm64.tar.gz +0 -0
  7. package/src/koffi/build/2.2.2-beta.6/koffi_freebsd_ia32.tar.gz +0 -0
  8. package/src/koffi/build/2.2.2-beta.6/koffi_freebsd_x64.tar.gz +0 -0
  9. package/src/koffi/build/2.2.2-beta.6/koffi_linux_arm32hf.tar.gz +0 -0
  10. package/src/koffi/build/2.2.2-beta.6/koffi_linux_arm64.tar.gz +0 -0
  11. package/src/koffi/build/2.2.2-beta.6/koffi_linux_ia32.tar.gz +0 -0
  12. package/src/koffi/build/2.2.2-beta.6/koffi_linux_riscv64hf64.tar.gz +0 -0
  13. package/src/koffi/build/2.2.2-beta.6/koffi_linux_x64.tar.gz +0 -0
  14. package/src/koffi/build/2.2.2-beta.6/koffi_openbsd_ia32.tar.gz +0 -0
  15. package/src/koffi/build/2.2.2-beta.6/koffi_openbsd_x64.tar.gz +0 -0
  16. package/src/koffi/build/2.2.2-beta.6/koffi_win32_arm64.tar.gz +0 -0
  17. package/src/koffi/build/2.2.2-beta.6/koffi_win32_ia32.tar.gz +0 -0
  18. package/src/koffi/build/2.2.2-beta.6/koffi_win32_x64.tar.gz +0 -0
  19. package/src/koffi/src/abi_arm32.cc +3 -70
  20. package/src/koffi/src/abi_arm32_fwd.S +6054 -97
  21. package/src/koffi/src/abi_arm64.cc +3 -70
  22. package/src/koffi/src/abi_arm64_fwd.S +6050 -93
  23. package/src/koffi/src/abi_arm64_fwd.asm +8082 -141
  24. package/src/koffi/src/abi_riscv64.cc +3 -70
  25. package/src/koffi/src/abi_riscv64_fwd.S +6044 -87
  26. package/src/koffi/src/abi_trampolines.inc +2065 -0
  27. package/src/koffi/src/abi_x64_sysv.cc +3 -70
  28. package/src/koffi/src/abi_x64_sysv_fwd.S +6048 -91
  29. package/src/koffi/src/abi_x64_win.cc +4 -71
  30. package/src/koffi/src/abi_x64_win_fwd.asm +8018 -77
  31. package/src/koffi/src/abi_x86.cc +4 -71
  32. package/src/koffi/src/abi_x86_fwd.S +6056 -99
  33. package/src/koffi/src/abi_x86_fwd.asm +8027 -86
  34. package/src/koffi/src/call.cc +20 -16
  35. package/src/koffi/src/call.hh +2 -4
  36. package/src/koffi/src/ffi.cc +31 -29
  37. package/src/koffi/src/ffi.hh +16 -5
  38. package/src/koffi/test/callbacks.js +11 -10
  39. package/src/koffi/test/misc.c +30 -17
  40. package/src/koffi/{qemu → tools}/qemu/.gitkeep +0 -0
  41. package/src/koffi/{qemu → tools}/qemu.js +4 -1
  42. package/src/koffi/{qemu → tools}/registry/machines.json +0 -0
  43. package/src/koffi/{qemu → tools}/registry/sha256sum.txt +0 -0
  44. package/src/koffi/tools/write_trampolines.py +138 -0
  45. package/src/koffi/build/2.2.2-beta.5/koffi_darwin_arm64.tar.gz +0 -0
  46. package/src/koffi/build/2.2.2-beta.5/koffi_darwin_x64.tar.gz +0 -0
  47. package/src/koffi/build/2.2.2-beta.5/koffi_freebsd_arm64.tar.gz +0 -0
  48. package/src/koffi/build/2.2.2-beta.5/koffi_freebsd_ia32.tar.gz +0 -0
  49. package/src/koffi/build/2.2.2-beta.5/koffi_freebsd_x64.tar.gz +0 -0
  50. package/src/koffi/build/2.2.2-beta.5/koffi_linux_arm32hf.tar.gz +0 -0
  51. package/src/koffi/build/2.2.2-beta.5/koffi_linux_arm64.tar.gz +0 -0
  52. package/src/koffi/build/2.2.2-beta.5/koffi_linux_ia32.tar.gz +0 -0
  53. package/src/koffi/build/2.2.2-beta.5/koffi_linux_riscv64hf64.tar.gz +0 -0
  54. package/src/koffi/build/2.2.2-beta.5/koffi_linux_x64.tar.gz +0 -0
  55. package/src/koffi/build/2.2.2-beta.5/koffi_openbsd_ia32.tar.gz +0 -0
  56. package/src/koffi/build/2.2.2-beta.5/koffi_openbsd_x64.tar.gz +0 -0
  57. package/src/koffi/build/2.2.2-beta.5/koffi_win32_arm64.tar.gz +0 -0
  58. package/src/koffi/build/2.2.2-beta.5/koffi_win32_ia32.tar.gz +0 -0
  59. package/src/koffi/build/2.2.2-beta.5/koffi_win32_x64.tar.gz +0 -0
@@ -53,19 +53,20 @@ CallData::~CallData()
53
53
  mem->stack = old_stack_mem;
54
54
  mem->heap = old_heap_mem;
55
55
 
56
- if (used_trampolines) {
56
+ if (used_trampolines.len) {
57
57
  std::lock_guard<std::mutex> lock(shared.mutex);
58
58
 
59
- for (Size i = 0; i < MaxTrampolines; i++) {
60
- if (used_trampolines & (1u << i)) {
61
- TrampolineInfo *trampoline = &shared.trampolines[i];
59
+ for (Size i = used_trampolines.len - 1; i >= 0; i--) {
60
+ int16_t idx = used_trampolines[i];
61
+ TrampolineInfo *trampoline = &shared.trampolines[idx];
62
62
 
63
- trampoline->func.Reset();
64
- trampoline->recv.Reset();
65
- }
66
- }
63
+ RG_ASSERT(!trampoline->func.IsEmpty());
67
64
 
68
- shared.temp_trampolines ^= used_trampolines;
65
+ trampoline->func.Reset();
66
+ trampoline->recv.Reset();
67
+
68
+ shared.available.Append(idx);
69
+ }
69
70
  }
70
71
 
71
72
  instance->temporaries -= mem->temporary;
@@ -1025,19 +1026,21 @@ void CallData::PopOutArguments()
1025
1026
 
1026
1027
  void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func)
1027
1028
  {
1028
- int idx;
1029
+ int16_t idx;
1029
1030
  {
1030
1031
  std::lock_guard<std::mutex> lock(shared.mutex);
1031
1032
 
1032
- idx = CountTrailingZeros(~shared.temp_trampolines);
1033
-
1034
- if (RG_UNLIKELY(idx >= MaxTrampolines)) {
1035
- ThrowError<Napi::Error>(env, "Too many temporary callbacks are in use (max = %1)", MaxTrampolines);
1033
+ if (RG_UNLIKELY(!shared.available.len)) {
1034
+ ThrowError<Napi::Error>(env, "Too many callbacks are in use (max = %1)", MaxTrampolines);
1035
+ return env.Null();
1036
+ }
1037
+ if (RG_UNLIKELY(!used_trampolines.Available())) {
1038
+ ThrowError<Napi::Error>(env, "This call uses too many temporary callbacks (max = %1)", RG_LEN(used_trampolines.data));
1036
1039
  return env.Null();
1037
1040
  }
1038
1041
 
1039
- shared.temp_trampolines |= 1u << idx;
1040
- used_trampolines |= 1u << idx;
1042
+ idx = shared.available.data[--shared.available.len];
1043
+ used_trampolines.Append(idx);
1041
1044
  }
1042
1045
 
1043
1046
  TrampolineInfo *trampoline = &shared.trampolines[idx];
@@ -1048,6 +1051,7 @@ void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func
1048
1051
  trampoline->generation = (int32_t)mem->generation;
1049
1052
 
1050
1053
  void *ptr = GetTrampoline(idx, proto);
1054
+
1051
1055
  return ptr;
1052
1056
  }
1053
1057
 
@@ -41,8 +41,7 @@ class alignas(8) CallData {
41
41
  Span<uint8_t> old_stack_mem;
42
42
  Span<uint8_t> old_heap_mem;
43
43
 
44
- uint32_t used_trampolines = 0;
45
-
44
+ LocalArray<int16_t, 16> used_trampolines;
46
45
  LocalArray<OutArgument, MaxOutParameters> out_arguments;
47
46
 
48
47
  uint8_t *new_sp;
@@ -112,7 +111,6 @@ private:
112
111
 
113
112
  void *ReserveTrampoline(const FunctionInfo *proto, Napi::Function func);
114
113
  };
115
- RG_STATIC_ASSERT(MaxTrampolines <= 32);
116
114
 
117
115
  template <typename T>
118
116
  inline bool CallData::AllocStack(Size size, Size align, T **out_ptr)
@@ -165,6 +163,6 @@ inline T *CallData::AllocHeap(Size size, Size align)
165
163
  }
166
164
  }
167
165
 
168
- void *GetTrampoline(Size idx, const FunctionInfo *proto);
166
+ void *GetTrampoline(int16_t idx, const FunctionInfo *proto);
169
167
 
170
168
  }
@@ -1001,6 +1001,8 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
1001
1001
 
1002
1002
  static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size)
1003
1003
  {
1004
+ std::lock_guard<std::mutex> lock(instance->memories_mutex);
1005
+
1004
1006
  for (Size i = 1; i < instance->memories.len; i++) {
1005
1007
  InstanceMemory *mem = instance->memories[i];
1006
1008
 
@@ -1436,19 +1438,16 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1436
1438
  return env.Null();
1437
1439
  }
1438
1440
 
1439
- int idx;
1441
+ int16_t idx;
1440
1442
  {
1441
1443
  std::lock_guard<std::mutex> lock(shared.mutex);
1442
1444
 
1443
- idx = CountTrailingZeros(~shared.registered_trampolines);
1444
-
1445
- if (RG_UNLIKELY(idx >= MaxTrampolines)) {
1446
- ThrowError<Napi::Error>(env, "Too many registered callbacks are in use (max = %1)", MaxTrampolines);
1445
+ if (RG_UNLIKELY(!shared.available.len)) {
1446
+ ThrowError<Napi::Error>(env, "Too many callbacks are in use (max = %1)", MaxTrampolines);
1447
1447
  return env.Null();
1448
1448
  }
1449
1449
 
1450
- shared.registered_trampolines |= 1u << idx;
1451
- idx += MaxTrampolines;
1450
+ idx = shared.available.data[--shared.available.len];
1452
1451
  }
1453
1452
 
1454
1453
  TrampolineInfo *trampoline = &shared.trampolines[idx];
@@ -1467,6 +1466,9 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1467
1466
  Napi::External<void> external = Napi::External<void>::New(env, ptr);
1468
1467
  SetValueTag(instance, external, type->ref.marker);
1469
1468
 
1469
+ // Cache index for fast unregistration
1470
+ instance->trampolines_map.Set(ptr, idx);
1471
+
1470
1472
  return external;
1471
1473
  }
1472
1474
 
@@ -1487,31 +1489,33 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
1487
1489
  Napi::External<void> external = info[0].As<Napi::External<void>>();
1488
1490
  void *ptr = external.Data();
1489
1491
 
1490
- // Release shared trampoline safely
1492
+ int16_t idx;
1491
1493
  {
1492
- std::lock_guard<std::mutex> lock(shared.mutex);
1494
+ int16_t *it = instance->trampolines_map.Find(ptr);
1493
1495
 
1494
- for (Size i = 0; i < MaxTrampolines; i++) {
1495
- Size idx = i + MaxTrampolines;
1496
+ if (RG_UNLIKELY(!it)) {
1497
+ ThrowError<Napi::Error>(env, "Could not find matching registered callback");
1498
+ return env.Null();
1499
+ }
1496
1500
 
1497
- if (!(shared.registered_trampolines & (1u << i)))
1498
- continue;
1501
+ idx = *it;
1502
+ instance->trampolines_map.Remove(it);
1503
+ }
1499
1504
 
1500
- TrampolineInfo *trampoline = &shared.trampolines[idx];
1505
+ // Release shared trampoline safely
1506
+ {
1507
+ std::lock_guard<std::mutex> lock(shared.mutex);
1501
1508
 
1502
- if (GetTrampoline(idx, trampoline->proto) == ptr) {
1503
- shared.registered_trampolines &= ~(1u << i);
1509
+ TrampolineInfo *trampoline = &shared.trampolines[idx];
1510
+ RG_ASSERT(!trampoline->func.IsEmpty());
1504
1511
 
1505
- trampoline->func.Reset();
1506
- trampoline->recv.Reset();
1512
+ trampoline->func.Reset();
1513
+ trampoline->recv.Reset();
1507
1514
 
1508
- return env.Undefined();
1509
- }
1510
- }
1515
+ shared.available.Append(idx);
1511
1516
  }
1512
1517
 
1513
- ThrowError<Napi::Error>(env, "Could not find matching registered callback");
1514
- return env.Null();
1518
+ return env.Undefined();
1515
1519
  }
1516
1520
 
1517
1521
  LibraryHolder::~LibraryHolder()
@@ -1709,18 +1713,16 @@ InstanceData::~InstanceData()
1709
1713
  delete mem;
1710
1714
  }
1711
1715
 
1712
- // Clean-up leftover registered trampolines
1716
+ // Clean-up leftover trampoline references
1713
1717
  {
1714
1718
  std::lock_guard<std::mutex> lock(shared.mutex);
1715
1719
 
1716
- for (Size i = 0; i < MaxTrampolines; i++) {
1717
- Size idx = i + MaxTrampolines;
1720
+ for (int16_t idx = 0; idx < MaxTrampolines; idx++) {
1721
+ TrampolineInfo *trampoline = &shared.trampolines[idx];
1718
1722
 
1719
- if (!(shared.registered_trampolines & (1u << i)))
1723
+ if (trampoline->func.IsEmpty())
1720
1724
  continue;
1721
1725
 
1722
- TrampolineInfo *trampoline = &shared.trampolines[idx];
1723
-
1724
1726
  if (trampoline->func.Env().GetInstanceData<InstanceData>() == this) {
1725
1727
  trampoline->func.Reset();
1726
1728
  trampoline->recv.Reset();
@@ -30,7 +30,7 @@ static const Size DefaultMaxTypeSize = Mebibytes(64);
30
30
  static const int MaxAsyncCalls = 256;
31
31
  static const Size MaxParameters = 32;
32
32
  static const Size MaxOutParameters = 16;
33
- static const Size MaxTrampolines = 16;
33
+ static const Size MaxTrampolines = 1024;
34
34
 
35
35
  extern const int TypeInfoMarker;
36
36
  extern const int CastMarker;
@@ -247,12 +247,15 @@ struct InstanceData {
247
247
  const TypeInfo *char_type;
248
248
  const TypeInfo *char16_type;
249
249
 
250
+ std::mutex memories_mutex;
250
251
  LocalArray<InstanceMemory *, 9> memories;
251
252
  int temporaries = 0;
252
253
 
253
254
  std::thread::id main_thread_id;
254
255
  napi_threadsafe_function broker = nullptr;
255
256
 
257
+ HashMap<void *, int16_t> trampolines_map;
258
+
256
259
  BlockAllocator str_alloc;
257
260
 
258
261
  Size sync_stack_size = DefaultSyncStackSize;
@@ -266,7 +269,6 @@ struct InstanceData {
266
269
  RG_STATIC_ASSERT(DefaultResidentAsyncPools <= RG_LEN(InstanceData::memories.data) - 1);
267
270
  RG_STATIC_ASSERT(DefaultMaxAsyncCalls >= DefaultResidentAsyncPools);
268
271
  RG_STATIC_ASSERT(MaxAsyncCalls >= DefaultMaxAsyncCalls);
269
- RG_STATIC_ASSERT(MaxTrampolines <= 16);
270
272
 
271
273
  struct TrampolineInfo {
272
274
  const FunctionInfo *proto;
@@ -279,10 +281,19 @@ struct TrampolineInfo {
279
281
  struct SharedData {
280
282
  std::mutex mutex;
281
283
 
282
- TrampolineInfo trampolines[MaxTrampolines * 2];
283
- uint32_t temp_trampolines = 0;
284
- uint32_t registered_trampolines = 0;
284
+ TrampolineInfo trampolines[MaxTrampolines];
285
+ LocalArray<int16_t, MaxTrampolines> available;
286
+
287
+ SharedData()
288
+ {
289
+ available.len = MaxTrampolines;
290
+
291
+ for (int16_t i = 0; i < MaxTrampolines; i++) {
292
+ available[i] = i;
293
+ }
294
+ }
285
295
  };
296
+ RG_STATIC_ASSERT(MaxTrampolines <= INT16_MAX);
286
297
 
287
298
  extern SharedData shared;
288
299
 
@@ -75,8 +75,7 @@ async function test() {
75
75
  const ApplyStruct = lib.func('int ApplyStruct(int x, StructCallbacks callbacks)');
76
76
  const SetIndirect = lib.func('void SetIndirect(IntCallback *func)');
77
77
  const CallIndirect = lib.func('int CallIndirect(int x)');
78
- const CallIndirectThreaded = lib.func('int CallIndirectThreaded(int x)');
79
- const CallDirectThreaded = lib.func('int CallDirectThreaded(IntCallback *func, int x)');
78
+ const CallThreaded = lib.func('int CallThreaded(IntCallback *func, int x)');
80
79
  const MakeVectors = lib.func('int MakeVectors(int len, VectorCallback *func)');
81
80
  const CallQSort = lib.func('void CallQSort(_Inout_ void *base, size_t nmemb, size_t size, SortCallback *cb)');
82
81
  const CallMeChar = lib.func('int CallMeChar(CharCallback *func)');
@@ -263,16 +262,18 @@ async function test() {
263
262
  assert.equal(ret, 97 + 2 * 98);
264
263
  }
265
264
 
266
- // Use temporary callback from secondary thread
267
- for (let i = 0; i < 128; i++)
268
- assert.equal(await util.promisify(CallDirectThreaded.async)(x => -x - 2, 27), -29);
269
-
270
- // Use registered callback from secondary thread
271
- for (let i = 0; i < 128; i++) {
265
+ // Use callbacks from secondary threads
266
+ for (let i = 0; i < 1024; i++) {
272
267
  let cb = koffi.register(x => -x - 2, koffi.pointer(IntCallback));
273
-
274
268
  SetIndirect(cb);
275
- assert.equal(await util.promisify(CallIndirectThreaded.async)(27), -29);
269
+
270
+ let results = await Promise.all([
271
+ util.promisify(CallThreaded.async)(x => -x - 4, 27),
272
+ util.promisify(CallThreaded.async)(null, 27)
273
+ ]);
274
+
275
+ assert.equal(results[0], -31);
276
+ assert.equal(results[1], -29);
276
277
 
277
278
  koffi.unregister(cb);
278
279
  }
@@ -681,17 +681,27 @@ EXPORT int CallIndirect(int x)
681
681
 
682
682
  #ifdef _WIN32
683
683
 
684
- static DWORD WINAPI CallIndirectThreadedFunc(void *udata)
684
+ typedef struct CallContext {
685
+ IntCallback *callback;
686
+ int *ptr;
687
+ } CallContext;
688
+
689
+ static DWORD WINAPI CallThreadedFunc(void *udata)
685
690
  {
686
- int *ptr = (int *)udata;
687
- *ptr = callback(*ptr);
691
+ CallContext *ctx = (CallContext *)udata;
692
+ *ctx->ptr = ctx->callback(*ctx->ptr);
688
693
 
689
694
  return 0;
690
695
  }
691
696
 
692
- EXPORT int CallIndirectThreaded(int x)
697
+ EXPORT int CallThreaded(IntCallback *func, int x)
693
698
  {
694
- HANDLE h = CreateThread(NULL, 0, CallIndirectThreadedFunc, &x, 0, NULL);
699
+ CallContext ctx;
700
+
701
+ ctx.callback = func ? func : callback;
702
+ ctx.ptr = &x;
703
+
704
+ HANDLE h = CreateThread(NULL, 0, CallThreadedFunc, &ctx, 0, NULL);
695
705
  if (!h) {
696
706
  perror("CreateThread");
697
707
  exit(1);
@@ -705,19 +715,28 @@ EXPORT int CallIndirectThreaded(int x)
705
715
 
706
716
  #else
707
717
 
708
- static void *CallIndirectThreadedFunc(void *udata)
718
+ typedef struct CallContext {
719
+ IntCallback *callback;
720
+ int *ptr;
721
+ } CallContext;
722
+
723
+ static void *CallThreadedFunc(void *udata)
709
724
  {
710
- int *ptr = (int *)udata;
711
- *ptr = callback(*ptr);
725
+ CallContext *ctx = (CallContext *)udata;
726
+ *ctx->ptr = ctx->callback(*ctx->ptr);
712
727
 
713
728
  return NULL;
714
729
  }
715
730
 
716
- EXPORT int CallIndirectThreaded(int x)
731
+ EXPORT int CallThreaded(IntCallback *func, int x)
717
732
  {
718
- pthread_t thread;
733
+ CallContext ctx;
719
734
 
720
- if (pthread_create(&thread, NULL, CallIndirectThreadedFunc, &x)) {
735
+ ctx.callback = func ? func : callback;
736
+ ctx.ptr = &x;
737
+
738
+ pthread_t thread;
739
+ if (pthread_create(&thread, NULL, CallThreadedFunc, &ctx)) {
721
740
  perror("pthread_create");
722
741
  exit(1);
723
742
  }
@@ -729,12 +748,6 @@ EXPORT int CallIndirectThreaded(int x)
729
748
 
730
749
  #endif
731
750
 
732
- EXPORT int CallDirectThreaded(IntCallback *func, int x)
733
- {
734
- callback = func;
735
- return CallIndirectThreaded(x);
736
- }
737
-
738
751
  EXPORT void ReverseBytes(void *p, int len)
739
752
  {
740
753
  uint8_t *bytes = (uint8_t *)p;
File without changes
@@ -342,7 +342,7 @@ async function prepare() {
342
342
  log(machine, `${suite} > Status`, chalk.bold.red(`[manual]`));
343
343
  needed = true;
344
344
  } else {
345
- log(machine, `${suite} > Status`, chalk.bold.red(`[build]`));
345
+ log(machine, `${suite} > Status`, chalk.bold.red(`[missing]`));
346
346
  needed = true;
347
347
  }
348
348
  }
@@ -494,6 +494,7 @@ async function prepare() {
494
494
  fs.renameSync(dist_dir + '/src/koffi/LICENSE.txt', dist_dir + '/LICENSE.txt');
495
495
  fs.renameSync(dist_dir + '/src/koffi/ChangeLog.md', dist_dir + '/ChangeLog.md');
496
496
  fs.renameSync(dist_dir + '/web/koffi.dev', dist_dir + '/doc');
497
+ fs.rmdirSync(dist_dir + '/web');
497
498
  }
498
499
 
499
500
  return dist_dir;
@@ -514,6 +515,8 @@ function snapshot() {
514
515
  } else if (parts[0] == 'src') {
515
516
  return parts[1] == null || parts[1] == 'cnoke' ||
516
517
  parts[1] == 'koffi';
518
+ } else if (parts[0] == 'tools') {
519
+ return parts[1] == null || parts[1] != 'qemu';
517
520
  } else if (parts[0] == 'vendor') {
518
521
  return parts[1] == null || parts[1] == 'brotli' ||
519
522
  parts[1] == 'dragonbox' ||
File without changes
File without changes
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Affero General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Affero General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Affero General Public License
14
+ # along with this program. If not, see https://www.gnu.org/licenses/.
15
+
16
+ import argparse
17
+ import os
18
+
19
+ def write_asm_trampolines(filename, comment_char, n,
20
+ fmt_export, fmt_export_x, fmt_proc, fmt_proc_x, end = None):
21
+ with open(filename) as f:
22
+ lines = f.readlines()
23
+
24
+ with open(filename, 'w') as f:
25
+ for line in lines:
26
+ if line.rstrip() == comment_char + ' Trampolines':
27
+ break
28
+ f.write(line)
29
+
30
+ print(comment_char + ' Trampolines', file = f)
31
+ print(comment_char + ' ----------------------------', file = f)
32
+ print('', file = f)
33
+
34
+ for i in range(0, n):
35
+ print(fmt_export.format(i), file = f)
36
+ print('', file = f)
37
+ for i in range(0, n):
38
+ print(fmt_export_x.format(i), file = f)
39
+ print('', file = f)
40
+
41
+ for i in range(0, n):
42
+ print(fmt_proc.format(i), file = f)
43
+ print('', file = f)
44
+ for i in range(0, n):
45
+ print(fmt_proc_x.format(i), file = f)
46
+
47
+ if end is not None:
48
+ print('', file = f)
49
+ print(end, file = f)
50
+
51
+ def write_cxx_trampolines(filename, n):
52
+ with open(filename) as f:
53
+ lines = f.readlines()
54
+
55
+ with open(filename, 'w') as f:
56
+ for line in lines:
57
+ if not line.startswith('//'):
58
+ break
59
+ f.write(line)
60
+
61
+ print('', file = f)
62
+ for i in range(0, n):
63
+ print('extern "C" int Trampoline{0}; extern "C" int TrampolineX{0};'.format(i), file = f)
64
+
65
+ print('', file = f)
66
+ print('static void *const Trampolines[][2] = {', file = f)
67
+ for i in range(0, n):
68
+ if i + 1 < n:
69
+ print(' {{ &Trampoline{0}, &TrampolineX{0} }},'.format(i), file = f)
70
+ else:
71
+ print(' {{ &Trampoline{0}, &TrampolineX{0} }}'.format(i), file = f)
72
+ print('};', file = f)
73
+ print('RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines);', file = f)
74
+
75
+ if __name__ == "__main__":
76
+ parser = argparse.ArgumentParser(description = 'Generate static trampolines')
77
+ parser.add_argument('n', metavar = 'n', type = int, help = 'Number of trampolines')
78
+ args = parser.parse_args()
79
+
80
+ src_dir = os.path.dirname(__file__) + '/../src'
81
+
82
+ write_asm_trampolines(src_dir + '/abi_arm32_fwd.S', '#', args.n,
83
+ '.global Trampoline{0}',
84
+ '.global TrampolineX{0}',
85
+ 'Trampoline{0}:\n trampoline {0}',
86
+ 'TrampolineX{0}:\n trampoline_vec {0}'
87
+ )
88
+
89
+ write_asm_trampolines(src_dir + '/abi_arm64_fwd.asm', ';', args.n,
90
+ ' EXPORT Trampoline{0}',
91
+ ' EXPORT TrampolineX{0}',
92
+ 'Trampoline{0} PROC\n trampoline {0}\n ENDP',
93
+ 'TrampolineX{0} PROC\n trampoline_vec {0}\n ENDP',
94
+ ' END'
95
+ )
96
+ write_asm_trampolines(src_dir + '/abi_arm64_fwd.S', '#', args.n,
97
+ '.global SYMBOL(Trampoline{0})',
98
+ '.global SYMBOL(TrampolineX{0})',
99
+ 'SYMBOL(Trampoline{0}):\n trampoline {0}',
100
+ 'SYMBOL(TrampolineX{0}):\n trampoline_vec {0}'
101
+ )
102
+
103
+ write_asm_trampolines(src_dir + '/abi_riscv64_fwd.S', '#', args.n,
104
+ '.global Trampoline{0}',
105
+ '.global TrampolineX{0}',
106
+ 'Trampoline{0}:\n trampoline {0}',
107
+ 'TrampolineX{0}:\n trampoline_vec {0}'
108
+ )
109
+
110
+ write_asm_trampolines(src_dir + '/abi_x64_sysv_fwd.S', '#', args.n,
111
+ '.global SYMBOL(Trampoline{0})',
112
+ '.global SYMBOL(TrampolineX{0})',
113
+ 'SYMBOL(Trampoline{0}):\n trampoline {0}',
114
+ 'SYMBOL(TrampolineX{0}):\n trampoline_xmm {0}'
115
+ )
116
+ write_asm_trampolines(src_dir + '/abi_x64_win_fwd.asm', ';', args.n,
117
+ 'public Trampoline{0}',
118
+ 'public TrampolineX{0}',
119
+ 'Trampoline{0} proc frame\n trampoline {0}\nTrampoline{0} endp',
120
+ 'TrampolineX{0} proc frame\n trampoline_xmm {0}\nTrampolineX{0} endp',
121
+ 'end'
122
+ )
123
+
124
+ write_asm_trampolines(src_dir + '/abi_x86_fwd.asm', ';', args.n,
125
+ 'public Trampoline{0}',
126
+ 'public TrampolineX{0}',
127
+ 'Trampoline{0} proc\n trampoline {0}\nTrampoline{0} endp',
128
+ 'TrampolineX{0} proc\n trampoline_x87 {0}\nTrampolineX{0} endp',
129
+ 'end'
130
+ )
131
+ write_asm_trampolines(src_dir + '/abi_x86_fwd.S', '#', args.n,
132
+ '.global Trampoline{0}',
133
+ '.global TrampolineX{0}',
134
+ 'Trampoline{0}:\n trampoline {0}',
135
+ 'TrampolineX{0}:\n trampoline_x87 {0}'
136
+ )
137
+
138
+ write_cxx_trampolines(src_dir + '/abi_trampolines.inc', args.n)