Skip to content

Commit bd1b90b

Browse files
committed
fixup! src,lib: initial ffi implementation
1 parent 5e33eeb commit bd1b90b

3 files changed

Lines changed: 87 additions & 43 deletions

File tree

lib/ffi.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const {
1010
const {
1111
setCallBuffer,
1212
getBufferPointer: getBufferPointerInternal,
13-
addSignature,
13+
FfiSignature,
1414
makeCall,
1515
getSymbol,
1616
getLibrary,
@@ -163,6 +163,7 @@ function getNativeFunction(lib, funcName, ret, args) {
163163
const argWriters = args.map(getWriter);
164164
ret = normalizeTypeToFfiTypes(ret);
165165
args = args.map(normalizeTypeToFfiTypes);
166+
166167
let libPtr = libCache[lib];
167168
if (!libCache[lib]) {
168169
libPtr = libCache[lib] = getLibrary(lib === NULL ? null : lib);
@@ -172,11 +173,12 @@ function getNativeFunction(lib, funcName, ret, args) {
172173
if (funcPtr === 0n) {
173174
throw new Error(`Symbol "${funcName}" not found`);
174175
}
175-
const sigPtr = addSignature(funcPtr, types[ret], args.map((n) => types[n]));
176+
177+
const sig = new FfiSignature(funcPtr, types[ret], args.map((n) => types[n]));
176178

177179
return function(...callArgs) {
178180
let offset = 0;
179-
offset = writers.pointer(offset, sigPtr);
181+
offset = writers.pointer(offset, sig.pointer); // TODO is this ref enough to keep sig alive?
180182
offset += POINTER_SIZE; // for the return value
181183
let argsOffset = offset + (args.length * POINTER_SIZE);
182184
for (let i = 0; i < args.length; i++) {

src/node_ffi.cc

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
#include "node_ffi.h"
22
#include "env-inl.h"
3+
#include "env.h"
34
#include "ffi.h"
45
#include "node_binding.h"
6+
#include "util.h"
57
#include "v8-array-buffer.h"
68
#include "v8-function-callback.h"
79
#include "v8-primitive.h"
810
#include "util-inl.h"
911
#include "node_external_reference.h"
12+
#include "v8-fast-api-calls.h"
13+
#include "v8-template.h"
1014

1115
using v8::Context;
1216
using v8::ArrayBuffer;
@@ -15,6 +19,10 @@ using v8::Number;
1519
using v8::Array;
1620
using v8::Isolate;
1721
using v8::String;
22+
using v8::FunctionCallbackInfo;
23+
using v8::FunctionTemplate;
24+
using v8::FastApiCallbackOptions;
25+
using v8::CFunction;
1826

1927
namespace node {
2028
namespace ffi {
@@ -24,7 +32,7 @@ static bool lossless = false;
2432
#define ReturnBigInt(isolate, ptr) args.GetReturnValue()\
2533
.Set(BigInt::NewFromUnsigned(isolate, (uint64_t)ptr))
2634

27-
void GetLibrary(const v8::FunctionCallbackInfo<Value>& args) {
35+
void GetLibrary(const FunctionCallbackInfo<Value>& args) {
2836
Environment* env = Environment::GetCurrent(args);
2937

3038
bool isNull = true;
@@ -56,7 +64,7 @@ void GetLibrary(const v8::FunctionCallbackInfo<Value>& args) {
5664
ReturnBigInt(env->isolate(), lib);
5765
}
5866

59-
void GetSymbol(const v8::FunctionCallbackInfo<Value>& args) {
67+
void GetSymbol(const FunctionCallbackInfo<Value>& args) {
6068
Environment* env = Environment::GetCurrent(args);
6169
CHECK(args[0]->IsBigInt());
6270
binding::DLib * lib = (binding::DLib *)args[0].As<BigInt>()
@@ -67,14 +75,14 @@ void GetSymbol(const v8::FunctionCallbackInfo<Value>& args) {
6775
ReturnBigInt(env->isolate(), symbol);
6876
}
6977

70-
void GetBufferPointer(const v8::FunctionCallbackInfo<Value>& args) {
78+
void GetBufferPointer(const FunctionCallbackInfo<Value>& args) {
7179
CHECK(args[0]->IsArrayBuffer());
7280
void* data = args[0].As<ArrayBuffer>()->Data();
7381

7482
ReturnBigInt(args.GetIsolate(), data);
7583
}
7684

77-
void SetCallBuffer(const v8::FunctionCallbackInfo<Value>& args) {
85+
void SetCallBuffer(const FunctionCallbackInfo<Value>& args) {
7886
CHECK(args[0]->IsArrayBuffer());
7987
Local<ArrayBuffer> ab = args[0].As<ArrayBuffer>();
8088

@@ -83,53 +91,67 @@ void SetCallBuffer(const v8::FunctionCallbackInfo<Value>& args) {
8391
ReturnBigInt(args.GetIsolate(), callBuffer);
8492
}
8593

86-
void AddSignature(const v8::FunctionCallbackInfo<Value>& args) {
87-
Isolate * isolate = args.GetIsolate();
88-
Local<Context> context = isolate->GetCurrentContext();
89-
90-
CHECK(args[0]->IsBigInt());
91-
void (* fnPtr)() = (void (*)()) args[0].As<BigInt>()->Uint64Value(&lossless);
92-
93-
CHECK(args[1]->IsBigInt());
94-
ffi_type * retType =
95-
reinterpret_cast<ffi_type*>(args[1].As<BigInt>()->Uint64Value(&lossless));
94+
FfiSignature::FfiSignature(
95+
Environment* env,
96+
Local<Object> object,
97+
Local<BigInt> fn,
98+
Local<BigInt> retType,
99+
Local<Array> argTypes) : BaseObject(env, object) {
100+
Local<Context> context = env->context();
96101

97-
CHECK(args[2]->IsArray());
98-
Local<Array> arguments = args[2].As<Array>();
99-
100-
uint32_t argc = arguments->Length();
101-
ffi_type** argv =
102+
cif_ = reinterpret_cast<ffi_cif*>(malloc(sizeof(ffi_cif)));
103+
fn_ = (void (*)()) fn->Uint64Value(&lossless);
104+
uint32_t argc = argTypes->Length();
105+
argvTypes_ =
102106
reinterpret_cast<ffi_type**>(malloc(sizeof(ffi_type *) * argc));
107+
108+
ffi_type * retTyp =
109+
reinterpret_cast<ffi_type*>(retType->Uint64Value(&lossless));
103110
for (uint32_t i = 0; i < argc; i++) {
104-
Local<Value> val = arguments->Get(context, i).ToLocalChecked();
111+
Local<Value> val = argTypes->Get(context, i).ToLocalChecked();
105112
CHECK(val->IsBigInt());
106113
uint64_t arg = val.As<BigInt>()->Uint64Value(&lossless);
107-
argv[i] = reinterpret_cast<ffi_type*>(arg);
114+
argvTypes_[i] = reinterpret_cast<ffi_type*>(arg);
108115
}
109116

110-
// TODO(bengl) throw all of this into FfiSignature constructor, and destruct
111-
// accordingly
112-
ffi_cif * cif = reinterpret_cast<ffi_cif*>(malloc(sizeof(ffi_cif)));
113-
ffi_prep_cif(cif, FFI_DEFAULT_ABI, argc, retType, argv);
117+
ffi_prep_cif(cif_, FFI_DEFAULT_ABI, argc, retTyp, argvTypes_);
118+
}
114119

115-
FfiSignature* sig = new FfiSignature();
116-
sig->cif = cif;
117-
sig->argvTypes = argv;
118-
sig->fn = fnPtr;
120+
FfiSignature::~FfiSignature() {
121+
free(cif_);
122+
free(argvTypes_);
123+
}
119124

120-
Local<BigInt> sigPtr = BigInt::NewFromUnsigned(isolate, (uint64_t)sig);
121-
args.GetReturnValue().Set(sigPtr);
125+
void FfiSignature::MemoryInfo(MemoryTracker* tracker) const {
126+
// TODO(bengl)
122127
}
123128

124-
void MakeCall(const v8::FunctionCallbackInfo<Value> &args) {
129+
void FfiSignature::New(const FunctionCallbackInfo<Value>& args) {
130+
CHECK(args.IsConstructCall());
131+
CHECK(args[0]->IsBigInt());
132+
CHECK(args[1]->IsBigInt());
133+
CHECK(args[2]->IsArray());
134+
Isolate * isolate = args.GetIsolate();
135+
Environment * env = Environment::GetCurrent(isolate);
136+
137+
FfiSignature* sig = new FfiSignature(
138+
env, args.This(), args[0].As<BigInt>(), args[1].As<BigInt>(), args[2].As<Array>());
139+
140+
args.This()->Set(
141+
env->context(),
142+
OneByteString(isolate, "pointer"),
143+
BigInt::NewFromUnsigned(isolate, (uint64_t)sig)).Check();
144+
}
145+
146+
void MakeCall(const FunctionCallbackInfo<Value> &args) {
125147
char* callBuffer = reinterpret_cast<char*>(
126148
Realm::GetBindingData<FfiBindingData>(args)->callBuffer);
127149
FfiSignature * sig = *reinterpret_cast<FfiSignature **>(callBuffer);
128150
char* rvalue = callBuffer + sizeof(char*);
129151
char** avalues = reinterpret_cast<char**>(rvalue + sizeof(char*));
130152
ffi_call(
131-
sig->cif,
132-
sig->fn,
153+
sig->cif_,
154+
sig->fn_,
133155
reinterpret_cast<void*>(rvalue),
134156
reinterpret_cast<void**>(avalues));
135157
}
@@ -143,6 +165,7 @@ void Initialize(
143165
Local<Value> unused,
144166
Local<Context> context,
145167
void* priv) {
168+
Environment * env = Environment::GetCurrent(context);
146169
Isolate* isolate = context->GetIsolate();
147170
Realm* realm = Realm::GetCurrent(context);
148171
FfiBindingData* const binding_data =
@@ -151,11 +174,15 @@ void Initialize(
151174

152175
SetMethod(context, target, "setCallBuffer", SetCallBuffer);
153176
SetMethod(context, target, "getBufferPointer", GetBufferPointer);
154-
SetMethod(context, target, "addSignature", AddSignature);
155177
SetMethod(context, target, "makeCall", MakeCall);
156178
SetMethod(context, target, "getSymbol", GetSymbol);
157179
SetMethod(context, target, "getLibrary", GetLibrary);
158180

181+
Local<FunctionTemplate> tmpl = NewFunctionTemplate(isolate, FfiSignature::New);
182+
tmpl->InstanceTemplate()->SetInternalFieldCount(FfiSignature::kInternalFieldCount);
183+
tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
184+
SetConstructorFunction(context, target, "FfiSignature", tmpl);
185+
159186
Local<Object> types = Object::New(isolate);
160187
#define NODE_FFI_SET_TYPE_CONSTANT(name, typ) types->Set(context, \
161188
OneByteString(isolate, #name), \
@@ -231,7 +258,7 @@ void Initialize(
231258
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
232259
registry->Register(SetCallBuffer);
233260
registry->Register(GetBufferPointer);
234-
registry->Register(AddSignature);
261+
registry->Register(FfiSignature::New);
235262
registry->Register(MakeCall);
236263
registry->Register(GetSymbol);
237264
registry->Register(GetLibrary);

src/node_ffi.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,30 @@
1515
using v8::Local;
1616
using v8::Object;
1717
using v8::Value;
18+
using v8::BigInt;
19+
using v8::Array;
20+
using v8::Context;
1821

1922
namespace node {
2023
namespace ffi {
2124

22-
class FfiSignature {
25+
class FfiSignature : public BaseObject {
2326
public:
24-
ffi_cif * cif;
25-
ffi_type ** argvTypes;
26-
void (* fn)();
27+
FfiSignature(
28+
Environment* env,
29+
Local<Object> object,
30+
Local<BigInt> fn,
31+
Local<BigInt> retType,
32+
Local<Array> argTypes);
33+
~FfiSignature() override;
34+
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
35+
void MemoryInfo(MemoryTracker* tracker) const override;
36+
SET_SELF_SIZE(FfiSignature)
37+
SET_MEMORY_INFO_NAME(FfiSignature)
38+
39+
ffi_cif * cif_;
40+
ffi_type ** argvTypes_;
41+
void (* fn_)();
2742
};
2843

2944
class FfiBindingData : public BaseObject {

0 commit comments

Comments
 (0)