| 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_MIPS | 7 #if V8_TARGET_ARCH_MIPS |
| 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 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 } | 394 } |
| 395 __ Branch(&do_store, eq, map_reg, Operand(scratch)); | 395 __ Branch(&do_store, eq, map_reg, Operand(scratch)); |
| 396 } | 396 } |
| 397 __ bind(&do_store); | 397 __ bind(&do_store); |
| 398 } | 398 } |
| 399 } | 399 } |
| 400 | 400 |
| 401 | 401 |
| 402 Register PropertyHandlerCompiler::CheckPrototypes( | 402 Register PropertyHandlerCompiler::CheckPrototypes( |
| 403 Register object_reg, Register holder_reg, Register scratch1, | 403 Register object_reg, Register holder_reg, Register scratch1, |
| 404 Register scratch2, Handle<Name> name, Label* miss, | 404 Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check, |
| 405 PrototypeCheckType check) { | 405 ReturnHolder return_what) { |
| 406 Handle<Map> receiver_map = map(); | 406 Handle<Map> receiver_map = map(); |
| 407 | 407 |
| 408 // Make sure there's no overlap between holder and object registers. | 408 // Make sure there's no overlap between holder and object registers. |
| 409 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 409 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 410 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && | 410 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && |
| 411 !scratch2.is(scratch1)); | 411 !scratch2.is(scratch1)); |
| 412 | 412 |
| 413 if (FLAG_eliminate_prototype_chain_checks) { |
| 414 Handle<Cell> validity_cell = |
| 415 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
| 416 if (!validity_cell.is_null()) { |
| 417 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), |
| 418 validity_cell->value()); |
| 419 __ li(scratch1, Operand(validity_cell)); |
| 420 __ lw(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); |
| 421 __ Branch(miss, ne, scratch1, |
| 422 Operand(Smi::FromInt(Map::kPrototypeChainValid))); |
| 423 } |
| 424 |
| 425 // The prototype chain of primitives (and their JSValue wrappers) depends |
| 426 // on the native context, which can't be guarded by validity cells. |
| 427 // |object_reg| holds the native context specific prototype in this case; |
| 428 // we need to check its map. |
| 429 if (check == CHECK_ALL_MAPS) { |
| 430 __ lw(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset)); |
| 431 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); |
| 432 __ GetWeakValue(scratch2, cell); |
| 433 __ Branch(miss, ne, scratch1, Operand(scratch2)); |
| 434 } |
| 435 } |
| 436 |
| 413 // Keep track of the current object in register reg. | 437 // Keep track of the current object in register reg. |
| 414 Register reg = object_reg; | 438 Register reg = object_reg; |
| 415 int depth = 0; | 439 int depth = 0; |
| 416 | 440 |
| 417 Handle<JSObject> current = Handle<JSObject>::null(); | 441 Handle<JSObject> current = Handle<JSObject>::null(); |
| 418 if (receiver_map->IsJSGlobalObjectMap()) { | 442 if (receiver_map->IsJSGlobalObjectMap()) { |
| 419 current = isolate()->global_object(); | 443 current = isolate()->global_object(); |
| 420 } | 444 } |
| 421 | 445 |
| 422 // Check access rights to the global object. This has to happen after | 446 // Check access rights to the global object. This has to happen after |
| (...skipping 24 matching lines...) Expand all Loading... |
| 447 !current_map->IsJSGlobalObjectMap()) { | 471 !current_map->IsJSGlobalObjectMap()) { |
| 448 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. | 472 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. |
| 449 if (!name->IsUniqueName()) { | 473 if (!name->IsUniqueName()) { |
| 450 DCHECK(name->IsString()); | 474 DCHECK(name->IsString()); |
| 451 name = factory()->InternalizeString(Handle<String>::cast(name)); | 475 name = factory()->InternalizeString(Handle<String>::cast(name)); |
| 452 } | 476 } |
| 453 DCHECK(current.is_null() || | 477 DCHECK(current.is_null() || |
| 454 current->property_dictionary()->FindEntry(name) == | 478 current->property_dictionary()->FindEntry(name) == |
| 455 NameDictionary::kNotFound); | 479 NameDictionary::kNotFound); |
| 456 | 480 |
| 481 if (FLAG_eliminate_prototype_chain_checks && depth > 1) { |
| 482 // TODO(jkummerow): Cache and re-use weak cell. |
| 483 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); |
| 484 } |
| 457 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, | 485 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, |
| 458 scratch2); | 486 scratch2); |
| 459 | 487 if (!FLAG_eliminate_prototype_chain_checks) { |
| 460 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | 488 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 461 reg = holder_reg; // From now on the object will be in holder_reg. | 489 __ lw(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); |
| 462 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); | 490 } |
| 463 } else { | 491 } else { |
| 464 Register map_reg = scratch1; | 492 Register map_reg = scratch1; |
| 465 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); | 493 if (!FLAG_eliminate_prototype_chain_checks) { |
| 466 | 494 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 495 } |
| 467 if (current_map->IsJSGlobalObjectMap()) { | 496 if (current_map->IsJSGlobalObjectMap()) { |
| 468 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), | 497 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), |
| 469 name, scratch2, miss); | 498 name, scratch2, miss); |
| 470 } else if (depth != 1 || check == CHECK_ALL_MAPS) { | 499 } else if (!FLAG_eliminate_prototype_chain_checks && |
| 500 (depth != 1 || check == CHECK_ALL_MAPS)) { |
| 471 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); | 501 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); |
| 472 __ GetWeakValue(scratch2, cell); | 502 __ GetWeakValue(scratch2, cell); |
| 473 __ Branch(miss, ne, scratch2, Operand(map_reg)); | 503 __ Branch(miss, ne, scratch2, Operand(map_reg)); |
| 474 } | 504 } |
| 475 | 505 if (!FLAG_eliminate_prototype_chain_checks) { |
| 476 reg = holder_reg; // From now on the object will be in holder_reg. | 506 __ lw(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); |
| 477 | 507 } |
| 478 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); | |
| 479 } | 508 } |
| 480 | 509 |
| 510 reg = holder_reg; // From now on the object will be in holder_reg. |
| 481 // Go to the next object in the prototype chain. | 511 // Go to the next object in the prototype chain. |
| 482 current = prototype; | 512 current = prototype; |
| 483 current_map = handle(current->map()); | 513 current_map = handle(current->map()); |
| 484 } | 514 } |
| 485 | 515 |
| 486 DCHECK(!current_map->IsJSGlobalProxyMap()); | 516 DCHECK(!current_map->IsJSGlobalProxyMap()); |
| 487 | 517 |
| 488 // Log the check depth. | 518 // Log the check depth. |
| 489 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 519 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 490 | 520 |
| 491 if (depth != 0 || check == CHECK_ALL_MAPS) { | 521 if (!FLAG_eliminate_prototype_chain_checks && |
| 522 (depth != 0 || check == CHECK_ALL_MAPS)) { |
| 492 // Check the holder map. | 523 // Check the holder map. |
| 493 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); | 524 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 494 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); | 525 Handle<WeakCell> cell = Map::WeakCellForMap(current_map); |
| 495 __ GetWeakValue(scratch2, cell); | 526 __ GetWeakValue(scratch2, cell); |
| 496 __ Branch(miss, ne, scratch2, Operand(scratch1)); | 527 __ Branch(miss, ne, scratch2, Operand(scratch1)); |
| 497 } | 528 } |
| 498 | 529 |
| 530 bool return_holder = return_what == RETURN_HOLDER; |
| 531 if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { |
| 532 __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); |
| 533 } |
| 534 |
| 499 // Return the register containing the holder. | 535 // Return the register containing the holder. |
| 500 return reg; | 536 return return_holder ? reg : no_reg; |
| 501 } | 537 } |
| 502 | 538 |
| 503 | 539 |
| 504 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { | 540 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { |
| 505 if (!miss->is_unused()) { | 541 if (!miss->is_unused()) { |
| 506 Label success; | 542 Label success; |
| 507 __ Branch(&success); | 543 __ Branch(&success); |
| 508 __ bind(miss); | 544 __ bind(miss); |
| 509 if (IC::ICUseVector(kind())) { | 545 if (IC::ICUseVector(kind())) { |
| 510 DCHECK(kind() == Code::LOAD_IC); | 546 DCHECK(kind() == Code::LOAD_IC); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 } | 741 } |
| 706 | 742 |
| 707 | 743 |
| 708 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( | 744 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( |
| 709 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { | 745 Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { |
| 710 Label miss; | 746 Label miss; |
| 711 if (IC::ICUseVector(kind())) { | 747 if (IC::ICUseVector(kind())) { |
| 712 PushVectorAndSlot(); | 748 PushVectorAndSlot(); |
| 713 } | 749 } |
| 714 | 750 |
| 715 FrontendHeader(receiver(), name, &miss); | 751 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); |
| 716 | 752 |
| 717 // Get the value from the cell. | 753 // Get the value from the cell. |
| 718 Register result = StoreDescriptor::ValueRegister(); | 754 Register result = StoreDescriptor::ValueRegister(); |
| 719 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); | 755 Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); |
| 720 __ LoadWeakValue(result, weak_cell, &miss); | 756 __ LoadWeakValue(result, weak_cell, &miss); |
| 721 __ lw(result, FieldMemOperand(result, PropertyCell::kValueOffset)); | 757 __ lw(result, FieldMemOperand(result, PropertyCell::kValueOffset)); |
| 722 | 758 |
| 723 // Check for deleted property if property can actually be deleted. | 759 // Check for deleted property if property can actually be deleted. |
| 724 if (is_configurable) { | 760 if (is_configurable) { |
| 725 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 761 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 739 // Return the generated code. | 775 // Return the generated code. |
| 740 return GetCode(kind(), Code::NORMAL, name); | 776 return GetCode(kind(), Code::NORMAL, name); |
| 741 } | 777 } |
| 742 | 778 |
| 743 | 779 |
| 744 #undef __ | 780 #undef __ |
| 745 } | 781 } |
| 746 } // namespace v8::internal | 782 } // namespace v8::internal |
| 747 | 783 |
| 748 #endif // V8_TARGET_ARCH_MIPS | 784 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |