// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "vm/globals.h" #if defined(TARGET_ARCH_DBC) #include "vm/compiler/assembler/assembler.h" #include "vm/compiler/backend/locations.h" #include "vm/compiler/compiler_state.h" #include "vm/stack_frame.h" #include "vm/symbols.h" #include "vm/unit_test.h" namespace dart { namespace compiler { static RawObject* ExecuteTest(const Code& code) { const intptr_t kTypeArgsLen = 0; const intptr_t kNumArgs = 0; const Array& args_desc = Array::Handle(ArgumentsDescriptor::New(kTypeArgsLen, kNumArgs)); const Array& args = Array::Handle(Array::New(0)); Thread* thread = Thread::Current(); TransitionToGenerated transition(thread); return Simulator::Current()->Call(code, args_desc, args, thread); } #define EXECUTE_TEST_CODE_INTPTR(code) \ Smi::Value(Smi::RawCast(ExecuteTest(code))) #define EXECUTE_TEST_CODE_BOOL(code) \ (Bool::RawCast(ExecuteTest(code)) == Bool::True().raw()) #define EXECUTE_TEST_CODE_OBJECT(code) Object::Handle(ExecuteTest(code)) #define EXECUTE_TEST_CODE_DOUBLE(code) \ bit_cast(ExecuteTest(code)) #define EXECUTE_TEST_CODE_INTPTR_UNBOXED(code) \ reinterpret_cast(ExecuteTest(code)) #define __ assembler-> static RawClass* CreateDummyClass(const String& class_name, const Script& script) { const Class& cls = Class::Handle(Class::New( Library::Handle(), class_name, script, TokenPosition::kNoSource)); cls.set_is_synthesized_class(); // Dummy class for testing. return cls.raw(); } static RawLibrary* CreateDummyLibrary(const String& library_name) { return Library::New(library_name); } static RawFunction* CreateFunction(const char* name) { Thread* thread = Thread::Current(); const String& class_name = String::Handle(Symbols::New(thread, "ownerClass")); const String& lib_name = String::Handle(Symbols::New(thread, "ownerLibrary")); const Script& script = Script::Handle(); const Class& owner_class = Class::Handle(CreateDummyClass(class_name, script)); const Library& owner_library = Library::Handle(CreateDummyLibrary(lib_name)); owner_class.set_library(owner_library); const String& function_name = String::ZoneHandle(Symbols::New(thread, name)); return Function::New(function_name, RawFunction::kRegularFunction, true, false, false, false, false, owner_class, TokenPosition::kMinSource); } static void GenerateDummyCode(Assembler* assembler, const Object& result) { __ PushConstant(result); __ ReturnTOS(); } static void MakeDummyInstanceCall(Assembler* assembler, const Object& result) { // Make a dummy function. ObjectPoolBuilder object_pool_builder; Assembler _assembler_(&object_pool_builder); GenerateDummyCode(&_assembler_, result); const char* dummy_function_name = "dummy_instance_function"; const Function& dummy_instance_function = Function::Handle(CreateFunction(dummy_function_name)); Code& code = Code::Handle(Code::FinalizeCodeAndNotify( dummy_instance_function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool)); dummy_instance_function.AttachCode(code); // Make a dummy ICData. const intptr_t kTypeArgsLen = 0; const intptr_t kNumArgs = 2; const Array& dummy_arguments_descriptor = Array::Handle(ArgumentsDescriptor::New(kTypeArgsLen, kNumArgs)); const ICData& ic_data = ICData::Handle(ICData::New( dummy_instance_function, String::Handle(dummy_instance_function.name()), dummy_arguments_descriptor, DeoptId::kNone, 2, ICData::kInstance)); // Wire up the Function in the ICData. GrowableArray cids(2); cids.Add(kSmiCid); cids.Add(kSmiCid); ic_data.AddCheck(cids, dummy_instance_function); // For the non-Smi tests. cids[0] = kMintCid; ic_data.AddCheck(cids, dummy_instance_function); ICData* call_ic_data = &ICData::ZoneHandle(ic_data.Original()); // Generate the instance call. const intptr_t call_ic_data_kidx = __ AddConstant(*call_ic_data); __ InstanceCall2(2, call_ic_data_kidx); } ASSEMBLER_TEST_GENERATE(Simple, assembler) { __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(Simple, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(Nop, assembler) { __ PushConstant(Smi::Handle(Smi::New(42))); __ Nop(0); __ Nop(0); __ Nop(0); __ Nop(0); __ Nop(0); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(Nop, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // Called from assembler_test.cc. // FP[-kParamEndSlotFromFp - 1]: growable array // FP[-kParamEndSlotFromFp - 2]: value ASSEMBLER_TEST_GENERATE(StoreIntoObject, assembler) { __ Frame(2); __ Move(0, -kParamEndSlotFromFp - 1); __ Move(1, -kParamEndSlotFromFp - 2); __ StoreField(0, GrowableObjectArray::data_offset() / target::kWordSize, 1); __ Return(0); } // - OneByteStringFromCharCode rA, rX // // Load the one-character symbol with the char code given by the Smi // in FP[rX] into FP[rA]. ASSEMBLER_TEST_GENERATE(OneByteStringFromCharCode, assembler) { __ Frame(2); __ LoadConstant(0, Smi::ZoneHandle(Smi::New(65))); __ OneByteStringFromCharCode(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(OneByteStringFromCharCode, test) { EXPECT_EQ(Symbols::New(Thread::Current(), "A"), EXECUTE_TEST_CODE_OBJECT(test->code()).raw()); } // - StringToCharCode rA, rX // // Load and smi-encode the single char code of the string in FP[rX] into // FP[rA]. If the string's length is not 1, load smi -1 instead. // ASSEMBLER_TEST_GENERATE(StringToCharCode, assembler) { __ Frame(2); __ LoadConstant(0, String::ZoneHandle(String::New("A", Heap::kOld))); __ StringToCharCode(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(StringToCharCode, test) { EXPECT_EQ(65, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(StringToCharCodeIllegalLength, assembler) { __ Frame(2); __ LoadConstant(0, String::ZoneHandle(String::New("AAA", Heap::kOld))); __ StringToCharCode(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(StringToCharCodeIllegalLength, test) { EXPECT_EQ(-1, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - AddTOS; SubTOS; MulTOS; BitOrTOS; BitAndTOS; EqualTOS; LessThanTOS; // GreaterThanTOS; // // Smi fast-path for a corresponding method. Checks if SP[0] and SP[-1] are // both smis and result of SP[0] SP[-1] is a smi - if this is true // then pops operands and pushes result on the stack and skips the next // instruction (which implements a slow path fallback). ASSEMBLER_TEST_GENERATE(AddTOS, assembler) { __ PushConstant(Smi::Handle(Smi::New(-42))); __ PushConstant(Smi::Handle(Smi::New(84))); __ AddTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(AddTOS, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(AddTOSOverflow, assembler) { __ PushConstant(Smi::Handle(Smi::New(Smi::kMaxValue))); __ PushConstant(Smi::Handle(Smi::New(1))); __ AddTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(AddTOSOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(AddTOSNonSmi, assembler) { const String& numstr = String::Handle(String::New("9176543219876543210", Heap::kOld)); __ PushConstant(Integer::Handle(Integer::New(numstr, Heap::kOld))); __ PushConstant(Smi::Handle(Smi::New(1))); __ AddTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(AddTOSNonSmi, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(SubTOS, assembler) { __ PushConstant(Smi::Handle(Smi::New(30))); __ PushConstant(Smi::Handle(Smi::New(-12))); __ SubTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(SubTOS, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(SubTOSOverflow, assembler) { __ PushConstant(Smi::Handle(Smi::New(Smi::kMinValue))); __ PushConstant(Smi::Handle(Smi::New(1))); __ SubTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(SubTOSOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(SubTOSNonSmi, assembler) { const String& numstr = String::Handle(String::New("9176543219876543210", Heap::kOld)); __ PushConstant(Integer::Handle(Integer::New(numstr, Heap::kOld))); __ PushConstant(Smi::Handle(Smi::New(1))); __ SubTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(SubTOSNonSmi, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(MulTOS, assembler) { __ PushConstant(Smi::Handle(Smi::New(-6))); __ PushConstant(Smi::Handle(Smi::New(-7))); __ MulTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(MulTOS, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(MulTOSOverflow, assembler) { __ PushConstant(Smi::Handle(Smi::New(Smi::kMaxValue))); __ PushConstant(Smi::Handle(Smi::New(-8))); __ MulTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(MulTOSOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(MulTOSNonSmi, assembler) { const String& numstr = String::Handle(String::New("9176543219876543210", Heap::kOld)); __ PushConstant(Integer::Handle(Integer::New(numstr, Heap::kOld))); __ PushConstant(Smi::Handle(Smi::New(1))); __ MulTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(MulTOSNonSmi, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(BitOrTOS, assembler) { __ PushConstant(Smi::Handle(Smi::New(0x22))); __ PushConstant(Smi::Handle(Smi::New(0x08))); __ BitOrTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(BitOrTOS, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(BitOrTOSNonSmi, assembler) { const String& numstr = String::Handle(String::New("9176543219876543210", Heap::kOld)); __ PushConstant(Integer::Handle(Integer::New(numstr, Heap::kOld))); __ PushConstant(Smi::Handle(Smi::New(0x08))); __ BitOrTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(BitOrTOSNonSmi, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(BitAndTOS, assembler) { __ PushConstant(Smi::Handle(Smi::New(0x2a))); __ PushConstant(Smi::Handle(Smi::New(0xaa))); __ BitAndTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(BitAndTOS, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(BitAndTOSNonSmi, assembler) { const String& numstr = String::Handle(String::New("9176543219876543210", Heap::kOld)); __ PushConstant(Integer::Handle(Integer::New(numstr, Heap::kOld))); __ PushConstant(Smi::Handle(Smi::New(0x08))); __ BitAndTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(BitAndTOSNonSmi, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(EqualTOSTrue, assembler) { __ PushConstant(Smi::Handle(Smi::New(42))); __ PushConstant(Smi::Handle(Smi::New(42))); __ EqualTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Bool::False()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(EqualTOSTrue, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(EqualTOSFalse, assembler) { __ PushConstant(Smi::Handle(Smi::New(42))); __ PushConstant(Smi::Handle(Smi::New(-42))); __ EqualTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Bool::True()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(EqualTOSFalse, test) { EXPECT(!EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(EqualTOSNonSmi, assembler) { const String& numstr = String::Handle(String::New("9176543219876543210", Heap::kOld)); __ PushConstant(Integer::Handle(Integer::New(numstr, Heap::kOld))); __ PushConstant(Smi::Handle(Smi::New(-42))); __ EqualTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Bool::True()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(EqualTOSNonSmi, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(LessThanTOSTrue, assembler) { __ PushConstant(Smi::Handle(Smi::New(-42))); __ PushConstant(Smi::Handle(Smi::New(42))); __ LessThanTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Bool::False()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(LessThanTOSTrue, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(LessThanTOSFalse, assembler) { __ PushConstant(Smi::Handle(Smi::New(42))); __ PushConstant(Smi::Handle(Smi::New(-42))); __ LessThanTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Bool::False()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(LessThanTOSFalse, test) { EXPECT(!EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(LessThanTOSNonSmi, assembler) { const String& numstr = String::Handle(String::New("9176543219876543210", Heap::kOld)); __ PushConstant(Integer::Handle(Integer::New(numstr, Heap::kOld))); __ PushConstant(Smi::Handle(Smi::New(-42))); __ LessThanTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Bool::True()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(LessThanTOSNonSmi, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(GreaterThanTOSTrue, assembler) { __ PushConstant(Smi::Handle(Smi::New(42))); __ PushConstant(Smi::Handle(Smi::New(-42))); __ GreaterThanTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Bool::False()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(GreaterThanTOSTrue, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(GreaterThanTOSFalse, assembler) { __ PushConstant(Smi::Handle(Smi::New(-42))); __ PushConstant(Smi::Handle(Smi::New(42))); __ GreaterThanTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Bool::False()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(GreaterThanTOSFalse, test) { EXPECT(!EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(GreaterThanTOSNonSmi, assembler) { const String& numstr = String::Handle(String::New("9176543219876543210", Heap::kOld)); __ PushConstant(Integer::Handle(Integer::New(numstr, Heap::kOld))); __ PushConstant(Smi::Handle(Smi::New(-42))); __ GreaterThanTOS(); // Shouldn't be skipped. MakeDummyInstanceCall(assembler, Bool::True()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(GreaterThanTOSNonSmi, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } // - Add, Sub, Mul, Div, Mod, Shl, Shr rA, rB, rC // // Arithmetic operations on Smis. FP[rA] <- FP[rB] op FP[rC]. // If these instructions can trigger a deoptimization, the following // instruction should be Deopt. If no deoptimization should be triggered, // the immediately following instruction is skipped. ASSEMBLER_TEST_GENERATE(AddNoOverflow, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(20))); __ LoadConstant(1, Smi::Handle(Smi::New(22))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Add(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(-42))); __ Return(2); } ASSEMBLER_TEST_RUN(AddNoOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(AddOverflow, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(Smi::kMaxValue))); __ LoadConstant(1, Smi::Handle(Smi::New(1))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Add(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(42))); __ Return(2); } ASSEMBLER_TEST_RUN(AddOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(SubNoOverflow, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(64))); __ LoadConstant(1, Smi::Handle(Smi::New(22))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Sub(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(-42))); __ Return(2); } ASSEMBLER_TEST_RUN(SubNoOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(SubOverflow, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(Smi::kMinValue))); __ LoadConstant(1, Smi::Handle(Smi::New(1))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Sub(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(42))); __ Return(2); } ASSEMBLER_TEST_RUN(SubOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(MulNoOverflow, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-6))); __ LoadConstant(1, Smi::Handle(Smi::New(-7))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Mul(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(-42))); __ Return(2); } ASSEMBLER_TEST_RUN(MulNoOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(MulOverflow, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(Smi::kMaxValue))); __ LoadConstant(1, Smi::Handle(Smi::New(-8))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Mul(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(42))); __ Return(2); } ASSEMBLER_TEST_RUN(MulOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(DivNoDeopt, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(27))); __ LoadConstant(1, Smi::Handle(Smi::New(3))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Div(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(-42))); __ Return(2); } ASSEMBLER_TEST_RUN(DivNoDeopt, test) { EXPECT_EQ(9, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(DivZero, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(3))); __ LoadConstant(1, Smi::Handle(Smi::New(0))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Div(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(42))); __ Return(2); } ASSEMBLER_TEST_RUN(DivZero, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(DivCornerCase, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(Smi::kMinValue))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Div(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(42))); __ Return(2); } ASSEMBLER_TEST_RUN(DivCornerCase, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(ModPosPos, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(4))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Mod(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(-42))); __ Return(2); } ASSEMBLER_TEST_RUN(ModPosPos, test) { EXPECT_EQ(2, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(ModNegPos, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-42))); __ LoadConstant(1, Smi::Handle(Smi::New(4))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Mod(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(-42))); __ Return(2); } ASSEMBLER_TEST_RUN(ModNegPos, test) { EXPECT_EQ(2, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(ModPosNeg, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(-4))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Mod(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(-42))); __ Return(2); } ASSEMBLER_TEST_RUN(ModPosNeg, test) { EXPECT_EQ(2, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(ModZero, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(3))); __ LoadConstant(1, Smi::Handle(Smi::New(0))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Mod(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(42))); __ Return(2); } ASSEMBLER_TEST_RUN(ModZero, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(ShlNoDeopt, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(21))); __ LoadConstant(1, Smi::Handle(Smi::New(1))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Shl(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(-42))); __ Return(2); } ASSEMBLER_TEST_RUN(ShlNoDeopt, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(ShlOverflow, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(Smi::kMaxValue))); __ LoadConstant(1, Smi::Handle(Smi::New(1))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Shl(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(42))); __ Return(2); } ASSEMBLER_TEST_RUN(ShlOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(ShlNegShift, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(21))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Shl(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(42))); __ Return(2); } ASSEMBLER_TEST_RUN(ShlNegShift, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(ShrNoDeopt, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(84))); __ LoadConstant(1, Smi::Handle(Smi::New(1))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Shr(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(-42))); __ Return(2); } ASSEMBLER_TEST_RUN(ShrNoDeopt, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(ShrNegShift, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(21))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ Shr(2, 0, 1); __ LoadConstant(2, Smi::Handle(Smi::New(42))); __ Return(2); } ASSEMBLER_TEST_RUN(ShrNegShift, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - Neg rA , rD // // FP[rA] <- -FP[rD]. Assumes FP[rD] is a Smi. If there is no overflow the // immediately following instruction is skipped. ASSEMBLER_TEST_GENERATE(NegPos, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ Neg(1, 0); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ Return(1); } ASSEMBLER_TEST_RUN(NegPos, test) { EXPECT_EQ(-42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(NegNeg, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(-42))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ Neg(1, 0); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ Return(1); } ASSEMBLER_TEST_RUN(NegNeg, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(NegOverflow, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(Smi::kMinValue))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ Neg(1, 0); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ Return(1); } ASSEMBLER_TEST_RUN(NegOverflow, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - BitOr, BitAnd, BitXor rA, rB, rC // // FP[rA] <- FP[rB] op FP[rC] ASSEMBLER_TEST_GENERATE(BitOr, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(0x2))); __ LoadConstant(1, Smi::Handle(Smi::New(0x28))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ BitOr(2, 0, 1); __ Return(2); } ASSEMBLER_TEST_RUN(BitOr, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(BitAnd, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(0x2b))); __ LoadConstant(1, Smi::Handle(Smi::New(0x6a))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ BitAnd(2, 0, 1); __ Return(2); } ASSEMBLER_TEST_RUN(BitAnd, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(BitXor, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(0x37))); __ LoadConstant(1, Smi::Handle(Smi::New(0x1d))); __ LoadConstant(2, Smi::Handle(Smi::New(-1))); __ BitXor(2, 0, 1); __ Return(2); } ASSEMBLER_TEST_RUN(BitXor, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - BitNot rA, rD // // FP[rA] <- ~FP[rD]. As above, assumes FP[rD] is a Smi. ASSEMBLER_TEST_GENERATE(BitNot, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(~42))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ BitNot(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(BitNot, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - IfNeStrictTOS; IfEqStrictTOS; IfNeStrictNumTOS; IfEqStrictNumTOS // // Skips the next instruction unless the given condition holds. 'Num' // variants perform number check while non-Num variants just compare // RawObject pointers. // // Used to implement conditional jump: // // IfNeStrictTOS // Jump T ;; jump if not equal ASSEMBLER_TEST_GENERATE(IfNeStrictTOSTaken, assembler) { Label branch_taken; const Array& array1 = Array::Handle(Array::New(1, Heap::kOld)); const Array& array2 = Array::Handle(Array::New(2, Heap::kOld)); __ PushConstant(array1); __ PushConstant(array2); __ IfNeStrictTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfNeStrictTOSTaken, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfNeStrictTOSNotTaken, assembler) { Label branch_taken; const Array& array1 = Array::Handle(Array::New(1, Heap::kOld)); __ PushConstant(array1); __ PushConstant(array1); __ IfNeStrictTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfNeStrictTOSNotTaken, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // TODO(zra): Also add tests that use Mint, Bignum. ASSEMBLER_TEST_GENERATE(IfNeStrictNumTOSTaken, assembler) { Label branch_taken; __ PushConstant(Smi::Handle(Smi::New(-1))); __ PushConstant(Smi::Handle(Smi::New(1))); __ IfNeStrictNumTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfNeStrictNumTOSTaken, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfNeStrictNumTOSNotTaken, assembler) { Label branch_taken; __ PushConstant(Smi::Handle(Smi::New(1))); __ PushConstant(Smi::Handle(Smi::New(1))); __ IfNeStrictNumTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfNeStrictNumTOSNotTaken, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfNeStrictNumTOSTakenDouble, assembler) { Label branch_taken; __ PushConstant(Double::Handle(Double::New(-1.0, Heap::kOld))); __ PushConstant(Double::Handle(Double::New(1.0, Heap::kOld))); __ IfNeStrictNumTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfNeStrictNumTOSTakenDouble, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfNeStrictNumTOSNotTakenDouble, assembler) { Label branch_taken; __ PushConstant(Double::Handle(Double::New(1.0, Heap::kOld))); __ PushConstant(Double::Handle(Double::New(1.0, Heap::kOld))); __ IfNeStrictNumTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfNeStrictNumTOSNotTakenDouble, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfEqStrictTOSTaken, assembler) { Label branch_taken; const Array& array1 = Array::Handle(Array::New(1, Heap::kOld)); __ PushConstant(array1); __ PushConstant(array1); __ IfEqStrictTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfEqStrictTOSTaken, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfEqStrictTOSNotTaken, assembler) { Label branch_taken; const Array& array1 = Array::Handle(Array::New(1, Heap::kOld)); const Array& array2 = Array::Handle(Array::New(2, Heap::kOld)); __ PushConstant(array1); __ PushConstant(array2); __ IfEqStrictTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfEqStrictTOSNotTaken, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // TODO(zra): Also add tests that use Mint, Bignum. ASSEMBLER_TEST_GENERATE(IfEqStrictNumTOSTaken, assembler) { Label branch_taken; __ PushConstant(Smi::Handle(Smi::New(1))); __ PushConstant(Smi::Handle(Smi::New(1))); __ IfEqStrictNumTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfEqStrictNumTOSTaken, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfEqStrictNumTOSNotTaken, assembler) { Label branch_taken; __ PushConstant(Smi::Handle(Smi::New(-1))); __ PushConstant(Smi::Handle(Smi::New(1))); __ IfEqStrictNumTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfEqStrictNumTOSNotTaken, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfEqStrictNumTOSTakenDouble, assembler) { Label branch_taken; __ PushConstant(Double::Handle(Double::New(1.0, Heap::kOld))); __ PushConstant(Double::Handle(Double::New(1.0, Heap::kOld))); __ IfEqStrictNumTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfEqStrictNumTOSTakenDouble, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfEqStrictNumTOSNotTakenDouble, assembler) { Label branch_taken; __ PushConstant(Double::Handle(Double::New(-1.0, Heap::kOld))); __ PushConstant(Double::Handle(Double::New(1.0, Heap::kOld))); __ IfEqStrictNumTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfEqStrictNumTOSNotTakenDouble, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - BooleanNegateTOS // // SP[0] = !SP[0] ASSEMBLER_TEST_GENERATE(BooleanNegateTOSTrue, assembler) { __ PushConstant(Bool::True()); __ BooleanNegateTOS(); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(BooleanNegateTOSTrue, test) { EXPECT(!EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(BooleanNegateTOSFalse, assembler) { __ PushConstant(Bool::False()); __ BooleanNegateTOS(); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(BooleanNegateTOSFalse, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } // - AssertBoolean A // // Assert that TOS is a boolean (A = 1) or that TOS is not null (A = 0). ASSEMBLER_TEST_GENERATE(AssertBooleanTrue, assembler) { __ PushConstant(Bool::True()); __ AssertBoolean(1); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(AssertBooleanTrue, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(AssertBooleanFalse, assembler) { __ PushConstant(Bool::False()); __ AssertBoolean(1); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(AssertBooleanFalse, test) { EXPECT(!EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(AssertBooleanNotNull, assembler) { __ PushConstant(Bool::True()); __ AssertBoolean(0); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(AssertBooleanNotNull, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(AssertBooleanFail1, assembler) { __ PushConstant(Smi::Handle(Smi::New(37))); __ AssertBoolean(1); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(AssertBooleanFail1, test) { EXPECT(EXECUTE_TEST_CODE_OBJECT(test->code()).IsError()); } ASSEMBLER_TEST_GENERATE(AssertBooleanFail2, assembler) { __ PushConstant(Object::null_object()); __ AssertBoolean(0); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(AssertBooleanFail2, test) { EXPECT(EXECUTE_TEST_CODE_OBJECT(test->code()).IsError()); } // - Drop1; DropR n; Drop n // // Drop 1 or n values from the stack, if instruction is DropR push the first // dropped value to the stack; ASSEMBLER_TEST_GENERATE(Drop1, assembler) { __ PushConstant(Smi::Handle(Smi::New(0))); __ PushConstant(Smi::Handle(Smi::New(42))); __ PushConstant(Smi::Handle(Smi::New(37))); __ Drop1(); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(Drop1, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(Drop, assembler) { __ PushConstant(Smi::Handle(Smi::New(0))); __ PushConstant(Smi::Handle(Smi::New(42))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ Drop(11); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(Drop, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(DropR, assembler) { __ PushConstant(Smi::Handle(Smi::New(0))); __ PushConstant(Smi::Handle(Smi::New(1))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(41))); __ DropR(11); __ AddTOS(); MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(DropR, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - Frame D // // Reserve and initialize with null space for D local variables. ASSEMBLER_TEST_GENERATE(FrameInitialized1, assembler) { __ Frame(1); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(FrameInitialized1, test) { EXPECT(EXECUTE_TEST_CODE_OBJECT(test->code()).IsNull()); } ASSEMBLER_TEST_GENERATE(FrameInitialized, assembler) { Label error; __ PushConstant(Smi::Handle(Smi::New(42))); __ Frame(4); __ PushConstant(Object::null_object()); __ IfNeStrictTOS(); __ Jump(&error); __ PushConstant(Object::null_object()); __ IfNeStrictTOS(); __ Jump(&error); __ PushConstant(Object::null_object()); __ IfNeStrictTOS(); __ Jump(&error); __ PushConstant(Object::null_object()); __ IfNeStrictTOS(); __ Jump(&error); __ ReturnTOS(); // If a frame slot was not initialized to null. __ Bind(&error); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(FrameInitialized, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - StoreLocal rX; PopLocal rX // // Store top of the stack into FP[rX] and pop it if needed. // // - Push rX // // Push FP[rX] to the stack. ASSEMBLER_TEST_GENERATE(StoreLocalPush, assembler) { __ Frame(1); __ PushConstant(Smi::Handle(Smi::New(37))); __ PushConstant(Smi::Handle(Smi::New(21))); __ StoreLocal(0); __ Push(0); __ AddTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(StoreLocalPush, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(PopLocalPush, assembler) { __ Frame(1); __ PushConstant(Smi::Handle(Smi::New(21))); __ PopLocal(0); __ Push(0); __ Push(0); __ AddTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(PopLocalPush, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(LoadConstantPush, assembler) { __ Frame(1); __ LoadConstant(0, Smi::Handle(Smi::New(21))); __ Push(0); __ Push(0); __ AddTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(LoadConstantPush, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - Move rA, rX // // FP[rA] <- FP[rX] // Note: rX is signed so it can be used to address parameters which are // at negative indices with respect to FP. ASSEMBLER_TEST_GENERATE(MoveLocalLocal, assembler) { __ Frame(2); __ PushConstant(Smi::Handle(Smi::New(21))); __ PopLocal(0); __ Move(1, 0); __ Push(0); __ Push(1); __ AddTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(MoveLocalLocal, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - Return R; ReturnTOS // // Return to the caller using either a value from the given register or a // value from the top-of-stack as a result. ASSEMBLER_TEST_GENERATE(Return1, assembler) { __ Frame(1); __ PushConstant(Smi::Handle(Smi::New(42))); __ StoreLocal(0); __ Return(0); } ASSEMBLER_TEST_RUN(Return1, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(Return2, assembler) { __ Frame(2); __ PushConstant(Smi::Handle(Smi::New(42))); __ StoreLocal(1); __ Return(1); } ASSEMBLER_TEST_RUN(Return2, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(Loop, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(0))); Label loop_entry, error; __ Bind(&loop_entry); // Add 1 to FP[1]. __ PushConstant(Smi::Handle(Smi::New(1))); __ Push(1); __ AddTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(-1))); __ PopLocal(1); // Subtract 1 from FP[0]. __ Push(0); __ PushConstant(Smi::Handle(Smi::New(1))); __ SubTOS(); // Should be skipped. MakeDummyInstanceCall(assembler, Smi::Handle(Smi::New(-1))); // Jump to loop_entry if FP[0] != 0. __ StoreLocal(0); __ PushConstant(Smi::Handle(Smi::New(0))); __ IfNeStrictNumTOS(); __ Jump(&loop_entry); __ Return(1); __ Bind(&error); __ LoadConstant(1, Smi::Handle(Smi::New(-42))); __ Return(1); } ASSEMBLER_TEST_RUN(Loop, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - LoadClassIdTOS, LoadClassId rA, D // // LoadClassIdTOS loads the class id from the object at SP[0] and stores it // to SP[0]. LoadClassId loads the class id from FP[rA] and stores it to // FP[D]. ASSEMBLER_TEST_GENERATE(LoadClassIdTOS, assembler) { __ PushConstant(Smi::Handle(Smi::New(42))); __ LoadClassIdTOS(); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(LoadClassIdTOS, test) { EXPECT_EQ(kSmiCid, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(LoadClassId, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadClassId(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(LoadClassId, test) { EXPECT_EQ(kSmiCid, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - CreateArrayTOS // // Allocate array of length SP[0] with type arguments SP[-1]. ASSEMBLER_TEST_GENERATE(CreateArrayTOS, assembler) { __ PushConstant(Object::null_object()); __ PushConstant(Smi::Handle(Smi::New(10))); __ CreateArrayTOS(); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(CreateArrayTOS, test) { const Object& obj = EXECUTE_TEST_CODE_OBJECT(test->code()); EXPECT(obj.IsArray()); Array& array = Array::Handle(); array ^= obj.raw(); EXPECT_EQ(10, array.Length()); } // - TestSmi rA, rD // // If FP[rA] & FP[rD] != 0, then skip the next instruction. FP[rA] and FP[rD] // must be Smis. ASSEMBLER_TEST_GENERATE(TestSmiTrue, assembler) { Label branch_taken; __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(7))); __ LoadConstant(1, Smi::Handle(Smi::New(3))); __ TestSmi(0, 1); __ Jump(&branch_taken); __ PushConstant(Bool::True()); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Bool::False()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(TestSmiTrue, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(TestSmiFalse, assembler) { Label branch_taken; __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(8))); __ LoadConstant(1, Smi::Handle(Smi::New(4))); __ TestSmi(0, 1); __ Jump(&branch_taken); __ PushConstant(Bool::True()); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Bool::False()); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(TestSmiFalse, test) { EXPECT(!EXECUTE_TEST_CODE_BOOL(test->code())); } // - TestCids rA, D // // The next D instructions must be Nops whose D field encodes a class id. If // the class id of FP[rA] matches, jump to PC + N + 1 if the matching Nop's // A != 0 or PC + N + 2 if the matching Nop's A = 0. If no match is found, // jump to PC + N. ASSEMBLER_TEST_GENERATE(TestCidsTrue, assembler) { Label true_branch, no_match_branch; __ Frame(2); __ LoadConstant(0, Object::Handle(String::New("Hi", Heap::kOld))); const intptr_t num_cases = 2; __ TestCids(0, num_cases); __ Nop(0, static_cast(kSmiCid)); // Smi => false __ Nop(1, static_cast(kOneByteStringCid)); // String => true __ Jump(&no_match_branch); __ Jump(&true_branch); __ LoadConstant(1, Smi::Handle(Smi::New(0))); // false branch __ Return(1); __ Bind(&true_branch); __ LoadConstant(1, Smi::Handle(Smi::New(1))); __ Return(1); __ Bind(&no_match_branch); __ LoadConstant(1, Smi::Handle(Smi::New(2))); __ Return(1); } ASSEMBLER_TEST_RUN(TestCidsTrue, test) { EXPECT_EQ(1, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(TestCidsFalse, assembler) { Label true_branch, no_match_branch; __ Frame(2); __ LoadConstant(0, Object::Handle(Smi::New(42))); const intptr_t num_cases = 2; __ TestCids(0, num_cases); __ Nop(0, static_cast(kSmiCid)); // Smi => false __ Nop(1, static_cast(kOneByteStringCid)); // String => true __ Jump(&no_match_branch); __ Jump(&true_branch); __ LoadConstant(1, Smi::Handle(Smi::New(0))); // false branch __ Return(1); __ Bind(&true_branch); __ LoadConstant(1, Smi::Handle(Smi::New(1))); __ Return(1); __ Bind(&no_match_branch); __ LoadConstant(1, Smi::Handle(Smi::New(2))); __ Return(1); } ASSEMBLER_TEST_RUN(TestCidsFalse, test) { EXPECT_EQ(0, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(TestCidsNoMatch, assembler) { Label true_branch, no_match_branch; __ Frame(2); __ LoadConstant(0, Object::Handle(Array::New(1, Heap::kOld))); const intptr_t num_cases = 2; __ TestCids(0, num_cases); __ Nop(0, static_cast(kSmiCid)); // Smi => false __ Nop(1, static_cast(kOneByteStringCid)); // String => true __ Jump(&no_match_branch); __ Jump(&true_branch); __ LoadConstant(1, Smi::Handle(Smi::New(0))); // false branch __ Return(1); __ Bind(&true_branch); __ LoadConstant(1, Smi::Handle(Smi::New(1))); __ Return(1); __ Bind(&no_match_branch); __ LoadConstant(1, Smi::Handle(Smi::New(2))); __ Return(1); } ASSEMBLER_TEST_RUN(TestCidsNoMatch, test) { EXPECT_EQ(2, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - CheckSmi rA // // If FP[rA] is a Smi, then skip the next instruction. ASSEMBLER_TEST_GENERATE(CheckSmiPass, assembler) { __ Frame(1); __ PushConstant(Smi::Handle(Smi::New(42))); __ LoadConstant(0, Smi::Handle(Smi::New(0))); __ CheckSmi(0); __ PushConstant(Smi::Handle(Smi::New(-1))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(CheckSmiPass, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(CheckSmiFail, assembler) { __ Frame(1); __ PushConstant(Smi::Handle(Smi::New(-1))); __ LoadConstant(0, Bool::True()); __ CheckSmi(0); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(CheckSmiFail, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - CheckClassId rA, D // // If the object at FP[rA]'s class id matches the class id in PP[D], then // skip the following instruction. ASSEMBLER_TEST_GENERATE(CheckClassIdSmiPass, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadClassId(1, 0); __ CheckClassId(1, kSmiCid); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(CheckClassIdSmiPass, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(CheckClassIdNonSmiPass, assembler) { __ Frame(2); __ LoadConstant(0, Bool::True()); __ LoadClassId(1, 0); __ CheckClassId(1, kBoolCid); __ LoadConstant(0, Bool::False()); __ Return(0); } ASSEMBLER_TEST_RUN(CheckClassIdNonSmiPass, test) { EXPECT(EXECUTE_TEST_CODE_BOOL(test->code())); } ASSEMBLER_TEST_GENERATE(CheckClassIdFail, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadClassId(1, 0); __ CheckClassId(1, kBoolCid); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(CheckClassIdFail, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - IfNull rA // // Cond is Eq or Ne. Skips the next instruction unless the given condition // holds. ASSEMBLER_TEST_GENERATE(IfEqNullNotNull, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ IfEqNull(0); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ Return(1); } ASSEMBLER_TEST_RUN(IfEqNullNotNull, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfEqNullIsNull, assembler) { __ Frame(2); __ LoadConstant(0, Object::null_object()); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ IfEqNull(0); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ Return(1); } ASSEMBLER_TEST_RUN(IfEqNullIsNull, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfNeNullIsNull, assembler) { __ Frame(2); __ LoadConstant(0, Object::null_object()); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ IfNeNull(0); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ Return(1); } ASSEMBLER_TEST_RUN(IfNeNullIsNull, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfNeNullNotNull, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ IfNeNull(0); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ Return(1); } ASSEMBLER_TEST_RUN(IfNeNullNotNull, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfEqNullTOSNotNull, assembler) { Label branch_taken; __ PushConstant(Smi::Handle(Smi::New(-1))); __ IfEqNullTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfEqNullTOSNotNull, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfEqNullTOSIsNull, assembler) { Label branch_taken; __ PushConstant(Object::null_object()); __ IfEqNullTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfEqNullTOSIsNull, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfNeNullTOSNotNull, assembler) { Label branch_taken; __ PushConstant(Smi::Handle(Smi::New(-1))); __ IfNeNullTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfNeNullTOSNotNull, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfNeNullTOSIsNull, assembler) { Label branch_taken; __ PushConstant(Object::null_object()); __ IfNeNullTOS(); __ Jump(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(42))); __ ReturnTOS(); __ Bind(&branch_taken); __ PushConstant(Smi::Handle(Smi::New(0))); __ ReturnTOS(); } ASSEMBLER_TEST_RUN(IfNeNullTOSIsNull, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - If rA, rD // // Cond is Le, Lt, Ge, Gt, unsigned variants ULe, ULt, UGe, UGt, and // unboxed double variants DEq, DNe, DLe, DLt, DGe, DGt. // Skips the next instruction unless FP[rA] FP[rD]. Assumes that // FP[rA] and FP[rD] are Smis or unboxed doubles as indicated by . ASSEMBLER_TEST_GENERATE(IfLeTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(-5))); __ LoadConstant(2, Smi::Handle(Smi::New(100))); __ IfLe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfLeTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfLeFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(100))); __ LoadConstant(2, Smi::Handle(Smi::New(-5))); __ IfLe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfLeFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfLtTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(-5))); __ LoadConstant(2, Smi::Handle(Smi::New(100))); __ IfLt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfLtTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfLtFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(100))); __ LoadConstant(2, Smi::Handle(Smi::New(-5))); __ IfLt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfLtFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfGeTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(100))); __ LoadConstant(2, Smi::Handle(Smi::New(-5))); __ IfGe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfGeTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfGeFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(-5))); __ LoadConstant(2, Smi::Handle(Smi::New(100))); __ IfGe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfGeFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfGtTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(100))); __ LoadConstant(2, Smi::Handle(Smi::New(-5))); __ IfGt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfGtTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfGtFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(-5))); __ LoadConstant(2, Smi::Handle(Smi::New(100))); __ IfGt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfGtFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } #if defined(ARCH_IS_64_BIT) ASSEMBLER_TEST_GENERATE(IfDNeTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDNe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDNeTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDNeFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDNe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDNeFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDNeNan, assembler) { const double not_a_number = bit_cast(0x7FF8000000000000LL); __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(not_a_number, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDNe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDNeNan, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDEqTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDEq(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDEqTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDEqFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDEq(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDEqFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDEqNan, assembler) { const double not_a_number = bit_cast(0x7FF8000000000000LL); __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(not_a_number, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDEq(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDEqNan, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDLeTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDLe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDLeTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDLeFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(100.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDLe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDLeFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDLeNan, assembler) { const double not_a_number = bit_cast(0x7FF8000000000000LL); __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDLe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDLeNan, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDLtTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDLt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDLtTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDLtFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(100.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDLt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDLtFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDLtNan, assembler) { const double not_a_number = bit_cast(0x7FF8000000000000LL); __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDLt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDLtNan, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDGeTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Double::Handle(Double::New(100.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDGe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDGeTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDGeFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDGe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDGeFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDGeNan, assembler) { const double not_a_number = bit_cast(0x7FF8000000000000LL); __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDGe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDGeNan, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDGtTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Double::Handle(Double::New(100.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDGt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDGtTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDGtFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDGt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDGtFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfDGtNan, assembler) { const double not_a_number = bit_cast(0x7FF8000000000000LL); __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld))); __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld))); __ UnboxDouble(1, 1); __ UnboxDouble(2, 2); __ IfDGt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfDGtNan, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } #endif // defined(ARCH_IS_64_BIT) ASSEMBLER_TEST_GENERATE(IfULeTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(5))); __ LoadConstant(2, Smi::Handle(Smi::New(100))); __ IfULe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfULeTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfULeFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(100))); __ LoadConstant(2, Smi::Handle(Smi::New(5))); __ IfULe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfULeFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfULeNegTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(5))); __ LoadConstant(2, Smi::Handle(Smi::New(-5))); __ IfULe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfULeNegTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfULtTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(5))); __ LoadConstant(2, Smi::Handle(Smi::New(100))); __ IfULt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfULtTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfULtFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(100))); __ LoadConstant(2, Smi::Handle(Smi::New(5))); __ IfULt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfULtFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfUGeTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(100))); __ LoadConstant(2, Smi::Handle(Smi::New(5))); __ IfUGe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfUGeTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfUGeFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(5))); __ LoadConstant(2, Smi::Handle(Smi::New(100))); __ IfUGe(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfUGeFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfUGtTrue, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ LoadConstant(1, Smi::Handle(Smi::New(100))); __ LoadConstant(2, Smi::Handle(Smi::New(5))); __ IfUGt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ Return(0); } ASSEMBLER_TEST_RUN(IfUGtTrue, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(IfUGtFalse, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(5))); __ LoadConstant(2, Smi::Handle(Smi::New(100))); __ IfUGt(1, 2); __ LoadConstant(0, Smi::Handle(Smi::New(-1))); __ Return(0); } ASSEMBLER_TEST_RUN(IfUGtFalse, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - Min, Max rA, rB, rC // // FP[rA] <- {min, max}(FP[rB], FP[rC]). Assumes that FP[rB], and FP[rC] are // Smis. ASSEMBLER_TEST_GENERATE(Min, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(500))); __ Min(2, 0, 1); __ Return(2); } ASSEMBLER_TEST_RUN(Min, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(Max, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ LoadConstant(1, Smi::Handle(Smi::New(5))); __ Max(2, 0, 1); __ Return(2); } ASSEMBLER_TEST_RUN(Max, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - UnboxInt32 rA, rB, C // // Unboxes the integer in FP[rB] into FP[rA]. If C == 1, the value may be // truncated. If FP[rA] is successfully unboxed the following instruction is // skipped. ASSEMBLER_TEST_GENERATE(UnboxInt32NoTrunctateSuccess, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(1234))); __ UnboxInt32(1, 0, /*may_truncate=*/0); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ Return(1); } ASSEMBLER_TEST_RUN(UnboxInt32NoTrunctateSuccess, test) { EXPECT_EQ(1234, EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } ASSEMBLER_TEST_GENERATE(UnboxInt32NoTrunctateFail, assembler) { __ Frame(2); __ LoadConstant(0, Integer::Handle(Integer::New(Smi::kMaxValue + 1))); __ UnboxInt32(1, 0, /*may_truncate=*/0); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ Return(1); } ASSEMBLER_TEST_RUN(UnboxInt32NoTrunctateFail, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(UnboxInt32TrunctateSuccess, assembler) { __ Frame(2); __ LoadConstant( 0, Integer::Handle(Integer::New(static_cast(kMaxInt32) + 1))); __ UnboxInt32(1, 0, /*may_truncate=*/1); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ Return(1); } ASSEMBLER_TEST_RUN(UnboxInt32TrunctateSuccess, test) { EXPECT_EQ(static_cast(kMaxInt32) + 1, EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } // - BoxInt32 rA, rD // // Boxes the unboxed signed 32-bit integer in FP[rD] into FP[rA]. ASSEMBLER_TEST_GENERATE(BoxInt32, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ UnboxInt32(1, 0, /*may_truncate=*/0); __ Nop(0); // Unboxing succeeds. __ BoxInt32(2, 1); __ Return(2); } ASSEMBLER_TEST_RUN(BoxInt32, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - BoxUint32 rA, rD // // Boxes the unboxed unsigned 32-bit integer in FP[rD] into FP[rA]. ASSEMBLER_TEST_GENERATE(BoxUint32, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ UnboxInt32(1, 0, /*may_truncate=*/0); __ Nop(0); // Unboxing succeeds. __ BoxUint32(2, 1); __ Return(2); } ASSEMBLER_TEST_RUN(BoxUint32, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - UnboxInt64 rA, rD // // Unboxes the integer in FP[rD] into FP[rA]. ASSEMBLER_TEST_GENERATE(UnboxInt64MaxMint, assembler) { __ Frame(2); __ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt64))); __ UnboxInt64(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(UnboxInt64MaxMint, test) { EXPECT_EQ(kMaxInt64, EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } ASSEMBLER_TEST_GENERATE(UnboxInt64MinMint, assembler) { __ Frame(2); __ LoadConstant(0, Integer::Handle(Integer::New(kMinInt64))); __ UnboxInt64(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(UnboxInt64MinMint, test) { EXPECT_EQ(kMinInt64, EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } ASSEMBLER_TEST_GENERATE(UnboxInt64Smi, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ UnboxInt64(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(UnboxInt64Smi, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } // - BoxInt64 rA, rD // // Boxes the unboxed signed 64-bit integer in FP[rD] into FP[rA]. If the // value does not fit into a Smi the following instruction is skipped. (The // following instruction should be a jump to a label after the slow path // allocating a Mint box and writing into the Mint box.) ASSEMBLER_TEST_GENERATE(BoxInt64Smi, assembler) { __ Frame(3); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ UnboxInt64(1, 0); __ BoxInt64(2, 1); __ Nop(0); __ Return(2); } ASSEMBLER_TEST_RUN(BoxInt64Smi, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(BoxInt64MintFails, assembler) { Label done; __ Frame(3); __ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt64))); __ UnboxInt64(1, 0); __ BoxInt64(2, 1); // Boxing into Smi fails. __ Jump(&done); // Faking a slow path, with a different Mint value. __ LoadConstant(2, Integer::Handle(Integer::New(kMaxInt64 - 42))); __ Bind(&done); __ Return(2); } ASSEMBLER_TEST_RUN(BoxInt64MintFails, test) { const Object& obj = EXECUTE_TEST_CODE_OBJECT(test->code()); EXPECT(obj.IsMint()); EXPECT_EQ(kMaxInt64 - 42, Mint::Cast(obj).value()); } ASSEMBLER_TEST_GENERATE(WriteIntoMint, assembler) { __ Frame(3); __ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt64))); __ UnboxInt64(1, 0); __ LoadConstant(2, Integer::Handle(Integer::New(kMaxInt64 - 42))); __ WriteIntoMint(2, 1); // Transplant unboxed value into an existing box. __ Return(2); } ASSEMBLER_TEST_RUN(WriteIntoMint, test) { const Object& obj = EXECUTE_TEST_CODE_OBJECT(test->code()); EXPECT(obj.IsMint()); EXPECT_EQ(kMaxInt64, Mint::Cast(obj).value()); } // - UnboxedWidthExtender rA rB C // // Sign- or zero-extends an unboxed integer in FP[rB] into an unboxed // integer in FP[rA]. C contains SmallRepresentation which determines how // the integer is extended. ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderInt8Positive, assembler) { __ Frame(3); __ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt8 + 0xFFFFFF00))); __ UnboxInt64(1, 0); // The lower bits contain 0x7F, overwrite the upper bits with 0. __ UnboxedWidthExtender(2, 1, kSmallUnboxedInt8); __ Return(2); } ASSEMBLER_TEST_RUN(UnboxedWidthExtenderInt8Positive, test) { EXPECT_EQ(static_cast(kMaxInt8), kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderInt8Negative, assembler) { __ Frame(3); __ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt32))); __ UnboxInt64(1, 0); // The lower bits contain 0xFF, overwrite the upper bits with 1. __ UnboxedWidthExtender(2, 1, kSmallUnboxedInt8); __ Return(2); } ASSEMBLER_TEST_RUN(UnboxedWidthExtenderInt8Negative, test) { // least significant 32 bits set to 1. EXPECT_EQ(kMaxUint32, kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderUint8, assembler) { __ Frame(3); __ LoadConstant(0, Integer::Handle(Integer::New(kMaxUint32))); __ UnboxInt64(1, 0); // The lower bits contain 0xFF, overwrite the upper bits with 0. __ UnboxedWidthExtender(2, 1, kSmallUnboxedUint8); __ Return(2); } ASSEMBLER_TEST_RUN(UnboxedWidthExtenderUint8, test) { EXPECT_EQ(kMaxUint8, kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderInt16Positive, assembler) { __ Frame(3); __ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt16 + 0xFFFF0000))); __ UnboxInt64(1, 0); // The lower bits contain 0x7FFF, overwrite the upper bits with 0. __ UnboxedWidthExtender(2, 1, kSmallUnboxedInt16); __ Return(2); } ASSEMBLER_TEST_RUN(UnboxedWidthExtenderInt16Positive, test) { EXPECT_EQ(static_cast(kMaxInt16), kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderInt16Negative, assembler) { __ Frame(3); __ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt32))); __ UnboxInt64(1, 0); // The lower bits contain 0xFFFF, overwrite the upper bits with 1. __ UnboxedWidthExtender(2, 1, kSmallUnboxedInt16); __ Return(2); } ASSEMBLER_TEST_RUN(UnboxedWidthExtenderInt16Negative, test) { // least significant 32 bits set to 1. EXPECT_EQ(kMaxUint32, kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderUint16, assembler) { __ Frame(3); __ LoadConstant(0, Integer::Handle(Integer::New(kMaxUint32))); __ UnboxInt64(1, 0); // The lower bits contain 0xFFFF, overwrite the upper bits with 0. __ UnboxedWidthExtender(2, 1, kSmallUnboxedUint16); __ Return(2); } ASSEMBLER_TEST_RUN(UnboxedWidthExtenderUint16, test) { EXPECT_EQ(kMaxUint16, kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code())); } #if defined(ARCH_IS_64_BIT) // - UnboxDouble rA, rD // // Unbox the double in FP[rD] into FP[rA]. Assumes FP[rD] is a double. // // - CheckedUnboxDouble rA, rD // // Unboxes FP[rD] into FP[rA] and skips the following instruction unless // FP[rD] is not a double or a Smi. When FP[rD] is a Smi, converts it to a // double. ASSEMBLER_TEST_GENERATE(UnboxDouble, assembler) { __ Frame(2); __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld))); __ UnboxDouble(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(UnboxDouble, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } ASSEMBLER_TEST_GENERATE(CheckedUnboxDouble, assembler) { __ Frame(2); __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld))); __ CheckedUnboxDouble(1, 0); __ LoadConstant(1, Smi::Handle(Smi::New(0))); __ Return(1); } ASSEMBLER_TEST_RUN(CheckedUnboxDouble, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } ASSEMBLER_TEST_GENERATE(WriteIntoDouble, assembler) { __ Frame(3); __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld))); __ UnboxDouble(1, 0); __ LoadConstant(2, Double::Handle(Double::New(0.0, Heap::kOld))); __ WriteIntoDouble(2, 1); // Transplant unboxed value into an existing box. __ Return(2); } ASSEMBLER_TEST_RUN(WriteIntoDouble, test) { const Object& obj = EXECUTE_TEST_CODE_OBJECT(test->code()); EXPECT(obj.IsDouble()); EXPECT_EQ(42.0, Double::Cast(obj).value()); } ASSEMBLER_TEST_GENERATE(CheckedUnboxSmi, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ CheckedUnboxDouble(1, 0); __ LoadConstant(1, Smi::Handle(Smi::New(0))); __ Return(1); } ASSEMBLER_TEST_RUN(CheckedUnboxSmi, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } ASSEMBLER_TEST_GENERATE(CheckedUnboxFail, assembler) { __ Frame(2); __ LoadConstant(0, Bool::True()); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ CheckedUnboxDouble(1, 0); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ Return(1); } ASSEMBLER_TEST_RUN(CheckedUnboxFail, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } // - DAdd, DSub, DMul, DDiv rA, rB, rC // // Arithmetic operations on unboxed doubles. FP[rA] <- FP[rB] op FP[rC]. ASSEMBLER_TEST_GENERATE(DAdd, assembler) { __ Frame(3); __ LoadConstant(0, Double::Handle(Double::New(41.0, Heap::kOld))); __ LoadConstant(1, Double::Handle(Double::New(1.0, Heap::kOld))); __ UnboxDouble(0, 0); __ UnboxDouble(1, 1); __ DAdd(2, 1, 0); __ Return(2); } ASSEMBLER_TEST_RUN(DAdd, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } ASSEMBLER_TEST_GENERATE(DSub, assembler) { __ Frame(3); __ LoadConstant(0, Double::Handle(Double::New(1.0, Heap::kOld))); __ LoadConstant(1, Double::Handle(Double::New(43.0, Heap::kOld))); __ UnboxDouble(0, 0); __ UnboxDouble(1, 1); __ DSub(2, 1, 0); __ Return(2); } ASSEMBLER_TEST_RUN(DSub, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } ASSEMBLER_TEST_GENERATE(DMul, assembler) { __ Frame(3); __ LoadConstant(0, Double::Handle(Double::New(6.0, Heap::kOld))); __ LoadConstant(1, Double::Handle(Double::New(7.0, Heap::kOld))); __ UnboxDouble(0, 0); __ UnboxDouble(1, 1); __ DMul(2, 1, 0); __ Return(2); } ASSEMBLER_TEST_RUN(DMul, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } ASSEMBLER_TEST_GENERATE(DDiv, assembler) { __ Frame(3); __ LoadConstant(0, Double::Handle(Double::New(2.0, Heap::kOld))); __ LoadConstant(1, Double::Handle(Double::New(84.0, Heap::kOld))); __ UnboxDouble(0, 0); __ UnboxDouble(1, 1); __ DDiv(2, 1, 0); __ Return(2); } ASSEMBLER_TEST_RUN(DDiv, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } ASSEMBLER_TEST_GENERATE(DNeg, assembler) { __ Frame(2); __ LoadConstant(0, Double::Handle(Double::New(-42.0, Heap::kOld))); __ UnboxDouble(0, 0); __ DNeg(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(DNeg, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } ASSEMBLER_TEST_GENERATE(DSqrt, assembler) { __ Frame(2); __ LoadConstant(0, Double::Handle(Double::New(36.0, Heap::kOld))); __ UnboxDouble(0, 0); __ DSqrt(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(DSqrt, test) { EXPECT_EQ(6.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } // - SmiToDouble rA, rD // // Convert the Smi in FP[rD] to an unboxed double in FP[rA]. // // - DoubleToSmi rA, rD // // If the unboxed double in FP[rD] can be converted to a Smi in FP[rA], then // this instruction does so, and skips the following instruction. Otherwise, // the following instruction is not skipped. ASSEMBLER_TEST_GENERATE(SmiToDouble, assembler) { __ Frame(2); __ LoadConstant(0, Smi::Handle(Smi::New(42))); __ SmiToDouble(1, 0); __ Return(1); } ASSEMBLER_TEST_RUN(SmiToDouble, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } ASSEMBLER_TEST_GENERATE(DoubleToSmi, assembler) { __ Frame(2); __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ UnboxDouble(0, 0); __ DoubleToSmi(1, 0); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ Return(1); } ASSEMBLER_TEST_RUN(DoubleToSmi, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(DoubleToSmiNearMax, assembler) { const double m = static_cast(Smi::kMaxValue - 1000); __ Frame(2); __ LoadConstant(0, Double::Handle(Double::New(m, Heap::kOld))); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ UnboxDouble(0, 0); __ DoubleToSmi(0, 0); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ Return(1); } ASSEMBLER_TEST_RUN(DoubleToSmiNearMax, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(DoubleToSmiNearMin, assembler) { const double m = static_cast(Smi::kMinValue); __ Frame(2); __ LoadConstant(0, Double::Handle(Double::New(m, Heap::kOld))); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ UnboxDouble(0, 0); __ DoubleToSmi(0, 0); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ Return(1); } ASSEMBLER_TEST_RUN(DoubleToSmiNearMin, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(DoubleToSmiFailPos, assembler) { const double pos_overflow = static_cast(Smi::kMaxValue + 1); __ Frame(2); __ LoadConstant(0, Double::Handle(Double::New(pos_overflow, Heap::kOld))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ UnboxDouble(0, 0); __ DoubleToSmi(1, 0); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ Return(1); } ASSEMBLER_TEST_RUN(DoubleToSmiFailPos, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(DoubleToSmiFailNeg, assembler) { const double neg_overflow = static_cast(Smi::kMinValue - 1000); __ Frame(2); __ LoadConstant(0, Double::Handle(Double::New(neg_overflow, Heap::kOld))); __ LoadConstant(1, Smi::Handle(Smi::New(-1))); __ UnboxDouble(0, 0); __ DoubleToSmi(1, 0); __ LoadConstant(1, Smi::Handle(Smi::New(42))); __ Return(1); } ASSEMBLER_TEST_RUN(DoubleToSmiFailNeg, test) { EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code())); } ASSEMBLER_TEST_GENERATE(DMin, assembler) { __ Frame(3); __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld))); __ LoadConstant(1, Double::Handle(Double::New(500.0, Heap::kOld))); __ UnboxDouble(0, 0); __ UnboxDouble(1, 1); __ DMin(2, 0, 1); __ Return(2); } ASSEMBLER_TEST_RUN(DMin, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } ASSEMBLER_TEST_GENERATE(DMax, assembler) { __ Frame(3); __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld))); __ LoadConstant(1, Double::Handle(Double::New(5.0, Heap::kOld))); __ UnboxDouble(0, 0); __ UnboxDouble(1, 1); __ DMax(2, 0, 1); __ Return(2); } ASSEMBLER_TEST_RUN(DMax, test) { EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code())); } #endif // defined(ARCH_IS_64_BIT) } // namespace compiler } // namespace dart #endif // defined(TARGET_ARCH_DBC)