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.
Files changed (36) hide show
  1. package/README.md +22 -21
  2. package/build/qemu/1.0.4/koffi_darwin_x64.tar.gz +0 -0
  3. package/build/qemu/1.0.4/koffi_freebsd_arm64.tar.gz +0 -0
  4. package/build/qemu/1.0.4/koffi_freebsd_ia32.tar.gz +0 -0
  5. package/build/qemu/1.0.4/koffi_freebsd_x64.tar.gz +0 -0
  6. package/build/qemu/1.0.4/koffi_linux_arm.tar.gz +0 -0
  7. package/build/qemu/1.0.4/koffi_linux_arm64.tar.gz +0 -0
  8. package/build/qemu/1.0.4/koffi_linux_ia32.tar.gz +0 -0
  9. package/build/qemu/1.0.4/koffi_linux_x64.tar.gz +0 -0
  10. package/build/qemu/1.0.4/koffi_win32_ia32.tar.gz +0 -0
  11. package/build/qemu/1.0.4/koffi_win32_x64.tar.gz +0 -0
  12. package/package.json +1 -1
  13. package/src/abi_arm32.cc +119 -211
  14. package/src/abi_arm64.cc +92 -113
  15. package/src/abi_x64_sysv.cc +106 -131
  16. package/src/abi_x64_win.cc +78 -94
  17. package/src/abi_x86.cc +80 -95
  18. package/src/call.cc +144 -19
  19. package/src/call.hh +39 -3
  20. package/src/ffi.cc +11 -2
  21. package/src/ffi.hh +6 -12
  22. package/src/util.cc +0 -127
  23. package/src/util.hh +0 -16
  24. package/test/misc.c +66 -0
  25. package/test/misc.js +47 -0
  26. package/vendor/libcc/libcc.hh +1 -1
  27. package/build/qemu/1.0.3/koffi_darwin_x64.tar.gz +0 -0
  28. package/build/qemu/1.0.3/koffi_freebsd_arm64.tar.gz +0 -0
  29. package/build/qemu/1.0.3/koffi_freebsd_ia32.tar.gz +0 -0
  30. package/build/qemu/1.0.3/koffi_freebsd_x64.tar.gz +0 -0
  31. package/build/qemu/1.0.3/koffi_linux_arm.tar.gz +0 -0
  32. package/build/qemu/1.0.3/koffi_linux_arm64.tar.gz +0 -0
  33. package/build/qemu/1.0.3/koffi_linux_ia32.tar.gz +0 -0
  34. package/build/qemu/1.0.3/koffi_linux_x64.tar.gz +0 -0
  35. package/build/qemu/1.0.3/koffi_win32_ia32.tar.gz +0 -0
  36. package/build/qemu/1.0.3/koffi_win32_x64.tar.gz +0 -0
package/src/abi_arm64.cc CHANGED
@@ -163,28 +163,24 @@ static bool PushHFA(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest
163
163
  InstanceData *instance = env.GetInstanceData<InstanceData>();
164
164
 
165
165
  RG_ASSERT(IsObject(obj));
166
+ RG_ASSERT(IsHFA(type));
166
167
  RG_ASSERT(type->primitive == PrimitiveKind::Record);
167
- RG_ASSERT(AlignUp(dest, 8) == dest);
168
+ RG_ASSERT(AlignUp(dest, type->members[0].type->size) == dest);
169
+
170
+ bool float32 = (type->members[0].type->primitive == PrimitiveKind::Float32);
168
171
 
169
172
  for (const RecordMember &member: type->members) {
170
173
  Napi::Value value = obj.Get(member.name);
171
174
 
172
- if (member.type->primitive == PrimitiveKind::Float32) {
173
- if (!value.IsNumber() && !value.IsBigInt()) {
174
- ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected number", GetValueType(instance, value), member.name);
175
- return false;
176
- }
175
+ if (!value.IsNumber() && !value.IsBigInt()) {
176
+ ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected number", GetValueType(instance, value), member.name);
177
+ return false;
178
+ }
177
179
 
180
+ if (float32) {
178
181
  *(float *)dest = CopyNumber<float>(value);
179
- } else if (member.type->primitive == PrimitiveKind::Float64) {
180
- if (!value.IsNumber() && !value.IsBigInt()) {
181
- ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected number", GetValueType(instance, value), member.name);
182
- return false;
183
- }
184
-
185
- *(double *)dest = CopyNumber<double>(value);
186
182
  } else {
187
- RG_UNREACHABLE();
183
+ *(double *)dest = CopyNumber<double>(value);
188
184
  }
189
185
 
190
186
  dest += 8;
@@ -196,18 +192,19 @@ static bool PushHFA(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest
196
192
  static Napi::Object PopHFA(napi_env env, const uint8_t *ptr, const TypeInfo *type)
197
193
  {
198
194
  RG_ASSERT(type->primitive == PrimitiveKind::Record);
195
+ RG_ASSERT(IsHFA(type));
199
196
 
200
197
  Napi::Object obj = Napi::Object::New(env);
201
198
 
199
+ bool float32 = (type->members[0].type->primitive == PrimitiveKind::Float32);
200
+
202
201
  for (const RecordMember &member: type->members) {
203
- if (member.type->primitive == PrimitiveKind::Float32) {
202
+ if (float32) {
204
203
  float f = *(float *)ptr;
205
204
  obj.Set(member.name, Napi::Number::New(env, (double)f));
206
- } else if (member.type->primitive == PrimitiveKind::Float64) {
205
+ } else {
207
206
  double d = *(double *)ptr;
208
207
  obj.Set(member.name, Napi::Number::New(env, d));
209
- } else {
210
- RG_UNREACHABLE();
211
208
  }
212
209
 
213
210
  ptr += 8;
@@ -216,34 +213,25 @@ static Napi::Object PopHFA(napi_env env, const uint8_t *ptr, const TypeInfo *typ
216
213
  return obj;
217
214
  }
218
215
 
219
- Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
216
+ bool CallData::Prepare(const Napi::CallbackInfo &info)
220
217
  {
221
- // Sanity checks
222
- if (info.Length() < (uint32_t)func->parameters.len) {
223
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
224
- return env.Null();
225
- }
226
-
227
- uint8_t *return_ptr = nullptr;
228
218
  uint8_t *args_ptr = nullptr;
229
219
  uint64_t *gpr_ptr = nullptr;
230
220
  uint64_t *vec_ptr = nullptr;
231
221
 
232
222
  // Return through registers unless it's too big
233
223
  if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
234
- return env.Null();
224
+ return false;
235
225
  if (RG_UNLIKELY(!AllocStack(8 * 8, 8, &vec_ptr)))
236
- return env.Null();
226
+ return false;
237
227
  if (RG_UNLIKELY(!AllocStack(9 * 8, 8, &gpr_ptr)))
238
- return env.Null();
228
+ return false;
239
229
  if (func->ret.use_memory) {
240
230
  if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
241
- return env.Null();
231
+ return false;
242
232
  gpr_ptr[8] = (uint64_t)return_ptr;
243
233
  }
244
234
 
245
- LocalArray<OutObject, MaxOutParameters> out_objects;
246
-
247
235
  // Push arguments
248
236
  for (Size i = 0; i < func->parameters.len; i++) {
249
237
  const ParameterInfo &param = func->parameters[i];
@@ -257,7 +245,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
257
245
  case PrimitiveKind::Bool: {
258
246
  if (RG_UNLIKELY(!value.IsBoolean())) {
259
247
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected boolean", GetValueType(instance, value), i + 1);
260
- return env.Null();
248
+ return false;
261
249
  }
262
250
 
263
251
  bool b = value.As<Napi::Boolean>();
@@ -283,7 +271,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
283
271
  case PrimitiveKind::UInt64: {
284
272
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
285
273
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
286
- return env.Null();
274
+ return false;
287
275
  }
288
276
 
289
277
  int64_t v = CopyNumber<int64_t>(value);
@@ -303,7 +291,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
303
291
  case PrimitiveKind::Float32: {
304
292
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
305
293
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
306
- return env.Null();
294
+ return false;
307
295
  }
308
296
 
309
297
  float f = CopyNumber<float>(value);
@@ -323,7 +311,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
323
311
  case PrimitiveKind::Float64: {
324
312
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
325
313
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
326
- return env.Null();
314
+ return false;
327
315
  }
328
316
 
329
317
  double d = CopyNumber<double>(value);
@@ -341,12 +329,12 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
341
329
  if (RG_LIKELY(value.IsString())) {
342
330
  str = PushString(value);
343
331
  if (RG_UNLIKELY(!str))
344
- return env.Null();
332
+ return false;
345
333
  } else if (IsNullOrUndefined(value)) {
346
334
  str = nullptr;
347
335
  } else {
348
336
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
349
- return env.Null();
337
+ return false;
350
338
  }
351
339
 
352
340
  if (RG_LIKELY(param.gpr_count)) {
@@ -362,12 +350,12 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
362
350
  if (RG_LIKELY(value.IsString())) {
363
351
  str16 = PushString16(value);
364
352
  if (RG_UNLIKELY(!str16))
365
- return env.Null();
353
+ return false;
366
354
  } else if (IsNullOrUndefined(value)) {
367
355
  str16 = nullptr;
368
356
  } else {
369
357
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
370
- return env.Null();
358
+ return false;
371
359
  }
372
360
 
373
361
  if (RG_LIKELY(param.gpr_count)) {
@@ -387,11 +375,11 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
387
375
  Napi::Object obj = value.As<Napi::Object>();
388
376
 
389
377
  if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
390
- return env.Null();
378
+ return false;
391
379
 
392
380
  if (param.directions & 1) {
393
381
  if (!PushObject(obj, param.type->ref, ptr))
394
- return env.Null();
382
+ return false;
395
383
  } else {
396
384
  memset(ptr, 0, param.type->size);
397
385
  }
@@ -403,7 +391,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
403
391
  ptr = nullptr;
404
392
  } else {
405
393
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
406
- return env.Null();
394
+ return false;
407
395
  }
408
396
 
409
397
  if (RG_LIKELY(param.gpr_count)) {
@@ -418,32 +406,32 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
418
406
  case PrimitiveKind::Record: {
419
407
  if (RG_UNLIKELY(!IsObject(value))) {
420
408
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected object", GetValueType(instance, value), i + 1);
421
- return env.Null();
409
+ return false;
422
410
  }
423
411
 
424
412
  Napi::Object obj = value.As<Napi::Object>();
425
413
 
426
414
  if (param.vec_count) {
427
415
  if (!PushHFA(obj, param.type, (uint8_t *)vec_ptr))
428
- return env.Null();
416
+ return false;
429
417
  vec_ptr += param.vec_count;
430
418
  } else if (!param.use_memory) {
431
419
  if (param.gpr_count) {
432
420
  RG_ASSERT(param.type->align <= 8);
433
421
 
434
422
  if (!PushObject(obj, param.type, (uint8_t *)gpr_ptr))
435
- return env.Null();
423
+ return false;
436
424
  gpr_ptr += param.gpr_count;
437
425
  } else if (param.type->size) {
438
426
  args_ptr = AlignUp(args_ptr, 8);
439
427
  if (!PushObject(obj, param.type, args_ptr))
440
- return env.Null();
428
+ return false;
441
429
  args_ptr += AlignLen(param.type->size, 8);
442
430
  }
443
431
  } else {
444
432
  uint8_t *ptr;
445
433
  if (RG_UNLIKELY(!AllocHeap(param.type->size, 16, &ptr)))
446
- return env.Null();
434
+ return false;
447
435
 
448
436
  if (param.gpr_count) {
449
437
  RG_ASSERT(param.gpr_count == 1);
@@ -457,107 +445,98 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
457
445
  }
458
446
 
459
447
  if (!PushObject(obj, param.type, ptr))
460
- return env.Null();
448
+ return false;
461
449
  }
462
450
  } break;
463
451
  }
464
452
  }
465
453
 
466
- if (instance->debug) {
467
- DumpDebug();
468
- }
454
+ return true;
455
+ }
469
456
 
457
+ void CallData::Execute()
458
+ {
470
459
  #define PERFORM_CALL(Suffix) \
471
460
  ([&]() { \
472
461
  auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, GetSP()) \
473
462
  : ForwardCall ## Suffix(func->func, GetSP())); \
474
- PopOutArguments(out_objects); \
475
463
  return ret; \
476
464
  })()
477
465
 
478
466
  // Execute and convert return value
479
467
  switch (func->ret.type->primitive) {
480
- case PrimitiveKind::Void: {
481
- PERFORM_CALL(GG);
482
- return env.Null();
483
- } break;
484
- case PrimitiveKind::Bool: {
485
- X0X1Ret ret = PERFORM_CALL(GG);
486
- return Napi::Boolean::New(env, ret.x0);
487
- } break;
468
+ case PrimitiveKind::Void:
469
+ case PrimitiveKind::Bool:
488
470
  case PrimitiveKind::Int8:
489
471
  case PrimitiveKind::UInt8:
490
472
  case PrimitiveKind::Int16:
491
473
  case PrimitiveKind::UInt16:
492
474
  case PrimitiveKind::Int32:
493
- case PrimitiveKind::UInt32: {
494
- X0X1Ret ret = PERFORM_CALL(GG);
495
- return Napi::Number::New(env, (double)ret.x0);
496
- } break;
497
- case PrimitiveKind::Int64: {
498
- X0X1Ret ret = PERFORM_CALL(GG);
499
- return Napi::BigInt::New(env, (int64_t)ret.x0);
500
- } break;
501
- case PrimitiveKind::UInt64: {
502
- X0X1Ret ret = PERFORM_CALL(GG);
503
- return Napi::BigInt::New(env, ret.x0);
504
- } break;
505
- case PrimitiveKind::Float32: {
506
- float f = PERFORM_CALL(F);
507
- return Napi::Number::New(env, (double)f);
508
- } break;
509
- case PrimitiveKind::Float64: {
510
- HfaRet ret = PERFORM_CALL(DDDD);
511
- return Napi::Number::New(env, (double)ret.d0);
512
- } break;
513
- case PrimitiveKind::String: {
514
- X0X1Ret ret = PERFORM_CALL(GG);
515
- return Napi::String::New(env, (const char *)ret.x0);
516
- } break;
517
- case PrimitiveKind::String16: {
518
- X0X1Ret ret = PERFORM_CALL(GG);
519
- return Napi::String::New(env, (const char16_t *)ret.x0);
520
- } break;
521
- case PrimitiveKind::Pointer: {
522
- X0X1Ret ret = PERFORM_CALL(GG);
523
- void *ptr = (void *)ret.x0;
524
-
525
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
526
- SetValueTag(instance, external, func->ret.type);
527
-
528
- return external;
529
- } break;
530
-
475
+ case PrimitiveKind::UInt32:
476
+ case PrimitiveKind::Int64:
477
+ case PrimitiveKind::UInt64:
478
+ case PrimitiveKind::String:
479
+ case PrimitiveKind::String16:
480
+ case PrimitiveKind::Pointer: { result.u64 = PERFORM_CALL(GG).x0; } break;
531
481
  case PrimitiveKind::Record: {
532
482
  if (func->ret.gpr_count) {
533
483
  X0X1Ret ret = PERFORM_CALL(GG);
534
-
535
- Napi::Object obj = PopObject(env, (const uint8_t *)&ret, func->ret.type);
536
- return obj;
484
+ memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
537
485
  } else if (func->ret.vec_count) {
538
486
  HfaRet ret = PERFORM_CALL(DDDD);
487
+ memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
488
+ } else {
489
+ PERFORM_CALL(GG);
490
+ }
491
+ } break;
492
+ case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
493
+ case PrimitiveKind::Float64: { result.d = PERFORM_CALL(DDDD).d0; } break;
494
+ }
539
495
 
540
- Napi::Object obj = PopHFA(env, (const uint8_t *)&ret, func->ret.type);
541
- return obj;
542
- } else if (func->ret.type->size) {
543
- RG_ASSERT(return_ptr);
496
+ #undef PERFORM_CALL
497
+ }
544
498
 
545
- X0X1Ret ret = PERFORM_CALL(GG);
546
- RG_ASSERT(ret.x0 == (uint64_t)return_ptr);
499
+ Napi::Value CallData::Complete()
500
+ {
501
+ for (const OutObject &obj: out_objects) {
502
+ PopObject(obj.obj, obj.ptr, obj.type);
503
+ }
504
+
505
+ switch (func->ret.type->primitive) {
506
+ case PrimitiveKind::Void: return env.Null();
507
+ case PrimitiveKind::Bool: return Napi::Boolean::New(env, result.u32);
508
+ case PrimitiveKind::Int8:
509
+ case PrimitiveKind::UInt8:
510
+ case PrimitiveKind::Int16:
511
+ case PrimitiveKind::UInt16:
512
+ case PrimitiveKind::Int32:
513
+ case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)result.u32);
514
+ case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)result.u64);
515
+ case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
516
+ case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
517
+ case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
518
+ case PrimitiveKind::Pointer: {
519
+ Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
520
+ SetValueTag(instance, external, func->ret.type);
547
521
 
548
- Napi::Object obj = PopObject(env, return_ptr, func->ret.type);
522
+ return external;
523
+ } break;
524
+ case PrimitiveKind::Record: {
525
+ if (func->ret.vec_count) {
526
+ Napi::Object obj = PopHFA(env, (const uint8_t *)&result.buf, func->ret.type);
549
527
  return obj;
550
528
  } else {
551
- PERFORM_CALL(GG);
529
+ const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
530
+ : (const uint8_t *)&result.buf;
552
531
 
553
- Napi::Object obj = Napi::Object::New(env);
532
+ Napi::Object obj = PopObject(ptr, func->ret.type);
554
533
  return obj;
555
534
  }
556
535
  } break;
536
+ case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
537
+ case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
557
538
  }
558
539
 
559
- #undef PERFORM_CALL
560
-
561
540
  RG_UNREACHABLE();
562
541
  }
563
542