Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(302)

Side by Side Diff: src/compiler/js-for-in-lowering.cc

Issue 2763533002: [WIP] JSForInLowering and JSForInHasOwnProperty.
Patch Set: Hack around the issue with indices not being available always. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/js-for-in-lowering.h ('k') | src/compiler/js-generic-lowering.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2017 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 #include "src/compiler/js-for-in-lowering.h"
6
7 #include "src/code-factory.h"
8 #include "src/compiler/access-builder.h"
9 #include "src/compiler/common-operator.h"
10 #include "src/compiler/graph.h"
11 #include "src/compiler/js-graph.h"
12 #include "src/compiler/linkage.h"
13 #include "src/compiler/node-properties.h"
14 #include "src/compiler/simplified-operator.h"
15
16 namespace v8 {
17 namespace internal {
18 namespace compiler {
19
20 Reduction JSForInLowering::Reduce(Node* node) {
21 switch (node->opcode()) {
22 case IrOpcode::kJSForInHasOwnProperty:
23 return ReduceJSForInHasOwnProperty(node);
24 case IrOpcode::kJSForInLoadProperty:
25 return ReduceJSForInLoadProperty(node);
26 case IrOpcode::kJSForInNext:
27 return ReduceJSForInNext(node);
28 case IrOpcode::kJSForInPrepare:
29 return ReduceJSForInPrepare(node);
30 default:
31 break;
32 }
33 return NoChange();
34 }
35
36 Reduction JSForInLowering::ReduceJSForInHasOwnProperty(Node* node) {
37 DCHECK_EQ(IrOpcode::kJSForInHasOwnProperty, node->opcode());
38 Node* target = NodeProperties::GetValueInput(node, 0);
39 Node* receiver = NodeProperties::GetValueInput(node, 1);
40 Node* name = NodeProperties::GetValueInput(node, 2);
41 Node* enumerator = NodeProperties::GetValueInput(node, 3);
42 Node* frame_state = NodeProperties::GetFrameStateInput(node);
43 Node* effect = NodeProperties::GetEffectInput(node);
44 Node* control = NodeProperties::GetControlInput(node);
45
46 // Load the map of the {receiver}.
47 Node* receiver_map = effect =
48 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
49 receiver, effect, control);
50
51 // Check if the expected map still matches that of the {receiver}.
52 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
53 enumerator);
54 Node* branch0 =
55 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
56
57 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
58 Node* etrue0 = effect;
59 Node* vtrue0;
60 {
61 // Don't need filtering since {enumerator} still matches the {receiver} map.
62 vtrue0 = jsgraph()->TrueConstant();
63 }
64
65 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
66 Node* efalse0 = effect;
67 Node* vfalse0;
68 {
69 // We need to call Object.prototype.hasOwnProperty here.
70 CallDescriptor const* const desc = Linkage::GetJSCallDescriptor(
71 graph()->zone(), false, 2, CallDescriptor::kNeedsFrameState);
72 Node* context = efalse0 = graph()->NewNode(
73 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
74 efalse0, if_false0);
75 vfalse0 = efalse0 = graph()->NewNode(common()->Call(desc), target, receiver,
76 name, jsgraph()->UndefinedConstant(),
77 jsgraph()->OneConstant(), context,
78 frame_state, efalse0, if_false0);
79 NodeProperties::SetType(vfalse0, Type::Boolean());
80
81 // Update potential {IfException} uses of {node} to point to the above
82 // Object.prototype.hasOwnProperty call node instead.
83 Node* if_exception = nullptr;
84 if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
85 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
86 NodeProperties::ReplaceControlInput(if_exception, vfalse0);
87 NodeProperties::ReplaceEffectInput(if_exception, efalse0);
88 Revisit(if_exception);
89 }
90 }
91
92 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
93 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
94 Node* value =
95 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), vtrue0,
96 vfalse0, control);
97 ReplaceWithValue(node, value, effect, control);
98 return Replace(value);
99 }
100
101 Reduction JSForInLowering::ReduceJSForInLoadProperty(Node* node) {
102 DCHECK_EQ(IrOpcode::kJSForInLoadProperty, node->opcode());
103 Node* receiver = NodeProperties::GetValueInput(node, 0);
104 Node* name = NodeProperties::GetValueInput(node, 1);
105 Node* enumerator = NodeProperties::GetValueInput(node, 2);
106 Node* index = NodeProperties::GetValueInput(node, 3);
107 Node* context = NodeProperties::GetContextInput(node);
108 Node* frame_state = NodeProperties::GetFrameStateInput(node);
109 Node* effect = NodeProperties::GetEffectInput(node);
110 Node* control = NodeProperties::GetControlInput(node);
111
112 // We know that the {index} is in Unsigned32 range here, otherwise executing
113 // the JSForInNext wouldn't be valid. Unfortunately due to OSR and generators
114 // this is not always reflected in the types, hence we might need to rename
115 // the {index} here.
116 if (!NodeProperties::GetType(index)->Is(Type::Unsigned32())) {
117 index = graph()->NewNode(common()->TypeGuard(Type::Unsigned32()), index,
118 control);
119 }
120
121 // Load the map of the {receiver}.
122 Node* receiver_map = effect =
123 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
124 receiver, effect, control);
125
126 // Check if the expected map still matches that of the {receiver}.
127 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
128 enumerator);
129 Node* branch0 =
130 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
131
132 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
133 Node* etrue0 = effect;
134 Node* vtrue0;
135 {
136 // We are using the enumeration cache, so we can just load the value
137 // for the property {name} on {receiver} by loading the FieldIndex
138 // from the indices part of the enum cache.
139 Node* receiver_descriptors = etrue0 = graph()->NewNode(
140 simplified()->LoadField(AccessBuilder::ForMapDescriptors()),
141 receiver_map, etrue0, if_true0);
142 Node* receiver_enum_cache = etrue0 = graph()->NewNode(
143 simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()),
144 receiver_descriptors, etrue0, if_true0);
145 Node* receiver_enum_indices = etrue0 = graph()->NewNode(
146 simplified()->LoadField(
147 AccessBuilder::ForDescriptorArrayEnumCacheBridgeIndicesCache()),
148 receiver_enum_cache, etrue0, if_true0);
149 // TODO(bmeurer): Weird hack!
150 receiver_enum_indices = etrue0 =
151 graph()->NewNode(simplified()->CheckHeapObject(), receiver_enum_indices,
152 etrue0, if_true0);
153 index = etrue0 = graph()->NewNode(
154 simplified()->LoadElement(
155 AccessBuilder::ForFixedArrayElement(FAST_SMI_ELEMENTS)),
156 receiver_enum_indices, index, etrue0, if_true0);
157 vtrue0 = etrue0 = graph()->NewNode(simplified()->LoadFieldByIndex(),
158 receiver, index, etrue0, if_true0);
159 }
160
161 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
162 Node* efalse0 = effect;
163 Node* vfalse0;
164 {
165 // Load the property with the given {name} from the {receiver} using
166 // the GetProperty stub.
167 Callable const callable = CodeFactory::GetProperty(isolate());
168 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
169 isolate(), graph()->zone(), callable.descriptor(), 0,
170 CallDescriptor::kNeedsFrameState);
171 vfalse0 = efalse0 = graph()->NewNode(
172 common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
173 receiver, name, context, frame_state, efalse0, if_false0);
174 NodeProperties::SetType(vfalse0, Type::NonInternal());
175
176 // Update potential {IfException} uses of {node} to point to the ahove
177 // GetProperty stub call node instead.
178 Node* if_exception = nullptr;
179 if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
180 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
181 NodeProperties::ReplaceControlInput(if_exception, vfalse0);
182 NodeProperties::ReplaceEffectInput(if_exception, efalse0);
183 Revisit(if_exception);
184 }
185 }
186
187 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
188 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
189 Node* value =
190 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), vtrue0,
191 vfalse0, control);
192 ReplaceWithValue(node, value, effect, control);
193 return Replace(value);
194 }
195
196 Reduction JSForInLowering::ReduceJSForInNext(Node* node) {
197 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
198 Node* receiver = NodeProperties::GetValueInput(node, 0);
199 Node* cache_array = NodeProperties::GetValueInput(node, 1);
200 Node* cache_type = NodeProperties::GetValueInput(node, 2);
201 Node* index = NodeProperties::GetValueInput(node, 3);
202 Node* context = NodeProperties::GetContextInput(node);
203 Node* frame_state = NodeProperties::GetFrameStateInput(node);
204 Node* effect = NodeProperties::GetEffectInput(node);
205 Node* control = NodeProperties::GetControlInput(node);
206
207 // We know that the {index} is in Unsigned32 range here, otherwise executing
208 // the JSForInNext wouldn't be valid. Unfortunately due to OSR and generators
209 // this is not always reflected in the types, hence we might need to rename
210 // the {index} here.
211 if (!NodeProperties::GetType(index)->Is(Type::Unsigned32())) {
212 index = graph()->NewNode(common()->TypeGuard(Type::Unsigned32()), index,
213 control);
214 }
215
216 // Load the next {key} from the {cache_array}.
217 Node* key = effect = graph()->NewNode(
218 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
219 cache_array, index, effect, control);
220
221 // Load the map of the {receiver}.
222 Node* receiver_map = effect =
223 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
224 receiver, effect, control);
225
226 // Check if the expected map still matches that of the {receiver}.
227 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
228 cache_type);
229 Node* branch0 =
230 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
231
232 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
233 Node* etrue0;
234 Node* vtrue0;
235 {
236 // Don't need filtering since expected map still matches that of the
237 // {receiver}; in this case the {key} is definitely a String.
238 etrue0 = effect;
239 vtrue0 =
240 graph()->NewNode(common()->TypeGuard(Type::String()), key, if_true0);
241 }
242
243 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
244 Node* efalse0;
245 Node* vfalse0;
246 {
247 // Filter the {key} to check if it's still a valid property of the
248 // {receiver} (does the ToName conversion implicitly).
249 Callable const callable = CodeFactory::ForInFilter(isolate());
250 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
251 isolate(), graph()->zone(), callable.descriptor(), 0,
252 CallDescriptor::kNeedsFrameState);
253 vfalse0 = efalse0 = graph()->NewNode(
254 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), key,
255 receiver, context, frame_state, effect, if_false0);
256 NodeProperties::SetType(vfalse0, Type::StringOrUndefined());
257
258 // Update potential {IfException} uses of {node} to point to the ahove
259 // ForInFilter stub call node instead.
260 Node* if_exception = nullptr;
261 if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
262 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
263 NodeProperties::ReplaceControlInput(if_exception, vfalse0);
264 NodeProperties::ReplaceEffectInput(if_exception, efalse0);
265 Revisit(if_exception);
266 }
267 }
268
269 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
270 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
271 Node* value =
272 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), vtrue0,
273 vfalse0, control);
274 ReplaceWithValue(node, value, effect, control);
275 return Replace(value);
276 }
277
278 Reduction JSForInLowering::ReduceJSForInPrepare(Node* node) {
279 DCHECK_EQ(IrOpcode::kJSForInPrepare, node->opcode());
280 Callable const callable = CodeFactory::ForInPrepare(isolate());
281 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
282 isolate(), graph()->zone(), callable.descriptor(), 0,
283 CallDescriptor::kNeedsFrameState, node->op()->properties(),
284 MachineType::AnyTagged(), 3);
285 Node* stub = jsgraph()->HeapConstant(callable.code());
286 node->InsertInput(graph()->zone(), 0, stub);
287 NodeProperties::ChangeOp(node, common()->Call(desc));
288 return Changed(node);
289 }
290
291 CommonOperatorBuilder* JSForInLowering::common() const {
292 return jsgraph()->common();
293 }
294
295 Graph* JSForInLowering::graph() const { return jsgraph()->graph(); }
296
297 Isolate* JSForInLowering::isolate() const { return jsgraph()->isolate(); }
298
299 SimplifiedOperatorBuilder* JSForInLowering::simplified() const {
300 return jsgraph()->simplified();
301 }
302
303 } // namespace compiler
304 } // namespace internal
305 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-for-in-lowering.h ('k') | src/compiler/js-generic-lowering.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698