koffi 1.0.3 → 1.0.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.
- package/README.md +22 -21
- package/build/qemu/1.0.4/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.0.4/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.0.4/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.0.4/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.0.4/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.0.4/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.0.4/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.0.4/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.0.4/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.0.4/koffi_win32_x64.tar.gz +0 -0
- package/package.json +1 -1
- package/src/abi_arm32.cc +119 -211
- package/src/abi_arm64.cc +92 -113
- package/src/abi_x64_sysv.cc +106 -131
- package/src/abi_x64_win.cc +78 -94
- package/src/abi_x86.cc +80 -95
- package/src/call.cc +144 -19
- package/src/call.hh +39 -3
- package/src/ffi.cc +11 -2
- package/src/ffi.hh +6 -12
- package/src/util.cc +0 -127
- package/src/util.hh +0 -16
- package/test/misc.c +66 -0
- package/test/misc.js +47 -0
- package/vendor/libcc/libcc.hh +1 -1
- package/build/qemu/1.0.3/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.0.3/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.0.3/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.0.3/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.0.3/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.0.3/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.0.3/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.0.3/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.0.3/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.0.3/koffi_win32_x64.tar.gz +0 -0
package/src/abi_x64_sysv.cc
CHANGED
|
@@ -181,34 +181,25 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
181
181
|
return true;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
185
185
|
{
|
|
186
|
-
// Sanity checks
|
|
187
|
-
if (info.Length() < (uint32_t)func->parameters.len) {
|
|
188
|
-
ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
|
|
189
|
-
return env.Null();
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
uint8_t *return_ptr = nullptr;
|
|
193
186
|
uint8_t *args_ptr = nullptr;
|
|
194
187
|
uint64_t *gpr_ptr = nullptr;
|
|
195
188
|
uint64_t *xmm_ptr = nullptr;
|
|
196
189
|
|
|
197
190
|
// Return through registers unless it's too big
|
|
198
191
|
if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
|
|
199
|
-
return
|
|
192
|
+
return false;
|
|
200
193
|
if (RG_UNLIKELY(!AllocStack(8 * 8, 8, &xmm_ptr)))
|
|
201
|
-
return
|
|
194
|
+
return false;
|
|
202
195
|
if (RG_UNLIKELY(!AllocStack(6 * 8, 8, &gpr_ptr)))
|
|
203
|
-
return
|
|
196
|
+
return false;
|
|
204
197
|
if (func->ret.use_memory) {
|
|
205
198
|
if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
|
|
206
|
-
return
|
|
199
|
+
return false;
|
|
207
200
|
*(uint8_t **)(gpr_ptr++) = return_ptr;
|
|
208
201
|
}
|
|
209
202
|
|
|
210
|
-
LocalArray<OutObject, MaxOutParameters> out_objects;
|
|
211
|
-
|
|
212
203
|
// Push arguments
|
|
213
204
|
for (Size i = 0; i < func->parameters.len; i++) {
|
|
214
205
|
const ParameterInfo ¶m = func->parameters[i];
|
|
@@ -222,7 +213,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
222
213
|
case PrimitiveKind::Bool: {
|
|
223
214
|
if (RG_UNLIKELY(!value.IsBoolean())) {
|
|
224
215
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argmument %2, expected boolean", GetValueType(instance, value), i + 1);
|
|
225
|
-
return
|
|
216
|
+
return false;
|
|
226
217
|
}
|
|
227
218
|
|
|
228
219
|
bool b = value.As<Napi::Boolean>();
|
|
@@ -244,7 +235,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
244
235
|
case PrimitiveKind::UInt64: {
|
|
245
236
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
246
237
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
247
|
-
return
|
|
238
|
+
return false;
|
|
248
239
|
}
|
|
249
240
|
|
|
250
241
|
int64_t v = CopyNumber<int64_t>(value);
|
|
@@ -257,49 +248,17 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
257
248
|
args_ptr += 8;
|
|
258
249
|
}
|
|
259
250
|
} break;
|
|
260
|
-
case PrimitiveKind::Float32: {
|
|
261
|
-
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
262
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
263
|
-
return env.Null();
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
float f = CopyNumber<float>(value);
|
|
267
|
-
|
|
268
|
-
if (RG_LIKELY(param.xmm_count)) {
|
|
269
|
-
memcpy(xmm_ptr++, &f, 4);
|
|
270
|
-
} else {
|
|
271
|
-
args_ptr = AlignUp(args_ptr, 4);
|
|
272
|
-
memcpy(args_ptr, &f, 4);
|
|
273
|
-
args_ptr += 8;
|
|
274
|
-
}
|
|
275
|
-
} break;
|
|
276
|
-
case PrimitiveKind::Float64: {
|
|
277
|
-
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
278
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
279
|
-
return env.Null();
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
double d = CopyNumber<double>(value);
|
|
283
|
-
|
|
284
|
-
if (RG_LIKELY(param.xmm_count)) {
|
|
285
|
-
memcpy(xmm_ptr++, &d, 8);
|
|
286
|
-
} else {
|
|
287
|
-
args_ptr = AlignUp(args_ptr, 8);
|
|
288
|
-
memcpy(args_ptr, &d, 8);
|
|
289
|
-
args_ptr += 8;
|
|
290
|
-
}
|
|
291
|
-
} break;
|
|
292
251
|
case PrimitiveKind::String: {
|
|
293
252
|
const char *str;
|
|
294
253
|
if (RG_LIKELY(value.IsString())) {
|
|
295
254
|
str = PushString(value);
|
|
296
255
|
if (RG_UNLIKELY(!str))
|
|
297
|
-
return
|
|
256
|
+
return false;
|
|
298
257
|
} else if (IsNullOrUndefined(value)) {
|
|
299
258
|
str = nullptr;
|
|
300
259
|
} else {
|
|
301
260
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
|
|
302
|
-
return
|
|
261
|
+
return false;
|
|
303
262
|
}
|
|
304
263
|
|
|
305
264
|
if (RG_LIKELY(param.gpr_count)) {
|
|
@@ -315,12 +274,12 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
315
274
|
if (RG_LIKELY(value.IsString())) {
|
|
316
275
|
str16 = PushString16(value);
|
|
317
276
|
if (RG_UNLIKELY(!str16))
|
|
318
|
-
return
|
|
277
|
+
return false;
|
|
319
278
|
} else if (IsNullOrUndefined(value)) {
|
|
320
279
|
str16 = nullptr;
|
|
321
280
|
} else {
|
|
322
281
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
|
|
323
|
-
return
|
|
282
|
+
return false;
|
|
324
283
|
}
|
|
325
284
|
|
|
326
285
|
if (RG_LIKELY(param.gpr_count)) {
|
|
@@ -340,11 +299,11 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
340
299
|
Napi::Object obj = value.As<Napi::Object>();
|
|
341
300
|
|
|
342
301
|
if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
|
|
343
|
-
return
|
|
302
|
+
return false;
|
|
344
303
|
|
|
345
304
|
if (param.directions & 1) {
|
|
346
305
|
if (!PushObject(obj, param.type->ref, ptr))
|
|
347
|
-
return
|
|
306
|
+
return false;
|
|
348
307
|
} else {
|
|
349
308
|
memset(ptr, 0, param.type->size);
|
|
350
309
|
}
|
|
@@ -356,7 +315,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
356
315
|
ptr = nullptr;
|
|
357
316
|
} else {
|
|
358
317
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
|
|
359
|
-
return
|
|
318
|
+
return false;
|
|
360
319
|
}
|
|
361
320
|
|
|
362
321
|
if (RG_LIKELY(param.gpr_count)) {
|
|
@@ -367,11 +326,10 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
367
326
|
args_ptr += 8;
|
|
368
327
|
}
|
|
369
328
|
} break;
|
|
370
|
-
|
|
371
329
|
case PrimitiveKind::Record: {
|
|
372
330
|
if (RG_UNLIKELY(!IsObject(value))) {
|
|
373
331
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected object", GetValueType(instance, value), i + 1);
|
|
374
|
-
return
|
|
332
|
+
return false;
|
|
375
333
|
}
|
|
376
334
|
|
|
377
335
|
Napi::Object obj = value.As<Napi::Object>();
|
|
@@ -381,7 +339,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
381
339
|
|
|
382
340
|
uint64_t buf[2] = {};
|
|
383
341
|
if (!PushObject(obj, param.type, (uint8_t *)buf))
|
|
384
|
-
return
|
|
342
|
+
return false;
|
|
385
343
|
|
|
386
344
|
if (param.gpr_first) {
|
|
387
345
|
uint64_t *ptr = buf;
|
|
@@ -405,112 +363,129 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
405
363
|
} else if (param.use_memory) {
|
|
406
364
|
args_ptr = AlignUp(args_ptr, param.type->align);
|
|
407
365
|
if (!PushObject(obj, param.type, args_ptr))
|
|
408
|
-
return
|
|
366
|
+
return false;
|
|
409
367
|
args_ptr += AlignLen(param.type->size, 8);
|
|
410
368
|
}
|
|
411
369
|
} break;
|
|
370
|
+
case PrimitiveKind::Float32: {
|
|
371
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
372
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
float f = CopyNumber<float>(value);
|
|
377
|
+
|
|
378
|
+
if (RG_LIKELY(param.xmm_count)) {
|
|
379
|
+
memcpy(xmm_ptr++, &f, 4);
|
|
380
|
+
} else {
|
|
381
|
+
args_ptr = AlignUp(args_ptr, 4);
|
|
382
|
+
memcpy(args_ptr, &f, 4);
|
|
383
|
+
args_ptr += 8;
|
|
384
|
+
}
|
|
385
|
+
} break;
|
|
386
|
+
case PrimitiveKind::Float64: {
|
|
387
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
388
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
double d = CopyNumber<double>(value);
|
|
393
|
+
|
|
394
|
+
if (RG_LIKELY(param.xmm_count)) {
|
|
395
|
+
memcpy(xmm_ptr++, &d, 8);
|
|
396
|
+
} else {
|
|
397
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
398
|
+
memcpy(args_ptr, &d, 8);
|
|
399
|
+
args_ptr += 8;
|
|
400
|
+
}
|
|
401
|
+
} break;
|
|
412
402
|
}
|
|
413
403
|
}
|
|
414
404
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
418
407
|
|
|
408
|
+
void CallData::Execute()
|
|
409
|
+
{
|
|
419
410
|
#define PERFORM_CALL(Suffix) \
|
|
420
411
|
([&]() { \
|
|
421
412
|
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, GetSP()) \
|
|
422
413
|
: ForwardCall ## Suffix(func->func, GetSP())); \
|
|
423
|
-
PopOutArguments(out_objects); \
|
|
424
414
|
return ret; \
|
|
425
415
|
})()
|
|
426
416
|
|
|
427
417
|
// Execute and convert return value
|
|
428
418
|
switch (func->ret.type->primitive) {
|
|
429
|
-
case PrimitiveKind::Void:
|
|
430
|
-
|
|
431
|
-
return env.Null();
|
|
432
|
-
} break;
|
|
433
|
-
case PrimitiveKind::Bool: {
|
|
434
|
-
RaxRdxRet ret = PERFORM_CALL(GG);
|
|
435
|
-
return Napi::Boolean::New(env, ret.rax);
|
|
436
|
-
} break;
|
|
419
|
+
case PrimitiveKind::Void:
|
|
420
|
+
case PrimitiveKind::Bool:
|
|
437
421
|
case PrimitiveKind::Int8:
|
|
438
422
|
case PrimitiveKind::UInt8:
|
|
439
423
|
case PrimitiveKind::Int16:
|
|
440
424
|
case PrimitiveKind::UInt16:
|
|
441
425
|
case PrimitiveKind::Int32:
|
|
442
|
-
case PrimitiveKind::UInt32:
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
case PrimitiveKind::
|
|
447
|
-
|
|
448
|
-
return Napi::BigInt::New(env, (int64_t)ret.rax);
|
|
449
|
-
} break;
|
|
450
|
-
case PrimitiveKind::UInt64: {
|
|
451
|
-
RaxRdxRet ret = PERFORM_CALL(GG);
|
|
452
|
-
return Napi::BigInt::New(env, ret.rax);
|
|
453
|
-
} break;
|
|
454
|
-
case PrimitiveKind::Float32: {
|
|
455
|
-
float f = PERFORM_CALL(F);
|
|
456
|
-
return Napi::Number::New(env, (double)f);
|
|
457
|
-
} break;
|
|
458
|
-
case PrimitiveKind::Float64: {
|
|
459
|
-
Xmm0RaxRet ret = PERFORM_CALL(DG);
|
|
460
|
-
return Napi::Number::New(env, ret.xmm0);
|
|
461
|
-
} break;
|
|
462
|
-
case PrimitiveKind::String: {
|
|
463
|
-
RaxRdxRet ret = PERFORM_CALL(GG);
|
|
464
|
-
return Napi::String::New(env, (const char *)ret.rax);
|
|
465
|
-
} break;
|
|
466
|
-
case PrimitiveKind::String16: {
|
|
467
|
-
RaxRdxRet ret = PERFORM_CALL(GG);
|
|
468
|
-
return Napi::String::New(env, (const char16_t *)ret.rax);
|
|
469
|
-
} break;
|
|
470
|
-
case PrimitiveKind::Pointer: {
|
|
471
|
-
RaxRdxRet ret = PERFORM_CALL(GG);
|
|
472
|
-
void *ptr = (void *)ret.rax;
|
|
473
|
-
|
|
474
|
-
Napi::External<void> external = Napi::External<void>::New(env, ptr);
|
|
475
|
-
SetValueTag(instance, external, func->ret.type);
|
|
476
|
-
|
|
477
|
-
return external;
|
|
478
|
-
} break;
|
|
479
|
-
|
|
426
|
+
case PrimitiveKind::UInt32:
|
|
427
|
+
case PrimitiveKind::Int64:
|
|
428
|
+
case PrimitiveKind::UInt64:
|
|
429
|
+
case PrimitiveKind::String:
|
|
430
|
+
case PrimitiveKind::String16:
|
|
431
|
+
case PrimitiveKind::Pointer: { result.u64 = PERFORM_CALL(GG).rax; } break;
|
|
480
432
|
case PrimitiveKind::Record: {
|
|
481
433
|
if (func->ret.gpr_first && !func->ret.xmm_count) {
|
|
482
434
|
RaxRdxRet ret = PERFORM_CALL(GG);
|
|
483
|
-
|
|
484
|
-
Napi::Object obj = PopObject(env, (const uint8_t *)&ret, func->ret.type);
|
|
485
|
-
return obj;
|
|
435
|
+
memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
|
|
486
436
|
} else if (func->ret.gpr_first) {
|
|
487
437
|
RaxXmm0Ret ret = PERFORM_CALL(GD);
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
438
|
+
memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
|
|
439
|
+
} else if (func->ret.xmm_count == 2) {
|
|
440
|
+
Xmm0Xmm1Ret ret = PERFORM_CALL(DD);
|
|
441
|
+
memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
|
|
442
|
+
} else {
|
|
492
443
|
Xmm0RaxRet ret = PERFORM_CALL(DG);
|
|
444
|
+
memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
|
|
445
|
+
}
|
|
446
|
+
} break;
|
|
447
|
+
case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
|
|
448
|
+
case PrimitiveKind::Float64: { result.d = PERFORM_CALL(DG).xmm0; } break;
|
|
449
|
+
}
|
|
493
450
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
} else if (func->ret.type->size) {
|
|
497
|
-
RG_ASSERT(return_ptr);
|
|
451
|
+
#undef PERFORM_CALL
|
|
452
|
+
}
|
|
498
453
|
|
|
499
|
-
|
|
500
|
-
|
|
454
|
+
Napi::Value CallData::Complete()
|
|
455
|
+
{
|
|
456
|
+
for (const OutObject &obj: out_objects) {
|
|
457
|
+
PopObject(obj.obj, obj.ptr, obj.type);
|
|
458
|
+
}
|
|
501
459
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
460
|
+
switch (func->ret.type->primitive) {
|
|
461
|
+
case PrimitiveKind::Void: return env.Null();
|
|
462
|
+
case PrimitiveKind::Bool: return Napi::Boolean::New(env, result.u32);
|
|
463
|
+
case PrimitiveKind::Int8:
|
|
464
|
+
case PrimitiveKind::UInt8:
|
|
465
|
+
case PrimitiveKind::Int16:
|
|
466
|
+
case PrimitiveKind::UInt16:
|
|
467
|
+
case PrimitiveKind::Int32:
|
|
468
|
+
case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)result.u32);
|
|
469
|
+
case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)result.u64);
|
|
470
|
+
case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
|
|
471
|
+
case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
|
|
472
|
+
case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
|
|
473
|
+
case PrimitiveKind::Pointer: {
|
|
474
|
+
Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
|
|
475
|
+
SetValueTag(instance, external, func->ret.type);
|
|
506
476
|
|
|
507
|
-
|
|
508
|
-
return obj;
|
|
509
|
-
}
|
|
477
|
+
return external;
|
|
510
478
|
} break;
|
|
511
|
-
|
|
479
|
+
case PrimitiveKind::Record: {
|
|
480
|
+
const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
|
|
481
|
+
: (const uint8_t *)&result.buf;
|
|
512
482
|
|
|
513
|
-
|
|
483
|
+
Napi::Object obj = PopObject(ptr, func->ret.type);
|
|
484
|
+
return obj;
|
|
485
|
+
} break;
|
|
486
|
+
case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
|
|
487
|
+
case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
|
|
488
|
+
}
|
|
514
489
|
|
|
515
490
|
RG_UNREACHABLE();
|
|
516
491
|
}
|
package/src/abi_x64_win.cc
CHANGED
|
@@ -51,28 +51,19 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
51
51
|
return true;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
55
55
|
{
|
|
56
|
-
// Sanity checks
|
|
57
|
-
if (info.Length() < (uint32_t)func->parameters.len) {
|
|
58
|
-
ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
|
|
59
|
-
return env.Null();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
uint8_t *return_ptr = nullptr;
|
|
63
56
|
uint64_t *args_ptr = nullptr;
|
|
64
57
|
|
|
65
58
|
// Pass return value in register or through memory
|
|
66
59
|
if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
|
|
67
|
-
return
|
|
60
|
+
return false;
|
|
68
61
|
if (!func->ret.regular) {
|
|
69
62
|
if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
|
|
70
|
-
return
|
|
63
|
+
return false;
|
|
71
64
|
*(uint8_t **)(args_ptr++) = return_ptr;
|
|
72
65
|
}
|
|
73
66
|
|
|
74
|
-
LocalArray<OutObject, MaxOutParameters> out_objects;
|
|
75
|
-
|
|
76
67
|
// Push arguments
|
|
77
68
|
for (Size i = 0; i < func->parameters.len; i++) {
|
|
78
69
|
const ParameterInfo ¶m = func->parameters[i];
|
|
@@ -86,7 +77,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
86
77
|
case PrimitiveKind::Bool: {
|
|
87
78
|
if (RG_UNLIKELY(!value.IsBoolean())) {
|
|
88
79
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected boolean", GetValueType(instance, value), i + 1);
|
|
89
|
-
return
|
|
80
|
+
return false;
|
|
90
81
|
}
|
|
91
82
|
|
|
92
83
|
bool b = value.As<Napi::Boolean>();
|
|
@@ -103,41 +94,23 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
103
94
|
case PrimitiveKind::UInt64: {
|
|
104
95
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
105
96
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
106
|
-
return
|
|
97
|
+
return false;
|
|
107
98
|
}
|
|
108
99
|
|
|
109
100
|
int64_t v = CopyNumber<int64_t>(value);
|
|
110
101
|
*(args_ptr++) = (uint64_t)v;
|
|
111
102
|
} break;
|
|
112
|
-
case PrimitiveKind::Float32: {
|
|
113
|
-
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
114
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
115
|
-
return env.Null();
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
float f = CopyNumber<float>(value);
|
|
119
|
-
*(float *)(args_ptr++) = f;
|
|
120
|
-
} break;
|
|
121
|
-
case PrimitiveKind::Float64: {
|
|
122
|
-
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
123
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
124
|
-
return env.Null();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
double d = CopyNumber<double>(value);
|
|
128
|
-
*(double *)(args_ptr++) = d;
|
|
129
|
-
} break;
|
|
130
103
|
case PrimitiveKind::String: {
|
|
131
104
|
const char *str;
|
|
132
105
|
if (RG_LIKELY(value.IsString())) {
|
|
133
106
|
str = PushString(value);
|
|
134
107
|
if (RG_UNLIKELY(!str))
|
|
135
|
-
return
|
|
108
|
+
return false;
|
|
136
109
|
} else if (IsNullOrUndefined(value)) {
|
|
137
110
|
str = nullptr;
|
|
138
111
|
} else {
|
|
139
112
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
|
|
140
|
-
return
|
|
113
|
+
return false;
|
|
141
114
|
}
|
|
142
115
|
|
|
143
116
|
*(const char **)(args_ptr++) = str;
|
|
@@ -147,12 +120,12 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
147
120
|
if (RG_LIKELY(value.IsString())) {
|
|
148
121
|
str16 = PushString16(value);
|
|
149
122
|
if (RG_UNLIKELY(!str16))
|
|
150
|
-
return
|
|
123
|
+
return false;
|
|
151
124
|
} else if (IsNullOrUndefined(value)) {
|
|
152
125
|
str16 = nullptr;
|
|
153
126
|
} else {
|
|
154
127
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
|
|
155
|
-
return
|
|
128
|
+
return false;
|
|
156
129
|
}
|
|
157
130
|
|
|
158
131
|
*(const char16_t **)(args_ptr++) = str16;
|
|
@@ -166,11 +139,11 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
166
139
|
Napi::Object obj = value.As<Napi::Object>();
|
|
167
140
|
|
|
168
141
|
if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
|
|
169
|
-
return
|
|
142
|
+
return false;
|
|
170
143
|
|
|
171
144
|
if (param.directions & 1) {
|
|
172
145
|
if (!PushObject(obj, param.type->ref, ptr))
|
|
173
|
-
return
|
|
146
|
+
return false;
|
|
174
147
|
} else {
|
|
175
148
|
memset(ptr, 0, param.type->size);
|
|
176
149
|
}
|
|
@@ -182,16 +155,15 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
182
155
|
ptr = nullptr;
|
|
183
156
|
} else {
|
|
184
157
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
|
|
185
|
-
return
|
|
158
|
+
return false;
|
|
186
159
|
}
|
|
187
160
|
|
|
188
161
|
*(uint8_t **)(args_ptr++) = ptr;
|
|
189
162
|
} break;
|
|
190
|
-
|
|
191
163
|
case PrimitiveKind::Record: {
|
|
192
164
|
if (RG_UNLIKELY(!IsObject(value))) {
|
|
193
165
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected object", GetValueType(instance, value), i + 1);
|
|
194
|
-
return
|
|
166
|
+
return false;
|
|
195
167
|
}
|
|
196
168
|
|
|
197
169
|
uint8_t *ptr;
|
|
@@ -199,93 +171,105 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
|
|
|
199
171
|
ptr = (uint8_t *)(args_ptr++);
|
|
200
172
|
} else {
|
|
201
173
|
if (RG_UNLIKELY(!AllocHeap(param.type->size, 16, &ptr)))
|
|
202
|
-
return
|
|
174
|
+
return false;
|
|
203
175
|
*(uint8_t **)(args_ptr++) = ptr;
|
|
204
176
|
}
|
|
205
177
|
|
|
206
178
|
Napi::Object obj = value.As<Napi::Object>();
|
|
207
179
|
if (!PushObject(obj, param.type, ptr))
|
|
208
|
-
return
|
|
180
|
+
return false;
|
|
181
|
+
} break;
|
|
182
|
+
case PrimitiveKind::Float32: {
|
|
183
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
184
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
float f = CopyNumber<float>(value);
|
|
189
|
+
*(float *)(args_ptr++) = f;
|
|
190
|
+
} break;
|
|
191
|
+
case PrimitiveKind::Float64: {
|
|
192
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
193
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
double d = CopyNumber<double>(value);
|
|
198
|
+
*(double *)(args_ptr++) = d;
|
|
209
199
|
} break;
|
|
210
200
|
}
|
|
211
201
|
}
|
|
212
202
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
216
205
|
|
|
206
|
+
void CallData::Execute()
|
|
207
|
+
{
|
|
217
208
|
#define PERFORM_CALL(Suffix) \
|
|
218
209
|
([&]() { \
|
|
219
210
|
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, GetSP()) \
|
|
220
211
|
: ForwardCall ## Suffix(func->func, GetSP())); \
|
|
221
|
-
PopOutArguments(out_objects); \
|
|
222
212
|
return ret; \
|
|
223
213
|
})()
|
|
224
214
|
|
|
225
|
-
// Execute and convert return value
|
|
226
215
|
switch (func->ret.type->primitive) {
|
|
227
|
-
case PrimitiveKind::Void:
|
|
228
|
-
|
|
229
|
-
return env.Null();
|
|
230
|
-
} break;
|
|
231
|
-
case PrimitiveKind::Bool: {
|
|
232
|
-
uint64_t rax = PERFORM_CALL(G);
|
|
233
|
-
return Napi::Boolean::New(env, rax);
|
|
234
|
-
} break;
|
|
216
|
+
case PrimitiveKind::Void:
|
|
217
|
+
case PrimitiveKind::Bool:
|
|
235
218
|
case PrimitiveKind::Int8:
|
|
236
219
|
case PrimitiveKind::UInt8:
|
|
237
220
|
case PrimitiveKind::Int16:
|
|
238
221
|
case PrimitiveKind::UInt16:
|
|
239
222
|
case PrimitiveKind::Int32:
|
|
240
|
-
case PrimitiveKind::UInt32:
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
case PrimitiveKind::
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
} break;
|
|
248
|
-
case PrimitiveKind::
|
|
249
|
-
|
|
250
|
-
return Napi::BigInt::New(env, rax);
|
|
251
|
-
} break;
|
|
252
|
-
case PrimitiveKind::Float32: {
|
|
253
|
-
float f = PERFORM_CALL(F);
|
|
254
|
-
return Napi::Number::New(env, (double)f);
|
|
255
|
-
} break;
|
|
256
|
-
case PrimitiveKind::Float64: {
|
|
257
|
-
double d = PERFORM_CALL(D);
|
|
258
|
-
return Napi::Number::New(env, d);
|
|
259
|
-
} break;
|
|
260
|
-
case PrimitiveKind::String: {
|
|
261
|
-
uint64_t rax = PERFORM_CALL(G);
|
|
262
|
-
return Napi::String::New(env, (const char *)rax);
|
|
263
|
-
} break;
|
|
264
|
-
case PrimitiveKind::String16: {
|
|
265
|
-
uint64_t rax = PERFORM_CALL(G);
|
|
266
|
-
return Napi::String::New(env, (const char16_t *)rax);
|
|
267
|
-
} break;
|
|
268
|
-
case PrimitiveKind::Pointer: {
|
|
269
|
-
uint64_t rax = PERFORM_CALL(G);
|
|
270
|
-
void *ptr = (void *)rax;
|
|
223
|
+
case PrimitiveKind::UInt32:
|
|
224
|
+
case PrimitiveKind::Int64:
|
|
225
|
+
case PrimitiveKind::UInt64:
|
|
226
|
+
case PrimitiveKind::String:
|
|
227
|
+
case PrimitiveKind::String16:
|
|
228
|
+
case PrimitiveKind::Pointer:
|
|
229
|
+
case PrimitiveKind::Record: { result.u64 = PERFORM_CALL(G); } break;
|
|
230
|
+
case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
|
|
231
|
+
case PrimitiveKind::Float64: { result.d = PERFORM_CALL(D); } break;
|
|
232
|
+
}
|
|
271
233
|
|
|
272
|
-
|
|
234
|
+
#undef PERFORM_CALL
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
Napi::Value CallData::Complete()
|
|
238
|
+
{
|
|
239
|
+
for (const OutObject &obj: out_objects) {
|
|
240
|
+
PopObject(obj.obj, obj.ptr, obj.type);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
switch (func->ret.type->primitive) {
|
|
244
|
+
case PrimitiveKind::Void: return env.Null();
|
|
245
|
+
case PrimitiveKind::Bool: return Napi::Boolean::New(env, result.u32);
|
|
246
|
+
case PrimitiveKind::Int8:
|
|
247
|
+
case PrimitiveKind::UInt8:
|
|
248
|
+
case PrimitiveKind::Int16:
|
|
249
|
+
case PrimitiveKind::UInt16:
|
|
250
|
+
case PrimitiveKind::Int32:
|
|
251
|
+
case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)result.u32);
|
|
252
|
+
case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)result.u64);
|
|
253
|
+
case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
|
|
254
|
+
case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
|
|
255
|
+
case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
|
|
256
|
+
case PrimitiveKind::Pointer: {
|
|
257
|
+
Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
|
|
273
258
|
SetValueTag(instance, external, func->ret.type);
|
|
274
259
|
|
|
275
260
|
return external;
|
|
276
261
|
} break;
|
|
277
|
-
|
|
278
262
|
case PrimitiveKind::Record: {
|
|
279
|
-
|
|
280
|
-
|
|
263
|
+
const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
|
|
264
|
+
: (const uint8_t *)&result.buf;
|
|
281
265
|
|
|
282
|
-
Napi::Object obj = PopObject(
|
|
266
|
+
Napi::Object obj = PopObject(ptr, func->ret.type);
|
|
283
267
|
return obj;
|
|
284
268
|
} break;
|
|
269
|
+
case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
|
|
270
|
+
case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
|
|
285
271
|
}
|
|
286
272
|
|
|
287
|
-
#undef PERFORM_CALL
|
|
288
|
-
|
|
289
273
|
RG_UNREACHABLE();
|
|
290
274
|
}
|
|
291
275
|
|