summaryrefslogtreecommitdiff
path: root/deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc
diff options
context:
space:
mode:
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.cc325
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