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