Commit 1a1f4e1e authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[test] Refactor AllocateAssemblerBuffer

Refactor the AllocateAssemblerBuffer helper for the new Assembler API.
This is the only non-mechanical part, all other callsites that create
Assembler instances can be trivially changed to the new API. This will
be done in a separate CL.

R=mstarzinger@chromium.org

Bug: v8:8689, v8:8562
Change-Id: I6c150748eeea778d9b70f41fd66fbb1221035a1b
Reviewed-on: https://chromium-review.googlesource.com/c/1415490
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58881}
parent 119c083e
......@@ -171,18 +171,19 @@ static void InitializeVM() {
#else // ifdef USE_SIMULATOR.
// Run the test on real hardware or models.
#define SETUP_SIZE(buf_size) \
Isolate* isolate = CcTest::i_isolate(); \
HandleScope scope(isolate); \
CHECK_NOT_NULL(isolate); \
size_t allocated; \
byte* buf = AllocateAssemblerBuffer(&allocated, buf_size); \
MacroAssembler masm(isolate, buf, static_cast<int>(allocated), \
v8::internal::CodeObjectRequired::kYes); \
#define SETUP_SIZE(buf_size) \
Isolate* isolate = CcTest::i_isolate(); \
HandleScope scope(isolate); \
CHECK_NOT_NULL(isolate); \
auto owned_buf = AllocateAssemblerBuffer(buf_size); \
MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes, \
owned_buf->CreateView()); \
uint8_t* buf = owned_buf->start(); \
USE(buf); \
RegisterDump core;
#define RESET() \
MakeAssemblerBufferWritable(buf, allocated); \
owned_buf->MakeWritable(); \
__ Reset(); \
/* Reset the machine state (like simulator.ResetState()). */ \
__ Msr(NZCV, xzr); \
......@@ -195,12 +196,11 @@ static void InitializeVM() {
RESET(); \
START_AFTER_RESET();
#define RUN() \
MakeAssemblerBufferExecutable(buf, allocated); \
{ \
void (*test_function)(void); \
memcpy(&test_function, &buf, sizeof(buf)); \
test_function(); \
#define RUN() \
owned_buf->MakeExecutable(); \
{ \
auto* test_function = bit_cast<void (*)()>(buf); \
test_function(); \
}
#define END() \
......@@ -209,7 +209,7 @@ static void InitializeVM() {
__ Ret(); \
__ GetCode(masm.isolate(), nullptr);
#define TEARDOWN() FreeAssemblerBuffer(buf, allocated);
#define TEARDOWN()
#endif // ifdef USE_SIMULATOR.
......
This diff is collapsed.
......@@ -21,9 +21,8 @@ static constexpr int kNumInstr = 100;
static constexpr int kNumIterations = 5;
static constexpr int kBufferSize = 8 * KB;
static void FloodWithInc(Isolate* isolate, byte* buffer, size_t allocated) {
MacroAssembler masm(isolate, buffer, static_cast<int>(allocated),
CodeObjectRequired::kYes);
static void FloodWithInc(Isolate* isolate, TestingAssemblerBuffer* buffer) {
MacroAssembler masm(isolate, CodeObjectRequired::kYes, buffer->CreateView());
#if V8_TARGET_ARCH_IA32
__ mov(eax, Operand(esp, kPointerSize));
for (int i = 0; i < kNumInstr; ++i) {
......@@ -69,9 +68,8 @@ static void FloodWithInc(Isolate* isolate, byte* buffer, size_t allocated) {
masm.GetCode(isolate, &desc);
}
static void FloodWithNop(Isolate* isolate, byte* buffer, size_t allocated) {
MacroAssembler masm(isolate, buffer, static_cast<int>(allocated),
CodeObjectRequired::kYes);
static void FloodWithNop(Isolate* isolate, TestingAssemblerBuffer* buffer) {
MacroAssembler masm(isolate, CodeObjectRequired::kYes, buffer->CreateView());
#if V8_TARGET_ARCH_IA32
__ mov(eax, Operand(esp, kPointerSize));
#elif V8_TARGET_ARCH_X64
......@@ -96,30 +94,27 @@ static void FloodWithNop(Isolate* isolate, byte* buffer, size_t allocated) {
TEST(TestFlushICacheOfWritable) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
for (int i = 0; i < kNumIterations; ++i) {
byte* buffer = AllocateAssemblerBuffer(&allocated, kBufferSize);
auto buffer = AllocateAssemblerBuffer(kBufferSize);
// Allow calling the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer);
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadWrite));
FloodWithInc(isolate, buffer, allocated);
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadExecute));
auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
buffer->size(), v8::PageAllocator::kReadWrite));
FloodWithInc(isolate, buffer.get());
Assembler::FlushICache(buffer->start(), buffer->size());
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
buffer->size(), v8::PageAllocator::kReadExecute));
CHECK_EQ(23 + kNumInstr, f.Call(23)); // Call into generated code.
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadWrite));
FloodWithNop(isolate, buffer, allocated);
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadExecute));
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
buffer->size(), v8::PageAllocator::kReadWrite));
FloodWithNop(isolate, buffer.get());
Assembler::FlushICache(buffer->start(), buffer->size());
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
buffer->size(), v8::PageAllocator::kReadExecute));
CHECK_EQ(23, f.Call(23)); // Call into generated code.
CHECK(FreePages(GetPlatformPageAllocator(), buffer, allocated));
}
}
......@@ -144,30 +139,27 @@ TEST(TestFlushICacheOfWritable) {
CONDITIONAL_TEST(TestFlushICacheOfExecutable) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
for (int i = 0; i < kNumIterations; ++i) {
byte* buffer = AllocateAssemblerBuffer(&allocated, kBufferSize);
auto buffer = AllocateAssemblerBuffer(kBufferSize);
// Allow calling the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer);
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadWrite));
FloodWithInc(isolate, buffer, allocated);
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadExecute));
Assembler::FlushICache(buffer, allocated);
auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
buffer->size(), v8::PageAllocator::kReadWrite));
FloodWithInc(isolate, buffer.get());
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
buffer->size(), v8::PageAllocator::kReadExecute));
Assembler::FlushICache(buffer->start(), buffer->size());
CHECK_EQ(23 + kNumInstr, f.Call(23)); // Call into generated code.
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadWrite));
FloodWithNop(isolate, buffer, allocated);
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadExecute));
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
buffer->size(), v8::PageAllocator::kReadWrite));
FloodWithNop(isolate, buffer.get());
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
buffer->size(), v8::PageAllocator::kReadExecute));
Assembler::FlushICache(buffer->start(), buffer->size());
CHECK_EQ(23, f.Call(23)); // Call into generated code.
CHECK(FreePages(GetPlatformPageAllocator(), buffer, allocated));
}
}
......@@ -178,24 +170,21 @@ CONDITIONAL_TEST(TestFlushICacheOfExecutable) {
TEST(TestFlushICacheOfWritableAndExecutable) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
for (int i = 0; i < kNumIterations; ++i) {
byte* buffer = AllocateAssemblerBuffer(&allocated, kBufferSize);
auto buffer = AllocateAssemblerBuffer(kBufferSize);
// Allow calling the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer);
auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadWriteExecute));
FloodWithInc(isolate, buffer, allocated);
Assembler::FlushICache(buffer, allocated);
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
buffer->size(), v8::PageAllocator::kReadWriteExecute));
FloodWithInc(isolate, buffer.get());
Assembler::FlushICache(buffer->start(), buffer->size());
CHECK_EQ(23 + kNumInstr, f.Call(23)); // Call into generated code.
FloodWithNop(isolate, buffer, allocated);
Assembler::FlushICache(buffer, allocated);
FloodWithNop(isolate, buffer.get());
Assembler::FlushICache(buffer->start(), buffer->size());
CHECK_EQ(23, f.Call(23)); // Call into generated code.
CHECK(FreePages(GetPlatformPageAllocator(), buffer, allocated));
}
}
......
......@@ -50,10 +50,9 @@ TEST(LoadAndStoreWithRepresentation) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer();
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler; // Create a pointer for the __ macro.
__ sub(sp, sp, Operand(1 * kPointerSize));
......@@ -140,10 +139,9 @@ TEST(ExtractLane) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer();
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler; // Create a pointer for the __ macro.
typedef struct {
......@@ -280,10 +278,9 @@ TEST(ReplaceLane) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer();
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler; // Create a pointer for the __ macro.
typedef struct {
......
......@@ -101,10 +101,9 @@ static void TestMoveSmi(MacroAssembler* masm, Label* exit, int id, Smi value) {
TEST(SmiMove) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer();
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler; // Create a pointer for the __ macro.
EntryCode(masm);
Label exit;
......@@ -129,9 +128,9 @@ TEST(SmiMove) {
CodeDesc desc;
masm->GetCode(isolate, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// Call the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer);
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
int result = f.Call();
CHECK_EQ(0, result);
}
......@@ -186,11 +185,9 @@ void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) {
TEST(SmiCompare) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer =
AllocateAssemblerBuffer(&allocated, 2 * Assembler::kMinimalBufferSize);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer(2 * Assembler::kMinimalBufferSize);
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler;
EntryCode(masm);
......@@ -223,9 +220,9 @@ TEST(SmiCompare) {
CodeDesc desc;
masm->GetCode(isolate, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// Call the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer);
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
int result = f.Call();
CHECK_EQ(0, result);
}
......@@ -233,10 +230,9 @@ TEST(SmiCompare) {
TEST(SmiTag) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer();
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler;
EntryCode(masm);
......@@ -322,9 +318,9 @@ TEST(SmiTag) {
CodeDesc desc;
masm->GetCode(isolate, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// Call the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer);
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
int result = f.Call();
CHECK_EQ(0, result);
}
......@@ -332,10 +328,9 @@ TEST(SmiTag) {
TEST(SmiCheck) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer();
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler;
EntryCode(masm);
......@@ -398,9 +393,9 @@ TEST(SmiCheck) {
CodeDesc desc;
masm->GetCode(isolate, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// Call the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer);
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
int result = f.Call();
CHECK_EQ(0, result);
}
......@@ -431,10 +426,9 @@ void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) {
TEST(SmiIndex) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer();
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler;
EntryCode(masm);
......@@ -453,9 +447,9 @@ TEST(SmiIndex) {
CodeDesc desc;
masm->GetCode(isolate, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// Call the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer);
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
int result = f.Call();
CHECK_EQ(0, result);
}
......@@ -466,10 +460,9 @@ TEST(OperandOffset) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer();
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler;
Label exit;
......@@ -807,9 +800,9 @@ TEST(OperandOffset) {
CodeDesc desc;
masm->GetCode(isolate, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// Call the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer);
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
int result = f.Call();
CHECK_EQ(0, result);
}
......@@ -818,10 +811,9 @@ TEST(OperandOffset) {
TEST(LoadAndStoreWithRepresentation) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer();
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler; // Create a pointer for the __ macro.
EntryCode(masm);
......@@ -969,9 +961,9 @@ TEST(LoadAndStoreWithRepresentation) {
CodeDesc desc;
masm->GetCode(isolate, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// Call the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer);
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
int result = f.Call();
CHECK_EQ(0, result);
}
......@@ -1101,10 +1093,9 @@ void TestFloat64x2Neg(MacroAssembler* masm, Label* exit, double x, double y) {
TEST(SIMDMacros) {
Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate);
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
MacroAssembler assembler(isolate, buffer, static_cast<int>(allocated),
v8::internal::CodeObjectRequired::kYes);
auto buffer = AllocateAssemblerBuffer();
MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView());
MacroAssembler* masm = &assembler;
EntryCode(masm);
......@@ -1123,9 +1114,9 @@ TEST(SIMDMacros) {
CodeDesc desc;
masm->GetCode(isolate, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// Call the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer);
auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
int result = f.Call();
CHECK_EQ(0, result);
}
......
......@@ -45,9 +45,10 @@ constexpr uint32_t kBufferSlotStartOffset =
constexpr uint32_t kAvailableBufferSlots = 0;
#endif
Address GenerateJumpTableThunk(Address jump_target, byte* thunk_slot_buffer,
std::bitset<kAvailableBufferSlots>* used_slots) {
size_t allocated;
Address GenerateJumpTableThunk(
Address jump_target, byte* thunk_slot_buffer,
std::bitset<kAvailableBufferSlots>* used_slots,
std::vector<std::unique_ptr<TestingAssemblerBuffer>>* thunk_buffers) {
#if V8_TARGET_ARCH_ARM64
// To guarantee that the branch range lies within the near-call range,
// generate the thunk in the same (kMaxWasmCodeMemory-sized) buffer as the
......@@ -71,15 +72,17 @@ Address GenerateJumpTableThunk(Address jump_target, byte* thunk_slot_buffer,
DCHECK(TurboAssembler::IsNearCallOffset(
(reinterpret_cast<byte*>(jump_target) - buffer) / kInstrSize));
allocated = AssemblerBase::kMinimalBufferSize;
#else
USE(thunk_slot_buffer);
USE(used_slots);
byte* buffer = AllocateAssemblerBuffer(
&allocated, AssemblerBase::kMinimalBufferSize, GetRandomMmapAddr());
thunk_buffers->emplace_back(AllocateAssemblerBuffer(
AssemblerBase::kMinimalBufferSize, GetRandomMmapAddr()));
byte* buffer = thunk_buffers->back()->start();
#endif
MacroAssembler masm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
MacroAssembler masm(
nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
ExternalAssemblerBuffer(buffer, AssemblerBase::kMinimalBufferSize));
Label exit;
Register scratch = kReturnRegister0;
......@@ -114,7 +117,6 @@ Address GenerateJumpTableThunk(Address jump_target, byte* thunk_slot_buffer,
CodeDesc desc;
masm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
return reinterpret_cast<Address>(buffer);
}
......@@ -180,7 +182,6 @@ class JumpTablePatcher : public v8::base::Thread {
TEST(JumpTablePatchingStress) {
constexpr int kNumberOfRunnerThreads = 5;
size_t allocated;
#if V8_TARGET_ARCH_ARM64
// We need the branches (from GenerateJumpTableThunk) to be within near-call
// range of the jump table slots. The address hint to AllocateAssemblerBuffer
......@@ -191,30 +192,34 @@ TEST(JumpTablePatchingStress) {
// TODO(wasm): Currently {kMaxWasmCodeMemory} limits code sufficiently, so
// that the jump table only supports {near_call} distances.
STATIC_ASSERT(kMaxWasmCodeMemory >= kJumpTableSize);
byte* buffer = AllocateAssemblerBuffer(&allocated, kMaxWasmCodeMemory);
byte* thunk_slot_buffer = buffer + kBufferSlotStartOffset;
auto buffer = AllocateAssemblerBuffer(kMaxWasmCodeMemory);
byte* thunk_slot_buffer = buffer->start() + kBufferSlotStartOffset;
#else
byte* buffer = AllocateAssemblerBuffer(&allocated, kJumpTableSize);
auto buffer = AllocateAssemblerBuffer(kJumpTableSize);
byte* thunk_slot_buffer = nullptr;
#endif
std::bitset<kAvailableBufferSlots> used_thunk_slots;
MakeAssemblerBufferWritableAndExecutable(buffer, allocated);
buffer->MakeWritableAndExecutable();
// Iterate through jump-table slots to hammer at different alignments within
// the jump-table, thereby increasing stress for variable-length ISAs.
Address slot_start = reinterpret_cast<Address>(buffer);
Address slot_start = reinterpret_cast<Address>(buffer->start());
for (int slot = 0; slot < kJumpTableSlotCount; ++slot) {
TRACE("Hammering on jump table slot #%d ...\n", slot);
uint32_t slot_offset = JumpTableAssembler::SlotIndexToOffset(slot);
Address thunk1 = GenerateJumpTableThunk(
slot_start + slot_offset, thunk_slot_buffer, &used_thunk_slots);
Address thunk2 = GenerateJumpTableThunk(
slot_start + slot_offset, thunk_slot_buffer, &used_thunk_slots);
std::vector<std::unique_ptr<TestingAssemblerBuffer>> thunk_buffers;
Address thunk1 =
GenerateJumpTableThunk(slot_start + slot_offset, thunk_slot_buffer,
&used_thunk_slots, &thunk_buffers);
Address thunk2 =
GenerateJumpTableThunk(slot_start + slot_offset, thunk_slot_buffer,
&used_thunk_slots, &thunk_buffers);
TRACE(" generated thunk1: " V8PRIxPTR_FMT "\n", thunk1);
TRACE(" generated thunk2: " V8PRIxPTR_FMT "\n", thunk2);
JumpTableAssembler::PatchJumpTableSlot(slot_start, slot, thunk1,
WasmCode::kFlushICache);
for (auto& buf : thunk_buffers) buf->MakeExecutable();
// Start multiple runner threads and a patcher thread that hammer on the
// same jump-table slot concurrently.
std::list<JumpTableRunner> runners;
......
......@@ -10,50 +10,70 @@
namespace v8 {
namespace internal {
static inline uint8_t* AllocateAssemblerBuffer(
size_t* allocated,
size_t requested = v8::internal::AssemblerBase::kMinimalBufferSize,
void* address = nullptr) {
size_t page_size = v8::internal::AllocatePageSize();
size_t alloc_size = RoundUp(requested, page_size);
void* result = AllocatePages(GetPlatformPageAllocator(), address, alloc_size,
page_size, v8::PageAllocator::kReadWrite);
CHECK(result);
*allocated = alloc_size;
return static_cast<uint8_t*>(result);
}
class TestingAssemblerBuffer : public AssemblerBuffer {
public:
TestingAssemblerBuffer(size_t requested, void* address) {
size_t page_size = v8::internal::AllocatePageSize();
size_t alloc_size = RoundUp(requested, page_size);
CHECK_GE(kMaxInt, alloc_size);
size_ = static_cast<int>(alloc_size);
buffer_ = static_cast<byte*>(AllocatePages(GetPlatformPageAllocator(),
address, alloc_size, page_size,
v8::PageAllocator::kReadWrite));
CHECK_NOT_NULL(buffer_);
}
static inline void FreeAssemblerBuffer(uint8_t* buffer, size_t size) {
CHECK(FreePages(GetPlatformPageAllocator(), buffer, size));
}
~TestingAssemblerBuffer() {
CHECK(FreePages(GetPlatformPageAllocator(), buffer_, size_));
}
static inline void MakeAssemblerBufferExecutable(uint8_t* buffer,
size_t allocated) {
// Flush the instruction cache as part of making the buffer executable.
// Note: we do this before setting permissions to ReadExecute because on
// some older ARM kernels there is a bug which causes an access error on
// cache flush instructions to trigger access error on non-writable memory.
// See https://bugs.chromium.org/p/v8/issues/detail?id=8157
Assembler::FlushICache(buffer, allocated);
bool result = SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadExecute);
CHECK(result);
}
byte* start() const override { return buffer_; }
static inline void MakeAssemblerBufferWritable(uint8_t* buffer,
size_t allocated) {
bool result = SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadWrite);
CHECK(result);
}
int size() const override { return size_; }
std::unique_ptr<AssemblerBuffer> Grow(int new_size) override {
FATAL("Cannot grow TestingAssemblerBuffer");
}
std::unique_ptr<AssemblerBuffer> CreateView() const {
return ExternalAssemblerBuffer(buffer_, size_);
}
// TODO(wasm): Only needed for the "test-jump-table-assembler.cc" tests.
static inline void MakeAssemblerBufferWritableAndExecutable(uint8_t* buffer,
size_t allocated) {
bool result = SetPermissions(GetPlatformPageAllocator(), buffer, allocated,
v8::PageAllocator::kReadWriteExecute);
CHECK(result);
void MakeExecutable() {
// Flush the instruction cache as part of making the buffer executable.
// Note: we do this before setting permissions to ReadExecute because on
// some older ARM kernels there is a bug which causes an access error on
// cache flush instructions to trigger access error on non-writable memory.
// See https://bugs.chromium.org/p/v8/issues/detail?id=8157
Assembler::FlushICache(buffer_, size_);
bool result = SetPermissions(GetPlatformPageAllocator(), buffer_, size_,
v8::PageAllocator::kReadExecute);
CHECK(result);
}
void MakeWritable() {
bool result = SetPermissions(GetPlatformPageAllocator(), buffer_, size_,
v8::PageAllocator::kReadWrite);
CHECK(result);
}
// TODO(wasm): Only needed for the "test-jump-table-assembler.cc" tests.
void MakeWritableAndExecutable() {
bool result = SetPermissions(GetPlatformPageAllocator(), buffer_, size_,
v8::PageAllocator::kReadWriteExecute);
CHECK(result);
}
private:
byte* buffer_;
int size_;
};
static inline std::unique_ptr<TestingAssemblerBuffer> AllocateAssemblerBuffer(
size_t requested = v8::internal::AssemblerBase::kMinimalBufferSize,
void* address = nullptr) {
return base::make_unique<TestingAssemblerBuffer>(requested, address);
}
} // namespace internal
......
......@@ -30,28 +30,26 @@ namespace internal {
class TurboAssemblerTest : public TestWithIsolate {};
TEST_F(TurboAssemblerTest, TestHardAbort) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
__ Abort(AbortReason::kNoReason);
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer);
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start());
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, ERROR_MESSAGE("abort: no reason"));
}
TEST_F(TurboAssemblerTest, TestCheck) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
// Fail if the first parameter is 17.
......@@ -62,9 +60,9 @@ TEST_F(TurboAssemblerTest, TestCheck) {
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer);
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start());
f.Call(0);
f.Call(18);
......
......@@ -30,28 +30,26 @@ namespace internal {
class TurboAssemblerTest : public TestWithIsolate {};
TEST_F(TurboAssemblerTest, TestHardAbort) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
__ Abort(AbortReason::kNoReason);
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer);
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start());
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, ERROR_MESSAGE("abort: no reason"));
}
TEST_F(TurboAssemblerTest, TestCheck) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
// Fail if the first parameter is 17.
......@@ -62,9 +60,9 @@ TEST_F(TurboAssemblerTest, TestCheck) {
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer);
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start());
f.Call(0);
f.Call(18);
......
......@@ -17,27 +17,25 @@ namespace internal {
// V8 library, create a context, or use any V8 objects.
TEST(TurboAssemblerTest, TestHardAbort) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
__ Abort(AbortReason::kNoReason);
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
auto f = GeneratedCode<void>::FromBuffer(nullptr, buffer);
buffer->MakeExecutable();
auto f = GeneratedCode<void>::FromBuffer(nullptr, buffer->start());
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason");
}
TEST(TurboAssemblerTest, TestCheck) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
// Fail if the first parameter is 17.
......@@ -48,8 +46,8 @@ TEST(TurboAssemblerTest, TestCheck) {
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
auto f = GeneratedCode<void, int>::FromBuffer(nullptr, buffer);
buffer->MakeExecutable();
auto f = GeneratedCode<void, int>::FromBuffer(nullptr, buffer->start());
f.Call(0);
f.Call(18);
......
......@@ -21,28 +21,26 @@ namespace internal {
class TurboAssemblerTest : public TestWithIsolate {};
TEST_F(TurboAssemblerTest, TestHardAbort) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
__ Abort(AbortReason::kNoReason);
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer);
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start());
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason");
}
TEST_F(TurboAssemblerTest, TestCheck) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
// Fail if the first parameter (in {a0}) is 17.
......@@ -51,9 +49,9 @@ TEST_F(TurboAssemblerTest, TestCheck) {
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer);
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start());
f.Call(0);
f.Call(18);
......
......@@ -21,28 +21,26 @@ namespace internal {
class TurboAssemblerTest : public TestWithIsolate {};
TEST_F(TurboAssemblerTest, TestHardAbort) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
__ Abort(AbortReason::kNoReason);
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer);
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start());
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason");
}
TEST_F(TurboAssemblerTest, TestCheck) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
// Fail if the first parameter (in {a0}) is 17.
......@@ -51,9 +49,9 @@ TEST_F(TurboAssemblerTest, TestCheck) {
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer);
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start());
f.Call(0);
f.Call(18);
......
......@@ -21,10 +21,9 @@ namespace internal {
class TurboAssemblerTest : public TestWithIsolate {};
TEST_F(TurboAssemblerTest, TestHardAbort) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
// Called from C
__ function_descriptor();
......@@ -34,7 +33,7 @@ TEST_F(TurboAssemblerTest, TestHardAbort) {
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer);
......@@ -42,10 +41,9 @@ TEST_F(TurboAssemblerTest, TestHardAbort) {
}
TEST_F(TurboAssemblerTest, TestCheck) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
// Called from C
__ function_descriptor();
......@@ -59,7 +57,7 @@ TEST_F(TurboAssemblerTest, TestCheck) {
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer);
......
......@@ -21,17 +21,16 @@ namespace internal {
class TurboAssemblerTest : public TestWithIsolate {};
TEST_F(TurboAssemblerTest, TestHardAbort) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
__ Abort(AbortReason::kNoReason);
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer);
......@@ -39,10 +38,9 @@ TEST_F(TurboAssemblerTest, TestHardAbort) {
}
TEST_F(TurboAssemblerTest, TestCheck) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
// Fail if the first parameter is 17.
......@@ -53,7 +51,7 @@ TEST_F(TurboAssemblerTest, TestCheck) {
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
buffer->MakeExecutable();
// We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer);
......
......@@ -17,27 +17,25 @@ namespace internal {
// V8 library, create a context, or use any V8 objects.
TEST(TurboAssemblerTest, TestHardAbort) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
__ Abort(AbortReason::kNoReason);
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
auto f = GeneratedCode<void>::FromBuffer(nullptr, buffer);
buffer->MakeExecutable();
auto f = GeneratedCode<void>::FromBuffer(nullptr, buffer->start());
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason");
}
TEST(TurboAssemblerTest, TestCheck) {
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
static_cast<int>(allocated), CodeObjectRequired::kNo);
auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView());
__ set_abort_hard(true);
// Fail if the first parameter is 17.
......@@ -48,8 +46,8 @@ TEST(TurboAssemblerTest, TestCheck) {
CodeDesc desc;
tasm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(buffer, allocated);
auto f = GeneratedCode<void, int>::FromBuffer(nullptr, buffer);
buffer->MakeExecutable();
auto f = GeneratedCode<void, int>::FromBuffer(nullptr, buffer->start());
f.Call(0);
f.Call(18);
......
......@@ -94,10 +94,8 @@ class TrapHandlerTest : public TestWithIsolate,
// The allocated memory buffer ends with a guard page.
crash_address_ = memory_buffer_.end() - 32;
// Allocate a buffer for the generated code.
size_t buffer_size;
byte* buffer = AllocateAssemblerBuffer(
&buffer_size, AssemblerBase::kMinimalBufferSize, GetRandomMmapAddr());
buffer_ = Vector<byte>(buffer, buffer_size);
buffer_ = AllocateAssemblerBuffer(AssemblerBase::kMinimalBufferSize,
GetRandomMmapAddr());
InitRecoveryCode();
......@@ -122,8 +120,8 @@ class TrapHandlerTest : public TestWithIsolate,
void TearDown() override {
// We should always have left wasm code.
CHECK(!GetThreadInWasmFlag());
FreeAssemblerBuffer(buffer_.start(), buffer_.size());
FreeAssemblerBuffer(recovery_buffer_.start(), recovery_buffer_.size());
buffer_.reset();
recovery_buffer_.reset();
// Free the allocated backing store.
i_isolate()->wasm_engine()->memory_tracker()->FreeBackingStoreForTesting(
......@@ -148,20 +146,17 @@ class TrapHandlerTest : public TestWithIsolate,
void InitRecoveryCode() {
// Create a code snippet where we can jump to to recover from a signal or
// exception. The code snippet only consists of a return statement.
size_t buffer_size;
byte* buffer = AllocateAssemblerBuffer(
&buffer_size, AssemblerBase::kMinimalBufferSize, GetRandomMmapAddr());
recovery_buffer_ = Vector<byte>(buffer, buffer_size);
recovery_buffer_ = AllocateAssemblerBuffer(
AssemblerBase::kMinimalBufferSize, GetRandomMmapAddr());
MacroAssembler masm(nullptr, AssemblerOptions{}, recovery_buffer_.start(),
recovery_buffer_.length(), CodeObjectRequired::kNo);
MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
recovery_buffer_->CreateView());
int recovery_offset = __ pc_offset();
__ Pop(scratch);
__ Ret();
CodeDesc desc;
masm.GetCode(nullptr, &desc);
MakeAssemblerBufferExecutable(recovery_buffer_.start(),
recovery_buffer_.size());
recovery_buffer_->MakeExecutable();
g_recovery_address =
reinterpret_cast<Address>(desc.buffer + recovery_offset);
}
......@@ -233,21 +228,22 @@ class TrapHandlerTest : public TestWithIsolate,
}
// Execute the code in buffer.
void ExecuteBuffer(Vector<byte> buffer) {
MakeAssemblerBufferExecutable(buffer.start(), buffer.size());
GeneratedCode<void>::FromAddress(i_isolate(),
reinterpret_cast<Address>(buffer.start()))
void ExecuteBuffer() {
buffer_->MakeExecutable();
GeneratedCode<void>::FromAddress(
i_isolate(), reinterpret_cast<Address>(buffer_->start()))
.Call();
CHECK(!g_test_handler_executed);
}
// Execute the code in buffer. We expect a crash which we recover from in the
// test handler.
void ExecuteExpectCrash(Vector<byte> buffer, bool check_wasm_flag = true) {
void ExecuteExpectCrash(TestingAssemblerBuffer* buffer,
bool check_wasm_flag = true) {
CHECK(!g_test_handler_executed);
MakeAssemblerBufferExecutable(buffer.start(), buffer.size());
buffer->MakeExecutable();
GeneratedCode<void>::FromAddress(i_isolate(),
reinterpret_cast<Address>(buffer.start()))
reinterpret_cast<Address>(buffer->start()))
.Call();
CHECK(g_test_handler_executed);
g_test_handler_executed = false;
......@@ -266,16 +262,16 @@ class TrapHandlerTest : public TestWithIsolate,
void* accessible_memory_start_;
// Buffer for generated code.
Vector<byte> buffer_;
std::unique_ptr<TestingAssemblerBuffer> buffer_;
// Buffer for the code for the landing pad of the test handler.
Vector<byte> recovery_buffer_;
std::unique_ptr<TestingAssemblerBuffer> recovery_buffer_;
};
TEST_P(TrapHandlerTest, TestTrapHandlerRecovery) {
// Test that the wasm trap handler can recover a memory access violation in
// wasm code (we fake the wasm code and the access violation).
MacroAssembler masm(nullptr, AssemblerOptions{}, buffer_.start(),
buffer_.length(), CodeObjectRequired::kNo);
MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer_->CreateView());
__ Push(scratch);
GenerateSetThreadInWasmFlagCode(&masm);
__ Move(scratch, crash_address_, RelocInfo::NONE);
......@@ -294,14 +290,14 @@ TEST_P(TrapHandlerTest, TestTrapHandlerRecovery) {
trap_handler::RegisterHandlerData(reinterpret_cast<Address>(desc.buffer),
desc.instr_size, 1, &protected_instruction);
ExecuteBuffer(buffer_);
ExecuteBuffer();
}
TEST_P(TrapHandlerTest, TestReleaseHandlerData) {
// Test that after we release handler data in the trap handler, it cannot
// recover from the specific memory access violation anymore.
MacroAssembler masm(nullptr, AssemblerOptions{}, buffer_.start(),
buffer_.length(), CodeObjectRequired::kNo);
MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer_->CreateView());
__ Push(scratch);
GenerateSetThreadInWasmFlagCode(&masm);
__ Move(scratch, crash_address_, RelocInfo::NONE);
......@@ -322,20 +318,20 @@ TEST_P(TrapHandlerTest, TestReleaseHandlerData) {
SetupTrapHandler(GetParam());
ExecuteBuffer(buffer_);
ExecuteBuffer();
// Deregister from the trap handler. The trap handler should not do the
// recovery now.
trap_handler::ReleaseHandlerData(handler_id);
ExecuteExpectCrash(buffer_);
ExecuteExpectCrash(buffer_.get());
}
TEST_P(TrapHandlerTest, TestNoThreadInWasmFlag) {
// That that if the thread_in_wasm flag is not set, the trap handler does not
// get active.
MacroAssembler masm(nullptr, AssemblerOptions{}, buffer_.start(),
buffer_.length(), CodeObjectRequired::kNo);
MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer_->CreateView());
__ Push(scratch);
__ Move(scratch, crash_address_, RelocInfo::NONE);
int crash_offset = __ pc_offset();
......@@ -353,14 +349,14 @@ TEST_P(TrapHandlerTest, TestNoThreadInWasmFlag) {
SetupTrapHandler(GetParam());
ExecuteExpectCrash(buffer_);
ExecuteExpectCrash(buffer_.get());
}
TEST_P(TrapHandlerTest, TestCrashInWasmNoProtectedInstruction) {
// Test that if the crash in wasm happened at an instruction which is not
// protected, then the trap handler does not handle it.
MacroAssembler masm(nullptr, AssemblerOptions{}, buffer_.start(),
buffer_.length(), CodeObjectRequired::kNo);
MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer_->CreateView());
__ Push(scratch);
GenerateSetThreadInWasmFlagCode(&masm);
int no_crash_offset = __ pc_offset();
......@@ -381,14 +377,14 @@ TEST_P(TrapHandlerTest, TestCrashInWasmNoProtectedInstruction) {
SetupTrapHandler(GetParam());
ExecuteExpectCrash(buffer_);
ExecuteExpectCrash(buffer_.get());
}
TEST_P(TrapHandlerTest, TestCrashInWasmWrongCrashType) {
// Test that if the crash reason is not a memory access violation, then the
// wasm trap handler does not handle it.
MacroAssembler masm(nullptr, AssemblerOptions{}, buffer_.start(),
buffer_.length(), CodeObjectRequired::kNo);
MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer_->CreateView());
__ Push(scratch);
GenerateSetThreadInWasmFlagCode(&masm);
__ xorq(scratch, scratch);
......@@ -417,7 +413,7 @@ TEST_P(TrapHandlerTest, TestCrashInWasmWrongCrashType) {
#else
bool check_wasm_flag = true;
#endif
ExecuteExpectCrash(buffer_, check_wasm_flag);
ExecuteExpectCrash(buffer_.get(), check_wasm_flag);
if (!check_wasm_flag) {
// Reset the thread-in-wasm flag because it was probably not reset in the
// trap handler.
......@@ -427,14 +423,14 @@ TEST_P(TrapHandlerTest, TestCrashInWasmWrongCrashType) {
class CodeRunner : public v8::base::Thread {
public:
CodeRunner(TrapHandlerTest* test, Vector<byte> buffer)
CodeRunner(TrapHandlerTest* test, TestingAssemblerBuffer* buffer)
: Thread(Options("CodeRunner")), test_(test), buffer_(buffer) {}
void Run() override { test_->ExecuteExpectCrash(buffer_); }
private:
TrapHandlerTest* test_;
Vector<byte> buffer_;
TestingAssemblerBuffer* buffer_;
};
TEST_P(TrapHandlerTest, TestCrashInOtherThread) {
......@@ -442,8 +438,8 @@ TEST_P(TrapHandlerTest, TestCrashInOtherThread) {
// The current thread enters wasm land (sets the thread_in_wasm flag)
// A second thread crashes at a protected instruction without having the flag
// set.
MacroAssembler masm(nullptr, AssemblerOptions{}, buffer_.start(),
buffer_.length(), CodeObjectRequired::kNo);
MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer_->CreateView());
__ Push(scratch);
__ Move(scratch, crash_address_, RelocInfo::NONE);
int crash_offset = __ pc_offset();
......@@ -461,7 +457,7 @@ TEST_P(TrapHandlerTest, TestCrashInOtherThread) {
SetupTrapHandler(GetParam());
CodeRunner runner(this, buffer_);
CodeRunner runner(this, buffer_.get());
CHECK(!GetThreadInWasmFlag());
// Set the thread-in-wasm flag manually in this thread.
*trap_handler::GetThreadInWasmThreadLocalAddress() = 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment