koffi 1.1.0-beta.7 → 1.1.1
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 +17 -6
- package/build/qemu/1.1.1/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_win32_x64.tar.gz +0 -0
- package/package.json +1 -1
- package/qemu/qemu.js +1 -1
- package/src/call.cc +210 -41
- package/src/call.hh +2 -2
- package/src/ffi.cc +15 -15
- package/src/ffi.hh +3 -2
- package/src/util.hh +1 -1
- package/test/misc.c +17 -0
- package/build/qemu/1.1.0-beta.7/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.0-beta.7/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.0-beta.7/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.0-beta.7/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.0-beta.7/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.0-beta.7/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.0-beta.7/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.0-beta.7/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.0-beta.7/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.0-beta.7/koffi_win32_x64.tar.gz +0 -0
package/README.md
CHANGED
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
|
|
21
21
|
Koffi is a fast and easy-to-use FFI module for Node.js, with support for primitive and aggregate data types (structs), both by reference (pointer) and by value.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
The following features are planned in the near future:
|
|
24
24
|
|
|
25
|
-
* 1.1: Asynchronous calls and fixed-size array types
|
|
26
25
|
* 1.2: C to JS callbacks
|
|
26
|
+
* 1.3: Type parser
|
|
27
27
|
|
|
28
28
|
The following platforms __are officially supported and tested__ at the moment:
|
|
29
29
|
|
|
@@ -231,11 +231,13 @@ Koffi exposes three functions to explore type information:
|
|
|
231
231
|
Fixed-size arrays are declared with `koffi.array(type, length)`. Just like in C, they cannot be passed
|
|
232
232
|
as functions parameters (they degenerate to pointers), or returned by value. You can however embed them in struct types.
|
|
233
233
|
|
|
234
|
-
|
|
235
|
-
- When converting from JS to C, Koffi can take a normal Array (e.g. `[1, 2]`) or a TypedArray of the correct type (e.g. `Uint8Array` for an array of `int8_t` numbers)
|
|
236
|
-
- When converting from C to JS (for return value or output parameters), Koffi will by default use a TypedArray. But you can change this behavior when you create the array type with the optional hint argument: `koffi.array('int8_t', 6, 'array')`
|
|
234
|
+
### JS typed arrays
|
|
237
235
|
|
|
238
|
-
|
|
236
|
+
Special rules apply for arrays of primitive integer and float types (uint32_t, double, etc...):
|
|
237
|
+
- When converting from JS to C, Koffi can take a normal Array (e.g. `[1, 2]`) or a TypedArray of the correct type (e.g. `Uint8Array` for an array of `uint8_t` numbers)
|
|
238
|
+
- When converting from C to JS (for return value or output parameters), Koffi will by default use a TypedArray. But you can change this behavior when you create the array type with the optional hint argument: `koffi.array('uint8_t', 64, 'array')`
|
|
239
|
+
|
|
240
|
+
See the example below:
|
|
239
241
|
|
|
240
242
|
```js
|
|
241
243
|
const koffi = require('koffi');
|
|
@@ -258,6 +260,14 @@ console.log(ReturnFoo1({ i: 5, a16: [6, 8] })) // Prints { i: 5, a16: Int16Array
|
|
|
258
260
|
console.log(ReturnFoo2({ i: 5, a16: [6, 8] })) // Prints { i: 5, a16: [6, 8] }
|
|
259
261
|
```
|
|
260
262
|
|
|
263
|
+
### C strings
|
|
264
|
+
|
|
265
|
+
Koffi can also convert JS strings to fixed-sized arrays in the following cases:
|
|
266
|
+
- char (or int8_t) arrays are filled with the UTF-8 encoded string, truncated if needed. The buffer is always NUL-terminated.
|
|
267
|
+
- char16 (or int16_t) arrays are filled with the UTF-16 encoded string, truncated if needed. The buffer is always NUL-terminated.
|
|
268
|
+
|
|
269
|
+
The reverse case is also true, Koffi can convert a C fixed-size buffer to a JS string. Use the `string` array hint to do this (e.g. `koffi.array('char', 8, 'string')`).
|
|
270
|
+
|
|
261
271
|
## Variadic functions
|
|
262
272
|
|
|
263
273
|
Variadic functions are declared with an ellipsis as the last argument.
|
|
@@ -267,6 +277,7 @@ In order to call a variadic function, you must provide two Javascript arguments
|
|
|
267
277
|
```js
|
|
268
278
|
const printf = lib.func('printf', 'int', ['string', '...']);
|
|
269
279
|
|
|
280
|
+
// The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *)
|
|
270
281
|
printf('Integer %d, double %g, string %s', 'int', 6, 'double', 8.5, 'string', 'THE END');
|
|
271
282
|
```
|
|
272
283
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/qemu/qemu.js
CHANGED
package/src/call.cc
CHANGED
|
@@ -142,21 +142,77 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
142
142
|
bool b = value.As<Napi::Boolean>();
|
|
143
143
|
*(bool *)dest = b;
|
|
144
144
|
} break;
|
|
145
|
-
case PrimitiveKind::Int8:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
145
|
+
case PrimitiveKind::Int8: {
|
|
146
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
147
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
int8_t v = CopyNumber<int8_t>(value);
|
|
152
|
+
*(int8_t *)dest = v;
|
|
153
|
+
} break;
|
|
154
|
+
case PrimitiveKind::UInt8: {
|
|
155
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
156
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
uint8_t v = CopyNumber<uint8_t>(value);
|
|
161
|
+
*(uint8_t *)dest = v;
|
|
162
|
+
} break;
|
|
163
|
+
case PrimitiveKind::Int16: {
|
|
164
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
165
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
int16_t v = CopyNumber<int16_t>(value);
|
|
170
|
+
*(int16_t *)dest = v;
|
|
171
|
+
} break;
|
|
172
|
+
case PrimitiveKind::UInt16: {
|
|
173
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
174
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
uint16_t v = CopyNumber<uint16_t>(value);
|
|
179
|
+
*(uint16_t *)dest = v;
|
|
180
|
+
} break;
|
|
181
|
+
case PrimitiveKind::Int32: {
|
|
182
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
183
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
int32_t v = CopyNumber<int32_t>(value);
|
|
188
|
+
*(int32_t *)dest = v;
|
|
189
|
+
} break;
|
|
190
|
+
case PrimitiveKind::UInt32: {
|
|
191
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
192
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
uint32_t v = CopyNumber<uint32_t>(value);
|
|
197
|
+
*(uint32_t *)dest = v;
|
|
198
|
+
} break;
|
|
199
|
+
case PrimitiveKind::Int64: {
|
|
153
200
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
154
201
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
|
|
155
202
|
return false;
|
|
156
203
|
}
|
|
157
204
|
|
|
158
205
|
int64_t v = CopyNumber<int64_t>(value);
|
|
159
|
-
|
|
206
|
+
*(int64_t *)dest = v;
|
|
207
|
+
} break;
|
|
208
|
+
case PrimitiveKind::UInt64: {
|
|
209
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
210
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected number", GetValueType(instance, value), member.name);
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
uint64_t v = CopyNumber<uint64_t>(value);
|
|
215
|
+
*(uint64_t *)dest = v;
|
|
160
216
|
} break;
|
|
161
217
|
case PrimitiveKind::String: {
|
|
162
218
|
if (RG_UNLIKELY(!value.IsString())) {
|
|
@@ -201,7 +257,7 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
201
257
|
return false;
|
|
202
258
|
} break;
|
|
203
259
|
case PrimitiveKind::Array: {
|
|
204
|
-
if (RG_UNLIKELY(!value.IsArray() && !value.IsTypedArray())) {
|
|
260
|
+
if (RG_UNLIKELY(!value.IsArray() && !value.IsTypedArray() && !value.IsString())) {
|
|
205
261
|
ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected array", GetValueType(instance, value), member.name);
|
|
206
262
|
return false;
|
|
207
263
|
}
|
|
@@ -236,15 +292,15 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
236
292
|
return true;
|
|
237
293
|
}
|
|
238
294
|
|
|
239
|
-
bool CallData::PushArray(const Napi::
|
|
295
|
+
bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t *dest, int16_t realign)
|
|
240
296
|
{
|
|
241
|
-
RG_ASSERT(
|
|
297
|
+
RG_ASSERT(value.IsArray() || value.IsTypedArray() || value.IsString());
|
|
242
298
|
RG_ASSERT(type->primitive == PrimitiveKind::Array);
|
|
243
299
|
|
|
244
300
|
uint32_t len = type->size / type->ref->size;
|
|
245
301
|
|
|
246
|
-
if (
|
|
247
|
-
Napi::Array array =
|
|
302
|
+
if (value.IsArray()) {
|
|
303
|
+
Napi::Array array = value.As<Napi::Array>();
|
|
248
304
|
|
|
249
305
|
if (RG_UNLIKELY(array.Length() != len)) {
|
|
250
306
|
ThrowError<Napi::Error>(env, "Expected array of length %1, got %2", len, array.Length());
|
|
@@ -279,17 +335,52 @@ bool CallData::PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
279
335
|
*(bool *)dest = b;
|
|
280
336
|
});
|
|
281
337
|
} break;
|
|
282
|
-
case PrimitiveKind::Int8:
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
case PrimitiveKind::
|
|
289
|
-
|
|
338
|
+
case PrimitiveKind::Int8: {
|
|
339
|
+
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
340
|
+
int8_t v = CopyNumber<int8_t>(value);
|
|
341
|
+
*(int8_t *)dest = v;
|
|
342
|
+
});
|
|
343
|
+
} break;
|
|
344
|
+
case PrimitiveKind::UInt8: {
|
|
345
|
+
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
346
|
+
uint8_t v = CopyNumber<uint8_t>(value);
|
|
347
|
+
*(uint8_t *)dest = v;
|
|
348
|
+
});
|
|
349
|
+
} break;
|
|
350
|
+
case PrimitiveKind::Int16: {
|
|
351
|
+
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
352
|
+
int16_t v = CopyNumber<int16_t>(value);
|
|
353
|
+
*(int16_t *)dest = v;
|
|
354
|
+
});
|
|
355
|
+
} break;
|
|
356
|
+
case PrimitiveKind::UInt16: {
|
|
357
|
+
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
358
|
+
uint16_t v = CopyNumber<uint16_t>(value);
|
|
359
|
+
*(uint16_t *)dest = v;
|
|
360
|
+
});
|
|
361
|
+
} break;
|
|
362
|
+
case PrimitiveKind::Int32: {
|
|
363
|
+
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
364
|
+
int32_t v = CopyNumber<int32_t>(value);
|
|
365
|
+
*(int32_t *)dest = v;
|
|
366
|
+
});
|
|
367
|
+
} break;
|
|
368
|
+
case PrimitiveKind::UInt32: {
|
|
369
|
+
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
370
|
+
uint32_t v = CopyNumber<uint32_t>(value);
|
|
371
|
+
*(uint32_t *)dest = v;
|
|
372
|
+
});
|
|
373
|
+
} break;
|
|
374
|
+
case PrimitiveKind::Int64: {
|
|
290
375
|
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
291
376
|
int64_t v = CopyNumber<int64_t>(value);
|
|
292
|
-
|
|
377
|
+
*(int64_t *)dest = v;
|
|
378
|
+
});
|
|
379
|
+
} break;
|
|
380
|
+
case PrimitiveKind::UInt64: {
|
|
381
|
+
PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
|
|
382
|
+
uint64_t v = CopyNumber<uint64_t>(value);
|
|
383
|
+
*(uint64_t *)dest = v;
|
|
293
384
|
});
|
|
294
385
|
} break;
|
|
295
386
|
case PrimitiveKind::String: {
|
|
@@ -322,7 +413,7 @@ bool CallData::PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
322
413
|
});
|
|
323
414
|
} break;
|
|
324
415
|
case PrimitiveKind::Array: {
|
|
325
|
-
PUSH_ARRAY(value.IsArray() || value.IsTypedArray(), "array", {
|
|
416
|
+
PUSH_ARRAY(value.IsArray() || value.IsTypedArray() || value.IsString(), "array", {
|
|
326
417
|
Napi::Object array = value.As<Napi::Array>();
|
|
327
418
|
if (!PushArray(array, type->ref, dest, realign))
|
|
328
419
|
return false;
|
|
@@ -343,8 +434,8 @@ bool CallData::PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
343
434
|
}
|
|
344
435
|
|
|
345
436
|
#undef PUSH_ARRAY
|
|
346
|
-
} else {
|
|
347
|
-
Napi::TypedArray array =
|
|
437
|
+
} else if (value.IsTypedArray()) {
|
|
438
|
+
Napi::TypedArray array = value.As<Napi::TypedArray>();
|
|
348
439
|
const uint8_t *buf = (const uint8_t *)array.ArrayBuffer().Data();
|
|
349
440
|
|
|
350
441
|
if (RG_UNLIKELY(array.ElementLength() != len)) {
|
|
@@ -378,6 +469,25 @@ bool CallData::PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
378
469
|
|
|
379
470
|
dest += type->ref->size;
|
|
380
471
|
}
|
|
472
|
+
} else if (value.IsString()) {
|
|
473
|
+
size_t len = 0;
|
|
474
|
+
|
|
475
|
+
if (type->ref->primitive == PrimitiveKind::Int8 || type->ref->primitive == PrimitiveKind::UInt8) {
|
|
476
|
+
napi_status status = napi_get_value_string_utf8(env, value, (char *)dest, type->size, &len);
|
|
477
|
+
RG_ASSERT(status == napi_ok);
|
|
478
|
+
} else if (type->ref->primitive == PrimitiveKind::Int16 || type->ref->primitive == PrimitiveKind::UInt16) {
|
|
479
|
+
napi_status status = napi_get_value_string_utf16(env, value, (char16_t *)dest, type->size / 2, &len);
|
|
480
|
+
RG_ASSERT(status == napi_ok);
|
|
481
|
+
|
|
482
|
+
len *= 2;
|
|
483
|
+
} else {
|
|
484
|
+
ThrowError<Napi::TypeError>(env, "Strings cannot be converted to %1 array", type->ref->name);
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
memset_safe(dest + len, 0, type->size - len);
|
|
489
|
+
} else {
|
|
490
|
+
RG_UNREACHABLE();
|
|
381
491
|
}
|
|
382
492
|
|
|
383
493
|
return true;
|
|
@@ -451,8 +561,8 @@ void CallData::PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *t
|
|
|
451
561
|
obj.Set(member.name, obj2);
|
|
452
562
|
} break;
|
|
453
563
|
case PrimitiveKind::Array: {
|
|
454
|
-
Napi::
|
|
455
|
-
obj.Set(member.name,
|
|
564
|
+
Napi::Value value = PopArray(src, member.type, realign);
|
|
565
|
+
obj.Set(member.name, value);
|
|
456
566
|
} break;
|
|
457
567
|
case PrimitiveKind::Float32: {
|
|
458
568
|
float f;
|
|
@@ -477,7 +587,18 @@ Napi::Object CallData::PopObject(const uint8_t *src, const TypeInfo *type, int16
|
|
|
477
587
|
return obj;
|
|
478
588
|
}
|
|
479
589
|
|
|
480
|
-
|
|
590
|
+
Size WideStringLength(const char16_t *str16, Size max)
|
|
591
|
+
{
|
|
592
|
+
Size len = 0;
|
|
593
|
+
|
|
594
|
+
while (len < max && str16[len]) {
|
|
595
|
+
len++;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return len;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
Napi::Value CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_t realign)
|
|
481
602
|
{
|
|
482
603
|
RG_ASSERT(type->primitive == PrimitiveKind::Array);
|
|
483
604
|
|
|
@@ -500,7 +621,12 @@ Napi::Object CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_
|
|
|
500
621
|
} while (false)
|
|
501
622
|
#define POP_NUMBER_ARRAY(TypedArrayType, CType) \
|
|
502
623
|
do { \
|
|
503
|
-
if (type->hint == TypeInfo::ArrayHint::
|
|
624
|
+
if (type->hint == TypeInfo::ArrayHint::Array) { \
|
|
625
|
+
POP_ARRAY({ \
|
|
626
|
+
double d = (double)*(CType *)src; \
|
|
627
|
+
array.Set(i, Napi::Number::New(env, d)); \
|
|
628
|
+
}); \
|
|
629
|
+
} else { \
|
|
504
630
|
Napi::TypedArrayType array = Napi::TypedArrayType::New(env, len); \
|
|
505
631
|
\
|
|
506
632
|
for (uint32_t i = 0; i < len; i++) { \
|
|
@@ -514,11 +640,6 @@ Napi::Object CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_
|
|
|
514
640
|
} \
|
|
515
641
|
\
|
|
516
642
|
return array; \
|
|
517
|
-
} else { \
|
|
518
|
-
POP_ARRAY({ \
|
|
519
|
-
double d = (double)*(CType *)src; \
|
|
520
|
-
array.Set(i, Napi::Number::New(env, d)); \
|
|
521
|
-
}); \
|
|
522
643
|
} \
|
|
523
644
|
} while (false)
|
|
524
645
|
|
|
@@ -531,10 +652,58 @@ Napi::Object CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_
|
|
|
531
652
|
array.Set(i, Napi::Boolean::New(env, b));
|
|
532
653
|
});
|
|
533
654
|
} break;
|
|
534
|
-
case PrimitiveKind::Int8: {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
655
|
+
case PrimitiveKind::Int8: {
|
|
656
|
+
if (type->hint == TypeInfo::ArrayHint::String) {
|
|
657
|
+
RG_ASSERT(!realign);
|
|
658
|
+
|
|
659
|
+
const char *ptr = (const char *)src;
|
|
660
|
+
size_t count = strnlen(ptr, (size_t)len);
|
|
661
|
+
|
|
662
|
+
Napi::String str = Napi::String::New(env, ptr, count);
|
|
663
|
+
return str;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
POP_NUMBER_ARRAY(Int8Array, int8_t);
|
|
667
|
+
} break;
|
|
668
|
+
case PrimitiveKind::UInt8: {
|
|
669
|
+
if (type->hint == TypeInfo::ArrayHint::String) {
|
|
670
|
+
RG_ASSERT(!realign);
|
|
671
|
+
|
|
672
|
+
const char *ptr = (const char *)src;
|
|
673
|
+
size_t count = strnlen(ptr, (size_t)len);
|
|
674
|
+
|
|
675
|
+
Napi::String str = Napi::String::New(env, ptr, count);
|
|
676
|
+
return str;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
POP_NUMBER_ARRAY(Uint8Array, uint8_t);
|
|
680
|
+
} break;
|
|
681
|
+
case PrimitiveKind::Int16: {
|
|
682
|
+
if (type->hint == TypeInfo::ArrayHint::String) {
|
|
683
|
+
RG_ASSERT(!realign);
|
|
684
|
+
|
|
685
|
+
const char16_t *ptr = (const char16_t *)src;
|
|
686
|
+
Size count = WideStringLength(ptr, len);
|
|
687
|
+
|
|
688
|
+
Napi::String str = Napi::String::New(env, ptr, count);
|
|
689
|
+
return str;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
POP_NUMBER_ARRAY(Int16Array, int16_t);
|
|
693
|
+
} break;
|
|
694
|
+
case PrimitiveKind::UInt16: {
|
|
695
|
+
if (type->hint == TypeInfo::ArrayHint::String) {
|
|
696
|
+
RG_ASSERT(!realign);
|
|
697
|
+
|
|
698
|
+
const char16_t *ptr = (const char16_t *)src;
|
|
699
|
+
Size count = WideStringLength(ptr, len);
|
|
700
|
+
|
|
701
|
+
Napi::String str = Napi::String::New(env, ptr, count);
|
|
702
|
+
return str;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
POP_NUMBER_ARRAY(Uint16Array, uint16_t);
|
|
706
|
+
} break;
|
|
538
707
|
case PrimitiveKind::Int32: { POP_NUMBER_ARRAY(Int32Array, int32_t); } break;
|
|
539
708
|
case PrimitiveKind::UInt32: { POP_NUMBER_ARRAY(Uint32Array, uint32_t); } break;
|
|
540
709
|
case PrimitiveKind::Int64: {
|
|
@@ -579,8 +748,8 @@ Napi::Object CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_
|
|
|
579
748
|
} break;
|
|
580
749
|
case PrimitiveKind::Array: {
|
|
581
750
|
POP_ARRAY({
|
|
582
|
-
Napi::
|
|
583
|
-
array.Set(i,
|
|
751
|
+
Napi::Value value = PopArray(src, type->ref, realign);
|
|
752
|
+
array.Set(i, value);
|
|
584
753
|
});
|
|
585
754
|
} break;
|
|
586
755
|
case PrimitiveKind::Float32: { POP_NUMBER_ARRAY(Float32Array, float); } break;
|
package/src/call.hh
CHANGED
|
@@ -78,11 +78,11 @@ private:
|
|
|
78
78
|
const char *PushString(const Napi::Value &value);
|
|
79
79
|
const char16_t *PushString16(const Napi::Value &value);
|
|
80
80
|
bool PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
|
|
81
|
-
bool PushArray(const Napi::
|
|
81
|
+
bool PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
|
|
82
82
|
|
|
83
83
|
void PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
|
|
84
84
|
Napi::Object PopObject(const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
|
|
85
|
-
Napi::
|
|
85
|
+
Napi::Value PopArray(const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
template <typename T>
|
package/src/ffi.cc
CHANGED
|
@@ -274,6 +274,8 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
274
274
|
hint = TypeInfo::ArrayHint::TypedArray;
|
|
275
275
|
} else if (to == "array") {
|
|
276
276
|
hint = TypeInfo::ArrayHint::Array;
|
|
277
|
+
} else if (to == "string") {
|
|
278
|
+
hint = TypeInfo::ArrayHint::String;
|
|
277
279
|
} else {
|
|
278
280
|
ThrowError<Napi::Error>(env, "Array conversion hint must be 'typed' or 'array'");
|
|
279
281
|
return env.Null();
|
|
@@ -297,7 +299,6 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
297
299
|
}
|
|
298
300
|
|
|
299
301
|
TypeInfo *type = instance->types.AppendDefault();
|
|
300
|
-
RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
|
|
301
302
|
|
|
302
303
|
type->name = Fmt(&instance->str_alloc, "%1[%2]", ref->name, len).ptr;
|
|
303
304
|
|
|
@@ -307,13 +308,6 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
307
308
|
type->ref = ref;
|
|
308
309
|
type->hint = hint;
|
|
309
310
|
|
|
310
|
-
// If the insert succeeds, we cannot fail anymore
|
|
311
|
-
if (!instance->types_map.TrySet(type).second) {
|
|
312
|
-
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
313
|
-
return env.Null();
|
|
314
|
-
}
|
|
315
|
-
err_guard.Disable();
|
|
316
|
-
|
|
317
311
|
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
|
|
318
312
|
SetValueTag(instance, external, &TypeInfoMarker);
|
|
319
313
|
|
|
@@ -390,9 +384,11 @@ static Span<uint8_t> AllocateAndAlign16(Allocator *alloc, Size size)
|
|
|
390
384
|
return MakeSpan(aligned, size - delta);
|
|
391
385
|
}
|
|
392
386
|
|
|
393
|
-
static InstanceMemory *
|
|
387
|
+
static InstanceMemory *AllocateAsyncMemory(InstanceData *instance)
|
|
394
388
|
{
|
|
395
|
-
for (
|
|
389
|
+
for (Size i = 1; i < instance->memories.len; i++) {
|
|
390
|
+
InstanceMemory *mem = instance->memories[i];
|
|
391
|
+
|
|
396
392
|
if (!mem->depth)
|
|
397
393
|
return mem;
|
|
398
394
|
}
|
|
@@ -422,7 +418,7 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
|
|
|
422
418
|
return env.Null();
|
|
423
419
|
}
|
|
424
420
|
|
|
425
|
-
InstanceMemory *mem =
|
|
421
|
+
InstanceMemory *mem = instance->memories[0];
|
|
426
422
|
CallData call(env, instance, func, mem);
|
|
427
423
|
|
|
428
424
|
return call.Run(info);
|
|
@@ -482,7 +478,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
|
482
478
|
if (RG_UNLIKELY(!AnalyseFunction(instance, &func)))
|
|
483
479
|
return env.Null();
|
|
484
480
|
|
|
485
|
-
InstanceMemory *mem =
|
|
481
|
+
InstanceMemory *mem = instance->memories[0];
|
|
486
482
|
CallData call(env, instance, &func, mem);
|
|
487
483
|
|
|
488
484
|
return call.Run(info);
|
|
@@ -558,7 +554,7 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
|
|
|
558
554
|
return env.Null();
|
|
559
555
|
}
|
|
560
556
|
|
|
561
|
-
InstanceMemory *mem =
|
|
557
|
+
InstanceMemory *mem = AllocateAsyncMemory(instance);
|
|
562
558
|
AsyncCall *async = new AsyncCall(env, instance, func, mem, callback);
|
|
563
559
|
|
|
564
560
|
if (async->Prepare(info) && instance->debug) {
|
|
@@ -930,8 +926,12 @@ void FunctionInfo::Unref() const
|
|
|
930
926
|
|
|
931
927
|
InstanceData::InstanceData()
|
|
932
928
|
{
|
|
933
|
-
|
|
934
|
-
|
|
929
|
+
InstanceMemory *mem = new InstanceMemory();
|
|
930
|
+
|
|
931
|
+
mem->stack = AllocateAndAlign16(&mem->mem_alloc, Mebibytes(2));
|
|
932
|
+
mem->heap = AllocateAndAlign16(&mem->mem_alloc, Mebibytes(4));
|
|
933
|
+
|
|
934
|
+
memories.Append(mem);
|
|
935
935
|
}
|
|
936
936
|
|
|
937
937
|
InstanceData::~InstanceData()
|
package/src/ffi.hh
CHANGED
|
@@ -69,7 +69,8 @@ struct RecordMember;
|
|
|
69
69
|
struct TypeInfo {
|
|
70
70
|
enum class ArrayHint {
|
|
71
71
|
Array,
|
|
72
|
-
TypedArray
|
|
72
|
+
TypedArray,
|
|
73
|
+
String
|
|
73
74
|
};
|
|
74
75
|
|
|
75
76
|
const char *name;
|
|
@@ -189,7 +190,7 @@ struct InstanceData {
|
|
|
189
190
|
bool debug;
|
|
190
191
|
uint64_t tag_lower;
|
|
191
192
|
|
|
192
|
-
LocalArray<InstanceMemory *,
|
|
193
|
+
LocalArray<InstanceMemory *, 6> memories;
|
|
193
194
|
|
|
194
195
|
BlockAllocator str_alloc;
|
|
195
196
|
};
|
package/src/util.hh
CHANGED
|
@@ -78,7 +78,7 @@ T CopyNumber(const Napi::Value &value)
|
|
|
78
78
|
RG_ASSERT(value.IsNumber() || value.IsBigInt());
|
|
79
79
|
|
|
80
80
|
if (RG_LIKELY(value.IsNumber())) {
|
|
81
|
-
return (T)value.As<Napi::Number>();
|
|
81
|
+
return (T)value.As<Napi::Number>().DoubleValue();
|
|
82
82
|
} else if (value.IsBigInt()) {
|
|
83
83
|
Napi::BigInt bigint = value.As<Napi::BigInt>();
|
|
84
84
|
|
package/test/misc.c
CHANGED
|
@@ -104,6 +104,13 @@ typedef struct PackedBFG {
|
|
|
104
104
|
} PackedBFG;
|
|
105
105
|
#pragma pack(pop)
|
|
106
106
|
|
|
107
|
+
typedef struct FixedString {
|
|
108
|
+
char buf[64];
|
|
109
|
+
} FixedString;
|
|
110
|
+
typedef struct FixedWide {
|
|
111
|
+
int16_t buf[64];
|
|
112
|
+
} FixedWide;
|
|
113
|
+
|
|
107
114
|
EXPORT void FillPack1(int a, Pack1 *p)
|
|
108
115
|
{
|
|
109
116
|
p->a = a;
|
|
@@ -359,3 +366,13 @@ EXPORT const char16_t *Concat16(const char16_t *str1, const char16_t *str2)
|
|
|
359
366
|
|
|
360
367
|
return buf;
|
|
361
368
|
}
|
|
369
|
+
|
|
370
|
+
EXPORT FixedString ReturnFixedStr(FixedString str)
|
|
371
|
+
{
|
|
372
|
+
return str;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
EXPORT FixedWide ReturnFixedWide(FixedWide str)
|
|
376
|
+
{
|
|
377
|
+
return str;
|
|
378
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|