| // Copyright 2015 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 "src/codegen/code-factory.h" |
| #include "src/compiler/code-assembler.h" |
| #include "src/compiler/node-properties.h" |
| #include "src/compiler/opcodes.h" |
| #include "src/execution/isolate.h" |
| #include "src/objects/heap-number-inl.h" |
| #include "src/objects/objects-inl.h" |
| #include "test/cctest/compiler/code-assembler-tester.h" |
| #include "test/cctest/compiler/function-tester.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace compiler { |
| |
| namespace { |
| |
| using Label = CodeAssemblerLabel; |
| using Variable = CodeAssemblerVariable; |
| |
| Node* SmiTag(CodeAssembler& m, // NOLINT(runtime/references) |
| Node* value) { |
| int32_t constant_value; |
| if (m.ToInt32Constant(value, constant_value) && |
| Smi::IsValid(constant_value)) { |
| return m.SmiConstant(Smi::FromInt(constant_value)); |
| } |
| return m.WordShl(value, m.IntPtrConstant(kSmiShiftSize + kSmiTagSize)); |
| } |
| |
| Node* UndefinedConstant(CodeAssembler& m) { // NOLINT(runtime/references) |
| return m.LoadRoot(RootIndex::kUndefinedValue); |
| } |
| |
| Node* SmiFromInt32(CodeAssembler& m, // NOLINT(runtime/references) |
| Node* value) { |
| value = m.ChangeInt32ToIntPtr(value); |
| return m.BitcastWordToTaggedSigned( |
| m.WordShl(value, kSmiShiftSize + kSmiTagSize)); |
| } |
| |
| Node* LoadObjectField(CodeAssembler& m, // NOLINT(runtime/references) |
| Node* object, int offset, |
| MachineType type = MachineType::AnyTagged()) { |
| return m.Load(type, object, m.IntPtrConstant(offset - kHeapObjectTag)); |
| } |
| |
| Node* LoadMap(CodeAssembler& m, // NOLINT(runtime/references) |
| Node* object) { |
| return LoadObjectField(m, object, JSObject::kMapOffset); |
| } |
| |
| } // namespace |
| |
| TEST(SimpleSmiReturn) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| m.Return(SmiTag(m, m.Int32Constant(37))); |
| FunctionTester ft(asm_tester.GenerateCode()); |
| CHECK_EQ(37, ft.CallChecked<Smi>()->value()); |
| } |
| |
| TEST(SimpleIntPtrReturn) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| int test; |
| m.Return(m.BitcastWordToTagged( |
| m.IntPtrConstant(reinterpret_cast<intptr_t>(&test)))); |
| FunctionTester ft(asm_tester.GenerateCode()); |
| MaybeHandle<Object> result = ft.Call(); |
| CHECK_EQ(reinterpret_cast<Address>(&test), result.ToHandleChecked()->ptr()); |
| } |
| |
| TEST(SimpleDoubleReturn) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| m.Return(m.NumberConstant(0.5)); |
| FunctionTester ft(asm_tester.GenerateCode()); |
| CHECK_EQ(0.5, ft.CallChecked<HeapNumber>()->value()); |
| } |
| |
| TEST(SimpleCallRuntime1Arg) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); |
| Node* b = SmiTag(m, m.Int32Constant(0)); |
| m.Return(m.CallRuntime(Runtime::kIsSmi, context, b)); |
| FunctionTester ft(asm_tester.GenerateCode()); |
| CHECK(ft.CallChecked<Oddball>().is_identical_to( |
| isolate->factory()->true_value())); |
| } |
| |
| TEST(SimpleTailCallRuntime1Arg) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); |
| Node* b = SmiTag(m, m.Int32Constant(0)); |
| m.TailCallRuntime(Runtime::kIsSmi, context, b); |
| FunctionTester ft(asm_tester.GenerateCode()); |
| CHECK(ft.CallChecked<Oddball>().is_identical_to( |
| isolate->factory()->true_value())); |
| } |
| |
| TEST(SimpleCallRuntime2Arg) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); |
| Node* a = SmiTag(m, m.Int32Constant(2)); |
| Node* b = SmiTag(m, m.Int32Constant(4)); |
| m.Return(m.CallRuntime(Runtime::kAdd, context, a, b)); |
| FunctionTester ft(asm_tester.GenerateCode()); |
| CHECK_EQ(6, ft.CallChecked<Smi>()->value()); |
| } |
| |
| TEST(SimpleTailCallRuntime2Arg) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); |
| Node* a = SmiTag(m, m.Int32Constant(2)); |
| Node* b = SmiTag(m, m.Int32Constant(4)); |
| m.TailCallRuntime(Runtime::kAdd, context, a, b); |
| FunctionTester ft(asm_tester.GenerateCode()); |
| CHECK_EQ(6, ft.CallChecked<Smi>()->value()); |
| } |
| |
| namespace { |
| |
| Handle<JSFunction> CreateSumAllArgumentsFunction( |
| FunctionTester& ft) { // NOLINT(runtime/references) |
| const char* source = |
| "(function() {\n" |
| " var sum = 0 + this;\n" |
| " for (var i = 0; i < arguments.length; i++) {\n" |
| " sum += arguments[i];\n" |
| " }\n" |
| " return sum;\n" |
| "})"; |
| return ft.NewFunction(source); |
| } |
| |
| } // namespace |
| |
| TEST(SimpleCallJSFunction0Arg) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| const int kNumParams = 1; |
| CodeAssemblerTester asm_tester(isolate, kNumParams); |
| CodeAssembler m(asm_tester.state()); |
| { |
| Node* function = m.Parameter(0); |
| Node* context = m.Parameter(kNumParams + 2); |
| |
| Node* receiver = SmiTag(m, m.Int32Constant(42)); |
| |
| Callable callable = CodeFactory::Call(isolate); |
| Node* result = m.CallJS(callable, context, function, receiver); |
| m.Return(result); |
| } |
| FunctionTester ft(asm_tester.GenerateCode(), kNumParams); |
| |
| Handle<JSFunction> sum = CreateSumAllArgumentsFunction(ft); |
| MaybeHandle<Object> result = ft.Call(sum); |
| CHECK_EQ(Smi::FromInt(42), *result.ToHandleChecked()); |
| } |
| |
| TEST(SimpleCallJSFunction1Arg) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| const int kNumParams = 2; |
| CodeAssemblerTester asm_tester(isolate, kNumParams); |
| CodeAssembler m(asm_tester.state()); |
| { |
| Node* function = m.Parameter(0); |
| Node* context = m.Parameter(1); |
| |
| Node* receiver = SmiTag(m, m.Int32Constant(42)); |
| Node* a = SmiTag(m, m.Int32Constant(13)); |
| |
| Callable callable = CodeFactory::Call(isolate); |
| Node* result = m.CallJS(callable, context, function, receiver, a); |
| m.Return(result); |
| } |
| FunctionTester ft(asm_tester.GenerateCode(), kNumParams); |
| |
| Handle<JSFunction> sum = CreateSumAllArgumentsFunction(ft); |
| MaybeHandle<Object> result = ft.Call(sum); |
| CHECK_EQ(Smi::FromInt(55), *result.ToHandleChecked()); |
| } |
| |
| TEST(SimpleCallJSFunction2Arg) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| const int kNumParams = 2; |
| CodeAssemblerTester asm_tester(isolate, kNumParams); |
| CodeAssembler m(asm_tester.state()); |
| { |
| Node* function = m.Parameter(0); |
| Node* context = m.Parameter(1); |
| |
| Node* receiver = SmiTag(m, m.Int32Constant(42)); |
| Node* a = SmiTag(m, m.Int32Constant(13)); |
| Node* b = SmiTag(m, m.Int32Constant(153)); |
| |
| Callable callable = CodeFactory::Call(isolate); |
| Node* result = m.CallJS(callable, context, function, receiver, a, b); |
| m.Return(result); |
| } |
| FunctionTester ft(asm_tester.GenerateCode(), kNumParams); |
| |
| Handle<JSFunction> sum = CreateSumAllArgumentsFunction(ft); |
| MaybeHandle<Object> result = ft.Call(sum); |
| CHECK_EQ(Smi::FromInt(208), *result.ToHandleChecked()); |
| } |
| |
| TEST(VariableMerge1) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Variable var1(&m, MachineRepresentation::kTagged); |
| Label l1(&m), l2(&m), merge(&m); |
| Node* temp = m.Int32Constant(0); |
| var1.Bind(temp); |
| m.Branch(m.Int32Constant(1), &l1, &l2); |
| m.Bind(&l1); |
| CHECK_EQ(var1.value(), temp); |
| m.Goto(&merge); |
| m.Bind(&l2); |
| CHECK_EQ(var1.value(), temp); |
| m.Goto(&merge); |
| m.Bind(&merge); |
| CHECK_EQ(var1.value(), temp); |
| } |
| |
| TEST(VariableMerge2) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Variable var1(&m, MachineRepresentation::kTagged); |
| Label l1(&m), l2(&m), merge(&m); |
| Node* temp = m.Int32Constant(0); |
| var1.Bind(temp); |
| m.Branch(m.Int32Constant(1), &l1, &l2); |
| m.Bind(&l1); |
| CHECK_EQ(var1.value(), temp); |
| m.Goto(&merge); |
| m.Bind(&l2); |
| Node* temp2 = m.Int32Constant(2); |
| var1.Bind(temp2); |
| CHECK_EQ(var1.value(), temp2); |
| m.Goto(&merge); |
| m.Bind(&merge); |
| CHECK_NE(var1.value(), temp); |
| } |
| |
| TEST(VariableMerge3) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Variable var1(&m, MachineRepresentation::kTagged); |
| Variable var2(&m, MachineRepresentation::kTagged); |
| Label l1(&m), l2(&m), merge(&m); |
| Node* temp = m.Int32Constant(0); |
| var1.Bind(temp); |
| var2.Bind(temp); |
| m.Branch(m.Int32Constant(1), &l1, &l2); |
| m.Bind(&l1); |
| CHECK_EQ(var1.value(), temp); |
| m.Goto(&merge); |
| m.Bind(&l2); |
| Node* temp2 = m.Int32Constant(2); |
| var1.Bind(temp2); |
| CHECK_EQ(var1.value(), temp2); |
| m.Goto(&merge); |
| m.Bind(&merge); |
| CHECK_NE(var1.value(), temp); |
| CHECK_NE(var1.value(), temp2); |
| CHECK_EQ(var2.value(), temp); |
| } |
| |
| TEST(VariableMergeBindFirst) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Variable var1(&m, MachineRepresentation::kTagged); |
| Label l1(&m), l2(&m), merge(&m, &var1), end(&m); |
| Node* temp = m.Int32Constant(0); |
| var1.Bind(temp); |
| m.Branch(m.Int32Constant(1), &l1, &l2); |
| m.Bind(&l1); |
| CHECK_EQ(var1.value(), temp); |
| m.Goto(&merge); |
| m.Bind(&merge); |
| CHECK(var1.value() != temp); |
| CHECK_NOT_NULL(var1.value()); |
| m.Goto(&end); |
| m.Bind(&l2); |
| Node* temp2 = m.Int32Constant(2); |
| var1.Bind(temp2); |
| CHECK_EQ(var1.value(), temp2); |
| m.Goto(&merge); |
| m.Bind(&end); |
| CHECK(var1.value() != temp); |
| CHECK_NOT_NULL(var1.value()); |
| } |
| |
| TEST(VariableMergeSwitch) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Variable var1(&m, MachineRepresentation::kTagged); |
| Label l1(&m), l2(&m), default_label(&m); |
| Label* labels[] = {&l1, &l2}; |
| int32_t values[] = {1, 2}; |
| Node* temp1 = m.Int32Constant(0); |
| var1.Bind(temp1); |
| m.Switch(m.Int32Constant(2), &default_label, values, labels, 2); |
| m.Bind(&l1); |
| CHECK_EQ(temp1, var1.value()); |
| m.Return(temp1); |
| m.Bind(&l2); |
| CHECK_EQ(temp1, var1.value()); |
| Node* temp2 = m.Int32Constant(7); |
| var1.Bind(temp2); |
| m.Goto(&default_label); |
| m.Bind(&default_label); |
| CHECK_EQ(IrOpcode::kPhi, var1.value()->opcode()); |
| CHECK_EQ(2, var1.value()->op()->ValueInputCount()); |
| CHECK_EQ(temp1, NodeProperties::GetValueInput(var1.value(), 0)); |
| CHECK_EQ(temp2, NodeProperties::GetValueInput(var1.value(), 1)); |
| m.Return(temp1); |
| } |
| |
| TEST(SplitEdgeBranchMerge) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Label l1(&m), merge(&m); |
| m.Branch(m.Int32Constant(1), &l1, &merge); |
| m.Bind(&l1); |
| m.Goto(&merge); |
| m.Bind(&merge); |
| USE(asm_tester.GenerateCode()); |
| } |
| |
| TEST(SplitEdgeSwitchMerge) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Label l1(&m), l2(&m), l3(&m), default_label(&m); |
| Label* labels[] = {&l1, &l2}; |
| int32_t values[] = {1, 2}; |
| m.Branch(m.Int32Constant(1), &l3, &l1); |
| m.Bind(&l3); |
| m.Switch(m.Int32Constant(2), &default_label, values, labels, 2); |
| m.Bind(&l1); |
| m.Goto(&l2); |
| m.Bind(&l2); |
| m.Goto(&default_label); |
| m.Bind(&default_label); |
| USE(asm_tester.GenerateCode()); |
| } |
| |
| TEST(TestToConstant) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| int32_t value32; |
| int64_t value64; |
| Node* a = m.Int32Constant(5); |
| CHECK(m.ToInt32Constant(a, value32)); |
| CHECK(m.ToInt64Constant(a, value64)); |
| |
| a = m.Int64Constant(static_cast<int64_t>(1) << 32); |
| CHECK(!m.ToInt32Constant(a, value32)); |
| CHECK(m.ToInt64Constant(a, value64)); |
| |
| a = m.Int64Constant(13); |
| CHECK(m.ToInt32Constant(a, value32)); |
| CHECK(m.ToInt64Constant(a, value64)); |
| |
| a = UndefinedConstant(m); |
| CHECK(!m.ToInt32Constant(a, value32)); |
| CHECK(!m.ToInt64Constant(a, value64)); |
| |
| a = UndefinedConstant(m); |
| CHECK(!m.ToInt32Constant(a, value32)); |
| CHECK(!m.ToInt64Constant(a, value64)); |
| } |
| |
| TEST(DeferredCodePhiHints) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Label block1(&m, Label::kDeferred); |
| m.Goto(&block1); |
| m.Bind(&block1); |
| { |
| Variable var_object(&m, MachineRepresentation::kTagged); |
| Label loop(&m, &var_object); |
| var_object.Bind(m.SmiConstant(0)); |
| m.Goto(&loop); |
| m.Bind(&loop); |
| { |
| Node* map = LoadMap(m, var_object.value()); |
| var_object.Bind(map); |
| m.Goto(&loop); |
| } |
| } |
| CHECK(!asm_tester.GenerateCode().is_null()); |
| } |
| |
| TEST(TestOutOfScopeVariable) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| Label block1(&m); |
| Label block2(&m); |
| Label block3(&m); |
| Label block4(&m); |
| m.Branch(m.WordEqual(m.UncheckedCast<IntPtrT>(m.Parameter(0)), |
| m.IntPtrConstant(0)), |
| &block1, &block4); |
| m.Bind(&block4); |
| { |
| Variable var_object(&m, MachineRepresentation::kTagged); |
| m.Branch(m.WordEqual(m.UncheckedCast<IntPtrT>(m.Parameter(0)), |
| m.IntPtrConstant(0)), |
| &block2, &block3); |
| |
| m.Bind(&block2); |
| var_object.Bind(m.IntPtrConstant(55)); |
| m.Goto(&block1); |
| |
| m.Bind(&block3); |
| var_object.Bind(m.IntPtrConstant(66)); |
| m.Goto(&block1); |
| } |
| m.Bind(&block1); |
| CHECK(!asm_tester.GenerateCode().is_null()); |
| } |
| |
| TEST(GotoIfException) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| |
| const int kNumParams = 1; |
| CodeAssemblerTester asm_tester(isolate, kNumParams); |
| CodeAssembler m(asm_tester.state()); |
| |
| Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); |
| Node* to_string_tag = |
| m.HeapConstant(isolate->factory()->to_string_tag_symbol()); |
| Variable exception(&m, MachineRepresentation::kTagged); |
| |
| Label exception_handler(&m); |
| Callable to_string = Builtins::CallableFor(isolate, Builtins::kToString); |
| Node* string = m.CallStub(to_string, context, to_string_tag); |
| m.GotoIfException(string, &exception_handler, &exception); |
| m.Return(string); |
| |
| m.Bind(&exception_handler); |
| m.Return(exception.value()); |
| |
| FunctionTester ft(asm_tester.GenerateCode(), kNumParams); |
| Handle<Object> result = ft.Call().ToHandleChecked(); |
| |
| // Should be a TypeError. |
| CHECK(result->IsJSObject()); |
| |
| Handle<Object> constructor = |
| Object::GetPropertyOrElement(isolate, result, |
| isolate->factory()->constructor_string()) |
| .ToHandleChecked(); |
| CHECK(constructor->SameValue(*isolate->type_error_function())); |
| } |
| |
| TEST(GotoIfExceptionMultiple) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| |
| const int kNumParams = 4; // receiver, first, second, third |
| CodeAssemblerTester asm_tester(isolate, kNumParams); |
| CodeAssembler m(asm_tester.state()); |
| |
| Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); |
| Node* first_value = m.Parameter(0); |
| Node* second_value = m.Parameter(1); |
| Node* third_value = m.Parameter(2); |
| |
| Label exception_handler1(&m); |
| Label exception_handler2(&m); |
| Label exception_handler3(&m); |
| Variable return_value(&m, MachineRepresentation::kWord32); |
| Variable error(&m, MachineRepresentation::kTagged); |
| |
| return_value.Bind(m.Int32Constant(0)); |
| |
| // try { return ToString(param1) } catch (e) { ... } |
| Callable to_string = Builtins::CallableFor(isolate, Builtins::kToString); |
| Node* string = m.CallStub(to_string, context, first_value); |
| m.GotoIfException(string, &exception_handler1, &error); |
| m.Return(string); |
| |
| // try { ToString(param2); return 7 } catch (e) { ... } |
| m.Bind(&exception_handler1); |
| return_value.Bind(m.Int32Constant(7)); |
| error.Bind(UndefinedConstant(m)); |
| string = m.CallStub(to_string, context, second_value); |
| m.GotoIfException(string, &exception_handler2, &error); |
| m.Return(SmiFromInt32(m, return_value.value())); |
| |
| // try { ToString(param3); return 7 & ~2; } catch (e) { return e; } |
| m.Bind(&exception_handler2); |
| // Return returnValue & ~2 |
| error.Bind(UndefinedConstant(m)); |
| string = m.CallStub(to_string, context, third_value); |
| m.GotoIfException(string, &exception_handler3, &error); |
| m.Return(SmiFromInt32( |
| m, m.Word32And(return_value.value(), |
| m.Word32Xor(m.Int32Constant(2), m.Int32Constant(-1))))); |
| |
| m.Bind(&exception_handler3); |
| m.Return(error.value()); |
| |
| FunctionTester ft(asm_tester.GenerateCode(), kNumParams); |
| |
| Handle<Object> result; |
| // First handler does not throw, returns result of first value. |
| result = ft.Call(isolate->factory()->undefined_value(), |
| isolate->factory()->to_string_tag_symbol()) |
| .ToHandleChecked(); |
| CHECK(String::cast(*result).IsOneByteEqualTo(OneByteVector("undefined"))); |
| |
| // First handler returns a number. |
| result = ft.Call(isolate->factory()->to_string_tag_symbol(), |
| isolate->factory()->undefined_value()) |
| .ToHandleChecked(); |
| CHECK_EQ(7, Smi::ToInt(*result)); |
| |
| // First handler throws, second handler returns a number. |
| result = ft.Call(isolate->factory()->to_string_tag_symbol(), |
| isolate->factory()->to_primitive_symbol()) |
| .ToHandleChecked(); |
| CHECK_EQ(7 & ~2, Smi::ToInt(*result)); |
| |
| // First handler throws, second handler throws, third handler returns thrown |
| // value. |
| result = ft.Call(isolate->factory()->to_string_tag_symbol(), |
| isolate->factory()->to_primitive_symbol(), |
| isolate->factory()->unscopables_symbol()) |
| .ToHandleChecked(); |
| |
| // Should be a TypeError. |
| CHECK(result->IsJSObject()); |
| |
| Handle<Object> constructor = |
| Object::GetPropertyOrElement(isolate, result, |
| isolate->factory()->constructor_string()) |
| .ToHandleChecked(); |
| CHECK(constructor->SameValue(*isolate->type_error_function())); |
| } |
| |
| TEST(ExceptionHandler) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| const int kNumParams = 0; |
| CodeAssemblerTester asm_tester(isolate, kNumParams); |
| CodeAssembler m(asm_tester.state()); |
| |
| CodeAssembler::TVariable<Object> var(m.SmiConstant(0), &m); |
| Label exception(&m, {&var}, Label::kDeferred); |
| { |
| CodeAssemblerScopedExceptionHandler handler(&m, &exception, &var); |
| Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); |
| m.CallRuntime(Runtime::kThrow, context, m.SmiConstant(2)); |
| } |
| m.Return(m.SmiConstant(1)); |
| |
| m.Bind(&exception); |
| m.Return(var.value()); |
| |
| FunctionTester ft(asm_tester.GenerateCode(), kNumParams); |
| CHECK_EQ(2, ft.CallChecked<Smi>()->value()); |
| } |
| |
| TEST(TestCodeAssemblerCodeComment) { |
| i::FLAG_code_comments = true; |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| const int kNumParams = 0; |
| CodeAssemblerTester asm_tester(isolate, kNumParams); |
| CodeAssembler m(asm_tester.state()); |
| |
| m.Comment("Comment1"); |
| m.Return(m.SmiConstant(1)); |
| |
| Handle<Code> code = asm_tester.GenerateCode(); |
| CHECK_NE(code->code_comments(), kNullAddress); |
| CodeCommentsIterator it(code->code_comments(), code->code_comments_size()); |
| CHECK(it.HasCurrent()); |
| bool found_comment = false; |
| while (it.HasCurrent()) { |
| if (strcmp(it.GetComment(), "Comment1") == 0) found_comment = true; |
| it.Next(); |
| } |
| CHECK(found_comment); |
| } |
| |
| TEST(StaticAssert) { |
| Isolate* isolate(CcTest::InitIsolateOnce()); |
| CodeAssemblerTester asm_tester(isolate); |
| CodeAssembler m(asm_tester.state()); |
| m.StaticAssert(m.ReinterpretCast<BoolT>(m.Int32Constant(1))); |
| USE(asm_tester.GenerateCode()); |
| } |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |