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