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/compilation-dependencies.h" | 8 #include "src/compilation-dependencies.h" |
9 #include "src/compiler/access-builder.h" | 9 #include "src/compiler/access-builder.h" |
10 #include "src/compiler/js-graph.h" | 10 #include "src/compiler/js-graph.h" |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
241 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), | 241 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), |
242 jsgraph()->Constant(property_cell), value, effect, control); | 242 jsgraph()->Constant(property_cell), value, effect, control); |
243 return Replace(node, value, effect, control); | 243 return Replace(node, value, effect, control); |
244 } | 244 } |
245 | 245 |
246 | 246 |
247 // This class encapsulates all information required to access a certain | 247 // This class encapsulates all information required to access a certain |
248 // object property, either on the object itself or on the prototype chain. | 248 // object property, either on the object itself or on the prototype chain. |
249 class JSNativeContextSpecialization::PropertyAccessInfo final { | 249 class JSNativeContextSpecialization::PropertyAccessInfo final { |
250 public: | 250 public: |
251 enum Kind { kInvalid, kDataConstant, kDataField }; | 251 enum Kind { kInvalid, kDataConstant, kDataField, kTransitionToField }; |
252 | 252 |
253 static PropertyAccessInfo DataConstant(Type* receiver_type, | 253 static PropertyAccessInfo DataConstant(Type* receiver_type, |
254 Handle<Object> constant, | 254 Handle<Object> constant, |
255 MaybeHandle<JSObject> holder) { | 255 MaybeHandle<JSObject> holder) { |
256 return PropertyAccessInfo(holder, constant, receiver_type); | 256 return PropertyAccessInfo(holder, constant, receiver_type); |
257 } | 257 } |
258 static PropertyAccessInfo DataField(Type* receiver_type, | 258 static PropertyAccessInfo DataField( |
259 FieldIndex field_index, Type* field_type, | 259 Type* receiver_type, FieldIndex field_index, Type* field_type, |
260 MaybeHandle<JSObject> holder) { | 260 MaybeHandle<JSObject> holder = MaybeHandle<JSObject>()) { |
261 return PropertyAccessInfo(holder, field_index, field_type, receiver_type); | 261 return PropertyAccessInfo(holder, field_index, field_type, receiver_type); |
262 } | 262 } |
263 static PropertyAccessInfo TransitionToField(Type* receiver_type, | |
264 FieldIndex field_index, | |
265 Type* field_type, | |
266 Handle<Map> transition_map, | |
267 MaybeHandle<JSObject> holder) { | |
268 return PropertyAccessInfo(holder, transition_map, field_index, field_type, | |
269 receiver_type); | |
270 } | |
263 | 271 |
264 PropertyAccessInfo() : kind_(kInvalid) {} | 272 PropertyAccessInfo() : kind_(kInvalid) {} |
265 PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant, | 273 PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant, |
266 Type* receiver_type) | 274 Type* receiver_type) |
267 : kind_(kDataConstant), | 275 : kind_(kDataConstant), |
268 receiver_type_(receiver_type), | 276 receiver_type_(receiver_type), |
269 constant_(constant), | 277 constant_(constant), |
270 holder_(holder) {} | 278 holder_(holder) {} |
271 PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index, | 279 PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index, |
272 Type* field_type, Type* receiver_type) | 280 Type* field_type, Type* receiver_type) |
273 : kind_(kDataField), | 281 : kind_(kDataField), |
274 receiver_type_(receiver_type), | 282 receiver_type_(receiver_type), |
275 holder_(holder), | 283 holder_(holder), |
276 field_index_(field_index), | 284 field_index_(field_index), |
277 field_type_(field_type) {} | 285 field_type_(field_type) {} |
286 PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Map> transition_map, | |
287 FieldIndex field_index, Type* field_type, | |
288 Type* receiver_type) | |
289 : kind_(kTransitionToField), | |
290 receiver_type_(receiver_type), | |
291 transition_map_(transition_map), | |
292 holder_(holder), | |
293 field_index_(field_index), | |
294 field_type_(field_type) {} | |
278 | 295 |
279 bool IsDataConstant() const { return kind() == kDataConstant; } | 296 bool IsDataConstant() const { return kind() == kDataConstant; } |
280 bool IsDataField() const { return kind() == kDataField; } | 297 bool IsDataField() const { return kind() == kDataField; } |
298 bool IsTransitionToField() const { return kind() == kTransitionToField; } | |
281 | 299 |
282 Kind kind() const { return kind_; } | 300 Kind kind() const { return kind_; } |
283 MaybeHandle<JSObject> holder() const { return holder_; } | 301 MaybeHandle<JSObject> holder() const { return holder_; } |
284 Handle<Object> constant() const { return constant_; } | 302 Handle<Object> constant() const { return constant_; } |
303 Handle<Object> transition_map() const { return transition_map_; } | |
285 FieldIndex field_index() const { return field_index_; } | 304 FieldIndex field_index() const { return field_index_; } |
286 Type* field_type() const { return field_type_; } | 305 Type* field_type() const { return field_type_; } |
287 Type* receiver_type() const { return receiver_type_; } | 306 Type* receiver_type() const { return receiver_type_; } |
288 | 307 |
289 private: | 308 private: |
290 Kind kind_; | 309 Kind kind_; |
291 Type* receiver_type_; | 310 Type* receiver_type_; |
292 Handle<Object> constant_; | 311 Handle<Object> constant_; |
312 Handle<Map> transition_map_; | |
293 MaybeHandle<JSObject> holder_; | 313 MaybeHandle<JSObject> holder_; |
294 FieldIndex field_index_; | 314 FieldIndex field_index_; |
295 Type* field_type_ = Type::Any(); | 315 Type* field_type_ = Type::Any(); |
296 }; | 316 }; |
297 | 317 |
298 | 318 |
299 namespace { | 319 namespace { |
300 | 320 |
301 bool CanInlinePropertyAccess(Handle<Map> map) { | 321 bool CanInlinePropertyAccess(Handle<Map> map) { |
302 // TODO(bmeurer): Do something about the number stuff. | 322 // TODO(bmeurer): Do something about the number stuff. |
303 if (map->instance_type() == HEAP_NUMBER_TYPE) return false; | 323 if (map->instance_type() == HEAP_NUMBER_TYPE) return false; |
304 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true; | 324 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true; |
305 return map->IsJSObjectMap() && !map->is_dictionary_map() && | 325 return map->IsJSObjectMap() && !map->is_dictionary_map() && |
306 !map->has_named_interceptor() && | 326 !map->has_named_interceptor() && |
307 // TODO(verwaest): Whitelist contexts to which we have access. | 327 // TODO(verwaest): Whitelist contexts to which we have access. |
308 !map->is_access_check_needed(); | 328 !map->is_access_check_needed(); |
309 } | 329 } |
310 | 330 |
311 } // namespace | 331 } // namespace |
312 | 332 |
313 | 333 |
314 bool JSNativeContextSpecialization::ComputePropertyAccessInfo( | 334 bool JSNativeContextSpecialization::ComputePropertyAccessInfo( |
315 Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode, | 335 Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode, |
316 PropertyAccessInfo* access_info) { | 336 PropertyAccessInfo* access_info) { |
317 MaybeHandle<JSObject> holder; | 337 // Check if it is safe to inline property access for the {map}. |
338 if (!CanInlinePropertyAccess(map)) return false; | |
339 | |
340 // Compute the receiver type. | |
318 Handle<Map> receiver_map = map; | 341 Handle<Map> receiver_map = map; |
319 Type* receiver_type = Type::Class(receiver_map, graph()->zone()); | 342 Type* receiver_type = Type::Class(receiver_map, graph()->zone()); |
320 while (CanInlinePropertyAccess(map)) { | 343 |
344 // We support fast inline cases for certain JSObject getters. | |
345 if (access_mode == kLoad) { | |
321 // Check for special JSObject field accessors. | 346 // Check for special JSObject field accessors. |
322 int offset; | 347 int offset; |
323 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) { | 348 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) { |
324 // Don't bother optimizing stores to special JSObject field accessors. | |
325 if (access_mode == kStore) { | |
326 break; | |
327 } | |
328 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset); | 349 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset); |
329 Type* field_type = Type::Tagged(); | 350 Type* field_type = Type::Tagged(); |
330 if (map->IsStringMap()) { | 351 if (map->IsStringMap()) { |
331 DCHECK(Name::Equals(factory()->length_string(), name)); | 352 DCHECK(Name::Equals(factory()->length_string(), name)); |
332 // The String::length property is always a smi in the range | 353 // The String::length property is always a smi in the range |
333 // [0, String::kMaxLength]. | 354 // [0, String::kMaxLength]. |
334 field_type = type_cache_.kStringLengthType; | 355 field_type = type_cache_.kStringLengthType; |
335 } else if (map->IsJSArrayMap()) { | 356 } else if (map->IsJSArrayMap()) { |
336 DCHECK(Name::Equals(factory()->length_string(), name)); | 357 DCHECK(Name::Equals(factory()->length_string(), name)); |
337 // The JSArray::length property is a smi in the range | 358 // The JSArray::length property is a smi in the range |
338 // [0, FixedDoubleArray::kMaxLength] in case of fast double | 359 // [0, FixedDoubleArray::kMaxLength] in case of fast double |
339 // elements, a smi in the range [0, FixedArray::kMaxLength] | 360 // elements, a smi in the range [0, FixedArray::kMaxLength] |
340 // in case of other fast elements, and [0, kMaxUInt32] in | 361 // in case of other fast elements, and [0, kMaxUInt32] in |
341 // case of other arrays. | 362 // case of other arrays. |
342 if (IsFastDoubleElementsKind(map->elements_kind())) { | 363 if (IsFastDoubleElementsKind(map->elements_kind())) { |
343 field_type = type_cache_.kFixedDoubleArrayLengthType; | 364 field_type = type_cache_.kFixedDoubleArrayLengthType; |
344 } else if (IsFastElementsKind(map->elements_kind())) { | 365 } else if (IsFastElementsKind(map->elements_kind())) { |
345 field_type = type_cache_.kFixedArrayLengthType; | 366 field_type = type_cache_.kFixedArrayLengthType; |
346 } else { | 367 } else { |
347 field_type = type_cache_.kJSArrayLengthType; | 368 field_type = type_cache_.kJSArrayLengthType; |
348 } | 369 } |
349 } | 370 } |
350 *access_info = PropertyAccessInfo::DataField(receiver_type, field_index, | 371 *access_info = |
351 field_type, holder); | 372 PropertyAccessInfo::DataField(receiver_type, field_index, field_type); |
352 return true; | 373 return true; |
353 } | 374 } |
375 } | |
354 | 376 |
377 MaybeHandle<JSObject> holder; | |
378 while (true) { | |
355 // Lookup the named property on the {map}. | 379 // Lookup the named property on the {map}. |
356 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); | 380 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); |
357 int const number = descriptors->SearchWithCache(*name, *map); | 381 int const number = descriptors->SearchWithCache(*name, *map); |
358 if (number != DescriptorArray::kNotFound) { | 382 if (number != DescriptorArray::kNotFound) { |
359 if (access_mode == kStore && !map.is_identical_to(receiver_map)) { | 383 PropertyDetails const details = descriptors->GetDetails(number); |
360 return false; | 384 if (access_mode == kStore) { |
385 // Don't bother optimizing stores to read-only properties. | |
386 if (details.IsReadOnly()) { | |
387 return false; | |
388 } | |
389 // Check for store to data property on a prototype. | |
390 if (details.kind() == kData && !holder.is_null()) { | |
391 // We need to add the data field to the receiver. Leave the loop | |
392 // and check whether we already have a transition for this field. | |
393 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) | |
394 break; | |
395 } | |
361 } | 396 } |
362 PropertyDetails const details = descriptors->GetDetails(number); | |
363 if (details.type() == DATA_CONSTANT) { | 397 if (details.type() == DATA_CONSTANT) { |
364 *access_info = PropertyAccessInfo::DataConstant( | 398 *access_info = PropertyAccessInfo::DataConstant( |
365 receiver_type, handle(descriptors->GetValue(number), isolate()), | 399 receiver_type, handle(descriptors->GetValue(number), isolate()), |
366 holder); | 400 holder); |
367 return true; | 401 return true; |
368 } else if (details.type() == DATA) { | 402 } else if (details.type() == DATA) { |
369 // Don't bother optimizing stores to read-only properties. | |
370 if (access_mode == kStore && details.IsReadOnly()) { | |
371 break; | |
372 } | |
373 int index = descriptors->GetFieldIndex(number); | 403 int index = descriptors->GetFieldIndex(number); |
374 Representation field_representation = details.representation(); | 404 Representation field_representation = details.representation(); |
375 FieldIndex field_index = FieldIndex::ForPropertyIndex( | 405 FieldIndex field_index = FieldIndex::ForPropertyIndex( |
376 *map, index, field_representation.IsDouble()); | 406 *map, index, field_representation.IsDouble()); |
377 Type* field_type = Type::Tagged(); | 407 Type* field_type = Type::Tagged(); |
378 if (field_representation.IsSmi()) { | 408 if (field_representation.IsSmi()) { |
379 field_type = type_cache_.kSmi; | 409 field_type = type_cache_.kSmi; |
380 } else if (field_representation.IsDouble()) { | 410 } else if (field_representation.IsDouble()) { |
381 if (access_mode == kStore) { | 411 if (access_mode == kStore) { |
382 // TODO(bmeurer): Add support for storing to double fields. | 412 // TODO(bmeurer): Add support for storing to double fields. |
383 break; | 413 return false; |
384 } | 414 } |
385 field_type = type_cache_.kFloat64; | 415 field_type = type_cache_.kFloat64; |
386 } else if (field_representation.IsHeapObject()) { | 416 } else if (field_representation.IsHeapObject()) { |
387 // Extract the field type from the property details (make sure its | 417 // Extract the field type from the property details (make sure its |
388 // representation is TaggedPointer to reflect the heap object case). | 418 // representation is TaggedPointer to reflect the heap object case). |
389 field_type = Type::Intersect( | 419 field_type = Type::Intersect( |
390 Type::Convert<HeapType>( | 420 Type::Convert<HeapType>( |
391 handle(descriptors->GetFieldType(number), isolate()), | 421 handle(descriptors->GetFieldType(number), isolate()), |
392 graph()->zone()), | 422 graph()->zone()), |
393 Type::TaggedPointer(), graph()->zone()); | 423 Type::TaggedPointer(), graph()->zone()); |
394 if (field_type->Is(Type::None())) { | 424 if (field_type->Is(Type::None())) { |
395 if (access_mode == kStore) { | 425 // Store is not safe if the field type was cleared. |
396 // Store is not safe if the field type was cleared. | 426 if (access_mode == kStore) return false; |
397 break; | |
398 } | |
399 | 427 |
400 // The field type was cleared by the GC, so we don't know anything | 428 // The field type was cleared by the GC, so we don't know anything |
401 // about the contents now. | 429 // about the contents now. |
402 // TODO(bmeurer): It would be awesome to make this saner in the | 430 // TODO(bmeurer): It would be awesome to make this saner in the |
403 // runtime/GC interaction. | 431 // runtime/GC interaction. |
404 field_type = Type::TaggedPointer(); | 432 field_type = Type::TaggedPointer(); |
405 } else if (!Type::Any()->Is(field_type)) { | 433 } else if (!Type::Any()->Is(field_type)) { |
406 // Add proper code dependencies in case of stable field map(s). | 434 // Add proper code dependencies in case of stable field map(s). |
407 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate()); | 435 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate()); |
408 dependencies()->AssumeFieldType(field_owner_map); | 436 dependencies()->AssumeFieldType(field_owner_map); |
409 } | 437 } |
410 DCHECK(field_type->Is(Type::TaggedPointer())); | 438 DCHECK(field_type->Is(Type::TaggedPointer())); |
411 } | 439 } |
412 *access_info = PropertyAccessInfo::DataField(receiver_type, field_index, | 440 *access_info = PropertyAccessInfo::DataField(receiver_type, field_index, |
413 field_type, holder); | 441 field_type, holder); |
414 return true; | 442 return true; |
415 } else { | 443 } else { |
416 // TODO(bmeurer): Add support for accessors. | 444 // TODO(bmeurer): Add support for accessors. |
417 break; | 445 return false; |
418 } | 446 } |
419 } | 447 } |
420 | 448 |
421 // Don't search on the prototype chain for special indices in case of | 449 // Don't search on the prototype chain for special indices in case of |
422 // integer indexed exotic objects (see ES6 section 9.4.5). | 450 // integer indexed exotic objects (see ES6 section 9.4.5). |
423 if (map->IsJSTypedArrayMap() && name->IsString() && | 451 if (map->IsJSTypedArrayMap() && name->IsString() && |
424 IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) { | 452 IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) { |
425 break; | 453 return false; |
426 } | 454 } |
427 | 455 |
428 // Walk up the prototype chain. | 456 // Walk up the prototype chain. |
429 if (!map->prototype()->IsJSObject()) { | 457 if (!map->prototype()->IsJSObject()) { |
430 // Perform the implicit ToObject for primitives here. | 458 // Perform the implicit ToObject for primitives here. |
431 // Implemented according to ES6 section 7.3.2 GetV (V, P). | 459 // Implemented according to ES6 section 7.3.2 GetV (V, P). |
432 Handle<JSFunction> constructor; | 460 Handle<JSFunction> constructor; |
433 if (Map::GetConstructorFunction(map, native_context()) | 461 if (Map::GetConstructorFunction(map, native_context()) |
434 .ToHandle(&constructor)) { | 462 .ToHandle(&constructor)) { |
435 map = handle(constructor->initial_map(), isolate()); | 463 map = handle(constructor->initial_map(), isolate()); |
436 DCHECK(map->prototype()->IsJSObject()); | 464 DCHECK(map->prototype()->IsJSObject()); |
465 } else if (map->prototype()->IsNull()) { | |
466 // Store to property not found on the receiver or any prototype, we need | |
467 // to transition to a new data property. | |
468 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) | |
469 if (access_mode == kStore) { | |
470 break; | |
471 } | |
472 // TODO(bmeurer): Handle the not found case if the prototype is null. | |
473 return false; | |
437 } else { | 474 } else { |
438 // TODO(bmeurer): Handle the not found case if the prototype is null. | 475 return false; |
439 break; | |
440 } | 476 } |
441 } | 477 } |
442 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); | 478 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); |
443 if (map_prototype->map()->is_deprecated()) { | 479 if (map_prototype->map()->is_deprecated()) { |
444 // Try to migrate the prototype object so we don't embed the deprecated | 480 // Try to migrate the prototype object so we don't embed the deprecated |
445 // map into the optimized code. | 481 // map into the optimized code. |
446 JSObject::TryMigrateInstance(map_prototype); | 482 JSObject::TryMigrateInstance(map_prototype); |
447 } | 483 } |
448 map = handle(map_prototype->map(), isolate()); | 484 map = handle(map_prototype->map(), isolate()); |
449 holder = map_prototype; | 485 holder = map_prototype; |
486 | |
487 // Check if it is safe to inline property access for the {map}. | |
488 if (!CanInlinePropertyAccess(map)) return false; | |
489 } | |
490 DCHECK_EQ(kStore, access_mode); | |
491 | |
492 // Check if the {receiver_map} has a data transition with the given {name}. | |
Jarin
2015/10/29 09:02:33
The structure of this code is strange. This whole
Benedikt Meurer
2015/10/29 09:03:47
Yes, but currently we have two "break" points. I w
| |
493 if (receiver_map->unused_property_fields() == 0) return false; | |
494 if (Map* transition = TransitionArray::SearchTransition(*receiver_map, kData, | |
495 *name, NONE)) { | |
496 Handle<Map> transition_map(transition, isolate()); | |
497 int const number = transition_map->LastAdded(); | |
498 PropertyDetails const details = | |
499 transition_map->instance_descriptors()->GetDetails(number); | |
500 // Don't bother optimizing stores to read-only properties. | |
501 if (details.IsReadOnly()) return false; | |
502 // TODO(bmeurer): Handle transition to data constant? | |
503 if (details.type() != DATA) return false; | |
504 int const index = details.field_index(); | |
505 Representation field_representation = details.representation(); | |
506 FieldIndex field_index = FieldIndex::ForPropertyIndex( | |
507 *transition_map, index, field_representation.IsDouble()); | |
508 Type* field_type = Type::Tagged(); | |
509 if (field_representation.IsSmi()) { | |
510 field_type = type_cache_.kSmi; | |
511 } else if (field_representation.IsDouble()) { | |
512 // TODO(bmeurer): Add support for storing to double fields. | |
513 return false; | |
514 } else if (field_representation.IsHeapObject()) { | |
515 // Extract the field type from the property details (make sure its | |
516 // representation is TaggedPointer to reflect the heap object case). | |
517 field_type = Type::Intersect( | |
518 Type::Convert<HeapType>( | |
519 handle( | |
520 transition_map->instance_descriptors()->GetFieldType(number), | |
521 isolate()), | |
522 graph()->zone()), | |
523 Type::TaggedPointer(), graph()->zone()); | |
524 if (field_type->Is(Type::None())) { | |
525 // Store is not safe if the field type was cleared. | |
526 return false; | |
527 } else if (!Type::Any()->Is(field_type)) { | |
528 // Add proper code dependencies in case of stable field map(s). | |
529 Handle<Map> field_owner_map(transition_map->FindFieldOwner(number), | |
530 isolate()); | |
531 dependencies()->AssumeFieldType(field_owner_map); | |
532 } | |
533 DCHECK(field_type->Is(Type::TaggedPointer())); | |
534 } | |
535 dependencies()->AssumeMapNotDeprecated(transition_map); | |
536 *access_info = PropertyAccessInfo::TransitionToField( | |
537 receiver_type, field_index, field_type, transition_map, holder); | |
538 return true; | |
450 } | 539 } |
451 return false; | 540 return false; |
452 } | 541 } |
453 | 542 |
454 | 543 |
455 bool JSNativeContextSpecialization::ComputePropertyAccessInfos( | 544 bool JSNativeContextSpecialization::ComputePropertyAccessInfos( |
456 MapHandleList const& maps, Handle<Name> name, | 545 MapHandleList const& maps, Handle<Name> name, |
457 PropertyAccessMode access_mode, | 546 PropertyAccessMode access_mode, |
458 ZoneVector<PropertyAccessInfo>* access_infos) { | 547 ZoneVector<PropertyAccessInfo>* access_infos) { |
459 for (Handle<Map> map : maps) { | 548 for (Handle<Map> map : maps) { |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
557 (this_control_count == 1) | 646 (this_control_count == 1) |
558 ? this_controls.front() | 647 ? this_controls.front() |
559 : graph()->NewNode(common()->Merge(this_control_count), | 648 : graph()->NewNode(common()->Merge(this_control_count), |
560 this_control_count, &this_controls.front()); | 649 this_control_count, &this_controls.front()); |
561 } | 650 } |
562 | 651 |
563 // Determine actual holder and perform prototype chain checks. | 652 // Determine actual holder and perform prototype chain checks. |
564 Handle<JSObject> holder; | 653 Handle<JSObject> holder; |
565 if (access_info.holder().ToHandle(&holder)) { | 654 if (access_info.holder().ToHandle(&holder)) { |
566 AssumePrototypesStable(receiver_type, holder); | 655 AssumePrototypesStable(receiver_type, holder); |
567 if (access_mode == kLoad) { | |
568 this_receiver = jsgraph()->Constant(holder); | |
569 } | |
570 } | 656 } |
571 | 657 |
572 // Generate the actual property access. | 658 // Generate the actual property access. |
573 if (access_info.IsDataConstant()) { | 659 if (access_info.IsDataConstant()) { |
574 this_value = jsgraph()->Constant(access_info.constant()); | 660 this_value = jsgraph()->Constant(access_info.constant()); |
575 if (access_mode == kStore) { | 661 if (access_mode == kStore) { |
576 Node* check = graph()->NewNode( | 662 Node* check = graph()->NewNode( |
577 simplified()->ReferenceEqual(Type::Tagged()), value, this_value); | 663 simplified()->ReferenceEqual(Type::Tagged()), value, this_value); |
578 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), | 664 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
579 check, this_control); | 665 check, this_control); |
580 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch)); | 666 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch)); |
581 this_control = graph()->NewNode(common()->IfTrue(), branch); | 667 this_control = graph()->NewNode(common()->IfTrue(), branch); |
582 } | 668 } |
583 } else { | 669 } else { |
584 DCHECK(access_info.IsDataField()); | 670 DCHECK(access_info.IsDataField() || access_info.IsTransitionToField()); |
585 FieldIndex const field_index = access_info.field_index(); | 671 FieldIndex const field_index = access_info.field_index(); |
586 Type* const field_type = access_info.field_type(); | 672 Type* const field_type = access_info.field_type(); |
673 if (access_mode == kLoad && access_info.holder().ToHandle(&holder)) { | |
674 this_receiver = jsgraph()->Constant(holder); | |
675 } | |
676 Node* this_storage = this_receiver; | |
587 if (!field_index.is_inobject()) { | 677 if (!field_index.is_inobject()) { |
588 this_receiver = this_effect = graph()->NewNode( | 678 this_storage = this_effect = graph()->NewNode( |
589 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), | 679 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), |
590 this_receiver, this_effect, this_control); | 680 this_storage, this_effect, this_control); |
591 } | 681 } |
592 FieldAccess field_access = {kTaggedBase, field_index.offset(), name, | 682 FieldAccess field_access = {kTaggedBase, field_index.offset(), name, |
593 field_type, kMachAnyTagged}; | 683 field_type, kMachAnyTagged}; |
594 if (access_mode == kLoad) { | 684 if (access_mode == kLoad) { |
595 if (field_type->Is(Type::UntaggedFloat64())) { | 685 if (field_type->Is(Type::UntaggedFloat64())) { |
596 if (!field_index.is_inobject() || field_index.is_hidden_field() || | 686 if (!field_index.is_inobject() || field_index.is_hidden_field() || |
597 !FLAG_unbox_double_fields) { | 687 !FLAG_unbox_double_fields) { |
598 this_receiver = this_effect = | 688 this_storage = this_effect = |
599 graph()->NewNode(simplified()->LoadField(field_access), | 689 graph()->NewNode(simplified()->LoadField(field_access), |
600 this_receiver, this_effect, this_control); | 690 this_storage, this_effect, this_control); |
601 field_access.offset = HeapNumber::kValueOffset; | 691 field_access.offset = HeapNumber::kValueOffset; |
602 field_access.name = MaybeHandle<Name>(); | 692 field_access.name = MaybeHandle<Name>(); |
603 } | 693 } |
604 field_access.machine_type = kMachFloat64; | 694 field_access.machine_type = kMachFloat64; |
605 } | 695 } |
606 this_value = this_effect = | 696 this_value = this_effect = |
607 graph()->NewNode(simplified()->LoadField(field_access), | 697 graph()->NewNode(simplified()->LoadField(field_access), |
608 this_receiver, this_effect, this_control); | 698 this_storage, this_effect, this_control); |
609 } else { | 699 } else { |
610 DCHECK_EQ(kStore, access_mode); | 700 DCHECK_EQ(kStore, access_mode); |
611 if (field_type->Is(Type::TaggedSigned())) { | 701 if (field_type->Is(Type::TaggedSigned())) { |
612 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value); | 702 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value); |
613 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), | 703 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
614 check, this_control); | 704 check, this_control); |
615 exit_controls.push_back( | 705 exit_controls.push_back( |
616 graph()->NewNode(common()->IfFalse(), branch)); | 706 graph()->NewNode(common()->IfFalse(), branch)); |
617 this_control = graph()->NewNode(common()->IfTrue(), branch); | 707 this_control = graph()->NewNode(common()->IfTrue(), branch); |
618 } else if (field_type->Is(Type::TaggedPointer())) { | 708 } else if (field_type->Is(Type::TaggedPointer())) { |
(...skipping 25 matching lines...) Expand all Loading... | |
644 this_control = | 734 this_control = |
645 (this_control_count == 1) | 735 (this_control_count == 1) |
646 ? this_controls.front() | 736 ? this_controls.front() |
647 : graph()->NewNode(common()->Merge(this_control_count), | 737 : graph()->NewNode(common()->Merge(this_control_count), |
648 this_control_count, | 738 this_control_count, |
649 &this_controls.front()); | 739 &this_controls.front()); |
650 } | 740 } |
651 } else { | 741 } else { |
652 DCHECK(field_type->Is(Type::Tagged())); | 742 DCHECK(field_type->Is(Type::Tagged())); |
653 } | 743 } |
744 if (access_info.IsTransitionToField()) { | |
745 this_effect = graph()->NewNode(common()->BeginRegion(), this_effect); | |
746 this_effect = graph()->NewNode( | |
747 simplified()->StoreField(AccessBuilder::ForMap()), this_receiver, | |
748 jsgraph()->Constant(access_info.transition_map()), this_effect, | |
749 this_control); | |
750 } | |
654 this_effect = graph()->NewNode(simplified()->StoreField(field_access), | 751 this_effect = graph()->NewNode(simplified()->StoreField(field_access), |
655 this_receiver, this_value, this_effect, | 752 this_storage, this_value, this_effect, |
656 this_control); | 753 this_control); |
754 if (access_info.IsTransitionToField()) { | |
755 this_effect = | |
756 graph()->NewNode(common()->FinishRegion(), | |
757 jsgraph()->UndefinedConstant(), this_effect); | |
758 } | |
657 } | 759 } |
658 } | 760 } |
659 | 761 |
660 // Remember the final state for this property access. | 762 // Remember the final state for this property access. |
661 values.push_back(this_value); | 763 values.push_back(this_value); |
662 effects.push_back(this_effect); | 764 effects.push_back(this_effect); |
663 controls.push_back(this_control); | 765 controls.push_back(this_control); |
664 } | 766 } |
665 | 767 |
666 // Collect the fallthru control as final "exit" control. | 768 // Collect the fallthru control as final "exit" control. |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
828 } | 930 } |
829 | 931 |
830 | 932 |
831 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 933 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
832 return jsgraph()->simplified(); | 934 return jsgraph()->simplified(); |
833 } | 935 } |
834 | 936 |
835 } // namespace compiler | 937 } // namespace compiler |
836 } // namespace internal | 938 } // namespace internal |
837 } // namespace v8 | 939 } // namespace v8 |
OLD | NEW |