diff options
Diffstat (limited to 'deps/v8/src/execution/isolate.cc')
-rw-r--r-- | deps/v8/src/execution/isolate.cc | 289 |
1 files changed, 234 insertions, 55 deletions
diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc index 55f3fac9b3..b4070372ee 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -7,7 +7,7 @@ #include <stdlib.h> #include <atomic> -#include <fstream> // NOLINT(readability/streams) +#include <fstream> #include <memory> #include <sstream> #include <string> @@ -19,9 +19,11 @@ #include "src/ast/scopes.h" #include "src/base/hashmap.h" #include "src/base/logging.h" +#include "src/base/platform/mutex.h" #include "src/base/platform/platform.h" #include "src/base/sys-info.h" #include "src/base/utils/random-number-generator.h" +#include "src/bigint/bigint.h" #include "src/builtins/builtins-promise.h" #include "src/builtins/constants-table-builder.h" #include "src/codegen/assembler-inl.h" @@ -318,10 +320,6 @@ void Isolate::SetEmbeddedBlob(const uint8_t* code, uint32_t code_size, } } #endif // DEBUG - - if (FLAG_experimental_flush_embedded_blob_icache) { - FlushInstructionCache(const_cast<uint8_t*>(code), code_size); - } } void Isolate::ClearEmbeddedBlob() { @@ -1404,12 +1402,15 @@ Object Isolate::StackOverflow() { Handle<JSFunction> fun = range_error_function(); Handle<Object> msg = factory()->NewStringFromAsciiChecked( MessageFormatter::TemplateString(MessageTemplate::kStackOverflow)); + Handle<Object> options = factory()->undefined_value(); Handle<Object> no_caller; - Handle<Object> exception; + Handle<JSObject> exception; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( this, exception, - ErrorUtils::Construct(this, fun, fun, msg, SKIP_NONE, no_caller, + ErrorUtils::Construct(this, fun, fun, msg, options, SKIP_NONE, no_caller, ErrorUtils::StackTraceCollection::kSimple)); + JSObject::AddProperty(this, exception, factory()->wasm_uncatchable_symbol(), + factory()->true_value(), NONE); Throw(*exception); @@ -1474,8 +1475,7 @@ void Isolate::RequestInterrupt(InterruptCallback callback, void* data) { } void Isolate::InvokeApiInterruptCallbacks() { - RuntimeCallTimerScope runtimeTimer( - this, RuntimeCallCounterId::kInvokeApiInterruptCallbacks); + RCS_SCOPE(this, RuntimeCallCounterId::kInvokeApiInterruptCallbacks); // Note: callback below should be called outside of execution access lock. while (true) { InterruptEntry entry; @@ -1675,10 +1675,36 @@ Object Isolate::ReThrow(Object exception) { return ReadOnlyRoots(heap()).exception(); } +namespace { +// This scope will set the thread-in-wasm flag after the execution of all +// destructors. The thread-in-wasm flag is only set when the scope gets enabled. +class SetThreadInWasmFlagScope { + public: + SetThreadInWasmFlagScope() { + DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(), + !trap_handler::IsThreadInWasm()); + } + + ~SetThreadInWasmFlagScope() { + if (enabled_) trap_handler::SetThreadInWasm(); + } + + void Enable() { enabled_ = true; } + + private: + bool enabled_ = false; +}; +} // namespace + Object Isolate::UnwindAndFindHandler() { + // Create the {SetThreadInWasmFlagScope} first in this function so that its + // destructor gets called after all the other destructors. It is important + // that the destructor sets the thread-in-wasm flag after all other + // destructors. The other destructors may cause exceptions, e.g. ASan on + // Windows, which would invalidate the thread-in-wasm flag when the wasm trap + // handler handles such non-wasm exceptions. + SetThreadInWasmFlagScope set_thread_in_wasm_flag_scope; Object exception = pending_exception(); - DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(), - !trap_handler::IsThreadInWasm()); auto FoundHandler = [&](Context context, Address instruction_start, intptr_t handler_offset, @@ -1771,9 +1797,10 @@ Object Isolate::UnwindAndFindHandler() { StandardFrameConstants::kFixedFrameSizeAboveFp - wasm_code->stack_slots() * kSystemPointerSize; - // This is going to be handled by Wasm, so we need to set the TLS flag. - trap_handler::SetThreadInWasm(); - + // This is going to be handled by WebAssembly, so we need to set the TLS + // flag. The {SetThreadInWasmFlagScope} will set the flag after all + // destructors have been executed. + set_thread_in_wasm_flag_scope.Enable(); return FoundHandler(Context(), wasm_code->instruction_start(), offset, wasm_code->constant_pool(), return_sp, frame->fp()); } @@ -1886,7 +1913,7 @@ Object Isolate::UnwindAndFindHandler() { static_cast<int>(offset)); Code code = - builtins()->builtin(Builtins::kInterpreterEnterBytecodeDispatch); + builtins()->builtin(Builtins::kInterpreterEnterAtBytecode); return FoundHandler(context, code.InstructionStart(), 0, code.constant_pool(), return_sp, frame->fp()); } @@ -2550,6 +2577,29 @@ void Isolate::SetAbortOnUncaughtExceptionCallback( abort_on_uncaught_exception_callback_ = callback; } +void Isolate::InstallConditionalFeatures(Handle<Context> context) { + Handle<JSGlobalObject> global = handle(context->global_object(), this); + Handle<String> sab_name = factory()->SharedArrayBuffer_string(); + if (IsSharedArrayBufferConstructorEnabled(context)) { + if (!JSObject::HasRealNamedProperty(global, sab_name).FromMaybe(true)) { + JSObject::AddProperty(this, global, factory()->SharedArrayBuffer_string(), + shared_array_buffer_fun(), DONT_ENUM); + } + } +} + +bool Isolate::IsSharedArrayBufferConstructorEnabled(Handle<Context> context) { + if (!FLAG_harmony_sharedarraybuffer) return false; + + if (!FLAG_enable_sharedarraybuffer_per_context) return true; + + if (sharedarraybuffer_constructor_enabled_callback()) { + v8::Local<v8::Context> api_context = v8::Utils::ToLocal(context); + return sharedarraybuffer_constructor_enabled_callback()(api_context); + } + return false; +} + bool Isolate::IsWasmSimdEnabled(Handle<Context> context) { #if V8_ENABLE_WEBASSEMBLY if (wasm_simd_enabled_callback()) { @@ -2667,9 +2717,10 @@ void Isolate::UnregisterManagedPtrDestructor(ManagedPtrDestructor* destructor) { } #if V8_ENABLE_WEBASSEMBLY -void Isolate::SetWasmEngine(std::shared_ptr<wasm::WasmEngine> engine) { +void Isolate::SetWasmEngine(wasm::WasmEngine* engine) { DCHECK_NULL(wasm_engine_); // Only call once before {Init}. - wasm_engine_ = std::move(engine); + DCHECK_NOT_NULL(engine); + wasm_engine_ = engine; wasm_engine_->AddIsolate(this); } @@ -2683,7 +2734,6 @@ void Isolate::AddSharedWasmMemory(Handle<WasmMemoryObject> memory_object) { } #endif // V8_ENABLE_WEBASSEMBLY -// NOLINTNEXTLINE Isolate::PerIsolateThreadData::~PerIsolateThreadData() { #if defined(USE_SIMULATOR) delete simulator_; @@ -2854,16 +2904,28 @@ std::atomic<size_t> Isolate::non_disposed_isolates_; #endif // DEBUG // static -Isolate* Isolate::New() { +Isolate* Isolate::New() { return Isolate::Allocate(false); } + +// static +Isolate* Isolate::NewShared(const v8::Isolate::CreateParams& params) { + Isolate* isolate = Isolate::Allocate(true); + v8::Isolate::Initialize(reinterpret_cast<v8::Isolate*>(isolate), params); + return isolate; +} + +// static +Isolate* Isolate::Allocate(bool is_shared) { // IsolateAllocator allocates the memory for the Isolate object according to // the given allocation mode. std::unique_ptr<IsolateAllocator> isolate_allocator = std::make_unique<IsolateAllocator>(); // Construct Isolate object in the allocated memory. void* isolate_ptr = isolate_allocator->isolate_memory(); - Isolate* isolate = new (isolate_ptr) Isolate(std::move(isolate_allocator)); + Isolate* isolate = + new (isolate_ptr) Isolate(std::move(isolate_allocator), is_shared); #ifdef V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE DCHECK(IsAligned(isolate->isolate_root(), kPtrComprCageBaseAlignment)); + DCHECK_EQ(isolate->isolate_root(), isolate->cage_base()); #endif #ifdef DEBUG @@ -2919,12 +2981,13 @@ void Isolate::SetUpFromReadOnlyArtifacts( heap_.SetUpFromReadOnlyHeap(read_only_heap_); } -v8::PageAllocator* Isolate::page_allocator() { +v8::PageAllocator* Isolate::page_allocator() const { return isolate_allocator_->page_allocator(); } -Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator) - : isolate_data_(this), +Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator, + bool is_shared) + : isolate_data_(this, isolate_allocator->GetPtrComprCageBase()), isolate_allocator_(std::move(isolate_allocator)), id_(isolate_counter.fetch_add(1, std::memory_order_relaxed)), allocator_(new TracingAccountingAllocator(this)), @@ -2941,7 +3004,8 @@ Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator) #endif next_module_async_evaluating_ordinal_( SourceTextModule::kFirstAsyncEvaluatingOrdinal), - cancelable_task_manager_(new CancelableTaskManager()) { + cancelable_task_manager_(new CancelableTaskManager()), + is_shared_(is_shared) { TRACE_ISOLATE(constructor); CheckIsolateLayout(); @@ -2951,6 +3015,18 @@ Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator) handle_scope_data_.Initialize(); + // When pointer compression is on with a per-Isolate cage, allocation in the + // shared Isolate can point into the per-Isolate RO heap as the offsets are + // constant across Isolates. + // + // When pointer compression is on with a shared cage or when pointer + // compression is off, a shared RO heap is required. Otherwise a shared + // allocation requested by a client Isolate could point into the client + // Isolate's RO space (e.g. an RO map) whose pages gets unmapped when it is + // disposed. + CHECK_IMPLIES(is_shared_, COMPRESS_POINTERS_IN_ISOLATE_CAGE_BOOL || + V8_SHARED_RO_HEAP_BOOL); + #define ISOLATE_INIT_EXECUTE(type, name, initial_value) \ name##_ = (initial_value); ISOLATE_INIT_LIST(ISOLATE_INIT_EXECUTE) @@ -2979,6 +3055,11 @@ void Isolate::CheckIsolateLayout() { CHECK_EQ(static_cast<int>( OFFSET_OF(Isolate, isolate_data_.fast_c_call_caller_pc_)), Internals::kIsolateFastCCallCallerPcOffset); + CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, isolate_data_.cage_base_)), + Internals::kIsolateCageBaseOffset); + CHECK_EQ(static_cast<int>( + OFFSET_OF(Isolate, isolate_data_.long_task_stats_counter_)), + Internals::kIsolateLongTaskStatsCounterOffset); CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, isolate_data_.stack_guard_)), Internals::kIsolateStackGuardOffset); CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, isolate_data_.roots_)), @@ -3020,10 +3101,10 @@ void Isolate::Deinit() { #if defined(V8_OS_WIN64) if (win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange() && - heap()->memory_allocator() && RequiresCodeRange()) { - const base::AddressRegion& code_range = - heap()->memory_allocator()->code_range(); - void* start = reinterpret_cast<void*>(code_range.begin()); + heap()->memory_allocator() && RequiresCodeRange() && + heap()->code_range()->AtomicDecrementUnwindInfoUseCount() == 1) { + const base::AddressRegion& code_region = heap()->code_region(); + void* start = reinterpret_cast<void*>(code_region.begin()); win64_unwindinfo::UnregisterNonABICompliantCodeRange(start); } #endif // V8_OS_WIN64 @@ -3044,6 +3125,9 @@ void Isolate::Deinit() { optimizing_compile_dispatcher_ = nullptr; } + // All client isolates should already be detached. + DCHECK_NULL(client_isolate_head_); + // Help sweeper threads complete sweeping to stop faster. heap_.mark_compact_collector()->DrainSweepingWorklists(); heap_.mark_compact_collector()->sweeper()->EnsureIterabilityCompleted(); @@ -3090,6 +3174,10 @@ void Isolate::Deinit() { main_thread_local_isolate_->heap()->FreeLinearAllocationArea(); + if (shared_isolate_) { + DetachFromSharedIsolate(); + } + heap_.TearDown(); main_thread_local_isolate_.reset(); @@ -3098,10 +3186,7 @@ void Isolate::Deinit() { if (logfile != nullptr) base::Fclose(logfile); #if V8_ENABLE_WEBASSEMBLY - if (wasm_engine_) { - wasm_engine_->RemoveIsolate(this); - wasm_engine_.reset(); - } + wasm_engine_->RemoveIsolate(this); #endif // V8_ENABLE_WEBASSEMBLY TearDownEmbeddedBlob(); @@ -3182,6 +3267,8 @@ Isolate::~Isolate() { delete thread_manager_; thread_manager_ = nullptr; + bigint_processor_->Destroy(); + delete global_handles_; global_handles_ = nullptr; delete eternal_handles_; @@ -3389,8 +3476,9 @@ void Isolate::MaybeRemapEmbeddedBuiltinsIntoCodeRange() { CHECK_NOT_NULL(embedded_blob_code_); CHECK_NE(embedded_blob_code_size_, 0); - embedded_blob_code_ = heap_.RemapEmbeddedBuiltinsIntoCodeRange( - embedded_blob_code_, embedded_blob_code_size_); + DCHECK_NOT_NULL(heap_.code_range_); + embedded_blob_code_ = heap_.code_range_->RemapEmbeddedBuiltins( + this, embedded_blob_code_, embedded_blob_code_size_); CHECK_NOT_NULL(embedded_blob_code_); // The un-embedded code blob is already a part of the registered code range // so it's not necessary to register it again. @@ -3474,6 +3562,21 @@ using MapOfLoadsAndStoresPerFunction = std::map<std::string /* function_name */, std::pair<uint64_t /* loads */, uint64_t /* stores */>>; MapOfLoadsAndStoresPerFunction* stack_access_count_map = nullptr; + +class BigIntPlatform : public bigint::Platform { + public: + explicit BigIntPlatform(Isolate* isolate) : isolate_(isolate) {} + ~BigIntPlatform() override = default; + + bool InterruptRequested() override { + StackLimitCheck interrupt_check(isolate_); + return (interrupt_check.InterruptRequested() && + isolate_->stack_guard()->HasTerminationRequest()); + } + + private: + Isolate* isolate_; +}; } // namespace bool Isolate::Init(SnapshotData* startup_snapshot_data, @@ -3522,6 +3625,7 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, heap_profiler_ = new HeapProfiler(heap()); interpreter_ = new interpreter::Interpreter(this); string_table_.reset(new StringTable(this)); + bigint_processor_ = bigint::Processor::New(new BigIntPlatform(this)); compiler_dispatcher_ = new CompilerDispatcher(this, V8::GetCurrentPlatform(), FLAG_stack_size); @@ -3531,7 +3635,7 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, metrics_recorder_ = std::make_shared<metrics::Recorder>(); - { // NOLINT + { // Ensure that the thread has a valid stack guard. The v8::Locker object // will ensure this too, but we don't have to use lockers if we are only // using one thread. @@ -3546,24 +3650,32 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, heap_.SetUpSpaces(); if (V8_SHORT_BUILTIN_CALLS_BOOL && FLAG_short_builtin_calls) { - // Check if the system has more than 4GB of physical memory by comaring - // the old space size with respective threshod value. - is_short_builtin_calls_enabled_ = - heap_.MaxOldGenerationSize() >= kShortBuiltinCallsOldSpaceSizeThreshold; + // Check if the system has more than 4GB of physical memory by comparing the + // old space size with respective threshold value. + // + // Additionally, enable if there is already a process-wide CodeRange that + // has re-embedded builtins. + is_short_builtin_calls_enabled_ = (heap_.MaxOldGenerationSize() >= + kShortBuiltinCallsOldSpaceSizeThreshold); + if (COMPRESS_POINTERS_IN_SHARED_CAGE_BOOL) { + std::shared_ptr<CodeRange> code_range = + CodeRange::GetProcessWideCodeRange(); + if (code_range && code_range->embedded_blob_code_copy() != nullptr) { + is_short_builtin_calls_enabled_ = true; + } + } } // Create LocalIsolate/LocalHeap for the main thread and set state to Running. main_thread_local_isolate_.reset(new LocalIsolate(this, ThreadKind::kMain)); main_thread_local_heap()->Unpark(); + heap_.InitializeMainThreadLocalHeap(main_thread_local_heap()); + isolate_data_.external_reference_table()->Init(this); #if V8_ENABLE_WEBASSEMBLY - // Setup the wasm engine. - if (wasm_engine_ == nullptr) { - SetWasmEngine(wasm::WasmEngine::GetWasmEngine()); - } - DCHECK_NOT_NULL(wasm_engine_); + SetWasmEngine(wasm::WasmEngine::GetWasmEngine()); #endif // V8_ENABLE_WEBASSEMBLY if (setup_delegate_ == nullptr) { @@ -3721,11 +3833,11 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, } #if defined(V8_OS_WIN64) - if (win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange()) { - const base::AddressRegion& code_range = - heap()->memory_allocator()->code_range(); - void* start = reinterpret_cast<void*>(code_range.begin()); - size_t size_in_bytes = code_range.size(); + if (win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange() && + heap()->code_range()->AtomicIncrementUnwindInfoUseCount() == 0) { + const base::AddressRegion& code_region = heap()->code_region(); + void* start = reinterpret_cast<void*>(code_region.begin()); + size_t size_in_bytes = code_region.size(); win64_unwindinfo::RegisterNonABICompliantCodeRange(start, size_in_bytes); } #endif // V8_OS_WIN64 @@ -3845,6 +3957,7 @@ void Isolate::DumpAndResetStats() { wasm_engine()->DumpAndResetTurboStatistics(); } #endif // V8_ENABLE_WEBASSEMBLY +#if V8_RUNTIME_CALL_STATS if (V8_UNLIKELY(TracingFlags::runtime_stats.load(std::memory_order_relaxed) == v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE)) { counters()->worker_thread_runtime_call_stats()->AddToMainTable( @@ -3852,6 +3965,7 @@ void Isolate::DumpAndResetStats() { counters()->runtime_call_stats()->Print(); counters()->runtime_call_stats()->Reset(); } +#endif // V8_RUNTIME_CALL_STATS if (BasicBlockProfiler::Get()->HasData(this)) { StdoutStream out; BasicBlockProfiler::Get()->Print(out, this); @@ -4264,11 +4378,15 @@ MaybeHandle<FixedArray> Isolate::GetImportAssertionsFromArgument( Handle<JSReceiver> import_assertions_object_receiver = Handle<JSReceiver>::cast(import_assertions_object); - Handle<FixedArray> assertion_keys = - KeyAccumulator::GetKeys(import_assertions_object_receiver, - KeyCollectionMode::kOwnOnly, ENUMERABLE_STRINGS, - GetKeysConversion::kConvertToString) - .ToHandleChecked(); + Handle<FixedArray> assertion_keys; + if (!KeyAccumulator::GetKeys(import_assertions_object_receiver, + KeyCollectionMode::kOwnOnly, ENUMERABLE_STRINGS, + GetKeysConversion::kConvertToString) + .ToHandle(&assertion_keys)) { + // This happens if the assertions object is a Proxy whose ownKeys() or + // getOwnPropertyDescriptor() trap throws. + return MaybeHandle<FixedArray>(); + } // The assertions will be passed to the host in the form: [key1, // value1, key2, value2, ...]. @@ -4315,7 +4433,7 @@ void Isolate::SetHostImportModuleDynamicallyCallback( MaybeHandle<JSObject> Isolate::RunHostInitializeImportMetaObjectCallback( Handle<SourceTextModule> module) { - CHECK(module->import_meta().IsTheHole(this)); + CHECK(module->import_meta(kAcquireLoad).IsTheHole(this)); Handle<JSObject> import_meta = factory()->NewJSObjectWithNullProto(); if (host_initialize_import_meta_object_callback_ != nullptr) { v8::Local<v8::Context> api_context = @@ -4894,6 +5012,18 @@ MaybeLocal<v8::Context> Isolate::GetContextFromRecorderContextId( return result->second.Get(reinterpret_cast<v8::Isolate*>(this)); } +void Isolate::UpdateLongTaskStats() { + if (last_long_task_stats_counter_ != isolate_data_.long_task_stats_counter_) { + last_long_task_stats_counter_ = isolate_data_.long_task_stats_counter_; + long_task_stats_ = v8::metrics::LongTaskStats{}; + } +} + +v8::metrics::LongTaskStats* Isolate::GetCurrentLongTaskStats() { + UpdateLongTaskStats(); + return &long_task_stats_; +} + void Isolate::RemoveContextIdCallback(const v8::WeakCallbackInfo<void>& data) { Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate()); uintptr_t context_id = reinterpret_cast<uintptr_t>(data.GetParameter()); @@ -4970,5 +5100,54 @@ Address Isolate::store_to_stack_count_address(const char* function_name) { return reinterpret_cast<Address>(&map[name].second); } +void Isolate::AttachToSharedIsolate(Isolate* shared) { + DCHECK(shared->is_shared()); + DCHECK_NULL(shared_isolate_); + shared->AppendAsClientIsolate(this); + shared_isolate_ = shared; + heap()->InitSharedSpaces(); +} + +void Isolate::DetachFromSharedIsolate() { + DCHECK_NOT_NULL(shared_isolate_); + shared_isolate_->RemoveAsClientIsolate(this); + shared_isolate_ = nullptr; + heap()->DeinitSharedSpaces(); +} + +void Isolate::AppendAsClientIsolate(Isolate* client) { + base::MutexGuard guard(&client_isolate_mutex_); + + DCHECK_NULL(client->prev_client_isolate_); + DCHECK_NULL(client->next_client_isolate_); + DCHECK_NE(client_isolate_head_, client); + + if (client_isolate_head_) { + client_isolate_head_->prev_client_isolate_ = client; + } + + client->prev_client_isolate_ = nullptr; + client->next_client_isolate_ = client_isolate_head_; + + client_isolate_head_ = client; +} + +void Isolate::RemoveAsClientIsolate(Isolate* client) { + base::MutexGuard guard(&client_isolate_mutex_); + + if (client->next_client_isolate_) { + client->next_client_isolate_->prev_client_isolate_ = + client->prev_client_isolate_; + } + + if (client->prev_client_isolate_) { + client->prev_client_isolate_->next_client_isolate_ = + client->next_client_isolate_; + } else { + DCHECK_EQ(client_isolate_head_, client); + client_isolate_head_ = client->next_client_isolate_; + } +} + } // namespace internal } // namespace v8 |