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 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_ARM | 7 #if V8_TARGET_ARCH_ARM |
8 | 8 |
9 #include "src/ic/call-optimization.h" | 9 #include "src/ic/call-optimization.h" |
10 #include "src/ic/handler-compiler.h" | 10 #include "src/ic/handler-compiler.h" |
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 } | 404 } |
405 __ b(eq, &do_store); | 405 __ b(eq, &do_store); |
406 } | 406 } |
407 __ bind(&do_store); | 407 __ bind(&do_store); |
408 } | 408 } |
409 } | 409 } |
410 | 410 |
411 | 411 |
412 Register PropertyHandlerCompiler::CheckPrototypes( | 412 Register PropertyHandlerCompiler::CheckPrototypes( |
413 Register object_reg, Register holder_reg, Register scratch1, | 413 Register object_reg, Register holder_reg, Register scratch1, |
414 Register scratch2, Handle<Name> name, Label* miss, | 414 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check, |
415 PrototypeCheckType check) { | 415 ReturnHolder return_what) { |
416 Handle<Map> receiver_map = map(); | 416 Handle<Map> receiver_map = map(); |
417 | 417 |
418 // Make sure there's no overlap between holder and object registers. | 418 // Make sure there's no overlap between holder and object registers. |
419 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 419 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
420 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && | 420 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && |
421 !scratch2.is(scratch1)); | 421 !scratch2.is(scratch1)); |
422 | 422 |
| 423 if (FLAG_eliminate_prototype_chain_checks) { |
| 424 Handle<Cell> validity_cell = |
| 425 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
| 426 if (!validity_cell.is_null()) { |
| 427 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), |
| 428 validity_cell->value()); |
| 429 __ mov(scratch1, Operand(validity_cell)); |
| 430 __ ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); |
| 431 __ cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid))); |
| 432 __ b(ne, miss); |
| 433 } |
| 434 |
| 435 // The prototype chain of primitives (and their JSValue wrappers) depends |
| 436 // on the native context, which can't be guarded by validity cells. |
| 437 // |object_reg| holds the native context specific prototype in this case; |
| 438 // we need to check its map. |
| 439 if (check == CHECK_ALL_MAPS) { |
| 440 __ ldr(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset)); |
| 441 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); |
| 442 __ CmpWeakValue(scratch1, cell, scratch2); |
| 443 __ b(ne, miss); |
| 444 } |
| 445 } |
| 446 |
423 // Keep track of the current object in register reg. | 447 // Keep track of the current object in register reg. |
424 Register reg = object_reg; | 448 Register reg = object_reg; |
425 int depth = 0; | 449 int depth = 0; |
426 | 450 |
427 Handle<JSObject> current = Handle<JSObject>::null(); | 451 Handle<JSObject> current = Handle<JSObject>::null(); |
428 if (receiver_map->IsJSGlobalObjectMap()) { | 452 if (receiver_map->IsJSGlobalObjectMap()) { |
429 current = isolate()->global_object(); | 453 current = isolate()->global_object(); |
430 } | 454 } |
431 | 455 |
432 // Check access rights to the global object. This has to happen after | 456 // Check access rights to the global object. This has to happen after |
(...skipping 24 matching lines...) Expand all Loading... |
457 !current_map->IsJSGlobalObjectMap()) { | 481 !current_map->IsJSGlobalObjectMap()) { |
458 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. | 482 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. |
459 if (!name->IsUniqueName()) { | 483 if (!name->IsUniqueName()) { |
460 DCHECK(name->IsString()); | 484 DCHECK(name->IsString()); |
461 name = factory()->InternalizeString(Handle<String>::cast(name)); | 485 name = factory()->InternalizeString(Handle<String>::cast(name)); |
462 } | 486 } |
463 DCHECK(current.is_null() || | 487 DCHECK(current.is_null() || |
464 current->property_dictionary()->FindEntry(name) == | 488 current->property_dictionary()->FindEntry(name) == |
465 NameDictionary::kNotFound); | 489 NameDictionary::kNotFound); |
466 | 490 |
| 491 if (FLAG_eliminate_prototype_chain_checks && depth > 1) { |
| 492 // TODO(jkummerow): Cache and re-use weak cell. |
| 493 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); |
| 494 } |
467 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, | 495 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, |
468 scratch2); | 496 scratch2); |
469 | 497 if (!FLAG_eliminate_prototype_chain_checks) { |
470 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | 498 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); |
471 reg = holder_reg; // From now on the object will be in holder_reg. | 499 __ ldr(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); |
472 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); | 500 } |
473 } else { | 501 } else { |
474 Register map_reg = scratch1; | 502 Register map_reg = scratch1; |
475 __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); | 503 if (!FLAG_eliminate_prototype_chain_checks) { |
476 | 504 __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 505 } |
477 if (current_map->IsJSGlobalObjectMap()) { | 506 if (current_map->IsJSGlobalObjectMap()) { |
478 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), | 507 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), |
479 name, scratch2, miss); | 508 name, scratch2, miss); |
480 } else if (depth != 1 || check == CHECK_ALL_MAPS) { | 509 } else if (!FLAG_eliminate_prototype_chain_checks && |
| 510 (depth != 1 || check == CHECK_ALL_MAPS)) { |
481 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); | 511 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); |
482 __ CmpWeakValue(map_reg, cell, scratch2); | 512 __ CmpWeakValue(map_reg, cell, scratch2); |
483 __ b(ne, miss); | 513 __ b(ne, miss); |
484 } | 514 } |
485 | 515 if (!FLAG_eliminate_prototype_chain_checks) { |
486 reg = holder_reg; // From now on the object will be in holder_reg. | 516 __ ldr(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); |
487 | 517 } |
488 __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); | |
489 } | 518 } |
490 | 519 |
| 520 reg = holder_reg; // From now on the object will be in holder_reg. |
491 // Go to the next object in the prototype chain. | 521 // Go to the next object in the prototype chain. |
492 current = prototype; | 522 current = prototype; |
493 current_map = handle(current->map()); | 523 current_map = handle(current->map()); |
494 } | 524 } |
495 | 525 |
496 DCHECK(!current_map->IsJSGlobalProxyMap()); | 526 DCHECK(!current_map->IsJSGlobalProxyMap()); |
497 | 527 |
498 // Log the check depth. | 528 // Log the check depth. |
499 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 529 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
500 | 530 |
501 if (depth != 0 || check == CHECK_ALL_MAPS) { | 531 if (!FLAG_eliminate_prototype_chain_checks && |
| 532 (depth != 0 || check == CHECK_ALL_MAPS)) { |
502 // Check the holder map. | 533 // Check the holder map. |
503 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | 534 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); |
504 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); | 535 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); |
505 __ CmpWeakValue(scratch1, cell, scratch2); | 536 __ CmpWeakValue(scratch1, cell, scratch2); |
506 __ b(ne, miss); | 537 __ b(ne, miss); |
507 } | 538 } |
508 | 539 |
| 540 bool return_holder = return_what == RETURN_HOLDER; |
| 541 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { |
| 542 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); |
| 543 } |
| 544 |
509 // Return the register containing the holder. | 545 // Return the register containing the holder. |
510 return reg; | 546 return return_holder ? reg : no_reg; |
511 } | 547 } |
512 | 548 |
513 | 549 |
514 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { | 550 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { |
515 if (!miss->is_unused()) { | 551 if (!miss->is_unused()) { |
516 Label success; | 552 Label success; |
517 __ b(&success); | 553 __ b(&success); |
518 __ bind(miss); | 554 __ bind(miss); |
519 if (IC::ICUseVector(kind())) { | 555 if (IC::ICUseVector(kind())) { |
520 DCHECK(kind() == Code::LOAD_IC); | 556 DCHECK(kind() == Code::LOAD_IC); |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
715 return StoreDescriptor::ValueRegister(); | 751 return StoreDescriptor::ValueRegister(); |
716 } | 752 } |
717 | 753 |
718 | 754 |
719 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( | 755 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( |
720 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { | 756 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { |
721 Label miss; | 757 Label miss; |
722 if (IC::ICUseVector(kind())) { | 758 if (IC::ICUseVector(kind())) { |
723 PushVectorAndSlot(); | 759 PushVectorAndSlot(); |
724 } | 760 } |
725 FrontendHeader(receiver(), name, &miss); | 761 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); |
726 | 762 |
727 // Get the value from the cell. | 763 // Get the value from the cell. |
728 Register result = StoreDescriptor::ValueRegister(); | 764 Register result = StoreDescriptor::ValueRegister(); |
729 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); | 765 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); |
730 __ LoadWeakValue(result, weak_cell, &miss); | 766 __ LoadWeakValue(result, weak_cell, &miss); |
731 __ ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset)); | 767 __ ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset)); |
732 | 768 |
733 // Check for deleted property if property can actually be deleted. | 769 // Check for deleted property if property can actually be deleted. |
734 if (is_configurable) { | 770 if (is_configurable) { |
735 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 771 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
(...skipping 13 matching lines...) Expand all Loading... |
749 // Return the generated code. | 785 // Return the generated code. |
750 return GetCode(kind(), Code::NORMAL, name); | 786 return GetCode(kind(), Code::NORMAL, name); |
751 } | 787 } |
752 | 788 |
753 | 789 |
754 #undef __ | 790 #undef __ |
755 } | 791 } |
756 } // namespace v8::internal | 792 } // namespace v8::internal |
757 | 793 |
758 #endif // V8_TARGET_ARCH_ARM | 794 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |