OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/code-factory.h" | 5 #include "src/code-factory.h" |
6 #include "src/compiler/code-assembler.h" | 6 #include "src/compiler/code-assembler.h" |
7 #include "src/isolate.h" | 7 #include "src/isolate.h" |
8 #include "test/cctest/compiler/code-assembler-tester.h" | 8 #include "test/cctest/compiler/code-assembler-tester.h" |
9 #include "test/cctest/compiler/function-tester.h" | 9 #include "test/cctest/compiler/function-tester.h" |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 namespace compiler { | 13 namespace compiler { |
14 | 14 |
15 namespace { | 15 namespace { |
16 | 16 |
17 Node* SmiTag(CodeAssembler& m, Node* value) { | 17 Node* SmiTag(CodeAssembler& m, Node* value) { |
18 int32_t constant_value; | 18 int32_t constant_value; |
19 if (m.ToInt32Constant(value, constant_value) && | 19 if (m.ToInt32Constant(value, constant_value) && |
20 Smi::IsValid(constant_value)) { | 20 Smi::IsValid(constant_value)) { |
21 return m.SmiConstant(Smi::FromInt(constant_value)); | 21 return m.SmiConstant(Smi::FromInt(constant_value)); |
22 } | 22 } |
23 return m.WordShl(value, m.IntPtrConstant(kSmiShiftSize + kSmiTagSize)); | 23 return m.WordShl(value, m.IntPtrConstant(kSmiShiftSize + kSmiTagSize)); |
24 } | 24 } |
25 | 25 |
26 Node* UndefinedConstant(CodeAssembler& m) { | 26 Node* UndefinedConstant(CodeAssembler& m) { |
27 return m.LoadRoot(Heap::kUndefinedValueRootIndex); | 27 return m.LoadRoot(Heap::kUndefinedValueRootIndex); |
28 } | 28 } |
29 | 29 |
| 30 Node* SmiFromWord32(CodeAssembler& m, Node* value) { |
| 31 value = m.ChangeInt32ToIntPtr(value); |
| 32 return m.BitcastWordToTaggedSigned( |
| 33 m.WordShl(value, kSmiShiftSize + kSmiTagSize)); |
| 34 } |
| 35 |
30 Node* LoadObjectField(CodeAssembler& m, Node* object, int offset, | 36 Node* LoadObjectField(CodeAssembler& m, Node* object, int offset, |
31 MachineType rep = MachineType::AnyTagged()) { | 37 MachineType rep = MachineType::AnyTagged()) { |
32 return m.Load(rep, object, m.IntPtrConstant(offset - kHeapObjectTag)); | 38 return m.Load(rep, object, m.IntPtrConstant(offset - kHeapObjectTag)); |
33 } | 39 } |
34 | 40 |
| 41 Node* LoadMap(CodeAssembler& m, Node* object) { |
| 42 return LoadObjectField(m, object, JSObject::kMapOffset); |
| 43 } |
| 44 |
35 } // namespace | 45 } // namespace |
36 | 46 |
37 TEST(SimpleSmiReturn) { | 47 TEST(SimpleSmiReturn) { |
38 Isolate* isolate(CcTest::InitIsolateOnce()); | 48 Isolate* isolate(CcTest::InitIsolateOnce()); |
39 CodeAssemblerTester data(isolate); | 49 CodeAssemblerTester data(isolate); |
40 CodeAssembler m(data.state()); | 50 CodeAssembler m(data.state()); |
41 m.Return(SmiTag(m, m.Int32Constant(37))); | 51 m.Return(SmiTag(m, m.Int32Constant(37))); |
42 Handle<Code> code = data.GenerateCode(); | 52 Handle<Code> code = data.GenerateCode(); |
43 FunctionTester ft(code); | 53 FunctionTester ft(code); |
44 MaybeHandle<Object> result = ft.Call(); | 54 MaybeHandle<Object> result = ft.Call(); |
45 CHECK_EQ(37, Handle<Smi>::cast(result.ToHandleChecked())->value()); | 55 CHECK_EQ(37, Handle<Smi>::cast(result.ToHandleChecked())->value()); |
46 } | 56 } |
47 | 57 |
48 TEST(SimpleIntPtrReturn) { | 58 TEST(SimpleIntPtrReturn) { |
49 Isolate* isolate(CcTest::InitIsolateOnce()); | 59 Isolate* isolate(CcTest::InitIsolateOnce()); |
50 CodeAssemblerTester data(isolate); | 60 CodeAssemblerTester data(isolate); |
51 CodeAssembler m(data.state()); | 61 CodeAssembler m(data.state()); |
52 int test; | 62 int test; |
53 m.Return(m.IntPtrConstant(reinterpret_cast<intptr_t>(&test))); | 63 m.Return(m.BitcastWordToTagged( |
| 64 m.IntPtrConstant(reinterpret_cast<intptr_t>(&test)))); |
54 Handle<Code> code = data.GenerateCode(); | 65 Handle<Code> code = data.GenerateCode(); |
55 FunctionTester ft(code); | 66 FunctionTester ft(code); |
56 MaybeHandle<Object> result = ft.Call(); | 67 MaybeHandle<Object> result = ft.Call(); |
57 CHECK_EQ(reinterpret_cast<intptr_t>(&test), | 68 CHECK_EQ(reinterpret_cast<intptr_t>(&test), |
58 reinterpret_cast<intptr_t>(*result.ToHandleChecked())); | 69 reinterpret_cast<intptr_t>(*result.ToHandleChecked())); |
59 } | 70 } |
60 | 71 |
61 TEST(SimpleDoubleReturn) { | 72 TEST(SimpleDoubleReturn) { |
62 Isolate* isolate(CcTest::InitIsolateOnce()); | 73 Isolate* isolate(CcTest::InitIsolateOnce()); |
63 CodeAssemblerTester data(isolate); | 74 CodeAssemblerTester data(isolate); |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 a = UndefinedConstant(m); | 386 a = UndefinedConstant(m); |
376 CHECK(!m.ToInt32Constant(a, value32)); | 387 CHECK(!m.ToInt32Constant(a, value32)); |
377 CHECK(!m.ToInt64Constant(a, value64)); | 388 CHECK(!m.ToInt64Constant(a, value64)); |
378 | 389 |
379 a = UndefinedConstant(m); | 390 a = UndefinedConstant(m); |
380 CHECK(!m.ToInt32Constant(a, value32)); | 391 CHECK(!m.ToInt32Constant(a, value32)); |
381 CHECK(!m.ToInt64Constant(a, value64)); | 392 CHECK(!m.ToInt64Constant(a, value64)); |
382 } | 393 } |
383 | 394 |
384 TEST(DeferredCodePhiHints) { | 395 TEST(DeferredCodePhiHints) { |
385 typedef compiler::Node Node; | |
386 typedef CodeAssemblerLabel Label; | 396 typedef CodeAssemblerLabel Label; |
387 typedef CodeAssemblerVariable Variable; | 397 typedef CodeAssemblerVariable Variable; |
388 Isolate* isolate(CcTest::InitIsolateOnce()); | 398 Isolate* isolate(CcTest::InitIsolateOnce()); |
389 CodeAssemblerTester data(isolate); | 399 CodeAssemblerTester data(isolate); |
390 CodeAssembler m(data.state()); | 400 CodeAssembler m(data.state()); |
391 Label block1(&m, Label::kDeferred); | 401 Label block1(&m, Label::kDeferred); |
392 m.Goto(&block1); | 402 m.Goto(&block1); |
393 m.Bind(&block1); | 403 m.Bind(&block1); |
394 { | 404 { |
395 Variable var_object(&m, MachineRepresentation::kTagged); | 405 Variable var_object(&m, MachineRepresentation::kTagged); |
396 Label loop(&m, &var_object); | 406 Label loop(&m, &var_object); |
397 var_object.Bind(m.IntPtrConstant(0)); | 407 var_object.Bind(m.SmiConstant(0)); |
398 m.Goto(&loop); | 408 m.Goto(&loop); |
399 m.Bind(&loop); | 409 m.Bind(&loop); |
400 { | 410 { |
401 Node* map = LoadObjectField(m, var_object.value(), JSObject::kMapOffset); | 411 Node* map = LoadMap(m, var_object.value()); |
402 var_object.Bind(map); | 412 var_object.Bind(map); |
403 m.Goto(&loop); | 413 m.Goto(&loop); |
404 } | 414 } |
405 } | 415 } |
406 CHECK(!data.GenerateCode().is_null()); | 416 CHECK(!data.GenerateCode().is_null()); |
407 } | 417 } |
408 | 418 |
409 TEST(TestOutOfScopeVariable) { | 419 TEST(TestOutOfScopeVariable) { |
410 typedef CodeAssemblerLabel Label; | 420 typedef CodeAssemblerLabel Label; |
411 typedef CodeAssemblerVariable Variable; | 421 typedef CodeAssemblerVariable Variable; |
(...skipping 16 matching lines...) Expand all Loading... |
428 m.Goto(&block1); | 438 m.Goto(&block1); |
429 | 439 |
430 m.Bind(&block3); | 440 m.Bind(&block3); |
431 var_object.Bind(m.IntPtrConstant(66)); | 441 var_object.Bind(m.IntPtrConstant(66)); |
432 m.Goto(&block1); | 442 m.Goto(&block1); |
433 } | 443 } |
434 m.Bind(&block1); | 444 m.Bind(&block1); |
435 CHECK(!data.GenerateCode().is_null()); | 445 CHECK(!data.GenerateCode().is_null()); |
436 } | 446 } |
437 | 447 |
| 448 TEST(GotoIfException) { |
| 449 typedef CodeAssemblerLabel Label; |
| 450 typedef CodeAssemblerVariable Variable; |
| 451 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 452 |
| 453 const int kNumParams = 1; |
| 454 CodeAssemblerTester data(isolate, kNumParams); |
| 455 CodeAssembler m(data.state()); |
| 456 |
| 457 Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); |
| 458 Node* to_string_tag = |
| 459 m.HeapConstant(isolate->factory()->to_string_tag_symbol()); |
| 460 Variable exception(&m, MachineRepresentation::kTagged); |
| 461 |
| 462 Label exception_handler(&m); |
| 463 Callable to_string = CodeFactory::ToString(isolate); |
| 464 Node* string = m.CallStub(to_string, context, to_string_tag); |
| 465 m.GotoIfException(string, &exception_handler, &exception); |
| 466 m.Return(string); |
| 467 |
| 468 m.Bind(&exception_handler); |
| 469 m.Return(exception.value()); |
| 470 |
| 471 Handle<Code> code = data.GenerateCode(); |
| 472 CHECK(!code.is_null()); |
| 473 |
| 474 FunctionTester ft(code, kNumParams); |
| 475 Handle<Object> result = ft.Call().ToHandleChecked(); |
| 476 |
| 477 // Should be a TypeError. |
| 478 CHECK(result->IsJSObject()); |
| 479 |
| 480 Handle<Object> constructor = |
| 481 Object::GetPropertyOrElement(result, |
| 482 isolate->factory()->constructor_string()) |
| 483 .ToHandleChecked(); |
| 484 CHECK(constructor->SameValue(*isolate->type_error_function())); |
| 485 } |
| 486 |
| 487 TEST(GotoIfExceptionMultiple) { |
| 488 typedef CodeAssemblerLabel Label; |
| 489 typedef CodeAssemblerVariable Variable; |
| 490 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 491 |
| 492 const int kNumParams = 4; // receiver, first, second, third |
| 493 CodeAssemblerTester data(isolate, kNumParams); |
| 494 CodeAssembler m(data.state()); |
| 495 |
| 496 Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); |
| 497 Node* first_value = m.Parameter(0); |
| 498 Node* second_value = m.Parameter(1); |
| 499 Node* third_value = m.Parameter(2); |
| 500 |
| 501 Label exception_handler1(&m); |
| 502 Label exception_handler2(&m); |
| 503 Label exception_handler3(&m); |
| 504 Variable return_value(&m, MachineRepresentation::kWord32); |
| 505 Variable error(&m, MachineRepresentation::kTagged); |
| 506 |
| 507 return_value.Bind(m.Int32Constant(0)); |
| 508 |
| 509 // try { return ToString(param1) } catch (e) { ... } |
| 510 Callable to_string = CodeFactory::ToString(isolate); |
| 511 Node* string = m.CallStub(to_string, context, first_value); |
| 512 m.GotoIfException(string, &exception_handler1, &error); |
| 513 m.Return(string); |
| 514 |
| 515 // try { ToString(param2); return 7 } catch (e) { ... } |
| 516 m.Bind(&exception_handler1); |
| 517 return_value.Bind(m.Int32Constant(7)); |
| 518 error.Bind(UndefinedConstant(m)); |
| 519 string = m.CallStub(to_string, context, second_value); |
| 520 m.GotoIfException(string, &exception_handler2, &error); |
| 521 m.Return(SmiFromWord32(m, return_value.value())); |
| 522 |
| 523 // try { ToString(param3); return 7 & ~2; } catch (e) { return e; } |
| 524 m.Bind(&exception_handler2); |
| 525 // Return returnValue & ~2 |
| 526 error.Bind(UndefinedConstant(m)); |
| 527 string = m.CallStub(to_string, context, third_value); |
| 528 m.GotoIfException(string, &exception_handler3, &error); |
| 529 m.Return(SmiFromWord32( |
| 530 m, m.Word32And(return_value.value(), |
| 531 m.Word32Xor(m.Int32Constant(2), m.Int32Constant(-1))))); |
| 532 |
| 533 m.Bind(&exception_handler3); |
| 534 m.Return(error.value()); |
| 535 |
| 536 Handle<Code> code = data.GenerateCode(); |
| 537 CHECK(!code.is_null()); |
| 538 |
| 539 FunctionTester ft(code, kNumParams); |
| 540 |
| 541 Handle<Object> result; |
| 542 // First handler does not throw, returns result of first value. |
| 543 result = ft.Call(isolate->factory()->undefined_value(), |
| 544 isolate->factory()->to_string_tag_symbol()) |
| 545 .ToHandleChecked(); |
| 546 CHECK(String::cast(*result)->IsOneByteEqualTo(OneByteVector("undefined"))); |
| 547 |
| 548 // First handler returns a number. |
| 549 result = ft.Call(isolate->factory()->to_string_tag_symbol(), |
| 550 isolate->factory()->undefined_value()) |
| 551 .ToHandleChecked(); |
| 552 CHECK_EQ(7, Smi::cast(*result)->value()); |
| 553 |
| 554 // First handler throws, second handler returns a number. |
| 555 result = ft.Call(isolate->factory()->to_string_tag_symbol(), |
| 556 isolate->factory()->to_primitive_symbol()) |
| 557 .ToHandleChecked(); |
| 558 CHECK_EQ(7 & ~2, Smi::cast(*result)->value()); |
| 559 |
| 560 // First handler throws, second handler throws, third handler returns thrown |
| 561 // value. |
| 562 result = ft.Call(isolate->factory()->to_string_tag_symbol(), |
| 563 isolate->factory()->to_primitive_symbol(), |
| 564 isolate->factory()->unscopables_symbol()) |
| 565 .ToHandleChecked(); |
| 566 |
| 567 // Should be a TypeError. |
| 568 CHECK(result->IsJSObject()); |
| 569 |
| 570 Handle<Object> constructor = |
| 571 Object::GetPropertyOrElement(result, |
| 572 isolate->factory()->constructor_string()) |
| 573 .ToHandleChecked(); |
| 574 CHECK(constructor->SameValue(*isolate->type_error_function())); |
| 575 } |
| 576 |
438 } // namespace compiler | 577 } // namespace compiler |
439 } // namespace internal | 578 } // namespace internal |
440 } // namespace v8 | 579 } // namespace v8 |
OLD | NEW |