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