| Index: test/cctest/test-ffi.cc
|
| diff --git a/test/cctest/test-ffi.cc b/test/cctest/test-ffi.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b4358427c776e6383f6f00a1eb00e7288c8e6d06
|
| --- /dev/null
|
| +++ b/test/cctest/test-ffi.cc
|
| @@ -0,0 +1,531 @@
|
| +// Copyright 2016 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <math.h>
|
| +#include <stdint.h>
|
| +#include <stdlib.h>
|
| +#include <string.h>
|
| +
|
| +#include "src/codegen.h"
|
| +#include "src/compiler/ffi-compiler.h"
|
| +
|
| +#include "test/cctest/cctest.h"
|
| +
|
| +using namespace v8::base;
|
| +using namespace v8::internal;
|
| +using namespace v8::internal::compiler;
|
| +
|
| +static int foo() {
|
| + printf("hello world from native code\n");
|
| + return 42;
|
| +}
|
| +
|
| +TEST(Run_FFI_Hello) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + Handle<String> name = isolate->factory()->InternalizeUtf8String("foo");
|
| + Handle<Object> undefined = isolate->factory()->undefined_value();
|
| +
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}};
|
| + static v8::internal::ffi::FFISignature sig_foo(1, 0, reps);
|
| + v8::internal::ffi::NativeFunction func = {&sig_foo,
|
| + reinterpret_cast<uint8_t*>(foo)};
|
| +
|
| + Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func);
|
| +
|
| + Handle<Object> result =
|
| + Execution::Call(isolate, jsfunc, undefined, 0, nullptr).ToHandleChecked();
|
| +
|
| + CHECK_EQ(42.0, result->Number());
|
| +}
|
| +
|
| +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();
|
| +
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kInt32, NULL}};
|
| + static v8::internal::ffi::FFISignature sig(1, 2, reps);
|
| + v8::internal::ffi::NativeFunction func = {&sig,
|
| + 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.
|
| + // TODO(ofrobots): should this throw instead?
|
| + {
|
| + 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.
|
| + // TODO(ofrobots): should this throw instead?
|
| + {
|
| + 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.
|
| + // TODO(ofrobots): should this throw instead?
|
| + {
|
| + 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.
|
| + // TODO(ofrobots): should this throw instead?
|
| + {
|
| + 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 void noop() {}
|
| +
|
| +TEST(Run_FFI_empty_signature) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + Handle<String> name = isolate->factory()->InternalizeUtf8String("noop");
|
| + Handle<Object> undefined = isolate->factory()->undefined_value();
|
| +
|
| + ffi::FFITypeElement reps[] = {};
|
| + static v8::internal::ffi::FFISignature sig(0, 0, reps);
|
| + v8::internal::ffi::NativeFunction func = {&sig,
|
| + reinterpret_cast<uint8_t*>(noop)};
|
| +
|
| + Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func);
|
| +
|
| + Execution::Call(isolate, jsfunc, undefined, 0, NULL).ToHandleChecked();
|
| +}
|
| +
|
| +static int add7(int x1, int x2, int x3, int x4, int x5, int x6, int x7) {
|
| + return x1 + x2 + x3 + x4 + x5 + x6 + x7;
|
| +}
|
| +
|
| +TEST(Run_FFI_add7) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + Handle<String> name = isolate->factory()->InternalizeUtf8String("add7");
|
| + Handle<Object> undefined = isolate->factory()->undefined_value();
|
| +
|
| + ffi::FFITypeElement reps[] = {
|
| + {ffi::FFIType::kInt32, NULL}, {ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kInt32, NULL}, {ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kInt32, NULL}, {ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kInt32, NULL}, {ffi::FFIType::kInt32, NULL}};
|
| + static v8::internal::ffi::FFISignature sig(1, 7, reps);
|
| + v8::internal::ffi::NativeFunction func = {&sig,
|
| + reinterpret_cast<uint8_t*>(add7)};
|
| +
|
| + Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func);
|
| +
|
| + Handle<Object> args[] = {
|
| + isolate->factory()->NewNumber(1.0), isolate->factory()->NewNumber(2.0),
|
| + isolate->factory()->NewNumber(3.0), isolate->factory()->NewNumber(4.0),
|
| + isolate->factory()->NewNumber(5.0), isolate->factory()->NewNumber(6.0),
|
| + isolate->factory()->NewNumber(7.0)};
|
| + Handle<Object> result =
|
| + Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
| + .ToHandleChecked();
|
| +
|
| + CHECK_EQ(28.0, result->Number());
|
| +}
|
| +
|
| +static char* createString() {
|
| + int length = 12;
|
| + char* str = reinterpret_cast<char*>(malloc(sizeof(char) * length));
|
| + snprintf(str, length, "hello world");
|
| + return str;
|
| +}
|
| +
|
| +TEST(Run_FFI_strings) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + Handle<String> name = isolate->factory()->InternalizeUtf8String("strlen");
|
| + Handle<Object> undefined = isolate->factory()->undefined_value();
|
| +
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kCharPtr, NULL}};
|
| + static v8::internal::ffi::FFISignature sig(1, 1, reps);
|
| + v8::internal::ffi::NativeFunction func = {&sig,
|
| + reinterpret_cast<uint8_t*>(strlen)};
|
| +
|
| + Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func);
|
| +
|
| + Handle<Object> args[] = {
|
| + isolate->factory()->InternalizeUtf8String("strlenstrlen")};
|
| + Handle<Object> result =
|
| + Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
| + .ToHandleChecked();
|
| +
|
| + CHECK_EQ(12, result->Number());
|
| +
|
| + Handle<String> name2 =
|
| + isolate->factory()->InternalizeUtf8String("createString");
|
| +
|
| + ffi::FFITypeElement reps2[] = {{ffi::FFIType::kCharPtr, NULL}};
|
| + static v8::internal::ffi::FFISignature sig2(1, 0, reps2);
|
| + v8::internal::ffi::NativeFunction func2 = {
|
| + &sig2, reinterpret_cast<uint8_t*>(createString)};
|
| +
|
| + Handle<JSFunction> jsfunc2 = CompileJSToNativeWrapper(isolate, name2, func2);
|
| +
|
| + Handle<Object> result2 =
|
| + Execution::Call(isolate, jsfunc2, undefined, 0, nullptr)
|
| + .ToHandleChecked();
|
| +
|
| + CHECK_EQ(strcmp(String::cast(*result2)->ToCString().get(), "hello world"), 0);
|
| +}
|
| +
|
| +static uint8_t peek(uint8_t* data) { return data[0]; }
|
| +
|
| +TEST(Run_FFI_typedarrays) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + Handle<String> name = isolate->factory()->InternalizeUtf8String("peek");
|
| + Handle<Object> undefined = isolate->factory()->undefined_value();
|
| +
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kTypedArray, NULL}};
|
| + static v8::internal::ffi::FFISignature sig(1, 1, reps);
|
| + v8::internal::ffi::NativeFunction func = {&sig,
|
| + reinterpret_cast<uint8_t*>(peek)};
|
| +
|
| + Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func);
|
| +
|
| + uint8_t backing_store[1];
|
| + backing_store[0] = 42;
|
| + Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
| + JSArrayBuffer::Setup(buffer, isolate, true, backing_store,
|
| + sizeof(backing_store));
|
| + Handle<JSTypedArray> array =
|
| + isolate->factory()->NewJSTypedArray(kExternalUint8Array, buffer, 0, 1);
|
| + Handle<Object> args[] = {array};
|
| + Handle<Object> result =
|
| + Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
| + .ToHandleChecked();
|
| +
|
| + CHECK_EQ(42, result->Number());
|
| +}
|
| +
|
| +static int takesCb(int (*cb)()) { return cb(); }
|
| +
|
| +TEST(Run_FFI_FunctionArgs) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + Handle<String> name = isolate->factory()->InternalizeUtf8String("foo");
|
| + Handle<Object> undefined = isolate->factory()->undefined_value();
|
| +
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}};
|
| + static v8::internal::ffi::FFISignature sig_foo(1, 0, reps);
|
| + static v8::ffi::FFISignature sig_foo_external = {1, 0, reps};
|
| + v8::internal::ffi::NativeFunction func = {&sig_foo,
|
| + reinterpret_cast<uint8_t*>(foo)};
|
| +
|
| + Handle<JSFunction> jsFoo = CompileJSToNativeWrapper(isolate, name, func);
|
| +
|
| + v8::ffi::FFISupplementalInfo info = {&sig_foo_external};
|
| +
|
| + ffi::FFITypeElement reps2[] = {{ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kFunction, &info}};
|
| + static v8::internal::ffi::FFISignature sig_cb(1, 1, reps2);
|
| + v8::internal::ffi::NativeFunction func2 = {
|
| + &sig_cb, reinterpret_cast<uint8_t*>(takesCb)};
|
| +
|
| + Handle<String> name2 = isolate->factory()->InternalizeUtf8String("takesCb");
|
| +
|
| + Handle<JSFunction> jsCb = CompileJSToNativeWrapper(isolate, name2, func2);
|
| +
|
| + Handle<Object> args[] = {jsFoo};
|
| +
|
| + Handle<Object> result =
|
| + Execution::Call(isolate, jsCb, undefined, arraysize(args), args)
|
| + .ToHandleChecked();
|
| +
|
| + printf("%f\n", result->Number());
|
| +
|
| + CHECK_EQ(42.0, result->Number());
|
| +}
|
| +
|
| +struct struct_type {
|
| + int i;
|
| + int64_t j;
|
| +};
|
| +
|
| +static int takesStruct(struct_type* s) {
|
| + return static_cast<int>(s->i) - static_cast<int>(s->j);
|
| +}
|
| +
|
| +TEST(Run_FFI_StructArgs) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + Handle<Object> undefined = isolate->factory()->undefined_value();
|
| +
|
| + v8::ffi::FFITypeElement i_struct_type = {ffi::FFIType::kInt32, NULL};
|
| + v8::ffi::FFITypeElement j_struct_type = {ffi::FFIType::kInt64, NULL};
|
| + v8::ffi::FFIStructElement struct_elem[] = {{"i", &i_struct_type},
|
| + {"j", &j_struct_type}};
|
| + v8::ffi::FFIStructSignature struct_sig = {2, struct_elem};
|
| + v8::ffi::FFISupplementalInfo info = {.struct_elements = &struct_sig};
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kStructPtr, &info}};
|
| + static v8::internal::ffi::FFISignature sig(1, 1, reps);
|
| + v8::internal::ffi::NativeFunction func = {
|
| + &sig, reinterpret_cast<uint8_t*>(takesStruct)};
|
| +
|
| + Handle<String> name =
|
| + isolate->factory()->InternalizeUtf8String("takesStruct");
|
| +
|
| + Handle<JSFunction> jsFun = CompileJSToNativeWrapper(isolate, name, func);
|
| +
|
| + Handle<JSObject> jsObj = isolate->factory()->NewJSObjectWithNullProto();
|
| + JSObject::AddProperty(jsObj, isolate->factory()->InternalizeUtf8String("i"),
|
| + isolate->factory()->NewNumber(42), NONE);
|
| + JSObject::AddProperty(jsObj, isolate->factory()->InternalizeUtf8String("j"),
|
| + isolate->factory()->NewNumber(17), NONE);
|
| +
|
| + Handle<Object> args[] = {jsObj};
|
| +
|
| + Handle<Object> result =
|
| + Execution::Call(isolate, jsFun, undefined, arraysize(args), args)
|
| + .ToHandleChecked();
|
| +
|
| + CHECK_EQ(25.0, result->Number());
|
| +}
|
| +
|
| +static int foreign = 1729;
|
| +
|
| +static int* producesForeign() { return &foreign; }
|
| +
|
| +static int consumesForeign(int* foreign) { return *foreign; }
|
| +
|
| +TEST(Run_FFI_Foreigns) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + Handle<Object> undefined = isolate->factory()->undefined_value();
|
| +
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kForeign, NULL}};
|
| + static v8::internal::ffi::FFISignature sig(1, 0, reps);
|
| + v8::internal::ffi::NativeFunction func = {
|
| + &sig, reinterpret_cast<uint8_t*>(producesForeign)};
|
| +
|
| + Handle<String> name =
|
| + isolate->factory()->InternalizeUtf8String("producesForeign");
|
| +
|
| + Handle<JSFunction> jsProducer = CompileJSToNativeWrapper(isolate, name, func);
|
| +
|
| + ffi::FFITypeElement reps2[] = {{ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kForeign, NULL}};
|
| + static v8::internal::ffi::FFISignature sig2(1, 1, reps2);
|
| + v8::internal::ffi::NativeFunction func2 = {
|
| + &sig2, reinterpret_cast<uint8_t*>(consumesForeign)};
|
| +
|
| + Handle<String> name2 =
|
| + isolate->factory()->InternalizeUtf8String("consumesForeign");
|
| +
|
| + Handle<JSFunction> jsConsumer =
|
| + CompileJSToNativeWrapper(isolate, name2, func2);
|
| +
|
| + Handle<Object> intermediate =
|
| + Execution::Call(isolate, jsProducer, undefined, 0, {}).ToHandleChecked();
|
| +
|
| + Handle<Object> args[] = {intermediate};
|
| +
|
| + Handle<Object> result =
|
| + Execution::Call(isolate, jsConsumer, undefined, arraysize(args), args)
|
| + .ToHandleChecked();
|
| +
|
| + CHECK_EQ(1729.0, result->Number());
|
| +}
|
| +
|
| +static int constant() { return 1729; }
|
| +
|
| +TEST(Run_FFI_BindNoArgs) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}};
|
| + static v8::internal::ffi::FFISignature sig(1, 0, reps);
|
| + v8::internal::ffi::NativeFunction func = {
|
| + &sig, reinterpret_cast<uint8_t*>(constant)};
|
| +
|
| + Handle<JSArray> arr = isolate->factory()->NewJSArray(0);
|
| +
|
| + int (*fn_ptr)() =
|
| + reinterpret_cast<int (*)()>(FFIFunctionBind(isolate, func, arr));
|
| +
|
| + CHECK_EQ(1729, fn_ptr());
|
| +}
|
| +
|
| +static void populate(void* data) { *(reinterpret_cast<int*>(data)) = 42; }
|
| +
|
| +TEST(Run_FFI_BufferNoCopy) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + Handle<String> name = isolate->factory()->InternalizeUtf8String("populate");
|
| + Handle<Object> undefined = isolate->factory()->undefined_value();
|
| +
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kBufferNoCopy, NULL}};
|
| + static v8::internal::ffi::FFISignature sig(0, 1, reps);
|
| + v8::internal::ffi::NativeFunction func = {
|
| + &sig, reinterpret_cast<uint8_t*>(populate)};
|
| +
|
| + Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func);
|
| +
|
| + uint8_t backing_store[1];
|
| + backing_store[0] = 17;
|
| + Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
| + JSArrayBuffer::Setup(buffer, isolate, true, backing_store,
|
| + sizeof(backing_store));
|
| + Handle<JSTypedArray> array =
|
| + isolate->factory()->NewJSTypedArray(kExternalUint8Array, buffer, 0, 1);
|
| + Handle<Object> args[] = {array};
|
| + USE(Execution::Call(isolate, jsfunc, undefined, arraysize(args), args)
|
| + .ToHandleChecked());
|
| +
|
| + CHECK_EQ(42, backing_store[0]);
|
| +}
|
| +
|
| +static int add(int a, int b) { return a + b; }
|
| +
|
| +TEST(Run_FFI_BindArgs) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kInt32, NULL}};
|
| + static v8::internal::ffi::FFISignature sig(1, 2, reps);
|
| + v8::internal::ffi::NativeFunction func = {&sig,
|
| + reinterpret_cast<uint8_t*>(add)};
|
| +
|
| + Handle<JSArray> arr = isolate->factory()->NewJSArray(2);
|
| + USE(Object::SetElement(isolate, arr, 0, isolate->factory()->NewNumber(17),
|
| + SLOPPY));
|
| + USE(Object::SetElement(isolate, arr, 1, isolate->factory()->NewNumber(25),
|
| + SLOPPY));
|
| +
|
| + int (*fn_ptr)() =
|
| + reinterpret_cast<int (*)()>(FFIFunctionBind(isolate, func, arr));
|
| +
|
| + CHECK_EQ(42, fn_ptr());
|
| +}
|
| +
|
| +TEST(Run_FFI_Serialization) {
|
| + Isolate* isolate = CcTest::InitIsolateOnce();
|
| + HandleScope scope(isolate);
|
| +
|
| + ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kInt32, NULL},
|
| + {ffi::FFIType::kInt32, NULL}};
|
| + static v8::internal::ffi::FFISignature sig(1, 2, reps);
|
| + v8::internal::ffi::NativeFunction func = {&sig,
|
| + reinterpret_cast<uint8_t*>(add)};
|
| +
|
| + int* (*serializer)(int, int) =
|
| + reinterpret_cast<int* (*)(int, int)>(BuildFFISerializer(isolate, func));
|
| + int (*executor)(int*) = reinterpret_cast<int (*)(int*)>(
|
| + BuildFFIDeserializedExecutor(isolate, func));
|
| + int* serialized = serializer(17, 25);
|
| +
|
| + CHECK_EQ(17, serialized[0]);
|
| + CHECK_EQ(25, serialized[1]);
|
| +
|
| + int result = executor(serialized);
|
| + CHECK_EQ(42, result);
|
| +}
|
|
|