| 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_X64 | 7 #if V8_TARGET_ARCH_X64 |
| 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 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 } | 406 } |
| 407 __ j(equal, &do_store, Label::kNear); | 407 __ j(equal, &do_store, Label::kNear); |
| 408 } | 408 } |
| 409 __ bind(&do_store); | 409 __ bind(&do_store); |
| 410 } | 410 } |
| 411 } | 411 } |
| 412 | 412 |
| 413 | 413 |
| 414 Register PropertyHandlerCompiler::CheckPrototypes( | 414 Register PropertyHandlerCompiler::CheckPrototypes( |
| 415 Register object_reg, Register holder_reg, Register scratch1, | 415 Register object_reg, Register holder_reg, Register scratch1, |
| 416 Register scratch2, Handle<Name> name, Label* miss, | 416 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check, |
| 417 PrototypeCheckType check) { | 417 ReturnHolder return_what) { |
| 418 Handle<Map> receiver_map = map(); | 418 Handle<Map> receiver_map = map(); |
| 419 | 419 |
| 420 // Make sure there's no overlap between holder and object registers. | 420 // Make sure there's no overlap between holder and object registers. |
| 421 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 421 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 422 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && | 422 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && |
| 423 !scratch2.is(scratch1)); | 423 !scratch2.is(scratch1)); |
| 424 | 424 |
| 425 if (FLAG_eliminate_prototype_chain_checks) { |
| 426 Handle<Cell> validity_cell = |
| 427 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
| 428 if (!validity_cell.is_null()) { |
| 429 DCHECK(validity_cell->value() == Smi::FromInt(Map::kPrototypeChainValid)); |
| 430 __ Move(scratch1, validity_cell, RelocInfo::CELL); |
| 431 // Move(..., CELL) loads the payload's address! |
| 432 __ SmiCompare(Operand(scratch1, 0), |
| 433 Smi::FromInt(Map::kPrototypeChainValid)); |
| 434 __ j(not_equal, miss); |
| 435 } |
| 436 |
| 437 // The prototype chain of primitives (and their JSValue wrappers) depends |
| 438 // on the native context, which can't be guarded by validity cells. |
| 439 // |object_reg| holds the native context specific prototype in this case; |
| 440 // we need to check its map. |
| 441 if (check == CHECK_ALL_MAPS) { |
| 442 __ movp(scratch1, FieldOperand(object_reg, HeapObject::kMapOffset)); |
| 443 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); |
| 444 __ CmpWeakValue(scratch1, cell, scratch2); |
| 445 __ j(not_equal, miss); |
| 446 } |
| 447 } |
| 448 |
| 425 // Keep track of the current object in register reg. On the first | 449 // Keep track of the current object in register reg. On the first |
| 426 // iteration, reg is an alias for object_reg, on later iterations, | 450 // iteration, reg is an alias for object_reg, on later iterations, |
| 427 // it is an alias for holder_reg. | 451 // it is an alias for holder_reg. |
| 428 Register reg = object_reg; | 452 Register reg = object_reg; |
| 429 int depth = 0; | 453 int depth = 0; |
| 430 | 454 |
| 431 Handle<JSObject> current = Handle<JSObject>::null(); | 455 Handle<JSObject> current = Handle<JSObject>::null(); |
| 432 if (receiver_map->IsJSGlobalObjectMap()) { | 456 if (receiver_map->IsJSGlobalObjectMap()) { |
| 433 current = isolate()->global_object(); | 457 current = isolate()->global_object(); |
| 434 } | 458 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 461 !current_map->IsJSGlobalObjectMap()) { | 485 !current_map->IsJSGlobalObjectMap()) { |
| 462 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. | 486 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. |
| 463 if (!name->IsUniqueName()) { | 487 if (!name->IsUniqueName()) { |
| 464 DCHECK(name->IsString()); | 488 DCHECK(name->IsString()); |
| 465 name = factory()->InternalizeString(Handle<String>::cast(name)); | 489 name = factory()->InternalizeString(Handle<String>::cast(name)); |
| 466 } | 490 } |
| 467 DCHECK(current.is_null() || | 491 DCHECK(current.is_null() || |
| 468 current->property_dictionary()->FindEntry(name) == | 492 current->property_dictionary()->FindEntry(name) == |
| 469 NameDictionary::kNotFound); | 493 NameDictionary::kNotFound); |
| 470 | 494 |
| 495 if (FLAG_eliminate_prototype_chain_checks && depth > 1) { |
| 496 // TODO(jkummerow): Cache and re-use weak cell. |
| 497 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); |
| 498 } |
| 471 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, | 499 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, |
| 472 scratch2); | 500 scratch2); |
| 473 | 501 |
| 474 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 502 if (!FLAG_eliminate_prototype_chain_checks) { |
| 475 reg = holder_reg; // From now on the object will be in holder_reg. | 503 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 476 __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 504 __ movp(holder_reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
| 505 } |
| 477 } else { | 506 } else { |
| 478 Register map_reg = scratch1; | 507 Register map_reg = scratch1; |
| 479 __ movp(map_reg, FieldOperand(reg, HeapObject::kMapOffset)); | 508 if (!FLAG_eliminate_prototype_chain_checks) { |
| 480 | 509 __ movp(map_reg, FieldOperand(reg, HeapObject::kMapOffset)); |
| 510 } |
| 481 if (current_map->IsJSGlobalObjectMap()) { | 511 if (current_map->IsJSGlobalObjectMap()) { |
| 482 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), | 512 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), |
| 483 name, scratch2, miss); | 513 name, scratch2, miss); |
| 484 } else if (depth != 1 || check == CHECK_ALL_MAPS) { | 514 } else if (!FLAG_eliminate_prototype_chain_checks && |
| 515 (depth != 1 || check == CHECK_ALL_MAPS)) { |
| 485 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); | 516 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); |
| 486 __ CmpWeakValue(map_reg, cell, scratch2); | 517 __ CmpWeakValue(map_reg, cell, scratch2); |
| 487 __ j(not_equal, miss); | 518 __ j(not_equal, miss); |
| 488 } | 519 } |
| 489 | 520 if (!FLAG_eliminate_prototype_chain_checks) { |
| 490 reg = holder_reg; // From now on the object will be in holder_reg. | 521 __ movp(holder_reg, FieldOperand(map_reg, Map::kPrototypeOffset)); |
| 491 | 522 } |
| 492 __ movp(reg, FieldOperand(map_reg, Map::kPrototypeOffset)); | |
| 493 } | 523 } |
| 494 | 524 |
| 525 reg = holder_reg; // From now on the object will be in holder_reg. |
| 495 // Go to the next object in the prototype chain. | 526 // Go to the next object in the prototype chain. |
| 496 current = prototype; | 527 current = prototype; |
| 497 current_map = handle(current->map()); | 528 current_map = handle(current->map()); |
| 498 } | 529 } |
| 499 | 530 |
| 500 DCHECK(!current_map->IsJSGlobalProxyMap()); | 531 DCHECK(!current_map->IsJSGlobalProxyMap()); |
| 501 | 532 |
| 502 // Log the check depth. | 533 // Log the check depth. |
| 503 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 534 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 504 | 535 |
| 505 if (depth != 0 || check == CHECK_ALL_MAPS) { | 536 if (!FLAG_eliminate_prototype_chain_checks && |
| 537 (depth != 0 || check == CHECK_ALL_MAPS)) { |
| 538 // Check the holder map. |
| 506 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 539 __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 507 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); | 540 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); |
| 508 __ CmpWeakValue(scratch1, cell, scratch2); | 541 __ CmpWeakValue(scratch1, cell, scratch2); |
| 509 __ j(not_equal, miss); | 542 __ j(not_equal, miss); |
| 510 } | 543 } |
| 511 | 544 |
| 545 bool return_holder = return_what == RETURN_HOLDER; |
| 546 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { |
| 547 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); |
| 548 } |
| 549 |
| 512 // Return the register containing the holder. | 550 // Return the register containing the holder. |
| 513 return reg; | 551 return return_holder ? reg : no_reg; |
| 514 } | 552 } |
| 515 | 553 |
| 516 | 554 |
| 517 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { | 555 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { |
| 518 if (!miss->is_unused()) { | 556 if (!miss->is_unused()) { |
| 519 Label success; | 557 Label success; |
| 520 __ jmp(&success); | 558 __ jmp(&success); |
| 521 __ bind(miss); | 559 __ bind(miss); |
| 522 if (IC::ICUseVector(kind())) { | 560 if (IC::ICUseVector(kind())) { |
| 523 DCHECK(kind() == Code::LOAD_IC); | 561 DCHECK(kind() == Code::LOAD_IC); |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 725 return StoreDescriptor::ValueRegister(); | 763 return StoreDescriptor::ValueRegister(); |
| 726 } | 764 } |
| 727 | 765 |
| 728 | 766 |
| 729 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( | 767 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( |
| 730 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { | 768 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { |
| 731 Label miss; | 769 Label miss; |
| 732 if (IC::ICUseVector(kind())) { | 770 if (IC::ICUseVector(kind())) { |
| 733 PushVectorAndSlot(); | 771 PushVectorAndSlot(); |
| 734 } | 772 } |
| 735 FrontendHeader(receiver(), name, &miss); | 773 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); |
| 736 | 774 |
| 737 // Get the value from the cell. | 775 // Get the value from the cell. |
| 738 Register result = StoreDescriptor::ValueRegister(); | 776 Register result = StoreDescriptor::ValueRegister(); |
| 739 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); | 777 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); |
| 740 __ LoadWeakValue(result, weak_cell, &miss); | 778 __ LoadWeakValue(result, weak_cell, &miss); |
| 741 __ movp(result, FieldOperand(result, PropertyCell::kValueOffset)); | 779 __ movp(result, FieldOperand(result, PropertyCell::kValueOffset)); |
| 742 | 780 |
| 743 // Check for deleted property if property can actually be deleted. | 781 // Check for deleted property if property can actually be deleted. |
| 744 if (is_configurable) { | 782 if (is_configurable) { |
| 745 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); | 783 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 761 // Return the generated code. | 799 // Return the generated code. |
| 762 return GetCode(kind(), Code::NORMAL, name); | 800 return GetCode(kind(), Code::NORMAL, name); |
| 763 } | 801 } |
| 764 | 802 |
| 765 | 803 |
| 766 #undef __ | 804 #undef __ |
| 767 } | 805 } |
| 768 } // namespace v8::internal | 806 } // namespace v8::internal |
| 769 | 807 |
| 770 #endif // V8_TARGET_ARCH_X64 | 808 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |