c7cb9beca1
This is a reland offbfa9bf4ec
The arm64 was missing proper codegen for CFI, thus sizes were off. Original change's description: > Reland "[deoptimizer] Change deopt entries into builtins" > > This is a reland of7f58ced72e
> > It fixes the different exit size emitted on x64/Atom CPUs due to > performance tuning in TurboAssembler::Call. Additionally, add > cctests to verify the fixed size exits. > > Original change's description: > > [deoptimizer] Change deopt entries into builtins > > > > While the overall goal of this commit is to change deoptimization > > entries into builtins, there are multiple related things happening: > > > > - Deoptimization entries, formerly stubs (i.e. Code objects generated > > at runtime, guaranteed to be immovable), have been converted into > > builtins. The major restriction is that we now need to preserve the > > kRootRegister, which was formerly used on most architectures to pass > > the deoptimization id. The solution differs based on platform. > > - Renamed DEOPT_ENTRIES_OR_FOR_TESTING code kind to FOR_TESTING. > > - Removed heap/ support for immovable Code generation. > > - Removed the DeserializerData class (no longer needed). > > - arm64: to preserve 4-byte deopt exits, introduced a new optimization > > in which the final jump to the deoptimization entry is generated > > once per Code object, and deopt exits can continue to emit a > > near-call. > > - arm,ia32,x64: change to fixed-size deopt exits. This reduces exit > > sizes by 4/8, 5, and 5 bytes, respectively. > > > > On arm the deopt exit size is reduced from 12 (or 16) bytes to 8 bytes > > by using the same strategy as on arm64 (recalc deopt id from return > > address). Before: > > > > e300a002 movw r10, <id> > > e59fc024 ldr ip, [pc, <entry offset>] > > e12fff3c blx ip > > > > After: > > > > e59acb35 ldr ip, [r10, <entry offset>] > > e12fff3c blx ip > > > > On arm64 the deopt exit size remains 4 bytes (or 8 bytes in same cases > > with CFI). Additionally, up to 4 builtin jumps are emitted per Code > > object (max 32 bytes added overhead per Code object). Before: > > > > 9401cdae bl <entry offset> > > > > After: > > > > # eager deoptimization entry jump. > > f95b1f50 ldr x16, [x26, <eager entry offset>] > > d61f0200 br x16 > > # lazy deoptimization entry jump. > > f95b2b50 ldr x16, [x26, <lazy entry offset>] > > d61f0200 br x16 > > # the deopt exit. > > 97fffffc bl <eager deoptimization entry jump offset> > > > > On ia32 the deopt exit size is reduced from 10 to 5 bytes. Before: > > > > bb00000000 mov ebx,<id> > > e825f5372b call <entry> > > > > After: > > > > e8ea2256ba call <entry> > > > > On x64 the deopt exit size is reduced from 12 to 7 bytes. Before: > > > > 49c7c511000000 REX.W movq r13,<id> > > e8ea2f0700 call <entry> > > > > After: > > > > 41ff9560360000 call [r13+<entry offset>] > > > > Bug: v8:8661,v8:8768 > > Change-Id: I13e30aedc360474dc818fecc528ce87c3bfeed42 > > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2465834 > > Commit-Queue: Jakob Gruber <jgruber@chromium.org> > > Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> > > Reviewed-by: Tobias Tebbi <tebbi@chromium.org> > > Reviewed-by: Ulan Degenbaev <ulan@chromium.org> > > Cr-Commit-Position: refs/heads/master@{#70597} > > Tbr: ulan@chromium.org, tebbi@chromium.org, rmcilroy@chromium.org > Bug: v8:8661,v8:8768,chromium:1140165 > Change-Id: Ibcd5c39c58a70bf2b2ac221aa375fc68d495e144 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2485506 > Reviewed-by: Jakob Gruber <jgruber@chromium.org> > Reviewed-by: Tobias Tebbi <tebbi@chromium.org> > Commit-Queue: Jakob Gruber <jgruber@chromium.org> > Cr-Commit-Position: refs/heads/master@{#70655} Tbr: ulan@chromium.org, tebbi@chromium.org, rmcilroy@chromium.org Bug: v8:8661 Bug: v8:8768 Bug: chromium:1140165 Change-Id: I471cc94fc085e527dc9bfb5a84b96bd907c2333f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2488682 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#70672}
197 lines
6.2 KiB
C++
197 lines
6.2 KiB
C++
// 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 {
|
|
|
|
#define __ tasm.
|
|
|
|
// 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
|
|
|
|
// 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.
|
|
|
|
class TurboAssemblerTest : public TestWithIsolate {};
|
|
|
|
TEST_F(TurboAssemblerTest, TestHardAbort) {
|
|
auto buffer = AllocateAssemblerBuffer();
|
|
TurboAssembler tasm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo,
|
|
buffer->CreateView());
|
|
__ set_root_array_available(false);
|
|
__ set_abort_hard(true);
|
|
|
|
__ CodeEntry();
|
|
|
|
__ Abort(AbortReason::kNoReason);
|
|
|
|
CodeDesc desc;
|
|
tasm.GetCode(isolate(), &desc);
|
|
buffer->MakeExecutable();
|
|
// 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(TurboAssemblerTest, TestCheck) {
|
|
auto buffer = AllocateAssemblerBuffer();
|
|
TurboAssembler tasm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo,
|
|
buffer->CreateView());
|
|
__ set_root_array_available(false);
|
|
__ set_abort_hard(true);
|
|
|
|
__ 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;
|
|
tasm.GetCode(isolate(), &desc);
|
|
buffer->MakeExecutable();
|
|
// 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"));
|
|
}
|
|
|
|
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 TurboAssemblerTestWithParam : public TurboAssemblerTest,
|
|
public ::testing::WithParamInterface<T> {};
|
|
|
|
using TurboAssemblerTestMoveObjectAndSlot =
|
|
TurboAssemblerTestWithParam<MoveObjectAndSlotTestCase>;
|
|
|
|
TEST_P(TurboAssemblerTestMoveObjectAndSlot, MoveObjectAndSlot) {
|
|
const MoveObjectAndSlotTestCase test_case = GetParam();
|
|
TRACED_FOREACH(int32_t, offset, kOffsets) {
|
|
auto buffer = AllocateAssemblerBuffer();
|
|
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
|
|
buffer->CreateView());
|
|
|
|
__ 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(&tasm);
|
|
Register scratch = temps.AcquireX();
|
|
__ Pop(padreg, scratch);
|
|
__ Str(dst_object, MemOperand(scratch));
|
|
__ Str(dst_slot, MemOperand(scratch, kSystemPointerSize));
|
|
|
|
__ Ret();
|
|
|
|
CodeDesc desc;
|
|
tasm.GetCode(nullptr, &desc);
|
|
if (FLAG_print_code) {
|
|
Handle<Code> code =
|
|
Factory::CodeBuilder(isolate(), desc, CodeKind::FOR_TESTING).Build();
|
|
StdoutStream os;
|
|
code->Print(os);
|
|
}
|
|
|
|
buffer->MakeExecutable();
|
|
// 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(TurboAssemblerTest,
|
|
TurboAssemblerTestMoveObjectAndSlot,
|
|
::testing::ValuesIn(kMoveObjectAndSlotTestCases));
|
|
|
|
#undef __
|
|
#undef ERROR_MESSAGE
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|