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

Side by Side Diff: src/compiler/js-native-context-specialization.cc

Issue 1721103003: [turbofan] Introduce DeoptimizeIf And DeoptimizeUnless common operators. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Add comments Created 4 years, 10 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
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/js-native-context-specialization.h" 5 #include "src/compiler/js-native-context-specialization.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/compilation-dependencies.h" 9 #include "src/compilation-dependencies.h"
10 #include "src/compiler/access-builder.h" 10 #include "src/compiler/access-builder.h"
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 101
102 // Nothing to do if we have no non-deprecated maps. 102 // Nothing to do if we have no non-deprecated maps.
103 if (access_infos.empty()) return NoChange(); 103 if (access_infos.empty()) return NoChange();
104 104
105 // The final states for every polymorphic branch. We join them with 105 // The final states for every polymorphic branch. We join them with
106 // Merge++Phi+EffectPhi at the bottom. 106 // Merge++Phi+EffectPhi at the bottom.
107 ZoneVector<Node*> values(zone()); 107 ZoneVector<Node*> values(zone());
108 ZoneVector<Node*> effects(zone()); 108 ZoneVector<Node*> effects(zone());
109 ZoneVector<Node*> controls(zone()); 109 ZoneVector<Node*> controls(zone());
110 110
111 // The list of "exiting" controls, which currently go to a single deoptimize.
112 // TODO(bmeurer): Consider using an IC as fallback.
113 Node* const exit_effect = effect;
114 ZoneVector<Node*> exit_controls(zone());
115
116 // Ensure that {index} matches the specified {name} (if {index} is given). 111 // Ensure that {index} matches the specified {name} (if {index} is given).
117 if (index != nullptr) { 112 if (index != nullptr) {
118 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), 113 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()),
119 index, jsgraph()->HeapConstant(name)); 114 index, jsgraph()->HeapConstant(name));
120 Node* branch = 115 control = graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
121 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 116 effect, control);
122 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch)); 117 }
123 control = graph()->NewNode(common()->IfTrue(), branch); 118
119 // Check if {receiver} may be a number.
120 bool receiverissmi_possible = false;
121 for (PropertyAccessInfo const& access_info : access_infos) {
122 if (access_info.receiver_type()->Is(Type::Number())) {
123 receiverissmi_possible = true;
124 break;
125 }
124 } 126 }
125 127
126 // Ensure that {receiver} is a heap object. 128 // Ensure that {receiver} is a heap object.
127 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); 129 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
128 Node* branch = graph()->NewNode(common()->Branch(), check, control); 130 Node* receiverissmi_control = nullptr;
129 control = graph()->NewNode(common()->IfFalse(), branch);
130 Node* receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
131 Node* receiverissmi_effect = effect; 131 Node* receiverissmi_effect = effect;
132 if (receiverissmi_possible) {
133 Node* branch = graph()->NewNode(common()->Branch(), check, control);
134 control = graph()->NewNode(common()->IfFalse(), branch);
135 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
136 receiverissmi_effect = effect;
137 } else {
138 control = graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
139 effect, control);
140 }
132 141
133 // Load the {receiver} map. The resulting effect is the dominating effect for 142 // Load the {receiver} map. The resulting effect is the dominating effect for
134 // all (polymorphic) branches. 143 // all (polymorphic) branches.
135 Node* receiver_map = effect = 144 Node* receiver_map = effect =
136 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 145 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
137 receiver, effect, control); 146 receiver, effect, control);
138 147
139 // Generate code for the various different property access patterns. 148 // Generate code for the various different property access patterns.
140 Node* fallthrough_control = control; 149 Node* fallthrough_control = control;
141 for (PropertyAccessInfo const& access_info : access_infos) { 150 for (size_t j = 0; j < access_infos.size(); ++j) {
151 PropertyAccessInfo const& access_info = access_infos[j];
142 Node* this_value = value; 152 Node* this_value = value;
143 Node* this_receiver = receiver; 153 Node* this_receiver = receiver;
144 Node* this_effect = effect; 154 Node* this_effect = effect;
145 Node* this_control; 155 Node* this_control;
146 156
147 // Perform map check on {receiver}. 157 // Perform map check on {receiver}.
148 Type* receiver_type = access_info.receiver_type(); 158 Type* receiver_type = access_info.receiver_type();
149 if (receiver_type->Is(Type::String())) { 159 if (receiver_type->Is(Type::String())) {
150 // Emit an instance type check for strings. 160 // Emit an instance type check for strings.
151 Node* receiver_instance_type = this_effect = graph()->NewNode( 161 Node* receiver_instance_type = this_effect = graph()->NewNode(
152 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), 162 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
153 receiver_map, this_effect, fallthrough_control); 163 receiver_map, this_effect, fallthrough_control);
154 Node* check = 164 Node* check =
155 graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type, 165 graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type,
156 jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE)); 166 jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE));
157 Node* branch = 167 if (j == access_infos.size() - 1) {
158 graph()->NewNode(common()->Branch(), check, fallthrough_control); 168 this_control =
159 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); 169 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
160 this_control = graph()->NewNode(common()->IfTrue(), branch); 170 this_effect, fallthrough_control);
171 fallthrough_control = nullptr;
172 } else {
173 Node* branch =
174 graph()->NewNode(common()->Branch(), check, fallthrough_control);
175 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
176 this_control = graph()->NewNode(common()->IfTrue(), branch);
177 }
161 } else { 178 } else {
162 // Emit a (sequence of) map checks for other {receiver}s. 179 // Emit a (sequence of) map checks for other {receiver}s.
163 ZoneVector<Node*> this_controls(zone()); 180 ZoneVector<Node*> this_controls(zone());
164 ZoneVector<Node*> this_effects(zone()); 181 ZoneVector<Node*> this_effects(zone());
182 int num_classes = access_info.receiver_type()->NumClasses();
165 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); 183 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
166 i.Advance()) { 184 i.Advance()) {
185 DCHECK_LT(0, num_classes);
167 Handle<Map> map = i.Current(); 186 Handle<Map> map = i.Current();
168 Node* check = 187 Node* check =
169 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), 188 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
170 receiver_map, jsgraph()->Constant(map)); 189 receiver_map, jsgraph()->Constant(map));
171 Node* branch = 190 if (--num_classes == 0 && j == access_infos.size() - 1) {
172 graph()->NewNode(common()->Branch(), check, fallthrough_control); 191 this_controls.push_back(
173 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); 192 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
174 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); 193 this_effect, fallthrough_control));
175 this_effects.push_back(this_effect); 194 this_effects.push_back(this_effect);
195 fallthrough_control = nullptr;
196 } else {
197 Node* branch =
198 graph()->NewNode(common()->Branch(), check, fallthrough_control);
199 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
200 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
201 this_effects.push_back(this_effect);
202 }
176 } 203 }
177 204
178 // The Number case requires special treatment to also deal with Smis. 205 // The Number case requires special treatment to also deal with Smis.
179 if (receiver_type->Is(Type::Number())) { 206 if (receiver_type->Is(Type::Number())) {
180 // Join this check with the "receiver is smi" check above, and mark the 207 // Join this check with the "receiver is smi" check above.
181 // "receiver is smi" check as "consumed" so that we don't deoptimize if 208 DCHECK_NOT_NULL(receiverissmi_effect);
182 // the {receiver} is actually a Smi. 209 DCHECK_NOT_NULL(receiverissmi_control);
183 if (receiverissmi_control != nullptr) { 210 this_effects.push_back(receiverissmi_effect);
184 this_controls.push_back(receiverissmi_control); 211 this_controls.push_back(receiverissmi_control);
185 this_effects.push_back(receiverissmi_effect); 212 receiverissmi_effect = receiverissmi_control = nullptr;
186 receiverissmi_control = receiverissmi_effect = nullptr;
187 }
188 } 213 }
189 214
190 // Create dominating Merge+EffectPhi for this {receiver} type. 215 // Create dominating Merge+EffectPhi for this {receiver} type.
191 int const this_control_count = static_cast<int>(this_controls.size()); 216 int const this_control_count = static_cast<int>(this_controls.size());
192 this_control = 217 this_control =
193 (this_control_count == 1) 218 (this_control_count == 1)
194 ? this_controls.front() 219 ? this_controls.front()
195 : graph()->NewNode(common()->Merge(this_control_count), 220 : graph()->NewNode(common()->Merge(this_control_count),
196 this_control_count, &this_controls.front()); 221 this_control_count, &this_controls.front());
197 this_effects.push_back(this_control); 222 this_effects.push_back(this_control);
198 int const this_effect_count = static_cast<int>(this_effects.size()); 223 int const this_effect_count = static_cast<int>(this_effects.size());
199 this_effect = 224 this_effect =
200 (this_control_count == 1) 225 (this_control_count == 1)
201 ? this_effects.front() 226 ? this_effects.front()
202 : graph()->NewNode(common()->EffectPhi(this_control_count), 227 : graph()->NewNode(common()->EffectPhi(this_control_count),
203 this_effect_count, &this_effects.front()); 228 this_effect_count, &this_effects.front());
204 } 229 }
205 230
206 // Determine actual holder and perform prototype chain checks. 231 // Determine actual holder and perform prototype chain checks.
207 Handle<JSObject> holder; 232 Handle<JSObject> holder;
208 if (access_info.holder().ToHandle(&holder)) { 233 if (access_info.holder().ToHandle(&holder)) {
209 AssumePrototypesStable(receiver_type, native_context, holder); 234 AssumePrototypesStable(receiver_type, native_context, holder);
210 } 235 }
211 236
212 // Generate the actual property access. 237 // Generate the actual property access.
213 if (access_info.IsNotFound()) { 238 if (access_info.IsNotFound()) {
214 DCHECK_EQ(AccessMode::kLoad, access_mode); 239 DCHECK_EQ(AccessMode::kLoad, access_mode);
215 if (is_strong(language_mode)) { 240 this_value = jsgraph()->UndefinedConstant();
216 // TODO(bmeurer/mstarzinger): Add support for lowering inside try
217 // blocks rewiring the IfException edge to a runtime call/throw.
218 exit_controls.push_back(this_control);
219 continue;
220 } else {
221 this_value = jsgraph()->UndefinedConstant();
222 }
223 } else if (access_info.IsDataConstant()) { 241 } else if (access_info.IsDataConstant()) {
224 this_value = jsgraph()->Constant(access_info.constant()); 242 this_value = jsgraph()->Constant(access_info.constant());
225 if (access_mode == AccessMode::kStore) { 243 if (access_mode == AccessMode::kStore) {
226 Node* check = graph()->NewNode( 244 Node* check = graph()->NewNode(
227 simplified()->ReferenceEqual(Type::Tagged()), value, this_value); 245 simplified()->ReferenceEqual(Type::Tagged()), value, this_value);
228 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 246 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
229 check, this_control); 247 frame_state, this_effect, this_control);
230 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
231 this_control = graph()->NewNode(common()->IfTrue(), branch);
232 } 248 }
233 } else { 249 } else {
234 DCHECK(access_info.IsDataField()); 250 DCHECK(access_info.IsDataField());
235 FieldIndex const field_index = access_info.field_index(); 251 FieldIndex const field_index = access_info.field_index();
236 FieldCheck const field_check = access_info.field_check(); 252 FieldCheck const field_check = access_info.field_check();
237 Type* const field_type = access_info.field_type(); 253 Type* const field_type = access_info.field_type();
238 switch (field_check) { 254 switch (field_check) {
239 case FieldCheck::kNone: 255 case FieldCheck::kNone:
240 break; 256 break;
241 case FieldCheck::kJSArrayBufferViewBufferNotNeutered: { 257 case FieldCheck::kJSArrayBufferViewBufferNotNeutered: {
242 Node* this_buffer = this_effect = 258 Node* this_buffer = this_effect =
243 graph()->NewNode(simplified()->LoadField( 259 graph()->NewNode(simplified()->LoadField(
244 AccessBuilder::ForJSArrayBufferViewBuffer()), 260 AccessBuilder::ForJSArrayBufferViewBuffer()),
245 this_receiver, this_effect, this_control); 261 this_receiver, this_effect, this_control);
246 Node* this_buffer_bit_field = this_effect = 262 Node* this_buffer_bit_field = this_effect =
247 graph()->NewNode(simplified()->LoadField( 263 graph()->NewNode(simplified()->LoadField(
248 AccessBuilder::ForJSArrayBufferBitField()), 264 AccessBuilder::ForJSArrayBufferBitField()),
249 this_buffer, this_effect, this_control); 265 this_buffer, this_effect, this_control);
250 Node* check = graph()->NewNode( 266 Node* check = graph()->NewNode(
251 machine()->Word32Equal(), 267 machine()->Word32Equal(),
252 graph()->NewNode(machine()->Word32And(), this_buffer_bit_field, 268 graph()->NewNode(machine()->Word32And(), this_buffer_bit_field,
253 jsgraph()->Int32Constant( 269 jsgraph()->Int32Constant(
254 1 << JSArrayBuffer::WasNeutered::kShift)), 270 1 << JSArrayBuffer::WasNeutered::kShift)),
255 jsgraph()->Int32Constant(0)); 271 jsgraph()->Int32Constant(0));
256 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), 272 this_control =
257 check, this_control); 273 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
258 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); 274 this_effect, this_control);
259 this_control = graph()->NewNode(common()->IfFalse(), branch);
260 break; 275 break;
261 } 276 }
262 } 277 }
263 if (access_mode == AccessMode::kLoad && 278 if (access_mode == AccessMode::kLoad &&
264 access_info.holder().ToHandle(&holder)) { 279 access_info.holder().ToHandle(&holder)) {
265 this_receiver = jsgraph()->Constant(holder); 280 this_receiver = jsgraph()->Constant(holder);
266 } 281 }
267 Node* this_storage = this_receiver; 282 Node* this_storage = this_receiver;
268 if (!field_index.is_inobject()) { 283 if (!field_index.is_inobject()) {
269 this_storage = this_effect = graph()->NewNode( 284 this_storage = this_effect = graph()->NewNode(
(...skipping 15 matching lines...) Expand all
285 field_access.machine_type = MachineType::Float64(); 300 field_access.machine_type = MachineType::Float64();
286 } 301 }
287 this_value = this_effect = 302 this_value = this_effect =
288 graph()->NewNode(simplified()->LoadField(field_access), 303 graph()->NewNode(simplified()->LoadField(field_access),
289 this_storage, this_effect, this_control); 304 this_storage, this_effect, this_control);
290 } else { 305 } else {
291 DCHECK_EQ(AccessMode::kStore, access_mode); 306 DCHECK_EQ(AccessMode::kStore, access_mode);
292 if (field_type->Is(Type::UntaggedFloat64())) { 307 if (field_type->Is(Type::UntaggedFloat64())) {
293 Node* check = 308 Node* check =
294 graph()->NewNode(simplified()->ObjectIsNumber(), this_value); 309 graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
295 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 310 this_control =
296 check, this_control); 311 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
297 exit_controls.push_back( 312 this_effect, this_control);
298 graph()->NewNode(common()->IfFalse(), branch));
299 this_control = graph()->NewNode(common()->IfTrue(), branch);
300 this_value = graph()->NewNode(common()->Guard(Type::Number()), 313 this_value = graph()->NewNode(common()->Guard(Type::Number()),
301 this_value, this_control); 314 this_value, this_control);
302 315
303 if (!field_index.is_inobject() || field_index.is_hidden_field() || 316 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
304 !FLAG_unbox_double_fields) { 317 !FLAG_unbox_double_fields) {
305 if (access_info.HasTransitionMap()) { 318 if (access_info.HasTransitionMap()) {
306 // Allocate a MutableHeapNumber for the new property. 319 // Allocate a MutableHeapNumber for the new property.
307 Callable callable = 320 Callable callable =
308 CodeFactory::AllocateMutableHeapNumber(isolate()); 321 CodeFactory::AllocateMutableHeapNumber(isolate());
309 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 322 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
(...skipping 18 matching lines...) Expand all
328 field_access.name = MaybeHandle<Name>(); 341 field_access.name = MaybeHandle<Name>();
329 field_access.machine_type = MachineType::Float64(); 342 field_access.machine_type = MachineType::Float64();
330 } 343 }
331 } else { 344 } else {
332 // Unboxed double field, we store directly to the field. 345 // Unboxed double field, we store directly to the field.
333 field_access.machine_type = MachineType::Float64(); 346 field_access.machine_type = MachineType::Float64();
334 } 347 }
335 } else if (field_type->Is(Type::TaggedSigned())) { 348 } else if (field_type->Is(Type::TaggedSigned())) {
336 Node* check = 349 Node* check =
337 graph()->NewNode(simplified()->ObjectIsSmi(), this_value); 350 graph()->NewNode(simplified()->ObjectIsSmi(), this_value);
338 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 351 this_control =
339 check, this_control); 352 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
340 exit_controls.push_back( 353 this_effect, this_control);
341 graph()->NewNode(common()->IfFalse(), branch));
342 this_control = graph()->NewNode(common()->IfTrue(), branch);
343 this_value = graph()->NewNode(common()->Guard(type_cache_.kSmi), 354 this_value = graph()->NewNode(common()->Guard(type_cache_.kSmi),
344 this_value, this_control); 355 this_value, this_control);
345 } else if (field_type->Is(Type::TaggedPointer())) { 356 } else if (field_type->Is(Type::TaggedPointer())) {
346 Node* check = 357 Node* check =
347 graph()->NewNode(simplified()->ObjectIsSmi(), this_value); 358 graph()->NewNode(simplified()->ObjectIsSmi(), this_value);
348 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), 359 this_control =
349 check, this_control); 360 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
350 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); 361 this_effect, this_control);
351 this_control = graph()->NewNode(common()->IfFalse(), branch); 362 if (field_type->NumClasses() == 1) {
352 if (field_type->NumClasses() > 0) { 363 // Emit a map check for the value.
353 // Emit a (sequence of) map checks for the value.
354 ZoneVector<Node*> this_controls(zone());
355 Node* this_value_map = this_effect = graph()->NewNode( 364 Node* this_value_map = this_effect = graph()->NewNode(
356 simplified()->LoadField(AccessBuilder::ForMap()), this_value, 365 simplified()->LoadField(AccessBuilder::ForMap()), this_value,
357 this_effect, this_control); 366 this_effect, this_control);
358 for (auto i = field_type->Classes(); !i.Done(); i.Advance()) { 367 Node* check = graph()->NewNode(
359 Handle<Map> field_map(i.Current()); 368 simplified()->ReferenceEqual(Type::Internal()), this_value_map,
360 check = graph()->NewNode( 369 jsgraph()->Constant(field_type->Classes().Current()));
361 simplified()->ReferenceEqual(Type::Internal()),
362 this_value_map, jsgraph()->Constant(field_map));
363 branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
364 check, this_control);
365 this_control = graph()->NewNode(common()->IfFalse(), branch);
366 this_controls.push_back(
367 graph()->NewNode(common()->IfTrue(), branch));
368 }
369 exit_controls.push_back(this_control);
370 int const this_control_count =
371 static_cast<int>(this_controls.size());
372 this_control = 370 this_control =
373 (this_control_count == 1) 371 graph()->NewNode(common()->DeoptimizeUnless(), check,
374 ? this_controls.front() 372 frame_state, this_effect, this_control);
375 : graph()->NewNode(common()->Merge(this_control_count), 373 } else {
376 this_control_count, 374 DCHECK_EQ(0, field_type->NumClasses());
377 &this_controls.front());
378 } 375 }
379 } else { 376 } else {
380 DCHECK(field_type->Is(Type::Tagged())); 377 DCHECK(field_type->Is(Type::Tagged()));
381 } 378 }
382 Handle<Map> transition_map; 379 Handle<Map> transition_map;
383 if (access_info.transition_map().ToHandle(&transition_map)) { 380 if (access_info.transition_map().ToHandle(&transition_map)) {
384 this_effect = graph()->NewNode(common()->BeginRegion(), this_effect); 381 this_effect = graph()->NewNode(common()->BeginRegion(), this_effect);
385 this_effect = graph()->NewNode( 382 this_effect = graph()->NewNode(
386 simplified()->StoreField(AccessBuilder::ForMap()), this_receiver, 383 simplified()->StoreField(AccessBuilder::ForMap()), this_receiver,
387 jsgraph()->Constant(transition_map), this_effect, this_control); 384 jsgraph()->Constant(transition_map), this_effect, this_control);
388 } 385 }
389 this_effect = graph()->NewNode(simplified()->StoreField(field_access), 386 this_effect = graph()->NewNode(simplified()->StoreField(field_access),
390 this_storage, this_value, this_effect, 387 this_storage, this_value, this_effect,
391 this_control); 388 this_control);
392 if (access_info.HasTransitionMap()) { 389 if (access_info.HasTransitionMap()) {
393 this_effect = 390 this_effect =
394 graph()->NewNode(common()->FinishRegion(), 391 graph()->NewNode(common()->FinishRegion(),
395 jsgraph()->UndefinedConstant(), this_effect); 392 jsgraph()->UndefinedConstant(), this_effect);
396 } 393 }
397 } 394 }
398 } 395 }
399 396
400 // Remember the final state for this property access. 397 // Remember the final state for this property access.
401 values.push_back(this_value); 398 values.push_back(this_value);
402 effects.push_back(this_effect); 399 effects.push_back(this_effect);
403 controls.push_back(this_control); 400 controls.push_back(this_control);
404 } 401 }
405 402
406 // Collect the fallthrough control as final "exit" control. 403 DCHECK_NULL(fallthrough_control);
407 if (fallthrough_control != control) {
408 // Mark the last fallthrough branch as deferred.
409 MarkAsDeferred(fallthrough_control);
410 }
411 exit_controls.push_back(fallthrough_control);
412
413 // Also collect the "receiver is smi" control if we didn't handle the case of
414 // Number primitives in the polymorphic branches above.
415 if (receiverissmi_control != nullptr) {
416 // Mark the "receiver is smi" case as deferred.
417 MarkAsDeferred(receiverissmi_control);
418 DCHECK_EQ(exit_effect, receiverissmi_effect);
419 exit_controls.push_back(receiverissmi_control);
420 }
421
422 // Generate the single "exit" point, where we get if either all map/instance
423 // type checks failed, or one of the assumptions inside one of the cases
424 // failes (i.e. failing prototype chain check).
425 // TODO(bmeurer): Consider falling back to IC here if deoptimization is
426 // disabled.
427 int const exit_control_count = static_cast<int>(exit_controls.size());
428 Node* exit_control =
429 (exit_control_count == 1)
430 ? exit_controls.front()
431 : graph()->NewNode(common()->Merge(exit_control_count),
432 exit_control_count, &exit_controls.front());
433 Node* deoptimize =
434 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
435 frame_state, exit_effect, exit_control);
436 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
437 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
438 Revisit(graph()->end());
439 404
440 // Generate the final merge point for all (polymorphic) branches. 405 // Generate the final merge point for all (polymorphic) branches.
441 int const control_count = static_cast<int>(controls.size()); 406 int const control_count = static_cast<int>(controls.size());
442 if (control_count == 0) { 407 if (control_count == 0) {
443 value = effect = control = jsgraph()->Dead(); 408 value = effect = control = jsgraph()->Dead();
444 } else if (control_count == 1) { 409 } else if (control_count == 1) {
445 value = values.front(); 410 value = values.front();
446 effect = effects.front(); 411 effect = effects.front();
447 control = controls.front(); 412 control = controls.front();
448 } else { 413 } else {
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 520
556 // Nothing to do if we have no non-deprecated maps. 521 // Nothing to do if we have no non-deprecated maps.
557 if (access_infos.empty()) return NoChange(); 522 if (access_infos.empty()) return NoChange();
558 523
559 // The final states for every polymorphic branch. We join them with 524 // The final states for every polymorphic branch. We join them with
560 // Merge+Phi+EffectPhi at the bottom. 525 // Merge+Phi+EffectPhi at the bottom.
561 ZoneVector<Node*> values(zone()); 526 ZoneVector<Node*> values(zone());
562 ZoneVector<Node*> effects(zone()); 527 ZoneVector<Node*> effects(zone());
563 ZoneVector<Node*> controls(zone()); 528 ZoneVector<Node*> controls(zone());
564 529
565 // The list of "exiting" controls, which currently go to a single deoptimize.
566 // TODO(bmeurer): Consider using an IC as fallback.
567 Node* const exit_effect = effect;
568 ZoneVector<Node*> exit_controls(zone());
569
570 // Ensure that {receiver} is a heap object. 530 // Ensure that {receiver} is a heap object.
571 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); 531 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
572 Node* branch = 532 control = graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
573 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); 533 effect, control);
574 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
575 control = graph()->NewNode(common()->IfFalse(), branch);
576 534
577 // Load the {receiver} map. The resulting effect is the dominating effect for 535 // Load the {receiver} map. The resulting effect is the dominating effect for
578 // all (polymorphic) branches. 536 // all (polymorphic) branches.
579 Node* receiver_map = effect = 537 Node* receiver_map = effect =
580 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 538 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
581 receiver, effect, control); 539 receiver, effect, control);
582 540
583 // Generate code for the various different element access patterns. 541 // Generate code for the various different element access patterns.
584 Node* fallthrough_control = control; 542 Node* fallthrough_control = control;
585 for (ElementAccessInfo const& access_info : access_infos) { 543 for (size_t j = 0; j < access_infos.size(); ++j) {
544 ElementAccessInfo const& access_info = access_infos[j];
586 Node* this_receiver = receiver; 545 Node* this_receiver = receiver;
587 Node* this_value = value; 546 Node* this_value = value;
588 Node* this_index = index; 547 Node* this_index = index;
589 Node* this_effect; 548 Node* this_effect;
590 Node* this_control; 549 Node* this_control;
591 550
592 // Perform map check on {receiver}. 551 // Perform map check on {receiver}.
593 Type* receiver_type = access_info.receiver_type(); 552 Type* receiver_type = access_info.receiver_type();
594 bool receiver_is_jsarray = true; 553 bool receiver_is_jsarray = true;
595 { 554 {
596 ZoneVector<Node*> this_controls(zone()); 555 ZoneVector<Node*> this_controls(zone());
597 ZoneVector<Node*> this_effects(zone()); 556 ZoneVector<Node*> this_effects(zone());
557 size_t num_transitions = access_info.transitions().size();
558 int num_classes = access_info.receiver_type()->NumClasses();
598 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); 559 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
599 i.Advance()) { 560 i.Advance()) {
561 DCHECK_LT(0, num_classes);
600 Handle<Map> map = i.Current(); 562 Handle<Map> map = i.Current();
601 Node* check = 563 Node* check =
602 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), 564 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
603 receiver_map, jsgraph()->Constant(map)); 565 receiver_map, jsgraph()->Constant(map));
604 Node* branch = 566 if (--num_classes == 0 && num_transitions == 0 &&
605 graph()->NewNode(common()->Branch(), check, fallthrough_control); 567 j == access_infos.size() - 1) {
606 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); 568 // Last map check on the fallthrough control path, do a conditional
569 // eager deoptimization exit here.
570 // TODO(turbofan): This is ugly as hell! We should probably introduce
571 // macro-ish operators for property access that encapsulate this whole
572 // mess.
573 this_controls.push_back(graph()->NewNode(common()->DeoptimizeUnless(),
574 check, frame_state, effect,
575 fallthrough_control));
576 fallthrough_control = nullptr;
577 } else {
578 Node* branch =
579 graph()->NewNode(common()->Branch(), check, fallthrough_control);
580 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
581 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
582 }
607 this_effects.push_back(effect); 583 this_effects.push_back(effect);
608 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
609 if (!map->IsJSArrayMap()) receiver_is_jsarray = false; 584 if (!map->IsJSArrayMap()) receiver_is_jsarray = false;
610 } 585 }
611 586
612 // Generate possible elements kind transitions. 587 // Generate possible elements kind transitions.
613 for (auto transition : access_info.transitions()) { 588 for (auto transition : access_info.transitions()) {
589 DCHECK_LT(0u, num_transitions);
614 Handle<Map> transition_source = transition.first; 590 Handle<Map> transition_source = transition.first;
615 Handle<Map> transition_target = transition.second; 591 Handle<Map> transition_target = transition.second;
592 Node* transition_control;
593 Node* transition_effect = effect;
616 594
617 // Check if {receiver} has the specified {transition_source} map. 595 // Check if {receiver} has the specified {transition_source} map.
618 Node* check = graph()->NewNode( 596 Node* check = graph()->NewNode(
619 simplified()->ReferenceEqual(Type::Any()), receiver_map, 597 simplified()->ReferenceEqual(Type::Any()), receiver_map,
620 jsgraph()->HeapConstant(transition_source)); 598 jsgraph()->HeapConstant(transition_source));
621 Node* branch = 599 if (--num_transitions == 0 && j == access_infos.size() - 1) {
622 graph()->NewNode(common()->Branch(), check, fallthrough_control); 600 transition_control =
601 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
602 transition_effect, fallthrough_control);
603 fallthrough_control = nullptr;
604 } else {
605 Node* branch =
606 graph()->NewNode(common()->Branch(), check, fallthrough_control);
607 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
608 transition_control = graph()->NewNode(common()->IfTrue(), branch);
609 }
623 610
624 // Migrate {receiver} from {transition_source} to {transition_target}. 611 // Migrate {receiver} from {transition_source} to {transition_target}.
625 Node* transition_control = graph()->NewNode(common()->IfTrue(), branch);
626 Node* transition_effect = effect;
627 if (IsSimpleMapChangeTransition(transition_source->elements_kind(), 612 if (IsSimpleMapChangeTransition(transition_source->elements_kind(),
628 transition_target->elements_kind())) { 613 transition_target->elements_kind())) {
629 // In-place migration, just store the {transition_target} map. 614 // In-place migration, just store the {transition_target} map.
630 transition_effect = graph()->NewNode( 615 transition_effect = graph()->NewNode(
631 simplified()->StoreField(AccessBuilder::ForMap()), receiver, 616 simplified()->StoreField(AccessBuilder::ForMap()), receiver,
632 jsgraph()->HeapConstant(transition_target), transition_effect, 617 jsgraph()->HeapConstant(transition_target), transition_effect,
633 transition_control); 618 transition_control);
634 } else { 619 } else {
635 // Instance migration, let the stub deal with the {receiver}. 620 // Instance migration, let the stub deal with the {receiver}.
636 TransitionElementsKindStub stub(isolate(), 621 TransitionElementsKindStub stub(isolate(),
637 transition_source->elements_kind(), 622 transition_source->elements_kind(),
638 transition_target->elements_kind(), 623 transition_target->elements_kind(),
639 transition_source->IsJSArrayMap()); 624 transition_source->IsJSArrayMap());
640 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 625 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
641 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 0, 626 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 0,
642 CallDescriptor::kNeedsFrameState, node->op()->properties()); 627 CallDescriptor::kNeedsFrameState, node->op()->properties());
643 transition_effect = graph()->NewNode( 628 transition_effect = graph()->NewNode(
644 common()->Call(desc), jsgraph()->HeapConstant(stub.GetCode()), 629 common()->Call(desc), jsgraph()->HeapConstant(stub.GetCode()),
645 receiver, jsgraph()->HeapConstant(transition_target), context, 630 receiver, jsgraph()->HeapConstant(transition_target), context,
646 frame_state, transition_effect, transition_control); 631 frame_state, transition_effect, transition_control);
647 } 632 }
648 this_controls.push_back(transition_control); 633 this_controls.push_back(transition_control);
649 this_effects.push_back(transition_effect); 634 this_effects.push_back(transition_effect);
650
651 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
652 } 635 }
653 636
654 // Create single chokepoint for the control. 637 // Create single chokepoint for the control.
655 int const this_control_count = static_cast<int>(this_controls.size()); 638 int const this_control_count = static_cast<int>(this_controls.size());
656 if (this_control_count == 1) { 639 if (this_control_count == 1) {
657 this_control = this_controls.front(); 640 this_control = this_controls.front();
658 this_effect = this_effects.front(); 641 this_effect = this_effects.front();
659 } else { 642 } else {
660 this_control = 643 this_control =
661 graph()->NewNode(common()->Merge(this_control_count), 644 graph()->NewNode(common()->Merge(this_control_count),
(...skipping 10 matching lines...) Expand all
672 // not compatible with (monomorphic) keyed stores. 655 // not compatible with (monomorphic) keyed stores.
673 Handle<JSObject> holder; 656 Handle<JSObject> holder;
674 if (access_info.holder().ToHandle(&holder)) { 657 if (access_info.holder().ToHandle(&holder)) {
675 AssumePrototypesStable(receiver_type, native_context, holder); 658 AssumePrototypesStable(receiver_type, native_context, holder);
676 } 659 }
677 660
678 // Check that the {index} is actually a Number. 661 // Check that the {index} is actually a Number.
679 if (!NumberMatcher(this_index).HasValue()) { 662 if (!NumberMatcher(this_index).HasValue()) {
680 Node* check = 663 Node* check =
681 graph()->NewNode(simplified()->ObjectIsNumber(), this_index); 664 graph()->NewNode(simplified()->ObjectIsNumber(), this_index);
682 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 665 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
683 check, this_control); 666 frame_state, this_effect, this_control);
684 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
685 this_control = graph()->NewNode(common()->IfTrue(), branch);
686 this_index = graph()->NewNode(common()->Guard(Type::Number()), this_index, 667 this_index = graph()->NewNode(common()->Guard(Type::Number()), this_index,
687 this_control); 668 this_control);
688 } 669 }
689 670
690 // Convert the {index} to an unsigned32 value and check if the result is 671 // Convert the {index} to an unsigned32 value and check if the result is
691 // equal to the original {index}. 672 // equal to the original {index}.
692 if (!NumberMatcher(this_index).IsInRange(0.0, kMaxUInt32)) { 673 if (!NumberMatcher(this_index).IsInRange(0.0, kMaxUInt32)) {
693 Node* this_index32 = 674 Node* this_index32 =
694 graph()->NewNode(simplified()->NumberToUint32(), this_index); 675 graph()->NewNode(simplified()->NumberToUint32(), this_index);
695 Node* check = graph()->NewNode(simplified()->NumberEqual(), this_index32, 676 Node* check = graph()->NewNode(simplified()->NumberEqual(), this_index32,
696 this_index); 677 this_index);
697 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 678 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
698 check, this_control); 679 frame_state, this_effect, this_control);
699 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
700 this_control = graph()->NewNode(common()->IfTrue(), branch);
701 this_index = this_index32; 680 this_index = this_index32;
702 } 681 }
703 682
704 // TODO(bmeurer): We currently specialize based on elements kind. We should 683 // TODO(bmeurer): We currently specialize based on elements kind. We should
705 // also be able to properly support strings and other JSObjects here. 684 // also be able to properly support strings and other JSObjects here.
706 ElementsKind elements_kind = access_info.elements_kind(); 685 ElementsKind elements_kind = access_info.elements_kind();
707 686
708 // Load the elements for the {receiver}. 687 // Load the elements for the {receiver}.
709 Node* this_elements = this_effect = graph()->NewNode( 688 Node* this_elements = this_effect = graph()->NewNode(
710 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 689 simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
711 this_receiver, this_effect, this_control); 690 this_receiver, this_effect, this_control);
712 691
713 // Don't try to store to a copy-on-write backing store. 692 // Don't try to store to a copy-on-write backing store.
714 if (access_mode == AccessMode::kStore && 693 if (access_mode == AccessMode::kStore &&
715 IsFastSmiOrObjectElementsKind(elements_kind)) { 694 IsFastSmiOrObjectElementsKind(elements_kind)) {
716 Node* this_elements_map = this_effect = 695 Node* this_elements_map = this_effect =
717 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 696 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
718 this_elements, this_effect, this_control); 697 this_elements, this_effect, this_control);
719 check = graph()->NewNode( 698 Node* check = graph()->NewNode(
720 simplified()->ReferenceEqual(Type::Any()), this_elements_map, 699 simplified()->ReferenceEqual(Type::Any()), this_elements_map,
721 jsgraph()->HeapConstant(factory()->fixed_array_map())); 700 jsgraph()->HeapConstant(factory()->fixed_array_map()));
722 branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), check, 701 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
723 this_control); 702 frame_state, this_effect, this_control);
724 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
725 this_control = graph()->NewNode(common()->IfTrue(), branch);
726 } 703 }
727 704
728 // Load the length of the {receiver}. 705 // Load the length of the {receiver}.
729 Node* this_length = this_effect = 706 Node* this_length = this_effect =
730 receiver_is_jsarray 707 receiver_is_jsarray
731 ? graph()->NewNode( 708 ? graph()->NewNode(
732 simplified()->LoadField( 709 simplified()->LoadField(
733 AccessBuilder::ForJSArrayLength(elements_kind)), 710 AccessBuilder::ForJSArrayLength(elements_kind)),
734 this_receiver, this_effect, this_control) 711 this_receiver, this_effect, this_control)
735 : graph()->NewNode( 712 : graph()->NewNode(
736 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), 713 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
737 this_elements, this_effect, this_control); 714 this_elements, this_effect, this_control);
738 715
739 // Check that the {index} is in the valid range for the {receiver}. 716 // Check that the {index} is in the valid range for the {receiver}.
740 Node* check = graph()->NewNode(simplified()->NumberLessThan(), this_index, 717 Node* check = graph()->NewNode(simplified()->NumberLessThan(), this_index,
741 this_length); 718 this_length);
742 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), check, 719 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
743 this_control); 720 frame_state, this_effect, this_control);
744 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
745 this_control = graph()->NewNode(common()->IfTrue(), branch);
746 721
747 // Compute the element access. 722 // Compute the element access.
748 Type* element_type = Type::Any(); 723 Type* element_type = Type::Any();
749 MachineType element_machine_type = MachineType::AnyTagged(); 724 MachineType element_machine_type = MachineType::AnyTagged();
750 if (IsFastDoubleElementsKind(elements_kind)) { 725 if (IsFastDoubleElementsKind(elements_kind)) {
751 element_type = Type::Number(); 726 element_type = Type::Number();
752 element_machine_type = MachineType::Float64(); 727 element_machine_type = MachineType::Float64();
753 } else if (IsFastSmiElementsKind(elements_kind)) { 728 } else if (IsFastSmiElementsKind(elements_kind)) {
754 element_type = type_cache_.kSmi; 729 element_type = type_cache_.kSmi;
755 } 730 }
(...skipping 18 matching lines...) Expand all
774 simplified()->LoadElement(element_access), this_elements, this_index, 749 simplified()->LoadElement(element_access), this_elements, this_index,
775 this_effect, this_control); 750 this_effect, this_control);
776 // Handle loading from holey backing stores correctly, by either mapping 751 // Handle loading from holey backing stores correctly, by either mapping
777 // the hole to undefined if possible, or deoptimizing otherwise. 752 // the hole to undefined if possible, or deoptimizing otherwise.
778 if (elements_kind == FAST_HOLEY_ELEMENTS || 753 if (elements_kind == FAST_HOLEY_ELEMENTS ||
779 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { 754 elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
780 // Perform the hole check on the result. 755 // Perform the hole check on the result.
781 Node* check = 756 Node* check =
782 graph()->NewNode(simplified()->ReferenceEqual(element_access.type), 757 graph()->NewNode(simplified()->ReferenceEqual(element_access.type),
783 this_value, jsgraph()->TheHoleConstant()); 758 this_value, jsgraph()->TheHoleConstant());
784 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
785 check, this_control);
786 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
787 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
788 // Check if we are allowed to turn the hole into undefined. 759 // Check if we are allowed to turn the hole into undefined.
789 Type* initial_holey_array_type = Type::Class( 760 Type* initial_holey_array_type = Type::Class(
790 handle(isolate()->get_initial_js_array_map(elements_kind)), 761 handle(isolate()->get_initial_js_array_map(elements_kind)),
791 graph()->zone()); 762 graph()->zone());
792 if (receiver_type->NowIs(initial_holey_array_type) && 763 if (receiver_type->NowIs(initial_holey_array_type) &&
793 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { 764 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
765 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
766 check, this_control);
767 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
768 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
794 // Add a code dependency on the array protector cell. 769 // Add a code dependency on the array protector cell.
795 AssumePrototypesStable(receiver_type, native_context, 770 AssumePrototypesStable(receiver_type, native_context,
796 isolate()->initial_object_prototype()); 771 isolate()->initial_object_prototype());
797 dependencies()->AssumePropertyCell(factory()->array_protector()); 772 dependencies()->AssumePropertyCell(factory()->array_protector());
798 // Turn the hole into undefined. 773 // Turn the hole into undefined.
799 this_control = 774 this_control =
800 graph()->NewNode(common()->Merge(2), if_true, if_false); 775 graph()->NewNode(common()->Merge(2), if_true, if_false);
801 this_value = graph()->NewNode( 776 this_value = graph()->NewNode(
802 common()->Phi(MachineRepresentation::kTagged, 2), 777 common()->Phi(MachineRepresentation::kTagged, 2),
803 jsgraph()->UndefinedConstant(), this_value, this_control); 778 jsgraph()->UndefinedConstant(), this_value, this_control);
804 element_type = 779 element_type =
805 Type::Union(element_type, Type::Undefined(), graph()->zone()); 780 Type::Union(element_type, Type::Undefined(), graph()->zone());
806 } else { 781 } else {
807 // Deoptimize in case of the hole. 782 // Deoptimize in case of the hole.
808 exit_controls.push_back(if_true); 783 this_control =
809 this_control = if_false; 784 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
785 this_effect, this_control);
810 } 786 }
811 // Rename the result to represent the actual type (not polluted by the 787 // Rename the result to represent the actual type (not polluted by the
812 // hole). 788 // hole).
813 this_value = graph()->NewNode(common()->Guard(element_type), this_value, 789 this_value = graph()->NewNode(common()->Guard(element_type), this_value,
814 this_control); 790 this_control);
815 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { 791 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
816 // Perform the hole check on the result. 792 // Perform the hole check on the result.
817 Node* check = 793 Node* check =
818 graph()->NewNode(simplified()->NumberIsHoleNaN(), this_value); 794 graph()->NewNode(simplified()->NumberIsHoleNaN(), this_value);
819 // Check if we are allowed to return the hole directly. 795 // Check if we are allowed to return the hole directly.
820 Type* initial_holey_array_type = Type::Class( 796 Type* initial_holey_array_type = Type::Class(
821 handle(isolate()->get_initial_js_array_map(elements_kind)), 797 handle(isolate()->get_initial_js_array_map(elements_kind)),
822 graph()->zone()); 798 graph()->zone());
823 if (receiver_type->NowIs(initial_holey_array_type) && 799 if (receiver_type->NowIs(initial_holey_array_type) &&
824 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { 800 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
825 // Add a code dependency on the array protector cell. 801 // Add a code dependency on the array protector cell.
826 AssumePrototypesStable(receiver_type, native_context, 802 AssumePrototypesStable(receiver_type, native_context,
827 isolate()->initial_object_prototype()); 803 isolate()->initial_object_prototype());
828 dependencies()->AssumePropertyCell(factory()->array_protector()); 804 dependencies()->AssumePropertyCell(factory()->array_protector());
829 // Turn the hole into undefined. 805 // Turn the hole into undefined.
830 this_value = graph()->NewNode( 806 this_value = graph()->NewNode(
831 common()->Select(MachineRepresentation::kTagged, 807 common()->Select(MachineRepresentation::kTagged,
832 BranchHint::kFalse), 808 BranchHint::kFalse),
833 check, jsgraph()->UndefinedConstant(), this_value); 809 check, jsgraph()->UndefinedConstant(), this_value);
834 } else { 810 } else {
835 // Deoptimize in case of the hole. 811 // Deoptimize in case of the hole.
836 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), 812 this_control =
837 check, this_control); 813 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
838 this_control = graph()->NewNode(common()->IfFalse(), branch); 814 this_effect, this_control);
839 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
840 } 815 }
841 } 816 }
842 } else { 817 } else {
843 DCHECK_EQ(AccessMode::kStore, access_mode); 818 DCHECK_EQ(AccessMode::kStore, access_mode);
844 if (IsFastSmiElementsKind(elements_kind)) { 819 if (IsFastSmiElementsKind(elements_kind)) {
845 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value); 820 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value);
846 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 821 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
847 check, this_control); 822 frame_state, this_effect, this_control);
848 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
849 this_control = graph()->NewNode(common()->IfTrue(), branch);
850 this_value = graph()->NewNode(common()->Guard(type_cache_.kSmi), 823 this_value = graph()->NewNode(common()->Guard(type_cache_.kSmi),
851 this_value, this_control); 824 this_value, this_control);
852 } else if (IsFastDoubleElementsKind(elements_kind)) { 825 } else if (IsFastDoubleElementsKind(elements_kind)) {
853 Node* check = 826 Node* check =
854 graph()->NewNode(simplified()->ObjectIsNumber(), this_value); 827 graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
855 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 828 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
856 check, this_control); 829 frame_state, this_effect, this_control);
857 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
858 this_control = graph()->NewNode(common()->IfTrue(), branch);
859 this_value = graph()->NewNode(common()->Guard(Type::Number()), 830 this_value = graph()->NewNode(common()->Guard(Type::Number()),
860 this_value, this_control); 831 this_value, this_control);
861 } 832 }
862 this_effect = graph()->NewNode(simplified()->StoreElement(element_access), 833 this_effect = graph()->NewNode(simplified()->StoreElement(element_access),
863 this_elements, this_index, this_value, 834 this_elements, this_index, this_value,
864 this_effect, this_control); 835 this_effect, this_control);
865 } 836 }
866 837
867 // Remember the final state for this element access. 838 // Remember the final state for this element access.
868 values.push_back(this_value); 839 values.push_back(this_value);
869 effects.push_back(this_effect); 840 effects.push_back(this_effect);
870 controls.push_back(this_control); 841 controls.push_back(this_control);
871 } 842 }
872 843
873 // Collect the fallthrough control as final "exit" control. 844 DCHECK_NULL(fallthrough_control);
874 if (fallthrough_control != control) {
875 // Mark the last fallthrough branch as deferred.
876 MarkAsDeferred(fallthrough_control);
877 }
878 exit_controls.push_back(fallthrough_control);
879
880 // Generate the single "exit" point, where we get if either all map/instance
881 // type checks failed, or one of the assumptions inside one of the cases
882 // failes (i.e. failing prototype chain check).
883 // TODO(bmeurer): Consider falling back to IC here if deoptimization is
884 // disabled.
885 int const exit_control_count = static_cast<int>(exit_controls.size());
886 Node* exit_control =
887 (exit_control_count == 1)
888 ? exit_controls.front()
889 : graph()->NewNode(common()->Merge(exit_control_count),
890 exit_control_count, &exit_controls.front());
891 Node* deoptimize =
892 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
893 frame_state, exit_effect, exit_control);
894 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
895 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
896 Revisit(graph()->end());
897 845
898 // Generate the final merge point for all (polymorphic) branches. 846 // Generate the final merge point for all (polymorphic) branches.
899 int const control_count = static_cast<int>(controls.size()); 847 int const control_count = static_cast<int>(controls.size());
900 if (control_count == 0) { 848 if (control_count == 0) {
901 value = effect = control = jsgraph()->Dead(); 849 value = effect = control = jsgraph()->Dead();
902 } else if (control_count == 1) { 850 } else if (control_count == 1) {
903 value = values.front(); 851 value = values.front();
904 effect = effects.front(); 852 effect = effects.front();
905 control = controls.front(); 853 control = controls.front();
906 } else { 854 } else {
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1041 Handle<JSFunction> constructor; 989 Handle<JSFunction> constructor;
1042 if (Map::GetConstructorFunction(map, native_context) 990 if (Map::GetConstructorFunction(map, native_context)
1043 .ToHandle(&constructor)) { 991 .ToHandle(&constructor)) {
1044 map = handle(constructor->initial_map(), isolate()); 992 map = handle(constructor->initial_map(), isolate());
1045 } 993 }
1046 dependencies()->AssumePrototypeMapsStable(map, holder); 994 dependencies()->AssumePrototypeMapsStable(map, holder);
1047 } 995 }
1048 } 996 }
1049 997
1050 998
1051 void JSNativeContextSpecialization::MarkAsDeferred(Node* if_projection) {
1052 Node* branch = NodeProperties::GetControlInput(if_projection);
1053 DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
1054 if (if_projection->opcode() == IrOpcode::kIfTrue) {
1055 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse));
1056 } else {
1057 DCHECK_EQ(IrOpcode::kIfFalse, if_projection->opcode());
1058 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue));
1059 }
1060 }
1061
1062
1063 MaybeHandle<Context> JSNativeContextSpecialization::GetNativeContext( 999 MaybeHandle<Context> JSNativeContextSpecialization::GetNativeContext(
1064 Node* node) { 1000 Node* node) {
1065 Node* const context = NodeProperties::GetContextInput(node); 1001 Node* const context = NodeProperties::GetContextInput(node);
1066 return NodeProperties::GetSpecializationNativeContext(context, 1002 return NodeProperties::GetSpecializationNativeContext(context,
1067 native_context()); 1003 native_context());
1068 } 1004 }
1069 1005
1070 1006
1071 Graph* JSNativeContextSpecialization::graph() const { 1007 Graph* JSNativeContextSpecialization::graph() const {
1072 return jsgraph()->graph(); 1008 return jsgraph()->graph();
(...skipping 25 matching lines...) Expand all
1098 } 1034 }
1099 1035
1100 1036
1101 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 1037 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
1102 return jsgraph()->simplified(); 1038 return jsgraph()->simplified();
1103 } 1039 }
1104 1040
1105 } // namespace compiler 1041 } // namespace compiler
1106 } // namespace internal 1042 } // namespace internal
1107 } // namespace v8 1043 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | src/compiler/mips/instruction-selector-mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698