1 // Copyright 2019 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 #ifndef V8_EXECUTION_THREAD_LOCAL_TOP_H_ 6 #define V8_EXECUTION_THREAD_LOCAL_TOP_H_ 7 8 #include "src/common/globals.h" 9 #include "src/execution/thread-id.h" 10 #include "src/objects/contexts.h" 11 #include "src/utils/utils.h" 12 13 #ifdef V8_ENABLE_CONSERVATIVE_STACK_SCANNING 14 #include "src/heap/base/stack.h" 15 #endif 16 17 namespace v8 { 18 19 class TryCatch; 20 21 namespace internal { 22 23 class ExternalCallbackScope; 24 class Isolate; 25 class PromiseOnStack; 26 class Simulator; 27 28 class ThreadLocalTop { 29 public: 30 // TODO(all): This is not particularly beautiful. We should probably 31 // refactor this to really consist of just Addresses and 32-bit 32 // integer fields. 33 #ifdef V8_ENABLE_CONSERVATIVE_STACK_SCANNING 34 static constexpr uint32_t kSizeInBytes = 25 * kSystemPointerSize; 35 #else 36 static constexpr uint32_t kSizeInBytes = 24 * kSystemPointerSize; 37 #endif 38 39 // Does early low-level initialization that does not depend on the 40 // isolate being present. 41 ThreadLocalTop() = default; 42 43 // Initialize the thread data. 44 void Initialize(Isolate*); 45 46 // The top C++ try catch handler or nullptr if none are registered. 47 // 48 // This field is not guaranteed to hold an address that can be 49 // used for comparison with addresses into the JS stack. If such 50 // an address is needed, use try_catch_handler_address. 51 v8::TryCatch* try_catch_handler_ = nullptr; 52 53 // Get the address of the top C++ try catch handler or nullptr if 54 // none are registered. 55 // 56 // This method always returns an address that can be compared to 57 // pointers into the JavaScript stack. When running on actual 58 // hardware, try_catch_handler_address and TryCatchHandler return 59 // the same pointer. When running on a simulator with a separate JS 60 // stack, try_catch_handler_address returns a JS stack address that 61 // corresponds to the place on the JS stack where the C++ handler 62 // would have been if the stack were not separate. try_catch_handler_address()63 Address try_catch_handler_address() { 64 return reinterpret_cast<Address>( 65 v8::TryCatch::JSStackComparableAddress(try_catch_handler_)); 66 } 67 68 // Call depth represents nested v8 api calls. Instead of storing the nesting 69 // level as an integer, we store the stack height of the last API entry. This 70 // additional information is used when we decide whether to trigger a debug 71 // break at a function entry. 72 template <typename Scope> IncrementCallDepth(Scope * stack_allocated_scope)73 void IncrementCallDepth(Scope* stack_allocated_scope) { 74 stack_allocated_scope->previous_stack_height_ = last_api_entry_; 75 #if defined(USE_SIMULATOR) || defined(V8_USE_ADDRESS_SANITIZER) 76 StoreCurrentStackPosition(); 77 #else 78 last_api_entry_ = reinterpret_cast<i::Address>(stack_allocated_scope); 79 #endif 80 } 81 82 #if defined(USE_SIMULATOR) || defined(V8_USE_ADDRESS_SANITIZER) 83 void StoreCurrentStackPosition(); 84 #endif 85 86 template <typename Scope> DecrementCallDepth(Scope * stack_allocated_scope)87 void DecrementCallDepth(Scope* stack_allocated_scope) { 88 last_api_entry_ = stack_allocated_scope->previous_stack_height_; 89 } 90 CallDepthIsZero()91 bool CallDepthIsZero() const { return last_api_entry_ == kNullAddress; } 92 93 void Free(); 94 95 Isolate* isolate_ = nullptr; 96 // The context where the current execution method is created and for variable 97 // lookups. 98 // TODO(3770): This field is read/written from generated code, so it would 99 // be cleaner to make it an "Address raw_context_", and construct a Context 100 // object in the getter. Same for {pending_handler_context_} below. In the 101 // meantime, assert that the memory layout is the same. 102 STATIC_ASSERT(sizeof(Context) == kSystemPointerSize); 103 Context context_; 104 ThreadId thread_id_ = ThreadId::Invalid(); 105 Object pending_exception_; 106 107 // Communication channel between Isolate::FindHandler and the CEntry. 108 Context pending_handler_context_; 109 Address pending_handler_entrypoint_ = kNullAddress; 110 Address pending_handler_constant_pool_ = kNullAddress; 111 Address pending_handler_fp_ = kNullAddress; 112 Address pending_handler_sp_ = kNullAddress; 113 114 Address last_api_entry_ = kNullAddress; 115 116 // Communication channel between Isolate::Throw and message consumers. 117 Object pending_message_obj_; 118 bool rethrowing_message_ = false; 119 120 // Use a separate value for scheduled exceptions to preserve the 121 // invariants that hold about pending_exception. We may want to 122 // unify them later. 123 bool external_caught_exception_ = false; 124 Object scheduled_exception_; 125 126 // Stack. 127 // The frame pointer of the top c entry frame. 128 Address c_entry_fp_ = kNullAddress; 129 // Try-blocks are chained through the stack. 130 Address handler_ = kNullAddress; 131 // C function that was called at c entry. 132 Address c_function_ = kNullAddress; 133 134 // Throwing an exception may cause a Promise rejection. For this purpose 135 // we keep track of a stack of nested promises and the corresponding 136 // try-catch handlers. 137 PromiseOnStack* promise_on_stack_ = nullptr; 138 139 // Simulator field is always present to get predictable layout. 140 Simulator* simulator_ = nullptr; 141 142 // The stack pointer of the bottom JS entry frame. 143 Address js_entry_sp_ = kNullAddress; 144 // The external callback we're currently in. 145 ExternalCallbackScope* external_callback_scope_ = nullptr; 146 StateTag current_vm_state_ = EXTERNAL; 147 148 // Call back function to report unsafe JS accesses. 149 v8::FailedAccessCheckCallback failed_access_check_callback_ = nullptr; 150 151 // Address of the thread-local "thread in wasm" flag. 152 Address thread_in_wasm_flag_address_ = kNullAddress; 153 154 #ifdef V8_ENABLE_CONSERVATIVE_STACK_SCANNING 155 ::heap::base::Stack stack_ = ::heap::base::Stack(nullptr); 156 #endif 157 }; 158 159 } // namespace internal 160 } // namespace v8 161 162 #endif // V8_EXECUTION_THREAD_LOCAL_TOP_H_ 163