koffi 1.0.1 → 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.
Files changed (50) hide show
  1. package/CMakeLists.txt +12 -11
  2. package/README.md +23 -20
  3. package/build/qemu/1.0.4/koffi_darwin_x64.tar.gz +0 -0
  4. package/build/qemu/1.0.4/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/build/qemu/1.0.4/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/build/qemu/1.0.4/koffi_freebsd_x64.tar.gz +0 -0
  7. package/build/qemu/1.0.4/koffi_linux_arm.tar.gz +0 -0
  8. package/build/qemu/1.0.4/koffi_linux_arm64.tar.gz +0 -0
  9. package/build/qemu/1.0.4/koffi_linux_ia32.tar.gz +0 -0
  10. package/build/qemu/1.0.4/koffi_linux_x64.tar.gz +0 -0
  11. package/build/qemu/1.0.4/koffi_win32_ia32.tar.gz +0 -0
  12. package/build/qemu/1.0.4/koffi_win32_x64.tar.gz +0 -0
  13. package/package.json +8 -4
  14. package/qemu/qemu.js +794 -0
  15. package/qemu/registry/machines.json +415 -0
  16. package/qemu/registry/sha256sum.txt +45 -0
  17. package/src/{call_arm32.cc → abi_arm32.cc} +153 -219
  18. package/src/{call_arm32_fwd.S → abi_arm32_fwd.S} +0 -0
  19. package/src/{call_arm64.cc → abi_arm64.cc} +130 -123
  20. package/src/{call_arm64_fwd.S → abi_arm64_fwd.S} +0 -0
  21. package/src/{call_x64_sysv.cc → abi_x64_sysv.cc} +138 -135
  22. package/src/{call_x64_sysv_fwd.S → abi_x64_sysv_fwd.S} +0 -0
  23. package/src/{call_x64_win.cc → abi_x64_win.cc} +107 -99
  24. package/src/{call_x64_win_fwd.asm → abi_x64_win_fwd.asm} +0 -0
  25. package/src/{call_x86.cc → abi_x86.cc} +110 -107
  26. package/src/{call_x86_fwd.S → abi_x86_fwd.S} +0 -0
  27. package/src/{call_x86_fwd.asm → abi_x86_fwd.asm} +0 -0
  28. package/src/call.cc +353 -0
  29. package/src/call.hh +132 -4
  30. package/src/ffi.cc +16 -2
  31. package/src/ffi.hh +8 -12
  32. package/src/util.cc +7 -280
  33. package/src/util.hh +0 -107
  34. package/test/CMakeLists.txt +1 -0
  35. package/test/misc.c +355 -0
  36. package/test/misc.def +3 -0
  37. package/test/misc.js +227 -0
  38. package/test/raylib.js +165 -0
  39. package/test/sqlite.js +104 -0
  40. package/vendor/libcc/libcc.hh +1 -1
  41. package/build/qemu/1.0.1/koffi_darwin_x64.tar.gz +0 -0
  42. package/build/qemu/1.0.1/koffi_freebsd_arm64.tar.gz +0 -0
  43. package/build/qemu/1.0.1/koffi_freebsd_ia32.tar.gz +0 -0
  44. package/build/qemu/1.0.1/koffi_freebsd_x64.tar.gz +0 -0
  45. package/build/qemu/1.0.1/koffi_linux_arm.tar.gz +0 -0
  46. package/build/qemu/1.0.1/koffi_linux_arm64.tar.gz +0 -0
  47. package/build/qemu/1.0.1/koffi_linux_ia32.tar.gz +0 -0
  48. package/build/qemu/1.0.1/koffi_linux_x64.tar.gz +0 -0
  49. package/build/qemu/1.0.1/koffi_win32_ia32.tar.gz +0 -0
  50. package/build/qemu/1.0.1/koffi_win32_x64.tar.gz +0 -0
@@ -93,6 +93,7 @@ static Size ClassifyType(const TypeInfo *type, Size offset, Span<RegisterClass>
93
93
  case PrimitiveKind::Int64:
94
94
  case PrimitiveKind::UInt64:
95
95
  case PrimitiveKind::String:
96
+ case PrimitiveKind::String16:
96
97
  case PrimitiveKind::Pointer: {
97
98
  classes[0] = MergeClasses(classes[0], RegisterClass::Integer);
98
99
  return 1;
@@ -180,37 +181,25 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
180
181
  return true;
181
182
  }
182
183
 
183
- Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, const Napi::CallbackInfo &info)
184
+ bool CallData::Prepare(const Napi::CallbackInfo &info)
184
185
  {
185
- Napi::Env env = info.Env();
186
- CallData call(env, instance, func);
187
-
188
- // Sanity checks
189
- if (info.Length() < (uint32_t)func->parameters.len) {
190
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
191
- return env.Null();
192
- }
193
-
194
- uint8_t *return_ptr = nullptr;
195
186
  uint8_t *args_ptr = nullptr;
196
187
  uint64_t *gpr_ptr = nullptr;
197
188
  uint64_t *xmm_ptr = nullptr;
198
189
 
199
190
  // Return through registers unless it's too big
200
- if (RG_UNLIKELY(!call.AllocStack(func->args_size, 16, &args_ptr)))
201
- return env.Null();
202
- if (RG_UNLIKELY(!call.AllocStack(8 * 8, 8, &xmm_ptr)))
203
- return env.Null();
204
- if (RG_UNLIKELY(!call.AllocStack(6 * 8, 8, &gpr_ptr)))
205
- return env.Null();
191
+ if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
192
+ return false;
193
+ if (RG_UNLIKELY(!AllocStack(8 * 8, 8, &xmm_ptr)))
194
+ return false;
195
+ if (RG_UNLIKELY(!AllocStack(6 * 8, 8, &gpr_ptr)))
196
+ return false;
206
197
  if (func->ret.use_memory) {
207
- if (RG_UNLIKELY(!call.AllocHeap(func->ret.type->size, 16, &return_ptr)))
208
- return env.Null();
198
+ if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
199
+ return false;
209
200
  *(uint8_t **)(gpr_ptr++) = return_ptr;
210
201
  }
211
202
 
212
- LocalArray<OutObject, MaxOutParameters> out_objects;
213
-
214
203
  // Push arguments
215
204
  for (Size i = 0; i < func->parameters.len; i++) {
216
205
  const ParameterInfo &param = func->parameters[i];
@@ -224,7 +213,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
224
213
  case PrimitiveKind::Bool: {
225
214
  if (RG_UNLIKELY(!value.IsBoolean())) {
226
215
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argmument %2, expected boolean", GetValueType(instance, value), i + 1);
227
- return env.Null();
216
+ return false;
228
217
  }
229
218
 
230
219
  bool b = value.As<Napi::Boolean>();
@@ -246,7 +235,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
246
235
  case PrimitiveKind::UInt64: {
247
236
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
248
237
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
249
- return env.Null();
238
+ return false;
250
239
  }
251
240
 
252
241
  int64_t v = CopyNumber<int64_t>(value);
@@ -259,56 +248,45 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
259
248
  args_ptr += 8;
260
249
  }
261
250
  } break;
262
- case PrimitiveKind::Float32: {
263
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
264
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
265
- return env.Null();
266
- }
267
-
268
- float f = CopyNumber<float>(value);
269
-
270
- if (RG_LIKELY(param.xmm_count)) {
271
- memcpy(xmm_ptr++, &f, 4);
251
+ case PrimitiveKind::String: {
252
+ const char *str;
253
+ if (RG_LIKELY(value.IsString())) {
254
+ str = PushString(value);
255
+ if (RG_UNLIKELY(!str))
256
+ return false;
257
+ } else if (IsNullOrUndefined(value)) {
258
+ str = nullptr;
272
259
  } else {
273
- args_ptr = AlignUp(args_ptr, 4);
274
- memcpy(args_ptr, &f, 4);
275
- args_ptr += 8;
276
- }
277
- } break;
278
- case PrimitiveKind::Float64: {
279
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
280
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
281
- return env.Null();
260
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
261
+ return false;
282
262
  }
283
263
 
284
- double d = CopyNumber<double>(value);
285
-
286
- if (RG_LIKELY(param.xmm_count)) {
287
- memcpy(xmm_ptr++, &d, 8);
264
+ if (RG_LIKELY(param.gpr_count)) {
265
+ *(gpr_ptr++) = (uint64_t)str;
288
266
  } else {
289
267
  args_ptr = AlignUp(args_ptr, 8);
290
- memcpy(args_ptr, &d, 8);
268
+ *(uint64_t *)args_ptr = (uint64_t)str;
291
269
  args_ptr += 8;
292
270
  }
293
271
  } break;
294
- case PrimitiveKind::String: {
295
- const char *str;
272
+ case PrimitiveKind::String16: {
273
+ const char16_t *str16;
296
274
  if (RG_LIKELY(value.IsString())) {
297
- str = call.PushString(value);
298
- if (RG_UNLIKELY(!str))
299
- return env.Null();
275
+ str16 = PushString16(value);
276
+ if (RG_UNLIKELY(!str16))
277
+ return false;
300
278
  } else if (IsNullOrUndefined(value)) {
301
- str = nullptr;
279
+ str16 = nullptr;
302
280
  } else {
303
281
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
304
- return env.Null();
282
+ return false;
305
283
  }
306
284
 
307
285
  if (RG_LIKELY(param.gpr_count)) {
308
- *(gpr_ptr++) = (uint64_t)str;
286
+ *(gpr_ptr++) = (uint64_t)str16;
309
287
  } else {
310
288
  args_ptr = AlignUp(args_ptr, 8);
311
- *(uint64_t *)args_ptr = (uint64_t)str;
289
+ *(uint64_t *)args_ptr = (uint64_t)str16;
312
290
  args_ptr += 8;
313
291
  }
314
292
  } break;
@@ -320,12 +298,12 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
320
298
  } else if (IsObject(value) && param.type->ref->primitive == PrimitiveKind::Record) {
321
299
  Napi::Object obj = value.As<Napi::Object>();
322
300
 
323
- if (RG_UNLIKELY(!call.AllocHeap(param.type->ref->size, 16, &ptr)))
324
- return env.Null();
301
+ if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
302
+ return false;
325
303
 
326
304
  if (param.directions & 1) {
327
- if (!call.PushObject(obj, param.type->ref, ptr))
328
- return env.Null();
305
+ if (!PushObject(obj, param.type->ref, ptr))
306
+ return false;
329
307
  } else {
330
308
  memset(ptr, 0, param.type->size);
331
309
  }
@@ -337,7 +315,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
337
315
  ptr = nullptr;
338
316
  } else {
339
317
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
340
- return env.Null();
318
+ return false;
341
319
  }
342
320
 
343
321
  if (RG_LIKELY(param.gpr_count)) {
@@ -348,11 +326,10 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
348
326
  args_ptr += 8;
349
327
  }
350
328
  } break;
351
-
352
329
  case PrimitiveKind::Record: {
353
330
  if (RG_UNLIKELY(!IsObject(value))) {
354
331
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected object", GetValueType(instance, value), i + 1);
355
- return env.Null();
332
+ return false;
356
333
  }
357
334
 
358
335
  Napi::Object obj = value.As<Napi::Object>();
@@ -361,8 +338,8 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
361
338
  RG_ASSERT(param.type->size <= 16);
362
339
 
363
340
  uint64_t buf[2] = {};
364
- if (!call.PushObject(obj, param.type, (uint8_t *)buf))
365
- return env.Null();
341
+ if (!PushObject(obj, param.type, (uint8_t *)buf))
342
+ return false;
366
343
 
367
344
  if (param.gpr_first) {
368
345
  uint64_t *ptr = buf;
@@ -385,105 +362,131 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
385
362
  }
386
363
  } else if (param.use_memory) {
387
364
  args_ptr = AlignUp(args_ptr, param.type->align);
388
- if (!call.PushObject(obj, param.type, args_ptr))
389
- return env.Null();
365
+ if (!PushObject(obj, param.type, args_ptr))
366
+ return false;
390
367
  args_ptr += AlignLen(param.type->size, 8);
391
368
  }
392
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;
393
402
  }
394
403
  }
395
404
 
396
- if (instance->debug) {
397
- call.DumpDebug();
398
- }
405
+ return true;
406
+ }
399
407
 
408
+ void CallData::Execute()
409
+ {
400
410
  #define PERFORM_CALL(Suffix) \
401
411
  ([&]() { \
402
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, call.GetSP()) \
403
- : ForwardCall ## Suffix(func->func, call.GetSP())); \
404
- PopOutArguments(out_objects); \
412
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, GetSP()) \
413
+ : ForwardCall ## Suffix(func->func, GetSP())); \
405
414
  return ret; \
406
415
  })()
407
416
 
408
417
  // Execute and convert return value
409
418
  switch (func->ret.type->primitive) {
410
- case PrimitiveKind::Float32: {
411
- float f = PERFORM_CALL(F);
412
-
413
- return Napi::Number::New(env, (double)f);
414
- } break;
415
-
416
- case PrimitiveKind::Float64: {
417
- Xmm0RaxRet ret = PERFORM_CALL(DG);
418
-
419
- return Napi::Number::New(env, ret.xmm0);
420
- } break;
421
-
419
+ case PrimitiveKind::Void:
420
+ case PrimitiveKind::Bool:
421
+ case PrimitiveKind::Int8:
422
+ case PrimitiveKind::UInt8:
423
+ case PrimitiveKind::Int16:
424
+ case PrimitiveKind::UInt16:
425
+ case PrimitiveKind::Int32:
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;
422
432
  case PrimitiveKind::Record: {
423
433
  if (func->ret.gpr_first && !func->ret.xmm_count) {
424
434
  RaxRdxRet ret = PERFORM_CALL(GG);
425
-
426
- Napi::Object obj = PopObject(env, (const uint8_t *)&ret, func->ret.type);
427
- return obj;
435
+ memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
428
436
  } else if (func->ret.gpr_first) {
429
437
  RaxXmm0Ret ret = PERFORM_CALL(GD);
430
-
431
- Napi::Object obj = PopObject(env, (const uint8_t *)&ret, func->ret.type);
432
- return obj;
433
- } else if (func->ret.xmm_count) {
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 {
434
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
+ }
435
450
 
436
- Napi::Object obj = PopObject(env, (const uint8_t *)&ret, func->ret.type);
437
- return obj;
438
- } else if (func->ret.type->size) {
439
- RG_ASSERT(return_ptr);
451
+ #undef PERFORM_CALL
452
+ }
440
453
 
441
- RaxRdxRet ret = PERFORM_CALL(GG);
442
- RG_ASSERT(ret.rax == (uint64_t)return_ptr);
454
+ Napi::Value CallData::Complete()
455
+ {
456
+ for (const OutObject &obj: out_objects) {
457
+ PopObject(obj.obj, obj.ptr, obj.type);
458
+ }
443
459
 
444
- Napi::Object obj = PopObject(env, return_ptr, func->ret.type);
445
- return obj;
446
- } else {
447
- PERFORM_CALL(GG);
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);
448
476
 
449
- Napi::Object obj = Napi::Object::New(env);
450
- return obj;
451
- }
477
+ return external;
452
478
  } break;
479
+ case PrimitiveKind::Record: {
480
+ const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
481
+ : (const uint8_t *)&result.buf;
453
482
 
454
- default: {
455
- RaxRdxRet ret = PERFORM_CALL(GG);
456
-
457
- switch (func->ret.type->primitive) {
458
- case PrimitiveKind::Void: return env.Null();
459
- case PrimitiveKind::Bool: return Napi::Boolean::New(env, ret.rax);
460
- case PrimitiveKind::Int8: return Napi::Number::New(env, (double)ret.rax);
461
- case PrimitiveKind::UInt8: return Napi::Number::New(env, (double)ret.rax);
462
- case PrimitiveKind::Int16: return Napi::Number::New(env, (double)ret.rax);
463
- case PrimitiveKind::UInt16: return Napi::Number::New(env, (double)ret.rax);
464
- case PrimitiveKind::Int32: return Napi::Number::New(env, (double)ret.rax);
465
- case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)ret.rax);
466
- case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)ret.rax);
467
- case PrimitiveKind::UInt64: return Napi::BigInt::New(env, ret.rax);
468
- case PrimitiveKind::Float32: { RG_UNREACHABLE(); } break;
469
- case PrimitiveKind::Float64: { RG_UNREACHABLE(); } break;
470
- case PrimitiveKind::String: return Napi::String::New(env, (const char *)ret.rax);
471
- case PrimitiveKind::Pointer: {
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
-
480
- case PrimitiveKind::Record: { RG_UNREACHABLE(); } break;
481
- }
483
+ Napi::Object obj = PopObject(ptr, func->ret.type);
484
+ return obj;
482
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);
483
488
  }
484
489
 
485
- #undef PERFORM_CALL
486
-
487
490
  RG_UNREACHABLE();
488
491
  }
489
492
 
File without changes