OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |