koffi 0.9.26 → 0.9.29
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/README.md +28 -28
- package/benchmark/CMakeLists.txt +15 -4
- package/benchmark/atoi_cc.cc +6 -9
- package/benchmark/atoi_koffi.js +10 -9
- package/benchmark/atoi_napi.cc +15 -9
- package/benchmark/atoi_napi.js +9 -8
- package/benchmark/atoi_node_ffi.js +9 -9
- package/benchmark/raylib_cc.cc +7 -10
- package/benchmark/raylib_koffi.js +11 -10
- package/benchmark/raylib_node_ffi.js +11 -10
- package/package.json +2 -2
- package/src/call_arm32.cc +2 -2
- package/src/call_arm32_fwd.S +12 -12
- package/src/ffi.cc +24 -11
- package/src/ffi.hh +1 -0
- package/src/util.cc +22 -11
- package/src/util.hh +6 -3
- package/test/CMakeLists.txt +4 -0
- package/test/registry/machines.json +10 -30
- package/test/tests/misc.c +47 -2
- package/test/tests/misc.js +56 -20
- package/test/tests/raylib.js +1 -1
- package/test/tests/sqlite.js +1 -1
- package/vendor/sqlite3/shell.c +31 -22
- package/vendor/sqlite3/sqlite3.c +329 -132
- package/vendor/sqlite3/sqlite3.h +10 -6
- package/benchmark/raylib_cc.exe +0 -0
package/README.md
CHANGED
|
@@ -261,84 +261,84 @@ At this stage, two benchmarks are implemented:
|
|
|
261
261
|
|
|
262
262
|
In order to run it, go to `koffi/benchmark` and run `../../cnoke/cnoke.js` (or `node ..\..\cnoke\cnoke.js` on Windows) before doing anything else.
|
|
263
263
|
|
|
264
|
-
Once this is done, you can execute each implementation, e.g. `build/atoi_cc
|
|
264
|
+
Once this is done, you can execute each implementation, e.g. `build/atoi_cc` or `./atoi_koffi.js`. You can optionally define a custom number of iterations, e.g. `./atoi_koffi.js 10000000`.
|
|
265
265
|
|
|
266
266
|
## atoi results
|
|
267
267
|
|
|
268
|
-
Here are some results from 2022-04-24 on my
|
|
268
|
+
Here are some results from 2022-04-24 on Linux on my machine (AMD® Ryzen™ 7 5800H 16G):
|
|
269
269
|
|
|
270
270
|
```sh
|
|
271
|
-
$ build/atoi_cc
|
|
271
|
+
$ build/atoi_cc
|
|
272
272
|
Iterations: 20000000
|
|
273
273
|
Time: 0.24s
|
|
274
274
|
|
|
275
|
-
$ ./atoi_napi.js
|
|
275
|
+
$ ./atoi_napi.js
|
|
276
276
|
Iterations: 20000000
|
|
277
|
-
Time: 1.
|
|
277
|
+
Time: 1.10s
|
|
278
278
|
|
|
279
|
-
$ ./atoi_koffi.js
|
|
279
|
+
$ ./atoi_koffi.js
|
|
280
280
|
Iterations: 20000000
|
|
281
|
-
Time:
|
|
281
|
+
Time: 1.91s
|
|
282
282
|
|
|
283
283
|
# Note: the Node-FFI version does a few setTimeout calls to force the GC to run (around 20
|
|
284
284
|
# for the example below), without which Node will consume all memory because the GC never appears
|
|
285
285
|
# to run, or not enough. It's not ideal but on the other hand it counts as another limitation
|
|
286
286
|
# to Node-FFI performance.
|
|
287
|
-
$ ./atoi_node_ffi.js
|
|
287
|
+
$ ./atoi_node_ffi.js
|
|
288
288
|
Iterations: 20000000
|
|
289
289
|
Time: 640.49s
|
|
290
290
|
```
|
|
291
291
|
|
|
292
|
-
And on
|
|
292
|
+
And on Windows on the same machine (AMD® Ryzen™ 7 5800H 16G):
|
|
293
293
|
|
|
294
294
|
```sh
|
|
295
|
-
$ build\atoi_cc.exe
|
|
295
|
+
$ build\atoi_cc.exe
|
|
296
296
|
Iterations: 20000000
|
|
297
|
-
Time: 0.
|
|
297
|
+
Time: 0.25s
|
|
298
298
|
|
|
299
|
-
$ node atoi_napi.js
|
|
299
|
+
$ node atoi_napi.js
|
|
300
300
|
Iterations: 20000000
|
|
301
|
-
Time:
|
|
301
|
+
Time: 1.94s
|
|
302
302
|
|
|
303
|
-
$ node atoi_koffi.js
|
|
303
|
+
$ node atoi_koffi.js
|
|
304
304
|
Iterations: 20000000
|
|
305
|
-
Time:
|
|
305
|
+
Time: 3.15s
|
|
306
306
|
|
|
307
|
-
$ node atoi_node_ffi.js
|
|
307
|
+
$ node atoi_node_ffi.js
|
|
308
308
|
Iterations: 20000000
|
|
309
|
-
Time:
|
|
309
|
+
Time: 267.20s
|
|
310
310
|
```
|
|
311
311
|
|
|
312
312
|
## Raylib results
|
|
313
313
|
|
|
314
|
-
Here are some results from 2022-04-24 on my
|
|
314
|
+
Here are some results from 2022-04-24 on Linux on my machine (AMD® Ryzen™ 7 5800H 16G):
|
|
315
315
|
|
|
316
316
|
```sh
|
|
317
|
-
$ build/raylib_cc
|
|
317
|
+
$ build/raylib_cc
|
|
318
318
|
Iterations: 100
|
|
319
319
|
Time: 4.14s
|
|
320
320
|
|
|
321
|
-
$ ./raylib_koffi.js
|
|
321
|
+
$ ./raylib_koffi.js
|
|
322
322
|
Iterations: 100
|
|
323
323
|
Time: 6.25s
|
|
324
324
|
|
|
325
|
-
$ ./raylib_node_ffi.js
|
|
325
|
+
$ ./raylib_node_ffi.js
|
|
326
326
|
Iterations: 100
|
|
327
327
|
Time: 27.13s
|
|
328
328
|
```
|
|
329
329
|
|
|
330
|
-
And on
|
|
330
|
+
And on Windows on the same machine (AMD® Ryzen™ 7 5800H 16G):
|
|
331
331
|
|
|
332
332
|
```sh
|
|
333
|
-
$ build\raylib_cc.exe
|
|
333
|
+
$ build\raylib_cc.exe
|
|
334
334
|
Iterations: 100
|
|
335
|
-
Time:
|
|
335
|
+
Time: 8.39s
|
|
336
336
|
|
|
337
|
-
$ node raylib_koffi.js
|
|
337
|
+
$ node raylib_koffi.js
|
|
338
338
|
Iterations: 100
|
|
339
|
-
Time:
|
|
339
|
+
Time: 11.51s
|
|
340
340
|
|
|
341
|
-
$ node raylib_node_ffi.js
|
|
341
|
+
$ node raylib_node_ffi.js
|
|
342
342
|
Iterations: 100
|
|
343
|
-
Time:
|
|
343
|
+
Time: 32.47s
|
|
344
344
|
```
|
package/benchmark/CMakeLists.txt
CHANGED
|
@@ -16,15 +16,21 @@ project(koffi C CXX ASM)
|
|
|
16
16
|
|
|
17
17
|
find_package(CNoke)
|
|
18
18
|
|
|
19
|
-
set(CMAKE_CXX_STANDARD
|
|
19
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
|
22
|
+
find_package(Threads REQUIRED)
|
|
23
|
+
|
|
24
|
+
if(NOT TARGET koffi)
|
|
25
|
+
add_subdirectory(.. koffi)
|
|
26
|
+
endif()
|
|
22
27
|
add_subdirectory(../test test)
|
|
23
28
|
|
|
24
29
|
# ---- atoi ----
|
|
25
30
|
|
|
26
31
|
add_executable(atoi_cc atoi_cc.cc ../vendor/libcc/libcc.cc)
|
|
27
32
|
target_include_directories(atoi_cc PRIVATE ..)
|
|
33
|
+
target_link_libraries(atoi_cc PRIVATE Threads::Threads)
|
|
28
34
|
|
|
29
35
|
if(WIN32)
|
|
30
36
|
target_compile_definitions(atoi_cc PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
|
|
@@ -33,19 +39,24 @@ endif()
|
|
|
33
39
|
|
|
34
40
|
add_node_addon(NAME atoi_napi SOURCES atoi_napi.cc ../vendor/libcc/libcc.cc)
|
|
35
41
|
target_include_directories(atoi_napi PRIVATE .. ../vendor/node-addon-api)
|
|
42
|
+
target_link_libraries(atoi_napi PRIVATE Threads::Threads)
|
|
36
43
|
|
|
37
44
|
if(WIN32)
|
|
38
45
|
target_compile_definitions(atoi_napi PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
|
|
39
46
|
target_link_libraries(atoi_napi PRIVATE ws2_32)
|
|
47
|
+
else()
|
|
48
|
+
target_link_libraries(atoi_napi PRIVATE dl)
|
|
40
49
|
endif()
|
|
41
50
|
|
|
42
51
|
# ---- Raylib ----
|
|
43
52
|
|
|
44
|
-
add_executable(raylib_cc
|
|
53
|
+
add_executable(raylib_cc raylib_cc.cc ../vendor/libcc/libcc.cc)
|
|
45
54
|
target_include_directories(raylib_cc PRIVATE ..)
|
|
46
|
-
|
|
55
|
+
target_link_libraries(raylib_cc PRIVATE Threads::Threads raylib)
|
|
47
56
|
|
|
48
57
|
if(WIN32)
|
|
49
58
|
target_compile_definitions(raylib_cc PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
|
|
50
59
|
target_link_libraries(raylib_cc PRIVATE ws2_32)
|
|
60
|
+
else()
|
|
61
|
+
target_link_libraries(raylib_cc PRIVATE dl)
|
|
51
62
|
endif()
|
package/benchmark/atoi_cc.cc
CHANGED
|
@@ -25,21 +25,18 @@ volatile uint64_t sum = 0;
|
|
|
25
25
|
|
|
26
26
|
int Main(int argc, char **argv)
|
|
27
27
|
{
|
|
28
|
-
|
|
29
|
-
LogError("Missing number of iterations");
|
|
30
|
-
LogInfo("Usage: atoi_cc <iterations>");
|
|
31
|
-
return 1;
|
|
32
|
-
}
|
|
28
|
+
int iterations = 20000000;
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
if (argc >= 2) {
|
|
31
|
+
if (!ParseInt(argv[1], &iterations))
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
37
34
|
LogInfo("Iterations: %1", iterations);
|
|
38
35
|
|
|
39
36
|
int64_t start = GetMonotonicTime();
|
|
40
37
|
|
|
41
38
|
for (int i = 0; i < iterations; i++) {
|
|
42
|
-
sum
|
|
39
|
+
sum = sum + (uint64_t)atoi(strings[i % RG_LEN(strings)]);
|
|
43
40
|
}
|
|
44
41
|
|
|
45
42
|
// Help prevent optimisation of loop
|
package/benchmark/atoi_koffi.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// You should have received a copy of the GNU Affero General Public License
|
|
14
14
|
// along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
15
|
|
|
16
|
-
const koffi = require('
|
|
16
|
+
const koffi = require('./build/koffi.node');
|
|
17
17
|
|
|
18
18
|
const strings = [
|
|
19
19
|
'424242',
|
|
@@ -26,14 +26,15 @@ let sum = 0;
|
|
|
26
26
|
main();
|
|
27
27
|
|
|
28
28
|
function main() {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
let iterations = 20000000;
|
|
30
|
+
|
|
31
|
+
if (process.argv.length >= 3) {
|
|
32
|
+
iterations = parseInt(process.argv[2], 10);
|
|
33
|
+
if (Number.isNaN(iterations))
|
|
34
|
+
throw new Error('Not a valid number');
|
|
35
|
+
if (iterations < 1)
|
|
36
|
+
throw new Error('Value must be positive');
|
|
37
|
+
}
|
|
37
38
|
console.log('Iterations:', iterations);
|
|
38
39
|
|
|
39
40
|
let lib = koffi.load(process.platform == 'win32' ? 'msvcrt.dll' : null);
|
package/benchmark/atoi_napi.cc
CHANGED
|
@@ -30,20 +30,26 @@ static Napi::Value RunAtoi(const Napi::CallbackInfo &info)
|
|
|
30
30
|
{
|
|
31
31
|
Napi::Env env = info.Env();
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
#if 0
|
|
35
|
-
if (info.Length() < 1) {
|
|
33
|
+
if (RG_UNLIKELY(info.Length() < 1)) {
|
|
36
34
|
ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
|
|
37
35
|
return env.Null();
|
|
38
36
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
|
|
38
|
+
char str[64];
|
|
39
|
+
{
|
|
40
|
+
napi_status status = napi_get_value_string_utf8(env, info[0], str, RG_SIZE(str), nullptr);
|
|
41
|
+
|
|
42
|
+
if (RG_UNLIKELY(status != napi_ok)) {
|
|
43
|
+
if (status == napi_string_expected) {
|
|
44
|
+
ThrowError<Napi::TypeError>(env, "Unexpected value for str, expected string");
|
|
45
|
+
} else {
|
|
46
|
+
ThrowError<Napi::TypeError>(env, "Failed to read JS string");
|
|
47
|
+
}
|
|
48
|
+
return env.Null();
|
|
49
|
+
}
|
|
42
50
|
}
|
|
43
|
-
#endif
|
|
44
51
|
|
|
45
|
-
|
|
46
|
-
int value = atoi(name.c_str());
|
|
52
|
+
int value = atoi(str);
|
|
47
53
|
|
|
48
54
|
return Napi::Number::New(env, value);
|
|
49
55
|
}
|
package/benchmark/atoi_napi.js
CHANGED
|
@@ -26,14 +26,15 @@ let sum = 0;
|
|
|
26
26
|
main();
|
|
27
27
|
|
|
28
28
|
function main() {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
let iterations = 20000000;
|
|
30
|
+
|
|
31
|
+
if (process.argv.length >= 3) {
|
|
32
|
+
iterations = parseInt(process.argv[2], 10);
|
|
33
|
+
if (Number.isNaN(iterations))
|
|
34
|
+
throw new Error('Not a valid number');
|
|
35
|
+
if (iterations < 1)
|
|
36
|
+
throw new Error('Value must be positive');
|
|
37
|
+
}
|
|
37
38
|
console.log('Iterations:', iterations);
|
|
38
39
|
|
|
39
40
|
let start = performance.now();
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
const ref = require('ref-napi');
|
|
17
17
|
const ffi = require('ffi-napi');
|
|
18
18
|
const struct = require('ref-struct-di')(ref);
|
|
19
|
-
const path = require('path');
|
|
20
19
|
|
|
21
20
|
const strings = [
|
|
22
21
|
'424242',
|
|
@@ -29,14 +28,15 @@ let sum = 0;
|
|
|
29
28
|
main();
|
|
30
29
|
|
|
31
30
|
async function main() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
let iterations = 20000000;
|
|
32
|
+
|
|
33
|
+
if (process.argv.length >= 3) {
|
|
34
|
+
iterations = parseInt(process.argv[2], 10);
|
|
35
|
+
if (Number.isNaN(iterations))
|
|
36
|
+
throw new Error('Not a valid number');
|
|
37
|
+
if (iterations < 1)
|
|
38
|
+
throw new Error('Value must be positive');
|
|
39
|
+
}
|
|
40
40
|
console.log('Iterations:', iterations);
|
|
41
41
|
|
|
42
42
|
const lib = ffi.Library(process.platform == 'win32' ? 'msvcrt.dll' : null, {
|
package/benchmark/raylib_cc.cc
CHANGED
|
@@ -18,15 +18,12 @@ namespace RG {
|
|
|
18
18
|
|
|
19
19
|
int Main(int argc, char **argv)
|
|
20
20
|
{
|
|
21
|
-
|
|
22
|
-
LogError("Missing number of iterations");
|
|
23
|
-
LogInfo("Usage: raylib_cc <iterations>");
|
|
24
|
-
return 1;
|
|
25
|
-
}
|
|
21
|
+
int iterations = 100;
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
if (argc >= 2) {
|
|
24
|
+
if (!ParseInt(argv[1], &iterations))
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
30
27
|
LogInfo("Iterations: %1", iterations);
|
|
31
28
|
|
|
32
29
|
// We need to call InitWindow before using anything else (such as fonts)
|
|
@@ -34,13 +31,13 @@ int Main(int argc, char **argv)
|
|
|
34
31
|
SetWindowState(FLAG_WINDOW_HIDDEN);
|
|
35
32
|
InitWindow(640, 480, "Raylib Test");
|
|
36
33
|
|
|
37
|
-
Image img = GenImageColor(800, 600,
|
|
34
|
+
Image img = GenImageColor(800, 600, Color { .r = 0, .g = 0, .b = 0, .a = 255 });
|
|
38
35
|
Font font = GetFontDefault();
|
|
39
36
|
|
|
40
37
|
int64_t start = GetMonotonicTime();
|
|
41
38
|
|
|
42
39
|
for (int i = 0; i < iterations; i++) {
|
|
43
|
-
ImageClearBackground(&img,
|
|
40
|
+
ImageClearBackground(&img, Color { .r = 0, .g = 0, .b = 0, .a = 255 });
|
|
44
41
|
|
|
45
42
|
for (int j = 0; j < 3600; j++) {
|
|
46
43
|
const char *text = "Hello World!";
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// You should have received a copy of the GNU Affero General Public License
|
|
14
14
|
// along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
15
|
|
|
16
|
-
const koffi = require('
|
|
16
|
+
const koffi = require('./build/koffi.node');
|
|
17
17
|
const path = require('path');
|
|
18
18
|
|
|
19
19
|
const Color = koffi.struct('Color', {
|
|
@@ -71,17 +71,18 @@ const Font = koffi.struct('Font', {
|
|
|
71
71
|
main();
|
|
72
72
|
|
|
73
73
|
function main() {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
let iterations = 100;
|
|
75
|
+
|
|
76
|
+
if (process.argv.length >= 3) {
|
|
77
|
+
iterations = parseInt(process.argv[2], 10);
|
|
78
|
+
if (Number.isNaN(iterations))
|
|
79
|
+
throw new Error('Not a valid number');
|
|
80
|
+
if (iterations < 1)
|
|
81
|
+
throw new Error('Value must be positive');
|
|
82
|
+
}
|
|
82
83
|
console.log('Iterations:', iterations);
|
|
83
84
|
|
|
84
|
-
let lib_filename = path.dirname(__filename) + '
|
|
85
|
+
let lib_filename = path.dirname(__filename) + '/build/raylib' + koffi.extension;
|
|
85
86
|
let lib = koffi.load(lib_filename);
|
|
86
87
|
|
|
87
88
|
const InitWindow = lib.cdecl('InitWindow', 'void', ['int', 'int', 'string']);
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
const ref = require('ref-napi');
|
|
17
17
|
const ffi = require('ffi-napi');
|
|
18
18
|
const struct = require('ref-struct-di')(ref);
|
|
19
|
-
const koffi = require('
|
|
19
|
+
const koffi = require('./build/koffi.node');
|
|
20
20
|
const path = require('path');
|
|
21
21
|
|
|
22
22
|
const Color = struct({
|
|
@@ -87,17 +87,18 @@ const Font = struct({
|
|
|
87
87
|
main();
|
|
88
88
|
|
|
89
89
|
function main() {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
90
|
+
let iterations = 100;
|
|
91
|
+
|
|
92
|
+
if (process.argv.length >= 3) {
|
|
93
|
+
iterations = parseInt(process.argv[2], 10);
|
|
94
|
+
if (Number.isNaN(iterations))
|
|
95
|
+
throw new Error('Not a valid number');
|
|
96
|
+
if (iterations < 1)
|
|
97
|
+
throw new Error('Value must be positive');
|
|
98
|
+
}
|
|
98
99
|
console.log('Iterations:', iterations);
|
|
99
100
|
|
|
100
|
-
let lib_filename = path.dirname(__filename) + '
|
|
101
|
+
let lib_filename = path.dirname(__filename) + '/build/raylib' + koffi.extension;
|
|
101
102
|
|
|
102
103
|
const r = ffi.Library(lib_filename, {
|
|
103
104
|
InitWindow: ['void', ['int', 'int', 'string']],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koffi",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.29",
|
|
4
4
|
"description": "Fast and simple FFI (foreign function interface) for Node.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"foreign",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"license": "AGPL-3.0",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"cnoke": "^0.
|
|
26
|
+
"cnoke": "^1.0.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"chalk": "^4.1.2",
|
package/src/call_arm32.cc
CHANGED
|
@@ -233,10 +233,10 @@ static Napi::Value TranslateCall(const Napi::CallbackInfo &info)
|
|
|
233
233
|
// Return through registers unless it's too big
|
|
234
234
|
if (RG_UNLIKELY(!call.AllocStack(func->args_size, 16, &args_ptr)))
|
|
235
235
|
return env.Null();
|
|
236
|
-
if (RG_UNLIKELY(!call.AllocStack(4 * 4, 8, &gpr_ptr)))
|
|
237
|
-
return env.Null();
|
|
238
236
|
if (RG_UNLIKELY(!call.AllocStack(8 * 8, 8, &vec_ptr)))
|
|
239
237
|
return env.Null();
|
|
238
|
+
if (RG_UNLIKELY(!call.AllocStack(4 * 4, 8, &gpr_ptr)))
|
|
239
|
+
return env.Null();
|
|
240
240
|
if (func->ret.use_memory) {
|
|
241
241
|
if (RG_UNLIKELY(!call.AllocHeap(func->ret.type->size, 16, &return_ptr)))
|
|
242
242
|
return env.Null();
|
package/src/call_arm32_fwd.S
CHANGED
|
@@ -56,22 +56,22 @@
|
|
|
56
56
|
|
|
57
57
|
// Prepare general purpose argument registers from array passed by caller.
|
|
58
58
|
.macro forward_int
|
|
59
|
-
ldr r3, [r1,
|
|
60
|
-
ldr r2, [r1,
|
|
61
|
-
ldr r0, [r1,
|
|
62
|
-
ldr r1, [r1,
|
|
59
|
+
ldr r3, [r1, 12]
|
|
60
|
+
ldr r2, [r1, 8]
|
|
61
|
+
ldr r0, [r1, 0]
|
|
62
|
+
ldr r1, [r1, 4]
|
|
63
63
|
.endm
|
|
64
64
|
|
|
65
65
|
// Prepare vector argument registers from array passed by caller.
|
|
66
66
|
.macro forward_vec
|
|
67
|
-
vldr d7, [r1,
|
|
68
|
-
vldr d6, [r1,
|
|
69
|
-
vldr d5, [r1,
|
|
70
|
-
vldr d4, [r1,
|
|
71
|
-
vldr d3, [r1,
|
|
72
|
-
vldr d2, [r1,
|
|
73
|
-
vldr d1, [r1,
|
|
74
|
-
vldr d0, [r1,
|
|
67
|
+
vldr d7, [r1, 72]
|
|
68
|
+
vldr d6, [r1, 64]
|
|
69
|
+
vldr d5, [r1, 56]
|
|
70
|
+
vldr d4, [r1, 48]
|
|
71
|
+
vldr d3, [r1, 40]
|
|
72
|
+
vldr d2, [r1, 32]
|
|
73
|
+
vldr d1, [r1, 24]
|
|
74
|
+
vldr d0, [r1, 16]
|
|
75
75
|
.endm
|
|
76
76
|
|
|
77
77
|
ForwardCallGG:
|
package/src/ffi.cc
CHANGED
|
@@ -75,20 +75,20 @@ static const TypeInfo *ResolveType(const InstanceData *instance, Napi::Value val
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
static Napi::Value CreateStructType(const Napi::CallbackInfo &info)
|
|
78
|
+
static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
79
79
|
{
|
|
80
80
|
Napi::Env env = info.Env();
|
|
81
81
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
82
82
|
|
|
83
|
-
if (info.Length() <
|
|
84
|
-
ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
|
|
83
|
+
if (info.Length() < 1) {
|
|
84
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
|
|
85
85
|
return env.Null();
|
|
86
86
|
}
|
|
87
|
-
if (!info[0].IsString()) {
|
|
87
|
+
if (info.Length() > 1 && !info[0].IsString()) {
|
|
88
88
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
89
89
|
return env.Null();
|
|
90
90
|
}
|
|
91
|
-
if (!IsObject(info[1])) {
|
|
91
|
+
if (!IsObject(info[info.Length() > 1])) {
|
|
92
92
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for members, expected object", GetValueType(instance, info[1]));
|
|
93
93
|
return env.Null();
|
|
94
94
|
}
|
|
@@ -96,8 +96,8 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info)
|
|
|
96
96
|
TypeInfo *type = instance->types.AppendDefault();
|
|
97
97
|
RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
|
|
98
98
|
|
|
99
|
-
std::string name = info[0].As<Napi::String>();
|
|
100
|
-
Napi::Object obj = info[1].As<Napi::Object>();
|
|
99
|
+
std::string name = info.Length() > 1 ? info[0].As<Napi::String>() : std::string("<anonymous>");
|
|
100
|
+
Napi::Object obj = info[info.Length() > 1].As<Napi::Object>();
|
|
101
101
|
Napi::Array keys = obj.GetPropertyNames();
|
|
102
102
|
|
|
103
103
|
type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
|
|
@@ -116,8 +116,10 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info)
|
|
|
116
116
|
if (!member.type)
|
|
117
117
|
return env.Null();
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
member.align = pad ? member.type->align : 1;
|
|
120
|
+
|
|
121
|
+
type->size = (int16_t)(AlignLen(type->size, member.align) + member.type->size);
|
|
122
|
+
type->align = std::max(type->align, member.align);
|
|
121
123
|
|
|
122
124
|
type->members.Append(member);
|
|
123
125
|
}
|
|
@@ -125,7 +127,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info)
|
|
|
125
127
|
type->size = (int16_t)AlignLen(type->size, type->align);
|
|
126
128
|
|
|
127
129
|
// If the insert succeeds, we cannot fail anymore
|
|
128
|
-
if (!instance->types_map.TrySet(type).second) {
|
|
130
|
+
if (info.Length() > 1 && !instance->types_map.TrySet(type).second) {
|
|
129
131
|
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
130
132
|
return env.Null();
|
|
131
133
|
}
|
|
@@ -137,6 +139,16 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info)
|
|
|
137
139
|
return external;
|
|
138
140
|
}
|
|
139
141
|
|
|
142
|
+
static Napi::Value CreatePaddedStructType(const Napi::CallbackInfo &info)
|
|
143
|
+
{
|
|
144
|
+
return CreateStructType(info, true);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static Napi::Value CreatePackedStructType(const Napi::CallbackInfo &info)
|
|
148
|
+
{
|
|
149
|
+
return CreateStructType(info, false);
|
|
150
|
+
}
|
|
151
|
+
|
|
140
152
|
static Napi::Value CreateHandleType(const Napi::CallbackInfo &info)
|
|
141
153
|
{
|
|
142
154
|
Napi::Env env = info.Env();
|
|
@@ -564,7 +576,8 @@ InstanceData::InstanceData()
|
|
|
564
576
|
template <typename Func>
|
|
565
577
|
static void SetExports(Napi::Env env, Func func)
|
|
566
578
|
{
|
|
567
|
-
func("struct", Napi::Function::New(env,
|
|
579
|
+
func("struct", Napi::Function::New(env, CreatePaddedStructType));
|
|
580
|
+
func("pack", Napi::Function::New(env, CreatePackedStructType));
|
|
568
581
|
func("handle", Napi::Function::New(env, CreateHandleType));
|
|
569
582
|
func("pointer", Napi::Function::New(env, CreatePointerType));
|
|
570
583
|
func("load", Napi::Function::New(env, LoadSharedLibrary));
|
package/src/ffi.hh
CHANGED
package/src/util.cc
CHANGED
|
@@ -82,20 +82,31 @@ const char *CallData::PushString(const Napi::Value &value)
|
|
|
82
82
|
RG_ASSERT(value.IsString());
|
|
83
83
|
|
|
84
84
|
Napi::Env env = value.Env();
|
|
85
|
-
napi_status status;
|
|
86
85
|
|
|
86
|
+
Span<char> buf;
|
|
87
87
|
size_t len = 0;
|
|
88
|
-
status
|
|
88
|
+
napi_status status;
|
|
89
|
+
|
|
90
|
+
buf.ptr = (char *)heap_mem->ptr;
|
|
91
|
+
buf.len = std::max((Size)0, heap_mem->len - Kibibytes(32));
|
|
92
|
+
|
|
93
|
+
status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
89
94
|
RG_ASSERT(status == napi_ok);
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
|
|
96
|
+
len++;
|
|
97
|
+
|
|
98
|
+
if (RG_LIKELY(len < (size_t)buf.len)) {
|
|
99
|
+
heap_mem->ptr += (Size)len;
|
|
100
|
+
heap_mem->len -= (Size)len;
|
|
101
|
+
} else {
|
|
102
|
+
status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
|
|
103
|
+
RG_ASSERT(status == napi_ok);
|
|
104
|
+
|
|
105
|
+
buf.ptr = (char *)Allocator::Allocate(&big_alloc, (Size)len);
|
|
106
|
+
buf.len = (Size)len;
|
|
95
107
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return nullptr;
|
|
108
|
+
status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
109
|
+
RG_ASSERT(status == napi_ok);
|
|
99
110
|
}
|
|
100
111
|
|
|
101
112
|
return buf.ptr;
|
|
@@ -117,7 +128,7 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
117
128
|
return false;
|
|
118
129
|
}
|
|
119
130
|
|
|
120
|
-
dest = AlignUp(dest, member.
|
|
131
|
+
dest = AlignUp(dest, member.align);
|
|
121
132
|
|
|
122
133
|
switch (member.type->primitive) {
|
|
123
134
|
case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
|
|
@@ -214,7 +225,7 @@ void PopObject(Napi::Object obj, const uint8_t *ptr, const TypeInfo *type)
|
|
|
214
225
|
RG_ASSERT(type->primitive == PrimitiveKind::Record);
|
|
215
226
|
|
|
216
227
|
for (const RecordMember &member: type->members) {
|
|
217
|
-
ptr = AlignUp(ptr, member.
|
|
228
|
+
ptr = AlignUp(ptr, member.align);
|
|
218
229
|
|
|
219
230
|
switch (member.type->primitive) {
|
|
220
231
|
case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
|