11cb0ef41Sopenharmony_ci// Copyright 2012 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/handles/handles.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/api/api.h" 81cb0ef41Sopenharmony_ci#include "src/base/logging.h" 91cb0ef41Sopenharmony_ci#include "src/codegen/optimized-compilation-info.h" 101cb0ef41Sopenharmony_ci#include "src/execution/isolate.h" 111cb0ef41Sopenharmony_ci#include "src/execution/thread-id.h" 121cb0ef41Sopenharmony_ci#include "src/handles/maybe-handles.h" 131cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 141cb0ef41Sopenharmony_ci#include "src/roots/roots-inl.h" 151cb0ef41Sopenharmony_ci#include "src/utils/address-map.h" 161cb0ef41Sopenharmony_ci#include "src/utils/identity-map.h" 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_MAGLEV 191cb0ef41Sopenharmony_ci#include "src/maglev/maglev-concurrent-dispatcher.h" 201cb0ef41Sopenharmony_ci#endif // V8_ENABLE_MAGLEV 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci#ifdef DEBUG 231cb0ef41Sopenharmony_ci// For GetIsolateFromWritableHeapObject. 241cb0ef41Sopenharmony_ci#include "src/heap/heap-write-barrier-inl.h" 251cb0ef41Sopenharmony_ci#endif 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_cinamespace v8 { 281cb0ef41Sopenharmony_cinamespace internal { 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci// Handles should be trivially copyable so that they can be efficiently passed 311cb0ef41Sopenharmony_ci// by value. If they are not trivially copyable, they cannot be passed in 321cb0ef41Sopenharmony_ci// registers. 331cb0ef41Sopenharmony_ciASSERT_TRIVIALLY_COPYABLE(HandleBase); 341cb0ef41Sopenharmony_ciASSERT_TRIVIALLY_COPYABLE(Handle<Object>); 351cb0ef41Sopenharmony_ciASSERT_TRIVIALLY_COPYABLE(MaybeHandle<Object>); 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci#ifdef DEBUG 381cb0ef41Sopenharmony_cibool HandleBase::IsDereferenceAllowed() const { 391cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(location_); 401cb0ef41Sopenharmony_ci Object object(*location_); 411cb0ef41Sopenharmony_ci if (object.IsSmi()) return true; 421cb0ef41Sopenharmony_ci HeapObject heap_object = HeapObject::cast(object); 431cb0ef41Sopenharmony_ci if (IsReadOnlyHeapObject(heap_object)) return true; 441cb0ef41Sopenharmony_ci Isolate* isolate = GetIsolateFromWritableObject(heap_object); 451cb0ef41Sopenharmony_ci RootIndex root_index; 461cb0ef41Sopenharmony_ci if (isolate->roots_table().IsRootHandleLocation(location_, &root_index) && 471cb0ef41Sopenharmony_ci RootsTable::IsImmortalImmovable(root_index)) { 481cb0ef41Sopenharmony_ci return true; 491cb0ef41Sopenharmony_ci } 501cb0ef41Sopenharmony_ci if (isolate->IsBuiltinTableHandleLocation(location_)) return true; 511cb0ef41Sopenharmony_ci if (!AllowHandleDereference::IsAllowed()) return false; 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci // Allocations in the shared heap may be dereferenced by multiple threads. 541cb0ef41Sopenharmony_ci if (isolate->is_shared()) return true; 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci LocalHeap* local_heap = isolate->CurrentLocalHeap(); 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci // Local heap can't access handles when parked 591cb0ef41Sopenharmony_ci if (!local_heap->IsHandleDereferenceAllowed()) { 601cb0ef41Sopenharmony_ci StdoutStream{} << "Cannot dereference handle owned by " 611cb0ef41Sopenharmony_ci << "non-running local heap\n"; 621cb0ef41Sopenharmony_ci return false; 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci // We are pretty strict with handle dereferences on background threads: A 661cb0ef41Sopenharmony_ci // background local heap is only allowed to dereference its own local or 671cb0ef41Sopenharmony_ci // persistent handles. 681cb0ef41Sopenharmony_ci if (!local_heap->is_main_thread()) { 691cb0ef41Sopenharmony_ci // The current thread owns the handle and thus can dereference it. 701cb0ef41Sopenharmony_ci return local_heap->ContainsPersistentHandle(location_) || 711cb0ef41Sopenharmony_ci local_heap->ContainsLocalHandle(location_); 721cb0ef41Sopenharmony_ci } 731cb0ef41Sopenharmony_ci // If LocalHeap::Current() is null, we're on the main thread -- if we were to 741cb0ef41Sopenharmony_ci // check main thread HandleScopes here, we should additionally check the 751cb0ef41Sopenharmony_ci // main-thread LocalHeap. 761cb0ef41Sopenharmony_ci DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci // TODO(leszeks): Check if the main thread owns this handle. 791cb0ef41Sopenharmony_ci return true; 801cb0ef41Sopenharmony_ci} 811cb0ef41Sopenharmony_ci#endif 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ciint HandleScope::NumberOfHandles(Isolate* isolate) { 841cb0ef41Sopenharmony_ci HandleScopeImplementer* impl = isolate->handle_scope_implementer(); 851cb0ef41Sopenharmony_ci int n = static_cast<int>(impl->blocks()->size()); 861cb0ef41Sopenharmony_ci if (n == 0) return 0; 871cb0ef41Sopenharmony_ci return ((n - 1) * kHandleBlockSize) + 881cb0ef41Sopenharmony_ci static_cast<int>( 891cb0ef41Sopenharmony_ci (isolate->handle_scope_data()->next - impl->blocks()->back())); 901cb0ef41Sopenharmony_ci} 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ciAddress* HandleScope::Extend(Isolate* isolate) { 931cb0ef41Sopenharmony_ci HandleScopeData* current = isolate->handle_scope_data(); 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci Address* result = current->next; 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci DCHECK(result == current->limit); 981cb0ef41Sopenharmony_ci // Make sure there's at least one scope on the stack and that the 991cb0ef41Sopenharmony_ci // top of the scope stack isn't a barrier. 1001cb0ef41Sopenharmony_ci if (!Utils::ApiCheck(current->level != current->sealed_level, 1011cb0ef41Sopenharmony_ci "v8::HandleScope::CreateHandle()", 1021cb0ef41Sopenharmony_ci "Cannot create a handle without a HandleScope")) { 1031cb0ef41Sopenharmony_ci return nullptr; 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci HandleScopeImplementer* impl = isolate->handle_scope_implementer(); 1061cb0ef41Sopenharmony_ci // If there's more room in the last block, we use that. This is used 1071cb0ef41Sopenharmony_ci // for fast creation of scopes after scope barriers. 1081cb0ef41Sopenharmony_ci if (!impl->blocks()->empty()) { 1091cb0ef41Sopenharmony_ci Address* limit = &impl->blocks()->back()[kHandleBlockSize]; 1101cb0ef41Sopenharmony_ci if (current->limit != limit) { 1111cb0ef41Sopenharmony_ci current->limit = limit; 1121cb0ef41Sopenharmony_ci DCHECK_LT(limit - current->next, kHandleBlockSize); 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci } 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci // If we still haven't found a slot for the handle, we extend the 1171cb0ef41Sopenharmony_ci // current handle scope by allocating a new handle block. 1181cb0ef41Sopenharmony_ci if (result == current->limit) { 1191cb0ef41Sopenharmony_ci // If there's a spare block, use it for growing the current scope. 1201cb0ef41Sopenharmony_ci result = impl->GetSpareOrNewBlock(); 1211cb0ef41Sopenharmony_ci // Add the extension to the global list of blocks, but count the 1221cb0ef41Sopenharmony_ci // extension as part of the current scope. 1231cb0ef41Sopenharmony_ci impl->blocks()->push_back(result); 1241cb0ef41Sopenharmony_ci current->limit = &result[kHandleBlockSize]; 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci return result; 1281cb0ef41Sopenharmony_ci} 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_civoid HandleScope::DeleteExtensions(Isolate* isolate) { 1311cb0ef41Sopenharmony_ci HandleScopeData* current = isolate->handle_scope_data(); 1321cb0ef41Sopenharmony_ci isolate->handle_scope_implementer()->DeleteExtensions(current->limit); 1331cb0ef41Sopenharmony_ci} 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci#ifdef ENABLE_HANDLE_ZAPPING 1361cb0ef41Sopenharmony_civoid HandleScope::ZapRange(Address* start, Address* end) { 1371cb0ef41Sopenharmony_ci DCHECK_LE(end - start, kHandleBlockSize); 1381cb0ef41Sopenharmony_ci for (Address* p = start; p != end; p++) { 1391cb0ef41Sopenharmony_ci *p = static_cast<Address>(kHandleZapValue); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci} 1421cb0ef41Sopenharmony_ci#endif 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ciAddress HandleScope::current_level_address(Isolate* isolate) { 1451cb0ef41Sopenharmony_ci return reinterpret_cast<Address>(&isolate->handle_scope_data()->level); 1461cb0ef41Sopenharmony_ci} 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ciAddress HandleScope::current_next_address(Isolate* isolate) { 1491cb0ef41Sopenharmony_ci return reinterpret_cast<Address>(&isolate->handle_scope_data()->next); 1501cb0ef41Sopenharmony_ci} 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ciAddress HandleScope::current_limit_address(Isolate* isolate) { 1531cb0ef41Sopenharmony_ci return reinterpret_cast<Address>(&isolate->handle_scope_data()->limit); 1541cb0ef41Sopenharmony_ci} 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ciCanonicalHandleScope::CanonicalHandleScope(Isolate* isolate, Zone* zone) 1571cb0ef41Sopenharmony_ci : zone_(zone == nullptr ? new Zone(isolate->allocator(), ZONE_NAME) : zone), 1581cb0ef41Sopenharmony_ci isolate_(isolate) { 1591cb0ef41Sopenharmony_ci HandleScopeData* handle_scope_data = isolate_->handle_scope_data(); 1601cb0ef41Sopenharmony_ci prev_canonical_scope_ = handle_scope_data->canonical_scope; 1611cb0ef41Sopenharmony_ci handle_scope_data->canonical_scope = this; 1621cb0ef41Sopenharmony_ci root_index_map_ = new RootIndexMap(isolate); 1631cb0ef41Sopenharmony_ci identity_map_ = std::make_unique<CanonicalHandlesMap>( 1641cb0ef41Sopenharmony_ci isolate->heap(), ZoneAllocationPolicy(zone_)); 1651cb0ef41Sopenharmony_ci canonical_level_ = handle_scope_data->level; 1661cb0ef41Sopenharmony_ci} 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ciCanonicalHandleScope::~CanonicalHandleScope() { 1691cb0ef41Sopenharmony_ci delete root_index_map_; 1701cb0ef41Sopenharmony_ci // Note: both the identity_map_ (zone-allocated) and the zone_ itself may 1711cb0ef41Sopenharmony_ci // have custom ownership semantics, controlled by subclasses. For example, in 1721cb0ef41Sopenharmony_ci // case of external ownership, the subclass destructor may 'steal' both by 1731cb0ef41Sopenharmony_ci // resetting the identity map pointer and nulling the zone. 1741cb0ef41Sopenharmony_ci identity_map_.reset(); 1751cb0ef41Sopenharmony_ci delete zone_; 1761cb0ef41Sopenharmony_ci isolate_->handle_scope_data()->canonical_scope = prev_canonical_scope_; 1771cb0ef41Sopenharmony_ci} 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ciAddress* CanonicalHandleScope::Lookup(Address object) { 1801cb0ef41Sopenharmony_ci DCHECK_LE(canonical_level_, isolate_->handle_scope_data()->level); 1811cb0ef41Sopenharmony_ci if (isolate_->handle_scope_data()->level != canonical_level_) { 1821cb0ef41Sopenharmony_ci // We are in an inner handle scope. Do not canonicalize since we will leave 1831cb0ef41Sopenharmony_ci // this handle scope while still being in the canonical scope. 1841cb0ef41Sopenharmony_ci return HandleScope::CreateHandle(isolate_, object); 1851cb0ef41Sopenharmony_ci } 1861cb0ef41Sopenharmony_ci if (Internals::HasHeapObjectTag(object)) { 1871cb0ef41Sopenharmony_ci RootIndex root_index; 1881cb0ef41Sopenharmony_ci if (root_index_map_->Lookup(object, &root_index)) { 1891cb0ef41Sopenharmony_ci return isolate_->root_handle(root_index).location(); 1901cb0ef41Sopenharmony_ci } 1911cb0ef41Sopenharmony_ci } 1921cb0ef41Sopenharmony_ci auto find_result = identity_map_->FindOrInsert(Object(object)); 1931cb0ef41Sopenharmony_ci if (!find_result.already_exists) { 1941cb0ef41Sopenharmony_ci // Allocate new handle location. 1951cb0ef41Sopenharmony_ci *find_result.entry = HandleScope::CreateHandle(isolate_, object); 1961cb0ef41Sopenharmony_ci } 1971cb0ef41Sopenharmony_ci return *find_result.entry; 1981cb0ef41Sopenharmony_ci} 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_cistd::unique_ptr<CanonicalHandlesMap> 2011cb0ef41Sopenharmony_ciCanonicalHandleScope::DetachCanonicalHandles() { 2021cb0ef41Sopenharmony_ci return std::move(identity_map_); 2031cb0ef41Sopenharmony_ci} 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_citemplate <class CompilationInfoT> 2061cb0ef41Sopenharmony_ciCanonicalHandleScopeForOptimization<CompilationInfoT>:: 2071cb0ef41Sopenharmony_ci CanonicalHandleScopeForOptimization(Isolate* isolate, 2081cb0ef41Sopenharmony_ci CompilationInfoT* info) 2091cb0ef41Sopenharmony_ci : CanonicalHandleScope(isolate, info->zone()), info_(info) {} 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_citemplate <class CompilationInfoT> 2121cb0ef41Sopenharmony_ciCanonicalHandleScopeForOptimization< 2131cb0ef41Sopenharmony_ci CompilationInfoT>::~CanonicalHandleScopeForOptimization() { 2141cb0ef41Sopenharmony_ci // We created the identity map on the compilation info's zone(). Pass 2151cb0ef41Sopenharmony_ci // ownership to the compilation info which is responsible for the disposal. 2161cb0ef41Sopenharmony_ci info_->set_canonical_handles(DetachCanonicalHandles()); 2171cb0ef41Sopenharmony_ci zone_ = nullptr; // We don't own the zone, null it. 2181cb0ef41Sopenharmony_ci} 2191cb0ef41Sopenharmony_ci 2201cb0ef41Sopenharmony_citemplate class CanonicalHandleScopeForOptimization<OptimizedCompilationInfo>; 2211cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_MAGLEV 2221cb0ef41Sopenharmony_citemplate class CanonicalHandleScopeForOptimization< 2231cb0ef41Sopenharmony_ci maglev::ExportedMaglevCompilationInfo>; 2241cb0ef41Sopenharmony_ci#endif // V8_ENABLE_MAGLEV 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci} // namespace internal 2271cb0ef41Sopenharmony_ci} // namespace v8 228