koffi 2.16.1 → 3.0.0-alpha.2
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 +2 -2
- package/README.md +8 -8
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/musl_arm64/koffi.node +0 -0
- package/build/koffi/musl_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/doc/benchmarks.md +33 -33
- package/doc/benchmarks.xlsx +0 -0
- package/doc/contribute.md +37 -25
- package/doc/index.md +8 -8
- package/doc/variables.md +1 -1
- package/index.d.ts +11 -9
- package/index.js +1 -634
- package/indirect.js +1 -533
- package/lib/native/base/base.cc +63 -85
- package/lib/native/base/base.hh +178 -151
- package/package.json +3 -4
- package/src/build.js +1178 -0
- package/src/koffi/CMakeLists.txt +97 -34
- package/src/koffi/index.js +359 -0
- package/src/koffi/indirect.js +216 -0
- package/src/koffi/src/{abi_arm32.cc → abi/arm32.cc} +279 -275
- package/src/koffi/src/{abi_arm32_asm.S → abi/arm32_asm.S} +2 -5
- package/src/koffi/src/abi/arm64.cc +1511 -0
- package/src/koffi/src/{abi_arm64_asm.S → abi/arm64_asm.S} +44 -23
- package/src/koffi/src/{abi_arm64_asm.asm → abi/arm64_asm.asm} +32 -25
- package/src/koffi/src/{abi_loong64_asm.S → abi/loong64_asm.S} +1 -5
- package/src/koffi/src/{abi_riscv64.cc → abi/riscv64.cc} +279 -273
- package/src/koffi/src/{abi_riscv64_asm.S → abi/riscv64_asm.S} +1 -4
- package/src/koffi/src/abi/x64sysv.cc +1456 -0
- package/src/koffi/src/{abi_x64_sysv_asm.S → abi/x64sysv_asm.S} +30 -33
- package/src/koffi/src/abi/x64win.cc +1121 -0
- package/src/koffi/src/{abi_x64_win_asm.S → abi/x64win_asm.S} +8 -12
- package/src/koffi/src/{abi_x64_win_asm.asm → abi/x64win_asm.asm} +11 -14
- package/src/koffi/src/abi/x86.cc +1233 -0
- package/src/koffi/src/{abi_x86_asm.S → abi/x86_asm.S} +49 -25
- package/src/koffi/src/{abi_x86_asm.asm → abi/x86_asm.asm} +11 -14
- package/src/koffi/src/call.cc +458 -598
- package/src/koffi/src/call.hh +61 -82
- package/src/koffi/src/ffi.cc +595 -309
- package/src/koffi/src/ffi.hh +103 -89
- package/src/koffi/src/parser.cc +0 -4
- package/src/koffi/src/primitives.inc +39 -0
- package/src/koffi/{tools/write_trampolines.js → src/trampolines.js} +1 -1
- package/src/koffi/src/util.cc +503 -446
- package/src/koffi/src/util.hh +269 -57
- package/src/koffi/src/uv.cc +2 -2
- package/src/koffi/src/uv.def +3 -0
- package/src/koffi/src/win32.hh +30 -1
- package/vendor/node-addon-api/napi-inl.h +4 -0
- package/vendor/node-addon-api/napi.h +1 -0
- package/build/koffi/linux_armhf/koffi.node +0 -0
- package/build/koffi/linux_loong64/koffi.node +0 -0
- package/build/koffi/linux_riscv64d/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.exp +0 -0
- package/build/koffi/win32_arm64/koffi.lib +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/doc/platforms.md +0 -36
- package/src/cnoke/LICENSE.txt +0 -22
- package/src/cnoke/README.md +0 -99
- package/src/cnoke/assets/FindCNoke.cmake +0 -127
- package/src/cnoke/assets/toolchains.json +0 -126
- package/src/cnoke/assets/win_delay_hook.c +0 -36
- package/src/cnoke/cnoke.js +0 -170
- package/src/cnoke/package.json +0 -24
- package/src/cnoke/src/builder.js +0 -511
- package/src/cnoke/src/index.js +0 -10
- package/src/cnoke/src/tools.js +0 -407
- package/src/koffi/src/abi_arm64.cc +0 -1295
- package/src/koffi/src/abi_x64_sysv.cc +0 -939
- package/src/koffi/src/abi_x64_win.cc +0 -715
- package/src/koffi/src/abi_x86.cc +0 -860
- package/src/koffi/src/init.js +0 -105
- /package/src/koffi/src/{abi_loong64.cc → abi/loong64.cc} +0 -0
package/src/koffi/src/ffi.hh
CHANGED
|
@@ -22,66 +22,15 @@ static const Size MaxParameters = 64;
|
|
|
22
22
|
static const Size MaxTrampolines = 8192;
|
|
23
23
|
|
|
24
24
|
enum class PrimitiveKind {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Bool,
|
|
28
|
-
Void,
|
|
29
|
-
Int8,
|
|
30
|
-
UInt8,
|
|
31
|
-
Int16,
|
|
32
|
-
Int16S, // Keep behind Int16
|
|
33
|
-
UInt16,
|
|
34
|
-
UInt16S, // Keep behind UInt16
|
|
35
|
-
Int32,
|
|
36
|
-
Int32S, // Keep behind Int32
|
|
37
|
-
UInt32,
|
|
38
|
-
UInt32S, // Keep behind UInt32
|
|
39
|
-
Int64,
|
|
40
|
-
Int64S, // Keep behind Int64
|
|
41
|
-
UInt64,
|
|
42
|
-
UInt64S, // Keep behind UInt64
|
|
43
|
-
String,
|
|
44
|
-
String16,
|
|
45
|
-
String32,
|
|
46
|
-
Pointer,
|
|
47
|
-
Record,
|
|
48
|
-
Union,
|
|
49
|
-
Array,
|
|
50
|
-
Float32,
|
|
51
|
-
Float64,
|
|
52
|
-
Prototype,
|
|
53
|
-
Callback
|
|
25
|
+
#define PRIMITIVE(Name) Name,
|
|
26
|
+
#include "primitives.inc"
|
|
54
27
|
};
|
|
55
28
|
static const char *const PrimitiveKindNames[] = {
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
"Int8",
|
|
59
|
-
"UInt8",
|
|
60
|
-
"Int16",
|
|
61
|
-
"Int16S",
|
|
62
|
-
"UInt16",
|
|
63
|
-
"UInt16S",
|
|
64
|
-
"Int32",
|
|
65
|
-
"Int32S",
|
|
66
|
-
"UInt32",
|
|
67
|
-
"UInt32S",
|
|
68
|
-
"Int64",
|
|
69
|
-
"Int64S",
|
|
70
|
-
"UInt64",
|
|
71
|
-
"UInt64S",
|
|
72
|
-
"String",
|
|
73
|
-
"String16",
|
|
74
|
-
"String32",
|
|
75
|
-
"Pointer",
|
|
76
|
-
"Record",
|
|
77
|
-
"Union",
|
|
78
|
-
"Array",
|
|
79
|
-
"Float32",
|
|
80
|
-
"Float64",
|
|
81
|
-
"Prototype",
|
|
82
|
-
"Callback"
|
|
29
|
+
#define PRIMITIVE(Name) K_STRINGIFY(Name),
|
|
30
|
+
#include "primitives.inc"
|
|
83
31
|
};
|
|
84
32
|
|
|
33
|
+
struct InstanceData;
|
|
85
34
|
struct TypeInfo;
|
|
86
35
|
struct RecordMember;
|
|
87
36
|
struct FunctionInfo;
|
|
@@ -109,7 +58,7 @@ static const char *const ArrayHintNames[] = {
|
|
|
109
58
|
struct TypeInfo {
|
|
110
59
|
const char *name;
|
|
111
60
|
|
|
112
|
-
// Make sure
|
|
61
|
+
// Make sure primitive ends up as the upper N-API tag value when we cast TypeInfo pointers to
|
|
113
62
|
// napi_type_tag pointers. Yes, I want to do this. We don't do strict aliasing here.
|
|
114
63
|
// N.B. Some node versions don't like when one of the two tag values is 0, so make sure
|
|
115
64
|
// this does not happen! It would happen if primitive is 0 and size is 0. To avoid this
|
|
@@ -124,7 +73,6 @@ struct TypeInfo {
|
|
|
124
73
|
|
|
125
74
|
HeapArray<RecordMember> members; // Record only
|
|
126
75
|
union {
|
|
127
|
-
const void *marker;
|
|
128
76
|
const TypeInfo *type; // Pointer or array
|
|
129
77
|
const FunctionInfo *proto; // Callback only
|
|
130
78
|
} ref;
|
|
@@ -139,6 +87,7 @@ struct TypeInfo {
|
|
|
139
87
|
|
|
140
88
|
struct RecordMember {
|
|
141
89
|
const char *name;
|
|
90
|
+
napi_ref key;
|
|
142
91
|
const TypeInfo *type;
|
|
143
92
|
int32_t offset;
|
|
144
93
|
Size countedby;
|
|
@@ -170,6 +119,16 @@ static const char *const CallConventionNames[] = {
|
|
|
170
119
|
"Thiscall"
|
|
171
120
|
};
|
|
172
121
|
|
|
122
|
+
enum class AbiMethod : int;
|
|
123
|
+
|
|
124
|
+
struct AbiInstruction {
|
|
125
|
+
void *op;
|
|
126
|
+
int32_t a;
|
|
127
|
+
int16_t b1;
|
|
128
|
+
int16_t b2;
|
|
129
|
+
const TypeInfo *type;
|
|
130
|
+
};
|
|
131
|
+
|
|
173
132
|
struct ParameterInfo {
|
|
174
133
|
const TypeInfo *type;
|
|
175
134
|
int directions;
|
|
@@ -179,20 +138,47 @@ struct ParameterInfo {
|
|
|
179
138
|
// ABI-specific part
|
|
180
139
|
|
|
181
140
|
#if defined(_M_X64)
|
|
182
|
-
bool regular;
|
|
141
|
+
bool regular; // Used for structs and unions
|
|
183
142
|
#elif defined(__x86_64__)
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
143
|
+
struct {
|
|
144
|
+
bool regular;
|
|
145
|
+
int offsets[2];
|
|
146
|
+
} abi;
|
|
188
147
|
#elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM64)
|
|
189
|
-
|
|
148
|
+
struct {
|
|
149
|
+
bool regular;
|
|
150
|
+
bool indirect;
|
|
151
|
+
int hfa32;
|
|
152
|
+
int offset;
|
|
153
|
+
} abi;
|
|
154
|
+
#elif __riscv_xlen == 64 || defined(__loongarch64)
|
|
155
|
+
bool use_memory;
|
|
190
156
|
int8_t gpr_count;
|
|
191
157
|
int8_t vec_count;
|
|
192
|
-
|
|
158
|
+
bool gpr_first; // Only for structs
|
|
159
|
+
int8_t reg_size[2];
|
|
160
|
+
#endif
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
struct ReturnInfo {
|
|
164
|
+
const TypeInfo *type;
|
|
165
|
+
|
|
166
|
+
// ABI-specific part
|
|
167
|
+
|
|
168
|
+
#if defined(_M_X64)
|
|
169
|
+
bool regular;
|
|
170
|
+
#elif defined(__x86_64__)
|
|
171
|
+
struct {
|
|
172
|
+
AbiMethod method;
|
|
173
|
+
} abi;
|
|
174
|
+
#elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM64)
|
|
175
|
+
struct {
|
|
176
|
+
bool regular;
|
|
177
|
+
int hfa32;
|
|
178
|
+
int offset;
|
|
179
|
+
} abi;
|
|
193
180
|
#elif defined(__i386__) || defined(_M_IX86)
|
|
194
|
-
bool trivial;
|
|
195
|
-
int8_t fast;
|
|
181
|
+
bool trivial;
|
|
196
182
|
#elif __riscv_xlen == 64 || defined(__loongarch64)
|
|
197
183
|
bool use_memory;
|
|
198
184
|
int8_t gpr_count;
|
|
@@ -203,35 +189,42 @@ struct ParameterInfo {
|
|
|
203
189
|
};
|
|
204
190
|
|
|
205
191
|
struct ValueCast {
|
|
206
|
-
|
|
192
|
+
napi_env env;
|
|
193
|
+
napi_ref ref;
|
|
207
194
|
const TypeInfo *type;
|
|
195
|
+
|
|
196
|
+
~ValueCast();
|
|
208
197
|
};
|
|
209
198
|
|
|
210
199
|
// Also used for callbacks, even though many members are not used in this case
|
|
211
200
|
struct FunctionInfo {
|
|
212
201
|
mutable std::atomic_int refcount { 1 };
|
|
213
202
|
|
|
203
|
+
napi_env env;
|
|
204
|
+
InstanceData *instance;
|
|
205
|
+
const LibraryHolder *lib = nullptr;
|
|
206
|
+
|
|
214
207
|
const char *name;
|
|
215
208
|
const char *decorated_name; // Only set for some platforms/calling conventions
|
|
216
209
|
#if defined(_WIN32)
|
|
217
210
|
int ordinal_name = -1;
|
|
218
211
|
#endif
|
|
219
|
-
const LibraryHolder *lib = nullptr;
|
|
220
212
|
|
|
221
213
|
void *native;
|
|
222
214
|
CallConvention convention;
|
|
223
215
|
|
|
224
|
-
|
|
216
|
+
ReturnInfo ret;
|
|
225
217
|
HeapArray<ParameterInfo> parameters;
|
|
226
218
|
int8_t required_parameters;
|
|
227
|
-
int8_t out_parameters;
|
|
228
219
|
bool variadic;
|
|
229
220
|
|
|
230
221
|
// ABI-specific part
|
|
231
222
|
|
|
232
|
-
|
|
223
|
+
HeapArray<AbiInstruction> sync;
|
|
224
|
+
HeapArray<AbiInstruction> async;
|
|
225
|
+
Size stk_size;
|
|
233
226
|
#if defined(__i386__) || defined(_M_IX86)
|
|
234
|
-
|
|
227
|
+
int ret_pop;
|
|
235
228
|
#else
|
|
236
229
|
bool forward_fp;
|
|
237
230
|
#endif
|
|
@@ -242,28 +235,36 @@ struct FunctionInfo {
|
|
|
242
235
|
void Unref() const;
|
|
243
236
|
};
|
|
244
237
|
|
|
238
|
+
template <typename T>
|
|
239
|
+
struct MemoryRange {
|
|
240
|
+
T *ptr;
|
|
241
|
+
T *end;
|
|
242
|
+
};
|
|
243
|
+
|
|
245
244
|
struct InstanceMemory {
|
|
246
245
|
~InstanceMemory();
|
|
247
246
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
247
|
+
MemoryRange<uint8_t> stack;
|
|
248
|
+
MemoryRange<uint8_t> stack0;
|
|
249
|
+
MemoryRange<uint8_t> heap;
|
|
250
|
+
|
|
251
|
+
// For big heap allocations
|
|
252
|
+
LinkedAllocator allocator;
|
|
251
253
|
|
|
252
254
|
bool busy;
|
|
253
255
|
bool temporary;
|
|
254
|
-
int depth;
|
|
255
256
|
};
|
|
256
257
|
|
|
257
258
|
struct InstanceData {
|
|
258
259
|
~InstanceData();
|
|
259
260
|
|
|
261
|
+
napi_env env;
|
|
262
|
+
|
|
260
263
|
BucketArray<TypeInfo> types;
|
|
261
264
|
HashMap<const char *, const TypeInfo *> types_map;
|
|
262
265
|
BucketArray<FunctionInfo> callbacks;
|
|
263
266
|
Size base_types_count;
|
|
264
267
|
|
|
265
|
-
bool debug;
|
|
266
|
-
|
|
267
268
|
const TypeInfo *void_type;
|
|
268
269
|
const TypeInfo *char_type;
|
|
269
270
|
const TypeInfo *char16_type;
|
|
@@ -278,18 +279,23 @@ struct InstanceData {
|
|
|
278
279
|
LocalArray<InstanceMemory *, 17> memories;
|
|
279
280
|
int temporaries = 0;
|
|
280
281
|
|
|
282
|
+
// Variadic cache
|
|
283
|
+
FunctionInfo *variadic_func = nullptr;
|
|
284
|
+
|
|
285
|
+
napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
|
|
286
|
+
|
|
281
287
|
std::thread::id main_thread_id;
|
|
282
288
|
napi_threadsafe_function broker = nullptr;
|
|
283
289
|
|
|
290
|
+
CallData *sync_call = nullptr;
|
|
291
|
+
|
|
284
292
|
#if defined(_WIN32)
|
|
285
293
|
void *main_stack_max;
|
|
286
294
|
void *main_stack_min;
|
|
287
|
-
|
|
288
|
-
uint32_t last_error = 0;
|
|
289
295
|
#endif
|
|
290
296
|
|
|
291
|
-
BucketArray<
|
|
292
|
-
HashMap<void *,
|
|
297
|
+
BucketArray<LinkedAllocator> encode_allocators;
|
|
298
|
+
HashMap<void *, LinkedAllocator *> encode_map;
|
|
293
299
|
|
|
294
300
|
HashMap<void *, int16_t> trampolines_map;
|
|
295
301
|
|
|
@@ -303,6 +309,9 @@ struct InstanceData {
|
|
|
303
309
|
int resident_async_pools = DefaultResidentAsyncPools;
|
|
304
310
|
int max_temporaries = DefaultMaxAsyncCalls - DefaultResidentAsyncPools;
|
|
305
311
|
Size max_type_size = DefaultMaxTypeSize;
|
|
312
|
+
|
|
313
|
+
bool fast_pointers = true;
|
|
314
|
+
bool fast_callbacks = true;
|
|
306
315
|
} config;
|
|
307
316
|
|
|
308
317
|
struct {
|
|
@@ -314,13 +323,12 @@ static_assert(DefaultMaxAsyncCalls >= DefaultResidentAsyncPools);
|
|
|
314
323
|
static_assert(MaxAsyncCalls >= DefaultMaxAsyncCalls);
|
|
315
324
|
|
|
316
325
|
struct TrampolineInfo {
|
|
317
|
-
|
|
326
|
+
int state;
|
|
318
327
|
|
|
328
|
+
InstanceData *instance;
|
|
319
329
|
const FunctionInfo *proto;
|
|
320
330
|
Napi::FunctionReference func;
|
|
321
331
|
Napi::Reference<Napi::Value> recv;
|
|
322
|
-
|
|
323
|
-
bool used;
|
|
324
332
|
};
|
|
325
333
|
|
|
326
334
|
struct SharedData {
|
|
@@ -342,12 +350,18 @@ static_assert(MaxTrampolines <= INT16_MAX);
|
|
|
342
350
|
|
|
343
351
|
extern SharedData shared;
|
|
344
352
|
|
|
353
|
+
// Recent N-API functions are loaded dynamically
|
|
354
|
+
extern napi_status (NAPI_CDECL *node_api_create_property_key_utf8)(napi_env env, const char* str, size_t length, napi_value* result);
|
|
355
|
+
extern napi_status (NAPI_CDECL *node_api_post_finalizer)(node_api_basic_env env, napi_finalize finalize_cb, void* finalize_data, void* finalize_hint);
|
|
356
|
+
extern napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
|
|
357
|
+
|
|
345
358
|
InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size);
|
|
346
359
|
void ReleaseMemory(InstanceData *instance, InstanceMemory *mem);
|
|
347
360
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
361
|
+
napi_value TranslateFastCall(napi_env env, napi_callback_info info);
|
|
362
|
+
napi_value TranslateNormalCall(napi_env env, napi_callback_info info);
|
|
363
|
+
napi_value TranslateVariadicCall(napi_env env, napi_callback_info info);
|
|
364
|
+
napi_value TranslateAsyncCall(napi_env env, napi_callback_info info);
|
|
351
365
|
|
|
352
366
|
bool InitAsyncBroker(Napi::Env env, InstanceData *instance);
|
|
353
367
|
|
package/src/koffi/src/parser.cc
CHANGED
|
@@ -60,10 +60,6 @@ bool PrototypeParser::Parse(const char *str, bool concrete, FunctionInfo *out_fu
|
|
|
60
60
|
MarkError("Functions cannot have more than %1 parameters", MaxParameters);
|
|
61
61
|
return false;
|
|
62
62
|
}
|
|
63
|
-
if ((param.directions & 2) && ++out_func->out_parameters >= MaxParameters) {
|
|
64
|
-
MarkError("Functions cannot have more than out %1 parameters", MaxParameters);
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
63
|
|
|
68
64
|
param.offset = (int8_t)out_func->parameters.len;
|
|
69
65
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
|
|
3
|
+
|
|
4
|
+
#if !defined(PRIMITIVE)
|
|
5
|
+
#error Please define PRIMITIVE() before including primitives.inc
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
// Void is explictly not first so that it is not 0, for reasons related to N-API type tags.
|
|
9
|
+
// Look at TypeInfo definition for more information!
|
|
10
|
+
|
|
11
|
+
PRIMITIVE(Bool)
|
|
12
|
+
PRIMITIVE(Void)
|
|
13
|
+
PRIMITIVE(Int8)
|
|
14
|
+
PRIMITIVE(UInt8)
|
|
15
|
+
PRIMITIVE(Int16)
|
|
16
|
+
PRIMITIVE(Int16S) // Keep behind Int16
|
|
17
|
+
PRIMITIVE(UInt16)
|
|
18
|
+
PRIMITIVE(UInt16S) // Keep behind UInt16
|
|
19
|
+
PRIMITIVE(Int32)
|
|
20
|
+
PRIMITIVE(Int32S) // Keep behind Int32
|
|
21
|
+
PRIMITIVE(UInt32)
|
|
22
|
+
PRIMITIVE(UInt32S) // Keep behind UInt32
|
|
23
|
+
PRIMITIVE(Int64)
|
|
24
|
+
PRIMITIVE(Int64S) // Keep behind Int64
|
|
25
|
+
PRIMITIVE(UInt64)
|
|
26
|
+
PRIMITIVE(UInt64S) // Keep behind UInt64
|
|
27
|
+
PRIMITIVE(String)
|
|
28
|
+
PRIMITIVE(String16)
|
|
29
|
+
PRIMITIVE(String32)
|
|
30
|
+
PRIMITIVE(Pointer)
|
|
31
|
+
PRIMITIVE(Record)
|
|
32
|
+
PRIMITIVE(Union)
|
|
33
|
+
PRIMITIVE(Array)
|
|
34
|
+
PRIMITIVE(Float32)
|
|
35
|
+
PRIMITIVE(Float64)
|
|
36
|
+
PRIMITIVE(Callback)
|
|
37
|
+
PRIMITIVE(Prototype)
|
|
38
|
+
|
|
39
|
+
#undef PRIMITIVE
|
|
@@ -20,7 +20,7 @@ function run() {
|
|
|
20
20
|
let args = process.argv.slice(2);
|
|
21
21
|
|
|
22
22
|
if (args.length < 2)
|
|
23
|
-
throw new Error('Usage:
|
|
23
|
+
throw new Error('Usage: trampolines.js DIRECTORY N');
|
|
24
24
|
|
|
25
25
|
let dest_dir = args[0]?.trim?.();
|
|
26
26
|
let n = parseInt(args[1], 10);
|