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