koffi 2.2.3-beta.3 → 2.2.4

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 (51) hide show
  1. package/ChangeLog.md +23 -3
  2. package/doc/calls.md +277 -0
  3. package/doc/functions.md +17 -275
  4. package/doc/index.rst +3 -1
  5. package/doc/misc.md +97 -0
  6. package/doc/pointers.md +135 -0
  7. package/doc/types.md +3 -193
  8. package/package.json +2 -2
  9. package/src/koffi/build/2.2.4/koffi_darwin_arm64.tar.gz +0 -0
  10. package/src/koffi/build/2.2.4/koffi_darwin_x64.tar.gz +0 -0
  11. package/src/koffi/build/2.2.4/koffi_freebsd_arm64.tar.gz +0 -0
  12. package/src/koffi/build/2.2.4/koffi_freebsd_ia32.tar.gz +0 -0
  13. package/src/koffi/build/2.2.4/koffi_freebsd_x64.tar.gz +0 -0
  14. package/src/koffi/build/2.2.4/koffi_linux_arm32hf.tar.gz +0 -0
  15. package/src/koffi/build/2.2.4/koffi_linux_arm64.tar.gz +0 -0
  16. package/src/koffi/build/2.2.4/koffi_linux_ia32.tar.gz +0 -0
  17. package/src/koffi/build/2.2.4/koffi_linux_riscv64hf64.tar.gz +0 -0
  18. package/src/koffi/build/2.2.4/koffi_linux_x64.tar.gz +0 -0
  19. package/src/koffi/build/2.2.4/koffi_openbsd_ia32.tar.gz +0 -0
  20. package/src/koffi/build/2.2.4/koffi_openbsd_x64.tar.gz +0 -0
  21. package/src/koffi/build/2.2.4/koffi_win32_arm64.tar.gz +0 -0
  22. package/src/koffi/build/2.2.4/koffi_win32_ia32.tar.gz +0 -0
  23. package/src/koffi/build/2.2.4/koffi_win32_x64.tar.gz +0 -0
  24. package/src/koffi/src/abi_arm64.cc +39 -0
  25. package/src/koffi/src/abi_x64_sysv_fwd.S +9 -9
  26. package/src/koffi/src/abi_x64_win_fwd.asm +12 -12
  27. package/src/koffi/src/abi_x86_fwd.S +13 -13
  28. package/src/koffi/src/abi_x86_fwd.asm +11 -11
  29. package/src/koffi/src/ffi.cc +29 -52
  30. package/src/koffi/src/ffi.hh +0 -4
  31. package/src/koffi/test/CMakeLists.txt +7 -0
  32. package/src/koffi/test/win32.c +39 -0
  33. package/src/koffi/test/win32.js +70 -0
  34. package/src/koffi/tools/qemu.js +20 -9
  35. package/src/koffi/tools/registry/machines.json +10 -2
  36. package/doc/memory.md +0 -33
  37. package/src/koffi/build/2.2.3-beta.3/koffi_darwin_arm64.tar.gz +0 -0
  38. package/src/koffi/build/2.2.3-beta.3/koffi_darwin_x64.tar.gz +0 -0
  39. package/src/koffi/build/2.2.3-beta.3/koffi_freebsd_arm64.tar.gz +0 -0
  40. package/src/koffi/build/2.2.3-beta.3/koffi_freebsd_ia32.tar.gz +0 -0
  41. package/src/koffi/build/2.2.3-beta.3/koffi_freebsd_x64.tar.gz +0 -0
  42. package/src/koffi/build/2.2.3-beta.3/koffi_linux_arm32hf.tar.gz +0 -0
  43. package/src/koffi/build/2.2.3-beta.3/koffi_linux_arm64.tar.gz +0 -0
  44. package/src/koffi/build/2.2.3-beta.3/koffi_linux_ia32.tar.gz +0 -0
  45. package/src/koffi/build/2.2.3-beta.3/koffi_linux_riscv64hf64.tar.gz +0 -0
  46. package/src/koffi/build/2.2.3-beta.3/koffi_linux_x64.tar.gz +0 -0
  47. package/src/koffi/build/2.2.3-beta.3/koffi_openbsd_ia32.tar.gz +0 -0
  48. package/src/koffi/build/2.2.3-beta.3/koffi_openbsd_x64.tar.gz +0 -0
  49. package/src/koffi/build/2.2.3-beta.3/koffi_win32_arm64.tar.gz +0 -0
  50. package/src/koffi/build/2.2.3-beta.3/koffi_win32_ia32.tar.gz +0 -0
  51. package/src/koffi/build/2.2.3-beta.3/koffi_win32_x64.tar.gz +0 -0
package/doc/misc.md ADDED
@@ -0,0 +1,97 @@
1
+ # Miscellaneous
2
+
3
+ ## Types
4
+
5
+ ### Introspection
6
+
7
+ *New in Koffi 2.0: `koffi.resolve()`, new in Koffi 2.2: `koffi.offsetof()`*
8
+
9
+ ```{note}
10
+ The value returned by `introspect()` has **changed in version 2.0 and in version 2.2**.
11
+
12
+ In Koffi 1.x, it could only be used with struct types and returned the object passed to koffi.struct() with the member names and types.
13
+
14
+ Starting in Koffi 2.2, each record member is exposed as an object containing the name, the type and the offset within the record.
15
+
16
+ Consult the [migration guide](changes.md) for more information.
17
+ ```
18
+
19
+ Use `koffi.introspect(type)` to get detailed information about a type: name, primitive, size, alignment, members (record types), reference type (array, pointer) and length (array).
20
+
21
+ ```js
22
+ const FoobarType = koffi.struct('FoobarType', {
23
+ a: 'int',
24
+ b: 'char *',
25
+ c: 'double'
26
+ });
27
+
28
+ console.log(koffi.introspect(FoobarType));
29
+
30
+ // Expected result on 64-bit machines:
31
+ // {
32
+ // name: 'FoobarType',
33
+ // primitive: 'Record',
34
+ // size: 24,
35
+ // alignment: 8,
36
+ // members: {
37
+ // a: { name: 'a', type: [External: 4b28a60], offset: 0 },
38
+ // b: { name: 'b', type: [External: 4b292e0], offset: 8 },
39
+ // c: { name: 'c', type: [External: 4b29260], offset: 16 }
40
+ // }
41
+ // }
42
+ ```
43
+
44
+ Koffi also exposes a few more utility functions to get a subset of this information:
45
+
46
+ - `koffi.sizeof(type)` to get the size of a type
47
+ - `koffi.alignof(type)` to get the alignment of a type
48
+ - `koffi.offsetof(type, member_name)` to get the offset of a record member
49
+ - `koffi.resolve(type)` to get the resolved type object from a type string
50
+
51
+ Just like before, you can refer to primitive types by their name or through `koffi.types`:
52
+
53
+ ```js
54
+ // These two lines do the same:
55
+ console.log(koffi.sizeof('long'));
56
+ console.log(koffi.sizeof(koffi.types.long));
57
+ ```
58
+
59
+ ### Aliases
60
+
61
+ *New in Koffi 2.0*
62
+
63
+ You can alias a type with `koffi.alias(name, type)`. Aliased types are completely equivalent.
64
+
65
+ ## Settings
66
+
67
+ ### Memory usage
68
+
69
+ For synchronous/normal calls, Koffi uses two preallocated memory blocks:
70
+
71
+ - One to construct the C stack and assign registers, subsequently used by the platform-specific assembly code (1 MiB by default)
72
+ - One to allocate strings and big objects/structs (2 MiB by default)
73
+
74
+ Unless very big strings or objects (at least more than one page of memory) are used, Koffi does not directly allocate any extra memory during calls or callbacks. However, please note that the JS engine (V8) might.
75
+
76
+ The size (in bytes) of these preallocated blocks can be changed. Use `koffi.config()` to get an object with the settings, and `koffi.config(obj)` to apply new settings.
77
+
78
+ ```js
79
+ let config = koffi.config();
80
+ console.log(config);
81
+ ```
82
+
83
+ The same is true for asynchronous calls. When an asynchronous call is made, Koffi will allocate new blocks unless there is an unused (resident) set of blocks still available. Once the asynchronous call is finished, these blocks are freed if there are more than `resident_async_pools` sets of blocks left around.
84
+
85
+ There cannot be more than `max_async_calls` running at the same time.
86
+
87
+ ### Default settings
88
+
89
+ Setting | Default | Description
90
+ -------------------- | ------- | -----------------------------------------------
91
+ sync_stack_size | 1 MiB | Stack size for synchronous calls
92
+ sync_heap_size | 2 MiB | Heap size for synchronous calls
93
+ async_stack_size | 256 kiB | Stack size for asynchronous calls
94
+ async_heap_size | 512 kiB | Heap size for asynchronous calls
95
+ resident_async_pools | 2 | Number of resident pools for asynchronous calls
96
+ max_async_calls | 64 | Maximum number of ongoing asynchronous calls
97
+ max_type_size | 64 MiB | Maximum size of Koffi types (for arrays and structs)
@@ -0,0 +1,135 @@
1
+ # Data pointers
2
+
3
+ ## How pointers are used
4
+
5
+ In C, pointer arguments are used for differenty purposes. It is important to distinguish these use cases because Koffi provides different ways to deal with each of them:
6
+
7
+ - **Struct pointers**: Use of struct pointers by C libraries fall in two cases: avoid (potentially) expensive copies, and to let the function change struct contents (output or input/output arguments).
8
+ - **Opaque pointers**: the library does not expose the contents of the structs, and only provides you with a pointer to it (e.g. `FILE *`). Only the functions provided by the library can do something with this pointer, in Koffi we call this an opaque type. This is usually done for ABI-stability reason, and to prevent library users from messing directly with library internals.
9
+ - **Pointers to primitive types**: This is more rare, and generally used for output or input/output arguments. The Win32 API has a lot of these.
10
+ - **Arrays**: in C, you dynamically-sized arrays are usually passed to functions with pointers, either NULL-terminated (or any other sentinel value) or with an additional length argument.
11
+
12
+ ## Pointer types
13
+
14
+ ### Struct pointers
15
+
16
+ The following Win32 example uses `GetCursorPos()` (with an output parameter) to retrieve and show the current cursor position.
17
+
18
+ ```js
19
+ const koffi = require('koffi');
20
+ const lib = koffi.load('kernel32.dll');
21
+
22
+ // Type declarations
23
+ const POINT = koffi.struct('POINT', {
24
+ x: 'long',
25
+ y: 'long'
26
+ });
27
+
28
+ // Functions declarations
29
+ const GetCursorPos = lib.func('int __stdcall GetCursorPos(_Out_ POINT *pos)');
30
+
31
+ // Get and show cursor position
32
+ let pos = {};
33
+ if (!GetCursorPos(pos))
34
+ throw new Error('Failed to get cursor position');
35
+ console.log(pos);
36
+ ```
37
+
38
+ ### Opaque pointers
39
+
40
+ *New in Koffi 2.0*
41
+
42
+ Some C libraries use handles, which behave as pointers to opaque structs. An example of this is the HANDLE type in the Win32 API. If you want to reproduce this behavior, you can define a **named pointer type** to an opaque type, like so:
43
+
44
+ ```js
45
+ const HANDLE = koffi.pointer('HANDLE', koffi.opaque());
46
+
47
+ // And now you get to use it this way:
48
+ const GetHandleInformation = lib.func('bool __stdcall GetHandleInformation(HANDLE h, _Out_ uint32_t *flags)');
49
+ const CloseHandle = lib.func('bool __stdcall CloseHandle(HANDLE h)');
50
+ ```
51
+
52
+ ### Pointer to primitive types
53
+
54
+ In javascript, it is not possible to pass a primitive value by reference to another function. This means that you cannot call a function and expect it to modify the value of one of its number or string parameter.
55
+
56
+ However, arrays and objects (among others) are reference type values. Assigning an array or an object from one variable to another does not invole any copy. Instead, as the following example illustrates, the new variable references the same array as the first:
57
+
58
+ ```js
59
+ let list1 = [1, 2];
60
+ let list2 = list1;
61
+
62
+ list2[1] = 42;
63
+
64
+ console.log(list1); // Prints [1, 42]
65
+ ```
66
+
67
+ All of this means that C functions that are expected to modify their primitive output values (such as an `int *` parameter) cannot be used directly. However, thanks to Koffi's transparent array support, you can use Javascript arrays to approximate reference semantics with single-element arrays.
68
+
69
+ Below, you can find an example of an addition function where the result is stored in an `int *` input/output parameter and how to use this function from Koffi.
70
+
71
+ ```c
72
+ void AddInt(int *dest, int add)
73
+ {
74
+ *dest += add;
75
+ }
76
+ ```
77
+
78
+ You can simply pass a single-element array as the first argument:
79
+
80
+ ```js
81
+ const AddInt = lib.func('void AddInt(_Inout_ int *dest, int add)');
82
+
83
+ let sum = [36];
84
+ AddInt(sum, 6);
85
+
86
+ console.log(sum[0]); // Prints 42
87
+ ```
88
+
89
+ ### Array pointers (dynamic arrays)
90
+
91
+ In C, dynamically-sized arrays are usually passed around as pointers. The length is either passed as an additional argument, or inferred from the array content itself, for example with a terminating sentinel value (such as a NULL pointers in the case of an array of strings).
92
+
93
+ Koffi can translate JS arrays and TypedArrays to pointer arguments. However, because C does not have a proper notion of dynamically-sized arrays (fat pointers), you need to provide the length or the sentinel value yourself depending on the API.
94
+
95
+ Here is a simple example of a C function taking a NULL-terminated list of strings as input, to calculate the total length of all strings.
96
+
97
+ ```c
98
+ // Build with: clang -fPIC -o length.so -shared length.c -Wall -O2
99
+
100
+ #include <stdlib.h>
101
+ #include <stdint.h>
102
+ #include <string.h>
103
+
104
+ int64_t ComputeTotalLength(const char **strings)
105
+ {
106
+ int64_t total = 0;
107
+
108
+ for (const char **ptr = strings; *ptr; ptr++) {
109
+ const char *str = *ptr;
110
+ total += strlen(str);
111
+ }
112
+
113
+ return total;
114
+ }
115
+ ```
116
+
117
+ ```js
118
+ const koffi = require('koffi');
119
+ const lib = koffi.load('./length.so');
120
+
121
+ const ComputeTotalLength = lib.func('int64_t ComputeTotalLength(const char **strings)');
122
+
123
+ let strings = ['Get', 'Total', 'Length', null];
124
+ let total = ComputeTotalLength(strings);
125
+
126
+ console.log(total); // Prints 14
127
+ ```
128
+
129
+ By default, just like for objects, array arguments are copied from JS to C but not vice-versa. You can however change the direction as documented in the section on [output parameters](calls.md#output-parameters).
130
+
131
+ ## Disposable types
132
+
133
+ Disposable types allow you to register a function that will automatically called after each C to JS conversion performed by Koffi. This can be used to avoid leaking heap-allocated strings, for example.
134
+
135
+ Read the documentation for [disposable types](calls.md#heap-allocated-values) on the page about function calls.
package/doc/types.md CHANGED
@@ -142,14 +142,14 @@ const Function2 = lib.func('Function', A, [A]);
142
142
 
143
143
  Many C libraries use some kind of object-oriented API, with a pair of functions dedicated to create and delete objects. An obvious example of this can be found in stdio.h, with the opaque `FILE *` pointer. You can open and close files with `fopen()` and `fclose()`, and manipule the opaque pointer with other functions such as `fread()` or `ftell()`.
144
144
 
145
- In Koffi, you can manage this with opaque types. Declare the opaque type with `koffi.opaque(name)`, and use a pointer to this type either as a return type or some kind of [output parameter](functions.md#output-parameters) (with a double pointer).
145
+ In Koffi, you can manage this with opaque types. Declare the opaque type with `koffi.opaque(name)`, and use a pointer to this type either as a return type or some kind of [output parameter](calls.md#output-parameters) (with a double pointer).
146
146
 
147
147
  ```{note}
148
148
  Opaque types **have changed in version 2.0, and again in version 2.1**.
149
149
 
150
150
  In Koffi 1.x, opaque handles were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer.
151
151
 
152
- Now, you must use them through a pointer, and use an array for output parameters. This is shown in the example below (look for the call to `ConcatNewOut` in the JS part), and is described in the section on [output parameters](functions.md#output-parameters).
152
+ Now, you must use them through a pointer, and use an array for output parameters. This is shown in the example below (look for the call to `ConcatNewOut` in the JS part), and is described in the section on [output parameters](calls.md#output-parameters).
153
153
 
154
154
  In addition to this, you should use `koffi.opaque()` (introduced in Koffi 2.1) instead of `koffi.handle()` which is deprecated, and will be removed eventually in Koffi 3.0.
155
155
 
@@ -330,90 +330,6 @@ try {
330
330
  }
331
331
  ```
332
332
 
333
- ## Pointer types
334
-
335
- In C, pointer arguments are used for differenty purposes. It is important to distinguish these use cases because Koffi provides different ways to deal with each of them:
336
-
337
- - **Struct pointers**: Use of struct pointers by C libraries fall in two cases: avoid (potentially) expensive copies, and to let the function change struct contents (output or input/output arguments).
338
- - **Opaque pointers**: the library does not expose the contents of the structs, and only provides you with a pointer to it (e.g. `FILE *`). Only the functions provided by the library can do something with this pointer, in Koffi we call this an opaque type. This is usually done for ABI-stability reason, and to prevent library users from messing directly with library internals.
339
- - **Pointers to primitive types**: This is more rare, and generally used for output or input/output arguments. The Win32 API has a lot of these.
340
- - **Arrays**: in C, you dynamically-sized arrays are usually passed to functions with pointers, either NULL-terminated (or any other sentinel value) or with an additional length argument.
341
-
342
- ### Struct pointers
343
-
344
- The following Win32 example uses `GetCursorPos()` (with an output parameter) to retrieve and show the current cursor position.
345
-
346
- ```js
347
- const koffi = require('koffi');
348
- const lib = koffi.load('kernel32.dll');
349
-
350
- // Type declarations
351
- const POINT = koffi.struct('POINT', {
352
- x: 'long',
353
- y: 'long'
354
- });
355
-
356
- // Functions declarations
357
- const GetCursorPos = lib.func('int __stdcall GetCursorPos(_Out_ POINT *pos)');
358
-
359
- // Get and show cursor position
360
- let pos = {};
361
- if (!GetCursorPos(pos))
362
- throw new Error('Failed to get cursor position');
363
- console.log(pos);
364
- ```
365
-
366
- ### Named pointer types
367
-
368
- *New in Koffi 2.0*
369
-
370
- Some C libraries use handles, which behave as pointers to opaque structs. An example of this is the HANDLE type in the Win32 API. If you want to reproduce this behavior, you can define a **named pointer type** to an opaque type, like so:
371
-
372
- ```js
373
- const HANDLE = koffi.pointer('HANDLE', koffi.opaque());
374
-
375
- // And now you get to use it this way:
376
- const GetHandleInformation = lib.func('bool __stdcall GetHandleInformation(HANDLE h, _Out_ uint32_t *flags)');
377
- const CloseHandle = lib.func('bool __stdcall CloseHandle(HANDLE h)');
378
- ```
379
-
380
- ### Pointers to primitive types
381
-
382
- In javascript, it is not possible to pass a primitive value by reference to another function. This means that you cannot call a function and expect it to modify the value of one of its number or string parameter.
383
-
384
- However, arrays and objects (among others) are reference type values. Assigning an array or an object from one variable to another does not invole any copy. Instead, as the following example illustrates, the new variable references the same array as the first:
385
-
386
- ```js
387
- let list1 = [1, 2];
388
- let list2 = list1;
389
-
390
- list2[1] = 42;
391
-
392
- console.log(list1); // Prints [1, 42]
393
- ```
394
-
395
- All of this means that C functions that are expected to modify their primitive output values (such as an `int *` parameter) cannot be used directly. However, thanks to Koffi's transparent array support, you can use Javascript arrays to approximate reference semantics with single-element arrays.
396
-
397
- Below, you can find an example of an addition function where the result is stored in an `int *` input/output parameter and how to use this function from Koffi.
398
-
399
- ```c
400
- void AddInt(int *dest, int add)
401
- {
402
- *dest += add;
403
- }
404
- ```
405
-
406
- You can simply pass a single-element array as the first argument:
407
-
408
- ```js
409
- const AddInt = lib.func('void AddInt(_Inout_ int *dest, int add)');
410
-
411
- let sum = [36];
412
- AddInt(sum, 6);
413
-
414
- console.log(sum[0]); // Prints 42
415
- ```
416
-
417
333
  ## Array types
418
334
 
419
335
  ### Fixed-size C arrays
@@ -459,110 +375,4 @@ The reverse case is also true, Koffi can convert a C fixed-size buffer to a JS s
459
375
 
460
376
  ### Array pointers (dynamic arrays)
461
377
 
462
- In C, dynamically-sized arrays are usually passed around as pointers. The length is either passed as an additional argument, or inferred from the array content itself, for example with a terminating sentinel value (such as a NULL pointers in the case of an array of strings).
463
-
464
- Koffi can translate JS arrays and TypedArrays to pointer arguments. However, because C does not have a proper notion of dynamically-sized arrays (fat pointers), you need to provide the length or the sentinel value yourself depending on the API.
465
-
466
- Here is a simple example of a C function taking a NULL-terminated list of strings as input, to calculate the total length of all strings.
467
-
468
- ```c
469
- // Build with: clang -fPIC -o length.so -shared length.c -Wall -O2
470
-
471
- #include <stdlib.h>
472
- #include <stdint.h>
473
- #include <string.h>
474
-
475
- int64_t ComputeTotalLength(const char **strings)
476
- {
477
- int64_t total = 0;
478
-
479
- for (const char **ptr = strings; *ptr; ptr++) {
480
- const char *str = *ptr;
481
- total += strlen(str);
482
- }
483
-
484
- return total;
485
- }
486
- ```
487
-
488
- ```js
489
- const koffi = require('koffi');
490
- const lib = koffi.load('./length.so');
491
-
492
- const ComputeTotalLength = lib.func('int64_t ComputeTotalLength(const char **strings)');
493
-
494
- let strings = ['Get', 'Total', 'Length', null];
495
- let total = ComputeTotalLength(strings);
496
-
497
- console.log(total); // Prints 14
498
- ```
499
-
500
- By default, just like for objects, array arguments are copied from JS to C but not vice-versa. You can however change the direction as documented in the section on [output parameters](functions.md#output-parameters).
501
-
502
- ## Disposable types
503
-
504
- Disposable types allow you to register a function that will automatically called after each C to JS conversion performed by Koffi. This can be used to avoid leaking heap-allocated strings, for example.
505
-
506
- Read the documentation for [disposable types](functions.md#heap-allocated-values) on the page about function calls.
507
-
508
- ## Utility functions
509
-
510
- ### Type introspection
511
-
512
- *New in Koffi 2.0: `koffi.resolve()`, new in Koffi 2.2: `koffi.offsetof()`*
513
-
514
- ```{note}
515
- The value returned by `introspect()` has **changed in version 2.0 and in version 2.2**.
516
-
517
- In Koffi 1.x, it could only be used with struct types and returned the object passed to koffi.struct() with the member names and types.
518
-
519
- Starting in Koffi 2.2, each record member is exposed as an object containing the name, the type and the offset within the record.
520
-
521
- Consult the [migration guide](changes.md) for more information.
522
- ```
523
-
524
- Use `koffi.introspect(type)` to get detailed information about a type: name, primitive, size, alignment, members (record types), reference type (array, pointer) and length (array).
525
-
526
- ```js
527
- const FoobarType = koffi.struct('FoobarType', {
528
- a: 'int',
529
- b: 'char *',
530
- c: 'double'
531
- });
532
-
533
- console.log(koffi.introspect(FoobarType));
534
-
535
- // Expected result on 64-bit machines:
536
- // {
537
- // name: 'FoobarType',
538
- // primitive: 'Record',
539
- // size: 24,
540
- // alignment: 8,
541
- // members: {
542
- // a: { name: 'a', type: [External: 4b28a60], offset: 0 },
543
- // b: { name: 'b', type: [External: 4b292e0], offset: 8 },
544
- // c: { name: 'c', type: [External: 4b29260], offset: 16 }
545
- // }
546
- // }
547
- ```
548
-
549
- Koffi also exposes a few more utility functions to get a subset of this information:
550
-
551
- - `koffi.sizeof(type)` to get the size of a type
552
- - `koffi.alignof(type)` to get the alignment of a type
553
- - `koffi.offsetof(type, member_name)` to get the offset of a record member
554
- - `koffi.resolve(type)` to get the resolved type object from a type string
555
-
556
- Just like before, you can refer to primitive types by their name or through `koffi.types`:
557
-
558
- ```js
559
- // These two lines do the same:
560
- console.log(koffi.sizeof('long'));
561
- console.log(koffi.sizeof(koffi.types.long));
562
- ```
563
-
564
- ### Type aliases
565
-
566
- *New in Koffi 2.0*
567
-
568
- You can alias a type with `koffi.alias(name, type)`. Aliased types are completely equivalent.
378
+ In C, dynamically-sized arrays are usually passed around as pointers. Read more about [array pointers](pointers.md#array-pointers-dynamic-arrays) in the relevant section.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.2.3-beta.3",
4
- "stable": "2.2.2",
3
+ "version": "2.2.4",
4
+ "stable": "2.2.4",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
@@ -17,6 +17,9 @@
17
17
  #include "ffi.hh"
18
18
  #include "call.hh"
19
19
  #include "util.hh"
20
+ #ifdef _WIN32
21
+ #include "win32.hh"
22
+ #endif
20
23
 
21
24
  #include <napi.h>
22
25
 
@@ -494,6 +497,24 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
494
497
 
495
498
  void CallData::Execute(const FunctionInfo *func)
496
499
  {
500
+ #ifdef _WIN32
501
+ TEB *teb = GetTEB();
502
+
503
+ // Restore previous stack limits at the end
504
+ RG_DEFER_C(base = teb->StackBase,
505
+ limit = teb->StackLimit,
506
+ dealloc = teb->DeallocationStack) {
507
+ teb->StackBase = base;
508
+ teb->StackLimit = limit;
509
+ teb->DeallocationStack = dealloc;
510
+ };
511
+
512
+ // Adjust stack limits so SEH works correctly
513
+ teb->StackBase = mem->stack0.end();
514
+ teb->StackLimit = mem->stack0.ptr;
515
+ teb->DeallocationStack = mem->stack0.ptr;
516
+ #endif
517
+
497
518
  #define PERFORM_CALL(Suffix) \
498
519
  ([&]() { \
499
520
  auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
@@ -611,6 +632,24 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
611
632
  if (RG_UNLIKELY(env.IsExceptionPending()))
612
633
  return;
613
634
 
635
+ #ifdef _WIN32
636
+ TEB *teb = GetTEB();
637
+
638
+ // Restore previous stack limits at the end
639
+ RG_DEFER_C(base = teb->StackBase,
640
+ limit = teb->StackLimit,
641
+ dealloc = teb->DeallocationStack) {
642
+ teb->StackBase = base;
643
+ teb->StackLimit = limit;
644
+ teb->DeallocationStack = dealloc;
645
+ };
646
+
647
+ // Adjust stack limits so SEH works correctly
648
+ teb->StackBase = instance->main_stack_max;
649
+ teb->StackLimit = instance->main_stack_min;
650
+ teb->DeallocationStack = instance->main_stack_min;
651
+ #endif
652
+
614
653
  const TrampolineInfo &trampoline = shared.trampolines[idx];
615
654
 
616
655
  const FunctionInfo *proto = trampoline.proto;
@@ -45,11 +45,11 @@
45
45
  .cfi_def_cfa rsp, 8
46
46
  ENDBR64
47
47
  movq %rdi, %r11
48
- pushq %rbx
48
+ pushq %rbp
49
49
  .cfi_def_cfa rsp, 16
50
50
  movq %rsp, (%rdx)
51
- movq %rsp, %rbx
52
- .cfi_def_cfa rbx, 16
51
+ movq %rsp, %rbp
52
+ .cfi_def_cfa rbp, 16
53
53
  leaq 112(%rsi), %rsp
54
54
  .endm
55
55
 
@@ -58,8 +58,8 @@
58
58
  # The return value is passed untouched through RAX or XMM0.
59
59
  .macro epilogue
60
60
  call *%r11
61
- movq %rbx, %rsp
62
- popq %rbx
61
+ movq %rbp, %rsp
62
+ popq %rbp
63
63
  .cfi_def_cfa rsp, 8
64
64
  ret
65
65
  .cfi_endproc
@@ -241,9 +241,9 @@ SYMBOL(CallSwitchStack):
241
241
  .cfi_startproc
242
242
  .cfi_def_cfa rsp, 8
243
243
  ENDBR64
244
- push %rbx
244
+ push %rbp
245
245
  .cfi_def_cfa rsp, 16
246
- movq %rsp, %rbx
246
+ movq %rsp, %rbp
247
247
  movq %rsp, %r10
248
248
  subq 0(%r8), %r10
249
249
  andq $-16, %r10
@@ -251,9 +251,9 @@ SYMBOL(CallSwitchStack):
251
251
  movq %rcx, %rsp
252
252
  .cfi_def_cfa rsp, 16
253
253
  call *%r9
254
- mov %rbx, %rsp
254
+ mov %rbp, %rsp
255
255
  .cfi_def_cfa rsp, 16
256
- pop %rbx
256
+ pop %rbp
257
257
  .cfi_def_cfa rsp, 8
258
258
  ret
259
259
  .cfi_endproc
@@ -33,11 +33,11 @@ public ForwardCallXD
33
33
  prologue macro
34
34
  endbr64
35
35
  mov rax, rcx
36
- push rbx
37
- .pushreg rbx
38
- mov rbx, rsp
36
+ push rbp
37
+ .pushreg rbp
38
+ mov rbp, rsp
39
39
  mov qword ptr [r8+0], rsp
40
- .setframe rbx, 0
40
+ .setframe rbp, 0
41
41
  .endprolog
42
42
  mov rsp, rdx
43
43
  endm
@@ -47,8 +47,8 @@ endm
47
47
  ; The return value is passed untouched through RAX or XMM0.
48
48
  epilogue macro
49
49
  call rax
50
- mov rsp, rbx
51
- pop rbx
50
+ mov rsp, rbp
51
+ pop rbp
52
52
  ret
53
53
  endm
54
54
 
@@ -169,10 +169,10 @@ endm
169
169
  ; The first three parameters (rcx, rdx, r8) are passed through untouched.
170
170
  CallSwitchStack proc frame
171
171
  endbr64
172
- push rbx
173
- .pushreg rbx
174
- mov rbx, rsp
175
- .setframe rbx, 0
172
+ push rbp
173
+ .pushreg rbp
174
+ mov rbp, rsp
175
+ .setframe rbp, 0
176
176
  .endprolog
177
177
  mov rax, qword ptr [rsp+56]
178
178
  mov r10, rsp
@@ -182,8 +182,8 @@ CallSwitchStack proc frame
182
182
  mov qword ptr [r11+8], r10
183
183
  lea rsp, [r9-32]
184
184
  call rax
185
- mov rsp, rbx
186
- pop rbx
185
+ mov rsp, rbp
186
+ pop rbp
187
187
  ret
188
188
  CallSwitchStack endp
189
189