koffi 1.1.0 → 1.1.3
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/CMakeLists.txt +10 -7
- package/README.md +29 -28
- package/build/qemu/1.1.3/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.3/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.3/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.3/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.3/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.3/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.3/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.3/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.3/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.3/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.3/koffi_win32_x64.tar.gz +0 -0
- package/package.json +2 -2
- package/qemu/qemu.js +1 -1
- package/qemu/registry/machines.json +47 -3
- package/qemu/registry/sha256sum.txt +16 -12
- package/src/abi_arm32.cc +43 -4
- package/src/abi_arm64.cc +22 -5
- package/src/abi_x64_sysv.cc +1 -1
- package/src/abi_x64_win.cc +1 -1
- package/src/abi_x86.cc +10 -4
- package/src/call.cc +213 -44
- package/src/call.hh +2 -2
- package/src/ffi.cc +63 -36
- package/src/ffi.hh +10 -4
- package/src/parser.cc +46 -24
- package/src/parser.hh +3 -1
- package/src/util.hh +1 -1
- package/test/CMakeLists.txt +3 -0
- package/test/misc.c +17 -0
- package/vendor/libcc/libcc.cc +7 -7
- package/vendor/libcc/libcc.hh +4 -1
- package/build/qemu/1.1.0/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.0/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.0/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.0/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.0/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.0/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.0/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.0/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.0/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.0/koffi_win32_x64.tar.gz +0 -0
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())) {
|
|
@@ -196,12 +252,12 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
196
252
|
return false;
|
|
197
253
|
}
|
|
198
254
|
|
|
199
|
-
Napi::Object
|
|
200
|
-
if (!PushObject(
|
|
255
|
+
Napi::Object obj2 = value.As<Napi::Object>();
|
|
256
|
+
if (!PushObject(obj2, member.type, dest, realign))
|
|
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,9 +292,9 @@ 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 &obj, const TypeInfo *type, uint8_t *dest, int16_t realign)
|
|
240
296
|
{
|
|
241
|
-
RG_ASSERT(obj.IsArray() || obj.IsTypedArray());
|
|
297
|
+
RG_ASSERT(obj.IsArray() || obj.IsTypedArray() || obj.IsString());
|
|
242
298
|
RG_ASSERT(type->primitive == PrimitiveKind::Array);
|
|
243
299
|
|
|
244
300
|
uint32_t len = type->size / type->ref->size;
|
|
@@ -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: {
|
|
@@ -316,15 +407,15 @@ bool CallData::PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
316
407
|
} break;
|
|
317
408
|
case PrimitiveKind::Record: {
|
|
318
409
|
PUSH_ARRAY(IsObject(value), "object", {
|
|
319
|
-
Napi::Object
|
|
320
|
-
if (!PushObject(
|
|
410
|
+
Napi::Object obj2 = value.As<Napi::Object>();
|
|
411
|
+
if (!PushObject(obj2, type->ref, dest, realign))
|
|
321
412
|
return false;
|
|
322
413
|
});
|
|
323
414
|
} break;
|
|
324
415
|
case PrimitiveKind::Array: {
|
|
325
|
-
PUSH_ARRAY(value.IsArray() || value.IsTypedArray(), "array", {
|
|
326
|
-
Napi::Object
|
|
327
|
-
if (!PushArray(
|
|
416
|
+
PUSH_ARRAY(value.IsArray() || value.IsTypedArray() || value.IsString(), "array", {
|
|
417
|
+
Napi::Object array2 = value.As<Napi::Array>();
|
|
418
|
+
if (!PushArray(array2, type->ref, dest, realign))
|
|
328
419
|
return false;
|
|
329
420
|
});
|
|
330
421
|
} break;
|
|
@@ -343,7 +434,7 @@ bool CallData::PushArray(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
343
434
|
}
|
|
344
435
|
|
|
345
436
|
#undef PUSH_ARRAY
|
|
346
|
-
} else {
|
|
437
|
+
} else if (obj.IsTypedArray()) {
|
|
347
438
|
Napi::TypedArray array = obj.As<Napi::TypedArray>();
|
|
348
439
|
const uint8_t *buf = (const uint8_t *)array.ArrayBuffer().Data();
|
|
349
440
|
|
|
@@ -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 (obj.IsString()) {
|
|
473
|
+
size_t encoded = 0;
|
|
474
|
+
|
|
475
|
+
if (type->ref->primitive == PrimitiveKind::Int8 || type->ref->primitive == PrimitiveKind::UInt8) {
|
|
476
|
+
napi_status status = napi_get_value_string_utf8(env, obj, (char *)dest, type->size, &encoded);
|
|
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, obj, (char16_t *)dest, type->size / 2, &encoded);
|
|
480
|
+
RG_ASSERT(status == napi_ok);
|
|
481
|
+
|
|
482
|
+
encoded *= 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 + encoded, 0, type->size - encoded);
|
|
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 &obj, 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
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
#else
|
|
30
30
|
#include <dlfcn.h>
|
|
31
31
|
#include <unistd.h>
|
|
32
|
+
#include <sys/mman.h>
|
|
32
33
|
#endif
|
|
33
34
|
|
|
34
35
|
#include <napi.h>
|
|
@@ -39,6 +40,11 @@
|
|
|
39
40
|
|
|
40
41
|
namespace RG {
|
|
41
42
|
|
|
43
|
+
const Size SyncStackSize = Mebibytes(2);
|
|
44
|
+
const Size SyncHeapSize = Mebibytes(4);
|
|
45
|
+
const Size AsyncStackSize = Mebibytes(1);
|
|
46
|
+
const Size AsyncHeapSize = Mebibytes(2);
|
|
47
|
+
|
|
42
48
|
// Value does not matter, the tag system uses memory addresses
|
|
43
49
|
const int TypeInfoMarker = 0xDEADBEEF;
|
|
44
50
|
|
|
@@ -274,6 +280,8 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
274
280
|
hint = TypeInfo::ArrayHint::TypedArray;
|
|
275
281
|
} else if (to == "array") {
|
|
276
282
|
hint = TypeInfo::ArrayHint::Array;
|
|
283
|
+
} else if (to == "string") {
|
|
284
|
+
hint = TypeInfo::ArrayHint::String;
|
|
277
285
|
} else {
|
|
278
286
|
ThrowError<Napi::Error>(env, "Array conversion hint must be 'typed' or 'array'");
|
|
279
287
|
return env.Null();
|
|
@@ -297,7 +305,6 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
297
305
|
}
|
|
298
306
|
|
|
299
307
|
TypeInfo *type = instance->types.AppendDefault();
|
|
300
|
-
RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
|
|
301
308
|
|
|
302
309
|
type->name = Fmt(&instance->str_alloc, "%1[%2]", ref->name, len).ptr;
|
|
303
310
|
|
|
@@ -307,13 +314,6 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
307
314
|
type->ref = ref;
|
|
308
315
|
type->hint = hint;
|
|
309
316
|
|
|
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
317
|
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
|
|
318
318
|
SetValueTag(instance, external, &TypeInfoMarker);
|
|
319
319
|
|
|
@@ -375,32 +375,34 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
|
375
375
|
return type->defn.Value();
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
-
static
|
|
378
|
+
static InstanceMemory *AllocateAsyncMemory(InstanceData *instance)
|
|
379
379
|
{
|
|
380
|
-
|
|
381
|
-
|
|
380
|
+
for (Size i = 1; i < instance->memories.len; i++) {
|
|
381
|
+
InstanceMemory *mem = instance->memories[i];
|
|
382
382
|
|
|
383
|
-
// Account for allocator overhead
|
|
384
|
-
size -= 256;
|
|
385
|
-
|
|
386
|
-
uint8_t *ptr = (uint8_t *)Allocator::Allocate(alloc, size);
|
|
387
|
-
uint8_t *aligned = AlignUp(ptr, 16);
|
|
388
|
-
Size delta = AlignLen(aligned - ptr, 16);
|
|
389
|
-
|
|
390
|
-
return MakeSpan(aligned, size - delta);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
static InstanceMemory *AllocateCallMemory(InstanceData *instance)
|
|
394
|
-
{
|
|
395
|
-
for (InstanceMemory *mem: instance->memories) {
|
|
396
383
|
if (!mem->depth)
|
|
397
384
|
return mem;
|
|
398
385
|
}
|
|
399
386
|
|
|
400
387
|
InstanceMemory *mem = new InstanceMemory();
|
|
401
388
|
|
|
402
|
-
mem->stack =
|
|
403
|
-
|
|
389
|
+
mem->stack.len = AsyncStackSize;
|
|
390
|
+
#if defined(_WIN32)
|
|
391
|
+
mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
392
|
+
#elif defined(__APPLE__)
|
|
393
|
+
mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
394
|
+
#else
|
|
395
|
+
mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
|
|
396
|
+
#endif
|
|
397
|
+
RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
|
|
398
|
+
|
|
399
|
+
mem->heap.len = AsyncHeapSize;
|
|
400
|
+
#ifdef _WIN32
|
|
401
|
+
mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
402
|
+
#else
|
|
403
|
+
mem->heap.ptr = (uint8_t *)mmap(nullptr, mem->heap.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
404
|
+
#endif
|
|
405
|
+
RG_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
|
|
404
406
|
|
|
405
407
|
if (instance->memories.Available()) {
|
|
406
408
|
instance->memories.Append(mem);
|
|
@@ -422,7 +424,7 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
|
|
|
422
424
|
return env.Null();
|
|
423
425
|
}
|
|
424
426
|
|
|
425
|
-
InstanceMemory *mem =
|
|
427
|
+
InstanceMemory *mem = instance->memories[0];
|
|
426
428
|
CallData call(env, instance, func, mem);
|
|
427
429
|
|
|
428
430
|
return call.Run(info);
|
|
@@ -482,7 +484,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
|
482
484
|
if (RG_UNLIKELY(!AnalyseFunction(instance, &func)))
|
|
483
485
|
return env.Null();
|
|
484
486
|
|
|
485
|
-
InstanceMemory *mem =
|
|
487
|
+
InstanceMemory *mem = instance->memories[0];
|
|
486
488
|
CallData call(env, instance, &func, mem);
|
|
487
489
|
|
|
488
490
|
return call.Run(info);
|
|
@@ -558,7 +560,7 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
|
|
|
558
560
|
return env.Null();
|
|
559
561
|
}
|
|
560
562
|
|
|
561
|
-
InstanceMemory *mem =
|
|
563
|
+
InstanceMemory *mem = AllocateAsyncMemory(instance);
|
|
562
564
|
AsyncCall *async = new AsyncCall(env, instance, func, mem, callback);
|
|
563
565
|
|
|
564
566
|
if (async->Prepare(info) && instance->debug) {
|
|
@@ -601,10 +603,10 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
601
603
|
return false;
|
|
602
604
|
}
|
|
603
605
|
|
|
604
|
-
|
|
606
|
+
uint32_t parameters_len = parameters.Length();
|
|
605
607
|
|
|
606
608
|
if (parameters_len) {
|
|
607
|
-
Napi::String str = ((Napi::Value)parameters[
|
|
609
|
+
Napi::String str = ((Napi::Value)parameters[parameters_len - 1]).As<Napi::String>();
|
|
608
610
|
|
|
609
611
|
if (str.IsString() && str.Utf8Value() == "...") {
|
|
610
612
|
func->variadic = true;
|
|
@@ -657,9 +659,13 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
657
659
|
if (!ParseClassicFunction(env, info[0u].As<Napi::String>(), info[1u], info[2u].As<Napi::Array>(), func))
|
|
658
660
|
return env.Null();
|
|
659
661
|
} else if (info.Length() >= 1) {
|
|
660
|
-
|
|
662
|
+
if (!info[0].IsString()) {
|
|
663
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for prototype, expected string", GetValueType(instance, info[0]));
|
|
664
|
+
return env.Null();
|
|
665
|
+
}
|
|
661
666
|
|
|
662
|
-
|
|
667
|
+
std::string proto = info[0u].As<Napi::String>();
|
|
668
|
+
if (!ParsePrototype(env, proto.c_str(), func))
|
|
663
669
|
return env.Null();
|
|
664
670
|
} else {
|
|
665
671
|
ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, not %1", info.Length());
|
|
@@ -788,6 +794,7 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
788
794
|
ADD_CONVENTION("cdecl", CallConvention::Cdecl);
|
|
789
795
|
ADD_CONVENTION("stdcall", CallConvention::Stdcall);
|
|
790
796
|
ADD_CONVENTION("fastcall", CallConvention::Fastcall);
|
|
797
|
+
ADD_CONVENTION("thiscall", CallConvention::Thiscall);
|
|
791
798
|
|
|
792
799
|
#undef ADD_CONVENTION
|
|
793
800
|
|
|
@@ -930,8 +937,27 @@ void FunctionInfo::Unref() const
|
|
|
930
937
|
|
|
931
938
|
InstanceData::InstanceData()
|
|
932
939
|
{
|
|
933
|
-
|
|
934
|
-
|
|
940
|
+
InstanceMemory *mem = new InstanceMemory();
|
|
941
|
+
|
|
942
|
+
mem->stack.len = SyncStackSize;
|
|
943
|
+
#if defined(_WIN32)
|
|
944
|
+
mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
945
|
+
#elif defined(__APPLE__)
|
|
946
|
+
mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
947
|
+
#else
|
|
948
|
+
mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
|
|
949
|
+
#endif
|
|
950
|
+
RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
|
|
951
|
+
|
|
952
|
+
mem->heap.len = SyncHeapSize;
|
|
953
|
+
#ifdef _WIN32
|
|
954
|
+
mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
955
|
+
#else
|
|
956
|
+
mem->heap.ptr = (uint8_t *)mmap(nullptr, mem->heap.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
957
|
+
#endif
|
|
958
|
+
RG_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
|
|
959
|
+
|
|
960
|
+
memories.Append(mem);
|
|
935
961
|
}
|
|
936
962
|
|
|
937
963
|
InstanceData::~InstanceData()
|
|
@@ -957,7 +983,6 @@ static void SetExports(Napi::Env env, Func func)
|
|
|
957
983
|
func("out", Napi::Function::New(env, MarkOut));
|
|
958
984
|
func("inout", Napi::Function::New(env, MarkInOut));
|
|
959
985
|
|
|
960
|
-
func("internal", Napi::Boolean::New(env, true));
|
|
961
986
|
#if defined(_WIN32)
|
|
962
987
|
func("extension", Napi::String::New(env, ".dll"));
|
|
963
988
|
#elif defined(__APPLE__)
|
|
@@ -1009,6 +1034,7 @@ static void InitInternal(v8::Local<v8::Object> target, v8::Local<v8::Value>,
|
|
|
1009
1034
|
FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
|
|
1010
1035
|
|
|
1011
1036
|
SetExports(env_napi, [&](const char *name, Napi::Value value) { SetValue(env, target, name, value); });
|
|
1037
|
+
SetValue(env, target, "internal", Napi::Boolean::New(env_cxx, true));
|
|
1012
1038
|
}
|
|
1013
1039
|
|
|
1014
1040
|
#else
|
|
@@ -1024,6 +1050,7 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
1024
1050
|
FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
|
|
1025
1051
|
|
|
1026
1052
|
SetExports(env, [&](const char *name, Napi::Value value) { exports.Set(name, value); });
|
|
1053
|
+
exports.Set("internal", Napi::Boolean::New(env, false));
|
|
1027
1054
|
|
|
1028
1055
|
return exports;
|
|
1029
1056
|
}
|
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;
|
|
@@ -108,12 +109,14 @@ struct LibraryHolder {
|
|
|
108
109
|
enum class CallConvention {
|
|
109
110
|
Cdecl,
|
|
110
111
|
Stdcall,
|
|
111
|
-
Fastcall
|
|
112
|
+
Fastcall,
|
|
113
|
+
Thiscall
|
|
112
114
|
};
|
|
113
115
|
static const char *const CallConventionNames[] = {
|
|
114
116
|
"Cdecl",
|
|
115
117
|
"Stdcall",
|
|
116
|
-
"Fastcall"
|
|
118
|
+
"Fastcall",
|
|
119
|
+
"Thiscall"
|
|
117
120
|
};
|
|
118
121
|
|
|
119
122
|
struct ParameterInfo {
|
|
@@ -162,6 +165,9 @@ struct FunctionInfo {
|
|
|
162
165
|
#if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__) || defined(_WIN64)
|
|
163
166
|
bool forward_fp;
|
|
164
167
|
#endif
|
|
168
|
+
#if defined(__i386__) || defined(_M_IX86)
|
|
169
|
+
bool fast;
|
|
170
|
+
#endif
|
|
165
171
|
|
|
166
172
|
~FunctionInfo();
|
|
167
173
|
|
|
@@ -189,7 +195,7 @@ struct InstanceData {
|
|
|
189
195
|
bool debug;
|
|
190
196
|
uint64_t tag_lower;
|
|
191
197
|
|
|
192
|
-
LocalArray<InstanceMemory *,
|
|
198
|
+
LocalArray<InstanceMemory *, 6> memories;
|
|
193
199
|
|
|
194
200
|
BlockAllocator str_alloc;
|
|
195
201
|
};
|