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

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: Fix 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 &&
Jarin 2016/02/24 08:56:38 Side-effect in shortcut operators, what could poss
Benedikt Meurer 2016/02/24 09:04:56 Acknowledged.
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 this_controls.push_back(graph()->NewNode(common()->DeoptimizeUnless(),
Jarin 2016/02/24 08:56:38 Please, add a comment explaining what you are doin
Benedikt Meurer 2016/02/24 09:04:56 Done.
569 check, frame_state, effect,
570 fallthrough_control));
571 fallthrough_control = nullptr;
572 } else {
573 Node* branch =
574 graph()->NewNode(common()->Branch(), check, fallthrough_control);
575 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
576 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
577 }
607 this_effects.push_back(effect); 578 this_effects.push_back(effect);
608 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
609 if (!map->IsJSArrayMap()) receiver_is_jsarray = false; 579 if (!map->IsJSArrayMap()) receiver_is_jsarray = false;
610 } 580 }
611 581
612 // Generate possible elements kind transitions. 582 // Generate possible elements kind transitions.
613 for (auto transition : access_info.transitions()) { 583 for (auto transition : access_info.transitions()) {
584 DCHECK_LT(0u, num_transitions);
614 Handle<Map> transition_source = transition.first; 585 Handle<Map> transition_source = transition.first;
615 Handle<Map> transition_target = transition.second; 586 Handle<Map> transition_target = transition.second;
587 Node* transition_control;
588 Node* transition_effect = effect;
616 589
617 // Check if {receiver} has the specified {transition_source} map. 590 // Check if {receiver} has the specified {transition_source} map.
618 Node* check = graph()->NewNode( 591 Node* check = graph()->NewNode(
619 simplified()->ReferenceEqual(Type::Any()), receiver_map, 592 simplified()->ReferenceEqual(Type::Any()), receiver_map,
620 jsgraph()->HeapConstant(transition_source)); 593 jsgraph()->HeapConstant(transition_source));
621 Node* branch = 594 if (--num_transitions == 0 && j == access_infos.size() - 1) {
622 graph()->NewNode(common()->Branch(), check, fallthrough_control); 595 transition_control =
596 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
597 transition_effect, fallthrough_control);
598 fallthrough_control = nullptr;
599 } else {
600 Node* branch =
601 graph()->NewNode(common()->Branch(), check, fallthrough_control);
602 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
603 transition_control = graph()->NewNode(common()->IfTrue(), branch);
604 }
623 605
624 // Migrate {receiver} from {transition_source} to {transition_target}. 606 // 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(), 607 if (IsSimpleMapChangeTransition(transition_source->elements_kind(),
628 transition_target->elements_kind())) { 608 transition_target->elements_kind())) {
629 // In-place migration, just store the {transition_target} map. 609 // In-place migration, just store the {transition_target} map.
630 transition_effect = graph()->NewNode( 610 transition_effect = graph()->NewNode(
631 simplified()->StoreField(AccessBuilder::ForMap()), receiver, 611 simplified()->StoreField(AccessBuilder::ForMap()), receiver,
632 jsgraph()->HeapConstant(transition_target), transition_effect, 612 jsgraph()->HeapConstant(transition_target), transition_effect,
633 transition_control); 613 transition_control);
634 } else { 614 } else {
635 // Instance migration, let the stub deal with the {receiver}. 615 // Instance migration, let the stub deal with the {receiver}.
636 TransitionElementsKindStub stub(isolate(), 616 TransitionElementsKindStub stub(isolate(),
637 transition_source->elements_kind(), 617 transition_source->elements_kind(),
638 transition_target->elements_kind(), 618 transition_target->elements_kind(),
639 transition_source->IsJSArrayMap()); 619 transition_source->IsJSArrayMap());
640 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 620 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
641 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 0, 621 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 0,
642 CallDescriptor::kNeedsFrameState, node->op()->properties()); 622 CallDescriptor::kNeedsFrameState, node->op()->properties());
643 transition_effect = graph()->NewNode( 623 transition_effect = graph()->NewNode(
644 common()->Call(desc), jsgraph()->HeapConstant(stub.GetCode()), 624 common()->Call(desc), jsgraph()->HeapConstant(stub.GetCode()),
645 receiver, jsgraph()->HeapConstant(transition_target), context, 625 receiver, jsgraph()->HeapConstant(transition_target), context,
646 frame_state, transition_effect, transition_control); 626 frame_state, transition_effect, transition_control);
647 } 627 }
648 this_controls.push_back(transition_control); 628 this_controls.push_back(transition_control);
649 this_effects.push_back(transition_effect); 629 this_effects.push_back(transition_effect);
650
651 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
652 } 630 }
653 631
654 // Create single chokepoint for the control. 632 // Create single chokepoint for the control.
655 int const this_control_count = static_cast<int>(this_controls.size()); 633 int const this_control_count = static_cast<int>(this_controls.size());
656 if (this_control_count == 1) { 634 if (this_control_count == 1) {
657 this_control = this_controls.front(); 635 this_control = this_controls.front();
658 this_effect = this_effects.front(); 636 this_effect = this_effects.front();
659 } else { 637 } else {
660 this_control = 638 this_control =
661 graph()->NewNode(common()->Merge(this_control_count), 639 graph()->NewNode(common()->Merge(this_control_count),
(...skipping 10 matching lines...) Expand all
672 // not compatible with (monomorphic) keyed stores. 650 // not compatible with (monomorphic) keyed stores.
673 Handle<JSObject> holder; 651 Handle<JSObject> holder;
674 if (access_info.holder().ToHandle(&holder)) { 652 if (access_info.holder().ToHandle(&holder)) {
675 AssumePrototypesStable(receiver_type, native_context, holder); 653 AssumePrototypesStable(receiver_type, native_context, holder);
676 } 654 }
677 655
678 // Check that the {index} is actually a Number. 656 // Check that the {index} is actually a Number.
679 if (!NumberMatcher(this_index).HasValue()) { 657 if (!NumberMatcher(this_index).HasValue()) {
680 Node* check = 658 Node* check =
681 graph()->NewNode(simplified()->ObjectIsNumber(), this_index); 659 graph()->NewNode(simplified()->ObjectIsNumber(), this_index);
682 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 660 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
683 check, this_control); 661 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, 662 this_index = graph()->NewNode(common()->Guard(Type::Number()), this_index,
687 this_control); 663 this_control);
688 } 664 }
689 665
690 // Convert the {index} to an unsigned32 value and check if the result is 666 // Convert the {index} to an unsigned32 value and check if the result is
691 // equal to the original {index}. 667 // equal to the original {index}.
692 if (!NumberMatcher(this_index).IsInRange(0.0, kMaxUInt32)) { 668 if (!NumberMatcher(this_index).IsInRange(0.0, kMaxUInt32)) {
693 Node* this_index32 = 669 Node* this_index32 =
694 graph()->NewNode(simplified()->NumberToUint32(), this_index); 670 graph()->NewNode(simplified()->NumberToUint32(), this_index);
695 Node* check = graph()->NewNode(simplified()->NumberEqual(), this_index32, 671 Node* check = graph()->NewNode(simplified()->NumberEqual(), this_index32,
696 this_index); 672 this_index);
697 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 673 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
698 check, this_control); 674 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; 675 this_index = this_index32;
702 } 676 }
703 677
704 // TODO(bmeurer): We currently specialize based on elements kind. We should 678 // TODO(bmeurer): We currently specialize based on elements kind. We should
705 // also be able to properly support strings and other JSObjects here. 679 // also be able to properly support strings and other JSObjects here.
706 ElementsKind elements_kind = access_info.elements_kind(); 680 ElementsKind elements_kind = access_info.elements_kind();
707 681
708 // Load the elements for the {receiver}. 682 // Load the elements for the {receiver}.
709 Node* this_elements = this_effect = graph()->NewNode( 683 Node* this_elements = this_effect = graph()->NewNode(
710 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 684 simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
711 this_receiver, this_effect, this_control); 685 this_receiver, this_effect, this_control);
712 686
713 // Don't try to store to a copy-on-write backing store. 687 // Don't try to store to a copy-on-write backing store.
714 if (access_mode == AccessMode::kStore && 688 if (access_mode == AccessMode::kStore &&
715 IsFastSmiOrObjectElementsKind(elements_kind)) { 689 IsFastSmiOrObjectElementsKind(elements_kind)) {
716 Node* this_elements_map = this_effect = 690 Node* this_elements_map = this_effect =
717 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 691 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
718 this_elements, this_effect, this_control); 692 this_elements, this_effect, this_control);
719 check = graph()->NewNode( 693 Node* check = graph()->NewNode(
720 simplified()->ReferenceEqual(Type::Any()), this_elements_map, 694 simplified()->ReferenceEqual(Type::Any()), this_elements_map,
721 jsgraph()->HeapConstant(factory()->fixed_array_map())); 695 jsgraph()->HeapConstant(factory()->fixed_array_map()));
722 branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), check, 696 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
723 this_control); 697 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 } 698 }
727 699
728 // Load the length of the {receiver}. 700 // Load the length of the {receiver}.
729 Node* this_length = this_effect = 701 Node* this_length = this_effect =
730 receiver_is_jsarray 702 receiver_is_jsarray
731 ? graph()->NewNode( 703 ? graph()->NewNode(
732 simplified()->LoadField( 704 simplified()->LoadField(
733 AccessBuilder::ForJSArrayLength(elements_kind)), 705 AccessBuilder::ForJSArrayLength(elements_kind)),
734 this_receiver, this_effect, this_control) 706 this_receiver, this_effect, this_control)
735 : graph()->NewNode( 707 : graph()->NewNode(
736 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), 708 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
737 this_elements, this_effect, this_control); 709 this_elements, this_effect, this_control);
738 710
739 // Check that the {index} is in the valid range for the {receiver}. 711 // Check that the {index} is in the valid range for the {receiver}.
740 Node* check = graph()->NewNode(simplified()->NumberLessThan(), this_index, 712 Node* check = graph()->NewNode(simplified()->NumberLessThan(), this_index,
741 this_length); 713 this_length);
742 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), check, 714 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
743 this_control); 715 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 716
747 // Compute the element access. 717 // Compute the element access.
748 Type* element_type = Type::Any(); 718 Type* element_type = Type::Any();
749 MachineType element_machine_type = MachineType::AnyTagged(); 719 MachineType element_machine_type = MachineType::AnyTagged();
750 if (IsFastDoubleElementsKind(elements_kind)) { 720 if (IsFastDoubleElementsKind(elements_kind)) {
751 element_type = Type::Number(); 721 element_type = Type::Number();
752 element_machine_type = MachineType::Float64(); 722 element_machine_type = MachineType::Float64();
753 } else if (IsFastSmiElementsKind(elements_kind)) { 723 } else if (IsFastSmiElementsKind(elements_kind)) {
754 element_type = type_cache_.kSmi; 724 element_type = type_cache_.kSmi;
755 } 725 }
(...skipping 18 matching lines...) Expand all
774 simplified()->LoadElement(element_access), this_elements, this_index, 744 simplified()->LoadElement(element_access), this_elements, this_index,
775 this_effect, this_control); 745 this_effect, this_control);
776 // Handle loading from holey backing stores correctly, by either mapping 746 // Handle loading from holey backing stores correctly, by either mapping
777 // the hole to undefined if possible, or deoptimizing otherwise. 747 // the hole to undefined if possible, or deoptimizing otherwise.
778 if (elements_kind == FAST_HOLEY_ELEMENTS || 748 if (elements_kind == FAST_HOLEY_ELEMENTS ||
779 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { 749 elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
780 // Perform the hole check on the result. 750 // Perform the hole check on the result.
781 Node* check = 751 Node* check =
782 graph()->NewNode(simplified()->ReferenceEqual(element_access.type), 752 graph()->NewNode(simplified()->ReferenceEqual(element_access.type),
783 this_value, jsgraph()->TheHoleConstant()); 753 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. 754 // Check if we are allowed to turn the hole into undefined.
789 Type* initial_holey_array_type = Type::Class( 755 Type* initial_holey_array_type = Type::Class(
790 handle(isolate()->get_initial_js_array_map(elements_kind)), 756 handle(isolate()->get_initial_js_array_map(elements_kind)),
791 graph()->zone()); 757 graph()->zone());
792 if (receiver_type->NowIs(initial_holey_array_type) && 758 if (receiver_type->NowIs(initial_holey_array_type) &&
793 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { 759 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
760 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
761 check, this_control);
762 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
763 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
794 // Add a code dependency on the array protector cell. 764 // Add a code dependency on the array protector cell.
795 AssumePrototypesStable(receiver_type, native_context, 765 AssumePrototypesStable(receiver_type, native_context,
796 isolate()->initial_object_prototype()); 766 isolate()->initial_object_prototype());
797 dependencies()->AssumePropertyCell(factory()->array_protector()); 767 dependencies()->AssumePropertyCell(factory()->array_protector());
798 // Turn the hole into undefined. 768 // Turn the hole into undefined.
799 this_control = 769 this_control =
800 graph()->NewNode(common()->Merge(2), if_true, if_false); 770 graph()->NewNode(common()->Merge(2), if_true, if_false);
801 this_value = graph()->NewNode( 771 this_value = graph()->NewNode(
802 common()->Phi(MachineRepresentation::kTagged, 2), 772 common()->Phi(MachineRepresentation::kTagged, 2),
803 jsgraph()->UndefinedConstant(), this_value, this_control); 773 jsgraph()->UndefinedConstant(), this_value, this_control);
804 element_type = 774 element_type =
805 Type::Union(element_type, Type::Undefined(), graph()->zone()); 775 Type::Union(element_type, Type::Undefined(), graph()->zone());
806 } else { 776 } else {
807 // Deoptimize in case of the hole. 777 // Deoptimize in case of the hole.
808 exit_controls.push_back(if_true); 778 this_control =
809 this_control = if_false; 779 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
780 this_effect, this_control);
810 } 781 }
811 // Rename the result to represent the actual type (not polluted by the 782 // Rename the result to represent the actual type (not polluted by the
812 // hole). 783 // hole).
813 this_value = graph()->NewNode(common()->Guard(element_type), this_value, 784 this_value = graph()->NewNode(common()->Guard(element_type), this_value,
814 this_control); 785 this_control);
815 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { 786 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
816 // Perform the hole check on the result. 787 // Perform the hole check on the result.
817 Node* check = 788 Node* check =
818 graph()->NewNode(simplified()->NumberIsHoleNaN(), this_value); 789 graph()->NewNode(simplified()->NumberIsHoleNaN(), this_value);
819 // Check if we are allowed to return the hole directly. 790 // Check if we are allowed to return the hole directly.
820 Type* initial_holey_array_type = Type::Class( 791 Type* initial_holey_array_type = Type::Class(
821 handle(isolate()->get_initial_js_array_map(elements_kind)), 792 handle(isolate()->get_initial_js_array_map(elements_kind)),
822 graph()->zone()); 793 graph()->zone());
823 if (receiver_type->NowIs(initial_holey_array_type) && 794 if (receiver_type->NowIs(initial_holey_array_type) &&
824 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { 795 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
825 // Add a code dependency on the array protector cell. 796 // Add a code dependency on the array protector cell.
826 AssumePrototypesStable(receiver_type, native_context, 797 AssumePrototypesStable(receiver_type, native_context,
827 isolate()->initial_object_prototype()); 798 isolate()->initial_object_prototype());
828 dependencies()->AssumePropertyCell(factory()->array_protector()); 799 dependencies()->AssumePropertyCell(factory()->array_protector());
829 // Turn the hole into undefined. 800 // Turn the hole into undefined.
830 this_value = graph()->NewNode( 801 this_value = graph()->NewNode(
831 common()->Select(MachineRepresentation::kTagged, 802 common()->Select(MachineRepresentation::kTagged,
832 BranchHint::kFalse), 803 BranchHint::kFalse),
833 check, jsgraph()->UndefinedConstant(), this_value); 804 check, jsgraph()->UndefinedConstant(), this_value);
834 } else { 805 } else {
835 // Deoptimize in case of the hole. 806 // Deoptimize in case of the hole.
836 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), 807 this_control =
837 check, this_control); 808 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
838 this_control = graph()->NewNode(common()->IfFalse(), branch); 809 this_effect, this_control);
839 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
840 } 810 }
841 } 811 }
842 } else { 812 } else {
843 DCHECK_EQ(AccessMode::kStore, access_mode); 813 DCHECK_EQ(AccessMode::kStore, access_mode);
844 if (IsFastSmiElementsKind(elements_kind)) { 814 if (IsFastSmiElementsKind(elements_kind)) {
845 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value); 815 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value);
846 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 816 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
847 check, this_control); 817 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), 818 this_value = graph()->NewNode(common()->Guard(type_cache_.kSmi),
851 this_value, this_control); 819 this_value, this_control);
852 } else if (IsFastDoubleElementsKind(elements_kind)) { 820 } else if (IsFastDoubleElementsKind(elements_kind)) {
853 Node* check = 821 Node* check =
854 graph()->NewNode(simplified()->ObjectIsNumber(), this_value); 822 graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
855 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 823 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
856 check, this_control); 824 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()), 825 this_value = graph()->NewNode(common()->Guard(Type::Number()),
860 this_value, this_control); 826 this_value, this_control);
861 } 827 }
862 this_effect = graph()->NewNode(simplified()->StoreElement(element_access), 828 this_effect = graph()->NewNode(simplified()->StoreElement(element_access),
863 this_elements, this_index, this_value, 829 this_elements, this_index, this_value,
864 this_effect, this_control); 830 this_effect, this_control);
865 } 831 }
866 832
867 // Remember the final state for this element access. 833 // Remember the final state for this element access.
868 values.push_back(this_value); 834 values.push_back(this_value);
869 effects.push_back(this_effect); 835 effects.push_back(this_effect);
870 controls.push_back(this_control); 836 controls.push_back(this_control);
871 } 837 }
872 838
873 // Collect the fallthrough control as final "exit" control. 839 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 840
898 // Generate the final merge point for all (polymorphic) branches. 841 // Generate the final merge point for all (polymorphic) branches.
899 int const control_count = static_cast<int>(controls.size()); 842 int const control_count = static_cast<int>(controls.size());
900 if (control_count == 0) { 843 if (control_count == 0) {
901 value = effect = control = jsgraph()->Dead(); 844 value = effect = control = jsgraph()->Dead();
902 } else if (control_count == 1) { 845 } else if (control_count == 1) {
903 value = values.front(); 846 value = values.front();
904 effect = effects.front(); 847 effect = effects.front();
905 control = controls.front(); 848 control = controls.front();
906 } else { 849 } else {
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1041 Handle<JSFunction> constructor; 984 Handle<JSFunction> constructor;
1042 if (Map::GetConstructorFunction(map, native_context) 985 if (Map::GetConstructorFunction(map, native_context)
1043 .ToHandle(&constructor)) { 986 .ToHandle(&constructor)) {
1044 map = handle(constructor->initial_map(), isolate()); 987 map = handle(constructor->initial_map(), isolate());
1045 } 988 }
1046 dependencies()->AssumePrototypeMapsStable(map, holder); 989 dependencies()->AssumePrototypeMapsStable(map, holder);
1047 } 990 }
1048 } 991 }
1049 992
1050 993
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( 994 MaybeHandle<Context> JSNativeContextSpecialization::GetNativeContext(
1064 Node* node) { 995 Node* node) {
1065 Node* const context = NodeProperties::GetContextInput(node); 996 Node* const context = NodeProperties::GetContextInput(node);
1066 return NodeProperties::GetSpecializationNativeContext(context, 997 return NodeProperties::GetSpecializationNativeContext(context,
1067 native_context()); 998 native_context());
1068 } 999 }
1069 1000
1070 1001
1071 Graph* JSNativeContextSpecialization::graph() const { 1002 Graph* JSNativeContextSpecialization::graph() const {
1072 return jsgraph()->graph(); 1003 return jsgraph()->graph();
(...skipping 25 matching lines...) Expand all
1098 } 1029 }
1099 1030
1100 1031
1101 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 1032 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
1102 return jsgraph()->simplified(); 1033 return jsgraph()->simplified();
1103 } 1034 }
1104 1035
1105 } // namespace compiler 1036 } // namespace compiler
1106 } // namespace internal 1037 } // namespace internal
1107 } // namespace v8 1038 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698