[ffi] Translation + test for int32
Also introduces FFIType separate from MachineType for express ffi signatures. BUG=v8:4456 Review-Url: https://codereview.chromium.org/2639163004 Cr-Commit-Position: refs/heads/master@{#42612}
This commit is contained in:
parent
6eba6b4b89
commit
a5913c9a8e
@ -35,23 +35,50 @@ class FFIAssembler : public CodeStubAssembler {
|
||||
public:
|
||||
explicit FFIAssembler(CodeAssemblerState* state) : CodeStubAssembler(state) {}
|
||||
|
||||
Node* ToJS(Node* node, Node* context, MachineType type) {
|
||||
Node* ToJS(Node* node, Node* context, FFIType type) {
|
||||
switch (type) {
|
||||
case FFIType::kInt32:
|
||||
return ChangeInt32ToTagged(node);
|
||||
}
|
||||
UNREACHABLE();
|
||||
// TODO(mattloring): Needs to be implemented.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node* FromJS(Node* node, Node* context, MachineType type) {
|
||||
Node* FromJS(Node* node, Node* context, FFIType type) {
|
||||
switch (type) {
|
||||
case FFIType::kInt32:
|
||||
return TruncateTaggedToWord32(context, node);
|
||||
}
|
||||
UNREACHABLE();
|
||||
// TODO(mattloring): Needs to be implemented.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MachineType FFIToMachineType(FFIType type) {
|
||||
switch (type) {
|
||||
case FFIType::kInt32:
|
||||
return MachineType::Int32();
|
||||
}
|
||||
UNREACHABLE();
|
||||
return MachineType::None();
|
||||
}
|
||||
|
||||
Signature<MachineType>* FFIToMachineSignature(FFISignature* sig) {
|
||||
Signature<MachineType>::Builder sig_builder(zone(), sig->return_count(),
|
||||
sig->parameter_count());
|
||||
for (size_t i = 0; i < sig->return_count(); i++) {
|
||||
sig_builder.AddReturn(FFIToMachineType(sig->GetReturn(i)));
|
||||
}
|
||||
for (size_t j = 0; j < sig->parameter_count(); j++) {
|
||||
sig_builder.AddParam(FFIToMachineType(sig->GetParam(j)));
|
||||
}
|
||||
return sig_builder.Build();
|
||||
}
|
||||
|
||||
void GenerateJSToNativeWrapper(NativeFunction* func) {
|
||||
int params = static_cast<int>(func->sig->parameter_count());
|
||||
int returns = static_cast<int>(func->sig->return_count());
|
||||
ApiFunction api_func(func->start);
|
||||
ExternalReference ref(&api_func, ExternalReference::DIRECT_API_CALL,
|
||||
ExternalReference ref(&api_func, ExternalReference::BUILTIN_CALL,
|
||||
isolate());
|
||||
|
||||
Node* context_param = GetJSContextParameter();
|
||||
@ -64,7 +91,8 @@ class FFIAssembler : public CodeStubAssembler {
|
||||
FromJS(Parameter(i), context_param, func->sig->GetParam(i));
|
||||
}
|
||||
|
||||
Node* call = CallCFunctionN(func->sig, input_count, inputs);
|
||||
Node* call =
|
||||
CallCFunctionN(FFIToMachineSignature(func->sig), input_count, inputs);
|
||||
Node* return_val = UndefinedConstant();
|
||||
if (returns == 1) {
|
||||
return_val = ToJS(call, context_param, func->sig->GetReturn());
|
||||
@ -79,7 +107,7 @@ Handle<JSFunction> CompileJSToNativeWrapper(Isolate* isolate,
|
||||
int params = static_cast<int>(func.sig->parameter_count());
|
||||
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||
CodeAssemblerState state(isolate, &zone, params,
|
||||
Code::ComputeFlags(Code::FUNCTION), "js-to-native");
|
||||
Code::ComputeFlags(Code::BUILTIN), "js-to-native");
|
||||
FFIAssembler assembler(&state);
|
||||
assembler.GenerateJSToNativeWrapper(&func);
|
||||
Handle<Code> code = assembler.GenerateCode(&state);
|
||||
|
@ -18,7 +18,9 @@ void InstallFFIMap(Isolate* isolate);
|
||||
|
||||
namespace ffi {
|
||||
|
||||
typedef Signature<MachineType> FFISignature;
|
||||
enum class FFIType : uint8_t { kInt32 };
|
||||
|
||||
typedef Signature<FFIType> FFISignature;
|
||||
|
||||
struct NativeFunction {
|
||||
FFISignature* sig;
|
||||
|
@ -34,6 +34,187 @@ TEST(Run_FFI_Hello) {
|
||||
CHECK(result->IsUndefined(isolate));
|
||||
}
|
||||
|
||||
static int add2(int x, int y) { return x + y; }
|
||||
|
||||
TEST(Run_FFI_add2) {
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
HandleScope scope(isolate);
|
||||
|
||||
Handle<String> name = isolate->factory()->InternalizeUtf8String("add2");
|
||||
Handle<Object> undefined = isolate->factory()->undefined_value();
|
||||
|
||||
AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
FFISignature::Builder sig_builder(&zone, 1, 2);
|
||||
sig_builder.AddReturn(FFIType::kInt32);
|
||||
sig_builder.AddParam(FFIType::kInt32);
|
||||
sig_builder.AddParam(FFIType::kInt32);
|
||||
NativeFunction func = {sig_builder.Build(), reinterpret_cast<uint8_t*>(add2)};
|
||||
|
||||
Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func);
|
||||
|
||||
// Simple math should work.
|
||||
{
|
||||
Handle<Object> args[] = {isolate->factory()->NewNumber(1.0),
|
||||
isolate->factory()->NewNumber(41.0)};
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(42.0, result->Number());
|
||||
}
|
||||
|
||||
// Truncate floating point to integer.
|
||||
{
|
||||
Handle<Object> args[] = {isolate->factory()->NewNumber(1.9),
|
||||
isolate->factory()->NewNumber(41.0)};
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(42.0, result->Number());
|
||||
}
|
||||
|
||||
// INT_MAX + 1 should wrap.
|
||||
{
|
||||
Handle<Object> args[] = {isolate->factory()->NewNumber(kMaxInt),
|
||||
isolate->factory()->NewNumber(1)};
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(kMinInt, result->Number());
|
||||
}
|
||||
|
||||
// INT_MIN + -1 should wrap.
|
||||
{
|
||||
Handle<Object> args[] = {isolate->factory()->NewNumber(kMinInt),
|
||||
isolate->factory()->NewNumber(-1)};
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(kMaxInt, result->Number());
|
||||
}
|
||||
|
||||
// Numbers get truncated to the 32 least significant bits.
|
||||
{
|
||||
Handle<Object> args[] = {isolate->factory()->NewNumber(1ull << 40),
|
||||
isolate->factory()->NewNumber(-1)};
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(-1, result->Number());
|
||||
}
|
||||
|
||||
// String '57' converts to 57.
|
||||
{
|
||||
Handle<Object> args[] = {
|
||||
isolate->factory()->NewStringFromAsciiChecked("57"),
|
||||
isolate->factory()->NewNumber(41.0)};
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(98.0, result->Number());
|
||||
}
|
||||
|
||||
// String 'foo' converts to 0.
|
||||
{
|
||||
Handle<Object> args[] = {
|
||||
isolate->factory()->NewStringFromAsciiChecked("foo"),
|
||||
isolate->factory()->NewNumber(41.0)};
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(41.0, result->Number());
|
||||
}
|
||||
|
||||
// String '58o' converts to 0.
|
||||
{
|
||||
Handle<Object> args[] = {
|
||||
isolate->factory()->NewStringFromAsciiChecked("58o"),
|
||||
isolate->factory()->NewNumber(41.0)};
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(41.0, result->Number());
|
||||
}
|
||||
|
||||
// NaN converts to 0.
|
||||
{
|
||||
Handle<Object> args[] = {isolate->factory()->nan_value(),
|
||||
isolate->factory()->NewNumber(41.0)};
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(41.0, result->Number());
|
||||
}
|
||||
|
||||
// null converts to 0.
|
||||
{
|
||||
Handle<Object> args[] = {isolate->factory()->null_value(),
|
||||
isolate->factory()->NewNumber(41.0)};
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(41.0, result->Number());
|
||||
}
|
||||
}
|
||||
|
||||
static int add6(int a, int b, int c, int d, int e, int f) {
|
||||
return a + b + c + d + e + f;
|
||||
}
|
||||
|
||||
TEST(Run_FFI_add6) {
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
HandleScope scope(isolate);
|
||||
|
||||
Handle<String> name = isolate->factory()->InternalizeUtf8String("add6");
|
||||
Handle<Object> undefined = isolate->factory()->undefined_value();
|
||||
|
||||
AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
FFISignature::Builder sig_builder(&zone, 1, 7);
|
||||
sig_builder.AddReturn(FFIType::kInt32);
|
||||
for (int i = 0; i < 7; i++) {
|
||||
sig_builder.AddParam(FFIType::kInt32);
|
||||
}
|
||||
NativeFunction func = {sig_builder.Build(), reinterpret_cast<uint8_t*>(add6)};
|
||||
|
||||
Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func);
|
||||
Handle<Object> args[] = {
|
||||
isolate->factory()->NewNumber(1), isolate->factory()->NewNumber(2),
|
||||
isolate->factory()->NewNumber(3), isolate->factory()->NewNumber(4),
|
||||
isolate->factory()->NewNumber(5), isolate->factory()->NewNumber(6)};
|
||||
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
|
||||
CHECK_EQ(21.0, result->Number());
|
||||
|
||||
{
|
||||
// Ensure builtin frames are generated
|
||||
FLAG_allow_natives_syntax = true;
|
||||
v8::Local<v8::Value> res = CompileRun(
|
||||
"var o = { valueOf: function() { %DebugTrace(); return 1; } }; o;");
|
||||
Handle<JSReceiver> param(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
|
||||
Handle<Object> args[] = {param,
|
||||
isolate->factory()->NewNumber(2),
|
||||
isolate->factory()->NewNumber(3),
|
||||
isolate->factory()->NewNumber(4),
|
||||
isolate->factory()->NewNumber(5),
|
||||
isolate->factory()->NewNumber(6),
|
||||
isolate->factory()->NewNumber(21)};
|
||||
|
||||
Handle<Object> result =
|
||||
Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
||||
.ToHandleChecked();
|
||||
CHECK_EQ(21.0, result->Number());
|
||||
CHECK_EQ(
|
||||
1.0,
|
||||
res->NumberValue(
|
||||
reinterpret_cast<v8::Isolate*>(isolate)->GetCurrentContext())
|
||||
.ToChecked());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ffi
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user