diff options
Diffstat (limited to 'deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc')
-rw-r--r-- | deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc | 325 |
1 files changed, 225 insertions, 100 deletions
diff --git a/deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc b/deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc index 021b0423f3..3bbbc49096 100644 --- a/deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc +++ b/deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc @@ -1,129 +1,254 @@ -// Copyright 2019 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <stdlib.h> - -#include "src/codegen/arm64/assembler-arm64-inl.h" -#include "src/codegen/macro-assembler-inl.h" -#include "src/deoptimizer/deoptimizer.h" -#include "src/heap/factory.h" -#include "src/objects/objects-inl.h" +// Copyright 2018 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/arm64/macro-assembler-arm64-inl.h" +#include "src/codegen/macro-assembler.h" +#include "src/execution/simulator.h" #include "src/utils/ostreams.h" #include "test/common/assembler-tester.h" #include "test/unittests/test-utils.h" +#include "testing/gtest-support.h" namespace v8 { namespace internal { -namespace test_macro_assembler_arm64 { -using MacroAssemblerArm64Test = TestWithIsolate; +#define __ masm. -using F0 = int(); +// If we are running on android and the output is not redirected (i.e. ends up +// in the android log) then we cannot find the error message in the output. This +// macro just returns the empty string in that case. +#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) +#define ERROR_MESSAGE(msg) "" +#else +#define ERROR_MESSAGE(msg) msg +#endif -#define __ masm. +// Test the x64 assembler by compiling some simple functions into +// a buffer and executing them. These tests do not initialize the +// V8 library, create a context, or use any V8 objects. -TEST_F(MacroAssemblerArm64Test, EmbeddedObj) { -#ifdef V8_COMPRESS_POINTERS - Isolate* isolate = i_isolate(); - HandleScope handles(isolate); +class MacroAssemblerTest : public TestWithIsolate {}; +TEST_F(MacroAssemblerTest, TestHardAbort) { auto buffer = AllocateAssemblerBuffer(); - MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes, + MacroAssembler masm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo, buffer->CreateView()); + __ set_root_array_available(false); + __ set_abort_hard(true); - AssemblerBufferWriteScope rw_scope(*buffer); - - Handle<HeapObject> old_array = isolate->factory()->NewFixedArray(2000); - Handle<HeapObject> my_array = isolate->factory()->NewFixedArray(1000); - __ Mov(w4, Immediate(my_array, RelocInfo::COMPRESSED_EMBEDDED_OBJECT)); - __ Mov(x5, old_array); - __ ret(x5); - - CodeDesc desc; - masm.GetCode(isolate, &desc); - Handle<Code> code = - Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build(); -#ifdef DEBUG - StdoutStream os; - code->Print(os); -#endif + { + AssemblerBufferWriteScope rw_scope(*buffer); - // Collect garbage to ensure reloc info can be walked by the heap. - CollectAllGarbage(); - CollectAllGarbage(); - CollectAllGarbage(); - - PtrComprCageBase cage_base(isolate); - - // Test the user-facing reloc interface. - const int mode_mask = RelocInfo::EmbeddedObjectModeMask(); - for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { - RelocInfo::Mode mode = it.rinfo()->rmode(); - if (RelocInfo::IsCompressedEmbeddedObject(mode)) { - CHECK_EQ(*my_array, it.rinfo()->target_object(cage_base)); - } else { - CHECK(RelocInfo::IsFullEmbeddedObject(mode)); - CHECK_EQ(*old_array, it.rinfo()->target_object(cage_base)); - } + __ CodeEntry(); + + __ Abort(AbortReason::kNoReason); + + CodeDesc desc; + masm.GetCode(isolate(), &desc); } -#endif // V8_COMPRESS_POINTERS + // We need an isolate here to execute in the simulator. + auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start()); + + ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, ERROR_MESSAGE("abort: no reason")); } -TEST_F(MacroAssemblerArm64Test, DeoptExitSizeIsFixed) { - Isolate* isolate = i_isolate(); - HandleScope handles(isolate); +TEST_F(MacroAssemblerTest, TestCheck) { auto buffer = AllocateAssemblerBuffer(); - MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes, + MacroAssembler masm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo, buffer->CreateView()); + __ set_root_array_available(false); + __ set_abort_hard(true); + + { + AssemblerBufferWriteScope rw_scope(*buffer); + + __ CodeEntry(); + + // Fail if the first parameter is 17. + __ Mov(w1, Immediate(17)); + __ Cmp(w0, w1); // 1st parameter is in {w0}. + __ Check(Condition::ne, AbortReason::kNoReason); + __ Ret(); + + CodeDesc desc; + masm.GetCode(isolate(), &desc); + } + // We need an isolate here to execute in the simulator. + auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); + + f.Call(0); + f.Call(18); + ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, ERROR_MESSAGE("abort: no reason")); +} - AssemblerBufferWriteScope rw_scope(*buffer); - - static_assert(static_cast<int>(kFirstDeoptimizeKind) == 0); - for (int i = 0; i < kDeoptimizeKindCount; i++) { - DeoptimizeKind kind = static_cast<DeoptimizeKind>(i); - Label before_exit; - Builtin target = Deoptimizer::GetDeoptimizationEntry(kind); - // Mirroring logic in code-generator.cc. - if (kind == DeoptimizeKind::kLazy) { - // CFI emits an extra instruction here. - masm.BindExceptionHandler(&before_exit); - } else { - masm.bind(&before_exit); +TEST_F(MacroAssemblerTest, CompareAndBranch) { + const int kTestCases[] = {-42, 0, 42}; + static_assert(Condition::eq == 0); + static_assert(Condition::le == 13); + TRACED_FORRANGE(int, cc, 0, 13) { // All conds except al and nv + Condition cond = static_cast<Condition>(cc); + TRACED_FOREACH(int, imm, kTestCases) { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(isolate(), AssemblerOptions{}, + CodeObjectRequired::kNo, buffer->CreateView()); + __ set_root_array_available(false); + __ set_abort_hard(true); + + { + AssemblerBufferWriteScope rw_scope(*buffer); + + __ CodeEntry(); + + Label start, lab; + __ Bind(&start); + __ CompareAndBranch(x0, Immediate(imm), cond, &lab); + if (imm == 0 && ((cond == eq) || (cond == ne) || (cond == hi) || + (cond == ls))) { // One instruction generated + ASSERT_EQ(kInstrSize, __ SizeOfCodeGeneratedSince(&start)); + } else { // Two instructions generated + ASSERT_EQ(static_cast<uint8_t>(2 * kInstrSize), + __ SizeOfCodeGeneratedSince(&start)); + } + __ Cmp(x0, Immediate(imm)); + __ Check(NegateCondition(cond), + AbortReason::kNoReason); // cond must not hold + __ Ret(); + __ Bind(&lab); // Branch leads here + __ Cmp(x0, Immediate(imm)); + __ Check(cond, AbortReason::kNoReason); // cond must hold + __ Ret(); + + CodeDesc desc; + masm.GetCode(isolate(), &desc); + } + // We need an isolate here to execute in the simulator. + auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); + + TRACED_FOREACH(int, n, kTestCases) { f.Call(n); } } - masm.CallForDeoptimization(target, 42, &before_exit, kind, &before_exit, - &before_exit); - CHECK_EQ(masm.SizeOfCodeGeneratedSince(&before_exit), - kind == DeoptimizeKind::kLazy ? Deoptimizer::kLazyDeoptExitSize - : Deoptimizer::kEagerDeoptExitSize); } } +struct MoveObjectAndSlotTestCase { + const char* comment; + Register dst_object; + Register dst_slot; + Register object; + Register offset_register = no_reg; +}; + +const MoveObjectAndSlotTestCase kMoveObjectAndSlotTestCases[] = { + {"no overlap", x0, x1, x2}, + {"no overlap", x0, x1, x2, x3}, + + {"object == dst_object", x2, x1, x2}, + {"object == dst_object", x2, x1, x2, x3}, + + {"object == dst_slot", x1, x2, x2}, + {"object == dst_slot", x1, x2, x2, x3}, + + {"offset == dst_object", x0, x1, x2, x0}, + + {"offset == dst_object && object == dst_slot", x0, x1, x1, x0}, + + {"offset == dst_slot", x0, x1, x2, x1}, + + {"offset == dst_slot && object == dst_object", x0, x1, x0, x1}}; + +// Make sure we include offsets that cannot be encoded in an add instruction. +const int kOffsets[] = {0, 42, kMaxRegularHeapObjectSize, 0x101001}; + +template <typename T> +class MacroAssemblerTestWithParam : public MacroAssemblerTest, + public ::testing::WithParamInterface<T> {}; + +using MacroAssemblerTestMoveObjectAndSlot = + MacroAssemblerTestWithParam<MoveObjectAndSlotTestCase>; + +TEST_P(MacroAssemblerTestMoveObjectAndSlot, MoveObjectAndSlot) { + const MoveObjectAndSlotTestCase test_case = GetParam(); + TRACED_FOREACH(int32_t, offset, kOffsets) { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); + + { + AssemblerBufferWriteScope rw_buffer_scope(*buffer); + + __ CodeEntry(); + __ Push(x0, padreg); + __ Mov(test_case.object, x1); + + Register src_object = test_case.object; + Register dst_object = test_case.dst_object; + Register dst_slot = test_case.dst_slot; + + Operand offset_operand(0); + if (test_case.offset_register == no_reg) { + offset_operand = Operand(offset); + } else { + __ Mov(test_case.offset_register, Operand(offset)); + offset_operand = Operand(test_case.offset_register); + } + + std::stringstream comment; + comment << "-- " << test_case.comment << ": MoveObjectAndSlot(" + << dst_object << ", " << dst_slot << ", " << src_object << ", "; + if (test_case.offset_register == no_reg) { + comment << "#" << offset; + } else { + comment << test_case.offset_register; + } + comment << ") --"; + __ RecordComment(comment.str().c_str()); + __ MoveObjectAndSlot(dst_object, dst_slot, src_object, offset_operand); + __ RecordComment("--"); + + // The `result` pointer was saved on the stack. + UseScratchRegisterScope temps(&masm); + Register scratch = temps.AcquireX(); + __ Pop(padreg, scratch); + __ Str(dst_object, MemOperand(scratch)); + __ Str(dst_slot, MemOperand(scratch, kSystemPointerSize)); + + __ Ret(); + + CodeDesc desc; + masm.GetCode(nullptr, &desc); + if (v8_flags.print_code) { + Handle<Code> code = + Factory::CodeBuilder(isolate(), desc, CodeKind::FOR_TESTING) + .Build(); + StdoutStream os; + code->Print(os); + } + } + + // We need an isolate here to execute in the simulator. + auto f = GeneratedCode<void, byte**, byte*>::FromBuffer(isolate(), + buffer->start()); + + byte* object = new byte[offset]; + byte* result[] = {nullptr, nullptr}; + + f.Call(result, object); + + // The first element must be the address of the object, and the second the + // slot addressed by `offset`. + EXPECT_EQ(result[0], &object[0]); + EXPECT_EQ(result[1], &object[offset]); + + delete[] object; + } +} + +INSTANTIATE_TEST_SUITE_P(MacroAssemblerTest, + MacroAssemblerTestMoveObjectAndSlot, + ::testing::ValuesIn(kMoveObjectAndSlotTestCases)); + #undef __ +#undef ERROR_MESSAGE -} // namespace test_macro_assembler_arm64 } // namespace internal } // namespace v8 |