1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_COMPILER_COMPILATION_DEPENDENCIES_H_ 6 #define V8_COMPILER_COMPILATION_DEPENDENCIES_H_ 7 8 #include "src/compiler/js-heap-broker.h" 9 #include "src/objects/objects.h" 10 #include "src/zone/zone-containers.h" 11 12 namespace v8 { 13 namespace internal { 14 namespace compiler { 15 16 class SlackTrackingPrediction { 17 public: 18 SlackTrackingPrediction(MapRef initial_map, int instance_size); 19 inobject_property_count()20 int inobject_property_count() const { return inobject_property_count_; } instance_size()21 int instance_size() const { return instance_size_; } 22 23 private: 24 int instance_size_; 25 int inobject_property_count_; 26 }; 27 28 class CompilationDependency; 29 30 // Collects and installs dependencies of the code that is being generated. 31 class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject { 32 public: 33 CompilationDependencies(JSHeapBroker* broker, Zone* zone); 34 35 V8_WARN_UNUSED_RESULT bool Commit(Handle<Code> code); 36 37 // Return the initial map of {function} and record the assumption that it 38 // stays the initial map. 39 MapRef DependOnInitialMap(const JSFunctionRef& function); 40 41 // Return the "prototype" property of the given function and record the 42 // assumption that it doesn't change. 43 ObjectRef DependOnPrototypeProperty(const JSFunctionRef& function); 44 45 // Record the assumption that {map} stays stable. 46 void DependOnStableMap(const MapRef& map); 47 48 // Depend on the fact that accessing property |property_name| from 49 // |receiver_map| yields the constant value |constant|, which is held by 50 // |holder|. Therefore, must be invalidated if |property_name| is added to any 51 // of the objects between receiver and |holder| on the prototype chain, b) any 52 // of the objects on the prototype chain up to |holder| change prototypes, or 53 // c) the value of |property_name| in |holder| changes. 54 // If PropertyKind is kData, |constant| is the value of the property in 55 // question. In case of PropertyKind::kAccessor, |constant| is the accessor 56 // function (i.e., getter or setter) itself, not the overall AccessorPair. 57 void DependOnConstantInDictionaryPrototypeChain(const MapRef& receiver_map, 58 const NameRef& property_name, 59 const ObjectRef& constant, 60 PropertyKind kind); 61 62 // Return the pretenure mode of {site} and record the assumption that it does 63 // not change. 64 AllocationType DependOnPretenureMode(const AllocationSiteRef& site); 65 66 // Return a field's constness and, if kConst, record the assumption that it 67 // remains kConst. The field is identified by the arguments. 68 // 69 // For arrays, arguments objects and value wrappers, only consider the field 70 // kConst if the map is stable (and register stability dependency in that 71 // case). This is to ensure that fast elements kind transitions cannot be 72 // used to mutate fields without deoptimization of the dependent code. 73 PropertyConstness DependOnFieldConstness(const MapRef& map, 74 InternalIndex descriptor); 75 76 // Record the assumption that neither {cell}'s {CellType} changes, nor the 77 // {IsReadOnly()} flag of {cell}'s {PropertyDetails}. 78 void DependOnGlobalProperty(const PropertyCellRef& cell); 79 80 // Return the validity of the given protector and, if true, record the 81 // assumption that the protector remains valid. 82 bool DependOnProtector(const PropertyCellRef& cell); 83 84 // Convenience wrappers around {DependOnProtector}. 85 bool DependOnArrayBufferDetachingProtector(); 86 bool DependOnArrayIteratorProtector(); 87 bool DependOnArraySpeciesProtector(); 88 bool DependOnNoElementsProtector(); 89 bool DependOnPromiseHookProtector(); 90 bool DependOnPromiseSpeciesProtector(); 91 bool DependOnPromiseThenProtector(); 92 93 // Record the assumption that {site}'s {ElementsKind} doesn't change. 94 void DependOnElementsKind(const AllocationSiteRef& site); 95 96 // Check that an object slot will not change during compilation. 97 void DependOnObjectSlotValue(const HeapObjectRef& object, int offset, 98 const ObjectRef& value); 99 100 void DependOnOwnConstantElement(const JSObjectRef& holder, uint32_t index, 101 const ObjectRef& element); 102 103 // Record the assumption that the {value} read from {holder} at {index} on the 104 // background thread is the correct value for a given property. 105 void DependOnOwnConstantDataProperty(const JSObjectRef& holder, 106 const MapRef& map, 107 Representation representation, 108 FieldIndex index, 109 const ObjectRef& value); 110 111 // Record the assumption that the {value} read from {holder} at {index} on the 112 // background thread is the correct value for a given dictionary property. 113 void DependOnOwnConstantDictionaryProperty(const JSObjectRef& holder, 114 InternalIndex index, 115 const ObjectRef& value); 116 117 // For each given map, depend on the stability of (the maps of) all prototypes 118 // up to (and including) the {last_prototype}. 119 void DependOnStablePrototypeChains( 120 ZoneVector<MapRef> const& receiver_maps, WhereToStart start, 121 base::Optional<JSObjectRef> last_prototype = 122 base::Optional<JSObjectRef>()); 123 124 // Like DependOnElementsKind but also applies to all nested allocation sites. 125 void DependOnElementsKinds(const AllocationSiteRef& site); 126 127 void DependOnConsistentJSFunctionView(const JSFunctionRef& function); 128 129 // Predict the final instance size for {function}'s initial map and record 130 // the assumption that this prediction is correct. In addition, register 131 // the initial map dependency. This method returns the {function}'s the 132 // predicted minimum slack instance size count (wrapped together with 133 // the corresponding in-object property count for convenience). 134 SlackTrackingPrediction DependOnInitialMapInstanceSizePrediction( 135 const JSFunctionRef& function); 136 137 // Records {dependency} if not null. 138 void RecordDependency(CompilationDependency const* dependency); 139 140 // The methods below allow for gathering dependencies without actually 141 // recording them. They can be recorded at a later time via RecordDependency 142 // (or they can be ignored). 143 144 // Gather the assumption that {target_map} can be transitioned to, i.e., that 145 // it does not become deprecated. 146 CompilationDependency const* TransitionDependencyOffTheRecord( 147 const MapRef& target_map) const; 148 149 // Gather the assumption that the field representation of a field does not 150 // change. The field is identified by the arguments. 151 CompilationDependency const* FieldRepresentationDependencyOffTheRecord( 152 const MapRef& map, InternalIndex descriptor, 153 Representation representation) const; 154 155 // Gather the assumption that the field type of a field does not change. The 156 // field is identified by the arguments. 157 CompilationDependency const* FieldTypeDependencyOffTheRecord( 158 const MapRef& map, InternalIndex descriptor, 159 const ObjectRef& /* Contains a FieldType underneath. */ type) const; 160 161 #ifdef DEBUG 162 static bool IsFieldRepresentationDependencyOnMap( 163 const CompilationDependency* dep, const Handle<Map>& receiver_map); 164 #endif // DEBUG 165 166 struct CompilationDependencyHash { 167 size_t operator()(const CompilationDependency* dep) const; 168 }; 169 struct CompilationDependencyEqual { 170 bool operator()(const CompilationDependency* lhs, 171 const CompilationDependency* rhs) const; 172 }; 173 174 private: 175 bool PrepareInstall(); 176 bool PrepareInstallPredictable(); 177 178 using CompilationDependencySet = 179 ZoneUnorderedSet<const CompilationDependency*, CompilationDependencyHash, 180 CompilationDependencyEqual>; 181 182 Zone* const zone_; 183 JSHeapBroker* const broker_; 184 CompilationDependencySet dependencies_; 185 }; 186 187 } // namespace compiler 188 } // namespace internal 189 } // namespace v8 190 191 #endif // V8_COMPILER_COMPILATION_DEPENDENCIES_H_ 192