• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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