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
15namespace v8 {
16namespace internal {
17
18// Forward declarations.
19class Factory;
20class JSGlobalObject;
21class JSGlobalProxy;
22class StringConstantBase;
23
24namespace compiler {
25
26// Forward declarations.
27enum class AccessMode;
28class CommonOperatorBuilder;
29class CompilationDependencies;
30class ElementAccessInfo;
31class JSGraph;
32class JSHeapBroker;
33class JSOperatorBuilder;
34class MachineOperatorBuilder;
35class PropertyAccessInfo;
36class SimplifiedOperatorBuilder;
37class 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).
43class 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
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:
132    ValueEffectControl()
133        : value_(nullptr), effect_(nullptr), control_(nullptr) {}
134    ValueEffectControl(Node* value, Node* effect, Node* control)
135        : value_(value), effect_(effect), control_(control) {}
136
137    Node* value() const { return value_; }
138    Node* effect() const { return effect_; }
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;
240  JSGraph* jsgraph() const { return jsgraph_; }
241
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;
248  Flags flags() const { return flags_; }
249  Handle<JSGlobalObject> global_object() const { return global_object_; }
250  Handle<JSGlobalProxy> global_proxy() const { return global_proxy_; }
251  NativeContextRef native_context() const {
252    return broker()->target_native_context();
253  }
254  CompilationDependencies* dependencies() const { return dependencies_; }
255  Zone* zone() const { return 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
269DEFINE_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