11cb0ef41Sopenharmony_ci// Copyright 2018 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#ifndef V8_COMPILER_JS_HEAP_BROKER_H_ 61cb0ef41Sopenharmony_ci#define V8_COMPILER_JS_HEAP_BROKER_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include "src/base/compiler-specific.h" 91cb0ef41Sopenharmony_ci#include "src/base/optional.h" 101cb0ef41Sopenharmony_ci#include "src/base/platform/mutex.h" 111cb0ef41Sopenharmony_ci#include "src/common/globals.h" 121cb0ef41Sopenharmony_ci#include "src/compiler/access-info.h" 131cb0ef41Sopenharmony_ci#include "src/compiler/feedback-source.h" 141cb0ef41Sopenharmony_ci#include "src/compiler/globals.h" 151cb0ef41Sopenharmony_ci#include "src/compiler/heap-refs.h" 161cb0ef41Sopenharmony_ci#include "src/compiler/processed-feedback.h" 171cb0ef41Sopenharmony_ci#include "src/compiler/refs-map.h" 181cb0ef41Sopenharmony_ci#include "src/execution/local-isolate.h" 191cb0ef41Sopenharmony_ci#include "src/handles/handles.h" 201cb0ef41Sopenharmony_ci#include "src/handles/persistent-handles.h" 211cb0ef41Sopenharmony_ci#include "src/heap/local-heap.h" 221cb0ef41Sopenharmony_ci#include "src/heap/parked-scope.h" 231cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-array-iterator.h" 241cb0ef41Sopenharmony_ci#include "src/objects/code-kind.h" 251cb0ef41Sopenharmony_ci#include "src/objects/feedback-vector.h" 261cb0ef41Sopenharmony_ci#include "src/objects/function-kind.h" 271cb0ef41Sopenharmony_ci#include "src/objects/objects.h" 281cb0ef41Sopenharmony_ci#include "src/utils/address-map.h" 291cb0ef41Sopenharmony_ci#include "src/utils/identity-map.h" 301cb0ef41Sopenharmony_ci#include "src/utils/ostreams.h" 311cb0ef41Sopenharmony_ci#include "src/zone/zone-containers.h" 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_cinamespace v8 { 341cb0ef41Sopenharmony_cinamespace internal { 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_cinamespace maglev { 371cb0ef41Sopenharmony_ciclass MaglevCompilationInfo; 381cb0ef41Sopenharmony_ci} 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_cinamespace compiler { 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciclass ObjectRef; 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_cistd::ostream& operator<<(std::ostream& os, const ObjectRef& ref); 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci#define TRACE_BROKER(broker, x) \ 471cb0ef41Sopenharmony_ci do { \ 481cb0ef41Sopenharmony_ci if (broker->tracing_enabled() && FLAG_trace_heap_broker_verbose) \ 491cb0ef41Sopenharmony_ci StdoutStream{} << broker->Trace() << x << '\n'; \ 501cb0ef41Sopenharmony_ci } while (false) 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci#define TRACE_BROKER_MEMORY(broker, x) \ 531cb0ef41Sopenharmony_ci do { \ 541cb0ef41Sopenharmony_ci if (broker->tracing_enabled() && FLAG_trace_heap_broker_memory) \ 551cb0ef41Sopenharmony_ci StdoutStream{} << broker->Trace() << x << std::endl; \ 561cb0ef41Sopenharmony_ci } while (false) 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci#define TRACE_BROKER_MISSING(broker, x) \ 591cb0ef41Sopenharmony_ci do { \ 601cb0ef41Sopenharmony_ci if (broker->tracing_enabled()) \ 611cb0ef41Sopenharmony_ci StdoutStream{} << broker->Trace() << "Missing " << x << " (" << __FILE__ \ 621cb0ef41Sopenharmony_ci << ":" << __LINE__ << ")" << std::endl; \ 631cb0ef41Sopenharmony_ci } while (false) 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_cistruct PropertyAccessTarget { 661cb0ef41Sopenharmony_ci MapRef map; 671cb0ef41Sopenharmony_ci NameRef name; 681cb0ef41Sopenharmony_ci AccessMode mode; 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci struct Hash { 711cb0ef41Sopenharmony_ci size_t operator()(const PropertyAccessTarget& pair) const { 721cb0ef41Sopenharmony_ci return base::hash_combine( 731cb0ef41Sopenharmony_ci base::hash_combine(pair.map.object().address(), 741cb0ef41Sopenharmony_ci pair.name.object().address()), 751cb0ef41Sopenharmony_ci static_cast<int>(pair.mode)); 761cb0ef41Sopenharmony_ci } 771cb0ef41Sopenharmony_ci }; 781cb0ef41Sopenharmony_ci struct Equal { 791cb0ef41Sopenharmony_ci bool operator()(const PropertyAccessTarget& lhs, 801cb0ef41Sopenharmony_ci const PropertyAccessTarget& rhs) const { 811cb0ef41Sopenharmony_ci return lhs.map.equals(rhs.map) && lhs.name.equals(rhs.name) && 821cb0ef41Sopenharmony_ci lhs.mode == rhs.mode; 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci }; 851cb0ef41Sopenharmony_ci}; 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_cienum GetOrCreateDataFlag { 881cb0ef41Sopenharmony_ci // If set, a failure to create the data object results in a crash. 891cb0ef41Sopenharmony_ci kCrashOnError = 1 << 0, 901cb0ef41Sopenharmony_ci // If set, data construction assumes that the given object is protected by 911cb0ef41Sopenharmony_ci // a memory fence (e.g. acquire-release) and thus fields required for 921cb0ef41Sopenharmony_ci // construction (like Object::map) are safe to read. The protection can 931cb0ef41Sopenharmony_ci // extend to some other situations as well. 941cb0ef41Sopenharmony_ci kAssumeMemoryFence = 1 << 1, 951cb0ef41Sopenharmony_ci}; 961cb0ef41Sopenharmony_ciusing GetOrCreateDataFlags = base::Flags<GetOrCreateDataFlag>; 971cb0ef41Sopenharmony_ciDEFINE_OPERATORS_FOR_FLAGS(GetOrCreateDataFlags) 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE JSHeapBroker { 1001cb0ef41Sopenharmony_ci public: 1011cb0ef41Sopenharmony_ci JSHeapBroker(Isolate* isolate, Zone* broker_zone, bool tracing_enabled, 1021cb0ef41Sopenharmony_ci CodeKind code_kind); 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci // For use only in tests, sets default values for some arguments. Avoids 1051cb0ef41Sopenharmony_ci // churn when new flags are added. 1061cb0ef41Sopenharmony_ci JSHeapBroker(Isolate* isolate, Zone* broker_zone) 1071cb0ef41Sopenharmony_ci : JSHeapBroker(isolate, broker_zone, FLAG_trace_heap_broker, 1081cb0ef41Sopenharmony_ci CodeKind::TURBOFAN) {} 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci ~JSHeapBroker(); 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci // The compilation target's native context. We need the setter because at 1131cb0ef41Sopenharmony_ci // broker construction time we don't yet have the canonical handle. 1141cb0ef41Sopenharmony_ci NativeContextRef target_native_context() const { 1151cb0ef41Sopenharmony_ci return target_native_context_.value(); 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci void SetTargetNativeContextRef(Handle<NativeContext> native_context); 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci void InitializeAndStartSerializing(); 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci Isolate* isolate() const { return isolate_; } 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci // The pointer compression cage base value used for decompression of all 1241cb0ef41Sopenharmony_ci // tagged values except references to Code objects. 1251cb0ef41Sopenharmony_ci PtrComprCageBase cage_base() const { 1261cb0ef41Sopenharmony_ci#if V8_COMPRESS_POINTERS 1271cb0ef41Sopenharmony_ci return cage_base_; 1281cb0ef41Sopenharmony_ci#else 1291cb0ef41Sopenharmony_ci return PtrComprCageBase{}; 1301cb0ef41Sopenharmony_ci#endif // V8_COMPRESS_POINTERS 1311cb0ef41Sopenharmony_ci } 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci Zone* zone() const { return zone_; } 1341cb0ef41Sopenharmony_ci bool tracing_enabled() const { return tracing_enabled_; } 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci NexusConfig feedback_nexus_config() const { 1371cb0ef41Sopenharmony_ci return IsMainThread() ? NexusConfig::FromMainThread(isolate()) 1381cb0ef41Sopenharmony_ci : NexusConfig::FromBackgroundThread( 1391cb0ef41Sopenharmony_ci isolate(), local_isolate()->heap()); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci enum BrokerMode { kDisabled, kSerializing, kSerialized, kRetired }; 1431cb0ef41Sopenharmony_ci BrokerMode mode() const { return mode_; } 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci void StopSerializing(); 1461cb0ef41Sopenharmony_ci void Retire(); 1471cb0ef41Sopenharmony_ci bool SerializingAllowed() const; 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci // Remember the local isolate and initialize its local heap with the 1501cb0ef41Sopenharmony_ci // persistent and canonical handles provided by {info}. 1511cb0ef41Sopenharmony_ci void AttachLocalIsolate(OptimizedCompilationInfo* info, 1521cb0ef41Sopenharmony_ci LocalIsolate* local_isolate); 1531cb0ef41Sopenharmony_ci // Forget about the local isolate and pass the persistent and canonical 1541cb0ef41Sopenharmony_ci // handles provided back to {info}. {info} is responsible for disposing of 1551cb0ef41Sopenharmony_ci // them. 1561cb0ef41Sopenharmony_ci void DetachLocalIsolate(OptimizedCompilationInfo* info); 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci // TODO(v8:7700): Refactor this once the broker is no longer 1591cb0ef41Sopenharmony_ci // Turbofan-specific. 1601cb0ef41Sopenharmony_ci void AttachLocalIsolateForMaglev(maglev::MaglevCompilationInfo* info, 1611cb0ef41Sopenharmony_ci LocalIsolate* local_isolate); 1621cb0ef41Sopenharmony_ci void DetachLocalIsolateForMaglev(maglev::MaglevCompilationInfo* info); 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ci bool StackHasOverflowed() const; 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci#ifdef DEBUG 1671cb0ef41Sopenharmony_ci void PrintRefsAnalysis() const; 1681cb0ef41Sopenharmony_ci#endif // DEBUG 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci // Returns the handle from root index table for read only heap objects. 1711cb0ef41Sopenharmony_ci Handle<Object> GetRootHandle(Object object); 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci // Never returns nullptr. 1741cb0ef41Sopenharmony_ci ObjectData* GetOrCreateData(Handle<Object> object, 1751cb0ef41Sopenharmony_ci GetOrCreateDataFlags flags = {}); 1761cb0ef41Sopenharmony_ci ObjectData* GetOrCreateData(Object object, GetOrCreateDataFlags flags = {}); 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci // Gets data only if we have it. However, thin wrappers will be created for 1791cb0ef41Sopenharmony_ci // smis, read-only objects and never-serialized objects. 1801cb0ef41Sopenharmony_ci ObjectData* TryGetOrCreateData(Handle<Object> object, 1811cb0ef41Sopenharmony_ci GetOrCreateDataFlags flags = {}); 1821cb0ef41Sopenharmony_ci ObjectData* TryGetOrCreateData(Object object, 1831cb0ef41Sopenharmony_ci GetOrCreateDataFlags flags = {}); 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci // Check if {object} is any native context's %ArrayPrototype% or 1861cb0ef41Sopenharmony_ci // %ObjectPrototype%. 1871cb0ef41Sopenharmony_ci bool IsArrayOrObjectPrototype(const JSObjectRef& object) const; 1881cb0ef41Sopenharmony_ci bool IsArrayOrObjectPrototype(Handle<JSObject> object) const; 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci bool HasFeedback(FeedbackSource const& source) const; 1911cb0ef41Sopenharmony_ci void SetFeedback(FeedbackSource const& source, 1921cb0ef41Sopenharmony_ci ProcessedFeedback const* feedback); 1931cb0ef41Sopenharmony_ci FeedbackSlotKind GetFeedbackSlotKind(FeedbackSource const& source) const; 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_ci ElementAccessFeedback const& ProcessFeedbackMapsForElementAccess( 1961cb0ef41Sopenharmony_ci ZoneVector<MapRef>& maps, KeyedAccessMode const& keyed_mode, 1971cb0ef41Sopenharmony_ci FeedbackSlotKind slot_kind); 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci // Binary, comparison and for-in hints can be fully expressed via 2001cb0ef41Sopenharmony_ci // an enum. Insufficient feedback is signaled by <Hint enum>::kNone. 2011cb0ef41Sopenharmony_ci BinaryOperationHint GetFeedbackForBinaryOperation( 2021cb0ef41Sopenharmony_ci FeedbackSource const& source); 2031cb0ef41Sopenharmony_ci CompareOperationHint GetFeedbackForCompareOperation( 2041cb0ef41Sopenharmony_ci FeedbackSource const& source); 2051cb0ef41Sopenharmony_ci ForInHint GetFeedbackForForIn(FeedbackSource const& source); 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci ProcessedFeedback const& GetFeedbackForCall(FeedbackSource const& source); 2081cb0ef41Sopenharmony_ci ProcessedFeedback const& GetFeedbackForGlobalAccess( 2091cb0ef41Sopenharmony_ci FeedbackSource const& source); 2101cb0ef41Sopenharmony_ci ProcessedFeedback const& GetFeedbackForInstanceOf( 2111cb0ef41Sopenharmony_ci FeedbackSource const& source); 2121cb0ef41Sopenharmony_ci ProcessedFeedback const& GetFeedbackForArrayOrObjectLiteral( 2131cb0ef41Sopenharmony_ci FeedbackSource const& source); 2141cb0ef41Sopenharmony_ci ProcessedFeedback const& GetFeedbackForRegExpLiteral( 2151cb0ef41Sopenharmony_ci FeedbackSource const& source); 2161cb0ef41Sopenharmony_ci ProcessedFeedback const& GetFeedbackForTemplateObject( 2171cb0ef41Sopenharmony_ci FeedbackSource const& source); 2181cb0ef41Sopenharmony_ci ProcessedFeedback const& GetFeedbackForPropertyAccess( 2191cb0ef41Sopenharmony_ci FeedbackSource const& source, AccessMode mode, 2201cb0ef41Sopenharmony_ci base::Optional<NameRef> static_name); 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci ProcessedFeedback const& ProcessFeedbackForBinaryOperation( 2231cb0ef41Sopenharmony_ci FeedbackSource const& source); 2241cb0ef41Sopenharmony_ci ProcessedFeedback const& ProcessFeedbackForCompareOperation( 2251cb0ef41Sopenharmony_ci FeedbackSource const& source); 2261cb0ef41Sopenharmony_ci ProcessedFeedback const& ProcessFeedbackForForIn( 2271cb0ef41Sopenharmony_ci FeedbackSource const& source); 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci bool FeedbackIsInsufficient(FeedbackSource const& source) const; 2301cb0ef41Sopenharmony_ci 2311cb0ef41Sopenharmony_ci base::Optional<NameRef> GetNameFeedback(FeedbackNexus const& nexus); 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci PropertyAccessInfo GetPropertyAccessInfo( 2341cb0ef41Sopenharmony_ci MapRef map, NameRef name, AccessMode access_mode, 2351cb0ef41Sopenharmony_ci CompilationDependencies* dependencies); 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci StringRef GetTypedArrayStringTag(ElementsKind kind); 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci bool IsMainThread() const { 2401cb0ef41Sopenharmony_ci return local_isolate() == nullptr || local_isolate()->is_main_thread(); 2411cb0ef41Sopenharmony_ci } 2421cb0ef41Sopenharmony_ci 2431cb0ef41Sopenharmony_ci LocalIsolate* local_isolate() const { return local_isolate_; } 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci // TODO(jgruber): Consider always having local_isolate_ set to a real value. 2461cb0ef41Sopenharmony_ci // This seems not entirely trivial since we currently reset local_isolate_ to 2471cb0ef41Sopenharmony_ci // nullptr at some point in the JSHeapBroker lifecycle. 2481cb0ef41Sopenharmony_ci LocalIsolate* local_isolate_or_isolate() const { 2491cb0ef41Sopenharmony_ci return local_isolate() != nullptr ? local_isolate() 2501cb0ef41Sopenharmony_ci : isolate()->AsLocalIsolate(); 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci // Return the corresponding canonical persistent handle for {object}. Create 2541cb0ef41Sopenharmony_ci // one if it does not exist. 2551cb0ef41Sopenharmony_ci // If we have the canonical map, we can create the canonical & persistent 2561cb0ef41Sopenharmony_ci // handle through it. This commonly happens during the Execute phase. 2571cb0ef41Sopenharmony_ci // If we don't, that means we are calling this method from serialization. If 2581cb0ef41Sopenharmony_ci // that happens, we should be inside a canonical and a persistent handle 2591cb0ef41Sopenharmony_ci // scope. Then, we would just use the regular handle creation. 2601cb0ef41Sopenharmony_ci template <typename T> 2611cb0ef41Sopenharmony_ci Handle<T> CanonicalPersistentHandle(T object) { 2621cb0ef41Sopenharmony_ci if (canonical_handles_) { 2631cb0ef41Sopenharmony_ci Address address = object.ptr(); 2641cb0ef41Sopenharmony_ci if (Internals::HasHeapObjectTag(address)) { 2651cb0ef41Sopenharmony_ci RootIndex root_index; 2661cb0ef41Sopenharmony_ci if (root_index_map_.Lookup(address, &root_index)) { 2671cb0ef41Sopenharmony_ci return Handle<T>(isolate_->root_handle(root_index).location()); 2681cb0ef41Sopenharmony_ci } 2691cb0ef41Sopenharmony_ci } 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci Object obj(address); 2721cb0ef41Sopenharmony_ci auto find_result = canonical_handles_->FindOrInsert(obj); 2731cb0ef41Sopenharmony_ci if (!find_result.already_exists) { 2741cb0ef41Sopenharmony_ci // Allocate new PersistentHandle if one wasn't created before. 2751cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(local_isolate()); 2761cb0ef41Sopenharmony_ci *find_result.entry = 2771cb0ef41Sopenharmony_ci local_isolate()->heap()->NewPersistentHandle(obj).location(); 2781cb0ef41Sopenharmony_ci } 2791cb0ef41Sopenharmony_ci return Handle<T>(*find_result.entry); 2801cb0ef41Sopenharmony_ci } else { 2811cb0ef41Sopenharmony_ci return Handle<T>(object, isolate()); 2821cb0ef41Sopenharmony_ci } 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci template <typename T> 2861cb0ef41Sopenharmony_ci Handle<T> CanonicalPersistentHandle(Handle<T> object) { 2871cb0ef41Sopenharmony_ci if (object.is_null()) return object; // Can't deref a null handle. 2881cb0ef41Sopenharmony_ci return CanonicalPersistentHandle<T>(*object); 2891cb0ef41Sopenharmony_ci } 2901cb0ef41Sopenharmony_ci 2911cb0ef41Sopenharmony_ci // Find the corresponding handle in the CanonicalHandlesMap. The entry must be 2921cb0ef41Sopenharmony_ci // found. 2931cb0ef41Sopenharmony_ci template <typename T> 2941cb0ef41Sopenharmony_ci Handle<T> FindCanonicalPersistentHandleForTesting(Object object) { 2951cb0ef41Sopenharmony_ci Address** entry = canonical_handles_->Find(object); 2961cb0ef41Sopenharmony_ci return Handle<T>(*entry); 2971cb0ef41Sopenharmony_ci } 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci // Set the persistent handles and copy the canonical handles over to the 3001cb0ef41Sopenharmony_ci // JSHeapBroker. 3011cb0ef41Sopenharmony_ci void SetPersistentAndCopyCanonicalHandlesForTesting( 3021cb0ef41Sopenharmony_ci std::unique_ptr<PersistentHandles> persistent_handles, 3031cb0ef41Sopenharmony_ci std::unique_ptr<CanonicalHandlesMap> canonical_handles); 3041cb0ef41Sopenharmony_ci std::string Trace() const; 3051cb0ef41Sopenharmony_ci void IncrementTracingIndentation(); 3061cb0ef41Sopenharmony_ci void DecrementTracingIndentation(); 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci // Locks {mutex} through the duration of this scope iff it is the first 3091cb0ef41Sopenharmony_ci // occurrence. This is done to have a recursive shared lock on {mutex}. 3101cb0ef41Sopenharmony_ci class V8_NODISCARD RecursiveSharedMutexGuardIfNeeded { 3111cb0ef41Sopenharmony_ci protected: 3121cb0ef41Sopenharmony_ci RecursiveSharedMutexGuardIfNeeded(LocalIsolate* local_isolate, 3131cb0ef41Sopenharmony_ci base::SharedMutex* mutex, 3141cb0ef41Sopenharmony_ci int* mutex_depth_address) 3151cb0ef41Sopenharmony_ci : mutex_depth_address_(mutex_depth_address), 3161cb0ef41Sopenharmony_ci initial_mutex_depth_(*mutex_depth_address_), 3171cb0ef41Sopenharmony_ci shared_mutex_guard_(local_isolate, mutex, initial_mutex_depth_ == 0) { 3181cb0ef41Sopenharmony_ci (*mutex_depth_address_)++; 3191cb0ef41Sopenharmony_ci } 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ci ~RecursiveSharedMutexGuardIfNeeded() { 3221cb0ef41Sopenharmony_ci DCHECK_GE((*mutex_depth_address_), 1); 3231cb0ef41Sopenharmony_ci (*mutex_depth_address_)--; 3241cb0ef41Sopenharmony_ci DCHECK_EQ(initial_mutex_depth_, (*mutex_depth_address_)); 3251cb0ef41Sopenharmony_ci } 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_ci private: 3281cb0ef41Sopenharmony_ci int* const mutex_depth_address_; 3291cb0ef41Sopenharmony_ci const int initial_mutex_depth_; 3301cb0ef41Sopenharmony_ci ParkedSharedMutexGuardIf<base::kShared> shared_mutex_guard_; 3311cb0ef41Sopenharmony_ci }; 3321cb0ef41Sopenharmony_ci 3331cb0ef41Sopenharmony_ci class MapUpdaterGuardIfNeeded final 3341cb0ef41Sopenharmony_ci : public RecursiveSharedMutexGuardIfNeeded { 3351cb0ef41Sopenharmony_ci public: 3361cb0ef41Sopenharmony_ci explicit MapUpdaterGuardIfNeeded(JSHeapBroker* broker) 3371cb0ef41Sopenharmony_ci : RecursiveSharedMutexGuardIfNeeded( 3381cb0ef41Sopenharmony_ci broker->local_isolate_or_isolate(), 3391cb0ef41Sopenharmony_ci broker->isolate()->map_updater_access(), 3401cb0ef41Sopenharmony_ci &broker->map_updater_mutex_depth_) {} 3411cb0ef41Sopenharmony_ci }; 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci class BoilerplateMigrationGuardIfNeeded final 3441cb0ef41Sopenharmony_ci : public RecursiveSharedMutexGuardIfNeeded { 3451cb0ef41Sopenharmony_ci public: 3461cb0ef41Sopenharmony_ci explicit BoilerplateMigrationGuardIfNeeded(JSHeapBroker* broker) 3471cb0ef41Sopenharmony_ci : RecursiveSharedMutexGuardIfNeeded( 3481cb0ef41Sopenharmony_ci broker->local_isolate_or_isolate(), 3491cb0ef41Sopenharmony_ci broker->isolate()->boilerplate_migration_access(), 3501cb0ef41Sopenharmony_ci &broker->boilerplate_migration_mutex_depth_) {} 3511cb0ef41Sopenharmony_ci }; 3521cb0ef41Sopenharmony_ci 3531cb0ef41Sopenharmony_ci // If this returns false, the object is guaranteed to be fully initialized and 3541cb0ef41Sopenharmony_ci // thus safe to read from a memory safety perspective. The converse does not 3551cb0ef41Sopenharmony_ci // necessarily hold. 3561cb0ef41Sopenharmony_ci bool ObjectMayBeUninitialized(Handle<Object> object) const; 3571cb0ef41Sopenharmony_ci bool ObjectMayBeUninitialized(Object object) const; 3581cb0ef41Sopenharmony_ci bool ObjectMayBeUninitialized(HeapObject object) const; 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ci void set_dependencies(CompilationDependencies* dependencies) { 3611cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(dependencies); 3621cb0ef41Sopenharmony_ci DCHECK_NULL(dependencies_); 3631cb0ef41Sopenharmony_ci dependencies_ = dependencies; 3641cb0ef41Sopenharmony_ci } 3651cb0ef41Sopenharmony_ci CompilationDependencies* dependencies() const { 3661cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(dependencies_); 3671cb0ef41Sopenharmony_ci return dependencies_; 3681cb0ef41Sopenharmony_ci } 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ci private: 3711cb0ef41Sopenharmony_ci friend class HeapObjectRef; 3721cb0ef41Sopenharmony_ci friend class ObjectRef; 3731cb0ef41Sopenharmony_ci friend class ObjectData; 3741cb0ef41Sopenharmony_ci friend class PropertyCellData; 3751cb0ef41Sopenharmony_ci 3761cb0ef41Sopenharmony_ci ProcessedFeedback const& GetFeedback(FeedbackSource const& source) const; 3771cb0ef41Sopenharmony_ci const ProcessedFeedback& NewInsufficientFeedback(FeedbackSlotKind kind) const; 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ci // Bottleneck FeedbackNexus access here, for storage in the broker 3801cb0ef41Sopenharmony_ci // or on-the-fly usage elsewhere in the compiler. 3811cb0ef41Sopenharmony_ci ProcessedFeedback const& ReadFeedbackForArrayOrObjectLiteral( 3821cb0ef41Sopenharmony_ci FeedbackSource const& source); 3831cb0ef41Sopenharmony_ci ProcessedFeedback const& ReadFeedbackForBinaryOperation( 3841cb0ef41Sopenharmony_ci FeedbackSource const& source) const; 3851cb0ef41Sopenharmony_ci ProcessedFeedback const& ReadFeedbackForCall(FeedbackSource const& source); 3861cb0ef41Sopenharmony_ci ProcessedFeedback const& ReadFeedbackForCompareOperation( 3871cb0ef41Sopenharmony_ci FeedbackSource const& source) const; 3881cb0ef41Sopenharmony_ci ProcessedFeedback const& ReadFeedbackForForIn( 3891cb0ef41Sopenharmony_ci FeedbackSource const& source) const; 3901cb0ef41Sopenharmony_ci ProcessedFeedback const& ReadFeedbackForGlobalAccess( 3911cb0ef41Sopenharmony_ci FeedbackSource const& source); 3921cb0ef41Sopenharmony_ci ProcessedFeedback const& ReadFeedbackForInstanceOf( 3931cb0ef41Sopenharmony_ci FeedbackSource const& source); 3941cb0ef41Sopenharmony_ci ProcessedFeedback const& ReadFeedbackForPropertyAccess( 3951cb0ef41Sopenharmony_ci FeedbackSource const& source, AccessMode mode, 3961cb0ef41Sopenharmony_ci base::Optional<NameRef> static_name); 3971cb0ef41Sopenharmony_ci ProcessedFeedback const& ReadFeedbackForRegExpLiteral( 3981cb0ef41Sopenharmony_ci FeedbackSource const& source); 3991cb0ef41Sopenharmony_ci ProcessedFeedback const& ReadFeedbackForTemplateObject( 4001cb0ef41Sopenharmony_ci FeedbackSource const& source); 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci void CollectArrayAndObjectPrototypes(); 4031cb0ef41Sopenharmony_ci 4041cb0ef41Sopenharmony_ci void set_persistent_handles( 4051cb0ef41Sopenharmony_ci std::unique_ptr<PersistentHandles> persistent_handles) { 4061cb0ef41Sopenharmony_ci DCHECK_NULL(ph_); 4071cb0ef41Sopenharmony_ci ph_ = std::move(persistent_handles); 4081cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(ph_); 4091cb0ef41Sopenharmony_ci } 4101cb0ef41Sopenharmony_ci std::unique_ptr<PersistentHandles> DetachPersistentHandles() { 4111cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(ph_); 4121cb0ef41Sopenharmony_ci return std::move(ph_); 4131cb0ef41Sopenharmony_ci } 4141cb0ef41Sopenharmony_ci 4151cb0ef41Sopenharmony_ci void set_canonical_handles( 4161cb0ef41Sopenharmony_ci std::unique_ptr<CanonicalHandlesMap> canonical_handles) { 4171cb0ef41Sopenharmony_ci DCHECK_NULL(canonical_handles_); 4181cb0ef41Sopenharmony_ci canonical_handles_ = std::move(canonical_handles); 4191cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(canonical_handles_); 4201cb0ef41Sopenharmony_ci } 4211cb0ef41Sopenharmony_ci 4221cb0ef41Sopenharmony_ci std::unique_ptr<CanonicalHandlesMap> DetachCanonicalHandles() { 4231cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(canonical_handles_); 4241cb0ef41Sopenharmony_ci return std::move(canonical_handles_); 4251cb0ef41Sopenharmony_ci } 4261cb0ef41Sopenharmony_ci 4271cb0ef41Sopenharmony_ci // Copy the canonical handles over to the JSHeapBroker. 4281cb0ef41Sopenharmony_ci void CopyCanonicalHandlesForTesting( 4291cb0ef41Sopenharmony_ci std::unique_ptr<CanonicalHandlesMap> canonical_handles); 4301cb0ef41Sopenharmony_ci 4311cb0ef41Sopenharmony_ci Isolate* const isolate_; 4321cb0ef41Sopenharmony_ci#if V8_COMPRESS_POINTERS 4331cb0ef41Sopenharmony_ci const PtrComprCageBase cage_base_; 4341cb0ef41Sopenharmony_ci#endif // V8_COMPRESS_POINTERS 4351cb0ef41Sopenharmony_ci Zone* const zone_; 4361cb0ef41Sopenharmony_ci base::Optional<NativeContextRef> target_native_context_; 4371cb0ef41Sopenharmony_ci RefsMap* refs_; 4381cb0ef41Sopenharmony_ci RootIndexMap root_index_map_; 4391cb0ef41Sopenharmony_ci ZoneUnorderedSet<Handle<JSObject>, Handle<JSObject>::hash, 4401cb0ef41Sopenharmony_ci Handle<JSObject>::equal_to> 4411cb0ef41Sopenharmony_ci array_and_object_prototypes_; 4421cb0ef41Sopenharmony_ci BrokerMode mode_ = kDisabled; 4431cb0ef41Sopenharmony_ci bool const tracing_enabled_; 4441cb0ef41Sopenharmony_ci CodeKind const code_kind_; 4451cb0ef41Sopenharmony_ci std::unique_ptr<PersistentHandles> ph_; 4461cb0ef41Sopenharmony_ci LocalIsolate* local_isolate_ = nullptr; 4471cb0ef41Sopenharmony_ci std::unique_ptr<CanonicalHandlesMap> canonical_handles_; 4481cb0ef41Sopenharmony_ci unsigned trace_indentation_ = 0; 4491cb0ef41Sopenharmony_ci ZoneUnorderedMap<FeedbackSource, ProcessedFeedback const*, 4501cb0ef41Sopenharmony_ci FeedbackSource::Hash, FeedbackSource::Equal> 4511cb0ef41Sopenharmony_ci feedback_; 4521cb0ef41Sopenharmony_ci ZoneUnorderedMap<PropertyAccessTarget, PropertyAccessInfo, 4531cb0ef41Sopenharmony_ci PropertyAccessTarget::Hash, PropertyAccessTarget::Equal> 4541cb0ef41Sopenharmony_ci property_access_infos_; 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci CompilationDependencies* dependencies_ = nullptr; 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_ci // The MapUpdater mutex is used in recursive patterns; for example, 4591cb0ef41Sopenharmony_ci // ComputePropertyAccessInfo may call itself recursively. Thus we need to 4601cb0ef41Sopenharmony_ci // emulate a recursive mutex, which we do by checking if this heap broker 4611cb0ef41Sopenharmony_ci // instance already holds the mutex when a lock is requested. This field 4621cb0ef41Sopenharmony_ci // holds the locking depth, i.e. how many times the mutex has been 4631cb0ef41Sopenharmony_ci // recursively locked. Only the outermost locker actually locks underneath. 4641cb0ef41Sopenharmony_ci int map_updater_mutex_depth_ = 0; 4651cb0ef41Sopenharmony_ci // Likewise for boilerplate migrations. 4661cb0ef41Sopenharmony_ci int boilerplate_migration_mutex_depth_ = 0; 4671cb0ef41Sopenharmony_ci 4681cb0ef41Sopenharmony_ci static constexpr uint32_t kMinimalRefsBucketCount = 8; 4691cb0ef41Sopenharmony_ci STATIC_ASSERT(base::bits::IsPowerOfTwo(kMinimalRefsBucketCount)); 4701cb0ef41Sopenharmony_ci static constexpr uint32_t kInitialRefsBucketCount = 1024; 4711cb0ef41Sopenharmony_ci STATIC_ASSERT(base::bits::IsPowerOfTwo(kInitialRefsBucketCount)); 4721cb0ef41Sopenharmony_ci}; 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ciclass V8_NODISCARD TraceScope { 4751cb0ef41Sopenharmony_ci public: 4761cb0ef41Sopenharmony_ci TraceScope(JSHeapBroker* broker, const char* label) 4771cb0ef41Sopenharmony_ci : TraceScope(broker, static_cast<void*>(broker), label) {} 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ci TraceScope(JSHeapBroker* broker, ObjectData* data, const char* label) 4801cb0ef41Sopenharmony_ci : TraceScope(broker, static_cast<void*>(data), label) {} 4811cb0ef41Sopenharmony_ci 4821cb0ef41Sopenharmony_ci TraceScope(JSHeapBroker* broker, void* subject, const char* label) 4831cb0ef41Sopenharmony_ci : broker_(broker) { 4841cb0ef41Sopenharmony_ci TRACE_BROKER(broker_, "Running " << label << " on " << subject); 4851cb0ef41Sopenharmony_ci broker_->IncrementTracingIndentation(); 4861cb0ef41Sopenharmony_ci } 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_ci ~TraceScope() { broker_->DecrementTracingIndentation(); } 4891cb0ef41Sopenharmony_ci 4901cb0ef41Sopenharmony_ci private: 4911cb0ef41Sopenharmony_ci JSHeapBroker* const broker_; 4921cb0ef41Sopenharmony_ci}; 4931cb0ef41Sopenharmony_ci 4941cb0ef41Sopenharmony_ci// Scope that unparks the LocalHeap, if: 4951cb0ef41Sopenharmony_ci// a) We have a JSHeapBroker, 4961cb0ef41Sopenharmony_ci// b) Said JSHeapBroker has a LocalIsolate and thus a LocalHeap, 4971cb0ef41Sopenharmony_ci// c) Said LocalHeap has been parked and 4981cb0ef41Sopenharmony_ci// d) The given condition evaluates to true. 4991cb0ef41Sopenharmony_ci// Used, for example, when printing the graph with --trace-turbo with a 5001cb0ef41Sopenharmony_ci// previously parked LocalHeap. 5011cb0ef41Sopenharmony_ciclass V8_NODISCARD UnparkedScopeIfNeeded { 5021cb0ef41Sopenharmony_ci public: 5031cb0ef41Sopenharmony_ci explicit UnparkedScopeIfNeeded(JSHeapBroker* broker, 5041cb0ef41Sopenharmony_ci bool extra_condition = true) { 5051cb0ef41Sopenharmony_ci if (broker != nullptr && extra_condition) { 5061cb0ef41Sopenharmony_ci LocalIsolate* local_isolate = broker->local_isolate(); 5071cb0ef41Sopenharmony_ci if (local_isolate != nullptr && local_isolate->heap()->IsParked()) { 5081cb0ef41Sopenharmony_ci unparked_scope.emplace(local_isolate->heap()); 5091cb0ef41Sopenharmony_ci } 5101cb0ef41Sopenharmony_ci } 5111cb0ef41Sopenharmony_ci } 5121cb0ef41Sopenharmony_ci 5131cb0ef41Sopenharmony_ci private: 5141cb0ef41Sopenharmony_ci base::Optional<UnparkedScope> unparked_scope; 5151cb0ef41Sopenharmony_ci}; 5161cb0ef41Sopenharmony_ci 5171cb0ef41Sopenharmony_citemplate <class T, 5181cb0ef41Sopenharmony_ci typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>> 5191cb0ef41Sopenharmony_cibase::Optional<typename ref_traits<T>::ref_type> TryMakeRef( 5201cb0ef41Sopenharmony_ci JSHeapBroker* broker, ObjectData* data) { 5211cb0ef41Sopenharmony_ci if (data == nullptr) return {}; 5221cb0ef41Sopenharmony_ci return {typename ref_traits<T>::ref_type(broker, data)}; 5231cb0ef41Sopenharmony_ci} 5241cb0ef41Sopenharmony_ci 5251cb0ef41Sopenharmony_ci// Usage: 5261cb0ef41Sopenharmony_ci// 5271cb0ef41Sopenharmony_ci// base::Optional<FooRef> ref = TryMakeRef(broker, o); 5281cb0ef41Sopenharmony_ci// if (!ref.has_value()) return {}; // bailout 5291cb0ef41Sopenharmony_ci// 5301cb0ef41Sopenharmony_ci// or 5311cb0ef41Sopenharmony_ci// 5321cb0ef41Sopenharmony_ci// FooRef ref = MakeRef(broker, o); 5331cb0ef41Sopenharmony_citemplate <class T, 5341cb0ef41Sopenharmony_ci typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>> 5351cb0ef41Sopenharmony_cibase::Optional<typename ref_traits<T>::ref_type> TryMakeRef( 5361cb0ef41Sopenharmony_ci JSHeapBroker* broker, T object, GetOrCreateDataFlags flags = {}) { 5371cb0ef41Sopenharmony_ci ObjectData* data = broker->TryGetOrCreateData(object, flags); 5381cb0ef41Sopenharmony_ci if (data == nullptr) { 5391cb0ef41Sopenharmony_ci TRACE_BROKER_MISSING(broker, "ObjectData for " << Brief(object)); 5401cb0ef41Sopenharmony_ci } 5411cb0ef41Sopenharmony_ci return TryMakeRef<T>(broker, data); 5421cb0ef41Sopenharmony_ci} 5431cb0ef41Sopenharmony_ci 5441cb0ef41Sopenharmony_citemplate <class T, 5451cb0ef41Sopenharmony_ci typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>> 5461cb0ef41Sopenharmony_cibase::Optional<typename ref_traits<T>::ref_type> TryMakeRef( 5471cb0ef41Sopenharmony_ci JSHeapBroker* broker, Handle<T> object, GetOrCreateDataFlags flags = {}) { 5481cb0ef41Sopenharmony_ci ObjectData* data = broker->TryGetOrCreateData(object, flags); 5491cb0ef41Sopenharmony_ci if (data == nullptr) { 5501cb0ef41Sopenharmony_ci DCHECK_EQ(flags & kCrashOnError, 0); 5511cb0ef41Sopenharmony_ci TRACE_BROKER_MISSING(broker, "ObjectData for " << Brief(*object)); 5521cb0ef41Sopenharmony_ci } 5531cb0ef41Sopenharmony_ci return TryMakeRef<T>(broker, data); 5541cb0ef41Sopenharmony_ci} 5551cb0ef41Sopenharmony_ci 5561cb0ef41Sopenharmony_citemplate <class T, 5571cb0ef41Sopenharmony_ci typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>> 5581cb0ef41Sopenharmony_citypename ref_traits<T>::ref_type MakeRef(JSHeapBroker* broker, T object) { 5591cb0ef41Sopenharmony_ci return TryMakeRef(broker, object, kCrashOnError).value(); 5601cb0ef41Sopenharmony_ci} 5611cb0ef41Sopenharmony_ci 5621cb0ef41Sopenharmony_citemplate <class T, 5631cb0ef41Sopenharmony_ci typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>> 5641cb0ef41Sopenharmony_citypename ref_traits<T>::ref_type MakeRef(JSHeapBroker* broker, 5651cb0ef41Sopenharmony_ci Handle<T> object) { 5661cb0ef41Sopenharmony_ci return TryMakeRef(broker, object, kCrashOnError).value(); 5671cb0ef41Sopenharmony_ci} 5681cb0ef41Sopenharmony_ci 5691cb0ef41Sopenharmony_citemplate <class T, 5701cb0ef41Sopenharmony_ci typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>> 5711cb0ef41Sopenharmony_citypename ref_traits<T>::ref_type MakeRefAssumeMemoryFence(JSHeapBroker* broker, 5721cb0ef41Sopenharmony_ci T object) { 5731cb0ef41Sopenharmony_ci return TryMakeRef(broker, object, kAssumeMemoryFence | kCrashOnError).value(); 5741cb0ef41Sopenharmony_ci} 5751cb0ef41Sopenharmony_ci 5761cb0ef41Sopenharmony_citemplate <class T, 5771cb0ef41Sopenharmony_ci typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>> 5781cb0ef41Sopenharmony_citypename ref_traits<T>::ref_type MakeRefAssumeMemoryFence(JSHeapBroker* broker, 5791cb0ef41Sopenharmony_ci Handle<T> object) { 5801cb0ef41Sopenharmony_ci return TryMakeRef(broker, object, kAssumeMemoryFence | kCrashOnError).value(); 5811cb0ef41Sopenharmony_ci} 5821cb0ef41Sopenharmony_ci 5831cb0ef41Sopenharmony_ci} // namespace compiler 5841cb0ef41Sopenharmony_ci} // namespace internal 5851cb0ef41Sopenharmony_ci} // namespace v8 5861cb0ef41Sopenharmony_ci 5871cb0ef41Sopenharmony_ci#endif // V8_COMPILER_JS_HEAP_BROKER_H_ 588