koffi 1.0.2 → 1.0.5

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 +24 -21
  2. package/build/qemu/1.0.5/koffi_darwin_x64.tar.gz +0 -0
  3. package/build/qemu/1.0.5/koffi_freebsd_arm64.tar.gz +0 -0
  4. package/build/qemu/1.0.5/koffi_freebsd_ia32.tar.gz +0 -0
  5. package/build/qemu/1.0.5/koffi_freebsd_x64.tar.gz +0 -0
  6. package/build/qemu/1.0.5/koffi_linux_arm.tar.gz +0 -0
  7. package/build/qemu/1.0.5/koffi_linux_arm64.tar.gz +0 -0
  8. package/build/qemu/1.0.5/koffi_linux_ia32.tar.gz +0 -0
  9. package/build/qemu/1.0.5/koffi_linux_x64.tar.gz +0 -0
  10. package/build/qemu/1.0.5/koffi_win32_ia32.tar.gz +0 -0
  11. package/build/qemu/1.0.5/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.2/koffi_darwin_x64.tar.gz +0 -0
  28. package/build/qemu/1.0.2/koffi_freebsd_arm64.tar.gz +0 -0
  29. package/build/qemu/1.0.2/koffi_freebsd_ia32.tar.gz +0 -0
  30. package/build/qemu/1.0.2/koffi_freebsd_x64.tar.gz +0 -0
  31. package/build/qemu/1.0.2/koffi_linux_arm.tar.gz +0 -0
  32. package/build/qemu/1.0.2/koffi_linux_arm64.tar.gz +0 -0
  33. package/build/qemu/1.0.2/koffi_linux_ia32.tar.gz +0 -0
  34. package/build/qemu/1.0.2/koffi_linux_x64.tar.gz +0 -0
  35. package/build/qemu/1.0.2/koffi_win32_ia32.tar.gz +0 -0
  36. package/build/qemu/1.0.2/koffi_win32_x64.tar.gz +0 -0
package/README.md CHANGED
@@ -16,34 +16,37 @@ Koffi is a fast and easy-to-use FFI module for Node.js, with support for primiti
16
16
 
17
17
  After the release of version 1.0, the following features are planned:
18
18
 
19
- * 1.1: C to JS callbacks
20
- * 1.2: Support fixed array types
19
+ * 1.1: Asynchronous calls
20
+ * 1.2: C to JS callbacks
21
+ * 1.3: Unions and (fixed size) array types
21
22
 
22
23
  The following platforms __are officially supported and tested__ at the moment:
23
24
 
24
- Platoform | Architecture | JS to C | C to JS (callback) | Pre-built binary
25
- --------- | -------------------------------- | ------- | ------------------ | ----------------
26
- Windows | x86 (cdecl, stdcall, fastcall) | 🟩 | 🟥 | Yes
27
- Windows | x86_64 | 🟩 | 🟥 | Yes
28
- Linux | x86 | 🟩 | 🟥 | Yes
29
- Linux | x86_64 | 🟩 | 🟥 | Yes
30
- Linux | ARM32+VFP Little Endian | 🟩 | 🟥 | Yes
31
- Linux | ARM64 Little Endian | 🟩 | 🟥 | Yes
32
- FreeBSD | x86 | 🟩 | 🟥 | Yes
33
- FreeBSD | x86_64 | 🟩 | 🟥 | Yes
34
- FreeBSD | ARM64 Little Endian | 🟩 | 🟥 | Yes
35
- macOS | x86_64 | 🟩 | 🟥 | Yes
36
- macOS | ARM64 (M1) Little Endian | 🟩 | 🟥 | No x
37
- NetBSD | x86_64 | 🟧 | 🟥 | No x
38
- NetBSD | ARM64 Little Endian | 🟧 | 🟥 | No x
39
- OpenBSD | x86_64 | 🟧 | 🟥 | No x
40
- OpenBSD | ARM64 Little Endian | 🟧 | 🟥 | No x
25
+ Platform | Architecture | JS to C | C to JS (callback) | Pre-built binary
26
+ --------- | -------------------------------- | -------- | ------------------ | ----------------
27
+ Windows | x86 (cdecl, stdcall, fastcall) | 🟩 Yes | 🟥 No | 🟩 Yes
28
+ Windows | x86_64 | 🟩 Yes | 🟥 No | 🟩 Yes
29
+ Linux | x86 | 🟩 Yes | 🟥 No | 🟩 Yes
30
+ Linux | x86_64 | 🟩 Yes | 🟥 No | 🟩 Yes
31
+ Linux | ARM32+VFP Little Endian | 🟩 Yes | 🟥 No | 🟩 Yes
32
+ Linux | ARM64 Little Endian | 🟩 Yes | 🟥 No | 🟩 Yes
33
+ FreeBSD | x86 | 🟩 Yes | 🟥 No | 🟩 Yes
34
+ FreeBSD | x86_64 | 🟩 Yes | 🟥 No | 🟩 Yes
35
+ FreeBSD | ARM64 Little Endian | 🟩 Yes | 🟥 No | 🟩 Yes
36
+ macOS | x86_64 | 🟩 Yes | 🟥 No | 🟩 Yes
37
+ macOS | ARM64 (M1) Little Endian | 🟩 Yes | 🟥 No | 🟥 No
38
+ OpenBSD | x86_64 | 🟧 Maybe | 🟥 No | 🟥 No
39
+ OpenBSD | x86 | 🟧 Maybe | 🟥 No | 🟥 No
40
+ OpenBSD | ARM64 Little Endian | 🟧 Maybe | 🟥 No | 🟥 No
41
+ NetBSD | x86_64 | 🟧 Maybe | 🟥 No | 🟥 No
42
+ NetBSD | x86 | 🟧 Maybe | 🟥 No | 🟥 No
43
+ NetBSD | ARM64 Little Endian | 🟧 Maybe | 🟥 No | 🟥 No
41
44
 
42
45
  🟩 Tested, fully operational
43
46
  🟧 May work, but not actively tested
44
47
  🟥 Does not work yet
45
48
 
46
- This is still in development, bugs are to expected. More tests will come in the near future.
49
+ This is still in development, bugs are to be expected. More tests will come in the near future.
47
50
 
48
51
  # Get started
49
52
 
@@ -101,7 +104,7 @@ MessageBoxA(null, 'Hello', 'Foobar', MB_ICONINFORMATION);
101
104
 
102
105
  ## Raylib example
103
106
 
104
- This section assumes you know how to build C shared libraries, such as Raylib. You may need to fix the URL to the library before you can do anything.
107
+ This section assumes you know how to build C shared libraries, such as Raylib. You may need to fix the path to the library before you can do anything.
105
108
 
106
109
  ```js
107
110
  const koffi = require('koffi');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
4
4
  "description": "Fast and simple FFI (foreign function interface) for Node.js",
5
5
  "keywords": [
6
6
  "foreign",
package/src/abi_arm32.cc CHANGED
@@ -162,74 +162,8 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
162
162
  return true;
163
163
  }
164
164
 
165
- static bool PushHFA(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest)
165
+ bool CallData::Prepare(const Napi::CallbackInfo &info)
166
166
  {
167
- Napi::Env env = obj.Env();
168
- InstanceData *instance = env.GetInstanceData<InstanceData>();
169
-
170
- RG_ASSERT(IsObject(obj));
171
- RG_ASSERT(type->primitive == PrimitiveKind::Record);
172
- RG_ASSERT(AlignUp(dest, type->members[0].type->size) == dest);
173
-
174
- for (const RecordMember &member: type->members) {
175
- Napi::Value value = obj.Get(member.name);
176
-
177
- if (member.type->primitive == PrimitiveKind::Float32) {
178
- if (!value.IsNumber() && !value.IsBigInt()) {
179
- ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected number", GetValueType(instance, value), member.name);
180
- return false;
181
- }
182
-
183
- *(float *)dest = CopyNumber<float>(value);
184
- } else if (member.type->primitive == PrimitiveKind::Float64) {
185
- if (!value.IsNumber() && !value.IsBigInt()) {
186
- ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected number", GetValueType(instance, value), member.name);
187
- return false;
188
- }
189
-
190
- *(double *)dest = CopyNumber<double>(value);
191
- } else {
192
- RG_UNREACHABLE();
193
- }
194
-
195
- dest += type->members[0].type->size;
196
- }
197
-
198
- return true;
199
- }
200
-
201
- static Napi::Object PopHFA(napi_env env, const uint8_t *ptr, const TypeInfo *type)
202
- {
203
- RG_ASSERT(type->primitive == PrimitiveKind::Record);
204
-
205
- Napi::Object obj = Napi::Object::New(env);
206
-
207
- for (const RecordMember &member: type->members) {
208
- if (member.type->primitive == PrimitiveKind::Float32) {
209
- float f = *(float *)ptr;
210
- obj.Set(member.name, Napi::Number::New(env, (double)f));
211
- } else if (member.type->primitive == PrimitiveKind::Float64) {
212
- double d = *(double *)ptr;
213
- obj.Set(member.name, Napi::Number::New(env, d));
214
- } else {
215
- RG_UNREACHABLE();
216
- }
217
-
218
- ptr += member.type->size;
219
- }
220
-
221
- return obj;
222
- }
223
-
224
- Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
225
- {
226
- // Sanity checks
227
- if (info.Length() < (uint32_t)func->parameters.len) {
228
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
229
- return env.Null();
230
- }
231
-
232
- uint8_t *return_ptr = nullptr;
233
167
  uint8_t *args_ptr = nullptr;
234
168
  uint32_t *gpr_ptr = nullptr;
235
169
  uint32_t *vec_ptr = nullptr;
@@ -239,19 +173,17 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
239
173
  // In the armv7hf calling convention, some arguments can end up
240
174
  // partially in GPR, partially in the stack.
241
175
  if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
242
- return env.Null();
176
+ return false;
243
177
  if (RG_UNLIKELY(!AllocStack(4 * 4, 8, &gpr_ptr)))
244
- return env.Null();
178
+ return false;
245
179
  if (RG_UNLIKELY(!AllocStack(8 * 8, 8, &vec_ptr)))
246
- return env.Null();
180
+ return false;
247
181
  if (func->ret.use_memory) {
248
182
  if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
249
- return env.Null();
183
+ return false;
250
184
  *(uint8_t **)(gpr_ptr++) = return_ptr;
251
185
  }
252
186
 
253
- LocalArray<OutObject, MaxOutParameters> out_objects;
254
-
255
187
  // Push arguments
256
188
  for (Size i = 0; i < func->parameters.len; i++) {
257
189
  const ParameterInfo &param = func->parameters[i];
@@ -265,7 +197,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
265
197
  case PrimitiveKind::Bool: {
266
198
  if (RG_UNLIKELY(!value.IsBoolean())) {
267
199
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected boolean", GetValueType(instance, value), i + 1);
268
- return env.Null();
200
+ return false;
269
201
  }
270
202
 
271
203
  bool b = value.As<Napi::Boolean>();
@@ -285,7 +217,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
285
217
  case PrimitiveKind::UInt32: {
286
218
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
287
219
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
288
- return env.Null();
220
+ return false;
289
221
  }
290
222
 
291
223
  int64_t v = CopyNumber<int64_t>(value);
@@ -301,7 +233,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
301
233
  case PrimitiveKind::UInt64: {
302
234
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
303
235
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
304
- return env.Null();
236
+ return false;
305
237
  }
306
238
 
307
239
  int64_t v = CopyNumber<int64_t>(value);
@@ -315,54 +247,17 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
315
247
  args_ptr += 8;
316
248
  }
317
249
  } break;
318
- case PrimitiveKind::Float32: {
319
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
320
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
321
- return env.Null();
322
- }
323
-
324
- float f = CopyNumber<float>(value);
325
-
326
- if (RG_LIKELY(param.vec_count)) {
327
- memcpy(vec_ptr++, &f, 4);
328
- } else if (param.gpr_count) {
329
- memcpy(gpr_ptr++, &f, 4);
330
- } else {
331
- memcpy(args_ptr, &f, 4);
332
- args_ptr += 4;
333
- }
334
- } break;
335
- case PrimitiveKind::Float64: {
336
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
337
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
338
- return env.Null();
339
- }
340
-
341
- double d = CopyNumber<double>(value);
342
-
343
- if (RG_LIKELY(param.vec_count)) {
344
- memcpy(vec_ptr, &d, 8);
345
- vec_ptr += 2;
346
- } else if (param.gpr_count) {
347
- memcpy(gpr_ptr, &d, 8);
348
- gpr_ptr += 2;
349
- } else {
350
- args_ptr = AlignUp(args_ptr, 8);
351
- memcpy(args_ptr, &d, 8);
352
- args_ptr += 8;
353
- }
354
- } break;
355
250
  case PrimitiveKind::String: {
356
251
  const char *str;
357
252
  if (RG_LIKELY(value.IsString())) {
358
253
  str = PushString(value);
359
254
  if (RG_UNLIKELY(!str))
360
- return env.Null();
255
+ return false;
361
256
  } else if (IsNullOrUndefined(value)) {
362
257
  str = nullptr;
363
258
  } else {
364
259
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
365
- return env.Null();
260
+ return false;
366
261
  }
367
262
 
368
263
  if (RG_LIKELY(param.gpr_count)) {
@@ -377,12 +272,12 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
377
272
  if (RG_LIKELY(value.IsString())) {
378
273
  str16 = PushString16(value);
379
274
  if (RG_UNLIKELY(!str16))
380
- return env.Null();
275
+ return false;
381
276
  } else if (IsNullOrUndefined(value)) {
382
277
  str16 = nullptr;
383
278
  } else {
384
279
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
385
- return env.Null();
280
+ return false;
386
281
  }
387
282
 
388
283
  if (RG_LIKELY(param.gpr_count)) {
@@ -401,11 +296,11 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
401
296
  Napi::Object obj = value.As<Napi::Object>();
402
297
 
403
298
  if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
404
- return env.Null();
299
+ return false;
405
300
 
406
301
  if (param.directions & 1) {
407
302
  if (!PushObject(obj, param.type->ref, ptr))
408
- return env.Null();
303
+ return false;
409
304
  } else {
410
305
  memset(ptr, 0, param.type->size);
411
306
  }
@@ -417,7 +312,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
417
312
  ptr = nullptr;
418
313
  } else {
419
314
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
420
- return env.Null();
315
+ return false;
421
316
  }
422
317
 
423
318
  if (RG_LIKELY(param.gpr_count)) {
@@ -427,140 +322,153 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
427
322
  args_ptr += 4;
428
323
  }
429
324
  } break;
430
-
431
325
  case PrimitiveKind::Record: {
432
326
  if (RG_UNLIKELY(!IsObject(value))) {
433
327
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected object", GetValueType(instance, value), i + 1);
434
- return env.Null();
328
+ return false;
435
329
  }
436
330
 
437
331
  Napi::Object obj = value.As<Napi::Object>();
438
332
 
439
333
  if (param.vec_count) {
440
- if (!PushHFA(obj, param.type, (uint8_t *)vec_ptr))
441
- return env.Null();
334
+ if (!PushObject(obj, param.type, (uint8_t *)vec_ptr))
335
+ return false;
442
336
  vec_ptr += param.vec_count;
443
- } else {
444
- if (param.gpr_count) {
445
- RG_ASSERT(param.type->align <= 8);
337
+ } else if (param.gpr_count) {
338
+ RG_ASSERT(param.type->align <= 8);
446
339
 
447
- if (!PushObject(obj, param.type, (uint8_t *)gpr_ptr))
448
- return env.Null();
340
+ if (!PushObject(obj, param.type, (uint8_t *)gpr_ptr))
341
+ return false;
449
342
 
450
- gpr_ptr += param.gpr_count;
451
- args_ptr += AlignLen(param.type->size - param.gpr_count * 4, 4);
452
- } else if (param.type->size) {
453
- int16_t align = (param.type->align <= 4) ? 4 : 8;
343
+ gpr_ptr += param.gpr_count;
344
+ args_ptr += AlignLen(param.type->size - param.gpr_count * 4, 4);
345
+ } else if (param.type->size) {
346
+ int16_t align = (param.type->align <= 4) ? 4 : 8;
454
347
 
455
- args_ptr = AlignUp(args_ptr, align);
456
- if (!PushObject(obj, param.type, args_ptr))
457
- return env.Null();
458
- args_ptr += AlignLen(param.type->size, 4);
459
- }
348
+ args_ptr = AlignUp(args_ptr, align);
349
+ if (!PushObject(obj, param.type, args_ptr))
350
+ return false;
351
+ args_ptr += AlignLen(param.type->size, 4);
352
+ }
353
+ } break;
354
+ case PrimitiveKind::Float32: {
355
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
356
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
357
+ return false;
358
+ }
359
+
360
+ float f = CopyNumber<float>(value);
361
+
362
+ if (RG_LIKELY(param.vec_count)) {
363
+ memcpy(vec_ptr++, &f, 4);
364
+ } else if (param.gpr_count) {
365
+ memcpy(gpr_ptr++, &f, 4);
366
+ } else {
367
+ memcpy(args_ptr, &f, 4);
368
+ args_ptr += 4;
369
+ }
370
+ } break;
371
+ case PrimitiveKind::Float64: {
372
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
373
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
374
+ return false;
375
+ }
376
+
377
+ double d = CopyNumber<double>(value);
378
+
379
+ if (RG_LIKELY(param.vec_count)) {
380
+ memcpy(vec_ptr, &d, 8);
381
+ vec_ptr += 2;
382
+ } else if (param.gpr_count) {
383
+ memcpy(gpr_ptr, &d, 8);
384
+ gpr_ptr += 2;
385
+ } else {
386
+ args_ptr = AlignUp(args_ptr, 8);
387
+ memcpy(args_ptr, &d, 8);
388
+ args_ptr += 8;
460
389
  }
461
390
  } break;
462
391
  }
463
392
  }
464
393
 
465
- if (instance->debug) {
466
- DumpDebug();
467
- }
394
+ return true;
395
+ }
468
396
 
397
+ void CallData::Execute()
398
+ {
469
399
  #define PERFORM_CALL(Suffix) \
470
400
  ([&]() { \
471
401
  auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, GetSP()) \
472
402
  : ForwardCall ## Suffix(func->func, GetSP())); \
473
- PopOutArguments(out_objects); \
474
403
  return ret; \
475
404
  })()
476
405
 
477
406
  // Execute and convert return value
478
407
  switch (func->ret.type->primitive) {
479
- case PrimitiveKind::Void: {
480
- PERFORM_CALL(GG);
481
- return env.Null();
482
- } break;
483
- case PrimitiveKind::Bool: {
484
- uint32_t r0 = (uint32_t)PERFORM_CALL(GG);
485
- return Napi::Boolean::New(env, r0);
486
- } break;
408
+ case PrimitiveKind::Void:
409
+ case PrimitiveKind::Bool:
487
410
  case PrimitiveKind::Int8:
488
411
  case PrimitiveKind::UInt8:
489
412
  case PrimitiveKind::Int16:
490
413
  case PrimitiveKind::UInt16:
491
414
  case PrimitiveKind::Int32:
492
- case PrimitiveKind::UInt32: {
493
- uint32_t r0 = (uint32_t)PERFORM_CALL(GG);
494
- return Napi::Number::New(env, (double)r0);
495
- } break;
496
- case PrimitiveKind::Int64: {
497
- uint64_t ret = PERFORM_CALL(GG);
498
- return Napi::BigInt::New(env, (int64_t)ret);
499
- } break;
500
- case PrimitiveKind::UInt64: {
501
- uint64_t ret = PERFORM_CALL(GG);
502
- return Napi::BigInt::New(env, ret);
503
- } break;
504
- case PrimitiveKind::Float32: {
505
- float f = PERFORM_CALL(F);
506
- return Napi::Number::New(env, (double)f);
507
- } break;
508
- case PrimitiveKind::Float64: {
509
- HfaRet ret = PERFORM_CALL(DDDD);
510
- return Napi::Number::New(env, (double)ret.d0);
511
- } break;
512
- case PrimitiveKind::String: {
513
- uint32_t r0 = (uint32_t)PERFORM_CALL(GG);
514
- return Napi::String::New(env, (const char *)r0);
515
- } break;
516
- case PrimitiveKind::String16: {
517
- uint32_t r0 = (uint32_t)PERFORM_CALL(GG);
518
- return Napi::String::New(env, (const char16_t *)r0);
415
+ case PrimitiveKind::UInt32:
416
+ case PrimitiveKind::Int64:
417
+ case PrimitiveKind::UInt64:
418
+ case PrimitiveKind::String:
419
+ case PrimitiveKind::String16:
420
+ case PrimitiveKind::Pointer: { result.u64 = PERFORM_CALL(GG); } break;
421
+ case PrimitiveKind::Record: {
422
+ if (func->ret.vec_count) {
423
+ HfaRet ret = PERFORM_CALL(DDDD);
424
+ memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
425
+ } else {
426
+ result.u64 = PERFORM_CALL(GG);
427
+ }
519
428
  } break;
520
- case PrimitiveKind::Pointer: {
521
- uint32_t r0 = (uint32_t)PERFORM_CALL(GG);
522
- void *ptr = (void *)r0;
429
+ case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
430
+ case PrimitiveKind::Float64: { result.d = PERFORM_CALL(DDDD).d0; } break;
431
+ }
432
+
433
+ #undef PERFORM_CALL
434
+ }
435
+
436
+ Napi::Value CallData::Complete()
437
+ {
438
+ for (const OutObject &obj: out_objects) {
439
+ PopObject(obj.obj, obj.ptr, obj.type);
440
+ }
523
441
 
524
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
442
+ switch (func->ret.type->primitive) {
443
+ case PrimitiveKind::Void: return env.Null();
444
+ case PrimitiveKind::Bool: return Napi::Boolean::New(env, result.u32);
445
+ case PrimitiveKind::Int8:
446
+ case PrimitiveKind::UInt8:
447
+ case PrimitiveKind::Int16:
448
+ case PrimitiveKind::UInt16:
449
+ case PrimitiveKind::Int32:
450
+ case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)result.u32);
451
+ case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)result.u64);
452
+ case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
453
+ case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
454
+ case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
455
+ case PrimitiveKind::Pointer: {
456
+ Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
525
457
  SetValueTag(instance, external, func->ret.type);
526
458
 
527
459
  return external;
528
460
  } break;
529
-
530
461
  case PrimitiveKind::Record: {
531
- if (func->ret.gpr_count) {
532
- RG_ASSERT(func->ret.gpr_count <= 1);
533
-
534
- uint64_t ret = PERFORM_CALL(GG);
535
- uint32_t r0 = (uint32_t)ret;
462
+ const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
463
+ : (const uint8_t *)&result.buf;
536
464
 
537
- Napi::Object obj = PopObject(env, (const uint8_t *)&r0, func->ret.type);
538
- return obj;
539
- } else if (func->ret.vec_count) {
540
- HfaRet ret = PERFORM_CALL(DDDD);
541
-
542
- Napi::Object obj = PopHFA(env, (const uint8_t *)&ret, func->ret.type);
543
- return obj;
544
- } else if (func->ret.type->size) {
545
- RG_ASSERT(return_ptr);
546
-
547
- uint64_t ret = PERFORM_CALL(GG);
548
- uint32_t r0 = (uint32_t)ret;
549
- RG_ASSERT(r0 == (uint32_t)return_ptr);
550
-
551
- Napi::Object obj = PopObject(env, return_ptr, func->ret.type);
552
- return obj;
553
- } else {
554
- PERFORM_CALL(GG);
555
-
556
- Napi::Object obj = Napi::Object::New(env);
557
- return obj;
558
- }
465
+ Napi::Object obj = PopObject(ptr, func->ret.type);
466
+ return obj;
559
467
  } break;
468
+ case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
469
+ case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
560
470
  }
561
471
 
562
- #undef PERFORM_CALL
563
-
564
472
  RG_UNREACHABLE();
565
473
  }
566
474