koffi 2.10.1 → 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 +314 -99
- package/README.md +1 -0
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_armhf/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_loong64/koffi.node +0 -0
- package/build/koffi/linux_riscv64d/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/musl_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/doc/assets.ini +1 -1
- package/doc/{flaat/flaat.css → flat/flat.css} +2 -0
- package/doc/{flaat → flat}/normal.css +125 -31
- package/doc/{flaat → flat}/print.css +1 -2
- package/doc/flat/reset.css +41 -0
- package/doc/{flaat → flat}/small.css +5 -2
- package/doc/{flaat/flaat.js → flat/static.js} +21 -10
- package/doc/pages/contribute.md +3 -3
- package/doc/pages/output.md +32 -1
- package/doc/pages/packaging.md +5 -5
- package/doc/pages/platforms.md +2 -0
- package/doc/pages/pointers.md +75 -0
- package/doc/static/koffi.css +3 -2
- package/index.js +35 -9
- package/indirect.js +25 -9
- package/package.json +2 -2
- package/src/cnoke/src/tools.js +6 -0
- package/src/core/libcc/libcc.hh +3 -1
- package/src/koffi/CMakeLists.txt +2 -0
- package/src/koffi/src/abi_loong64.cc +23 -0
- package/src/koffi/src/abi_loong64_asm.S +240 -0
- package/src/koffi/src/abi_riscv64.cc +2 -2
- package/src/koffi/src/ffi.cc +39 -0
- package/src/koffi/src/ffi.hh +1 -1
- package/src/koffi/src/util.hh +21 -5
- package/build/koffi/linux_riscv64/koffi.node +0 -0
package/doc/pages/pointers.md
CHANGED
|
@@ -248,6 +248,81 @@ Disposable types can only be created from pointer or string types.
|
|
|
248
248
|
> [!WARNING]
|
|
249
249
|
> Be careful on Windows: if your shared library uses a different CRT (such as msvcrt), the memory could have been allocated by a different malloc/free implementation or heap, resulting in undefined behavior if you use `koffi.free()`.
|
|
250
250
|
|
|
251
|
+
# External buffers (views)
|
|
252
|
+
|
|
253
|
+
*New in Koffi 2.11.0*
|
|
254
|
+
|
|
255
|
+
You can access unmanaged memory with `koffi.view(ptr, len)`. This function takes a pointer and a length, and creates an ArrayBuffer through which you can access the underlying memory without copy.
|
|
256
|
+
|
|
257
|
+
> [!NOTE]
|
|
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
|
+
|
|
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
|
+
|
|
251
326
|
# Unwrap pointers
|
|
252
327
|
|
|
253
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/doc/static/koffi.css
CHANGED
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
You should have received a copy of the GNU General Public License
|
|
14
14
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
15
15
|
|
|
16
|
-
@import url('../
|
|
16
|
+
@import url('../flat/flat.css');
|
|
17
17
|
@import url('../../../vendor/highlight.js/styles/base16/tomorrow.css');
|
|
18
18
|
|
|
19
19
|
html {
|
|
20
|
-
--
|
|
20
|
+
--top_color: #ec7400;
|
|
21
|
+
--anchor_color: #ec7400;
|
|
21
22
|
}
|
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
|
-
//
|
|
7
|
+
// package/src/cnoke/src/tools.js
|
|
8
8
|
var require_tools = __commonJS({
|
|
9
|
-
"
|
|
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
|
-
//
|
|
377
|
+
// package/src/koffi/package.json
|
|
362
378
|
var require_package = __commonJS({
|
|
363
|
-
"
|
|
379
|
+
"package/src/koffi/package.json"(exports2, module2) {
|
|
364
380
|
module2.exports = {
|
|
365
381
|
name: "koffi",
|
|
366
|
-
version: "2.
|
|
367
|
-
stable: "2.
|
|
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
|
-
//
|
|
427
|
+
// package/src/koffi/src/init.js
|
|
412
428
|
var require_init = __commonJS({
|
|
413
|
-
"
|
|
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
|
-
//
|
|
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
|
-
//
|
|
7
|
+
// package/src/cnoke/src/tools.js
|
|
8
8
|
var require_tools = __commonJS({
|
|
9
|
-
"
|
|
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
|
-
//
|
|
377
|
+
// package/src/koffi/package.json
|
|
362
378
|
var require_package = __commonJS({
|
|
363
|
-
"
|
|
379
|
+
"package/src/koffi/package.json"(exports2, module2) {
|
|
364
380
|
module2.exports = {
|
|
365
381
|
name: "koffi",
|
|
366
|
-
version: "2.
|
|
367
|
-
stable: "2.
|
|
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
|
-
//
|
|
427
|
+
// package/src/koffi/src/init.js
|
|
412
428
|
var require_init = __commonJS({
|
|
413
|
-
"
|
|
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
|
-
//
|
|
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
package/src/cnoke/src/tools.js
CHANGED
|
@@ -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
|
|
package/src/core/libcc/libcc.hh
CHANGED
|
@@ -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, ...) \
|
package/src/koffi/CMakeLists.txt
CHANGED
|
@@ -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;
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -2107,6 +2107,44 @@ static Napi::Value EncodeValue(const Napi::CallbackInfo &info)
|
|
|
2107
2107
|
return env.Undefined();
|
|
2108
2108
|
}
|
|
2109
2109
|
|
|
2110
|
+
static Napi::Value CreateView(const Napi::CallbackInfo &info)
|
|
2111
|
+
{
|
|
2112
|
+
Napi::Env env = info.Env();
|
|
2113
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
2114
|
+
|
|
2115
|
+
if (info.Length() < 1) {
|
|
2116
|
+
ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
|
|
2117
|
+
return env.Null();
|
|
2118
|
+
}
|
|
2119
|
+
if (!info[1].IsNumber()) {
|
|
2120
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for length, expected integer", GetValueType(instance, info[1]));
|
|
2121
|
+
return env.Null();
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
void *ptr = nullptr;
|
|
2125
|
+
if (!GetExternalPointer(env, info[0], &ptr))
|
|
2126
|
+
return env.Null();
|
|
2127
|
+
Size len = (Size)info[1].As<Napi::Number>().Int64Value();
|
|
2128
|
+
|
|
2129
|
+
if (len < 0) {
|
|
2130
|
+
ThrowError<Napi::TypeError>(env, "Array length must be positive and non-zero");
|
|
2131
|
+
return env.Null();
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
if (len) {
|
|
2135
|
+
Napi::ArrayBuffer view = Napi::ArrayBuffer::New(env, ptr, (size_t)len);
|
|
2136
|
+
|
|
2137
|
+
if (!view.ByteLength()) {
|
|
2138
|
+
ThrowError<Napi::Error>(env, "This runtime does not support external buffers");
|
|
2139
|
+
return env.Null();
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
return view;
|
|
2143
|
+
} else {
|
|
2144
|
+
return Napi::ArrayBuffer::New(env, 0);
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2110
2148
|
static Napi::Value ResetKoffi(const Napi::CallbackInfo &info)
|
|
2111
2149
|
{
|
|
2112
2150
|
Napi::Env env = info.Env();
|
|
@@ -2364,6 +2402,7 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2364
2402
|
exports.Set("address", Napi::Function::New(env, GetPointerAddress, "address"));
|
|
2365
2403
|
exports.Set("call", Napi::Function::New(env, CallPointerSync, "call"));
|
|
2366
2404
|
exports.Set("encode", Napi::Function::New(env, EncodeValue, "encode"));
|
|
2405
|
+
exports.Set("view", Napi::Function::New(env, CreateView, "view"));
|
|
2367
2406
|
|
|
2368
2407
|
exports.Set("reset", Napi::Function::New(env, ResetKoffi, "reset"));
|
|
2369
2408
|
|
package/src/koffi/src/ffi.hh
CHANGED
|
@@ -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;
|