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 |