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_JS_NATIVE_CONTEXT_SPECIALIZATION_H_ 6 #define V8_COMPILER_JS_NATIVE_CONTEXT_SPECIALIZATION_H_ 7 8 #include "src/base/flags.h" 9 #include "src/base/optional.h" 10 #include "src/compiler/graph-reducer.h" 11 #include "src/compiler/js-heap-broker.h" 12 #include "src/deoptimizer/deoptimize-reason.h" 13 #include "src/objects/map.h" 14 15 namespace v8 { 16 namespace internal { 17 18 // Forward declarations. 19 class Factory; 20 class JSGlobalObject; 21 class JSGlobalProxy; 22 class StringConstantBase; 23 24 namespace compiler { 25 26 // Forward declarations. 27 enum class AccessMode; 28 class CommonOperatorBuilder; 29 class CompilationDependencies; 30 class ElementAccessInfo; 31 class JSGraph; 32 class JSHeapBroker; 33 class JSOperatorBuilder; 34 class MachineOperatorBuilder; 35 class PropertyAccessInfo; 36 class SimplifiedOperatorBuilder; 37 class TypeCache; 38 39 // Specializes a given JSGraph to a given native context, potentially constant 40 // folding some {LoadGlobal} nodes or strength reducing some {StoreGlobal} 41 // nodes. And also specializes {LoadNamed} and {SetNamedProperty} nodes 42 // according to type feedback (if available). 43 class V8_EXPORT_PRIVATE JSNativeContextSpecialization final 44 : public AdvancedReducer { 45 public: 46 // Flags that control the mode of operation. 47 enum Flag { 48 kNoFlags = 0u, 49 kBailoutOnUninitialized = 1u << 0, 50 }; 51 using Flags = base::Flags<Flag>; 52 53 JSNativeContextSpecialization(Editor* editor, JSGraph* jsgraph, 54 JSHeapBroker* broker, Flags flags, 55 CompilationDependencies* dependencies, 56 Zone* zone, Zone* shared_zone); 57 JSNativeContextSpecialization(const JSNativeContextSpecialization&) = delete; 58 JSNativeContextSpecialization& operator=( 59 const JSNativeContextSpecialization&) = delete; 60 reducer_name()61 const char* reducer_name() const override { 62 return "JSNativeContextSpecialization"; 63 } 64 65 Reduction Reduce(Node* node) final; 66 67 // Utility for folding string constant concatenation. 68 // Supports JSAdd nodes and nodes typed as string or number. 69 // Public for the sake of unit testing. 70 static base::Optional<size_t> GetMaxStringLength(JSHeapBroker* broker, 71 Node* node); 72 73 private: 74 Reduction ReduceJSAdd(Node* node); 75 Reduction ReduceJSAsyncFunctionEnter(Node* node); 76 Reduction ReduceJSAsyncFunctionReject(Node* node); 77 Reduction ReduceJSAsyncFunctionResolve(Node* node); 78 Reduction ReduceJSGetSuperConstructor(Node* node); 79 Reduction ReduceJSInstanceOf(Node* node); 80 Reduction ReduceJSHasInPrototypeChain(Node* node); 81 Reduction ReduceJSOrdinaryHasInstance(Node* node); 82 Reduction ReduceJSPromiseResolve(Node* node); 83 Reduction ReduceJSResolvePromise(Node* node); 84 Reduction ReduceJSLoadGlobal(Node* node); 85 Reduction ReduceJSStoreGlobal(Node* node); 86 Reduction ReduceJSLoadNamed(Node* node); 87 Reduction ReduceJSLoadNamedFromSuper(Node* node); 88 Reduction ReduceJSGetIterator(Node* node); 89 Reduction ReduceJSSetNamedProperty(Node* node); 90 Reduction ReduceJSHasProperty(Node* node); 91 Reduction ReduceJSLoadProperty(Node* node); 92 Reduction ReduceJSSetKeyedProperty(Node* node); 93 Reduction ReduceJSDefineKeyedOwnProperty(Node* node); 94 Reduction ReduceJSDefineNamedOwnProperty(Node* node); 95 Reduction ReduceJSDefineKeyedOwnPropertyInLiteral(Node* node); 96 Reduction ReduceJSStoreInArrayLiteral(Node* node); 97 Reduction ReduceJSToObject(Node* node); 98 99 Reduction ReduceElementAccess(Node* node, Node* index, Node* value, 100 ElementAccessFeedback const& feedback); 101 // In the case of non-keyed (named) accesses, pass the name as {static_name} 102 // and use {nullptr} for {key} (load/store modes are irrelevant). 103 Reduction ReducePropertyAccess(Node* node, Node* key, 104 base::Optional<NameRef> static_name, 105 Node* value, FeedbackSource const& source, 106 AccessMode access_mode); 107 Reduction ReduceNamedAccess(Node* node, Node* value, 108 NamedAccessFeedback const& feedback, 109 AccessMode access_mode, Node* key = nullptr); 110 Reduction ReduceGlobalAccess(Node* node, Node* lookup_start_object, 111 Node* receiver, Node* value, NameRef const& name, 112 AccessMode access_mode, Node* key, 113 PropertyCellRef const& property_cell, 114 Node* effect = nullptr); 115 Reduction ReduceElementLoadFromHeapConstant(Node* node, Node* key, 116 AccessMode access_mode, 117 KeyedAccessLoadMode load_mode); 118 Reduction ReduceElementAccessOnString(Node* node, Node* index, Node* value, 119 KeyedAccessMode const& keyed_mode); 120 121 Reduction ReduceEagerDeoptimize(Node* node, DeoptimizeReason reason); 122 Reduction ReduceJSToString(Node* node); 123 124 Reduction ReduceJSLoadPropertyWithEnumeratedKey(Node* node); 125 126 base::Optional<const StringConstantBase*> CreateDelayedStringConstant( 127 Node* node); 128 129 // A triple of nodes that represents a continuation. 130 class ValueEffectControl final { 131 public: ValueEffectControl()132 ValueEffectControl() 133 : value_(nullptr), effect_(nullptr), control_(nullptr) {} ValueEffectControl(Node * value,Node * effect,Node * control)134 ValueEffectControl(Node* value, Node* effect, Node* control) 135 : value_(value), effect_(effect), control_(control) {} 136 value()137 Node* value() const { return value_; } effect()138 Node* effect() const { return effect_; } control()139 Node* control() const { return control_; } 140 141 private: 142 Node* value_; 143 Node* effect_; 144 Node* control_; 145 }; 146 147 // Construct the appropriate subgraph for property access. Return {} if the 148 // property access couldn't be built. 149 base::Optional<ValueEffectControl> BuildPropertyAccess( 150 Node* lookup_start_object, Node* receiver, Node* value, Node* context, 151 Node* frame_state, Node* effect, Node* control, NameRef const& name, 152 ZoneVector<Node*>* if_exceptions, PropertyAccessInfo const& access_info, 153 AccessMode access_mode); 154 base::Optional<ValueEffectControl> BuildPropertyLoad( 155 Node* lookup_start_object, Node* receiver, Node* context, 156 Node* frame_state, Node* effect, Node* control, NameRef const& name, 157 ZoneVector<Node*>* if_exceptions, PropertyAccessInfo const& access_info); 158 159 ValueEffectControl BuildPropertyStore(Node* receiver, Node* value, 160 Node* context, Node* frame_state, 161 Node* effect, Node* control, 162 NameRef const& name, 163 ZoneVector<Node*>* if_exceptions, 164 PropertyAccessInfo const& access_info, 165 AccessMode access_mode); 166 167 ValueEffectControl BuildPropertyTest(Node* effect, Node* control, 168 PropertyAccessInfo const& access_info); 169 170 // Helpers for accessor inlining. 171 Node* InlinePropertyGetterCall(Node* receiver, 172 ConvertReceiverMode receiver_mode, 173 Node* lookup_start_object, Node* context, 174 Node* frame_state, Node** effect, 175 Node** control, 176 ZoneVector<Node*>* if_exceptions, 177 PropertyAccessInfo const& access_info); 178 void InlinePropertySetterCall(Node* receiver, Node* value, Node* context, 179 Node* frame_state, Node** effect, 180 Node** control, 181 ZoneVector<Node*>* if_exceptions, 182 PropertyAccessInfo const& access_info); 183 Node* InlineApiCall(Node* receiver, Node* holder, Node* frame_state, 184 Node* value, Node** effect, Node** control, 185 FunctionTemplateInfoRef const& function_template_info); 186 187 // Construct the appropriate subgraph for element access. 188 ValueEffectControl BuildElementAccess(Node* receiver, Node* index, 189 Node* value, Node* effect, 190 Node* control, 191 ElementAccessInfo const& access_info, 192 KeyedAccessMode const& keyed_mode); 193 194 // Construct appropriate subgraph to load from a String. 195 Node* BuildIndexedStringLoad(Node* receiver, Node* index, Node* length, 196 Node** effect, Node** control, 197 KeyedAccessLoadMode load_mode); 198 199 // Construct appropriate subgraph to extend properties backing store. 200 Node* BuildExtendPropertiesBackingStore(const MapRef& map, Node* properties, 201 Node* effect, Node* control); 202 203 // Construct appropriate subgraph to check that the {value} matches 204 // the previously recorded {name} feedback. 205 Node* BuildCheckEqualsName(NameRef const& name, Node* value, Node* effect, 206 Node* control); 207 208 // Checks if we can turn the hole into undefined when loading an element 209 // from an object with one of the {receiver_maps}; sets up appropriate 210 // code dependencies and might use the array protector cell. 211 bool CanTreatHoleAsUndefined(ZoneVector<MapRef> const& receiver_maps); 212 213 void RemoveImpossibleMaps(Node* object, ZoneVector<MapRef>* maps) const; 214 215 ElementAccessFeedback const& TryRefineElementAccessFeedback( 216 ElementAccessFeedback const& feedback, Node* receiver, 217 Effect effect) const; 218 219 // Try to infer maps for the given {object} at the current {effect}. 220 bool InferMaps(Node* object, Effect effect, ZoneVector<MapRef>* maps) const; 221 222 // Try to infer a root map for the {object} independent of the current program 223 // location. 224 base::Optional<MapRef> InferRootMap(Node* object) const; 225 226 // Checks if we know at compile time that the {receiver} either definitely 227 // has the {prototype} in it's prototype chain, or the {receiver} definitely 228 // doesn't have the {prototype} in it's prototype chain. 229 enum InferHasInPrototypeChainResult { 230 kIsInPrototypeChain, 231 kIsNotInPrototypeChain, 232 kMayBeInPrototypeChain 233 }; 234 InferHasInPrototypeChainResult InferHasInPrototypeChain( 235 Node* receiver, Effect effect, HeapObjectRef const& prototype); 236 237 Node* BuildLoadPrototypeFromObject(Node* object, Node* effect, Node* control); 238 239 Graph* graph() const; jsgraph()240 JSGraph* jsgraph() const { return jsgraph_; } 241 broker()242 JSHeapBroker* broker() const { return broker_; } 243 Isolate* isolate() const; 244 Factory* factory() const; 245 CommonOperatorBuilder* common() const; 246 JSOperatorBuilder* javascript() const; 247 SimplifiedOperatorBuilder* simplified() const; flags()248 Flags flags() const { return flags_; } global_object()249 Handle<JSGlobalObject> global_object() const { return global_object_; } global_proxy()250 Handle<JSGlobalProxy> global_proxy() const { return global_proxy_; } native_context()251 NativeContextRef native_context() const { 252 return broker()->target_native_context(); 253 } dependencies()254 CompilationDependencies* dependencies() const { return dependencies_; } zone()255 Zone* zone() const { return zone_; } shared_zone()256 Zone* shared_zone() const { return shared_zone_; } 257 258 JSGraph* const jsgraph_; 259 JSHeapBroker* const broker_; 260 Flags const flags_; 261 Handle<JSGlobalObject> global_object_; 262 Handle<JSGlobalProxy> global_proxy_; 263 CompilationDependencies* const dependencies_; 264 Zone* const zone_; 265 Zone* const shared_zone_; 266 TypeCache const* type_cache_; 267 }; 268 269 DEFINE_OPERATORS_FOR_FLAGS(JSNativeContextSpecialization::Flags) 270 271 } // namespace compiler 272 } // namespace internal 273 } // namespace v8 274 275 #endif // V8_COMPILER_JS_NATIVE_CONTEXT_SPECIALIZATION_H_ 276