[isolate] Move ThreadLocalTop into IsolateData.

This refactors the ThreadLocalTop into separate header and
implementation files, and moves it from the Isolate to the
IsolateData (with some tweaks to make the layout of the class
predictable). This has the advantage that all external references
referring to addresses in the ThreadLocalTop (like js_entry_sp,
c_function, c_entry_fp, etc.) need only a single memory access
to reach them. For example the CallApiCallback can now use

```
mov %rbp,0x8e40(%r13)
mov %rsi,0x8de0(%r13)
mov %rbx,0x8e50(%r13)
```

to setup the information about context, frame pointer, and C++
function pointer in the ThreadLocalTop instead of the previously
generated code

```
mov 0x2e28(%r13),%r10
mov %rbp,(%r10)
mov 0x2e38(%r13),%r10
mov %rsi,(%r10)
mov 0x2e30(%r13),%r10
mov %rbx,(%r10)
```

which always had to load the scratch register %r10 with the actual
address first. This has interesting performance impact. On the
test case mentioned in v8:8820 (with the `d8` patch applied), the
performance goes from

```
console.timeEnd: fnMono, 2290.012000
console.timeEnd: fnCall, 2604.954000
```

to

```
console.timeEnd: fnMono, 2062.743000
console.timeEnd: fnCall, 2477.556000
```

which is a pretty solid **10%** improvement for the monomorphic API
accessor case, and a **5%** improvement for calling into the API
accessor instead.

But there might as well be other places besides API callback calls
that will benefit from this change, which I haven't tested explicitly.

Although this change is supposed to be as minimal as possible without
any functional effects, some changes were necessary/logical. Eventually
we should reconsider changing the layout and the types for the fields
in the ThreadLocalTop to be more consistent with the other IsolateData
entities. But this can be done in separate follow-up CLs, as this will
be quite a bit of churn on the code base, depending on how we do that
exactly, and is orthogonal to this optimization.

Bug: v8:8820, v8:8848, chromium:913553
Change-Id: I4732c8e60231f0312eb7767358c48bae0338220d
Cq-Include-Trybots: luci.chromium.try:linux-blink-rel
Reviewed-on: https://chromium-review.googlesource.com/c/1474230
Reviewed-by: Yang Guo <yangguo@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59624}
This commit is contained in:
Benedikt Meurer 2019-02-14 21:13:15 +01:00 committed by Commit Bot
parent 08fa19f3dd
commit e17e46fde6
8 changed files with 229 additions and 175 deletions

View File

@ -2561,6 +2561,8 @@ v8_source_set("v8_base") {
"src/third_party/utf8-decoder/utf8-decoder.h",
"src/thread-id.cc",
"src/thread-id.h",
"src/thread-local-top.cc",
"src/thread-local-top.h",
"src/tracing/trace-event.cc",
"src/tracing/trace-event.h",
"src/tracing/traced-value.cc",

View File

@ -315,7 +315,7 @@ class CallDepthScope {
handle_scope_implementer->DecrementCallDepth();
bool clear_exception =
handle_scope_implementer->CallDepthIsZero() &&
isolate_->thread_local_top()->try_catch_handler() == nullptr;
isolate_->thread_local_top()->try_catch_handler_ == nullptr;
isolate_->OptionalRescheduleException(clear_exception);
}

View File

@ -9,6 +9,7 @@
#include "src/constants-arch.h"
#include "src/external-reference-table.h"
#include "src/roots.h"
#include "src/thread-local-top.h"
#include "src/utils.h"
namespace v8 {
@ -91,6 +92,9 @@ class IsolateData final {
return (address - start) < sizeof(*this);
}
ThreadLocalTop& thread_local_top() { return thread_local_top_; }
ThreadLocalTop const& thread_local_top() const { return thread_local_top_; }
RootsTable& roots() { return roots_; }
const RootsTable& roots() const { return roots_; }
@ -110,6 +114,7 @@ class IsolateData final {
V(kExternalMemoryAtLastMarkCompactOffset, kInt64Size) \
V(kRootsTableOffset, RootsTable::kEntriesCount* kSystemPointerSize) \
V(kExternalReferenceTableOffset, ExternalReferenceTable::kSizeInBytes) \
V(kThreadLocalTopOffset, ThreadLocalTop::kSizeInBytes) \
V(kBuiltinEntryTableOffset, Builtins::builtin_count* kSystemPointerSize) \
V(kBuiltinsTableOffset, Builtins::builtin_count* kSystemPointerSize) \
V(kVirtualCallTargetRegisterOffset, kSystemPointerSize) \
@ -145,6 +150,8 @@ class IsolateData final {
ExternalReferenceTable external_reference_table_;
ThreadLocalTop thread_local_top_;
// The entry points for all builtins. This corresponds to
// Code::InstructionStart() for each Code object in the builtins table below.
// The entry table is in IsolateData for easy access through kRootRegister.
@ -190,11 +197,14 @@ class IsolateData final {
// actual V8 code.
void IsolateData::AssertPredictableLayout() {
STATIC_ASSERT(std::is_standard_layout<RootsTable>::value);
STATIC_ASSERT(std::is_standard_layout<ThreadLocalTop>::value);
STATIC_ASSERT(std::is_standard_layout<ExternalReferenceTable>::value);
STATIC_ASSERT(std::is_standard_layout<IsolateData>::value);
STATIC_ASSERT(offsetof(IsolateData, roots_) == kRootsTableOffset);
STATIC_ASSERT(offsetof(IsolateData, external_reference_table_) ==
kExternalReferenceTableOffset);
STATIC_ASSERT(offsetof(IsolateData, thread_local_top_) ==
kThreadLocalTopOffset);
STATIC_ASSERT(offsetof(IsolateData, builtins_) == kBuiltinsTableOffset);
STATIC_ASSERT(offsetof(IsolateData, virtual_call_target_register_) ==
kVirtualCallTargetRegisterOffset);

View File

@ -22,7 +22,7 @@ IsolateAllocationMode Isolate::isolate_allocation_mode() {
void Isolate::set_context(Context context) {
DCHECK(context.is_null() || context->IsContext());
thread_local_top_.context_ = context;
thread_local_top()->context_ = context;
}
Handle<NativeContext> Isolate::native_context() {
@ -35,47 +35,49 @@ NativeContext Isolate::raw_native_context() {
Object Isolate::pending_exception() {
DCHECK(has_pending_exception());
DCHECK(!thread_local_top_.pending_exception_->IsException(this));
return thread_local_top_.pending_exception_;
DCHECK(!thread_local_top()->pending_exception_->IsException(this));
return thread_local_top()->pending_exception_;
}
void Isolate::set_pending_exception(Object exception_obj) {
DCHECK(!exception_obj->IsException(this));
thread_local_top_.pending_exception_ = exception_obj;
thread_local_top()->pending_exception_ = exception_obj;
}
void Isolate::clear_pending_exception() {
DCHECK(!thread_local_top_.pending_exception_->IsException(this));
thread_local_top_.pending_exception_ = ReadOnlyRoots(this).the_hole_value();
DCHECK(!thread_local_top()->pending_exception_->IsException(this));
thread_local_top()->pending_exception_ = ReadOnlyRoots(this).the_hole_value();
}
bool Isolate::has_pending_exception() {
DCHECK(!thread_local_top_.pending_exception_->IsException(this));
return !thread_local_top_.pending_exception_->IsTheHole(this);
DCHECK(!thread_local_top()->pending_exception_->IsException(this));
return !thread_local_top()->pending_exception_->IsTheHole(this);
}
void Isolate::clear_pending_message() {
thread_local_top_.pending_message_obj_ = ReadOnlyRoots(this).the_hole_value();
thread_local_top()->pending_message_obj_ =
ReadOnlyRoots(this).the_hole_value();
}
Object Isolate::scheduled_exception() {
DCHECK(has_scheduled_exception());
DCHECK(!thread_local_top_.scheduled_exception_->IsException(this));
return thread_local_top_.scheduled_exception_;
DCHECK(!thread_local_top()->scheduled_exception_->IsException(this));
return thread_local_top()->scheduled_exception_;
}
bool Isolate::has_scheduled_exception() {
DCHECK(!thread_local_top_.scheduled_exception_->IsException(this));
return thread_local_top_.scheduled_exception_ !=
DCHECK(!thread_local_top()->scheduled_exception_->IsException(this));
return thread_local_top()->scheduled_exception_ !=
ReadOnlyRoots(this).the_hole_value();
}
void Isolate::clear_scheduled_exception() {
DCHECK(!thread_local_top_.scheduled_exception_->IsException(this));
thread_local_top_.scheduled_exception_ = ReadOnlyRoots(this).the_hole_value();
DCHECK(!thread_local_top()->scheduled_exception_->IsException(this));
thread_local_top()->scheduled_exception_ =
ReadOnlyRoots(this).the_hole_value();
}
bool Isolate::is_catchable_by_javascript(Object exception) {

View File

@ -288,22 +288,6 @@ size_t Isolate::HashIsolateForEmbeddedBlob() {
return hash;
}
void ThreadLocalTop::Initialize(Isolate* isolate) {
*this = ThreadLocalTop();
isolate_ = isolate;
#ifdef USE_SIMULATOR
simulator_ = Simulator::current(isolate);
#endif
thread_id_ = ThreadId::Current();
thread_in_wasm_flag_address_ = reinterpret_cast<Address>(
trap_handler::GetThreadInWasmThreadLocalAddress());
}
void ThreadLocalTop::Free() {
// Match unmatched PopPromise calls.
while (promise_on_stack_) isolate_->PopPromise();
}
base::Thread::LocalStorageKey Isolate::isolate_key_;
base::Thread::LocalStorageKey Isolate::per_isolate_thread_data_key_;
@ -394,7 +378,7 @@ void Isolate::Iterate(RootVisitor* v, ThreadLocalTop* thread) {
v->VisitRootPointer(Root::kTop, nullptr,
FullObjectSlot(&thread->scheduled_exception_));
for (v8::TryCatch* block = thread->try_catch_handler(); block != nullptr;
for (v8::TryCatch* block = thread->try_catch_handler_; block != nullptr;
block = block->next_) {
// TODO(3770): Make TryCatch::exception_ an Address (and message_obj_ too).
v->VisitRootPointer(
@ -453,13 +437,13 @@ bool Isolate::IsDeferredHandle(Address* handle) {
void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
thread_local_top()->set_try_catch_handler(that);
thread_local_top()->try_catch_handler_ = that;
}
void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) {
DCHECK(thread_local_top()->try_catch_handler() == that);
thread_local_top()->set_try_catch_handler(that->next_);
DCHECK(thread_local_top()->try_catch_handler_ == that);
thread_local_top()->try_catch_handler_ = that->next_;
}
@ -1995,7 +1979,7 @@ void Isolate::CancelScheduledExceptionFromTryCatch(v8::TryCatch* handler) {
clear_scheduled_exception();
}
}
if (reinterpret_cast<void*>(thread_local_top_.pending_message_obj_.ptr()) ==
if (reinterpret_cast<void*>(thread_local_top()->pending_message_obj_.ptr()) ==
handler->message_obj_) {
clear_pending_message();
}
@ -2229,7 +2213,7 @@ void Isolate::ReportPendingMessagesImpl(bool report_externally) {
Object exception = pending_exception();
// Clear the pending message object early to avoid endless recursion.
Object message_obj = thread_local_top_.pending_message_obj_;
Object message_obj = thread_local_top()->pending_message_obj_;
clear_pending_message();
// For uncatchable exceptions we do nothing. If needed, the exception and the
@ -2309,27 +2293,27 @@ void Isolate::ReportPendingMessagesFromJavaScript() {
auto PropagateToExternalHandler = [=]() {
if (IsHandledByJavaScript()) {
thread_local_top_.external_caught_exception_ = false;
thread_local_top()->external_caught_exception_ = false;
return false;
}
if (!IsHandledExternally()) {
thread_local_top_.external_caught_exception_ = false;
thread_local_top()->external_caught_exception_ = false;
return true;
}
thread_local_top_.external_caught_exception_ = true;
thread_local_top()->external_caught_exception_ = true;
v8::TryCatch* handler = try_catch_handler();
DCHECK(thread_local_top_.pending_message_obj_->IsJSMessageObject() ||
thread_local_top_.pending_message_obj_->IsTheHole(this));
DCHECK(thread_local_top()->pending_message_obj_->IsJSMessageObject() ||
thread_local_top()->pending_message_obj_->IsTheHole(this));
handler->can_continue_ = true;
handler->has_terminated_ = false;
handler->exception_ = reinterpret_cast<void*>(pending_exception().ptr());
// Propagate to the external try-catch only if we got an actual message.
if (thread_local_top_.pending_message_obj_->IsTheHole(this)) return true;
if (thread_local_top()->pending_message_obj_->IsTheHole(this)) return true;
handler->message_obj_ =
reinterpret_cast<void*>(thread_local_top_.pending_message_obj_.ptr());
reinterpret_cast<void*>(thread_local_top()->pending_message_obj_.ptr());
return true;
};
@ -2342,11 +2326,11 @@ void Isolate::ReportPendingMessagesFromJavaScript() {
MessageLocation Isolate::GetMessageLocation() {
DCHECK(has_pending_exception());
if (thread_local_top_.pending_exception_ !=
if (thread_local_top()->pending_exception_ !=
ReadOnlyRoots(heap()).termination_exception() &&
!thread_local_top_.pending_message_obj_->IsTheHole(this)) {
!thread_local_top()->pending_message_obj_->IsTheHole(this)) {
Handle<JSMessageObject> message_obj(
JSMessageObject::cast(thread_local_top_.pending_message_obj_), this);
JSMessageObject::cast(thread_local_top()->pending_message_obj_), this);
Handle<Script> script(message_obj->script(), this);
int start_pos = message_obj->start_position();
int end_pos = message_obj->end_position();
@ -3121,7 +3105,7 @@ Isolate::~Isolate() {
default_microtask_queue_ = nullptr;
}
void Isolate::InitializeThreadLocal() { thread_local_top_.Initialize(this); }
void Isolate::InitializeThreadLocal() { thread_local_top()->Initialize(this); }
void Isolate::SetTerminationOnExternalTryCatch() {
if (try_catch_handler() == nullptr) return;
@ -3135,30 +3119,30 @@ bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
Object exception = pending_exception();
if (IsJavaScriptHandlerOnTop(exception)) {
thread_local_top_.external_caught_exception_ = false;
thread_local_top()->external_caught_exception_ = false;
return false;
}
if (!IsExternalHandlerOnTop(exception)) {
thread_local_top_.external_caught_exception_ = false;
thread_local_top()->external_caught_exception_ = false;
return true;
}
thread_local_top_.external_caught_exception_ = true;
thread_local_top()->external_caught_exception_ = true;
if (!is_catchable_by_javascript(exception)) {
SetTerminationOnExternalTryCatch();
} else {
v8::TryCatch* handler = try_catch_handler();
DCHECK(thread_local_top_.pending_message_obj_->IsJSMessageObject() ||
thread_local_top_.pending_message_obj_->IsTheHole(this));
DCHECK(thread_local_top()->pending_message_obj_->IsJSMessageObject() ||
thread_local_top()->pending_message_obj_->IsTheHole(this));
handler->can_continue_ = true;
handler->has_terminated_ = false;
handler->exception_ = reinterpret_cast<void*>(pending_exception().ptr());
// Propagate to the external try-catch only if we got an actual message.
if (thread_local_top_.pending_message_obj_->IsTheHole(this)) return true;
if (thread_local_top()->pending_message_obj_->IsTheHole(this)) return true;
handler->message_obj_ =
reinterpret_cast<void*>(thread_local_top_.pending_message_obj_.ptr());
reinterpret_cast<void*>(thread_local_top()->pending_message_obj_.ptr());
}
return true;
}

View File

@ -33,7 +33,6 @@
#include "src/objects/code.h"
#include "src/objects/debug-objects.h"
#include "src/runtime/runtime.h"
#include "src/thread-id.h"
#include "src/unicode.h"
#ifdef V8_INTL_SUPPORT
@ -76,7 +75,6 @@ class DeoptimizerData;
class DescriptorLookupCache;
class EmbeddedFileWriterInterface;
class EternalHandles;
class ExternalCallbackScope;
class HandleScopeImplementer;
class HeapObjectToIndexHashMap;
class HeapProfiler;
@ -86,7 +84,6 @@ class MaterializedObjectStore;
class Microtask;
class MicrotaskQueue;
class OptimizingCompileDispatcher;
class PromiseOnStack;
class RegExpStack;
class RootVisitor;
class RuntimeProfiler;
@ -340,101 +337,6 @@ class WasmEngine;
V8_EXPORT_PRIVATE void DisableEmbeddedBlobRefcounting();
V8_EXPORT_PRIVATE void FreeCurrentEmbeddedBlob();
class ThreadLocalTop {
public:
// Does early low-level initialization that does not depend on the
// isolate being present.
ThreadLocalTop() = default;
// Initialize the thread data.
void Initialize(Isolate*);
// Get the top C++ try catch handler or nullptr if none are registered.
//
// This method is not guaranteed to return an address that can be
// used for comparison with addresses into the JS stack. If such an
// address is needed, use try_catch_handler_address.
FIELD_ACCESSOR(v8::TryCatch*, try_catch_handler)
// Get the address of the top C++ try catch handler or nullptr if
// none are registered.
//
// This method always returns an address that can be compared to
// pointers into the JavaScript stack. When running on actual
// hardware, try_catch_handler_address and TryCatchHandler return
// the same pointer. When running on a simulator with a separate JS
// stack, try_catch_handler_address returns a JS stack address that
// corresponds to the place on the JS stack where the C++ handler
// would have been if the stack were not separate.
Address try_catch_handler_address() {
return reinterpret_cast<Address>(
v8::TryCatch::JSStackComparableAddress(try_catch_handler()));
}
void Free();
Isolate* isolate_ = nullptr;
// The context where the current execution method is created and for variable
// lookups.
// TODO(3770): This field is read/written from generated code, so it would
// be cleaner to make it an "Address raw_context_", and construct a Context
// object in the getter. Same for {pending_handler_context_} below. In the
// meantime, assert that the memory layout is the same.
STATIC_ASSERT(sizeof(Context) == kSystemPointerSize);
Context context_;
ThreadId thread_id_ = ThreadId::Invalid();
Object pending_exception_;
// Communication channel between Isolate::FindHandler and the CEntry.
Context pending_handler_context_;
Address pending_handler_entrypoint_ = kNullAddress;
Address pending_handler_constant_pool_ = kNullAddress;
Address pending_handler_fp_ = kNullAddress;
Address pending_handler_sp_ = kNullAddress;
// Communication channel between Isolate::Throw and message consumers.
bool rethrowing_message_ = false;
Object pending_message_obj_;
// Use a separate value for scheduled exceptions to preserve the
// invariants that hold about pending_exception. We may want to
// unify them later.
Object scheduled_exception_;
bool external_caught_exception_ = false;
// Stack.
// The frame pointer of the top c entry frame.
Address c_entry_fp_ = kNullAddress;
// Try-blocks are chained through the stack.
Address handler_ = kNullAddress;
// C function that was called at c entry.
Address c_function_ = kNullAddress;
// Throwing an exception may cause a Promise rejection. For this purpose
// we keep track of a stack of nested promises and the corresponding
// try-catch handlers.
PromiseOnStack* promise_on_stack_ = nullptr;
#ifdef USE_SIMULATOR
Simulator* simulator_ = nullptr;
#endif
// The stack pointer of the bottom JS entry frame.
Address js_entry_sp_ = kNullAddress;
// The external callback we're currently in.
ExternalCallbackScope* external_callback_scope_ = nullptr;
StateTag current_vm_state_ = EXTERNAL;
// Call back function to report unsafe JS accesses.
v8::FailedAccessCheckCallback failed_access_check_callback_ = nullptr;
// Address of the thread-local "thread in wasm" flag.
Address thread_in_wasm_flag_address_ = kNullAddress;
private:
v8::TryCatch* try_catch_handler_ = nullptr;
};
#ifdef DEBUG
#define ISOLATE_INIT_DEBUG_ARRAY_LIST(V) \
@ -500,12 +402,12 @@ typedef std::vector<HeapObject> DebugObjectCache;
V(bool, only_terminate_in_safe_scope, false) \
V(bool, detailed_source_positions_for_profiling, FLAG_detailed_line_info)
#define THREAD_LOCAL_TOP_ACCESSOR(type, name) \
inline void set_##name(type v) { thread_local_top_.name##_ = v; } \
inline type name() const { return thread_local_top_.name##_; }
#define THREAD_LOCAL_TOP_ACCESSOR(type, name) \
inline void set_##name(type v) { thread_local_top()->name##_ = v; } \
inline type name() const { return thread_local_top()->name##_; }
#define THREAD_LOCAL_TOP_ADDRESS(type, name) \
type* name##_address() { return &thread_local_top_.name##_; }
type* name##_address() { return &thread_local_top()->name##_; }
// HiddenFactory exists so Isolate can privately inherit from it without making
// Factory's members available to Isolate directly.
@ -660,9 +562,9 @@ class Isolate final : private HiddenFactory {
Address get_address_from_id(IsolateAddressId id);
// Access to top context (where the current function object was created).
Context context() { return thread_local_top_.context_; }
Context context() { return thread_local_top()->context_; }
inline void set_context(Context context);
Context* context_address() { return &thread_local_top_.context_; }
Context* context_address() { return &thread_local_top()->context_; }
// Access to current thread id.
THREAD_LOCAL_TOP_ACCESSOR(ThreadId, thread_id)
@ -687,17 +589,17 @@ class Isolate final : private HiddenFactory {
THREAD_LOCAL_TOP_ACCESSOR(bool, external_caught_exception)
v8::TryCatch* try_catch_handler() {
return thread_local_top_.try_catch_handler();
return thread_local_top()->try_catch_handler_;
}
bool* external_caught_exception_address() {
return &thread_local_top_.external_caught_exception_;
return &thread_local_top()->external_caught_exception_;
}
THREAD_LOCAL_TOP_ADDRESS(Object, scheduled_exception)
inline void clear_pending_message();
Address pending_message_obj_address() {
return reinterpret_cast<Address>(&thread_local_top_.pending_message_obj_);
return reinterpret_cast<Address>(&thread_local_top()->pending_message_obj_);
}
inline Object scheduled_exception();
@ -714,22 +616,20 @@ class Isolate final : private HiddenFactory {
return thread->c_entry_fp_;
}
static Address handler(ThreadLocalTop* thread) { return thread->handler_; }
Address c_function() { return thread_local_top_.c_function_; }
Address c_function() { return thread_local_top()->c_function_; }
inline Address* c_entry_fp_address() {
return &thread_local_top_.c_entry_fp_;
return &thread_local_top()->c_entry_fp_;
}
inline Address* handler_address() { return &thread_local_top_.handler_; }
inline Address* handler_address() { return &thread_local_top()->handler_; }
inline Address* c_function_address() {
return &thread_local_top_.c_function_;
return &thread_local_top()->c_function_;
}
// Bottom JS entry.
Address js_entry_sp() {
return thread_local_top_.js_entry_sp_;
}
Address js_entry_sp() { return thread_local_top()->js_entry_sp_; }
inline Address* js_entry_sp_address() {
return &thread_local_top_.js_entry_sp_;
return &thread_local_top()->js_entry_sp_;
}
// Returns the global object of the current context. It could be
@ -740,7 +640,7 @@ class Isolate final : private HiddenFactory {
inline Handle<JSObject> global_proxy();
static int ArchiveSpacePerThread() { return sizeof(ThreadLocalTop); }
void FreeThreadResources() { thread_local_top_.Free(); }
void FreeThreadResources() { thread_local_top()->Free(); }
// This method is called by the api after operations that may throw
// exceptions. If an exception was thrown and not handled by an external
@ -1016,7 +916,12 @@ class Isolate final : private HiddenFactory {
void set_deoptimizer_lazy_throw(bool value) {
deoptimizer_lazy_throw_ = value;
}
ThreadLocalTop* thread_local_top() { return &thread_local_top_; }
ThreadLocalTop* thread_local_top() {
return &isolate_data_.thread_local_top_;
}
ThreadLocalTop const* thread_local_top() const {
return &isolate_data_.thread_local_top_;
}
static uint32_t thread_in_wasm_flag_address_offset() {
// For WebAssembly trap handlers there is a flag in thread-local storage
@ -1025,7 +930,7 @@ class Isolate final : private HiddenFactory {
// flag in ThreadLocalTop in thread_in_wasm_flag_address_. This function
// here returns the offset of that member from {isolate_root()}.
return static_cast<uint32_t>(
OFFSET_OF(Isolate, thread_local_top_.thread_in_wasm_flag_address_) -
OFFSET_OF(Isolate, thread_local_top()->thread_in_wasm_flag_address_) -
isolate_root_bias());
}
@ -1711,7 +1616,6 @@ class Isolate final : private HiddenFactory {
DeoptimizerData* deoptimizer_data_ = nullptr;
bool deoptimizer_lazy_throw_ = false;
MaterializedObjectStore* materialized_object_store_ = nullptr;
ThreadLocalTop thread_local_top_;
bool capture_stack_trace_for_uncaught_exceptions_ = false;
int stack_trace_for_uncaught_exceptions_frame_limit_ = 0;
StackTrace::StackTraceOptions stack_trace_for_uncaught_exceptions_options_ =

30
src/thread-local-top.cc Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/thread-local-top.h"
#include "src/isolate.h"
#include "src/simulator.h"
#include "src/trap-handler/trap-handler.h"
namespace v8 {
namespace internal {
void ThreadLocalTop::Initialize(Isolate* isolate) {
*this = ThreadLocalTop();
isolate_ = isolate;
#ifdef USE_SIMULATOR
simulator_ = Simulator::current(isolate);
#endif
thread_id_ = ThreadId::Current();
thread_in_wasm_flag_address_ = reinterpret_cast<Address>(
trap_handler::GetThreadInWasmThreadLocalAddress());
}
void ThreadLocalTop::Free() {
// Match unmatched PopPromise calls.
while (promise_on_stack_) isolate_->PopPromise();
}
} // namespace internal
} // namespace v8

122
src/thread-local-top.h Normal file
View File

@ -0,0 +1,122 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_THREAD_LOCAL_TOP_H_
#define V8_THREAD_LOCAL_TOP_H_
#include "src/contexts.h"
#include "src/globals.h"
#include "src/thread-id.h"
namespace v8 {
class TryCatch;
namespace internal {
class ExternalCallbackScope;
class Isolate;
class PromiseOnStack;
class Simulator;
class ThreadLocalTop {
public:
// TODO(all): This is not particularly beautiful. We should probably
// refactor this to really consist of just Addresses and 32-bit
// integer fields.
static constexpr uint32_t kSizeInBytes = 23 * kSystemPointerSize;
// Does early low-level initialization that does not depend on the
// isolate being present.
ThreadLocalTop() = default;
// Initialize the thread data.
void Initialize(Isolate*);
// The top C++ try catch handler or nullptr if none are registered.
//
// This field is not guaranteed to hold an address that can be
// used for comparison with addresses into the JS stack. If such
// an address is needed, use try_catch_handler_address.
v8::TryCatch* try_catch_handler_ = nullptr;
// Get the address of the top C++ try catch handler or nullptr if
// none are registered.
//
// This method always returns an address that can be compared to
// pointers into the JavaScript stack. When running on actual
// hardware, try_catch_handler_address and TryCatchHandler return
// the same pointer. When running on a simulator with a separate JS
// stack, try_catch_handler_address returns a JS stack address that
// corresponds to the place on the JS stack where the C++ handler
// would have been if the stack were not separate.
Address try_catch_handler_address() {
return reinterpret_cast<Address>(
v8::TryCatch::JSStackComparableAddress(try_catch_handler_));
}
void Free();
Isolate* isolate_ = nullptr;
// The context where the current execution method is created and for variable
// lookups.
// TODO(3770): This field is read/written from generated code, so it would
// be cleaner to make it an "Address raw_context_", and construct a Context
// object in the getter. Same for {pending_handler_context_} below. In the
// meantime, assert that the memory layout is the same.
STATIC_ASSERT(sizeof(Context) == kSystemPointerSize);
Context context_;
ThreadId thread_id_ = ThreadId::Invalid();
Object pending_exception_;
// Communication channel between Isolate::FindHandler and the CEntry.
Context pending_handler_context_;
Address pending_handler_entrypoint_ = kNullAddress;
Address pending_handler_constant_pool_ = kNullAddress;
Address pending_handler_fp_ = kNullAddress;
Address pending_handler_sp_ = kNullAddress;
// Communication channel between Isolate::Throw and message consumers.
Object pending_message_obj_;
bool rethrowing_message_ = false;
// Use a separate value for scheduled exceptions to preserve the
// invariants that hold about pending_exception. We may want to
// unify them later.
bool external_caught_exception_ = false;
Object scheduled_exception_;
// Stack.
// The frame pointer of the top c entry frame.
Address c_entry_fp_ = kNullAddress;
// Try-blocks are chained through the stack.
Address handler_ = kNullAddress;
// C function that was called at c entry.
Address c_function_ = kNullAddress;
// Throwing an exception may cause a Promise rejection. For this purpose
// we keep track of a stack of nested promises and the corresponding
// try-catch handlers.
PromiseOnStack* promise_on_stack_ = nullptr;
// Simulator field is always present to get predictable layout.
Simulator* simulator_ = nullptr;
// The stack pointer of the bottom JS entry frame.
Address js_entry_sp_ = kNullAddress;
// The external callback we're currently in.
ExternalCallbackScope* external_callback_scope_ = nullptr;
StateTag current_vm_state_ = EXTERNAL;
// Call back function to report unsafe JS accesses.
v8::FailedAccessCheckCallback failed_access_check_callback_ = nullptr;
// Address of the thread-local "thread in wasm" flag.
Address thread_in_wasm_flag_address_ = kNullAddress;
};
} // namespace internal
} // namespace v8
#endif // V8_THREAD_LOCAL_TOP_H_