OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <math.h> |
| 6 #include <stdint.h> |
| 7 #include <stdlib.h> |
| 8 #include <string.h> |
| 9 |
| 10 #include "src/codegen.h" |
| 11 #include "src/compiler/ffi-compiler.h" |
| 12 |
| 13 #include "test/cctest/cctest.h" |
| 14 |
| 15 using namespace v8::base; |
| 16 using namespace v8::internal; |
| 17 using namespace v8::internal::compiler; |
| 18 |
| 19 static int foo() { |
| 20 printf("hello world from native code\n"); |
| 21 return 42; |
| 22 } |
| 23 |
| 24 TEST(Run_FFI_Hello) { |
| 25 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 26 HandleScope scope(isolate); |
| 27 |
| 28 Handle<String> name = isolate->factory()->InternalizeUtf8String("foo"); |
| 29 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 30 |
| 31 ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}}; |
| 32 static v8::internal::ffi::FFISignature sig_foo(1, 0, reps); |
| 33 v8::internal::ffi::NativeFunction func = {&sig_foo, |
| 34 reinterpret_cast<uint8_t*>(foo)}; |
| 35 |
| 36 Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func); |
| 37 |
| 38 Handle<Object> result = |
| 39 Execution::Call(isolate, jsfunc, undefined, 0, nullptr).ToHandleChecked(); |
| 40 |
| 41 CHECK_EQ(42.0, result->Number()); |
| 42 } |
| 43 |
| 44 static int add2(int x, int y) { return x + y; } |
| 45 |
| 46 TEST(Run_FFI_add2) { |
| 47 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 48 HandleScope scope(isolate); |
| 49 |
| 50 Handle<String> name = isolate->factory()->InternalizeUtf8String("add2"); |
| 51 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 52 |
| 53 ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}, |
| 54 {ffi::FFIType::kInt32, NULL}, |
| 55 {ffi::FFIType::kInt32, NULL}}; |
| 56 static v8::internal::ffi::FFISignature sig(1, 2, reps); |
| 57 v8::internal::ffi::NativeFunction func = {&sig, |
| 58 reinterpret_cast<uint8_t*>(add2)}; |
| 59 |
| 60 Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func); |
| 61 |
| 62 // Simple math should work. |
| 63 { |
| 64 Handle<Object> args[] = {isolate->factory()->NewNumber(1.0), |
| 65 isolate->factory()->NewNumber(41.0)}; |
| 66 Handle<Object> result = |
| 67 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 68 .ToHandleChecked(); |
| 69 CHECK_EQ(42.0, result->Number()); |
| 70 } |
| 71 |
| 72 // Truncate floating point to integer. |
| 73 { |
| 74 Handle<Object> args[] = {isolate->factory()->NewNumber(1.9), |
| 75 isolate->factory()->NewNumber(41.0)}; |
| 76 Handle<Object> result = |
| 77 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 78 .ToHandleChecked(); |
| 79 CHECK_EQ(42.0, result->Number()); |
| 80 } |
| 81 |
| 82 // INT_MAX + 1 should wrap. |
| 83 { |
| 84 Handle<Object> args[] = {isolate->factory()->NewNumber(kMaxInt), |
| 85 isolate->factory()->NewNumber(1)}; |
| 86 Handle<Object> result = |
| 87 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 88 .ToHandleChecked(); |
| 89 CHECK_EQ(kMinInt, result->Number()); |
| 90 } |
| 91 |
| 92 // INT_MIN + -1 should wrap. |
| 93 { |
| 94 Handle<Object> args[] = {isolate->factory()->NewNumber(kMinInt), |
| 95 isolate->factory()->NewNumber(-1)}; |
| 96 Handle<Object> result = |
| 97 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 98 .ToHandleChecked(); |
| 99 CHECK_EQ(kMaxInt, result->Number()); |
| 100 } |
| 101 |
| 102 // Numbers get truncated to the 32 least significant bits. |
| 103 { |
| 104 Handle<Object> args[] = {isolate->factory()->NewNumber(1ull << 40), |
| 105 isolate->factory()->NewNumber(-1)}; |
| 106 Handle<Object> result = |
| 107 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 108 .ToHandleChecked(); |
| 109 CHECK_EQ(-1, result->Number()); |
| 110 } |
| 111 |
| 112 // String '57' converts to 57. |
| 113 { |
| 114 Handle<Object> args[] = { |
| 115 isolate->factory()->NewStringFromAsciiChecked("57"), |
| 116 isolate->factory()->NewNumber(41.0)}; |
| 117 Handle<Object> result = |
| 118 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 119 .ToHandleChecked(); |
| 120 CHECK_EQ(98.0, result->Number()); |
| 121 } |
| 122 |
| 123 // String 'foo' converts to 0. |
| 124 // TODO(ofrobots): should this throw instead? |
| 125 { |
| 126 Handle<Object> args[] = { |
| 127 isolate->factory()->NewStringFromAsciiChecked("foo"), |
| 128 isolate->factory()->NewNumber(41.0)}; |
| 129 Handle<Object> result = |
| 130 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 131 .ToHandleChecked(); |
| 132 CHECK_EQ(41.0, result->Number()); |
| 133 } |
| 134 |
| 135 // String '58o' converts to 0. |
| 136 // TODO(ofrobots): should this throw instead? |
| 137 { |
| 138 Handle<Object> args[] = { |
| 139 isolate->factory()->NewStringFromAsciiChecked("58o"), |
| 140 isolate->factory()->NewNumber(41.0)}; |
| 141 Handle<Object> result = |
| 142 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 143 .ToHandleChecked(); |
| 144 CHECK_EQ(41.0, result->Number()); |
| 145 } |
| 146 |
| 147 // NaN converts to 0. |
| 148 // TODO(ofrobots): should this throw instead? |
| 149 { |
| 150 Handle<Object> args[] = {isolate->factory()->nan_value(), |
| 151 isolate->factory()->NewNumber(41.0)}; |
| 152 Handle<Object> result = |
| 153 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 154 .ToHandleChecked(); |
| 155 CHECK_EQ(41.0, result->Number()); |
| 156 } |
| 157 |
| 158 // null converts to 0. |
| 159 // TODO(ofrobots): should this throw instead? |
| 160 { |
| 161 Handle<Object> args[] = {isolate->factory()->null_value(), |
| 162 isolate->factory()->NewNumber(41.0)}; |
| 163 Handle<Object> result = |
| 164 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 165 .ToHandleChecked(); |
| 166 CHECK_EQ(41.0, result->Number()); |
| 167 } |
| 168 } |
| 169 |
| 170 static void noop() {} |
| 171 |
| 172 TEST(Run_FFI_empty_signature) { |
| 173 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 174 HandleScope scope(isolate); |
| 175 |
| 176 Handle<String> name = isolate->factory()->InternalizeUtf8String("noop"); |
| 177 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 178 |
| 179 ffi::FFITypeElement reps[] = {}; |
| 180 static v8::internal::ffi::FFISignature sig(0, 0, reps); |
| 181 v8::internal::ffi::NativeFunction func = {&sig, |
| 182 reinterpret_cast<uint8_t*>(noop)}; |
| 183 |
| 184 Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func); |
| 185 |
| 186 Execution::Call(isolate, jsfunc, undefined, 0, NULL).ToHandleChecked(); |
| 187 } |
| 188 |
| 189 static int add7(int x1, int x2, int x3, int x4, int x5, int x6, int x7) { |
| 190 return x1 + x2 + x3 + x4 + x5 + x6 + x7; |
| 191 } |
| 192 |
| 193 TEST(Run_FFI_add7) { |
| 194 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 195 HandleScope scope(isolate); |
| 196 |
| 197 Handle<String> name = isolate->factory()->InternalizeUtf8String("add7"); |
| 198 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 199 |
| 200 ffi::FFITypeElement reps[] = { |
| 201 {ffi::FFIType::kInt32, NULL}, {ffi::FFIType::kInt32, NULL}, |
| 202 {ffi::FFIType::kInt32, NULL}, {ffi::FFIType::kInt32, NULL}, |
| 203 {ffi::FFIType::kInt32, NULL}, {ffi::FFIType::kInt32, NULL}, |
| 204 {ffi::FFIType::kInt32, NULL}, {ffi::FFIType::kInt32, NULL}}; |
| 205 static v8::internal::ffi::FFISignature sig(1, 7, reps); |
| 206 v8::internal::ffi::NativeFunction func = {&sig, |
| 207 reinterpret_cast<uint8_t*>(add7)}; |
| 208 |
| 209 Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func); |
| 210 |
| 211 Handle<Object> args[] = { |
| 212 isolate->factory()->NewNumber(1.0), isolate->factory()->NewNumber(2.0), |
| 213 isolate->factory()->NewNumber(3.0), isolate->factory()->NewNumber(4.0), |
| 214 isolate->factory()->NewNumber(5.0), isolate->factory()->NewNumber(6.0), |
| 215 isolate->factory()->NewNumber(7.0)}; |
| 216 Handle<Object> result = |
| 217 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 218 .ToHandleChecked(); |
| 219 |
| 220 CHECK_EQ(28.0, result->Number()); |
| 221 } |
| 222 |
| 223 static char* createString() { |
| 224 int length = 12; |
| 225 char* str = reinterpret_cast<char*>(malloc(sizeof(char) * length)); |
| 226 snprintf(str, length, "hello world"); |
| 227 return str; |
| 228 } |
| 229 |
| 230 TEST(Run_FFI_strings) { |
| 231 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 232 HandleScope scope(isolate); |
| 233 |
| 234 Handle<String> name = isolate->factory()->InternalizeUtf8String("strlen"); |
| 235 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 236 |
| 237 ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}, |
| 238 {ffi::FFIType::kCharPtr, NULL}}; |
| 239 static v8::internal::ffi::FFISignature sig(1, 1, reps); |
| 240 v8::internal::ffi::NativeFunction func = {&sig, |
| 241 reinterpret_cast<uint8_t*>(strlen)}; |
| 242 |
| 243 Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func); |
| 244 |
| 245 Handle<Object> args[] = { |
| 246 isolate->factory()->InternalizeUtf8String("strlenstrlen")}; |
| 247 Handle<Object> result = |
| 248 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 249 .ToHandleChecked(); |
| 250 |
| 251 CHECK_EQ(12, result->Number()); |
| 252 |
| 253 Handle<String> name2 = |
| 254 isolate->factory()->InternalizeUtf8String("createString"); |
| 255 |
| 256 ffi::FFITypeElement reps2[] = {{ffi::FFIType::kCharPtr, NULL}}; |
| 257 static v8::internal::ffi::FFISignature sig2(1, 0, reps2); |
| 258 v8::internal::ffi::NativeFunction func2 = { |
| 259 &sig2, reinterpret_cast<uint8_t*>(createString)}; |
| 260 |
| 261 Handle<JSFunction> jsfunc2 = CompileJSToNativeWrapper(isolate, name2, func2); |
| 262 |
| 263 Handle<Object> result2 = |
| 264 Execution::Call(isolate, jsfunc2, undefined, 0, nullptr) |
| 265 .ToHandleChecked(); |
| 266 |
| 267 CHECK_EQ(strcmp(String::cast(*result2)->ToCString().get(), "hello world"), 0); |
| 268 } |
| 269 |
| 270 static uint8_t peek(uint8_t* data) { return data[0]; } |
| 271 |
| 272 TEST(Run_FFI_typedarrays) { |
| 273 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 274 HandleScope scope(isolate); |
| 275 |
| 276 Handle<String> name = isolate->factory()->InternalizeUtf8String("peek"); |
| 277 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 278 |
| 279 ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}, |
| 280 {ffi::FFIType::kTypedArray, NULL}}; |
| 281 static v8::internal::ffi::FFISignature sig(1, 1, reps); |
| 282 v8::internal::ffi::NativeFunction func = {&sig, |
| 283 reinterpret_cast<uint8_t*>(peek)}; |
| 284 |
| 285 Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func); |
| 286 |
| 287 uint8_t backing_store[1]; |
| 288 backing_store[0] = 42; |
| 289 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); |
| 290 JSArrayBuffer::Setup(buffer, isolate, true, backing_store, |
| 291 sizeof(backing_store)); |
| 292 Handle<JSTypedArray> array = |
| 293 isolate->factory()->NewJSTypedArray(kExternalUint8Array, buffer, 0, 1); |
| 294 Handle<Object> args[] = {array}; |
| 295 Handle<Object> result = |
| 296 Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 297 .ToHandleChecked(); |
| 298 |
| 299 CHECK_EQ(42, result->Number()); |
| 300 } |
| 301 |
| 302 static int takesCb(int (*cb)()) { return cb(); } |
| 303 |
| 304 TEST(Run_FFI_FunctionArgs) { |
| 305 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 306 HandleScope scope(isolate); |
| 307 |
| 308 Handle<String> name = isolate->factory()->InternalizeUtf8String("foo"); |
| 309 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 310 |
| 311 ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}}; |
| 312 static v8::internal::ffi::FFISignature sig_foo(1, 0, reps); |
| 313 static v8::ffi::FFISignature sig_foo_external = {1, 0, reps}; |
| 314 v8::internal::ffi::NativeFunction func = {&sig_foo, |
| 315 reinterpret_cast<uint8_t*>(foo)}; |
| 316 |
| 317 Handle<JSFunction> jsFoo = CompileJSToNativeWrapper(isolate, name, func); |
| 318 |
| 319 v8::ffi::FFISupplementalInfo info = {&sig_foo_external}; |
| 320 |
| 321 ffi::FFITypeElement reps2[] = {{ffi::FFIType::kInt32, NULL}, |
| 322 {ffi::FFIType::kFunction, &info}}; |
| 323 static v8::internal::ffi::FFISignature sig_cb(1, 1, reps2); |
| 324 v8::internal::ffi::NativeFunction func2 = { |
| 325 &sig_cb, reinterpret_cast<uint8_t*>(takesCb)}; |
| 326 |
| 327 Handle<String> name2 = isolate->factory()->InternalizeUtf8String("takesCb"); |
| 328 |
| 329 Handle<JSFunction> jsCb = CompileJSToNativeWrapper(isolate, name2, func2); |
| 330 |
| 331 Handle<Object> args[] = {jsFoo}; |
| 332 |
| 333 Handle<Object> result = |
| 334 Execution::Call(isolate, jsCb, undefined, arraysize(args), args) |
| 335 .ToHandleChecked(); |
| 336 |
| 337 printf("%f\n", result->Number()); |
| 338 |
| 339 CHECK_EQ(42.0, result->Number()); |
| 340 } |
| 341 |
| 342 struct struct_type { |
| 343 int i; |
| 344 int64_t j; |
| 345 }; |
| 346 |
| 347 static int takesStruct(struct_type* s) { |
| 348 return static_cast<int>(s->i) - static_cast<int>(s->j); |
| 349 } |
| 350 |
| 351 TEST(Run_FFI_StructArgs) { |
| 352 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 353 HandleScope scope(isolate); |
| 354 |
| 355 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 356 |
| 357 v8::ffi::FFITypeElement i_struct_type = {ffi::FFIType::kInt32, NULL}; |
| 358 v8::ffi::FFITypeElement j_struct_type = {ffi::FFIType::kInt64, NULL}; |
| 359 v8::ffi::FFIStructElement struct_elem[] = {{"i", &i_struct_type}, |
| 360 {"j", &j_struct_type}}; |
| 361 v8::ffi::FFIStructSignature struct_sig = {2, struct_elem}; |
| 362 v8::ffi::FFISupplementalInfo info = {.struct_elements = &struct_sig}; |
| 363 ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}, |
| 364 {ffi::FFIType::kStructPtr, &info}}; |
| 365 static v8::internal::ffi::FFISignature sig(1, 1, reps); |
| 366 v8::internal::ffi::NativeFunction func = { |
| 367 &sig, reinterpret_cast<uint8_t*>(takesStruct)}; |
| 368 |
| 369 Handle<String> name = |
| 370 isolate->factory()->InternalizeUtf8String("takesStruct"); |
| 371 |
| 372 Handle<JSFunction> jsFun = CompileJSToNativeWrapper(isolate, name, func); |
| 373 |
| 374 Handle<JSObject> jsObj = isolate->factory()->NewJSObjectWithNullProto(); |
| 375 JSObject::AddProperty(jsObj, isolate->factory()->InternalizeUtf8String("i"), |
| 376 isolate->factory()->NewNumber(42), NONE); |
| 377 JSObject::AddProperty(jsObj, isolate->factory()->InternalizeUtf8String("j"), |
| 378 isolate->factory()->NewNumber(17), NONE); |
| 379 |
| 380 Handle<Object> args[] = {jsObj}; |
| 381 |
| 382 Handle<Object> result = |
| 383 Execution::Call(isolate, jsFun, undefined, arraysize(args), args) |
| 384 .ToHandleChecked(); |
| 385 |
| 386 CHECK_EQ(25.0, result->Number()); |
| 387 } |
| 388 |
| 389 static int foreign = 1729; |
| 390 |
| 391 static int* producesForeign() { return &foreign; } |
| 392 |
| 393 static int consumesForeign(int* foreign) { return *foreign; } |
| 394 |
| 395 TEST(Run_FFI_Foreigns) { |
| 396 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 397 HandleScope scope(isolate); |
| 398 |
| 399 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 400 |
| 401 ffi::FFITypeElement reps[] = {{ffi::FFIType::kForeign, NULL}}; |
| 402 static v8::internal::ffi::FFISignature sig(1, 0, reps); |
| 403 v8::internal::ffi::NativeFunction func = { |
| 404 &sig, reinterpret_cast<uint8_t*>(producesForeign)}; |
| 405 |
| 406 Handle<String> name = |
| 407 isolate->factory()->InternalizeUtf8String("producesForeign"); |
| 408 |
| 409 Handle<JSFunction> jsProducer = CompileJSToNativeWrapper(isolate, name, func); |
| 410 |
| 411 ffi::FFITypeElement reps2[] = {{ffi::FFIType::kInt32, NULL}, |
| 412 {ffi::FFIType::kForeign, NULL}}; |
| 413 static v8::internal::ffi::FFISignature sig2(1, 1, reps2); |
| 414 v8::internal::ffi::NativeFunction func2 = { |
| 415 &sig2, reinterpret_cast<uint8_t*>(consumesForeign)}; |
| 416 |
| 417 Handle<String> name2 = |
| 418 isolate->factory()->InternalizeUtf8String("consumesForeign"); |
| 419 |
| 420 Handle<JSFunction> jsConsumer = |
| 421 CompileJSToNativeWrapper(isolate, name2, func2); |
| 422 |
| 423 Handle<Object> intermediate = |
| 424 Execution::Call(isolate, jsProducer, undefined, 0, {}).ToHandleChecked(); |
| 425 |
| 426 Handle<Object> args[] = {intermediate}; |
| 427 |
| 428 Handle<Object> result = |
| 429 Execution::Call(isolate, jsConsumer, undefined, arraysize(args), args) |
| 430 .ToHandleChecked(); |
| 431 |
| 432 CHECK_EQ(1729.0, result->Number()); |
| 433 } |
| 434 |
| 435 static int constant() { return 1729; } |
| 436 |
| 437 TEST(Run_FFI_BindNoArgs) { |
| 438 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 439 HandleScope scope(isolate); |
| 440 |
| 441 ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}}; |
| 442 static v8::internal::ffi::FFISignature sig(1, 0, reps); |
| 443 v8::internal::ffi::NativeFunction func = { |
| 444 &sig, reinterpret_cast<uint8_t*>(constant)}; |
| 445 |
| 446 Handle<JSArray> arr = isolate->factory()->NewJSArray(0); |
| 447 |
| 448 int (*fn_ptr)() = |
| 449 reinterpret_cast<int (*)()>(FFIFunctionBind(isolate, func, arr)); |
| 450 |
| 451 CHECK_EQ(1729, fn_ptr()); |
| 452 } |
| 453 |
| 454 static void populate(void* data) { *(reinterpret_cast<int*>(data)) = 42; } |
| 455 |
| 456 TEST(Run_FFI_BufferNoCopy) { |
| 457 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 458 HandleScope scope(isolate); |
| 459 |
| 460 Handle<String> name = isolate->factory()->InternalizeUtf8String("populate"); |
| 461 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 462 |
| 463 ffi::FFITypeElement reps[] = {{ffi::FFIType::kBufferNoCopy, NULL}}; |
| 464 static v8::internal::ffi::FFISignature sig(0, 1, reps); |
| 465 v8::internal::ffi::NativeFunction func = { |
| 466 &sig, reinterpret_cast<uint8_t*>(populate)}; |
| 467 |
| 468 Handle<JSFunction> jsfunc = CompileJSToNativeWrapper(isolate, name, func); |
| 469 |
| 470 uint8_t backing_store[1]; |
| 471 backing_store[0] = 17; |
| 472 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); |
| 473 JSArrayBuffer::Setup(buffer, isolate, true, backing_store, |
| 474 sizeof(backing_store)); |
| 475 Handle<JSTypedArray> array = |
| 476 isolate->factory()->NewJSTypedArray(kExternalUint8Array, buffer, 0, 1); |
| 477 Handle<Object> args[] = {array}; |
| 478 USE(Execution::Call(isolate, jsfunc, undefined, arraysize(args), args) |
| 479 .ToHandleChecked()); |
| 480 |
| 481 CHECK_EQ(42, backing_store[0]); |
| 482 } |
| 483 |
| 484 static int add(int a, int b) { return a + b; } |
| 485 |
| 486 TEST(Run_FFI_BindArgs) { |
| 487 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 488 HandleScope scope(isolate); |
| 489 |
| 490 ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}, |
| 491 {ffi::FFIType::kInt32, NULL}, |
| 492 {ffi::FFIType::kInt32, NULL}}; |
| 493 static v8::internal::ffi::FFISignature sig(1, 2, reps); |
| 494 v8::internal::ffi::NativeFunction func = {&sig, |
| 495 reinterpret_cast<uint8_t*>(add)}; |
| 496 |
| 497 Handle<JSArray> arr = isolate->factory()->NewJSArray(2); |
| 498 USE(Object::SetElement(isolate, arr, 0, isolate->factory()->NewNumber(17), |
| 499 SLOPPY)); |
| 500 USE(Object::SetElement(isolate, arr, 1, isolate->factory()->NewNumber(25), |
| 501 SLOPPY)); |
| 502 |
| 503 int (*fn_ptr)() = |
| 504 reinterpret_cast<int (*)()>(FFIFunctionBind(isolate, func, arr)); |
| 505 |
| 506 CHECK_EQ(42, fn_ptr()); |
| 507 } |
| 508 |
| 509 TEST(Run_FFI_Serialization) { |
| 510 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 511 HandleScope scope(isolate); |
| 512 |
| 513 ffi::FFITypeElement reps[] = {{ffi::FFIType::kInt32, NULL}, |
| 514 {ffi::FFIType::kInt32, NULL}, |
| 515 {ffi::FFIType::kInt32, NULL}}; |
| 516 static v8::internal::ffi::FFISignature sig(1, 2, reps); |
| 517 v8::internal::ffi::NativeFunction func = {&sig, |
| 518 reinterpret_cast<uint8_t*>(add)}; |
| 519 |
| 520 int* (*serializer)(int, int) = |
| 521 reinterpret_cast<int* (*)(int, int)>(BuildFFISerializer(isolate, func)); |
| 522 int (*executor)(int*) = reinterpret_cast<int (*)(int*)>( |
| 523 BuildFFIDeserializedExecutor(isolate, func)); |
| 524 int* serialized = serializer(17, 25); |
| 525 |
| 526 CHECK_EQ(17, serialized[0]); |
| 527 CHECK_EQ(25, serialized[1]); |
| 528 |
| 529 int result = executor(serialized); |
| 530 CHECK_EQ(42, result); |
| 531 } |
OLD | NEW |