Commit e73757be authored by Deepti Gandluri's avatar Deepti Gandluri Committed by V8 LUCI CQ

Revert "[rwx][mac] Introduce RwxMemoryWriteScope"

This reverts commit 4d8e1846.

Reason for revert: Blocks V8 roll, crbug.com/1316800

Original change's description:
> [rwx][mac] Introduce RwxMemoryWriteScope
>
> ... as a single bottleneck that encapsulates the semantics and
> implementation of fast per-thread W^X permission switching supported
> by Apple Silicon (arm64 M1).
> On other architectures this class is a no-op.
>
> Bug: v8:12797
> Change-Id: Ica842ff9f843e20b7f61fd7e80591e7a1fd29771
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3586986
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Commit-Queue: Igor Sheludko <ishell@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#79994}

Bug: v8:12797
Change-Id: I81792567839e72b4147d009c0845b0c0de003eb0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3590752
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Deepti Gandluri <gdeepti@chromium.org>
Owners-Override: Deepti Gandluri <gdeepti@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80007}
parent c9617b66
...@@ -1205,9 +1205,6 @@ filegroup( ...@@ -1205,9 +1205,6 @@ filegroup(
"src/common/assert-scope.h", "src/common/assert-scope.h",
"src/common/allow-deprecated.h", "src/common/allow-deprecated.h",
"src/common/checks.h", "src/common/checks.h",
"src/common/code-memory-access-inl.h",
"src/common/code-memory-access.cc",
"src/common/code-memory-access.h",
"src/common/high-allocation-throughput-scope.h", "src/common/high-allocation-throughput-scope.h",
"src/common/message-template.h", "src/common/message-template.h",
"src/common/operation.h", "src/common/operation.h",
......
...@@ -2750,8 +2750,6 @@ v8_header_set("v8_internal_headers") { ...@@ -2750,8 +2750,6 @@ v8_header_set("v8_internal_headers") {
"src/common/allow-deprecated.h", "src/common/allow-deprecated.h",
"src/common/assert-scope.h", "src/common/assert-scope.h",
"src/common/checks.h", "src/common/checks.h",
"src/common/code-memory-access-inl.h",
"src/common/code-memory-access.h",
"src/common/high-allocation-throughput-scope.h", "src/common/high-allocation-throughput-scope.h",
"src/common/message-template.h", "src/common/message-template.h",
"src/common/operation.h", "src/common/operation.h",
...@@ -4165,9 +4163,6 @@ v8_source_set("v8_base_without_compiler") { ...@@ -4165,9 +4163,6 @@ v8_source_set("v8_base_without_compiler") {
"src/codegen/turbo-assembler.cc", "src/codegen/turbo-assembler.cc",
"src/codegen/unoptimized-compilation-info.cc", "src/codegen/unoptimized-compilation-info.cc",
"src/common/assert-scope.cc", "src/common/assert-scope.cc",
"src/common/code-memory-access-inl.h",
"src/common/code-memory-access.cc",
"src/common/code-memory-access.h",
"src/compiler-dispatcher/lazy-compile-dispatcher.cc", "src/compiler-dispatcher/lazy-compile-dispatcher.cc",
"src/compiler-dispatcher/optimizing-compile-dispatcher.cc", "src/compiler-dispatcher/optimizing-compile-dispatcher.cc",
"src/date/date.cc", "src/date/date.cc",
......
// Copyright 2022 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.
#ifndef V8_COMMON_CODE_MEMORY_ACCESS_INL_H_
#define V8_COMMON_CODE_MEMORY_ACCESS_INL_H_
#include "src/common/code-memory-access.h"
#include "src/logging/log.h"
namespace v8 {
namespace internal {
RwxMemoryWriteScope::RwxMemoryWriteScope() { SetWritable(); }
RwxMemoryWriteScope::~RwxMemoryWriteScope() { SetExecutable(); }
#if V8_HAS_PTHREAD_JIT_WRITE_PROTECT
// Ignoring this warning is considered better than relying on
// __builtin_available.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
// static
void RwxMemoryWriteScope::SetWritable() {
if (code_space_write_nesting_level_ == 0) {
pthread_jit_write_protect_np(0);
}
code_space_write_nesting_level_++;
}
// static
void RwxMemoryWriteScope::SetExecutable() {
code_space_write_nesting_level_--;
if (code_space_write_nesting_level_ == 0) {
pthread_jit_write_protect_np(1);
}
}
#pragma clang diagnostic pop
#else // !V8_HAS_PTHREAD_JIT_WRITE_PROTECT
void RwxMemoryWriteScope::SetWritable() {}
void RwxMemoryWriteScope::SetExecutable() {}
#endif // V8_HAS_PTHREAD_JIT_WRITE_PROTECT
} // namespace internal
} // namespace v8
#endif // V8_COMMON_CODE_MEMORY_ACCESS_INL_H_
// Copyright 2022 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/common/code-memory-access.h"
namespace v8 {
namespace internal {
#if V8_HAS_PTHREAD_JIT_WRITE_PROTECT
thread_local int RwxMemoryWriteScope::code_space_write_nesting_level_ = 0;
#endif // V8_HAS_PTHREAD_JIT_WRITE_PROTECT
} // namespace internal
} // namespace v8
// Copyright 2022 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.
#ifndef V8_COMMON_CODE_MEMORY_ACCESS_H_
#define V8_COMMON_CODE_MEMORY_ACCESS_H_
#include "src/base/build_config.h"
namespace v8 {
namespace internal {
class CodePageCollectionMemoryModificationScope;
class CodePageMemoryModificationScope;
class CodeSpaceMemoryModificationScope;
namespace wasm {
class CodeSpaceWriteScope;
}
// This scope is a wrapper for APRR/MAP_JIT machinery on MacOS on ARM64
// ("Apple M1"/Apple Silicon) with respective semantics.
// See pthread_jit_write_protect_np() for details.
// On other platforms the scope is a no-op.
//
// The semantics is the following: the scope switches permissions between
// writable and executable for all the pages allocated with RWX permissions.
// Only current thread is affected. This achieves "real" W^X and it's fast.
// By default it is assumed that the state is executable.
//
// The scope is reentrant and thread safe.
class V8_NODISCARD RwxMemoryWriteScope final {
public:
V8_INLINE explicit RwxMemoryWriteScope();
V8_INLINE virtual ~RwxMemoryWriteScope();
// Disable copy constructor and copy-assignment operator, since this manages
// a resource and implicit copying of the scope can yield surprising errors.
RwxMemoryWriteScope(const RwxMemoryWriteScope&) = delete;
RwxMemoryWriteScope& operator=(const RwxMemoryWriteScope&) = delete;
private:
friend class CodePageCollectionMemoryModificationScope;
friend class CodePageMemoryModificationScope;
friend class CodeSpaceMemoryModificationScope;
friend class wasm::CodeSpaceWriteScope;
// {SetWritable} and {SetExecutable} implicitly enters/exits the scope.
// These methods are exposed only for the purpose of implementing other
// scope classes that affect executable pages permissions.
V8_INLINE static void SetWritable();
V8_INLINE static void SetExecutable();
#if V8_HAS_PTHREAD_JIT_WRITE_PROTECT
// This counter is used for supporting scope reentrance.
static thread_local int code_space_write_nesting_level_;
#endif // V8_HAS_PTHREAD_JIT_WRITE_PROTECT || defined(DEBUG)
};
} // namespace internal
} // namespace v8
#endif // V8_COMMON_CODE_MEMORY_ACCESS_H_
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#include "src/wasm/code-space-access.h" #include "src/wasm/code-space-access.h"
#include "src/common/code-memory-access-inl.h"
#include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-code-manager.h"
#include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-engine.h"
...@@ -37,13 +36,20 @@ CodeSpaceWriteScope::~CodeSpaceWriteScope() { ...@@ -37,13 +36,20 @@ CodeSpaceWriteScope::~CodeSpaceWriteScope() {
#if V8_HAS_PTHREAD_JIT_WRITE_PROTECT #if V8_HAS_PTHREAD_JIT_WRITE_PROTECT
// Ignoring this warning is considered better than relying on
// __builtin_available.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
// static // static
void CodeSpaceWriteScope::SetWritable() { RwxMemoryWriteScope::SetWritable(); } void CodeSpaceWriteScope::SetWritable() {
pthread_jit_write_protect_np(0);
}
// static // static
void CodeSpaceWriteScope::SetExecutable() { void CodeSpaceWriteScope::SetExecutable() {
RwxMemoryWriteScope::SetExecutable(); pthread_jit_write_protect_np(1);
} }
#pragma clang diagnostic pop
// static // static
bool CodeSpaceWriteScope::SwitchingPerNativeModule() { return false; } bool CodeSpaceWriteScope::SwitchingPerNativeModule() { return false; }
......
...@@ -118,25 +118,23 @@ static void InitializeVM() { ...@@ -118,25 +118,23 @@ static void InitializeVM() {
#ifdef USE_SIMULATOR #ifdef USE_SIMULATOR
// Run tests with the simulator. // Run tests with the simulator.
#define SETUP_SIZE(buf_size) \ #define SETUP_SIZE(buf_size) \
Isolate* isolate = CcTest::i_isolate(); \ Isolate* isolate = CcTest::i_isolate(); \
HandleScope scope(isolate); \ HandleScope scope(isolate); \
CHECK_NOT_NULL(isolate); \ CHECK_NOT_NULL(isolate); \
auto owned_buf = \ std::unique_ptr<byte[]> owned_buf{new byte[buf_size]}; \
AllocateAssemblerBuffer(buf_size, nullptr, VirtualMemory::kNoJit); \ MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes, \
MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes, \ ExternalAssemblerBuffer(owned_buf.get(), buf_size)); \
ExternalAssemblerBuffer(owned_buf->start(), buf_size)); \ Decoder<DispatchingDecoderVisitor>* decoder = \
std::optional<AssemblerBufferWriteScope> rw_buffer_scope; \ new Decoder<DispatchingDecoderVisitor>(); \
Decoder<DispatchingDecoderVisitor>* decoder = \ Simulator simulator(decoder); \
new Decoder<DispatchingDecoderVisitor>(); \ std::unique_ptr<PrintDisassembler> pdis; \
Simulator simulator(decoder); \ RegisterDump core; \
std::unique_ptr<PrintDisassembler> pdis; \ HandleScope handle_scope(isolate); \
RegisterDump core; \ Handle<Code> code; \
HandleScope handle_scope(isolate); \ if (i::FLAG_trace_sim) { \
Handle<Code> code; \ pdis.reset(new PrintDisassembler(stdout)); \
if (i::FLAG_trace_sim) { \ decoder->PrependVisitor(pdis.get()); \
pdis.reset(new PrintDisassembler(stdout)); \
decoder->PrependVisitor(pdis.get()); \
} }
// Reset the assembler and simulator, so that instructions can be generated, // Reset the assembler and simulator, so that instructions can be generated,
...@@ -179,7 +177,6 @@ static void InitializeVM() { ...@@ -179,7 +177,6 @@ static void InitializeVM() {
HandleScope scope(isolate); \ HandleScope scope(isolate); \
CHECK_NOT_NULL(isolate); \ CHECK_NOT_NULL(isolate); \
auto owned_buf = AllocateAssemblerBuffer(buf_size); \ auto owned_buf = AllocateAssemblerBuffer(buf_size); \
std::optional<AssemblerBufferWriteScope> rw_buffer_scope; \
MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes, \ MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes, \
owned_buf->CreateView()); \ owned_buf->CreateView()); \
HandleScope handle_scope(isolate); \ HandleScope handle_scope(isolate); \
...@@ -187,7 +184,7 @@ static void InitializeVM() { ...@@ -187,7 +184,7 @@ static void InitializeVM() {
RegisterDump core; RegisterDump core;
#define RESET() \ #define RESET() \
rw_buffer_scope.emplace(*owned_buf); \ owned_buf->MakeWritable(); \
__ Reset(); \ __ Reset(); \
__ CodeEntry(); \ __ CodeEntry(); \
/* Reset the machine state (like simulator.ResetState()). */ \ /* Reset the machine state (like simulator.ResetState()). */ \
...@@ -201,12 +198,10 @@ static void InitializeVM() { ...@@ -201,12 +198,10 @@ static void InitializeVM() {
RESET(); \ RESET(); \
START_AFTER_RESET(); START_AFTER_RESET();
#define RUN() \ #define RUN() \
{ \ { \
/* Reset the scope and thus make the buffer executable. */ \ auto f = GeneratedCode<void>::FromCode(*code); \
rw_buffer_scope.reset(); \ f.Call(); \
auto f = GeneratedCode<void>::FromCode(*code); \
f.Call(); \
} }
#define END() \ #define END() \
...@@ -14885,7 +14880,6 @@ TEST(pool_size) { ...@@ -14885,7 +14880,6 @@ TEST(pool_size) {
// This test does not execute any code. It only tests that the size of the // This test does not execute any code. It only tests that the size of the
// pools is read correctly from the RelocInfo. // pools is read correctly from the RelocInfo.
rw_buffer_scope.emplace(*owned_buf);
Label exit; Label exit;
__ b(&exit); __ b(&exit);
......
...@@ -113,18 +113,19 @@ TEST(TestFlushICacheOfWritable) { ...@@ -113,18 +113,19 @@ TEST(TestFlushICacheOfWritable) {
// Allow calling the function from C++. // Allow calling the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start()); auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
{ CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
AssemblerBufferWriteScope rw_buffer_scope(*buffer); buffer->size(), v8::PageAllocator::kReadWrite));
FloodWithInc(isolate, buffer.get()); FloodWithInc(isolate, buffer.get());
FlushInstructionCache(buffer->start(), buffer->size()); FlushInstructionCache(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_EQ(23 + kNumInstr, f.Call(23)); // Call into generated code.
CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
{ buffer->size(), v8::PageAllocator::kReadWrite));
AssemblerBufferWriteScope rw_buffer_scope(*buffer); FloodWithNop(isolate, buffer.get());
FloodWithNop(isolate, buffer.get()); FlushInstructionCache(buffer->start(), buffer->size());
FlushInstructionCache(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_EQ(23, f.Call(23)); // Call into generated code.
} }
} }
...@@ -183,6 +184,24 @@ TEST(TestFlushICacheOfWritableAndExecutable) { ...@@ -183,6 +184,24 @@ TEST(TestFlushICacheOfWritableAndExecutable) {
Isolate* isolate = CcTest::i_isolate(); Isolate* isolate = CcTest::i_isolate();
HandleScope handles(isolate); HandleScope handles(isolate);
struct V8_NODISCARD EnableWritePermissionsOnMacArm64Scope {
#if defined(V8_OS_DARWIN) && defined(V8_HOST_ARCH_ARM64)
// Ignoring this warning is considered better than relying on
// __builtin_available.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
EnableWritePermissionsOnMacArm64Scope() { pthread_jit_write_protect_np(0); }
~EnableWritePermissionsOnMacArm64Scope() {
pthread_jit_write_protect_np(1);
}
#pragma clang diagnostic pop
#else
EnableWritePermissionsOnMacArm64Scope() {
// Define a constructor to avoid unused variable warnings.
}
#endif
};
for (int i = 0; i < kNumIterations; ++i) { for (int i = 0; i < kNumIterations; ++i) {
auto buffer = AllocateAssemblerBuffer(kBufferSize, nullptr, auto buffer = AllocateAssemblerBuffer(kBufferSize, nullptr,
VirtualMemory::kMapAsJittable); VirtualMemory::kMapAsJittable);
...@@ -190,16 +209,16 @@ TEST(TestFlushICacheOfWritableAndExecutable) { ...@@ -190,16 +209,16 @@ TEST(TestFlushICacheOfWritableAndExecutable) {
// Allow calling the function from C++. // Allow calling the function from C++.
auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start()); auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
buffer->MakeWritableAndExecutable(); CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
buffer->size(), v8::PageAllocator::kReadWriteExecute));
{ {
RwxMemoryWriteScope rw_scope; EnableWritePermissionsOnMacArm64Scope write_scope;
FloodWithInc(isolate, buffer.get()); FloodWithInc(isolate, buffer.get());
FlushInstructionCache(buffer->start(), buffer->size()); FlushInstructionCache(buffer->start(), buffer->size());
} }
CHECK_EQ(23 + kNumInstr, f.Call(23)); // Call into generated code. CHECK_EQ(23 + kNumInstr, f.Call(23)); // Call into generated code.
{ {
RwxMemoryWriteScope rw_scope; EnableWritePermissionsOnMacArm64Scope write_scope;
FloodWithNop(isolate, buffer.get()); FloodWithNop(isolate, buffer.get());
FlushInstructionCache(buffer->start(), buffer->size()); FlushInstructionCache(buffer->start(), buffer->size());
} }
......
...@@ -57,8 +57,6 @@ TEST(EmbeddedObj) { ...@@ -57,8 +57,6 @@ TEST(EmbeddedObj) {
MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes, MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView()); buffer->CreateView());
AssemblerBufferWriteScope rw_scope(*buffer);
Handle<HeapObject> old_array = isolate->factory()->NewFixedArray(2000); Handle<HeapObject> old_array = isolate->factory()->NewFixedArray(2000);
Handle<HeapObject> my_array = isolate->factory()->NewFixedArray(1000); Handle<HeapObject> my_array = isolate->factory()->NewFixedArray(1000);
__ Mov(w4, Immediate(my_array, RelocInfo::COMPRESSED_EMBEDDED_OBJECT)); __ Mov(w4, Immediate(my_array, RelocInfo::COMPRESSED_EMBEDDED_OBJECT));
...@@ -102,8 +100,6 @@ TEST(DeoptExitSizeIsFixed) { ...@@ -102,8 +100,6 @@ TEST(DeoptExitSizeIsFixed) {
MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes, MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
buffer->CreateView()); buffer->CreateView());
AssemblerBufferWriteScope rw_scope(*buffer);
STATIC_ASSERT(static_cast<int>(kFirstDeoptimizeKind) == 0); STATIC_ASSERT(static_cast<int>(kFirstDeoptimizeKind) == 0);
for (int i = 0; i < kDeoptimizeKindCount; i++) { for (int i = 0; i < kDeoptimizeKindCount; i++) {
DeoptimizeKind kind = static_cast<DeoptimizeKind>(i); DeoptimizeKind kind = static_cast<DeoptimizeKind>(i);
......
...@@ -55,6 +55,17 @@ constexpr uint32_t kAvailableBufferSlots = 0; ...@@ -55,6 +55,17 @@ constexpr uint32_t kAvailableBufferSlots = 0;
constexpr uint32_t kBufferSlotStartOffset = 0; constexpr uint32_t kBufferSlotStartOffset = 0;
#endif #endif
void EnsureThreadHasWritePermissions() {
#if defined(V8_OS_DARWIN) && defined(V8_HOST_ARCH_ARM64)
// Ignoring this warning is considered better than relying on
// __builtin_available.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
pthread_jit_write_protect_np(0);
#pragma clang diagnostic pop
#endif
}
Address AllocateJumpTableThunk( Address AllocateJumpTableThunk(
Address jump_target, byte* thunk_slot_buffer, Address jump_target, byte* thunk_slot_buffer,
std::bitset<kAvailableBufferSlots>* used_slots, std::bitset<kAvailableBufferSlots>* used_slots,
...@@ -203,7 +214,7 @@ class JumpTablePatcher : public v8::base::Thread { ...@@ -203,7 +214,7 @@ class JumpTablePatcher : public v8::base::Thread {
void Run() override { void Run() override {
TRACE("Patcher %p is starting ...\n", this); TRACE("Patcher %p is starting ...\n", this);
RwxMemoryWriteScope rwx_write_scope; EnsureThreadHasWritePermissions();
Address slot_address = Address slot_address =
slot_start_ + JumpTableAssembler::JumpSlotIndexToOffset(slot_index_); slot_start_ + JumpTableAssembler::JumpSlotIndexToOffset(slot_index_);
// First, emit code to the two thunks. // First, emit code to the two thunks.
...@@ -254,11 +265,11 @@ TEST(JumpTablePatchingStress) { ...@@ -254,11 +265,11 @@ TEST(JumpTablePatchingStress) {
std::bitset<kAvailableBufferSlots> used_thunk_slots; std::bitset<kAvailableBufferSlots> used_thunk_slots;
buffer->MakeWritableAndExecutable(); buffer->MakeWritableAndExecutable();
RwxMemoryWriteScope rwx_write_scope;
// Iterate through jump-table slots to hammer at different alignments within // Iterate through jump-table slots to hammer at different alignments within
// the jump-table, thereby increasing stress for variable-length ISAs. // the jump-table, thereby increasing stress for variable-length ISAs.
Address slot_start = reinterpret_cast<Address>(buffer->start()); Address slot_start = reinterpret_cast<Address>(buffer->start());
EnsureThreadHasWritePermissions();
for (int slot = 0; slot < kJumpTableSlotCount; ++slot) { for (int slot = 0; slot < kJumpTableSlotCount; ++slot) {
TRACE("Hammering on jump table slot #%d ...\n", slot); TRACE("Hammering on jump table slot #%d ...\n", slot);
uint32_t slot_offset = JumpTableAssembler::JumpSlotIndexToOffset(slot); uint32_t slot_offset = JumpTableAssembler::JumpSlotIndexToOffset(slot);
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "src/codegen/assembler.h" #include "src/codegen/assembler.h"
#include "src/codegen/code-desc.h" #include "src/codegen/code-desc.h"
#include "src/common/code-memory-access-inl.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -28,7 +27,7 @@ class TestingAssemblerBuffer : public AssemblerBuffer { ...@@ -28,7 +27,7 @@ class TestingAssemblerBuffer : public AssemblerBuffer {
MakeWritable(); MakeWritable();
} }
~TestingAssemblerBuffer() override { reservation_.Free(); } ~TestingAssemblerBuffer() { reservation_.Free(); }
byte* start() const override { byte* start() const override {
return reinterpret_cast<byte*>(reservation_.address()); return reinterpret_cast<byte*>(reservation_.address());
...@@ -63,6 +62,7 @@ class TestingAssemblerBuffer : public AssemblerBuffer { ...@@ -63,6 +62,7 @@ class TestingAssemblerBuffer : public AssemblerBuffer {
CHECK(result); CHECK(result);
} }
// TODO(wasm): Only needed for the "test-jump-table-assembler.cc" tests.
void MakeWritableAndExecutable() { void MakeWritableAndExecutable() {
bool result = SetPermissions(GetPlatformPageAllocator(), start(), size(), bool result = SetPermissions(GetPlatformPageAllocator(), start(), size(),
v8::PageAllocator::kReadWriteExecute); v8::PageAllocator::kReadWriteExecute);
...@@ -73,31 +73,6 @@ class TestingAssemblerBuffer : public AssemblerBuffer { ...@@ -73,31 +73,6 @@ class TestingAssemblerBuffer : public AssemblerBuffer {
VirtualMemory reservation_; VirtualMemory reservation_;
}; };
// This scope class is mostly necesasry for arm64 tests running on Apple Silicon
// (M1) which prohibits reconfiguration of page permissions for RWX pages.
// Instead of altering the page permissions one must flip the X-W state by
// calling pthread_jit_write_protect_np() function.
// See RwxMemoryWriteScope for details.
class V8_NODISCARD AssemblerBufferWriteScope final {
public:
explicit AssemblerBufferWriteScope(TestingAssemblerBuffer& buffer)
: buffer_(buffer) {
buffer_.MakeWritable();
}
~AssemblerBufferWriteScope() { buffer_.MakeExecutable(); }
// Disable copy constructor and copy-assignment operator, since this manages
// a resource and implicit copying of the scope can yield surprising errors.
AssemblerBufferWriteScope(const AssemblerBufferWriteScope&) = delete;
AssemblerBufferWriteScope& operator=(const AssemblerBufferWriteScope&) =
delete;
private:
RwxMemoryWriteScope rwx_write_scope_;
TestingAssemblerBuffer& buffer_;
};
static inline std::unique_ptr<TestingAssemblerBuffer> AllocateAssemblerBuffer( static inline std::unique_ptr<TestingAssemblerBuffer> AllocateAssemblerBuffer(
size_t requested = v8::internal::AssemblerBase::kDefaultBufferSize, size_t requested = v8::internal::AssemblerBase::kDefaultBufferSize,
void* address = nullptr, void* address = nullptr,
......
...@@ -37,16 +37,13 @@ TEST_F(TurboAssemblerTest, TestHardAbort) { ...@@ -37,16 +37,13 @@ TEST_F(TurboAssemblerTest, TestHardAbort) {
__ set_root_array_available(false); __ set_root_array_available(false);
__ set_abort_hard(true); __ set_abort_hard(true);
{ __ CodeEntry();
AssemblerBufferWriteScope rw_scope(*buffer);
__ CodeEntry(); __ Abort(AbortReason::kNoReason);
__ Abort(AbortReason::kNoReason);
CodeDesc desc; CodeDesc desc;
tasm.GetCode(isolate(), &desc); tasm.GetCode(isolate(), &desc);
} buffer->MakeExecutable();
// We need an isolate here to execute in the simulator. // We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start()); auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start());
...@@ -60,20 +57,17 @@ TEST_F(TurboAssemblerTest, TestCheck) { ...@@ -60,20 +57,17 @@ TEST_F(TurboAssemblerTest, TestCheck) {
__ set_root_array_available(false); __ set_root_array_available(false);
__ set_abort_hard(true); __ set_abort_hard(true);
{ __ CodeEntry();
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();
// Fail if the first parameter is 17. CodeDesc desc;
__ Mov(w1, Immediate(17)); tasm.GetCode(isolate(), &desc);
__ Cmp(w0, w1); // 1st parameter is in {w0}. buffer->MakeExecutable();
__ Check(Condition::ne, AbortReason::kNoReason);
__ Ret();
CodeDesc desc;
tasm.GetCode(isolate(), &desc);
}
// We need an isolate here to execute in the simulator. // We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start());
...@@ -125,58 +119,54 @@ TEST_P(TurboAssemblerTestMoveObjectAndSlot, MoveObjectAndSlot) { ...@@ -125,58 +119,54 @@ TEST_P(TurboAssemblerTestMoveObjectAndSlot, MoveObjectAndSlot) {
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView()); buffer->CreateView());
{ __ CodeEntry();
AssemblerBufferWriteScope rw_buffer_scope(*buffer); __ Push(x0, padreg);
__ Mov(test_case.object, x1);
__ CodeEntry();
__ Push(x0, padreg); Register src_object = test_case.object;
__ Mov(test_case.object, x1); Register dst_object = test_case.dst_object;
Register dst_slot = test_case.dst_slot;
Register src_object = test_case.object;
Register dst_object = test_case.dst_object; Operand offset_operand(0);
Register dst_slot = test_case.dst_slot; if (test_case.offset_register == no_reg) {
offset_operand = Operand(offset);
Operand offset_operand(0); } else {
if (test_case.offset_register == no_reg) { __ Mov(test_case.offset_register, Operand(offset));
offset_operand = Operand(offset); offset_operand = Operand(test_case.offset_register);
} 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 << ", ";
std::stringstream comment; if (test_case.offset_register == no_reg) {
comment << "-- " << test_case.comment << ": MoveObjectAndSlot(" comment << "#" << offset;
<< dst_object << ", " << dst_slot << ", " << src_object << ", "; } else {
if (test_case.offset_register == no_reg) { comment << test_case.offset_register;
comment << "#" << offset; }
} else { comment << ") --";
comment << test_case.offset_register; __ RecordComment(comment.str().c_str());
} __ MoveObjectAndSlot(dst_object, dst_slot, src_object, offset_operand);
comment << ") --"; __ RecordComment("--");
__ RecordComment(comment.str().c_str());
__ MoveObjectAndSlot(dst_object, dst_slot, src_object, offset_operand); // The `result` pointer was saved on the stack.
__ RecordComment("--"); UseScratchRegisterScope temps(&tasm);
Register scratch = temps.AcquireX();
// The `result` pointer was saved on the stack. __ Pop(padreg, scratch);
UseScratchRegisterScope temps(&tasm); __ Str(dst_object, MemOperand(scratch));
Register scratch = temps.AcquireX(); __ Str(dst_slot, MemOperand(scratch, kSystemPointerSize));
__ Pop(padreg, scratch);
__ Str(dst_object, MemOperand(scratch)); __ Ret();
__ Str(dst_slot, MemOperand(scratch, kSystemPointerSize));
CodeDesc desc;
__ Ret(); tasm.GetCode(nullptr, &desc);
if (FLAG_print_code) {
CodeDesc desc; Handle<Code> code =
tasm.GetCode(nullptr, &desc); Factory::CodeBuilder(isolate(), desc, CodeKind::FOR_TESTING).Build();
if (FLAG_print_code) { StdoutStream os;
Handle<Code> code = code->Print(os);
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. // We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void, byte**, byte*>::FromBuffer(isolate(), auto f = GeneratedCode<void, byte**, byte*>::FromBuffer(isolate(),
buffer->start()); buffer->start());
......
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