1 // Copyright 2021 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/wasm/code-space-access.h"
6 
7 #include "src/wasm/wasm-code-manager.h"
8 #include "src/wasm/wasm-engine.h"
9 
10 namespace v8 {
11 namespace internal {
12 namespace wasm {
13 
14 thread_local NativeModule* CodeSpaceWriteScope::current_native_module_ =
15     nullptr;
16 
17 // TODO(jkummerow): Background threads could permanently stay in
18 // writable mode; only the main thread has to switch back and forth.
CodeSpaceWriteScope(NativeModule* native_module)19 CodeSpaceWriteScope::CodeSpaceWriteScope(NativeModule* native_module)
20     : previous_native_module_(current_native_module_) {
21   DCHECK_NOT_NULL(native_module);
22   if (previous_native_module_ == native_module) return;
23   current_native_module_ = native_module;
24   if (previous_native_module_ == nullptr || SwitchingPerNativeModule()) {
25     SetWritable();
26   }
27 }
28 
~CodeSpaceWriteScope()29 CodeSpaceWriteScope::~CodeSpaceWriteScope() {
30   if (previous_native_module_ == current_native_module_) return;
31   if (previous_native_module_ == nullptr || SwitchingPerNativeModule()) {
32     SetExecutable();
33   }
34   current_native_module_ = previous_native_module_;
35 }
36 
37 #if V8_HAS_PTHREAD_JIT_WRITE_PROTECT
38 
39 // Ignoring this warning is considered better than relying on
40 // __builtin_available.
41 #pragma clang diagnostic push
42 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
43 // static
SetWritable()44 void CodeSpaceWriteScope::SetWritable() {
45   pthread_jit_write_protect_np(0);
46 }
47 
48 // static
SetExecutable()49 void CodeSpaceWriteScope::SetExecutable() {
50   pthread_jit_write_protect_np(1);
51 }
52 #pragma clang diagnostic pop
53 
54 // static
SwitchingPerNativeModule()55 bool CodeSpaceWriteScope::SwitchingPerNativeModule() { return false; }
56 
57 #else  // !V8_HAS_PTHREAD_JIT_WRITE_PROTECT
58 
59 // static
SetWritable()60 void CodeSpaceWriteScope::SetWritable() {
61   auto* code_manager = GetWasmCodeManager();
62   if (code_manager->MemoryProtectionKeysEnabled()) {
63     code_manager->SetThreadWritable(true);
64   } else if (FLAG_wasm_write_protect_code_memory) {
65     current_native_module_->AddWriter();
66   }
67 }
68 
69 // static
SetExecutable()70 void CodeSpaceWriteScope::SetExecutable() {
71   auto* code_manager = GetWasmCodeManager();
72   if (code_manager->MemoryProtectionKeysEnabled()) {
73     DCHECK(FLAG_wasm_memory_protection_keys);
74     code_manager->SetThreadWritable(false);
75   } else if (FLAG_wasm_write_protect_code_memory) {
76     current_native_module_->RemoveWriter();
77   }
78 }
79 
80 // static
SwitchingPerNativeModule()81 bool CodeSpaceWriteScope::SwitchingPerNativeModule() {
82   return !GetWasmCodeManager()->MemoryProtectionKeysEnabled() &&
83          FLAG_wasm_write_protect_code_memory;
84 }
85 
86 #endif  // !V8_HAS_PTHREAD_JIT_WRITE_PROTECT
87 
88 }  // namespace wasm
89 }  // namespace internal
90 }  // namespace v8
91