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..569ce8d8f4d8af644ca012b3ee9eb18c5a50b7c1 |
--- /dev/null |
+++ b/test/cctest/test-ffi.cc |
@@ -0,0 +1,199 @@ |
+// 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/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(); |
+ |
+ MachineType reps[] = {MachineType::Int32()}; |
+ static v8::internal::MachineSignature 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(); |
+ |
+ MachineType reps[] = {MachineType::Int32(), MachineType::Int32(), |
+ MachineType::Int32()}; |
+ static v8::internal::MachineSignature 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 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(); |
+ |
+ MachineType reps[] = {MachineType::Int32(), MachineType::Int32(), |
+ MachineType::Int32(), MachineType::Int32(), |
+ MachineType::Int32(), MachineType::Int32(), |
+ MachineType::Int32(), MachineType::Int32()}; |
+ static v8::internal::MachineSignature 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()); |
+} |