OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
6 | 6 |
7 #include "src/ic/handler-compiler.h" | 7 #include "src/ic/handler-compiler.h" |
8 | 8 |
9 #include "src/api-arguments.h" | 9 #include "src/api-arguments.h" |
10 #include "src/field-type.h" | 10 #include "src/field-type.h" |
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 Register PropertyHandlerCompiler::CheckPrototypes( | 460 Register PropertyHandlerCompiler::CheckPrototypes( |
461 Register object_reg, Register holder_reg, Register scratch1, | 461 Register object_reg, Register holder_reg, Register scratch1, |
462 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check, | 462 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check, |
463 ReturnHolder return_what) { | 463 ReturnHolder return_what) { |
464 Handle<Map> receiver_map = map(); | 464 Handle<Map> receiver_map = map(); |
465 | 465 |
466 // object_reg and holder_reg registers can alias. | 466 // object_reg and holder_reg registers can alias. |
467 DCHECK(!AreAliased(object_reg, scratch1, scratch2)); | 467 DCHECK(!AreAliased(object_reg, scratch1, scratch2)); |
468 DCHECK(!AreAliased(holder_reg, scratch1, scratch2)); | 468 DCHECK(!AreAliased(holder_reg, scratch1, scratch2)); |
469 | 469 |
470 if (FLAG_eliminate_prototype_chain_checks) { | 470 Handle<Cell> validity_cell = |
471 Handle<Cell> validity_cell = | 471 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
472 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); | 472 if (!validity_cell.is_null()) { |
473 if (!validity_cell.is_null()) { | 473 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value()); |
474 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), | 474 __ Mov(scratch1, Operand(validity_cell)); |
475 validity_cell->value()); | 475 __ Ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); |
476 __ Mov(scratch1, Operand(validity_cell)); | 476 __ Cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid))); |
477 __ Ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); | 477 __ B(ne, miss); |
478 __ Cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid))); | 478 } |
479 __ B(ne, miss); | |
480 } | |
481 | 479 |
482 // The prototype chain of primitives (and their JSValue wrappers) depends | 480 // The prototype chain of primitives (and their JSValue wrappers) depends |
483 // on the native context, which can't be guarded by validity cells. | 481 // on the native context, which can't be guarded by validity cells. |
484 // |object_reg| holds the native context specific prototype in this case; | 482 // |object_reg| holds the native context specific prototype in this case; |
485 // we need to check its map. | 483 // we need to check its map. |
486 if (check == CHECK_ALL_MAPS) { | 484 if (check == CHECK_ALL_MAPS) { |
487 __ Ldr(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset)); | 485 __ Ldr(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset)); |
488 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); | 486 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); |
489 __ CmpWeakValue(scratch1, cell, scratch2); | 487 __ CmpWeakValue(scratch1, cell, scratch2); |
490 __ B(ne, miss); | 488 __ B(ne, miss); |
491 } | |
492 } | 489 } |
493 | 490 |
494 // Keep track of the current object in register reg. | 491 // Keep track of the current object in register reg. |
495 Register reg = object_reg; | 492 Register reg = object_reg; |
496 int depth = 0; | 493 int depth = 0; |
497 | 494 |
498 Handle<JSObject> current = Handle<JSObject>::null(); | 495 Handle<JSObject> current = Handle<JSObject>::null(); |
499 if (receiver_map->IsJSGlobalObjectMap()) { | 496 if (receiver_map->IsJSGlobalObjectMap()) { |
500 current = isolate()->global_object(); | 497 current = isolate()->global_object(); |
501 } | 498 } |
(...skipping 16 matching lines...) Expand all Loading... |
518 // fast and global objects or do negative lookup for normal objects. | 515 // fast and global objects or do negative lookup for normal objects. |
519 while (!current_map.is_identical_to(holder_map)) { | 516 while (!current_map.is_identical_to(holder_map)) { |
520 ++depth; | 517 ++depth; |
521 | 518 |
522 // Only global objects and objects that do not require access | 519 // Only global objects and objects that do not require access |
523 // checks are allowed in stubs. | 520 // checks are allowed in stubs. |
524 DCHECK(current_map->IsJSGlobalProxyMap() || | 521 DCHECK(current_map->IsJSGlobalProxyMap() || |
525 !current_map->is_access_check_needed()); | 522 !current_map->is_access_check_needed()); |
526 | 523 |
527 prototype = handle(JSObject::cast(current_map->prototype())); | 524 prototype = handle(JSObject::cast(current_map->prototype())); |
528 if (current_map->is_dictionary_map() && | 525 if (current_map->IsJSGlobalObjectMap()) { |
529 !current_map->IsJSGlobalObjectMap()) { | 526 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), |
| 527 name, scratch2, miss); |
| 528 } else if (current_map->is_dictionary_map()) { |
530 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. | 529 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. |
531 if (!name->IsUniqueName()) { | 530 if (!name->IsUniqueName()) { |
532 DCHECK(name->IsString()); | 531 DCHECK(name->IsString()); |
533 name = factory()->InternalizeString(Handle<String>::cast(name)); | 532 name = factory()->InternalizeString(Handle<String>::cast(name)); |
534 } | 533 } |
535 DCHECK(current.is_null() || (current->property_dictionary()->FindEntry( | 534 DCHECK(current.is_null() || (current->property_dictionary()->FindEntry( |
536 name) == NameDictionary::kNotFound)); | 535 name) == NameDictionary::kNotFound)); |
537 | 536 |
538 if (FLAG_eliminate_prototype_chain_checks && depth > 1) { | 537 if (depth > 1) { |
539 // TODO(jkummerow): Cache and re-use weak cell. | 538 // TODO(jkummerow): Cache and re-use weak cell. |
540 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); | 539 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); |
541 } | 540 } |
542 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, | 541 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, |
543 scratch2); | 542 scratch2); |
544 | |
545 if (!FLAG_eliminate_prototype_chain_checks) { | |
546 __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | |
547 __ Ldr(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); | |
548 } | |
549 } else { | |
550 Register map_reg = scratch1; | |
551 if (!FLAG_eliminate_prototype_chain_checks) { | |
552 __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); | |
553 } | |
554 if (current_map->IsJSGlobalObjectMap()) { | |
555 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), | |
556 name, scratch2, miss); | |
557 } else if (!FLAG_eliminate_prototype_chain_checks && | |
558 (depth != 1 || check == CHECK_ALL_MAPS)) { | |
559 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); | |
560 __ CmpWeakValue(map_reg, cell, scratch2); | |
561 __ B(ne, miss); | |
562 } | |
563 if (!FLAG_eliminate_prototype_chain_checks) { | |
564 __ Ldr(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); | |
565 } | |
566 } | 543 } |
567 | 544 |
568 reg = holder_reg; // From now on the object will be in holder_reg. | 545 reg = holder_reg; // From now on the object will be in holder_reg. |
569 // Go to the next object in the prototype chain. | 546 // Go to the next object in the prototype chain. |
570 current = prototype; | 547 current = prototype; |
571 current_map = handle(current->map()); | 548 current_map = handle(current->map()); |
572 } | 549 } |
573 | 550 |
574 DCHECK(!current_map->IsJSGlobalProxyMap()); | 551 DCHECK(!current_map->IsJSGlobalProxyMap()); |
575 | 552 |
576 // Log the check depth. | 553 // Log the check depth. |
577 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 554 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
578 | 555 |
579 if (!FLAG_eliminate_prototype_chain_checks && | |
580 (depth != 0 || check == CHECK_ALL_MAPS)) { | |
581 // Check the holder map. | |
582 __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | |
583 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); | |
584 __ CmpWeakValue(scratch1, cell, scratch2); | |
585 __ B(ne, miss); | |
586 } | |
587 | |
588 bool return_holder = return_what == RETURN_HOLDER; | 556 bool return_holder = return_what == RETURN_HOLDER; |
589 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { | 557 if (return_holder && depth != 0) { |
590 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); | 558 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); |
591 } | 559 } |
592 | 560 |
593 // Return the register containing the holder. | 561 // Return the register containing the holder. |
594 return return_holder ? reg : no_reg; | 562 return return_holder ? reg : no_reg; |
595 } | 563 } |
596 | 564 |
597 | 565 |
598 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { | 566 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { |
599 if (!miss->is_unused()) { | 567 if (!miss->is_unused()) { |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
734 // Return the generated code. | 702 // Return the generated code. |
735 return GetCode(kind(), name); | 703 return GetCode(kind(), name); |
736 } | 704 } |
737 | 705 |
738 | 706 |
739 #undef __ | 707 #undef __ |
740 } // namespace internal | 708 } // namespace internal |
741 } // namespace v8 | 709 } // namespace v8 |
742 | 710 |
743 #endif // V8_TARGET_ARCH_IA32 | 711 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |