koffi 1.0.5 → 1.1.0-beta.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.
Files changed (39) hide show
  1. package/CMakeLists.txt +4 -0
  2. package/README.md +54 -24
  3. package/build/qemu/1.1.0-beta.2/koffi_darwin_x64.tar.gz +0 -0
  4. package/build/qemu/1.1.0-beta.2/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/build/qemu/1.1.0-beta.2/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/build/qemu/1.1.0-beta.2/koffi_freebsd_x64.tar.gz +0 -0
  7. package/build/qemu/1.1.0-beta.2/koffi_linux_arm.tar.gz +0 -0
  8. package/build/qemu/1.1.0-beta.2/koffi_linux_arm64.tar.gz +0 -0
  9. package/build/qemu/1.1.0-beta.2/koffi_linux_ia32.tar.gz +0 -0
  10. package/build/qemu/1.1.0-beta.2/koffi_linux_x64.tar.gz +0 -0
  11. package/build/qemu/1.1.0-beta.2/koffi_win32_ia32.tar.gz +0 -0
  12. package/build/qemu/1.1.0-beta.2/koffi_win32_x64.tar.gz +0 -0
  13. package/package.json +1 -1
  14. package/qemu/qemu.js +12 -5
  15. package/qemu/registry/machines.json +20 -10
  16. package/src/abi_arm32.cc +40 -51
  17. package/src/abi_arm64.cc +71 -138
  18. package/src/abi_x64_sysv.cc +37 -13
  19. package/src/abi_x64_win.cc +16 -6
  20. package/src/abi_x86.cc +16 -6
  21. package/src/call.cc +564 -58
  22. package/src/call.hh +32 -44
  23. package/src/ffi.cc +218 -19
  24. package/src/ffi.hh +27 -11
  25. package/src/parser.cc +4 -0
  26. package/src/util.cc +72 -0
  27. package/src/util.hh +2 -0
  28. package/test/misc.c +16 -10
  29. package/build/qemu/1.0.5/koffi_darwin_x64.tar.gz +0 -0
  30. package/build/qemu/1.0.5/koffi_freebsd_arm64.tar.gz +0 -0
  31. package/build/qemu/1.0.5/koffi_freebsd_ia32.tar.gz +0 -0
  32. package/build/qemu/1.0.5/koffi_freebsd_x64.tar.gz +0 -0
  33. package/build/qemu/1.0.5/koffi_linux_arm.tar.gz +0 -0
  34. package/build/qemu/1.0.5/koffi_linux_arm64.tar.gz +0 -0
  35. package/build/qemu/1.0.5/koffi_linux_ia32.tar.gz +0 -0
  36. package/build/qemu/1.0.5/koffi_linux_x64.tar.gz +0 -0
  37. package/build/qemu/1.0.5/koffi_win32_ia32.tar.gz +0 -0
  38. package/build/qemu/1.0.5/koffi_win32_x64.tar.gz +0 -0
  39. package/test/misc.js +0 -227
package/CMakeLists.txt CHANGED
@@ -18,7 +18,11 @@ find_package(CNoke)
18
18
 
19
19
  set(CMAKE_CXX_STANDARD 17)
20
20
  if(MSVC)
21
+ add_compile_options(/W4 /wd4200 /wd4458 /wd4706 /wd4100 /wd4127 /wd4702)
21
22
  enable_language(ASM_MASM)
23
+ else()
24
+ add_compile_options(-Wall -Wextra -Wno-missing-field-initializers
25
+ -Wno-unused-parameter -Wno-class-memaccess)
22
26
  endif()
23
27
 
24
28
  # ---- Koffi ----
package/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  - [Introduction](#introduction)
4
4
  - [Get started](#get-started)
5
+ - [Extra features](#extra-features)
6
+ * [C arrays](#c-arrays)
7
+ * [Variadic functions](#variadic-functions)
8
+ * [Asynchronous calls](#asynchronous-calls)
9
+ * [Callbacks](#callbacks)
5
10
  - [Benchmarks](#benchmarks)
6
11
  * [atoi results](#atoi-results)
7
12
  * [Raylib results](#raylib-results)
@@ -16,31 +21,30 @@ Koffi is a fast and easy-to-use FFI module for Node.js, with support for primiti
16
21
 
17
22
  After the release of version 1.0, the following features are planned:
18
23
 
19
- * 1.1: Asynchronous calls
24
+ * 1.1: Asynchronous calls and fixed-size array types
20
25
  * 1.2: C to JS callbacks
21
- * 1.3: Unions and (fixed size) array types
22
26
 
23
27
  The following platforms __are officially supported and tested__ at the moment:
24
28
 
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
29
+ Platform | Architecture | Sync calls | Async calls | Callbacks | Pre-built binary
30
+ --------- | -------------------------------- | ---------- | ----------- | --------- | ----------------
31
+ Windows | x86 (cdecl, stdcall, fastcall) | 🟩 Yes | 🟩 Yes | 🟥 No | 🟩 Yes
32
+ Windows | x86_64 | 🟩 Yes | 🟩 Yes | 🟥 No | 🟩 Yes
33
+ Linux | x86 | 🟩 Yes | 🟩 Yes | 🟥 No | 🟩 Yes
34
+ Linux | x86_64 | 🟩 Yes | 🟩 Yes | 🟥 No | 🟩 Yes
35
+ Linux | ARM32+VFP Little Endian | 🟩 Yes | 🟩 Yes | 🟥 No | 🟩 Yes
36
+ Linux | ARM64 Little Endian | 🟩 Yes | 🟩 Yes | 🟥 No | 🟩 Yes
37
+ FreeBSD | x86 | 🟩 Yes | 🟩 Yes | 🟥 No | 🟩 Yes
38
+ FreeBSD | x86_64 | 🟩 Yes | 🟩 Yes | 🟥 No | 🟩 Yes
39
+ FreeBSD | ARM64 Little Endian | 🟩 Yes | 🟩 Yes | 🟥 No | 🟩 Yes
40
+ macOS | x86_64 | 🟩 Yes | 🟩 Yes | 🟥 No | 🟩 Yes
41
+ macOS | ARM64 (M1) Little Endian | 🟩 Yes | 🟩 Yes | 🟥 No | 🟥 No
42
+ OpenBSD | x86_64 | 🟧 Maybe | 🟧 Maybe | 🟥 No | 🟥 No
43
+ OpenBSD | x86 | 🟧 Maybe | 🟧 Maybe | 🟥 No | 🟥 No
44
+ OpenBSD | ARM64 Little Endian | 🟧 Maybe | 🟧 Maybe | 🟥 No | 🟥 No
45
+ NetBSD | x86_64 | 🟧 Maybe | 🟧 Maybe | 🟥 No | 🟥 No
46
+ NetBSD | x86 | 🟧 Maybe | 🟧 Maybe | 🟥 No | 🟥 No
47
+ NetBSD | ARM64 Little Endian | 🟧 Maybe | 🟧 Maybe | 🟥 No | 🟥 No
44
48
 
45
49
  🟩 Tested, fully operational
46
50
  🟧 May work, but not actively tested
@@ -214,12 +218,16 @@ while (!WindowShouldClose()) {
214
218
 
215
219
  # Extra features
216
220
 
221
+ ## C arrays
222
+
223
+ Fixed-size arrays are declared with `koffi.array(type, length)`. Just like in C, they cannot be passed
224
+ as functions parameters (they degenerate to pointers), or returned by value. You can however embed them in struct types.
225
+
217
226
  ## Variadic functions
218
227
 
219
228
  Variadic functions are declared with an ellipsis as the last argument.
220
229
 
221
- In order to call a variadic function, you must provide two Javascript arguments for each C parameter,
222
- the first one is the expected type and the second one is the value.
230
+ In order to call a variadic function, you must provide two Javascript arguments for each C parameter, the first one is the expected type and the second one is the value.
223
231
 
224
232
  ```js
225
233
  const printf = lib.func('printf', 'int', ['string', '...']);
@@ -227,9 +235,31 @@ const printf = lib.func('printf', 'int', ['string', '...']);
227
235
  printf('Integer %d, double %g, string %s', 'int', 6, 'double', 8.5, 'string', 'THE END');
228
236
  ```
229
237
 
238
+ ## Asynchronous calls
239
+
240
+ You can issue asynchronous calls by calling the function through its async member. In this case, you need to provide a callback function as the last argument, with `(err, res)` parameters.
241
+
242
+ ```js
243
+ const koffi = require('koffi');
244
+ const lib = koffi.load('libc.so.6');
245
+
246
+ const atoi = lib.func('int atoi(const char *str)');
247
+
248
+ atoi.async('1257', (err, res) => {
249
+ console.log('Result:', res);
250
+ })
251
+ console.log('Hello World!');
252
+
253
+ // This program will print "Hello World!", and then "Result: 1257"
254
+ ```
255
+
256
+ You can easily convert this callback-style async function to a promise-based version with `util.promisify()` from the Node.js standard library.
257
+
258
+ Variadic functions do not support async.
259
+
230
260
  ## Callbacks
231
261
 
232
- Koffi does not yet support passing JS functions as callbacks. This is planned for version 1.1.
262
+ Koffi does not yet support passing JS functions as callbacks. This is planned for version 1.2.
233
263
 
234
264
  # Benchmarks
235
265
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "1.0.5",
3
+ "version": "1.1.0-beta.2",
4
4
  "description": "Fast and simple FFI (foreign function interface) for Node.js",
5
5
  "keywords": [
6
6
  "foreign",
package/qemu/qemu.js CHANGED
@@ -275,6 +275,7 @@ async function pack() {
275
275
  let json = fs.readFileSync(root_dir + '/koffi/package.json', { encoding: 'utf-8' });
276
276
  let version = JSON.parse(json).version;
277
277
 
278
+ console.log('>> Version:', version);
278
279
  console.log('>> Checking build archives...');
279
280
  for (let machine of machines) {
280
281
  let needed = false;
@@ -430,16 +431,22 @@ async function copy(func) {
430
431
  let copied = true;
431
432
 
432
433
  for (let directory of func(machine)) {
433
- try {
434
- await machine.ssh.exec('rm', ['-rf', directory]);
435
- } catch (err) {
436
- // Fails often on Windows (busy directory or whatever), but rarely a problem
434
+ for (let i = 0; i < 10; i++) {
435
+ try {
436
+ await machine.ssh.exec('rm', ['-rf', directory]);
437
+ break;
438
+ } catch (err) {
439
+ // Fails often on Windows (busy directory or whatever), but rarely a problem
440
+
441
+ await wait(1000);
442
+ continue;
443
+ }
437
444
  }
438
445
 
439
446
  try {
440
447
  await machine.ssh.putDirectory(snapshot_dir, directory, {
441
448
  recursive: true,
442
- concurrency: 4
449
+ concurrency: (process.platform != 'win32') ? 4 : 1
443
450
  });
444
451
  } catch (err) {
445
452
  ignore.add(machine);
@@ -35,8 +35,9 @@
35
35
  "Build": "node ../cnoke/cnoke.js -C test"
36
36
  },
37
37
  "commands": {
38
+ "Test Sync": "node test/sync.js",
39
+ "Test Async": "node test/async.js",
38
40
  "Test Raylib": "xvfb-run node test/raylib.js",
39
- "Test Misc": "node test/misc.js",
40
41
  "Test SQLite": "node test/sqlite.js"
41
42
  }
42
43
  }
@@ -79,8 +80,9 @@
79
80
  "Build": "node ../cnoke/cnoke.js -C test"
80
81
  },
81
82
  "commands": {
83
+ "Test Sync": "node test/sync.js",
84
+ "Test Async": "node test/async.js",
82
85
  "Test Raylib": "xvfb-run node test/raylib.js",
83
- "Test Misc": "node test/misc.js",
84
86
  "Test SQLite": "node test/sqlite.js"
85
87
  }
86
88
  }
@@ -123,8 +125,9 @@
123
125
  "Build": "node ../cnoke/cnoke.js -C test"
124
126
  },
125
127
  "commands": {
128
+ "Test Sync": "node test/sync.js",
129
+ "Test Async": "node test/async.js",
126
130
  "Test Raylib": "xvfb-run node test/raylib.js",
127
- "Test Misc": "node test/misc.js",
128
131
  "Test SQLite": "node test/sqlite.js"
129
132
  }
130
133
  }
@@ -167,8 +170,9 @@
167
170
  "Build": "node ../cnoke/cnoke.js -C test"
168
171
  },
169
172
  "commands": {
173
+ "Test Sync": "node test/sync.js",
174
+ "Test Async": "node test/async.js",
170
175
  "Test Raylib": "xvfb-run node test/raylib.js",
171
- "Test Misc": "node test/misc.js",
172
176
  "Test SQLite": "node test/sqlite.js"
173
177
  }
174
178
  }
@@ -218,8 +222,9 @@
218
222
  "Build": "C:\\Node32\\node32.cmd node ../cnoke/cnoke.js -C test"
219
223
  },
220
224
  "commands": {
225
+ "Test Sync": "C:\\Node32\\node32.cmd node test/sync.js",
226
+ "Test Async": "C:\\Node32\\node32.cmd node test/async.js",
221
227
  "Test Raylib": "seatsh C:\\Node32\\node32.cmd node test/raylib.js",
222
- "Test Misc": "C:\\Node32\\node32.cmd node test/misc.js",
223
228
  "Test SQLite": "C:\\Node32\\node32.cmd node test/sqlite.js"
224
229
  }
225
230
  },
@@ -230,8 +235,9 @@
230
235
  "Build": "C:\\Node64\\node64.cmd node ../cnoke/cnoke.js -C test"
231
236
  },
232
237
  "commands": {
238
+ "Test Sync": "C:\\Node64\\node64.cmd node test/sync.js",
239
+ "Test Async": "C:\\Node64\\node64.cmd node test/async.js",
233
240
  "Test Raylib": "seatsh C:\\Node64\\node64.cmd node test/raylib.js",
234
- "Test Misc": "C:\\Node64\\node64.cmd node test/misc.js",
235
241
  "Test SQLite": "C:\\Node64\\node64.cmd node test/sqlite.js"
236
242
  }
237
243
  }
@@ -274,8 +280,9 @@
274
280
  "Build": "node ../cnoke/cnoke.js -C test"
275
281
  },
276
282
  "commands": {
283
+ "Test Sync": "node test/sync.js",
284
+ "Test Async": "node test/async.js",
277
285
  "Test Raylib": "xvfb-run node test/raylib.js",
278
- "Test Misc": "node test/misc.js",
279
286
  "Test SQLite": "node test/sqlite.js"
280
287
  }
281
288
  }
@@ -318,8 +325,9 @@
318
325
  "Build": "node ../cnoke/cnoke.js -C test"
319
326
  },
320
327
  "commands": {
328
+ "Test Sync": "node test/sync.js",
329
+ "Test Async": "node test/async.js",
321
330
  "Test Raylib": "xvfb-run node test/raylib.js",
322
- "Test Misc": "node test/misc.js",
323
331
  "Test SQLite": "node test/sqlite.js"
324
332
  }
325
333
  }
@@ -362,8 +370,9 @@
362
370
  "Build": "node ../cnoke/cnoke.js -C test"
363
371
  },
364
372
  "commands": {
373
+ "Test Sync": "node test/sync.js",
374
+ "Test Async": "node test/async.js",
365
375
  "Test Raylib": "xvfb-run node test/raylib.js",
366
- "Test Misc": "node test/misc.js",
367
376
  "Test SQLite": "node test/sqlite.js"
368
377
  }
369
378
  }
@@ -406,7 +415,8 @@
406
415
  "Build": "PATH=/usr/local/bin:/usr/bin:/bin SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX11.3.sdk node ../cnoke/cnoke.js -C test"
407
416
  },
408
417
  "commands": {
409
- "Test Misc": "PATH=/usr/local/bin:/usr/bin:/bin node test/misc.js",
418
+ "Test Sync": "PATH=/usr/local/bin:/usr/bin:/bin node test/sync.js",
419
+ "Test Async": "PATH=/usr/local/bin:/usr/bin:/bin node test/async.js",
410
420
  "Test SQLite": "PATH=/usr/local/bin:/usr/bin:/bin node test/sqlite.js"
411
421
  }
412
422
  }
package/src/abi_arm32.cc CHANGED
@@ -37,28 +37,9 @@ extern "C" uint64_t ForwardCallXGG(const void *func, uint8_t *sp);
37
37
  extern "C" float ForwardCallXF(const void *func, uint8_t *sp);
38
38
  extern "C" HfaRet ForwardCallXDDDD(const void *func, uint8_t *sp);
39
39
 
40
- static bool IsHFA(const TypeInfo *type)
41
- {
42
- if (type->primitive != PrimitiveKind::Record)
43
- return false;
44
-
45
- if (type->members.len < 1 || type->members.len > 4)
46
- return false;
47
- if (type->members[0].type->primitive != PrimitiveKind::Float32 &&
48
- type->members[0].type->primitive != PrimitiveKind::Float64)
49
- return false;
50
-
51
- for (Size i = 1; i < type->members.len; i++) {
52
- if (type->members[i].type != type->members[0].type)
53
- return false;
54
- }
55
-
56
- return true;
57
- }
58
-
59
40
  bool AnalyseFunction(InstanceData *, FunctionInfo *func)
60
41
  {
61
- if (IsHFA(func->ret.type)) {
42
+ if (IsHFA(func->ret.type, 1, 4)) {
62
43
  func->ret.vec_count = func->ret.type->members.len *
63
44
  (func->ret.type->members[0].type->size / 4);
64
45
  } else if (func->ret.type->primitive != PrimitiveKind::Record ||
@@ -93,7 +74,6 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
93
74
  started_stack = true;
94
75
  }
95
76
  } break;
96
-
97
77
  case PrimitiveKind::Int64:
98
78
  case PrimitiveKind::UInt64: {
99
79
  if (gpr_avail >= 2) {
@@ -103,31 +83,8 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
103
83
  started_stack = true;
104
84
  }
105
85
  } break;
106
-
107
- case PrimitiveKind::Float32:
108
- case PrimitiveKind::Float64: {
109
- Size need = param.type->size / 4;
110
- bool vfp = !param.variadic;
111
-
112
- if (vfp) {
113
- if (need <= vec_avail) {
114
- param.vec_count = need;
115
- vec_avail -= need;
116
- } else {
117
- started_stack = true;
118
- }
119
- } else {
120
- if (need <= gpr_avail) {
121
- param.gpr_count = need;
122
- gpr_avail -= need;
123
- } else {
124
- started_stack = true;
125
- }
126
- }
127
- } break;
128
-
129
86
  case PrimitiveKind::Record: {
130
- if (IsHFA(param.type)) {
87
+ if (IsHFA(param.type, 1, 4)) {
131
88
  int vec_count = (int)(param.type->members.len *
132
89
  param.type->members[0].type->size / 4);
133
90
 
@@ -152,6 +109,28 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
152
109
  }
153
110
  }
154
111
  } break;
112
+ case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
113
+ case PrimitiveKind::Float32:
114
+ case PrimitiveKind::Float64: {
115
+ Size need = param.type->size / 4;
116
+ bool vfp = !param.variadic;
117
+
118
+ if (vfp) {
119
+ if (need <= vec_avail) {
120
+ param.vec_count = need;
121
+ vec_avail -= need;
122
+ } else {
123
+ started_stack = true;
124
+ }
125
+ } else {
126
+ if (need <= gpr_avail) {
127
+ param.gpr_count = need;
128
+ gpr_avail -= need;
129
+ } else {
130
+ started_stack = true;
131
+ }
132
+ }
133
+ } break;
155
134
  }
156
135
 
157
136
  func->args_size += AlignLen(param.type->size, 16);
@@ -305,8 +284,11 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
305
284
  memset(ptr, 0, param.type->size);
306
285
  }
307
286
  if (param.directions & 2) {
308
- OutObject out = {obj, ptr, param.type->ref};
309
- out_objects.Append(out);
287
+ OutObject *out = out_objects.AppendDefault();
288
+
289
+ out->ref.Reset(obj, 1);
290
+ out->ptr = ptr;
291
+ out->type = param.type->ref;
310
292
  }
311
293
  } else if (IsNullOrUndefined(value)) {
312
294
  ptr = nullptr;
@@ -351,6 +333,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
351
333
  args_ptr += AlignLen(param.type->size, 4);
352
334
  }
353
335
  } break;
336
+ case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
354
337
  case PrimitiveKind::Float32: {
355
338
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
356
339
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
@@ -391,6 +374,9 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
391
374
  }
392
375
  }
393
376
 
377
+ stack = MakeSpan(mem->stack.end(), old_stack_mem.end() - mem->stack.end());
378
+ heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
379
+
394
380
  return true;
395
381
  }
396
382
 
@@ -398,8 +384,8 @@ void CallData::Execute()
398
384
  {
399
385
  #define PERFORM_CALL(Suffix) \
400
386
  ([&]() { \
401
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, GetSP()) \
402
- : ForwardCall ## Suffix(func->func, GetSP())); \
387
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, stack.ptr) \
388
+ : ForwardCall ## Suffix(func->func, stack.ptr)); \
403
389
  return ret; \
404
390
  })()
405
391
 
@@ -426,6 +412,7 @@ void CallData::Execute()
426
412
  result.u64 = PERFORM_CALL(GG);
427
413
  }
428
414
  } break;
415
+ case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
429
416
  case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
430
417
  case PrimitiveKind::Float64: { result.d = PERFORM_CALL(DDDD).d0; } break;
431
418
  }
@@ -435,8 +422,9 @@ void CallData::Execute()
435
422
 
436
423
  Napi::Value CallData::Complete()
437
424
  {
438
- for (const OutObject &obj: out_objects) {
439
- PopObject(obj.obj, obj.ptr, obj.type);
425
+ for (const OutObject &out: out_objects) {
426
+ Napi::Object obj = out.ref.Value().As<Napi::Object>();
427
+ PopObject(obj, out.ptr, out.type);
440
428
  }
441
429
 
442
430
  switch (func->ret.type->primitive) {
@@ -465,6 +453,7 @@ Napi::Value CallData::Complete()
465
453
  Napi::Object obj = PopObject(ptr, func->ret.type);
466
454
  return obj;
467
455
  } break;
456
+ case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
468
457
  case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
469
458
  case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
470
459
  }