koffi 2.11.0 → 2.12.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,15 @@
5
5
 
6
6
  ## Koffi 2
7
7
 
8
+ ### Koffi 2.12
9
+
10
+ #### Koffi 2.12.0
11
+
12
+ *Released on 2025-06-19*
13
+
14
+ - Support LoongArch64 architecture (thanks to [wjh-la](https://github.com/wjh-la))
15
+ - Fix wrong path for RISC-V 64 prebuild
16
+
8
17
  ### Koffi 2.11
9
18
 
10
19
  #### Koffi 2.11.0
package/README.md CHANGED
@@ -16,6 +16,7 @@ x86_64 (AMD64) | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |
16
16
  ARM32 LE [^2] | ⬜️ *N/A* | ✅ Yes | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
17
17
  ARM64 (AArch64) LE | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | 🟨 Probably
18
18
  RISC-V 64 [^3] | ⬜️ *N/A* | ✅ Yes | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
19
+ LoongArch64 | ⬜️ *N/A* | ✅ Yes | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
19
20
 
20
21
  [^1]: The following call conventions are supported: cdecl, stdcall, MS fastcall, thiscall.
21
22
  [^2]: The prebuilt binary uses the hard float ABI and expects a VFP coprocessor. Build from source to use Koffi with a different ABI (softfp, soft).
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -370,6 +370,7 @@ code:not(.hljs) {
370
370
  font-family: monospace;
371
371
  font-size: 14px;
372
372
  background: #eee;
373
+ white-space: nowrap;
373
374
  }
374
375
  pre > code:not(.hljs) {
375
376
  padding: 0;
@@ -21,6 +21,7 @@ x86_64 (AMD64) | ✅ | ✅ | ✅
21
21
  ARM32 LE [^2] | ⬜️ | ✅ | 🟨
22
22
  ARM64 (AArch64) LE | ✅ | ✅ | 🟨
23
23
  RISC-V 64 [^3] | ⬜️ | ✅ | 🟨
24
+ LoongArch64 | ⬜️ | ✅ | 🟨
24
25
 
25
26
  <div class="legend">✅ Yes | 🟨 Probably | ⬜️ Not applicable</div>
26
27
 
@@ -31,6 +32,7 @@ x86_64 (AMD64) | ✅ | ✅ | ✅
31
32
  ARM32 LE [^2] | ⬜️ | 🟨 | 🟨
32
33
  ARM64 (AArch64) LE | ✅ | ✅ | 🟨
33
34
  RISC-V 64 [^3] | ⬜️ | 🟨 | 🟨
35
+ LoongArch64 | ⬜️ | 🟨 | 🟨
34
36
 
35
37
  <div class="legend">✅ Yes | 🟨 Probably | ⬜️ Not applicable</div>
36
38
 
@@ -257,6 +257,72 @@ You can access unmanaged memory with `koffi.view(ptr, len)`. This function takes
257
257
  > [!NOTE]
258
258
  > Some runtimes (such as Electron) forbid the use of external buffers. In this case, trying to create a view will trigger an exception.
259
259
 
260
+ The following Linux example writes the string "Hello World!" to a file named "hello.txt" through mmaped memory, to demontrate the use of `koffi.view()`:
261
+
262
+ ```js
263
+ // ES6 syntax: import koffi from 'koffi';
264
+ const koffi = require('koffi');
265
+
266
+ const libc = koffi.load('libc.so.6');
267
+
268
+ const mode_t = koffi.alias('mode_t', 'uint32_t');
269
+ const off_t = koffi.alias('off_t', 'int64_t');
270
+
271
+ // These values are used on Linux and may differ on other systems
272
+ const O_RDONLY = 00000000;
273
+ const O_WRONLY = 00000001;
274
+ const O_RDWR = 00000002;
275
+ const O_CREAT = 00000100;
276
+ const O_EXCL = 00000200;
277
+ const O_CLOEXEC = 02000000;
278
+
279
+ // These values are used on Linux and may differ on other systems
280
+ const PROT_READ = 0x01;
281
+ const PROT_WRITE = 0x02;
282
+ const PROT_EXEC = 0x04;
283
+ const MAP_SHARED = 0x01;
284
+ const MAP_PRIVATE = 0x02;
285
+
286
+ const open = libc.func('int open(const char *path, int flags, uint32_t mode)');
287
+ const close = libc.func('int close(int fd)');
288
+ const ftruncate = libc.func('int ftruncate(int fd, off_t length)');
289
+ const mmap = libc.func('void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)');
290
+ const munmap = libc.func('int munmap(void *addr, size_t length)');
291
+ const strerror = libc.func('const char *strerror(int errnum)');
292
+
293
+ write('hello.txt', 'Hello World!');
294
+
295
+ function write(filename, str) {
296
+ let fd = -1;
297
+ let ptr = null;
298
+
299
+ // Work with encoded string
300
+ str = Buffer.from(str);
301
+
302
+ try {
303
+ fd = open(filename, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0644);
304
+ if (fd < 0)
305
+ throw new Error(`Failed to create '${filename}': ` + strerror(koffi.errno()));
306
+
307
+ if (ftruncate(fd, str.length) < 0)
308
+ throw new Error(`Failed to resize '${filename}': ` + strerror(koffi.errno()));
309
+
310
+ ptr = mmap(null, str.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
311
+ if (ptr == null)
312
+ throw new Error(`Failed to map '${filename}' to memory: ` + strerror(koffi.errno()));
313
+
314
+ let ab = koffi.view(ptr, str.length);
315
+ let view = new Uint8Array(ab);
316
+
317
+ str.copy(view);
318
+ } finally {
319
+ if (ptr != null)
320
+ munmap(ptr, str.length);
321
+ close(fd);
322
+ }
323
+ }
324
+ ```
325
+
260
326
  # Unwrap pointers
261
327
 
262
328
  You can use `koffi.address(ptr)` on a pointer to get the numeric value as a [BigInt object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt).
package/index.js CHANGED
@@ -4,9 +4,9 @@ var __commonJS = (cb, mod3) => function __require() {
4
4
  return mod3 || (0, cb[__getOwnPropNames(cb)[0]])((mod3 = { exports: {} }).exports, mod3), mod3.exports;
5
5
  };
6
6
 
7
- // ../../bin/Koffi/package/src/cnoke/src/tools.js
7
+ // package/src/cnoke/src/tools.js
8
8
  var require_tools = __commonJS({
9
- "../../bin/Koffi/package/src/cnoke/src/tools.js"(exports2, module2) {
9
+ "package/src/cnoke/src/tools.js"(exports2, module2) {
10
10
  "use strict";
11
11
  var crypto = require("crypto");
12
12
  var fs2 = require("fs");
@@ -278,6 +278,22 @@ var require_tools = __commonJS({
278
278
  }
279
279
  }
280
280
  break;
281
+ case 248:
282
+ {
283
+ switch (buf[4]) {
284
+ case 1:
285
+ {
286
+ header.e_machine = "loong32";
287
+ }
288
+ break;
289
+ case 2:
290
+ {
291
+ header.e_machine = "loong64";
292
+ }
293
+ break;
294
+ }
295
+ }
296
+ break;
281
297
  default:
282
298
  throw new Error("Unknown ELF machine type");
283
299
  }
@@ -358,13 +374,13 @@ var require_tools = __commonJS({
358
374
  }
359
375
  });
360
376
 
361
- // ../../bin/Koffi/package/src/koffi/package.json
377
+ // package/src/koffi/package.json
362
378
  var require_package = __commonJS({
363
- "../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
379
+ "package/src/koffi/package.json"(exports2, module2) {
364
380
  module2.exports = {
365
381
  name: "koffi",
366
- version: "2.11.0",
367
- stable: "2.11.0",
382
+ version: "2.12.0",
383
+ stable: "2.12.0",
368
384
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
369
385
  keywords: [
370
386
  "foreign",
@@ -408,9 +424,9 @@ var require_package = __commonJS({
408
424
  }
409
425
  });
410
426
 
411
- // ../../bin/Koffi/package/src/koffi/src/init.js
427
+ // package/src/koffi/src/init.js
412
428
  var require_init = __commonJS({
413
- "../../bin/Koffi/package/src/koffi/src/init.js"(exports, module) {
429
+ "package/src/koffi/src/init.js"(exports, module) {
414
430
  var fs = require("fs");
415
431
  var path = require("path");
416
432
  var util = require("util");
@@ -493,7 +509,7 @@ var require_init = __commonJS({
493
509
  }
494
510
  });
495
511
 
496
- // ../../bin/Koffi/package/src/koffi/index.js
512
+ // package/src/koffi/index.js
497
513
  var { detect: detect2, init: init2 } = require_init();
498
514
  var triplet2 = detect2();
499
515
  var native2 = null;
@@ -539,6 +555,11 @@ try {
539
555
  native2 = require("./build/koffi/linux_ia32/koffi.node");
540
556
  }
541
557
  break;
558
+ case "linux_loong64":
559
+ {
560
+ native2 = require("./build/koffi/linux_loong64/koffi.node");
561
+ }
562
+ break;
542
563
  case "linux_riscv64d":
543
564
  {
544
565
  native2 = require("./build/koffi/linux_riscv64d/koffi.node");
@@ -593,6 +614,11 @@ try {
593
614
  native2 = require("./build/koffi/musl_ia32/koffi.node");
594
615
  }
595
616
  break;
617
+ case "linux_loong64":
618
+ {
619
+ native2 = require("./build/koffi/musl_loong64/koffi.node");
620
+ }
621
+ break;
596
622
  case "linux_riscv64d":
597
623
  {
598
624
  native2 = require("./build/koffi/musl_riscv64d/koffi.node");
package/indirect.js CHANGED
@@ -4,9 +4,9 @@ var __commonJS = (cb, mod3) => function __require() {
4
4
  return mod3 || (0, cb[__getOwnPropNames(cb)[0]])((mod3 = { exports: {} }).exports, mod3), mod3.exports;
5
5
  };
6
6
 
7
- // ../../bin/Koffi/package/src/cnoke/src/tools.js
7
+ // package/src/cnoke/src/tools.js
8
8
  var require_tools = __commonJS({
9
- "../../bin/Koffi/package/src/cnoke/src/tools.js"(exports2, module2) {
9
+ "package/src/cnoke/src/tools.js"(exports2, module2) {
10
10
  "use strict";
11
11
  var crypto = require("crypto");
12
12
  var fs2 = require("fs");
@@ -278,6 +278,22 @@ var require_tools = __commonJS({
278
278
  }
279
279
  }
280
280
  break;
281
+ case 248:
282
+ {
283
+ switch (buf[4]) {
284
+ case 1:
285
+ {
286
+ header.e_machine = "loong32";
287
+ }
288
+ break;
289
+ case 2:
290
+ {
291
+ header.e_machine = "loong64";
292
+ }
293
+ break;
294
+ }
295
+ }
296
+ break;
281
297
  default:
282
298
  throw new Error("Unknown ELF machine type");
283
299
  }
@@ -358,13 +374,13 @@ var require_tools = __commonJS({
358
374
  }
359
375
  });
360
376
 
361
- // ../../bin/Koffi/package/src/koffi/package.json
377
+ // package/src/koffi/package.json
362
378
  var require_package = __commonJS({
363
- "../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
379
+ "package/src/koffi/package.json"(exports2, module2) {
364
380
  module2.exports = {
365
381
  name: "koffi",
366
- version: "2.11.0",
367
- stable: "2.11.0",
382
+ version: "2.12.0",
383
+ stable: "2.12.0",
368
384
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
369
385
  keywords: [
370
386
  "foreign",
@@ -408,9 +424,9 @@ var require_package = __commonJS({
408
424
  }
409
425
  });
410
426
 
411
- // ../../bin/Koffi/package/src/koffi/src/init.js
427
+ // package/src/koffi/src/init.js
412
428
  var require_init = __commonJS({
413
- "../../bin/Koffi/package/src/koffi/src/init.js"(exports, module) {
429
+ "package/src/koffi/src/init.js"(exports, module) {
414
430
  var fs = require("fs");
415
431
  var path = require("path");
416
432
  var util = require("util");
@@ -493,7 +509,7 @@ var require_init = __commonJS({
493
509
  }
494
510
  });
495
511
 
496
- // ../../bin/Koffi/package/src/koffi/indirect.js
512
+ // package/src/koffi/indirect.js
497
513
  var { detect: detect2, init: init2 } = require_init();
498
514
  var triplet2 = detect2();
499
515
  var mod2 = init2(triplet2, null);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.11.0",
4
- "stable": "2.11.0",
3
+ "version": "2.12.0",
4
+ "stable": "2.12.0",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
@@ -304,6 +304,12 @@ function decode_elf_header(buf) {
304
304
  case 2: { header.e_machine = 'riscv64'; } break;
305
305
  }
306
306
  } break;
307
+ case 248: {
308
+ switch (buf[4]) {
309
+ case 1: { header.e_machine = 'loong32'; } break;
310
+ case 2: { header.e_machine = 'loong64'; } break;
311
+ }
312
+ } break;
307
313
  default: throw new Error('Unknown ELF machine type');
308
314
  }
309
315
 
@@ -105,7 +105,7 @@ extern "C" const char *FelixTarget;
105
105
  extern "C" const char *FelixVersion;
106
106
  extern "C" const char *FelixCompiler;
107
107
 
108
- #if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) || __riscv_xlen == 64
108
+ #if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) || __riscv_xlen == 64 || defined(__loongarch64)
109
109
  typedef int64_t Size;
110
110
  #define RG_SIZE_MAX INT64_MAX
111
111
  #elif defined(_WIN32) || defined(__APPLE__) || defined(__unix__)
@@ -211,6 +211,8 @@ extern "C" void AssertMessage(const char *filename, int line, const char *cond);
211
211
  #define RG_DEBUG_BREAK() __asm__ __volatile__(".inst 0xe7f001f0")
212
212
  #elif defined(__riscv)
213
213
  #define RG_DEBUG_BREAK() __asm__ __volatile__("ebreak")
214
+ #elif defined(__loongarch64)
215
+ #define RG_DEBUG_BREAK() __asm__ __volatile__("break 1")
214
216
  #endif
215
217
 
216
218
  #define RG_CRITICAL(Cond, ...) \
@@ -110,6 +110,8 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
110
110
  endif()
111
111
  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv")
112
112
  list(APPEND KOFFI_SRC src/abi_riscv64.cc src/abi_riscv64_asm.S)
113
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "loongarch64")
114
+ list(APPEND KOFFI_SRC src/abi_riscv64.cc src/abi_loong64_asm.S)
113
115
  else()
114
116
  if(WIN32)
115
117
  list(APPEND KOFFI_SRC src/abi_x64_win.cc src/abi_x64_win_asm.asm)
@@ -0,0 +1,23 @@
1
+ // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ // this software and associated documentation files (the “Software”), to deal in
5
+ // the Software without restriction, including without limitation the rights to use,
6
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
+ // Software, and to permit persons to whom the Software is furnished to do so,
8
+ // subject to the following conditions:
9
+ //
10
+ // The above copyright notice and this permission notice shall be included in all
11
+ // copies or substantial portions of the Software.
12
+ //
13
+ // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
+ // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
+ // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
+ // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
+ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
+ // OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ // There's nothing to see here, this architecture uses the ABI code in abi_riscv64.cc!
23
+ // This file only exists to avoid leaving abi_loong64_asm.S alone :)
@@ -0,0 +1,240 @@
1
+ # Copyright 2023 Niels Martignène <niels.martignene@protonmail.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ # this software and associated documentation files (the “Software”), to deal in
5
+ # the Software without restriction, including without limitation the rights to use,
6
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
+ # Software, and to permit persons to whom the Software is furnished to do so,
8
+ # subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
+ # OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ #define SYMBOL(Symbol) Symbol
23
+
24
+ # Forward
25
+ # ----------------------------
26
+
27
+ # These three are the same, but they differ (in the C side) by their return type.
28
+ # Unlike the three next functions, these ones don't forward FA argument registers.
29
+ .global ForwardCallGG
30
+ .global ForwardCallF
31
+ .global ForwardCallDG
32
+ .global ForwardCallGD
33
+ .global ForwardCallDD
34
+
35
+ # The X variants are slightly slower, and are used when FA arguments must be forwarded.
36
+ .global ForwardCallXGG
37
+ .global ForwardCallXF
38
+ .global ForwardCallXDG
39
+ .global ForwardCallXGD
40
+ .global ForwardCallXDD
41
+
42
+ # Copy function pointer to t7, in order to save it through argument forwarding.
43
+ # Also make a copy of the SP to CallData::old_sp because the callback system might need it.
44
+ # Save SP in FP, and use carefully assembled stack provided by caller.
45
+ .macro prologue
46
+ addi.d $sp, $sp, -16
47
+ st.d $ra, $sp, 0
48
+ st.d $fp, $sp, 8
49
+ move $fp, $sp
50
+ st.d $fp, $a2, 0
51
+ move $t7, $a0
52
+ addi.d $sp, $a1, 128
53
+ .endm
54
+
55
+ # Call native function.
56
+ # Once done, restore normal stack pointer and return.
57
+ # The return value is passed untouched through registers.
58
+ .macro epilogue
59
+ jirl $ra, $t7,0
60
+ move $sp, $fp
61
+ ld.d $ra, $sp, 0
62
+ ld.d $fp, $sp, 8
63
+ addi.d $sp, $sp, 16
64
+ jr $ra
65
+ .endm
66
+
67
+ # Prepare general purpose argument registers from array passed by caller.
68
+ .macro forward_gpr
69
+ ld.d $a7, $a1, 120
70
+ ld.d $a6, $a1, 112
71
+ ld.d $a5, $a1, 104
72
+ ld.d $a4, $a1, 96
73
+ ld.d $a3, $a1, 88
74
+ ld.d $a2, $a1, 80
75
+ ld.d $a0, $a1, 64
76
+ ld.d $a1, $a1, 72
77
+ .endm
78
+
79
+ # Prepare vector argument registers from array passed by caller.
80
+ .macro forward_vec
81
+ fld.d $fa7, $a1, 56
82
+ fld.d $fa6, $a1, 48
83
+ fld.d $fa5, $a1, 40
84
+ fld.d $fa4, $a1, 32
85
+ fld.d $fa3, $a1, 24
86
+ fld.d $fa2, $a1, 16
87
+ fld.d $fa1, $a1, 8
88
+ fld.d $fa0, $a1, 0
89
+ .endm
90
+
91
+ ForwardCallGG:
92
+ prologue
93
+ forward_gpr
94
+ epilogue
95
+
96
+ ForwardCallF:
97
+ prologue
98
+ forward_gpr
99
+ epilogue
100
+
101
+ ForwardCallDG:
102
+ prologue
103
+ forward_gpr
104
+ epilogue
105
+
106
+ ForwardCallGD:
107
+ prologue
108
+ forward_gpr
109
+ epilogue
110
+
111
+ ForwardCallDD:
112
+ prologue
113
+ forward_gpr
114
+ epilogue
115
+
116
+ ForwardCallXGG:
117
+ prologue
118
+ forward_vec
119
+ forward_gpr
120
+ epilogue
121
+
122
+ ForwardCallXF:
123
+ prologue
124
+ forward_vec
125
+ forward_gpr
126
+ epilogue
127
+
128
+ ForwardCallXDG:
129
+ prologue
130
+ forward_vec
131
+ forward_gpr
132
+ epilogue
133
+
134
+ ForwardCallXGD:
135
+ prologue
136
+ forward_vec
137
+ forward_gpr
138
+ epilogue
139
+
140
+ ForwardCallXDD:
141
+ prologue
142
+ forward_vec
143
+ forward_gpr
144
+ epilogue
145
+
146
+ # Callbacks
147
+ # ----------------------------
148
+
149
+ .global RelayCallback
150
+ .global CallSwitchStack
151
+
152
+ # First, make a copy of the GPR argument registers (a0 to a7).
153
+ # Then call the C function RelayCallback with the following arguments:
154
+ # static trampoline ID, a pointer to the saved GPR array, a pointer to the stack
155
+ # arguments of this call, and a pointer to a struct that will contain the result registers.
156
+ # After the call, simply load these registers from the output struct.
157
+ .macro trampoline id
158
+ addi.d $sp, $sp, -176
159
+ st.d $ra, $sp, 0
160
+ st.d $a0, $sp, 8
161
+ st.d $a1, $sp, 16
162
+ st.d $a2, $sp, 24
163
+ st.d $a3, $sp, 32
164
+ st.d $a4, $sp, 40
165
+ st.d $a5, $sp, 48
166
+ st.d $a6, $sp, 56
167
+ st.d $a7, $sp, 64
168
+ li.d $a0, \id
169
+ addi.d $a1, $sp, 8
170
+ addi.d $a2, $sp, 176
171
+ addi.d $a3, $sp, 136
172
+ bl RelayCallback
173
+ ld.d $ra, $sp, 0
174
+ ld.d $a0, $sp, 136
175
+ ld.d $a1, $sp, 144
176
+ addi.d $sp, $sp, 176
177
+ jr $ra
178
+ .endm
179
+
180
+ # Same thing, but also forwards the floating-point argument registers and loads them at the end.
181
+ .macro trampoline_vec id
182
+ addi.d $sp, $sp, -176
183
+ st.d $ra, $sp, 0
184
+ st.d $a0, $sp, 8
185
+ st.d $a1, $sp, 16
186
+ st.d $a2, $sp, 24
187
+ st.d $a3, $sp, 32
188
+ st.d $a4, $sp, 40
189
+ st.d $a5, $sp, 48
190
+ st.d $a6, $sp, 56
191
+ st.d $a7, $sp, 64
192
+ fst.d $fa0, $sp, 72
193
+ fst.d $fa1, $sp, 80
194
+ fst.d $fa2, $sp, 88
195
+ fst.d $fa3, $sp, 96
196
+ fst.d $fa4, $sp, 104
197
+ fst.d $fa5, $sp, 112
198
+ fst.d $fa6, $sp, 120
199
+ fst.d $fa7, $sp, 128
200
+ li.d $a0, \id
201
+ addi.d $a1, $sp, 8
202
+ addi.d $a2, $sp, 176
203
+ addi.d $a3, $sp, 136
204
+ bl RelayCallback
205
+ ld.d $ra, $sp, 0
206
+ ld.d $a0, $sp, 136
207
+ ld.d $a1, $sp, 144
208
+ fld.d $fa0, $sp, 152
209
+ fld.d $fa1, $sp, 160
210
+ addi.d $sp, $sp, 176
211
+ jr $ra
212
+ .endm
213
+
214
+ # When a callback is relayed, Koffi will call into Node.js and V8 to execute Javascript.
215
+ # The problem is that we're still running on the separate Koffi stack, and V8 will
216
+ # probably misdetect this as a "stack overflow". We have to restore the old
217
+ # stack pointer, call Node.js/V8 and go back to ours.
218
+ # The first three parameters (a0, a1, a2) are passed through untouched.
219
+ CallSwitchStack:
220
+ addi.d $sp, $sp, -16
221
+ st.d $ra, $sp, 0
222
+ st.d $fp, $sp, 8
223
+ move $fp, $sp
224
+ ld.d $t0, $a4, 0
225
+ sub.d $t0, $sp, $t0
226
+ li.d $t1, -16
227
+ and $t0, $t0, $t1
228
+ st.d $t0, $a4, 8
229
+ move $sp, $a3
230
+ jirl $ra, $a5, 0
231
+ move $sp, $fp
232
+ ld.d $ra, $sp, 0
233
+ ld.d $fp, $sp, 8
234
+ addi.d $sp, $sp, 16
235
+ jr $ra
236
+
237
+ # Trampolines
238
+ # ----------------------------
239
+
240
+ #include "trampolines/gnu.inc"
@@ -19,7 +19,7 @@
19
19
  // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
20
  // OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- #if __riscv_xlen == 64
22
+ #if __riscv_xlen == 64 || defined(__loongarch64)
23
23
 
24
24
  #include "src/core/libcc/libcc.hh"
25
25
  #include "ffi.hh"
@@ -97,7 +97,7 @@ static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int vec_avail)
97
97
  gpr_avail = std::min(2, gpr_avail);
98
98
  vec_avail = std::min(2, vec_avail);
99
99
 
100
- #if defined(__riscv_float_abi_double)
100
+ #if defined(__riscv_float_abi_double) || defined(__loongarch64)
101
101
  if (param->type->primitive != PrimitiveKind::Union) {
102
102
  int gpr_count = 0;
103
103
  int vec_count = 0;
@@ -209,7 +209,7 @@ struct ParameterInfo {
209
209
  #elif defined(__i386__) || defined(_M_IX86)
210
210
  bool trivial; // Only matters for return value
211
211
  int8_t fast;
212
- #elif __riscv_xlen == 64
212
+ #elif __riscv_xlen == 64 || defined(__loongarch64)
213
213
  bool use_memory;
214
214
  int8_t gpr_count;
215
215
  int8_t vec_count;
@@ -123,11 +123,27 @@ static inline bool IsRawBuffer(Napi::Value value)
123
123
  static inline Span<uint8_t> GetRawBuffer(Napi::Value value)
124
124
  {
125
125
  if (value.IsTypedArray()) {
126
- Napi::TypedArray array = value.As<Napi::TypedArray>();
127
- Napi::ArrayBuffer buffer = array.ArrayBuffer();
128
- Size offset = array.ByteOffset();
129
-
130
- return MakeSpan((uint8_t *)buffer.Data() + offset, (Size)array.ByteLength());
126
+ napi_typedarray_type type = napi_int8_array;
127
+ size_t length = 0;
128
+ void *ptr = nullptr;
129
+
130
+ napi_get_typedarray_info(value.Env(), value, &type, &length, &ptr, nullptr, nullptr);
131
+
132
+ switch (type) {
133
+ case napi_int8_array: { length *= 1; } break;
134
+ case napi_uint8_array: { length *= 1; } break;
135
+ case napi_uint8_clamped_array: { length *= 1; } break;
136
+ case napi_int16_array: { length *= 2; } break;
137
+ case napi_uint16_array: { length *= 2; } break;
138
+ case napi_int32_array: { length *= 4; } break;
139
+ case napi_uint32_array: { length *= 4; } break;
140
+ case napi_float32_array: { length *= 4; } break;
141
+ case napi_float64_array: { length *= 8; } break;
142
+ case napi_bigint64_array: { length *= 8; } break;
143
+ case napi_biguint64_array: { length *= 8; } break;
144
+ }
145
+
146
+ return MakeSpan((uint8_t *)ptr, (Size)length);
131
147
  } else if (value.IsArrayBuffer()) {
132
148
  Napi::ArrayBuffer buffer = value.As<Napi::ArrayBuffer>();
133
149