koffi 3.0.0 → 3.0.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/CHANGELOG.md +9 -1
- package/README.md +5 -4
- package/cnoke.cjs +3 -3
- package/doc/benchmarks.md +23 -46
- package/doc/callbacks.md +4 -13
- package/doc/contribute.md +3 -3
- package/doc/index.md +3 -2
- package/doc/migration.md +100 -0
- package/doc/start.md +7 -5
- package/index.d.ts +308 -308
- package/index.js +2 -1
- package/indirect.d.ts +322 -0
- package/indirect.js +2 -1
- package/package.json +20 -18
- package/src/koffi/CMakeLists.txt +19 -12
- package/src/koffi/index.cjs +65 -16
- package/src/koffi/index.js +105 -16
- package/src/koffi/indirect.cjs +65 -16
- package/src/koffi/indirect.js +105 -16
- package/src/koffi/src/abi/arm64.cc +29 -29
- package/src/koffi/src/abi/riscv64.cc +29 -29
- package/src/koffi/src/abi/x64sysv.cc +25 -25
- package/src/koffi/src/abi/x64win.cc +63 -63
- package/src/koffi/src/abi/x86.cc +66 -65
- package/src/koffi/src/call.cc +2 -2
- package/src/koffi/src/ffi.cc +64 -8
- package/src/koffi/src/ffi.hh +9 -6
- package/src/koffi/src/primitives.inc +1 -4
- package/src/koffi/src/util.cc +175 -121
- package/src/koffi/src/util.hh +13 -14
package/src/koffi/src/abi/x86.cc
CHANGED
|
@@ -36,19 +36,19 @@ extern "C" double ForwardCallDR(const void *func, uint8_t *sp, uint8_t **out_sav
|
|
|
36
36
|
enum class AbiOpcode {
|
|
37
37
|
#define PRIMITIVE(Name) Push ## Name,
|
|
38
38
|
#include "../primitives.inc"
|
|
39
|
-
|
|
39
|
+
PushAggregateStack,
|
|
40
40
|
#define PRIMITIVE(Name) Run ## Name,
|
|
41
41
|
#include "../primitives.inc"
|
|
42
42
|
RunAggregateG,
|
|
43
43
|
RunAggregateF,
|
|
44
44
|
RunAggregateD,
|
|
45
|
-
|
|
45
|
+
RunAggregateMem,
|
|
46
46
|
#define PRIMITIVE(Name) Run ## Name ## R,
|
|
47
47
|
#include "../primitives.inc"
|
|
48
48
|
RunAggregateGR,
|
|
49
49
|
RunAggregateFR,
|
|
50
50
|
RunAggregateDR,
|
|
51
|
-
|
|
51
|
+
RunAggregateMemR,
|
|
52
52
|
Yield,
|
|
53
53
|
CallG,
|
|
54
54
|
CallF,
|
|
@@ -61,7 +61,7 @@ enum class AbiOpcode {
|
|
|
61
61
|
#define PRIMITIVE(Name) Return ## Name,
|
|
62
62
|
#include "../primitives.inc"
|
|
63
63
|
ReturnAggregateReg,
|
|
64
|
-
|
|
64
|
+
ReturnAggregateMem
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
static inline void *Code2Op(AbiOpcode code)
|
|
@@ -119,14 +119,14 @@ bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func)
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
if (param.type->primitive == PrimitiveKind::Record || param.type->primitive == PrimitiveKind::Union) {
|
|
122
|
-
func->sync.Append({ .op = Code2Op(AbiOpcode::
|
|
123
|
-
func->async.Append({ .op = Code2Op(AbiOpcode::
|
|
122
|
+
func->sync.Append({ .op = Code2Op(AbiOpcode::PushAggregateStack), .a = param.offset, .b1 = (int16_t)(offset * 4), .b2 = (int16_t)param.directions, .type = param.type });
|
|
123
|
+
func->async.Append({ .op = Code2Op(AbiOpcode::PushAggregateStack), .a = param.offset, .b1 = (int16_t)(offset * 4), .b2 = (int16_t)param.directions, .type = param.type });
|
|
124
124
|
} else {
|
|
125
125
|
int delta = (int)AbiOpcode::PushVoid - (int)PrimitiveKind::Void;
|
|
126
126
|
AbiOpcode code = (AbiOpcode)((int)param.type->primitive + delta);
|
|
127
127
|
|
|
128
|
-
func->sync.Append({ .op = Code2Op(code), .a = param.offset, .b1 = offset, .b2 = (int16_t)param.directions, .type = param.type });
|
|
129
|
-
func->async.Append({ .op = Code2Op(code), .a = param.offset, .b1 = offset, .b2 = (int16_t)param.directions, .type = param.type });
|
|
128
|
+
func->sync.Append({ .op = Code2Op(code), .a = param.offset, .b1 = (int16_t)(offset * 4), .b2 = (int16_t)param.directions, .type = param.type });
|
|
129
|
+
func->async.Append({ .op = Code2Op(code), .a = param.offset, .b1 = (int16_t)(offset * 4), .b2 = (int16_t)param.directions, .type = param.type });
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
|
|
@@ -232,12 +232,12 @@ bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func)
|
|
|
232
232
|
func->async.Append({ .op = Code2Op(call) });
|
|
233
233
|
func->async.Append({ .op = Code2Op(AbiOpcode::ReturnAggregateReg), .type = func->ret.type });
|
|
234
234
|
} else {
|
|
235
|
-
AbiOpcode run = fast ? AbiOpcode::
|
|
235
|
+
AbiOpcode run = fast ? AbiOpcode::RunAggregateMemR : AbiOpcode::RunAggregateMem;
|
|
236
236
|
AbiOpcode call = fast ? AbiOpcode::CallStackR : AbiOpcode::CallStack;
|
|
237
237
|
|
|
238
238
|
func->sync.Append({ .op = Code2Op(run), .a = (int32_t)func->ret.type->size, .type = func->ret.type });
|
|
239
239
|
func->async.Append({ .op = Code2Op(call), .a = (int32_t)func->ret.type->size });
|
|
240
|
-
func->async.Append({ .op = Code2Op(AbiOpcode::
|
|
240
|
+
func->async.Append({ .op = Code2Op(AbiOpcode::ReturnAggregateMem), .type = func->ret.type });
|
|
241
241
|
}
|
|
242
242
|
} break;
|
|
243
243
|
case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
|
|
@@ -298,7 +298,7 @@ namespace {
|
|
|
298
298
|
#define NEXT() \
|
|
299
299
|
break
|
|
300
300
|
|
|
301
|
-
napi_value RunLoop(CallData *call, napi_value *args,
|
|
301
|
+
napi_value RunLoop(CallData *call, napi_value *args, uint8_t *base, const AbiInstruction *inst)
|
|
302
302
|
{
|
|
303
303
|
for (;; ++inst) {
|
|
304
304
|
switch ((intptr_t)inst->op) {
|
|
@@ -328,7 +328,7 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
328
328
|
return call->env.Null(); \
|
|
329
329
|
} \
|
|
330
330
|
\
|
|
331
|
-
*(base + inst->b1) = (uint32_t)v; \
|
|
331
|
+
*(uint32_t *)(base + inst->b1) = (uint32_t)v; \
|
|
332
332
|
} while (false)
|
|
333
333
|
#define INTEGER32_SWAP(CType) \
|
|
334
334
|
do { \
|
|
@@ -338,7 +338,7 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
338
338
|
return call->env.Null(); \
|
|
339
339
|
} \
|
|
340
340
|
\
|
|
341
|
-
*(base + inst->b1) = (uint32_t)ReverseBytes(v); \
|
|
341
|
+
*(uint32_t *)(base + inst->b1) = (uint32_t)ReverseBytes(v); \
|
|
342
342
|
} while (false)
|
|
343
343
|
#define INTEGER64(CType) \
|
|
344
344
|
do { \
|
|
@@ -459,7 +459,7 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
459
459
|
NEXT();
|
|
460
460
|
}
|
|
461
461
|
OP(PushPrototype) { K_UNREACHABLE(); return call->env.Null(); }
|
|
462
|
-
OP(
|
|
462
|
+
OP(PushAggregateStack) {
|
|
463
463
|
napi_value arg = args[inst->a];
|
|
464
464
|
|
|
465
465
|
if (!IsObject(call->env, arg)) [[unlikely]] {
|
|
@@ -482,22 +482,22 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
482
482
|
|
|
483
483
|
#define INTEGER32(Suffix, CType) \
|
|
484
484
|
do { \
|
|
485
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCall ## Suffix(call->native,
|
|
485
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCall ## Suffix(call->native, base, &call->saved_sp)); \
|
|
486
486
|
return NewInt(call->env, (CType)eax); \
|
|
487
487
|
} while (false)
|
|
488
488
|
#define INTEGER32_SWAP(Suffix, CType) \
|
|
489
489
|
do { \
|
|
490
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCall ## Suffix(call->native,
|
|
490
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCall ## Suffix(call->native, base, &call->saved_sp)); \
|
|
491
491
|
return NewInt(call->env, ReverseBytes((CType)eax)); \
|
|
492
492
|
} while (false)
|
|
493
493
|
#define INTEGER64(Suffix, CType) \
|
|
494
494
|
do { \
|
|
495
|
-
uint64_t ret = WRAP(ForwardCall ## Suffix(call->native,
|
|
495
|
+
uint64_t ret = WRAP(ForwardCall ## Suffix(call->native, base, &call->saved_sp)); \
|
|
496
496
|
return NewInt(call->env, (CType)ret); \
|
|
497
497
|
} while (false)
|
|
498
498
|
#define INTEGER64_SWAP(Suffix, CType) \
|
|
499
499
|
do { \
|
|
500
|
-
uint64_t ret = WRAP(ForwardCall ## Suffix(call->native,
|
|
500
|
+
uint64_t ret = WRAP(ForwardCall ## Suffix(call->native, base, &call->saved_sp)); \
|
|
501
501
|
return NewInt(call->env, ReverseBytes((CType)ret)); \
|
|
502
502
|
} while (false)
|
|
503
503
|
#define DISPOSE(Ptr) \
|
|
@@ -508,11 +508,11 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
508
508
|
} while (false)
|
|
509
509
|
|
|
510
510
|
OP(RunVoid) {
|
|
511
|
-
WRAP(ForwardCallG(call->native,
|
|
511
|
+
WRAP(ForwardCallG(call->native, base, &call->saved_sp));
|
|
512
512
|
return nullptr;
|
|
513
513
|
}
|
|
514
514
|
OP(RunBool) {
|
|
515
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native,
|
|
515
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native, base, &call->saved_sp));
|
|
516
516
|
return Napi::Boolean::New(call->env, eax & 0x1);
|
|
517
517
|
}
|
|
518
518
|
OP(RunInt8) { INTEGER32(G, int8_t); }
|
|
@@ -530,68 +530,68 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
530
530
|
OP(RunUInt64) { INTEGER64(G, uint64_t); }
|
|
531
531
|
OP(RunUInt64S) { INTEGER64_SWAP(G, uint64_t); }
|
|
532
532
|
OP(RunString) {
|
|
533
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native,
|
|
533
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native, base, &call->saved_sp));
|
|
534
534
|
napi_value value = eax ? Napi::String::New(call->env, (const char *)eax) : call->env.Null();
|
|
535
535
|
DISPOSE((void *)eax);
|
|
536
536
|
return value;
|
|
537
537
|
}
|
|
538
538
|
OP(RunString16) {
|
|
539
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native,
|
|
539
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native, base, &call->saved_sp));
|
|
540
540
|
napi_value value = eax ? Napi::String::New(call->env, (const char16_t *)eax) : call->env.Null();
|
|
541
541
|
DISPOSE((void *)eax);
|
|
542
542
|
return value;
|
|
543
543
|
}
|
|
544
544
|
OP(RunString32) {
|
|
545
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native,
|
|
545
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native, base, &call->saved_sp));
|
|
546
546
|
napi_value value = eax ? MakeStringFromUTF32(call->env, (const char32_t *)eax) : call->env.Null();
|
|
547
547
|
DISPOSE((void *)eax);
|
|
548
548
|
return value;
|
|
549
549
|
}
|
|
550
550
|
OP(RunPointer) {
|
|
551
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native,
|
|
551
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native, base, &call->saved_sp));
|
|
552
552
|
napi_value value = eax ? WrapPointer(call->env, inst->type, (void *)eax) : call->env.Null();
|
|
553
553
|
DISPOSE((void *)eax);
|
|
554
554
|
return value;
|
|
555
555
|
}
|
|
556
556
|
OP(RunCallback) {
|
|
557
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native,
|
|
557
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native, base, &call->saved_sp));
|
|
558
558
|
return eax ? WrapPointer(call->env, inst->type, (void *)eax) : call->env.Null();
|
|
559
559
|
}
|
|
560
560
|
OP(RunRecord) { K_UNREACHABLE(); return call->env.Null(); }
|
|
561
561
|
OP(RunUnion) { K_UNREACHABLE(); return call->env.Null(); }
|
|
562
562
|
OP(RunArray) { K_UNREACHABLE(); return call->env.Null(); }
|
|
563
563
|
OP(RunFloat32) {
|
|
564
|
-
float f = WRAP(ForwardCallF(call->native,
|
|
564
|
+
float f = WRAP(ForwardCallF(call->native, base, &call->saved_sp));
|
|
565
565
|
return Napi::Number::New(call->env, (double)f);
|
|
566
566
|
}
|
|
567
567
|
OP(RunFloat64) {
|
|
568
|
-
double d = WRAP(ForwardCallD(call->native,
|
|
568
|
+
double d = WRAP(ForwardCallD(call->native, base, &call->saved_sp));
|
|
569
569
|
return Napi::Number::New(call->env, d);
|
|
570
570
|
}
|
|
571
571
|
OP(RunPrototype) { K_UNREACHABLE(); return call->env.Null(); }
|
|
572
572
|
OP(RunAggregateG) {
|
|
573
|
-
auto ret = WRAP(ForwardCallG(call->native,
|
|
574
|
-
return DecodeObject(call->
|
|
573
|
+
auto ret = WRAP(ForwardCallG(call->native, base, &call->saved_sp));
|
|
574
|
+
return DecodeObject(call->instance, (const uint8_t *)&ret, inst->type);
|
|
575
575
|
}
|
|
576
576
|
OP(RunAggregateF) {
|
|
577
|
-
auto ret = WRAP(ForwardCallF(call->native,
|
|
578
|
-
return DecodeObject(call->
|
|
577
|
+
auto ret = WRAP(ForwardCallF(call->native, base, &call->saved_sp));
|
|
578
|
+
return DecodeObject(call->instance, (const uint8_t *)&ret, inst->type);
|
|
579
579
|
}
|
|
580
580
|
OP(RunAggregateD) {
|
|
581
|
-
auto ret = WRAP(ForwardCallD(call->native,
|
|
582
|
-
return DecodeObject(call->
|
|
581
|
+
auto ret = WRAP(ForwardCallD(call->native, base, &call->saved_sp));
|
|
582
|
+
return DecodeObject(call->instance, (const uint8_t *)&ret, inst->type);
|
|
583
583
|
}
|
|
584
|
-
OP(
|
|
584
|
+
OP(RunAggregateMem) {
|
|
585
585
|
*(uint8_t **)base = call->AllocHeap(inst->a);
|
|
586
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native,
|
|
587
|
-
return DecodeObject(call->
|
|
586
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallG(call->native, base, &call->saved_sp));
|
|
587
|
+
return DecodeObject(call->instance, (const uint8_t *)eax, inst->type);
|
|
588
588
|
}
|
|
589
589
|
OP(RunVoidR) {
|
|
590
|
-
WRAP(ForwardCallGR(call->native,
|
|
590
|
+
WRAP(ForwardCallGR(call->native, base, &call->saved_sp));
|
|
591
591
|
return nullptr;
|
|
592
592
|
}
|
|
593
593
|
OP(RunBoolR) {
|
|
594
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native,
|
|
594
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native, base, &call->saved_sp));
|
|
595
595
|
return Napi::Boolean::New(call->env, eax & 0x1);
|
|
596
596
|
}
|
|
597
597
|
OP(RunInt8R) { INTEGER32(GR, int8_t); }
|
|
@@ -609,65 +609,65 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
609
609
|
OP(RunUInt64R) { INTEGER64(GR, uint64_t); }
|
|
610
610
|
OP(RunUInt64SR) { INTEGER64_SWAP(GR, uint64_t); }
|
|
611
611
|
OP(RunStringR) {
|
|
612
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native,
|
|
612
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native, base, &call->saved_sp));
|
|
613
613
|
napi_value value = eax ? Napi::String::New(call->env, (const char *)eax) : call->env.Null();
|
|
614
614
|
DISPOSE((void *)eax);
|
|
615
615
|
return value;
|
|
616
616
|
}
|
|
617
617
|
OP(RunString16R) {
|
|
618
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native,
|
|
618
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native, base, &call->saved_sp));
|
|
619
619
|
napi_value value = eax ? Napi::String::New(call->env, (const char16_t *)eax) : call->env.Null();
|
|
620
620
|
DISPOSE((void *)eax);
|
|
621
621
|
return value;
|
|
622
622
|
}
|
|
623
623
|
OP(RunString32R) {
|
|
624
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native,
|
|
624
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native, base, &call->saved_sp));
|
|
625
625
|
napi_value value = eax ? MakeStringFromUTF32(call->env, (const char32_t *)eax) : call->env.Null();
|
|
626
626
|
DISPOSE((void *)eax);
|
|
627
627
|
return value;
|
|
628
628
|
}
|
|
629
629
|
OP(RunPointerR) {
|
|
630
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native,
|
|
630
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native, base, &call->saved_sp));
|
|
631
631
|
napi_value value = eax ? WrapPointer(call->env, inst->type, (void *)eax) : call->env.Null();
|
|
632
632
|
DISPOSE((void *)eax);
|
|
633
633
|
return value;
|
|
634
634
|
}
|
|
635
635
|
OP(RunCallbackR) {
|
|
636
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native,
|
|
636
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native, base, &call->saved_sp));
|
|
637
637
|
return eax ? WrapPointer(call->env, inst->type, (void *)eax) : call->env.Null();
|
|
638
638
|
}
|
|
639
639
|
OP(RunRecordR) { K_UNREACHABLE(); return call->env.Null(); }
|
|
640
640
|
OP(RunUnionR) { K_UNREACHABLE(); return call->env.Null(); }
|
|
641
641
|
OP(RunArrayR) { K_UNREACHABLE(); return call->env.Null(); }
|
|
642
642
|
OP(RunFloat32R) {
|
|
643
|
-
float f = WRAP(ForwardCallFR(call->native,
|
|
643
|
+
float f = WRAP(ForwardCallFR(call->native, base, &call->saved_sp));
|
|
644
644
|
return Napi::Number::New(call->env, (double)f);
|
|
645
645
|
}
|
|
646
646
|
OP(RunFloat64R) {
|
|
647
|
-
double d = WRAP(ForwardCallDR(call->native,
|
|
647
|
+
double d = WRAP(ForwardCallDR(call->native, base, &call->saved_sp));
|
|
648
648
|
return Napi::Number::New(call->env, d);
|
|
649
649
|
}
|
|
650
650
|
OP(RunPrototypeR) { K_UNREACHABLE(); return call->env.Null(); }
|
|
651
651
|
OP(RunAggregateGR) {
|
|
652
|
-
auto ret = WRAP(ForwardCallGR(call->native,
|
|
653
|
-
return DecodeObject(call->
|
|
652
|
+
auto ret = WRAP(ForwardCallGR(call->native, base, &call->saved_sp));
|
|
653
|
+
return DecodeObject(call->instance, (const uint8_t *)&ret, inst->type);
|
|
654
654
|
}
|
|
655
655
|
OP(RunAggregateFR) {
|
|
656
|
-
auto ret = WRAP(ForwardCallFR(call->native,
|
|
657
|
-
return DecodeObject(call->
|
|
656
|
+
auto ret = WRAP(ForwardCallFR(call->native, base, &call->saved_sp));
|
|
657
|
+
return DecodeObject(call->instance, (const uint8_t *)&ret, inst->type);
|
|
658
658
|
}
|
|
659
659
|
OP(RunAggregateDR) {
|
|
660
|
-
auto ret = WRAP(ForwardCallDR(call->native,
|
|
661
|
-
return DecodeObject(call->
|
|
660
|
+
auto ret = WRAP(ForwardCallDR(call->native, base, &call->saved_sp));
|
|
661
|
+
return DecodeObject(call->instance, (const uint8_t *)&ret, inst->type);
|
|
662
662
|
}
|
|
663
|
-
OP(
|
|
663
|
+
OP(RunAggregateMemR) {
|
|
664
664
|
#if defined(_WIN32)
|
|
665
|
-
*(uint8_t **)(base +
|
|
665
|
+
*(uint8_t **)(base + 16) = call->AllocHeap(inst->a);
|
|
666
666
|
#else
|
|
667
667
|
*(uint8_t **)base = call->AllocHeap(inst->a);
|
|
668
668
|
#endif
|
|
669
|
-
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native,
|
|
670
|
-
return DecodeObject(call->
|
|
669
|
+
uint32_t eax = (uint32_t)WRAP(ForwardCallGR(call->native, base, &call->saved_sp));
|
|
670
|
+
return DecodeObject(call->instance, (const uint8_t *)eax, inst->type);
|
|
671
671
|
}
|
|
672
672
|
|
|
673
673
|
#undef DISPOSE
|
|
@@ -678,7 +678,7 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
678
678
|
|
|
679
679
|
#define CALL(Suffix) \
|
|
680
680
|
do { \
|
|
681
|
-
auto ret = WRAP(ForwardCall ## Suffix(call->native,
|
|
681
|
+
auto ret = WRAP(ForwardCall ## Suffix(call->native, base, &call->saved_sp)); \
|
|
682
682
|
memcpy(base, &ret, K_SIZE(ret)); \
|
|
683
683
|
} while (false)
|
|
684
684
|
#define DISPOSE() \
|
|
@@ -711,6 +711,7 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
711
711
|
|
|
712
712
|
OP(Yield) {
|
|
713
713
|
call->async_ip = inst + 1;
|
|
714
|
+
call->async_base = base;
|
|
714
715
|
return nullptr;
|
|
715
716
|
}
|
|
716
717
|
|
|
@@ -727,7 +728,7 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
727
728
|
OP(CallDR) { CALL(DR); return nullptr; }
|
|
728
729
|
OP(CallStackR) {
|
|
729
730
|
#if defined(_WIN32)
|
|
730
|
-
*(uint8_t **)(base +
|
|
731
|
+
*(uint8_t **)(base + 16) = call->AllocHeap(inst->a);
|
|
731
732
|
#else
|
|
732
733
|
*(uint8_t **)base = call->AllocHeap(inst->a);
|
|
733
734
|
#endif
|
|
@@ -794,10 +795,10 @@ napi_value RunLoop(CallData *call, napi_value *args, uint32_t *base, const AbiIn
|
|
|
794
795
|
return Napi::Number::New(call->env, d);
|
|
795
796
|
}
|
|
796
797
|
OP(ReturnPrototype) { K_UNREACHABLE(); return call->env.Null(); }
|
|
797
|
-
OP(ReturnAggregateReg) { return DecodeObject(call->
|
|
798
|
-
OP(
|
|
798
|
+
OP(ReturnAggregateReg) { return DecodeObject(call->instance, (const uint8_t *)base, inst->type); }
|
|
799
|
+
OP(ReturnAggregateMem) {
|
|
799
800
|
uint32_t eax = *(uint32_t *)base;
|
|
800
|
-
return DecodeObject(call->
|
|
801
|
+
return DecodeObject(call->instance, (const uint8_t *)eax, inst->type);
|
|
801
802
|
}
|
|
802
803
|
|
|
803
804
|
#undef DISPOSE
|
|
@@ -821,7 +822,7 @@ napi_value CallData::Run(const FunctionInfo *func, napi_value *args)
|
|
|
821
822
|
return env.Null();
|
|
822
823
|
|
|
823
824
|
const AbiInstruction *first = func->sync.ptr;
|
|
824
|
-
return RunLoop(this, args,
|
|
825
|
+
return RunLoop(this, args, base, first);
|
|
825
826
|
}
|
|
826
827
|
|
|
827
828
|
bool CallData::PrepareAsync(const FunctionInfo *func, napi_value *args)
|
|
@@ -832,19 +833,19 @@ bool CallData::PrepareAsync(const FunctionInfo *func, napi_value *args)
|
|
|
832
833
|
async_base = base;
|
|
833
834
|
|
|
834
835
|
const AbiInstruction *first = func->async.ptr;
|
|
835
|
-
return !RunLoop(this, args,
|
|
836
|
+
return !RunLoop(this, args, base, first); // Yield returns nullptr
|
|
836
837
|
}
|
|
837
838
|
|
|
838
839
|
void CallData::ExecuteAsync()
|
|
839
840
|
{
|
|
840
841
|
const AbiInstruction *next = async_ip++;
|
|
841
|
-
RunLoop(this, nullptr,
|
|
842
|
+
RunLoop(this, nullptr, async_base, next);
|
|
842
843
|
}
|
|
843
844
|
|
|
844
845
|
napi_value CallData::EndAsync()
|
|
845
846
|
{
|
|
846
847
|
const AbiInstruction *next = async_ip++;
|
|
847
|
-
return RunLoop(this, nullptr,
|
|
848
|
+
return RunLoop(this, nullptr, async_base, next);
|
|
848
849
|
}
|
|
849
850
|
|
|
850
851
|
void CallData::Relay(Size idx, uint8_t *sp)
|
|
@@ -1000,7 +1001,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
|
|
|
1000
1001
|
case PrimitiveKind::Record:
|
|
1001
1002
|
case PrimitiveKind::Union: {
|
|
1002
1003
|
uint8_t *ptr = (uint8_t *)args_ptr;
|
|
1003
|
-
arguments[i] = DecodeObject(
|
|
1004
|
+
arguments[i] = DecodeObject(instance, ptr, param.type);
|
|
1004
1005
|
|
|
1005
1006
|
args_ptr = (uint32_t *)AlignUp(ptr + param.type->size, 4);
|
|
1006
1007
|
} break;
|
package/src/koffi/src/call.cc
CHANGED
|
@@ -68,7 +68,7 @@ void CallData::Finalize()
|
|
|
68
68
|
K_ASSERT(IsArray(env, value));
|
|
69
69
|
|
|
70
70
|
uint32_t len = GetArrayLength(env, value);
|
|
71
|
-
DecodeElements(
|
|
71
|
+
DecodeElements(instance, value, out.ptr, out.type, len);
|
|
72
72
|
} break;
|
|
73
73
|
|
|
74
74
|
case OutArgument::Kind::Buffer: {
|
|
@@ -117,7 +117,7 @@ void CallData::Finalize()
|
|
|
117
117
|
|
|
118
118
|
u->SetRaw(out.ptr);
|
|
119
119
|
} else {
|
|
120
|
-
DecodeObject(
|
|
120
|
+
DecodeObject(instance, value, out.ptr, out.type->ref.type);
|
|
121
121
|
}
|
|
122
122
|
} break;
|
|
123
123
|
}
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -37,10 +37,12 @@ namespace K {
|
|
|
37
37
|
|
|
38
38
|
SharedData shared;
|
|
39
39
|
|
|
40
|
-
// Some
|
|
40
|
+
// Some Node-API functions are loaded dynamically to work around bugs or because they are recent
|
|
41
41
|
napi_status (NAPI_CDECL *node_api_get_buffer_info)(napi_env env, napi_value value, void **data, size_t *length);
|
|
42
42
|
napi_status (NAPI_CDECL *node_api_create_property_key_utf8)(napi_env env, const char* str, size_t length, napi_value* result);
|
|
43
43
|
napi_status (NAPI_CDECL *node_api_post_finalizer)(node_api_basic_env env, napi_finalize finalize_cb, void* finalize_data, void* finalize_hint);
|
|
44
|
+
napi_status (NAPI_CDECL *node_api_create_object_with_properties)(napi_env env, napi_value prototype_or_null, const napi_value *property_names,
|
|
45
|
+
const napi_value *property_values, size_t property_count, napi_value *result);
|
|
44
46
|
napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
|
|
45
47
|
|
|
46
48
|
static bool ChangeSize(const char *name, Napi::Value value, Size min_size, Size max_size, Size *out_size)
|
|
@@ -254,7 +256,11 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
254
256
|
|
|
255
257
|
bool skip = (info.Length() > 1);
|
|
256
258
|
bool named = skip && !IsNullOrUndefined(env, info[0]);
|
|
259
|
+
#if defined(EXTERNAL_TYPES)
|
|
260
|
+
bool redefine = named && info[0].IsExternal() && CheckValueTag(env, info[0], &TypeObjectMarker);
|
|
261
|
+
#else
|
|
257
262
|
bool redefine = named && info[0].IsObject() && CheckValueTag(env, info[0], &TypeObjectMarker);
|
|
263
|
+
#endif
|
|
258
264
|
|
|
259
265
|
if (named && !info[0].IsString() && !redefine) {
|
|
260
266
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
@@ -288,10 +294,16 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
288
294
|
TypeInfo *replace = nullptr;
|
|
289
295
|
|
|
290
296
|
if (redefine) {
|
|
297
|
+
#if defined(EXTERNAL_TYPES)
|
|
298
|
+
Napi::External<TypeInfo> external = name.As<Napi::External<TypeInfo>>();
|
|
299
|
+
replace = external.Data();
|
|
300
|
+
#else
|
|
291
301
|
TypeObject *defn = nullptr;
|
|
292
302
|
napi_unwrap(env, name, (void **)&defn);
|
|
293
303
|
|
|
294
304
|
replace = (TypeInfo *)defn->GetType();
|
|
305
|
+
#endif
|
|
306
|
+
|
|
295
307
|
type->name = replace->name;
|
|
296
308
|
|
|
297
309
|
if (replace->primitive != PrimitiveKind::Void || replace == instance->void_type) {
|
|
@@ -442,7 +454,11 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
|
|
|
442
454
|
|
|
443
455
|
bool skip = (info.Length() > 1);
|
|
444
456
|
bool named = skip && !IsNullOrUndefined(env, info[0]);
|
|
457
|
+
#if defined(EXTERNAL_TYPES)
|
|
458
|
+
bool redefine = named && info[0].IsExternal() && CheckValueTag(env, info[0], &TypeObjectMarker);
|
|
459
|
+
#else
|
|
445
460
|
bool redefine = named && info[0].IsObject() && CheckValueTag(env, info[0], &TypeObjectMarker);
|
|
461
|
+
#endif
|
|
446
462
|
|
|
447
463
|
if (named && !info[0].IsString() && !redefine) {
|
|
448
464
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
@@ -476,10 +492,16 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
|
|
|
476
492
|
TypeInfo *replace = nullptr;
|
|
477
493
|
|
|
478
494
|
if (redefine) {
|
|
495
|
+
#if defined(EXTERNAL_TYPES)
|
|
496
|
+
Napi::External<TypeInfo> external = name.As<Napi::External<TypeInfo>>();
|
|
497
|
+
replace = external.Data();
|
|
498
|
+
#else
|
|
479
499
|
TypeObject *defn = nullptr;
|
|
480
500
|
napi_unwrap(env, name, (void **)&defn);
|
|
481
501
|
|
|
482
502
|
replace = (TypeInfo *)defn->GetType();
|
|
503
|
+
#endif
|
|
504
|
+
|
|
483
505
|
type->name = replace->name;
|
|
484
506
|
|
|
485
507
|
if (replace->primitive != PrimitiveKind::Void || replace == instance->void_type) {
|
|
@@ -1338,12 +1360,13 @@ static Napi::Value CreateEnumType(const Napi::CallbackInfo &info)
|
|
|
1338
1360
|
return env.Null();
|
|
1339
1361
|
err_guard.Disable();
|
|
1340
1362
|
|
|
1341
|
-
Napi::
|
|
1363
|
+
Napi::Value wrapper = WrapType(env, type, false);
|
|
1364
|
+
Napi::Object defn = type->defn.Value();
|
|
1342
1365
|
|
|
1343
1366
|
defn.Set("values", values);
|
|
1344
1367
|
defn.Freeze();
|
|
1345
1368
|
|
|
1346
|
-
return
|
|
1369
|
+
return wrapper;
|
|
1347
1370
|
}
|
|
1348
1371
|
|
|
1349
1372
|
static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
|
|
@@ -1390,6 +1413,29 @@ static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
|
|
|
1390
1413
|
return WrapType(env, type);
|
|
1391
1414
|
}
|
|
1392
1415
|
|
|
1416
|
+
#if defined(EXTERNAL_TYPES)
|
|
1417
|
+
|
|
1418
|
+
static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
1419
|
+
{
|
|
1420
|
+
Napi::Env env = info.Env();
|
|
1421
|
+
|
|
1422
|
+
if (info.Length() < 1) {
|
|
1423
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
|
|
1424
|
+
return env.Null();
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
const TypeInfo *type = ResolveType(info[0]);
|
|
1428
|
+
if (!type)
|
|
1429
|
+
return env.Null();
|
|
1430
|
+
|
|
1431
|
+
// Make sure definition is available
|
|
1432
|
+
WrapType(env, type);
|
|
1433
|
+
|
|
1434
|
+
return type->defn.Value();
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
#endif
|
|
1438
|
+
|
|
1393
1439
|
InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size)
|
|
1394
1440
|
{
|
|
1395
1441
|
std::lock_guard<std::mutex> lock(instance->mem_mutex);
|
|
@@ -1878,11 +1924,11 @@ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
|
|
|
1878
1924
|
if (has_len) {
|
|
1879
1925
|
Size len = info[2 + has_offset].As<Napi::Number>();
|
|
1880
1926
|
|
|
1881
|
-
|
|
1882
|
-
return ret;
|
|
1927
|
+
napi_value ret = Decode(value, (Size)offset, type, &len);
|
|
1928
|
+
return Napi::Value(env, ret);
|
|
1883
1929
|
} else {
|
|
1884
|
-
|
|
1885
|
-
return ret;
|
|
1930
|
+
napi_value ret = Decode(value, (Size)offset, type);
|
|
1931
|
+
return Napi::Value(env, ret);
|
|
1886
1932
|
}
|
|
1887
1933
|
}
|
|
1888
1934
|
|
|
@@ -2417,7 +2463,7 @@ static napi_value CreateFunction(napi_env env, napi_callback native, const char
|
|
|
2417
2463
|
|
|
2418
2464
|
static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
2419
2465
|
{
|
|
2420
|
-
// Load recent
|
|
2466
|
+
// Load recent Node-API functions (version >= 9) functions dynamically
|
|
2421
2467
|
{
|
|
2422
2468
|
static std::once_flag flag;
|
|
2423
2469
|
|
|
@@ -2464,6 +2510,8 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2464
2510
|
node_api_post_finalizer = SYMBOL(node_api_post_finalizer);
|
|
2465
2511
|
}
|
|
2466
2512
|
|
|
2513
|
+
node_api_create_object_with_properties = SYMBOL(node_api_create_object_with_properties);
|
|
2514
|
+
|
|
2467
2515
|
#undef SYMBOL
|
|
2468
2516
|
});
|
|
2469
2517
|
}
|
|
@@ -2495,6 +2543,9 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2495
2543
|
exports.Set("enumeration", Napi::Function::New(env, CreateEnumType, "enumeration"));
|
|
2496
2544
|
|
|
2497
2545
|
exports.Set("type", Napi::Function::New(env, GetResolvedType, "type"));
|
|
2546
|
+
#if defined(EXTERNAL_TYPES)
|
|
2547
|
+
exports.Set("introspect", Napi::Function::New(env, GetTypeDefinition, "introspect"));
|
|
2548
|
+
#endif
|
|
2498
2549
|
|
|
2499
2550
|
exports.Set("load", Napi::Function::New(env, LoadSharedLibrary, "load"));
|
|
2500
2551
|
|
|
@@ -2573,13 +2624,18 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2573
2624
|
|
|
2574
2625
|
// Init object classes and symbols
|
|
2575
2626
|
{
|
|
2627
|
+
instance->object_constructor = Napi::Persistent(env.RunScript("Object.prototype").As<Napi::Object>());
|
|
2576
2628
|
instance->construct_lib = Napi::Persistent(LibraryHandle::InitClass(env));
|
|
2629
|
+
#if !defined(EXTERNAL_TYPES)
|
|
2577
2630
|
instance->construct_type = Napi::Persistent(TypeObject::InitClass(env));
|
|
2631
|
+
#endif
|
|
2578
2632
|
instance->construct_poll = Napi::Persistent(PollHandle::InitClass(env));
|
|
2579
2633
|
instance->active_symbol = Napi::Persistent(Napi::Symbol::New(env, "active"));
|
|
2580
2634
|
|
|
2581
2635
|
exports.Set("LibraryHandle", instance->construct_lib.Value());
|
|
2636
|
+
#if !defined(EXTERNAL_TYPES)
|
|
2582
2637
|
exports.Set("TypeObject", instance->construct_type.Value());
|
|
2638
|
+
#endif
|
|
2583
2639
|
}
|
|
2584
2640
|
|
|
2585
2641
|
// Init base types
|
package/src/koffi/src/ffi.hh
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
namespace K {
|
|
11
11
|
|
|
12
|
+
// #define EXTERNAL_POINTERS
|
|
13
|
+
// #define EXTERNAL_TYPES
|
|
14
|
+
|
|
12
15
|
static const Size DefaultSyncStackSize = Mebibytes(1);
|
|
13
16
|
static const Size DefaultSyncHeapSize = Mebibytes(2);
|
|
14
17
|
static const Size DefaultAsyncStackSize = Kibibytes(128);
|
|
@@ -66,11 +69,6 @@ struct RecordMember {
|
|
|
66
69
|
struct TypeInfo {
|
|
67
70
|
const char *name;
|
|
68
71
|
|
|
69
|
-
// Make sure primitive ends up as the upper N-API tag value when we cast TypeInfo pointers to
|
|
70
|
-
// napi_type_tag pointers. Yes, I want to do this. We don't do strict aliasing here.
|
|
71
|
-
// N.B. Some node versions don't like when one of the two tag values is 0, so make sure
|
|
72
|
-
// this does not happen! It would happen if primitive is 0 and size is 0. To avoid this
|
|
73
|
-
// situation, PrimitiveKind::Void (the only type with size 0) is explictly not 0.
|
|
74
72
|
alignas(8) PrimitiveKind primitive;
|
|
75
73
|
int32_t size;
|
|
76
74
|
int16_t align;
|
|
@@ -309,8 +307,11 @@ struct InstanceData {
|
|
|
309
307
|
const TypeInfo *str16_type;
|
|
310
308
|
const TypeInfo *str32_type;
|
|
311
309
|
|
|
310
|
+
Napi::ObjectReference object_constructor;
|
|
312
311
|
Napi::FunctionReference construct_lib;
|
|
312
|
+
#if !defined(EXTERNAL_TYPES)
|
|
313
313
|
Napi::FunctionReference construct_type;
|
|
314
|
+
#endif
|
|
314
315
|
Napi::FunctionReference construct_poll;
|
|
315
316
|
Napi::Reference<Napi::Symbol> active_symbol;
|
|
316
317
|
|
|
@@ -390,10 +391,12 @@ static_assert(MaxTrampolines <= INT16_MAX);
|
|
|
390
391
|
|
|
391
392
|
extern SharedData shared;
|
|
392
393
|
|
|
393
|
-
// Some
|
|
394
|
+
// Some Node-API functions are loaded dynamically to work around bugs or because they are recent
|
|
394
395
|
extern napi_status (NAPI_CDECL *node_api_get_buffer_info)(napi_env env, napi_value value, void **data, size_t *length);
|
|
395
396
|
extern napi_status (NAPI_CDECL *node_api_create_property_key_utf8)(napi_env env, const char* str, size_t length, napi_value* result);
|
|
396
397
|
extern napi_status (NAPI_CDECL *node_api_post_finalizer)(node_api_basic_env env, napi_finalize finalize_cb, void* finalize_data, void* finalize_hint);
|
|
398
|
+
extern napi_status (NAPI_CDECL *node_api_create_object_with_properties)(napi_env env, napi_value prototype_or_null, const napi_value *property_names,
|
|
399
|
+
const napi_value *property_values, size_t property_count, napi_value *result);
|
|
397
400
|
extern napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
|
|
398
401
|
|
|
399
402
|
InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size);
|
|
@@ -5,11 +5,8 @@
|
|
|
5
5
|
#error Please define PRIMITIVE() before including primitives.inc
|
|
6
6
|
#endif
|
|
7
7
|
|
|
8
|
-
// Void is explictly not first so that it is not 0, for reasons related to N-API type tags.
|
|
9
|
-
// Look at TypeInfo definition for more information!
|
|
10
|
-
|
|
11
|
-
PRIMITIVE(Bool)
|
|
12
8
|
PRIMITIVE(Void)
|
|
9
|
+
PRIMITIVE(Bool)
|
|
13
10
|
PRIMITIVE(Int8)
|
|
14
11
|
PRIMITIVE(UInt8)
|
|
15
12
|
PRIMITIVE(Int16)
|