| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 814 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 __ test(edx, Operand(edx)); | 825 __ test(edx, Operand(edx)); |
| 826 DeoptimizeIf(not_zero, instr->environment()); | 826 DeoptimizeIf(not_zero, instr->environment()); |
| 827 } | 827 } |
| 828 | 828 |
| 829 | 829 |
| 830 void LCodeGen::DoMulI(LMulI* instr) { | 830 void LCodeGen::DoMulI(LMulI* instr) { |
| 831 Register left = ToRegister(instr->left()); | 831 Register left = ToRegister(instr->left()); |
| 832 LOperand* right = instr->right(); | 832 LOperand* right = instr->right(); |
| 833 | 833 |
| 834 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 834 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 835 __ mov(ToRegister(instr->temp()), left); | 835 __ mov(ToRegister(instr->TempAt(0)), left); |
| 836 } | 836 } |
| 837 | 837 |
| 838 if (right->IsConstantOperand()) { | 838 if (right->IsConstantOperand()) { |
| 839 __ imul(left, left, ToInteger32(LConstantOperand::cast(right))); | 839 __ imul(left, left, ToInteger32(LConstantOperand::cast(right))); |
| 840 } else { | 840 } else { |
| 841 __ imul(left, ToOperand(right)); | 841 __ imul(left, ToOperand(right)); |
| 842 } | 842 } |
| 843 | 843 |
| 844 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 844 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 845 DeoptimizeIf(overflow, instr->environment()); | 845 DeoptimizeIf(overflow, instr->environment()); |
| 846 } | 846 } |
| 847 | 847 |
| 848 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 848 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 849 // Bail out if the result is supposed to be negative zero. | 849 // Bail out if the result is supposed to be negative zero. |
| 850 NearLabel done; | 850 NearLabel done; |
| 851 __ test(left, Operand(left)); | 851 __ test(left, Operand(left)); |
| 852 __ j(not_zero, &done); | 852 __ j(not_zero, &done); |
| 853 if (right->IsConstantOperand()) { | 853 if (right->IsConstantOperand()) { |
| 854 if (ToInteger32(LConstantOperand::cast(right)) < 0) { | 854 if (ToInteger32(LConstantOperand::cast(right)) < 0) { |
| 855 DeoptimizeIf(no_condition, instr->environment()); | 855 DeoptimizeIf(no_condition, instr->environment()); |
| 856 } | 856 } |
| 857 } else { | 857 } else { |
| 858 // Test the non-zero operand for negative sign. | 858 // Test the non-zero operand for negative sign. |
| 859 __ or_(ToRegister(instr->temp()), ToOperand(right)); | 859 __ or_(ToRegister(instr->TempAt(0)), ToOperand(right)); |
| 860 DeoptimizeIf(sign, instr->environment()); | 860 DeoptimizeIf(sign, instr->environment()); |
| 861 } | 861 } |
| 862 __ bind(&done); | 862 __ bind(&done); |
| 863 } | 863 } |
| 864 } | 864 } |
| 865 | 865 |
| 866 | 866 |
| 867 void LCodeGen::DoBitI(LBitI* instr) { | 867 void LCodeGen::DoBitI(LBitI* instr) { |
| 868 LOperand* left = instr->left(); | 868 LOperand* left = instr->left(); |
| 869 LOperand* right = instr->right(); | 869 LOperand* right = instr->right(); |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1026 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { | 1026 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { |
| 1027 Register result = ToRegister(instr->result()); | 1027 Register result = ToRegister(instr->result()); |
| 1028 Register array = ToRegister(instr->input()); | 1028 Register array = ToRegister(instr->input()); |
| 1029 __ mov(result, FieldOperand(array, FixedArray::kLengthOffset)); | 1029 __ mov(result, FieldOperand(array, FixedArray::kLengthOffset)); |
| 1030 } | 1030 } |
| 1031 | 1031 |
| 1032 | 1032 |
| 1033 void LCodeGen::DoValueOf(LValueOf* instr) { | 1033 void LCodeGen::DoValueOf(LValueOf* instr) { |
| 1034 Register input = ToRegister(instr->input()); | 1034 Register input = ToRegister(instr->input()); |
| 1035 Register result = ToRegister(instr->result()); | 1035 Register result = ToRegister(instr->result()); |
| 1036 Register map = ToRegister(instr->temporary()); | 1036 Register map = ToRegister(instr->TempAt(0)); |
| 1037 ASSERT(input.is(result)); | 1037 ASSERT(input.is(result)); |
| 1038 NearLabel done; | 1038 NearLabel done; |
| 1039 // If the object is a smi return the object. | 1039 // If the object is a smi return the object. |
| 1040 __ test(input, Immediate(kSmiTagMask)); | 1040 __ test(input, Immediate(kSmiTagMask)); |
| 1041 __ j(zero, &done); | 1041 __ j(zero, &done); |
| 1042 | 1042 |
| 1043 // If the object is not a value type, return the object. | 1043 // If the object is not a value type, return the object. |
| 1044 __ CmpObjectType(input, JS_VALUE_TYPE, map); | 1044 __ CmpObjectType(input, JS_VALUE_TYPE, map); |
| 1045 __ j(not_equal, &done); | 1045 __ j(not_equal, &done); |
| 1046 __ mov(result, FieldOperand(input, JSValue::kValueOffset)); | 1046 __ mov(result, FieldOperand(input, JSValue::kValueOffset)); |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1428 } else { | 1428 } else { |
| 1429 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1429 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1430 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1430 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1431 __ j(equal, true_label); | 1431 __ j(equal, true_label); |
| 1432 __ cmp(reg, Factory::undefined_value()); | 1432 __ cmp(reg, Factory::undefined_value()); |
| 1433 __ j(equal, true_label); | 1433 __ j(equal, true_label); |
| 1434 __ test(reg, Immediate(kSmiTagMask)); | 1434 __ test(reg, Immediate(kSmiTagMask)); |
| 1435 __ j(zero, false_label); | 1435 __ j(zero, false_label); |
| 1436 // Check for undetectable objects by looking in the bit field in | 1436 // Check for undetectable objects by looking in the bit field in |
| 1437 // the map. The object has already been smi checked. | 1437 // the map. The object has already been smi checked. |
| 1438 Register scratch = ToRegister(instr->temp()); | 1438 Register scratch = ToRegister(instr->TempAt(0)); |
| 1439 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); | 1439 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
| 1440 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset)); | 1440 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset)); |
| 1441 __ test(scratch, Immediate(1 << Map::kIsUndetectable)); | 1441 __ test(scratch, Immediate(1 << Map::kIsUndetectable)); |
| 1442 EmitBranch(true_block, false_block, not_zero); | 1442 EmitBranch(true_block, false_block, not_zero); |
| 1443 } | 1443 } |
| 1444 } | 1444 } |
| 1445 | 1445 |
| 1446 | 1446 |
| 1447 Condition LCodeGen::EmitIsObject(Register input, | 1447 Condition LCodeGen::EmitIsObject(Register input, |
| 1448 Register temp1, | 1448 Register temp1, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1469 __ cmp(temp2, FIRST_JS_OBJECT_TYPE); | 1469 __ cmp(temp2, FIRST_JS_OBJECT_TYPE); |
| 1470 __ j(below, is_not_object); | 1470 __ j(below, is_not_object); |
| 1471 __ cmp(temp2, LAST_JS_OBJECT_TYPE); | 1471 __ cmp(temp2, LAST_JS_OBJECT_TYPE); |
| 1472 return below_equal; | 1472 return below_equal; |
| 1473 } | 1473 } |
| 1474 | 1474 |
| 1475 | 1475 |
| 1476 void LCodeGen::DoIsObject(LIsObject* instr) { | 1476 void LCodeGen::DoIsObject(LIsObject* instr) { |
| 1477 Register reg = ToRegister(instr->input()); | 1477 Register reg = ToRegister(instr->input()); |
| 1478 Register result = ToRegister(instr->result()); | 1478 Register result = ToRegister(instr->result()); |
| 1479 Register temp = ToRegister(instr->temp()); | 1479 Register temp = ToRegister(instr->TempAt(0)); |
| 1480 Label is_false, is_true, done; | 1480 Label is_false, is_true, done; |
| 1481 | 1481 |
| 1482 Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true); | 1482 Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true); |
| 1483 __ j(true_cond, &is_true); | 1483 __ j(true_cond, &is_true); |
| 1484 | 1484 |
| 1485 __ bind(&is_false); | 1485 __ bind(&is_false); |
| 1486 __ mov(result, Handle<Object>(Heap::false_value())); | 1486 __ mov(result, Handle<Object>(Heap::false_value())); |
| 1487 __ jmp(&done); | 1487 __ jmp(&done); |
| 1488 | 1488 |
| 1489 __ bind(&is_true); | 1489 __ bind(&is_true); |
| 1490 __ mov(result, Handle<Object>(Heap::true_value())); | 1490 __ mov(result, Handle<Object>(Heap::true_value())); |
| 1491 | 1491 |
| 1492 __ bind(&done); | 1492 __ bind(&done); |
| 1493 } | 1493 } |
| 1494 | 1494 |
| 1495 | 1495 |
| 1496 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { | 1496 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { |
| 1497 Register reg = ToRegister(instr->input()); | 1497 Register reg = ToRegister(instr->input()); |
| 1498 Register temp = ToRegister(instr->temp()); | 1498 Register temp = ToRegister(instr->TempAt(0)); |
| 1499 Register temp2 = ToRegister(instr->temp2()); | 1499 Register temp2 = ToRegister(instr->TempAt(1)); |
| 1500 | 1500 |
| 1501 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1501 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1502 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1502 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1503 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1503 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1504 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1504 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1505 | 1505 |
| 1506 Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label); | 1506 Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label); |
| 1507 | 1507 |
| 1508 EmitBranch(true_block, false_block, true_cond); | 1508 EmitBranch(true_block, false_block, true_cond); |
| 1509 } | 1509 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1527 Operand input = ToOperand(instr->input()); | 1527 Operand input = ToOperand(instr->input()); |
| 1528 | 1528 |
| 1529 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1529 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1530 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1530 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1531 | 1531 |
| 1532 __ test(input, Immediate(kSmiTagMask)); | 1532 __ test(input, Immediate(kSmiTagMask)); |
| 1533 EmitBranch(true_block, false_block, zero); | 1533 EmitBranch(true_block, false_block, zero); |
| 1534 } | 1534 } |
| 1535 | 1535 |
| 1536 | 1536 |
| 1537 InstanceType LHasInstanceType::TestType() { | 1537 static InstanceType TestType(HHasInstanceType* instr) { |
| 1538 InstanceType from = hydrogen()->from(); | 1538 InstanceType from = instr->from(); |
| 1539 InstanceType to = hydrogen()->to(); | 1539 InstanceType to = instr->to(); |
| 1540 if (from == FIRST_TYPE) return to; | 1540 if (from == FIRST_TYPE) return to; |
| 1541 ASSERT(from == to || to == LAST_TYPE); | 1541 ASSERT(from == to || to == LAST_TYPE); |
| 1542 return from; | 1542 return from; |
| 1543 } | 1543 } |
| 1544 | 1544 |
| 1545 | 1545 |
| 1546 | 1546 |
| 1547 Condition LHasInstanceType::BranchCondition() { | 1547 static Condition BranchCondition(HHasInstanceType* instr) { |
| 1548 InstanceType from = hydrogen()->from(); | 1548 InstanceType from = instr->from(); |
| 1549 InstanceType to = hydrogen()->to(); | 1549 InstanceType to = instr->to(); |
| 1550 if (from == to) return equal; | 1550 if (from == to) return equal; |
| 1551 if (to == LAST_TYPE) return above_equal; | 1551 if (to == LAST_TYPE) return above_equal; |
| 1552 if (from == FIRST_TYPE) return below_equal; | 1552 if (from == FIRST_TYPE) return below_equal; |
| 1553 UNREACHABLE(); | 1553 UNREACHABLE(); |
| 1554 return equal; | 1554 return equal; |
| 1555 } | 1555 } |
| 1556 | 1556 |
| 1557 | 1557 |
| 1558 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { | 1558 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { |
| 1559 Register input = ToRegister(instr->input()); | 1559 Register input = ToRegister(instr->input()); |
| 1560 Register result = ToRegister(instr->result()); | 1560 Register result = ToRegister(instr->result()); |
| 1561 | 1561 |
| 1562 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | 1562 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); |
| 1563 __ test(input, Immediate(kSmiTagMask)); | 1563 __ test(input, Immediate(kSmiTagMask)); |
| 1564 NearLabel done, is_false; | 1564 NearLabel done, is_false; |
| 1565 __ j(zero, &is_false); | 1565 __ j(zero, &is_false); |
| 1566 __ CmpObjectType(input, instr->TestType(), result); | 1566 __ CmpObjectType(input, TestType(instr->hydrogen()), result); |
| 1567 __ j(NegateCondition(instr->BranchCondition()), &is_false); | 1567 __ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false); |
| 1568 __ mov(result, Handle<Object>(Heap::true_value())); | 1568 __ mov(result, Handle<Object>(Heap::true_value())); |
| 1569 __ jmp(&done); | 1569 __ jmp(&done); |
| 1570 __ bind(&is_false); | 1570 __ bind(&is_false); |
| 1571 __ mov(result, Handle<Object>(Heap::false_value())); | 1571 __ mov(result, Handle<Object>(Heap::false_value())); |
| 1572 __ bind(&done); | 1572 __ bind(&done); |
| 1573 } | 1573 } |
| 1574 | 1574 |
| 1575 | 1575 |
| 1576 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { | 1576 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { |
| 1577 Register input = ToRegister(instr->input()); | 1577 Register input = ToRegister(instr->input()); |
| 1578 Register temp = ToRegister(instr->temp()); | 1578 Register temp = ToRegister(instr->TempAt(0)); |
| 1579 | 1579 |
| 1580 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1580 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1581 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1581 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1582 | 1582 |
| 1583 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1583 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1584 | 1584 |
| 1585 __ test(input, Immediate(kSmiTagMask)); | 1585 __ test(input, Immediate(kSmiTagMask)); |
| 1586 __ j(zero, false_label); | 1586 __ j(zero, false_label); |
| 1587 | 1587 |
| 1588 __ CmpObjectType(input, instr->TestType(), temp); | 1588 __ CmpObjectType(input, TestType(instr->hydrogen()), temp); |
| 1589 EmitBranch(true_block, false_block, instr->BranchCondition()); | 1589 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); |
| 1590 } | 1590 } |
| 1591 | 1591 |
| 1592 | 1592 |
| 1593 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { | 1593 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { |
| 1594 Register input = ToRegister(instr->input()); | 1594 Register input = ToRegister(instr->input()); |
| 1595 Register result = ToRegister(instr->result()); | 1595 Register result = ToRegister(instr->result()); |
| 1596 | 1596 |
| 1597 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | 1597 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); |
| 1598 __ mov(result, Handle<Object>(Heap::true_value())); | 1598 __ mov(result, Handle<Object>(Heap::true_value())); |
| 1599 __ test(FieldOperand(input, String::kHashFieldOffset), | 1599 __ test(FieldOperand(input, String::kHashFieldOffset), |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1672 // comparison. | 1672 // comparison. |
| 1673 __ cmp(temp, class_name); | 1673 __ cmp(temp, class_name); |
| 1674 // End with the answer in the z flag. | 1674 // End with the answer in the z flag. |
| 1675 } | 1675 } |
| 1676 | 1676 |
| 1677 | 1677 |
| 1678 void LCodeGen::DoClassOfTest(LClassOfTest* instr) { | 1678 void LCodeGen::DoClassOfTest(LClassOfTest* instr) { |
| 1679 Register input = ToRegister(instr->input()); | 1679 Register input = ToRegister(instr->input()); |
| 1680 Register result = ToRegister(instr->result()); | 1680 Register result = ToRegister(instr->result()); |
| 1681 ASSERT(input.is(result)); | 1681 ASSERT(input.is(result)); |
| 1682 Register temp = ToRegister(instr->temporary()); | 1682 Register temp = ToRegister(instr->TempAt(0)); |
| 1683 Handle<String> class_name = instr->hydrogen()->class_name(); | 1683 Handle<String> class_name = instr->hydrogen()->class_name(); |
| 1684 NearLabel done; | 1684 NearLabel done; |
| 1685 Label is_true, is_false; | 1685 Label is_true, is_false; |
| 1686 | 1686 |
| 1687 EmitClassOfTest(&is_true, &is_false, class_name, input, temp, input); | 1687 EmitClassOfTest(&is_true, &is_false, class_name, input, temp, input); |
| 1688 | 1688 |
| 1689 __ j(not_equal, &is_false); | 1689 __ j(not_equal, &is_false); |
| 1690 | 1690 |
| 1691 __ bind(&is_true); | 1691 __ bind(&is_true); |
| 1692 __ mov(result, Handle<Object>(Heap::true_value())); | 1692 __ mov(result, Handle<Object>(Heap::true_value())); |
| 1693 __ jmp(&done); | 1693 __ jmp(&done); |
| 1694 | 1694 |
| 1695 __ bind(&is_false); | 1695 __ bind(&is_false); |
| 1696 __ mov(result, Handle<Object>(Heap::false_value())); | 1696 __ mov(result, Handle<Object>(Heap::false_value())); |
| 1697 __ bind(&done); | 1697 __ bind(&done); |
| 1698 } | 1698 } |
| 1699 | 1699 |
| 1700 | 1700 |
| 1701 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { | 1701 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
| 1702 Register input = ToRegister(instr->input()); | 1702 Register input = ToRegister(instr->input()); |
| 1703 Register temp = ToRegister(instr->temporary()); | 1703 Register temp = ToRegister(instr->TempAt(0)); |
| 1704 Register temp2 = ToRegister(instr->temporary2()); | 1704 Register temp2 = ToRegister(instr->TempAt(1)); |
| 1705 if (input.is(temp)) { | 1705 if (input.is(temp)) { |
| 1706 // Swap. | 1706 // Swap. |
| 1707 Register swapper = temp; | 1707 Register swapper = temp; |
| 1708 temp = temp2; | 1708 temp = temp2; |
| 1709 temp2 = swapper; | 1709 temp2 = swapper; |
| 1710 } | 1710 } |
| 1711 Handle<String> class_name = instr->hydrogen()->class_name(); | 1711 Handle<String> class_name = instr->hydrogen()->class_name(); |
| 1712 | 1712 |
| 1713 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1713 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1714 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1714 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1774 private: | 1774 private: |
| 1775 LInstanceOfKnownGlobal* instr_; | 1775 LInstanceOfKnownGlobal* instr_; |
| 1776 Label map_check_; | 1776 Label map_check_; |
| 1777 }; | 1777 }; |
| 1778 | 1778 |
| 1779 DeferredInstanceOfKnownGlobal* deferred; | 1779 DeferredInstanceOfKnownGlobal* deferred; |
| 1780 deferred = new DeferredInstanceOfKnownGlobal(this, instr); | 1780 deferred = new DeferredInstanceOfKnownGlobal(this, instr); |
| 1781 | 1781 |
| 1782 Label done, false_result; | 1782 Label done, false_result; |
| 1783 Register object = ToRegister(instr->input()); | 1783 Register object = ToRegister(instr->input()); |
| 1784 Register temp = ToRegister(instr->temp()); | 1784 Register temp = ToRegister(instr->TempAt(0)); |
| 1785 | 1785 |
| 1786 // A Smi is not instance of anything. | 1786 // A Smi is not instance of anything. |
| 1787 __ test(object, Immediate(kSmiTagMask)); | 1787 __ test(object, Immediate(kSmiTagMask)); |
| 1788 __ j(zero, &false_result, not_taken); | 1788 __ j(zero, &false_result, not_taken); |
| 1789 | 1789 |
| 1790 // This is the inlined call site instanceof cache. The two occourences of the | 1790 // This is the inlined call site instanceof cache. The two occourences of the |
| 1791 // hole value will be patched to the last map/result pair generated by the | 1791 // hole value will be patched to the last map/result pair generated by the |
| 1792 // instanceof stub. | 1792 // instanceof stub. |
| 1793 NearLabel cache_miss; | 1793 NearLabel cache_miss; |
| 1794 Register map = ToRegister(instr->temp()); | 1794 Register map = ToRegister(instr->TempAt(0)); |
| 1795 __ mov(map, FieldOperand(object, HeapObject::kMapOffset)); | 1795 __ mov(map, FieldOperand(object, HeapObject::kMapOffset)); |
| 1796 __ bind(deferred->map_check()); // Label for calculating code patching. | 1796 __ bind(deferred->map_check()); // Label for calculating code patching. |
| 1797 __ cmp(map, Factory::the_hole_value()); // Patched to cached map. | 1797 __ cmp(map, Factory::the_hole_value()); // Patched to cached map. |
| 1798 __ j(not_equal, &cache_miss, not_taken); | 1798 __ j(not_equal, &cache_miss, not_taken); |
| 1799 __ mov(eax, Factory::the_hole_value()); // Patched to either true or false. | 1799 __ mov(eax, Factory::the_hole_value()); // Patched to either true or false. |
| 1800 __ jmp(&done); | 1800 __ jmp(&done); |
| 1801 | 1801 |
| 1802 // The inlined call site cache did not match. Check null and string before | 1802 // The inlined call site cache did not match. Check null and string before |
| 1803 // calling the deferred code. | 1803 // calling the deferred code. |
| 1804 __ bind(&cache_miss); | 1804 __ bind(&cache_miss); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1832 flags | InstanceofStub::kArgsInRegisters); | 1832 flags | InstanceofStub::kArgsInRegisters); |
| 1833 flags = static_cast<InstanceofStub::Flags>( | 1833 flags = static_cast<InstanceofStub::Flags>( |
| 1834 flags | InstanceofStub::kCallSiteInlineCheck); | 1834 flags | InstanceofStub::kCallSiteInlineCheck); |
| 1835 flags = static_cast<InstanceofStub::Flags>( | 1835 flags = static_cast<InstanceofStub::Flags>( |
| 1836 flags | InstanceofStub::kReturnTrueFalseObject); | 1836 flags | InstanceofStub::kReturnTrueFalseObject); |
| 1837 InstanceofStub stub(flags); | 1837 InstanceofStub stub(flags); |
| 1838 | 1838 |
| 1839 // Get the temp register reserved by the instruction. This needs to be edi as | 1839 // Get the temp register reserved by the instruction. This needs to be edi as |
| 1840 // its slot of the pushing of safepoint registers is used to communicate the | 1840 // its slot of the pushing of safepoint registers is used to communicate the |
| 1841 // offset to the location of the map check. | 1841 // offset to the location of the map check. |
| 1842 Register temp = ToRegister(instr->temp()); | 1842 Register temp = ToRegister(instr->TempAt(0)); |
| 1843 ASSERT(temp.is(edi)); | 1843 ASSERT(temp.is(edi)); |
| 1844 __ mov(InstanceofStub::right(), Immediate(instr->function())); | 1844 __ mov(InstanceofStub::right(), Immediate(instr->function())); |
| 1845 static const int kAdditionalDelta = 13; | 1845 static const int kAdditionalDelta = 13; |
| 1846 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; | 1846 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; |
| 1847 Label before_push_delta; | 1847 Label before_push_delta; |
| 1848 __ bind(&before_push_delta); | 1848 __ bind(&before_push_delta); |
| 1849 __ mov(temp, Immediate(delta)); | 1849 __ mov(temp, Immediate(delta)); |
| 1850 __ mov(Operand(esp, EspIndexForPushAll(temp) * kPointerSize), temp); | 1850 __ mov(Operand(esp, EspIndexForPushAll(temp) * kPointerSize), temp); |
| 1851 __ call(stub.GetCode(), RelocInfo::CODE_TARGET); | 1851 __ call(stub.GetCode(), RelocInfo::CODE_TARGET); |
| 1852 ASSERT_EQ(kAdditionalDelta, | 1852 ASSERT_EQ(kAdditionalDelta, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1966 ASSERT(ToRegister(instr->result()).is(eax)); | 1966 ASSERT(ToRegister(instr->result()).is(eax)); |
| 1967 | 1967 |
| 1968 __ mov(ecx, instr->name()); | 1968 __ mov(ecx, instr->name()); |
| 1969 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1969 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 1970 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 1970 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 1971 } | 1971 } |
| 1972 | 1972 |
| 1973 | 1973 |
| 1974 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { | 1974 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { |
| 1975 Register function = ToRegister(instr->function()); | 1975 Register function = ToRegister(instr->function()); |
| 1976 Register temp = ToRegister(instr->temporary()); | 1976 Register temp = ToRegister(instr->TempAt(0)); |
| 1977 Register result = ToRegister(instr->result()); | 1977 Register result = ToRegister(instr->result()); |
| 1978 | 1978 |
| 1979 // Check that the function really is a function. | 1979 // Check that the function really is a function. |
| 1980 __ CmpObjectType(function, JS_FUNCTION_TYPE, result); | 1980 __ CmpObjectType(function, JS_FUNCTION_TYPE, result); |
| 1981 DeoptimizeIf(not_equal, instr->environment()); | 1981 DeoptimizeIf(not_equal, instr->environment()); |
| 1982 | 1982 |
| 1983 // Check whether the function has an instance prototype. | 1983 // Check whether the function has an instance prototype. |
| 1984 NearLabel non_instance; | 1984 NearLabel non_instance; |
| 1985 __ test_b(FieldOperand(result, Map::kBitFieldOffset), | 1985 __ test_b(FieldOperand(result, Map::kBitFieldOffset), |
| 1986 1 << Map::kHasNonInstancePrototype); | 1986 1 << Map::kHasNonInstancePrototype); |
| (...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2603 int offset = instr->offset(); | 2603 int offset = instr->offset(); |
| 2604 | 2604 |
| 2605 if (!instr->transition().is_null()) { | 2605 if (!instr->transition().is_null()) { |
| 2606 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); | 2606 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); |
| 2607 } | 2607 } |
| 2608 | 2608 |
| 2609 // Do the store. | 2609 // Do the store. |
| 2610 if (instr->is_in_object()) { | 2610 if (instr->is_in_object()) { |
| 2611 __ mov(FieldOperand(object, offset), value); | 2611 __ mov(FieldOperand(object, offset), value); |
| 2612 if (instr->needs_write_barrier()) { | 2612 if (instr->needs_write_barrier()) { |
| 2613 Register temp = ToRegister(instr->temp()); | 2613 Register temp = ToRegister(instr->TempAt(0)); |
| 2614 // Update the write barrier for the object for in-object properties. | 2614 // Update the write barrier for the object for in-object properties. |
| 2615 __ RecordWrite(object, offset, value, temp); | 2615 __ RecordWrite(object, offset, value, temp); |
| 2616 } | 2616 } |
| 2617 } else { | 2617 } else { |
| 2618 Register temp = ToRegister(instr->temp()); | 2618 Register temp = ToRegister(instr->TempAt(0)); |
| 2619 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset)); | 2619 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset)); |
| 2620 __ mov(FieldOperand(temp, offset), value); | 2620 __ mov(FieldOperand(temp, offset), value); |
| 2621 if (instr->needs_write_barrier()) { | 2621 if (instr->needs_write_barrier()) { |
| 2622 // Update the write barrier for the properties array. | 2622 // Update the write barrier for the properties array. |
| 2623 // object is used as a scratch register. | 2623 // object is used as a scratch register. |
| 2624 __ RecordWrite(temp, offset, value, object); | 2624 __ RecordWrite(temp, offset, value, object); |
| 2625 } | 2625 } |
| 2626 } | 2626 } |
| 2627 } | 2627 } |
| 2628 | 2628 |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2755 public: | 2755 public: |
| 2756 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) | 2756 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) |
| 2757 : LDeferredCode(codegen), instr_(instr) { } | 2757 : LDeferredCode(codegen), instr_(instr) { } |
| 2758 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } | 2758 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } |
| 2759 private: | 2759 private: |
| 2760 LNumberTagD* instr_; | 2760 LNumberTagD* instr_; |
| 2761 }; | 2761 }; |
| 2762 | 2762 |
| 2763 XMMRegister input_reg = ToDoubleRegister(instr->input()); | 2763 XMMRegister input_reg = ToDoubleRegister(instr->input()); |
| 2764 Register reg = ToRegister(instr->result()); | 2764 Register reg = ToRegister(instr->result()); |
| 2765 Register tmp = ToRegister(instr->temp()); | 2765 Register tmp = ToRegister(instr->TempAt(0)); |
| 2766 | 2766 |
| 2767 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); | 2767 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); |
| 2768 if (FLAG_inline_new) { | 2768 if (FLAG_inline_new) { |
| 2769 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry()); | 2769 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry()); |
| 2770 } else { | 2770 } else { |
| 2771 __ jmp(deferred->entry()); | 2771 __ jmp(deferred->entry()); |
| 2772 } | 2772 } |
| 2773 __ bind(deferred->exit()); | 2773 __ bind(deferred->exit()); |
| 2774 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); | 2774 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); |
| 2775 } | 2775 } |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2896 | 2896 |
| 2897 // Reserve space for 64 bit answer. | 2897 // Reserve space for 64 bit answer. |
| 2898 __ bind(&convert); | 2898 __ bind(&convert); |
| 2899 __ sub(Operand(esp), Immediate(kDoubleSize)); | 2899 __ sub(Operand(esp), Immediate(kDoubleSize)); |
| 2900 // Do conversion, which cannot fail because we checked the exponent. | 2900 // Do conversion, which cannot fail because we checked the exponent. |
| 2901 __ fisttp_d(Operand(esp, 0)); | 2901 __ fisttp_d(Operand(esp, 0)); |
| 2902 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result. | 2902 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result. |
| 2903 __ add(Operand(esp), Immediate(kDoubleSize)); | 2903 __ add(Operand(esp), Immediate(kDoubleSize)); |
| 2904 } else { | 2904 } else { |
| 2905 NearLabel deopt; | 2905 NearLabel deopt; |
| 2906 XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); | 2906 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0)); |
| 2907 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 2907 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 2908 __ cvttsd2si(input_reg, Operand(xmm0)); | 2908 __ cvttsd2si(input_reg, Operand(xmm0)); |
| 2909 __ cmp(input_reg, 0x80000000u); | 2909 __ cmp(input_reg, 0x80000000u); |
| 2910 __ j(not_equal, &done); | 2910 __ j(not_equal, &done); |
| 2911 // Check if the input was 0x8000000 (kMinInt). | 2911 // Check if the input was 0x8000000 (kMinInt). |
| 2912 // If no, then we got an overflow and we deoptimize. | 2912 // If no, then we got an overflow and we deoptimize. |
| 2913 ExternalReference min_int = ExternalReference::address_of_min_int(); | 2913 ExternalReference min_int = ExternalReference::address_of_min_int(); |
| 2914 __ movdbl(xmm_temp, Operand::StaticVariable(min_int)); | 2914 __ movdbl(xmm_temp, Operand::StaticVariable(min_int)); |
| 2915 __ ucomisd(xmm_temp, xmm0); | 2915 __ ucomisd(xmm_temp, xmm0); |
| 2916 DeoptimizeIf(not_equal, instr->environment()); | 2916 DeoptimizeIf(not_equal, instr->environment()); |
| 2917 DeoptimizeIf(parity_even, instr->environment()); // NaN. | 2917 DeoptimizeIf(parity_even, instr->environment()); // NaN. |
| 2918 } | 2918 } |
| 2919 } else { | 2919 } else { |
| 2920 // Deoptimize if we don't have a heap number. | 2920 // Deoptimize if we don't have a heap number. |
| 2921 DeoptimizeIf(not_equal, instr->environment()); | 2921 DeoptimizeIf(not_equal, instr->environment()); |
| 2922 | 2922 |
| 2923 XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); | 2923 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0)); |
| 2924 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 2924 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 2925 __ cvttsd2si(input_reg, Operand(xmm0)); | 2925 __ cvttsd2si(input_reg, Operand(xmm0)); |
| 2926 __ cvtsi2sd(xmm_temp, Operand(input_reg)); | 2926 __ cvtsi2sd(xmm_temp, Operand(input_reg)); |
| 2927 __ ucomisd(xmm0, xmm_temp); | 2927 __ ucomisd(xmm0, xmm_temp); |
| 2928 DeoptimizeIf(not_equal, instr->environment()); | 2928 DeoptimizeIf(not_equal, instr->environment()); |
| 2929 DeoptimizeIf(parity_even, instr->environment()); // NaN. | 2929 DeoptimizeIf(parity_even, instr->environment()); // NaN. |
| 2930 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 2930 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 2931 __ test(input_reg, Operand(input_reg)); | 2931 __ test(input_reg, Operand(input_reg)); |
| 2932 __ j(not_zero, &done); | 2932 __ j(not_zero, &done); |
| 2933 __ movmskpd(input_reg, xmm0); | 2933 __ movmskpd(input_reg, xmm0); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3004 DeoptimizeIf(no_condition, instr->environment()); | 3004 DeoptimizeIf(no_condition, instr->environment()); |
| 3005 __ bind(&convert); | 3005 __ bind(&convert); |
| 3006 // Do conversion, which cannot fail because we checked the exponent. | 3006 // Do conversion, which cannot fail because we checked the exponent. |
| 3007 __ fld_d(Operand(esp, 0)); | 3007 __ fld_d(Operand(esp, 0)); |
| 3008 __ fisttp_d(Operand(esp, 0)); | 3008 __ fisttp_d(Operand(esp, 0)); |
| 3009 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result. | 3009 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result. |
| 3010 __ add(Operand(esp), Immediate(kDoubleSize)); | 3010 __ add(Operand(esp), Immediate(kDoubleSize)); |
| 3011 __ bind(&done); | 3011 __ bind(&done); |
| 3012 } else { | 3012 } else { |
| 3013 NearLabel done; | 3013 NearLabel done; |
| 3014 Register temp_reg = ToRegister(instr->temporary()); | 3014 Register temp_reg = ToRegister(instr->TempAt(0)); |
| 3015 XMMRegister xmm_scratch = xmm0; | 3015 XMMRegister xmm_scratch = xmm0; |
| 3016 | 3016 |
| 3017 // If cvttsd2si succeeded, we're done. Otherwise, we attempt | 3017 // If cvttsd2si succeeded, we're done. Otherwise, we attempt |
| 3018 // manual conversion. | 3018 // manual conversion. |
| 3019 __ j(not_equal, &done); | 3019 __ j(not_equal, &done); |
| 3020 | 3020 |
| 3021 // Get high 32 bits of the input in result_reg and temp_reg. | 3021 // Get high 32 bits of the input in result_reg and temp_reg. |
| 3022 __ pshufd(xmm_scratch, input_reg, 1); | 3022 __ pshufd(xmm_scratch, input_reg, 1); |
| 3023 __ movd(Operand(temp_reg), xmm_scratch); | 3023 __ movd(Operand(temp_reg), xmm_scratch); |
| 3024 __ mov(result_reg, temp_reg); | 3024 __ mov(result_reg, temp_reg); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3092 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 3092 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 3093 LOperand* input = instr->input(); | 3093 LOperand* input = instr->input(); |
| 3094 ASSERT(input->IsRegister()); | 3094 ASSERT(input->IsRegister()); |
| 3095 __ test(ToRegister(input), Immediate(kSmiTagMask)); | 3095 __ test(ToRegister(input), Immediate(kSmiTagMask)); |
| 3096 DeoptimizeIf(instr->condition(), instr->environment()); | 3096 DeoptimizeIf(instr->condition(), instr->environment()); |
| 3097 } | 3097 } |
| 3098 | 3098 |
| 3099 | 3099 |
| 3100 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { | 3100 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { |
| 3101 Register input = ToRegister(instr->input()); | 3101 Register input = ToRegister(instr->input()); |
| 3102 Register temp = ToRegister(instr->temp()); | 3102 Register temp = ToRegister(instr->TempAt(0)); |
| 3103 InstanceType first = instr->hydrogen()->first(); | 3103 InstanceType first = instr->hydrogen()->first(); |
| 3104 InstanceType last = instr->hydrogen()->last(); | 3104 InstanceType last = instr->hydrogen()->last(); |
| 3105 | 3105 |
| 3106 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); | 3106 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); |
| 3107 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset), | 3107 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset), |
| 3108 static_cast<int8_t>(first)); | 3108 static_cast<int8_t>(first)); |
| 3109 | 3109 |
| 3110 // If there is only one type in the interval check for equality. | 3110 // If there is only one type in the interval check for equality. |
| 3111 if (first == last) { | 3111 if (first == last) { |
| 3112 DeoptimizeIf(not_equal, instr->environment()); | 3112 DeoptimizeIf(not_equal, instr->environment()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3145 Handle<JSGlobalPropertyCell> cell = | 3145 Handle<JSGlobalPropertyCell> cell = |
| 3146 Factory::NewJSGlobalPropertyCell(prototype); | 3146 Factory::NewJSGlobalPropertyCell(prototype); |
| 3147 __ mov(result, Operand::Cell(cell)); | 3147 __ mov(result, Operand::Cell(cell)); |
| 3148 } else { | 3148 } else { |
| 3149 __ mov(result, prototype); | 3149 __ mov(result, prototype); |
| 3150 } | 3150 } |
| 3151 } | 3151 } |
| 3152 | 3152 |
| 3153 | 3153 |
| 3154 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { | 3154 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { |
| 3155 Register reg = ToRegister(instr->temp()); | 3155 Register reg = ToRegister(instr->TempAt(0)); |
| 3156 | 3156 |
| 3157 Handle<JSObject> holder = instr->holder(); | 3157 Handle<JSObject> holder = instr->holder(); |
| 3158 Handle<Map> receiver_map = instr->receiver_map(); | 3158 Handle<Map> receiver_map = instr->receiver_map(); |
| 3159 Handle<JSObject> current_prototype(JSObject::cast(receiver_map->prototype())); | 3159 Handle<JSObject> current_prototype(JSObject::cast(receiver_map->prototype())); |
| 3160 | 3160 |
| 3161 // Load prototype object. | 3161 // Load prototype object. |
| 3162 LoadPrototype(reg, current_prototype); | 3162 LoadPrototype(reg, current_prototype); |
| 3163 | 3163 |
| 3164 // Check prototype maps up to the holder. | 3164 // Check prototype maps up to the holder. |
| 3165 while (!current_prototype.is_identical_to(holder)) { | 3165 while (!current_prototype.is_identical_to(holder)) { |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3476 ASSERT(!environment->HasBeenRegistered()); | 3476 ASSERT(!environment->HasBeenRegistered()); |
| 3477 RegisterEnvironmentForDeoptimization(environment); | 3477 RegisterEnvironmentForDeoptimization(environment); |
| 3478 ASSERT(osr_pc_offset_ == -1); | 3478 ASSERT(osr_pc_offset_ == -1); |
| 3479 osr_pc_offset_ = masm()->pc_offset(); | 3479 osr_pc_offset_ = masm()->pc_offset(); |
| 3480 } | 3480 } |
| 3481 | 3481 |
| 3482 | 3482 |
| 3483 #undef __ | 3483 #undef __ |
| 3484 | 3484 |
| 3485 } } // namespace v8::internal | 3485 } } // namespace v8::internal |
| OLD | NEW |