// Copyright 2018 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_COMPILER_JS_HEAP_BROKER_H_ #define V8_COMPILER_JS_HEAP_BROKER_H_ #include "src/base/compiler-specific.h" #include "src/base/optional.h" #include "src/common/globals.h" #include "src/compiler/access-info.h" #include "src/compiler/refs-map.h" #include "src/handles/handles.h" #include "src/interpreter/bytecode-array-accessor.h" #include "src/objects/feedback-vector.h" #include "src/objects/function-kind.h" #include "src/objects/objects.h" #include "src/utils/ostreams.h" #include "src/zone/zone-containers.h" namespace v8 { namespace internal { namespace compiler { class BytecodeAnalysis; class ObjectRef; std::ostream& operator<<(std::ostream& os, const ObjectRef& ref); struct FeedbackSource { FeedbackSource(Handle vector_, FeedbackSlot slot_) : vector(vector_), slot(slot_) {} explicit FeedbackSource(FeedbackNexus const& nexus); explicit FeedbackSource(VectorSlotPair const& pair); Handle const vector; FeedbackSlot const slot; struct Hash { size_t operator()(FeedbackSource const& source) const { return base::hash_combine(source.vector.address(), source.slot); } }; struct Equal { bool operator()(FeedbackSource const& lhs, FeedbackSource const& rhs) const { return lhs.vector.equals(rhs.vector) && lhs.slot == rhs.slot; } }; }; #define TRACE_BROKER(broker, x) \ do { \ if (broker->tracing_enabled() && FLAG_trace_heap_broker_verbose) \ broker->Trace() << x << '\n'; \ } while (false) #define TRACE_BROKER_MISSING(broker, x) \ do { \ if (broker->tracing_enabled()) \ broker->Trace() << __FUNCTION__ << ": missing " << x << '\n'; \ } while (false) class V8_EXPORT_PRIVATE JSHeapBroker { public: JSHeapBroker(Isolate* isolate, Zone* broker_zone, bool tracing_enabled); void SetNativeContextRef(); void SerializeStandardObjects(); Isolate* isolate() const { return isolate_; } Zone* zone() const { return current_zone_; } bool tracing_enabled() const { return tracing_enabled_; } NativeContextRef native_context() const { return native_context_.value(); } PerIsolateCompilerCache* compiler_cache() const { return compiler_cache_; } enum BrokerMode { kDisabled, kSerializing, kSerialized, kRetired }; BrokerMode mode() const { return mode_; } void StartSerializing(); void StopSerializing(); void Retire(); bool SerializingAllowed() const; // Returns nullptr iff handle unknown. ObjectData* GetData(Handle) const; // Never returns nullptr. ObjectData* GetOrCreateData(Handle); // Like the previous but wraps argument in handle first (for convenience). ObjectData* GetOrCreateData(Object); // Check if {object} is any native context's %ArrayPrototype% or // %ObjectPrototype%. bool IsArrayOrObjectPrototype(const JSObjectRef& object) const; bool HasFeedback(FeedbackSource const& source) const; // The processed {feedback} can be {nullptr}, indicating that the original // feedback didn't contain information relevant for Turbofan. void SetFeedback(FeedbackSource const& source, ProcessedFeedback const* feedback); ProcessedFeedback const* GetFeedback(FeedbackSource const& source) const; // Convenience wrappers around GetFeedback. GlobalAccessFeedback const* GetGlobalAccessFeedback( FeedbackSource const& source) const; // TODO(neis): Move these into serializer when we're always in the background. ElementAccessFeedback const* ProcessFeedbackMapsForElementAccess( MapHandles const& maps, KeyedAccessMode const& keyed_mode); GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess( FeedbackSource const& source); BytecodeAnalysis const& GetBytecodeAnalysis( Handle bytecode_array, BailoutId osr_offset, bool analyze_liveness, bool serialize); base::Optional GetNameFeedback(FeedbackNexus const& nexus); // If there is no result stored for {map}, we return an Invalid // PropertyAccessInfo. PropertyAccessInfo GetAccessInfoForLoadingThen(MapRef map); void CreateAccessInfoForLoadingThen(MapRef map, CompilationDependencies* dependencies); PropertyAccessInfo GetAccessInfoForLoadingExec(MapRef map); PropertyAccessInfo const& CreateAccessInfoForLoadingExec( MapRef map, CompilationDependencies* dependencies); std::ostream& Trace(); void IncrementTracingIndentation(); void DecrementTracingIndentation(); private: friend class HeapObjectRef; friend class ObjectRef; friend class ObjectData; void SerializeShareableObjects(); void CollectArrayAndObjectPrototypes(); Isolate* const isolate_; Zone* const broker_zone_; Zone* current_zone_; base::Optional native_context_; RefsMap* refs_; ZoneUnorderedSet, Handle::hash, Handle::equal_to> array_and_object_prototypes_; BrokerMode mode_ = kDisabled; bool const tracing_enabled_; StdoutStream trace_out_; unsigned trace_indentation_ = 0; PerIsolateCompilerCache* compiler_cache_; ZoneUnorderedMap feedback_; ZoneUnorderedMap bytecode_analyses_; typedef ZoneUnorderedMap MapToAccessInfos; MapToAccessInfos ais_for_loading_then_; MapToAccessInfos ais_for_loading_exec_; static const size_t kMinimalRefsBucketCount = 8; // must be power of 2 static const size_t kInitialRefsBucketCount = 1024; // must be power of 2 }; class TraceScope { public: TraceScope(JSHeapBroker* broker, const char* label) : TraceScope(broker, static_cast(broker), label) {} TraceScope(JSHeapBroker* broker, ObjectData* data, const char* label) : TraceScope(broker, static_cast(data), label) {} TraceScope(JSHeapBroker* broker, void* subject, const char* label) : broker_(broker) { TRACE_BROKER(broker_, "Running " << label << " on " << subject); broker_->IncrementTracingIndentation(); } ~TraceScope() { broker_->DecrementTracingIndentation(); } private: JSHeapBroker* const broker_; }; #define ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING(something_var, \ optionally_something) \ auto optionally_something_ = optionally_something; \ if (!optionally_something_) \ return NoChangeBecauseOfMissingData(broker(), __FUNCTION__, __LINE__); \ something_var = *optionally_something_; class Reduction; Reduction NoChangeBecauseOfMissingData(JSHeapBroker* broker, const char* function, int line); // Miscellaneous definitions that should be moved elsewhere once concurrent // compilation is finished. bool CanInlineElementAccess(MapRef const& map); class OffHeapBytecodeArray final : public interpreter::AbstractBytecodeArray { public: explicit OffHeapBytecodeArray(BytecodeArrayRef bytecode_array); int length() const override; int parameter_count() const override; uint8_t get(int index) const override; void set(int index, uint8_t value) override; Address GetFirstBytecodeAddress() const override; Handle GetConstantAtIndex(int index, Isolate* isolate) const override; bool IsConstantAtIndexSmi(int index) const override; Smi GetConstantAtIndexAsSmi(int index) const override; private: BytecodeArrayRef array_; }; } // namespace compiler } // namespace internal } // namespace v8 #endif // V8_COMPILER_JS_HEAP_BROKER_H_