| 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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 int deoptimization_index_; | 74 int deoptimization_index_; |
| 75 }; | 75 }; |
| 76 | 76 |
| 77 | 77 |
| 78 #define __ masm()-> | 78 #define __ masm()-> |
| 79 | 79 |
| 80 bool LCodeGen::GenerateCode() { | 80 bool LCodeGen::GenerateCode() { |
| 81 HPhase phase("Code generation", chunk()); | 81 HPhase phase("Code generation", chunk()); |
| 82 ASSERT(is_unused()); | 82 ASSERT(is_unused()); |
| 83 status_ = GENERATING; | 83 status_ = GENERATING; |
| 84 |
| 85 // Open a frame scope to indicate that there is a frame on the stack. The |
| 86 // MANUAL indicates that the scope shouldn't actually generate code to set up |
| 87 // the frame (that is done in GeneratePrologue). |
| 88 FrameScope frame_scope(masm_, StackFrame::MANUAL); |
| 89 |
| 84 return GeneratePrologue() && | 90 return GeneratePrologue() && |
| 85 GenerateBody() && | 91 GenerateBody() && |
| 86 GenerateDeferredCode() && | 92 GenerateDeferredCode() && |
| 87 GenerateJumpTable() && | 93 GenerateJumpTable() && |
| 88 GenerateSafepointTable(); | 94 GenerateSafepointTable(); |
| 89 } | 95 } |
| 90 | 96 |
| 91 | 97 |
| 92 void LCodeGen::FinishCode(Handle<Code> code) { | 98 void LCodeGen::FinishCode(Handle<Code> code) { |
| 93 ASSERT(is_done()); | 99 ASSERT(is_done()); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 for (int i = 0; i < num_parameters; i++) { | 216 for (int i = 0; i < num_parameters; i++) { |
| 211 Variable* var = scope()->parameter(i); | 217 Variable* var = scope()->parameter(i); |
| 212 if (var->IsContextSlot()) { | 218 if (var->IsContextSlot()) { |
| 213 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 219 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 214 (num_parameters - 1 - i) * kPointerSize; | 220 (num_parameters - 1 - i) * kPointerSize; |
| 215 // Load parameter from stack. | 221 // Load parameter from stack. |
| 216 __ movq(rax, Operand(rbp, parameter_offset)); | 222 __ movq(rax, Operand(rbp, parameter_offset)); |
| 217 // Store it in the context. | 223 // Store it in the context. |
| 218 int context_offset = Context::SlotOffset(var->index()); | 224 int context_offset = Context::SlotOffset(var->index()); |
| 219 __ movq(Operand(rsi, context_offset), rax); | 225 __ movq(Operand(rsi, context_offset), rax); |
| 220 // Update the write barrier. This clobbers all involved | 226 // Update the write barrier. This clobbers rax and rbx. |
| 221 // registers, so we have use a third register to avoid | 227 __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs); |
| 222 // clobbering rsi. | |
| 223 __ movq(rcx, rsi); | |
| 224 __ RecordWrite(rcx, context_offset, rax, rbx); | |
| 225 } | 228 } |
| 226 } | 229 } |
| 227 Comment(";;; End allocate local context"); | 230 Comment(";;; End allocate local context"); |
| 228 } | 231 } |
| 229 | 232 |
| 230 // Trace the call. | 233 // Trace the call. |
| 231 if (FLAG_trace) { | 234 if (FLAG_trace) { |
| 232 __ CallRuntime(Runtime::kTraceEnter, 0); | 235 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 233 } | 236 } |
| 234 return !is_aborted(); | 237 return !is_aborted(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 273 return !is_aborted(); | 276 return !is_aborted(); |
| 274 } | 277 } |
| 275 | 278 |
| 276 | 279 |
| 277 bool LCodeGen::GenerateDeferredCode() { | 280 bool LCodeGen::GenerateDeferredCode() { |
| 278 ASSERT(is_generating()); | 281 ASSERT(is_generating()); |
| 279 if (deferred_.length() > 0) { | 282 if (deferred_.length() > 0) { |
| 280 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 283 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| 281 LDeferredCode* code = deferred_[i]; | 284 LDeferredCode* code = deferred_[i]; |
| 282 __ bind(code->entry()); | 285 __ bind(code->entry()); |
| 286 Comment(";;; Deferred code @%d: %s.", |
| 287 code->instruction_index(), |
| 288 code->instr()->Mnemonic()); |
| 283 code->Generate(); | 289 code->Generate(); |
| 284 __ jmp(code->exit()); | 290 __ jmp(code->exit()); |
| 285 } | 291 } |
| 286 | 292 |
| 287 // Pad code to ensure that the last piece of deferred code have | 293 // Pad code to ensure that the last piece of deferred code have |
| 288 // room for lazy bailout. | 294 // room for lazy bailout. |
| 289 while ((masm()->pc_offset() - LastSafepointEnd()) | 295 while ((masm()->pc_offset() - LastSafepointEnd()) |
| 290 < Deoptimizer::patch_size()) { | 296 < Deoptimizer::patch_size()) { |
| 291 int padding = masm()->pc_offset() - LastSafepointEnd(); | 297 int padding = masm()->pc_offset() - LastSafepointEnd(); |
| 292 if (padding > 9) { | 298 if (padding > 9) { |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 } | 666 } |
| 661 | 667 |
| 662 | 668 |
| 663 void LCodeGen::RecordSafepoint( | 669 void LCodeGen::RecordSafepoint( |
| 664 LPointerMap* pointers, | 670 LPointerMap* pointers, |
| 665 Safepoint::Kind kind, | 671 Safepoint::Kind kind, |
| 666 int arguments, | 672 int arguments, |
| 667 int deoptimization_index) { | 673 int deoptimization_index) { |
| 668 ASSERT(kind == expected_safepoint_kind_); | 674 ASSERT(kind == expected_safepoint_kind_); |
| 669 | 675 |
| 670 const ZoneList<LOperand*>* operands = pointers->operands(); | 676 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands(); |
| 671 | 677 |
| 672 Safepoint safepoint = safepoints_.DefineSafepoint(masm(), | 678 Safepoint safepoint = safepoints_.DefineSafepoint(masm(), |
| 673 kind, arguments, deoptimization_index); | 679 kind, arguments, deoptimization_index); |
| 674 for (int i = 0; i < operands->length(); i++) { | 680 for (int i = 0; i < operands->length(); i++) { |
| 675 LOperand* pointer = operands->at(i); | 681 LOperand* pointer = operands->at(i); |
| 676 if (pointer->IsStackSlot()) { | 682 if (pointer->IsStackSlot()) { |
| 677 safepoint.DefinePointerSlot(pointer->index()); | 683 safepoint.DefinePointerSlot(pointer->index()); |
| 678 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { | 684 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { |
| 679 safepoint.DefinePointerRegister(ToRegister(pointer)); | 685 safepoint.DefinePointerRegister(ToRegister(pointer)); |
| 680 } | 686 } |
| (...skipping 889 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1570 void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { | 1576 void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { |
| 1571 Register left = ToRegister(instr->InputAt(0)); | 1577 Register left = ToRegister(instr->InputAt(0)); |
| 1572 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1578 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1573 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1579 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1574 | 1580 |
| 1575 __ cmpq(left, Immediate(instr->hydrogen()->right())); | 1581 __ cmpq(left, Immediate(instr->hydrogen()->right())); |
| 1576 EmitBranch(true_block, false_block, equal); | 1582 EmitBranch(true_block, false_block, equal); |
| 1577 } | 1583 } |
| 1578 | 1584 |
| 1579 | 1585 |
| 1580 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { | 1586 void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { |
| 1581 Register reg = ToRegister(instr->InputAt(0)); | 1587 Register reg = ToRegister(instr->InputAt(0)); |
| 1582 | |
| 1583 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1588 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1584 | 1589 |
| 1590 // If the expression is known to be untagged or a smi, then it's definitely |
| 1591 // not null, and it can't be a an undetectable object. |
| 1585 if (instr->hydrogen()->representation().IsSpecialization() || | 1592 if (instr->hydrogen()->representation().IsSpecialization() || |
| 1586 instr->hydrogen()->type().IsSmi()) { | 1593 instr->hydrogen()->type().IsSmi()) { |
| 1587 // If the expression is known to untagged or smi, then it's definitely | |
| 1588 // not null, and it can't be a an undetectable object. | |
| 1589 // Jump directly to the false block. | |
| 1590 EmitGoto(false_block); | 1594 EmitGoto(false_block); |
| 1591 return; | 1595 return; |
| 1592 } | 1596 } |
| 1593 | 1597 |
| 1594 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1598 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1595 | 1599 Heap::RootListIndex nil_value = instr->nil() == kNullValue ? |
| 1596 __ CompareRoot(reg, Heap::kNullValueRootIndex); | 1600 Heap::kNullValueRootIndex : |
| 1597 if (instr->is_strict()) { | 1601 Heap::kUndefinedValueRootIndex; |
| 1602 __ CompareRoot(reg, nil_value); |
| 1603 if (instr->kind() == kStrictEquality) { |
| 1598 EmitBranch(true_block, false_block, equal); | 1604 EmitBranch(true_block, false_block, equal); |
| 1599 } else { | 1605 } else { |
| 1606 Heap::RootListIndex other_nil_value = instr->nil() == kNullValue ? |
| 1607 Heap::kUndefinedValueRootIndex : |
| 1608 Heap::kNullValueRootIndex; |
| 1600 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1609 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1601 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1610 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1602 __ j(equal, true_label); | 1611 __ j(equal, true_label); |
| 1603 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); | 1612 __ CompareRoot(reg, other_nil_value); |
| 1604 __ j(equal, true_label); | 1613 __ j(equal, true_label); |
| 1605 __ JumpIfSmi(reg, false_label); | 1614 __ JumpIfSmi(reg, false_label); |
| 1606 // Check for undetectable objects by looking in the bit field in | 1615 // Check for undetectable objects by looking in the bit field in |
| 1607 // the map. The object has already been smi checked. | 1616 // the map. The object has already been smi checked. |
| 1608 Register scratch = ToRegister(instr->TempAt(0)); | 1617 Register scratch = ToRegister(instr->TempAt(0)); |
| 1609 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); | 1618 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
| 1610 __ testb(FieldOperand(scratch, Map::kBitFieldOffset), | 1619 __ testb(FieldOperand(scratch, Map::kBitFieldOffset), |
| 1611 Immediate(1 << Map::kIsUndetectable)); | 1620 Immediate(1 << Map::kIsUndetectable)); |
| 1612 EmitBranch(true_block, false_block, not_zero); | 1621 EmitBranch(true_block, false_block, not_zero); |
| 1613 } | 1622 } |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1745 EmitBranch(true_block, false_block, equal); | 1754 EmitBranch(true_block, false_block, equal); |
| 1746 } | 1755 } |
| 1747 | 1756 |
| 1748 | 1757 |
| 1749 // Branches to a label or falls through with the answer in the z flag. | 1758 // Branches to a label or falls through with the answer in the z flag. |
| 1750 // Trashes the temp register and possibly input (if it and temp are aliased). | 1759 // Trashes the temp register and possibly input (if it and temp are aliased). |
| 1751 void LCodeGen::EmitClassOfTest(Label* is_true, | 1760 void LCodeGen::EmitClassOfTest(Label* is_true, |
| 1752 Label* is_false, | 1761 Label* is_false, |
| 1753 Handle<String> class_name, | 1762 Handle<String> class_name, |
| 1754 Register input, | 1763 Register input, |
| 1755 Register temp) { | 1764 Register temp, |
| 1765 Register scratch) { |
| 1756 __ JumpIfSmi(input, is_false); | 1766 __ JumpIfSmi(input, is_false); |
| 1757 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp); | |
| 1758 __ j(below, is_false); | |
| 1759 | 1767 |
| 1760 // Map is now in temp. | |
| 1761 // Functions have class 'Function'. | |
| 1762 __ CmpInstanceType(temp, FIRST_CALLABLE_SPEC_OBJECT_TYPE); | |
| 1763 if (class_name->IsEqualTo(CStrVector("Function"))) { | 1768 if (class_name->IsEqualTo(CStrVector("Function"))) { |
| 1764 __ j(above_equal, is_true); | 1769 // Assuming the following assertions, we can use the same compares to test |
| 1770 // for both being a function type and being in the object type range. |
| 1771 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
| 1772 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == |
| 1773 FIRST_SPEC_OBJECT_TYPE + 1); |
| 1774 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == |
| 1775 LAST_SPEC_OBJECT_TYPE - 1); |
| 1776 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); |
| 1777 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp); |
| 1778 __ j(below, is_false); |
| 1779 __ j(equal, is_true); |
| 1780 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE); |
| 1781 __ j(equal, is_true); |
| 1765 } else { | 1782 } else { |
| 1766 __ j(above_equal, is_false); | 1783 // Faster code path to avoid two compares: subtract lower bound from the |
| 1784 // actual type and do a signed compare with the width of the type range. |
| 1785 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset)); |
| 1786 __ movq(scratch, FieldOperand(temp, Map::kInstanceTypeOffset)); |
| 1787 __ subb(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 1788 __ cmpb(scratch, |
| 1789 Immediate(static_cast<int8_t>(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - |
| 1790 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE))); |
| 1791 __ j(above, is_false); |
| 1767 } | 1792 } |
| 1768 | 1793 |
| 1794 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. |
| 1769 // Check if the constructor in the map is a function. | 1795 // Check if the constructor in the map is a function. |
| 1770 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset)); | 1796 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset)); |
| 1771 | 1797 |
| 1772 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last type and | |
| 1773 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after | |
| 1774 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. | |
| 1775 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); | |
| 1776 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == | |
| 1777 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); | |
| 1778 | |
| 1779 // Objects with a non-function constructor have class 'Object'. | 1798 // Objects with a non-function constructor have class 'Object'. |
| 1780 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister); | 1799 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister); |
| 1781 if (class_name->IsEqualTo(CStrVector("Object"))) { | 1800 if (class_name->IsEqualTo(CStrVector("Object"))) { |
| 1782 __ j(not_equal, is_true); | 1801 __ j(not_equal, is_true); |
| 1783 } else { | 1802 } else { |
| 1784 __ j(not_equal, is_false); | 1803 __ j(not_equal, is_false); |
| 1785 } | 1804 } |
| 1786 | 1805 |
| 1787 // temp now contains the constructor function. Grab the | 1806 // temp now contains the constructor function. Grab the |
| 1788 // instance class name from there. | 1807 // instance class name from there. |
| 1789 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); | 1808 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); |
| 1790 __ movq(temp, FieldOperand(temp, | 1809 __ movq(temp, FieldOperand(temp, |
| 1791 SharedFunctionInfo::kInstanceClassNameOffset)); | 1810 SharedFunctionInfo::kInstanceClassNameOffset)); |
| 1792 // The class name we are testing against is a symbol because it's a literal. | 1811 // The class name we are testing against is a symbol because it's a literal. |
| 1793 // The name in the constructor is a symbol because of the way the context is | 1812 // The name in the constructor is a symbol because of the way the context is |
| 1794 // booted. This routine isn't expected to work for random API-created | 1813 // booted. This routine isn't expected to work for random API-created |
| 1795 // classes and it doesn't have to because you can't access it with natives | 1814 // classes and it doesn't have to because you can't access it with natives |
| 1796 // syntax. Since both sides are symbols it is sufficient to use an identity | 1815 // syntax. Since both sides are symbols it is sufficient to use an identity |
| 1797 // comparison. | 1816 // comparison. |
| 1798 ASSERT(class_name->IsSymbol()); | 1817 ASSERT(class_name->IsSymbol()); |
| 1799 __ Cmp(temp, class_name); | 1818 __ Cmp(temp, class_name); |
| 1800 // End with the answer in the z flag. | 1819 // End with the answer in the z flag. |
| 1801 } | 1820 } |
| 1802 | 1821 |
| 1803 | 1822 |
| 1804 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { | 1823 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
| 1805 Register input = ToRegister(instr->InputAt(0)); | 1824 Register input = ToRegister(instr->InputAt(0)); |
| 1806 Register temp = ToRegister(instr->TempAt(0)); | 1825 Register temp = ToRegister(instr->TempAt(0)); |
| 1826 Register temp2 = ToRegister(instr->TempAt(1)); |
| 1807 Handle<String> class_name = instr->hydrogen()->class_name(); | 1827 Handle<String> class_name = instr->hydrogen()->class_name(); |
| 1808 | 1828 |
| 1809 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1829 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1810 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1830 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1811 | 1831 |
| 1812 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1832 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1813 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1833 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1814 | 1834 |
| 1815 EmitClassOfTest(true_label, false_label, class_name, input, temp); | 1835 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2); |
| 1816 | 1836 |
| 1817 EmitBranch(true_block, false_block, equal); | 1837 EmitBranch(true_block, false_block, equal); |
| 1818 } | 1838 } |
| 1819 | 1839 |
| 1820 | 1840 |
| 1821 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { | 1841 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { |
| 1822 Register reg = ToRegister(instr->InputAt(0)); | 1842 Register reg = ToRegister(instr->InputAt(0)); |
| 1823 int true_block = instr->true_block_id(); | 1843 int true_block = instr->true_block_id(); |
| 1824 int false_block = instr->false_block_id(); | 1844 int false_block = instr->false_block_id(); |
| 1825 | 1845 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1846 | 1866 |
| 1847 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { | 1867 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { |
| 1848 class DeferredInstanceOfKnownGlobal: public LDeferredCode { | 1868 class DeferredInstanceOfKnownGlobal: public LDeferredCode { |
| 1849 public: | 1869 public: |
| 1850 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, | 1870 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, |
| 1851 LInstanceOfKnownGlobal* instr) | 1871 LInstanceOfKnownGlobal* instr) |
| 1852 : LDeferredCode(codegen), instr_(instr) { } | 1872 : LDeferredCode(codegen), instr_(instr) { } |
| 1853 virtual void Generate() { | 1873 virtual void Generate() { |
| 1854 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); | 1874 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); |
| 1855 } | 1875 } |
| 1856 | 1876 virtual LInstruction* instr() { return instr_; } |
| 1857 Label* map_check() { return &map_check_; } | 1877 Label* map_check() { return &map_check_; } |
| 1858 | |
| 1859 private: | 1878 private: |
| 1860 LInstanceOfKnownGlobal* instr_; | 1879 LInstanceOfKnownGlobal* instr_; |
| 1861 Label map_check_; | 1880 Label map_check_; |
| 1862 }; | 1881 }; |
| 1863 | 1882 |
| 1864 | 1883 |
| 1865 DeferredInstanceOfKnownGlobal* deferred; | 1884 DeferredInstanceOfKnownGlobal* deferred; |
| 1866 deferred = new DeferredInstanceOfKnownGlobal(this, instr); | 1885 deferred = new DeferredInstanceOfKnownGlobal(this, instr); |
| 1867 | 1886 |
| 1868 Label done, false_result; | 1887 Label done, false_result; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1989 | 2008 |
| 1990 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { | 2009 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { |
| 1991 Register result = ToRegister(instr->result()); | 2010 Register result = ToRegister(instr->result()); |
| 1992 if (result.is(rax)) { | 2011 if (result.is(rax)) { |
| 1993 __ load_rax(instr->hydrogen()->cell().location(), | 2012 __ load_rax(instr->hydrogen()->cell().location(), |
| 1994 RelocInfo::GLOBAL_PROPERTY_CELL); | 2013 RelocInfo::GLOBAL_PROPERTY_CELL); |
| 1995 } else { | 2014 } else { |
| 1996 __ movq(result, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL); | 2015 __ movq(result, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL); |
| 1997 __ movq(result, Operand(result, 0)); | 2016 __ movq(result, Operand(result, 0)); |
| 1998 } | 2017 } |
| 1999 if (instr->hydrogen()->check_hole_value()) { | 2018 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2000 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); | 2019 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| 2001 DeoptimizeIf(equal, instr->environment()); | 2020 DeoptimizeIf(equal, instr->environment()); |
| 2002 } | 2021 } |
| 2003 } | 2022 } |
| 2004 | 2023 |
| 2005 | 2024 |
| 2006 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { | 2025 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { |
| 2007 ASSERT(ToRegister(instr->global_object()).is(rax)); | 2026 ASSERT(ToRegister(instr->global_object()).is(rax)); |
| 2008 ASSERT(ToRegister(instr->result()).is(rax)); | 2027 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2009 | 2028 |
| 2010 __ Move(rcx, instr->name()); | 2029 __ Move(rcx, instr->name()); |
| 2011 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET : | 2030 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET : |
| 2012 RelocInfo::CODE_TARGET_CONTEXT; | 2031 RelocInfo::CODE_TARGET_CONTEXT; |
| 2013 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 2032 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 2014 CallCode(ic, mode, instr); | 2033 CallCode(ic, mode, instr); |
| 2015 } | 2034 } |
| 2016 | 2035 |
| 2017 | 2036 |
| 2018 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { | 2037 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { |
| 2038 Register object = ToRegister(instr->TempAt(0)); |
| 2039 Register address = ToRegister(instr->TempAt(1)); |
| 2019 Register value = ToRegister(instr->InputAt(0)); | 2040 Register value = ToRegister(instr->InputAt(0)); |
| 2020 Register temp = ToRegister(instr->TempAt(0)); | 2041 ASSERT(!value.is(object)); |
| 2021 ASSERT(!value.is(temp)); | 2042 Handle<JSGlobalPropertyCell> cell_handle(instr->hydrogen()->cell()); |
| 2022 bool check_hole = instr->hydrogen()->check_hole_value(); | 2043 |
| 2023 if (!check_hole && value.is(rax)) { | 2044 __ movq(address, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL); |
| 2024 __ store_rax(instr->hydrogen()->cell().location(), | 2045 |
| 2025 RelocInfo::GLOBAL_PROPERTY_CELL); | |
| 2026 return; | |
| 2027 } | |
| 2028 // If the cell we are storing to contains the hole it could have | 2046 // If the cell we are storing to contains the hole it could have |
| 2029 // been deleted from the property dictionary. In that case, we need | 2047 // been deleted from the property dictionary. In that case, we need |
| 2030 // to update the property details in the property dictionary to mark | 2048 // to update the property details in the property dictionary to mark |
| 2031 // it as no longer deleted. We deoptimize in that case. | 2049 // it as no longer deleted. We deoptimize in that case. |
| 2032 __ movq(temp, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL); | 2050 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2033 if (check_hole) { | 2051 __ CompareRoot(Operand(address, 0), Heap::kTheHoleValueRootIndex); |
| 2034 __ CompareRoot(Operand(temp, 0), Heap::kTheHoleValueRootIndex); | |
| 2035 DeoptimizeIf(equal, instr->environment()); | 2052 DeoptimizeIf(equal, instr->environment()); |
| 2036 } | 2053 } |
| 2037 __ movq(Operand(temp, 0), value); | 2054 |
| 2055 // Store the value. |
| 2056 __ movq(Operand(address, 0), value); |
| 2057 |
| 2058 Label smi_store; |
| 2059 __ JumpIfSmi(value, &smi_store, Label::kNear); |
| 2060 |
| 2061 int offset = JSGlobalPropertyCell::kValueOffset - kHeapObjectTag; |
| 2062 __ lea(object, Operand(address, -offset)); |
| 2063 // Cells are always in the remembered set. |
| 2064 __ RecordWrite(object, |
| 2065 address, |
| 2066 value, |
| 2067 kSaveFPRegs, |
| 2068 OMIT_REMEMBERED_SET, |
| 2069 OMIT_SMI_CHECK); |
| 2070 __ bind(&smi_store); |
| 2038 } | 2071 } |
| 2039 | 2072 |
| 2040 | 2073 |
| 2041 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { | 2074 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { |
| 2042 ASSERT(ToRegister(instr->global_object()).is(rdx)); | 2075 ASSERT(ToRegister(instr->global_object()).is(rdx)); |
| 2043 ASSERT(ToRegister(instr->value()).is(rax)); | 2076 ASSERT(ToRegister(instr->value()).is(rax)); |
| 2044 | 2077 |
| 2045 __ Move(rcx, instr->name()); | 2078 __ Move(rcx, instr->name()); |
| 2046 Handle<Code> ic = instr->strict_mode() | 2079 Handle<Code> ic = instr->strict_mode() |
| 2047 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 2080 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 2048 : isolate()->builtins()->StoreIC_Initialize(); | 2081 : isolate()->builtins()->StoreIC_Initialize(); |
| 2049 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); | 2082 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); |
| 2050 } | 2083 } |
| 2051 | 2084 |
| 2052 | 2085 |
| 2053 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 2086 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
| 2054 Register context = ToRegister(instr->context()); | 2087 Register context = ToRegister(instr->context()); |
| 2055 Register result = ToRegister(instr->result()); | 2088 Register result = ToRegister(instr->result()); |
| 2056 __ movq(result, ContextOperand(context, instr->slot_index())); | 2089 __ movq(result, ContextOperand(context, instr->slot_index())); |
| 2057 } | 2090 } |
| 2058 | 2091 |
| 2059 | 2092 |
| 2060 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { | 2093 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { |
| 2061 Register context = ToRegister(instr->context()); | 2094 Register context = ToRegister(instr->context()); |
| 2062 Register value = ToRegister(instr->value()); | 2095 Register value = ToRegister(instr->value()); |
| 2063 __ movq(ContextOperand(context, instr->slot_index()), value); | 2096 __ movq(ContextOperand(context, instr->slot_index()), value); |
| 2064 if (instr->needs_write_barrier()) { | 2097 if (instr->needs_write_barrier()) { |
| 2065 int offset = Context::SlotOffset(instr->slot_index()); | 2098 int offset = Context::SlotOffset(instr->slot_index()); |
| 2066 Register scratch = ToRegister(instr->TempAt(0)); | 2099 Register scratch = ToRegister(instr->TempAt(0)); |
| 2067 __ RecordWrite(context, offset, value, scratch); | 2100 __ RecordWriteContextSlot(context, offset, value, scratch, kSaveFPRegs); |
| 2068 } | 2101 } |
| 2069 } | 2102 } |
| 2070 | 2103 |
| 2071 | 2104 |
| 2072 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { | 2105 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
| 2073 Register object = ToRegister(instr->InputAt(0)); | 2106 Register object = ToRegister(instr->InputAt(0)); |
| 2074 Register result = ToRegister(instr->result()); | 2107 Register result = ToRegister(instr->result()); |
| 2075 if (instr->hydrogen()->is_in_object()) { | 2108 if (instr->hydrogen()->is_in_object()) { |
| 2076 __ movq(result, FieldOperand(object, instr->hydrogen()->offset())); | 2109 __ movq(result, FieldOperand(object, instr->hydrogen()->offset())); |
| 2077 } else { | 2110 } else { |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2276 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); | 2309 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| 2277 DeoptimizeIf(equal, instr->environment()); | 2310 DeoptimizeIf(equal, instr->environment()); |
| 2278 } | 2311 } |
| 2279 } | 2312 } |
| 2280 | 2313 |
| 2281 | 2314 |
| 2282 void LCodeGen::DoLoadKeyedFastDoubleElement( | 2315 void LCodeGen::DoLoadKeyedFastDoubleElement( |
| 2283 LLoadKeyedFastDoubleElement* instr) { | 2316 LLoadKeyedFastDoubleElement* instr) { |
| 2284 XMMRegister result(ToDoubleRegister(instr->result())); | 2317 XMMRegister result(ToDoubleRegister(instr->result())); |
| 2285 | 2318 |
| 2286 if (instr->hydrogen()->RequiresHoleCheck()) { | 2319 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag + |
| 2287 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag + | 2320 sizeof(kHoleNanLower32); |
| 2288 sizeof(kHoleNanLower32); | 2321 Operand hole_check_operand = BuildFastArrayOperand( |
| 2289 Operand hole_check_operand = BuildFastArrayOperand( | 2322 instr->elements(), |
| 2290 instr->elements(), | 2323 instr->key(), |
| 2291 instr->key(), | 2324 FAST_DOUBLE_ELEMENTS, |
| 2292 FAST_DOUBLE_ELEMENTS, | 2325 offset); |
| 2293 offset); | 2326 __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32)); |
| 2294 __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32)); | 2327 DeoptimizeIf(equal, instr->environment()); |
| 2295 DeoptimizeIf(equal, instr->environment()); | |
| 2296 } | |
| 2297 | 2328 |
| 2298 Operand double_load_operand = BuildFastArrayOperand( | 2329 Operand double_load_operand = BuildFastArrayOperand( |
| 2299 instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS, | 2330 instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS, |
| 2300 FixedDoubleArray::kHeaderSize - kHeapObjectTag); | 2331 FixedDoubleArray::kHeaderSize - kHeapObjectTag); |
| 2301 __ movsd(result, double_load_operand); | 2332 __ movsd(result, double_load_operand); |
| 2302 } | 2333 } |
| 2303 | 2334 |
| 2304 | 2335 |
| 2305 Operand LCodeGen::BuildFastArrayOperand( | 2336 Operand LCodeGen::BuildFastArrayOperand( |
| 2306 LOperand* elements_pointer, | 2337 LOperand* elements_pointer, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2358 __ movl(result, operand); | 2389 __ movl(result, operand); |
| 2359 __ testl(result, result); | 2390 __ testl(result, result); |
| 2360 // TODO(danno): we could be more clever here, perhaps having a special | 2391 // TODO(danno): we could be more clever here, perhaps having a special |
| 2361 // version of the stub that detects if the overflow case actually | 2392 // version of the stub that detects if the overflow case actually |
| 2362 // happens, and generate code that returns a double rather than int. | 2393 // happens, and generate code that returns a double rather than int. |
| 2363 DeoptimizeIf(negative, instr->environment()); | 2394 DeoptimizeIf(negative, instr->environment()); |
| 2364 break; | 2395 break; |
| 2365 case EXTERNAL_FLOAT_ELEMENTS: | 2396 case EXTERNAL_FLOAT_ELEMENTS: |
| 2366 case EXTERNAL_DOUBLE_ELEMENTS: | 2397 case EXTERNAL_DOUBLE_ELEMENTS: |
| 2367 case FAST_ELEMENTS: | 2398 case FAST_ELEMENTS: |
| 2399 case FAST_SMI_ONLY_ELEMENTS: |
| 2368 case FAST_DOUBLE_ELEMENTS: | 2400 case FAST_DOUBLE_ELEMENTS: |
| 2369 case DICTIONARY_ELEMENTS: | 2401 case DICTIONARY_ELEMENTS: |
| 2370 case NON_STRICT_ARGUMENTS_ELEMENTS: | 2402 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 2371 UNREACHABLE(); | 2403 UNREACHABLE(); |
| 2372 break; | 2404 break; |
| 2373 } | 2405 } |
| 2374 } | 2406 } |
| 2375 } | 2407 } |
| 2376 | 2408 |
| 2377 | 2409 |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2674 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { | 2706 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { |
| 2675 // Class for deferred case. | 2707 // Class for deferred case. |
| 2676 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { | 2708 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { |
| 2677 public: | 2709 public: |
| 2678 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, | 2710 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, |
| 2679 LUnaryMathOperation* instr) | 2711 LUnaryMathOperation* instr) |
| 2680 : LDeferredCode(codegen), instr_(instr) { } | 2712 : LDeferredCode(codegen), instr_(instr) { } |
| 2681 virtual void Generate() { | 2713 virtual void Generate() { |
| 2682 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); | 2714 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); |
| 2683 } | 2715 } |
| 2716 virtual LInstruction* instr() { return instr_; } |
| 2684 private: | 2717 private: |
| 2685 LUnaryMathOperation* instr_; | 2718 LUnaryMathOperation* instr_; |
| 2686 }; | 2719 }; |
| 2687 | 2720 |
| 2688 ASSERT(instr->InputAt(0)->Equals(instr->result())); | 2721 ASSERT(instr->InputAt(0)->Equals(instr->result())); |
| 2689 Representation r = instr->hydrogen()->value()->representation(); | 2722 Representation r = instr->hydrogen()->value()->representation(); |
| 2690 | 2723 |
| 2691 if (r.IsDouble()) { | 2724 if (r.IsDouble()) { |
| 2692 XMMRegister scratch = xmm0; | 2725 XMMRegister scratch = xmm0; |
| 2693 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 2726 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2970 __ Move(rcx, instr->name()); | 3003 __ Move(rcx, instr->name()); |
| 2971 CallCode(ic, mode, instr); | 3004 CallCode(ic, mode, instr); |
| 2972 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 3005 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2973 } | 3006 } |
| 2974 | 3007 |
| 2975 | 3008 |
| 2976 void LCodeGen::DoCallFunction(LCallFunction* instr) { | 3009 void LCodeGen::DoCallFunction(LCallFunction* instr) { |
| 2977 ASSERT(ToRegister(instr->result()).is(rax)); | 3010 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2978 | 3011 |
| 2979 int arity = instr->arity(); | 3012 int arity = instr->arity(); |
| 2980 CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT); | 3013 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS); |
| 2981 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 3014 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2982 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 3015 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2983 __ Drop(1); | 3016 __ Drop(1); |
| 2984 } | 3017 } |
| 2985 | 3018 |
| 2986 | 3019 |
| 2987 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { | 3020 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { |
| 2988 ASSERT(ToRegister(instr->result()).is(rax)); | 3021 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2989 int arity = instr->arity(); | 3022 int arity = instr->arity(); |
| 2990 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT; | 3023 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3026 if (!instr->transition().is_null()) { | 3059 if (!instr->transition().is_null()) { |
| 3027 __ Move(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); | 3060 __ Move(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); |
| 3028 } | 3061 } |
| 3029 | 3062 |
| 3030 // Do the store. | 3063 // Do the store. |
| 3031 if (instr->is_in_object()) { | 3064 if (instr->is_in_object()) { |
| 3032 __ movq(FieldOperand(object, offset), value); | 3065 __ movq(FieldOperand(object, offset), value); |
| 3033 if (instr->needs_write_barrier()) { | 3066 if (instr->needs_write_barrier()) { |
| 3034 Register temp = ToRegister(instr->TempAt(0)); | 3067 Register temp = ToRegister(instr->TempAt(0)); |
| 3035 // Update the write barrier for the object for in-object properties. | 3068 // Update the write barrier for the object for in-object properties. |
| 3036 __ RecordWrite(object, offset, value, temp); | 3069 __ RecordWriteField(object, offset, value, temp, kSaveFPRegs); |
| 3037 } | 3070 } |
| 3038 } else { | 3071 } else { |
| 3039 Register temp = ToRegister(instr->TempAt(0)); | 3072 Register temp = ToRegister(instr->TempAt(0)); |
| 3040 __ movq(temp, FieldOperand(object, JSObject::kPropertiesOffset)); | 3073 __ movq(temp, FieldOperand(object, JSObject::kPropertiesOffset)); |
| 3041 __ movq(FieldOperand(temp, offset), value); | 3074 __ movq(FieldOperand(temp, offset), value); |
| 3042 if (instr->needs_write_barrier()) { | 3075 if (instr->needs_write_barrier()) { |
| 3043 // Update the write barrier for the properties array. | 3076 // Update the write barrier for the properties array. |
| 3044 // object is used as a scratch register. | 3077 // object is used as a scratch register. |
| 3045 __ RecordWrite(temp, offset, value, object); | 3078 __ RecordWriteField(temp, offset, value, object, kSaveFPRegs); |
| 3046 } | 3079 } |
| 3047 } | 3080 } |
| 3048 } | 3081 } |
| 3049 | 3082 |
| 3050 | 3083 |
| 3051 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { | 3084 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
| 3052 ASSERT(ToRegister(instr->object()).is(rdx)); | 3085 ASSERT(ToRegister(instr->object()).is(rdx)); |
| 3053 ASSERT(ToRegister(instr->value()).is(rax)); | 3086 ASSERT(ToRegister(instr->value()).is(rax)); |
| 3054 | 3087 |
| 3055 __ Move(rcx, instr->hydrogen()->name()); | 3088 __ Move(rcx, instr->hydrogen()->name()); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 3083 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3116 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3084 __ movw(operand, value); | 3117 __ movw(operand, value); |
| 3085 break; | 3118 break; |
| 3086 case EXTERNAL_INT_ELEMENTS: | 3119 case EXTERNAL_INT_ELEMENTS: |
| 3087 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3120 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3088 __ movl(operand, value); | 3121 __ movl(operand, value); |
| 3089 break; | 3122 break; |
| 3090 case EXTERNAL_FLOAT_ELEMENTS: | 3123 case EXTERNAL_FLOAT_ELEMENTS: |
| 3091 case EXTERNAL_DOUBLE_ELEMENTS: | 3124 case EXTERNAL_DOUBLE_ELEMENTS: |
| 3092 case FAST_ELEMENTS: | 3125 case FAST_ELEMENTS: |
| 3126 case FAST_SMI_ONLY_ELEMENTS: |
| 3093 case FAST_DOUBLE_ELEMENTS: | 3127 case FAST_DOUBLE_ELEMENTS: |
| 3094 case DICTIONARY_ELEMENTS: | 3128 case DICTIONARY_ELEMENTS: |
| 3095 case NON_STRICT_ARGUMENTS_ELEMENTS: | 3129 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 3096 UNREACHABLE(); | 3130 UNREACHABLE(); |
| 3097 break; | 3131 break; |
| 3098 } | 3132 } |
| 3099 } | 3133 } |
| 3100 } | 3134 } |
| 3101 | 3135 |
| 3102 | 3136 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3118 } | 3152 } |
| 3119 DeoptimizeIf(below_equal, instr->environment()); | 3153 DeoptimizeIf(below_equal, instr->environment()); |
| 3120 } | 3154 } |
| 3121 | 3155 |
| 3122 | 3156 |
| 3123 void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { | 3157 void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { |
| 3124 Register value = ToRegister(instr->value()); | 3158 Register value = ToRegister(instr->value()); |
| 3125 Register elements = ToRegister(instr->object()); | 3159 Register elements = ToRegister(instr->object()); |
| 3126 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; | 3160 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; |
| 3127 | 3161 |
| 3162 // This instruction cannot handle the FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS |
| 3163 // conversion, so it deopts in that case. |
| 3164 if (instr->hydrogen()->ValueNeedsSmiCheck()) { |
| 3165 Condition cc = masm()->CheckSmi(value); |
| 3166 DeoptimizeIf(NegateCondition(cc), instr->environment()); |
| 3167 } |
| 3168 |
| 3128 // Do the store. | 3169 // Do the store. |
| 3129 if (instr->key()->IsConstantOperand()) { | 3170 if (instr->key()->IsConstantOperand()) { |
| 3130 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); | 3171 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); |
| 3131 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); | 3172 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); |
| 3132 int offset = | 3173 int offset = |
| 3133 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize; | 3174 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize; |
| 3134 __ movq(FieldOperand(elements, offset), value); | 3175 __ movq(FieldOperand(elements, offset), value); |
| 3135 } else { | 3176 } else { |
| 3136 __ movq(FieldOperand(elements, | 3177 __ movq(FieldOperand(elements, |
| 3137 key, | 3178 key, |
| 3138 times_pointer_size, | 3179 times_pointer_size, |
| 3139 FixedArray::kHeaderSize), | 3180 FixedArray::kHeaderSize), |
| 3140 value); | 3181 value); |
| 3141 } | 3182 } |
| 3142 | 3183 |
| 3143 if (instr->hydrogen()->NeedsWriteBarrier()) { | 3184 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 3144 // Compute address of modified element and store it into key register. | 3185 // Compute address of modified element and store it into key register. |
| 3145 __ lea(key, FieldOperand(elements, | 3186 __ lea(key, FieldOperand(elements, |
| 3146 key, | 3187 key, |
| 3147 times_pointer_size, | 3188 times_pointer_size, |
| 3148 FixedArray::kHeaderSize)); | 3189 FixedArray::kHeaderSize)); |
| 3149 __ RecordWrite(elements, key, value); | 3190 __ RecordWrite(elements, key, value, kSaveFPRegs); |
| 3150 } | 3191 } |
| 3151 } | 3192 } |
| 3152 | 3193 |
| 3153 | 3194 |
| 3154 void LCodeGen::DoStoreKeyedFastDoubleElement( | 3195 void LCodeGen::DoStoreKeyedFastDoubleElement( |
| 3155 LStoreKeyedFastDoubleElement* instr) { | 3196 LStoreKeyedFastDoubleElement* instr) { |
| 3156 XMMRegister value = ToDoubleRegister(instr->value()); | 3197 XMMRegister value = ToDoubleRegister(instr->value()); |
| 3157 Label have_value; | 3198 Label have_value; |
| 3158 | 3199 |
| 3159 __ ucomisd(value, value); | 3200 __ ucomisd(value, value); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 3189 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 3230 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3190 } | 3231 } |
| 3191 | 3232 |
| 3192 | 3233 |
| 3193 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { | 3234 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| 3194 class DeferredStringCharCodeAt: public LDeferredCode { | 3235 class DeferredStringCharCodeAt: public LDeferredCode { |
| 3195 public: | 3236 public: |
| 3196 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) | 3237 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) |
| 3197 : LDeferredCode(codegen), instr_(instr) { } | 3238 : LDeferredCode(codegen), instr_(instr) { } |
| 3198 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } | 3239 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } |
| 3240 virtual LInstruction* instr() { return instr_; } |
| 3199 private: | 3241 private: |
| 3200 LStringCharCodeAt* instr_; | 3242 LStringCharCodeAt* instr_; |
| 3201 }; | 3243 }; |
| 3202 | 3244 |
| 3203 Register string = ToRegister(instr->string()); | 3245 Register string = ToRegister(instr->string()); |
| 3204 Register index = ToRegister(instr->index()); | 3246 Register index = ToRegister(instr->index()); |
| 3205 Register result = ToRegister(instr->result()); | 3247 Register result = ToRegister(instr->result()); |
| 3206 | 3248 |
| 3207 DeferredStringCharCodeAt* deferred = | 3249 DeferredStringCharCodeAt* deferred = |
| 3208 new DeferredStringCharCodeAt(this, instr); | 3250 new DeferredStringCharCodeAt(this, instr); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3309 __ StoreToSafepointRegisterSlot(result, rax); | 3351 __ StoreToSafepointRegisterSlot(result, rax); |
| 3310 } | 3352 } |
| 3311 | 3353 |
| 3312 | 3354 |
| 3313 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { | 3355 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { |
| 3314 class DeferredStringCharFromCode: public LDeferredCode { | 3356 class DeferredStringCharFromCode: public LDeferredCode { |
| 3315 public: | 3357 public: |
| 3316 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) | 3358 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) |
| 3317 : LDeferredCode(codegen), instr_(instr) { } | 3359 : LDeferredCode(codegen), instr_(instr) { } |
| 3318 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } | 3360 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } |
| 3361 virtual LInstruction* instr() { return instr_; } |
| 3319 private: | 3362 private: |
| 3320 LStringCharFromCode* instr_; | 3363 LStringCharFromCode* instr_; |
| 3321 }; | 3364 }; |
| 3322 | 3365 |
| 3323 DeferredStringCharFromCode* deferred = | 3366 DeferredStringCharFromCode* deferred = |
| 3324 new DeferredStringCharFromCode(this, instr); | 3367 new DeferredStringCharFromCode(this, instr); |
| 3325 | 3368 |
| 3326 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); | 3369 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); |
| 3327 Register char_code = ToRegister(instr->char_code()); | 3370 Register char_code = ToRegister(instr->char_code()); |
| 3328 Register result = ToRegister(instr->result()); | 3371 Register result = ToRegister(instr->result()); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3385 __ Integer32ToSmi(reg, reg); | 3428 __ Integer32ToSmi(reg, reg); |
| 3386 } | 3429 } |
| 3387 | 3430 |
| 3388 | 3431 |
| 3389 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { | 3432 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
| 3390 class DeferredNumberTagD: public LDeferredCode { | 3433 class DeferredNumberTagD: public LDeferredCode { |
| 3391 public: | 3434 public: |
| 3392 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) | 3435 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) |
| 3393 : LDeferredCode(codegen), instr_(instr) { } | 3436 : LDeferredCode(codegen), instr_(instr) { } |
| 3394 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } | 3437 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } |
| 3438 virtual LInstruction* instr() { return instr_; } |
| 3395 private: | 3439 private: |
| 3396 LNumberTagD* instr_; | 3440 LNumberTagD* instr_; |
| 3397 }; | 3441 }; |
| 3398 | 3442 |
| 3399 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 3443 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| 3400 Register reg = ToRegister(instr->result()); | 3444 Register reg = ToRegister(instr->result()); |
| 3401 Register tmp = ToRegister(instr->TempAt(0)); | 3445 Register tmp = ToRegister(instr->TempAt(0)); |
| 3402 | 3446 |
| 3403 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); | 3447 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); |
| 3404 if (FLAG_inline_new) { | 3448 if (FLAG_inline_new) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3480 __ jmp(&done, Label::kNear); | 3524 __ jmp(&done, Label::kNear); |
| 3481 | 3525 |
| 3482 // Smi to XMM conversion | 3526 // Smi to XMM conversion |
| 3483 __ bind(&load_smi); | 3527 __ bind(&load_smi); |
| 3484 __ SmiToInteger32(kScratchRegister, input_reg); | 3528 __ SmiToInteger32(kScratchRegister, input_reg); |
| 3485 __ cvtlsi2sd(result_reg, kScratchRegister); | 3529 __ cvtlsi2sd(result_reg, kScratchRegister); |
| 3486 __ bind(&done); | 3530 __ bind(&done); |
| 3487 } | 3531 } |
| 3488 | 3532 |
| 3489 | 3533 |
| 3490 class DeferredTaggedToI: public LDeferredCode { | |
| 3491 public: | |
| 3492 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) | |
| 3493 : LDeferredCode(codegen), instr_(instr) { } | |
| 3494 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } | |
| 3495 private: | |
| 3496 LTaggedToI* instr_; | |
| 3497 }; | |
| 3498 | |
| 3499 | |
| 3500 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { | 3534 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { |
| 3501 Label done, heap_number; | 3535 Label done, heap_number; |
| 3502 Register input_reg = ToRegister(instr->InputAt(0)); | 3536 Register input_reg = ToRegister(instr->InputAt(0)); |
| 3503 | 3537 |
| 3504 // Heap number map check. | 3538 // Heap number map check. |
| 3505 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), | 3539 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 3506 Heap::kHeapNumberMapRootIndex); | 3540 Heap::kHeapNumberMapRootIndex); |
| 3507 | 3541 |
| 3508 if (instr->truncating()) { | 3542 if (instr->truncating()) { |
| 3509 __ j(equal, &heap_number, Label::kNear); | 3543 __ j(equal, &heap_number, Label::kNear); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 3538 __ movmskpd(input_reg, xmm0); | 3572 __ movmskpd(input_reg, xmm0); |
| 3539 __ andl(input_reg, Immediate(1)); | 3573 __ andl(input_reg, Immediate(1)); |
| 3540 DeoptimizeIf(not_zero, instr->environment()); | 3574 DeoptimizeIf(not_zero, instr->environment()); |
| 3541 } | 3575 } |
| 3542 } | 3576 } |
| 3543 __ bind(&done); | 3577 __ bind(&done); |
| 3544 } | 3578 } |
| 3545 | 3579 |
| 3546 | 3580 |
| 3547 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { | 3581 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { |
| 3582 class DeferredTaggedToI: public LDeferredCode { |
| 3583 public: |
| 3584 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) |
| 3585 : LDeferredCode(codegen), instr_(instr) { } |
| 3586 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } |
| 3587 virtual LInstruction* instr() { return instr_; } |
| 3588 private: |
| 3589 LTaggedToI* instr_; |
| 3590 }; |
| 3591 |
| 3548 LOperand* input = instr->InputAt(0); | 3592 LOperand* input = instr->InputAt(0); |
| 3549 ASSERT(input->IsRegister()); | 3593 ASSERT(input->IsRegister()); |
| 3550 ASSERT(input->Equals(instr->result())); | 3594 ASSERT(input->Equals(instr->result())); |
| 3551 | 3595 |
| 3552 Register input_reg = ToRegister(input); | 3596 Register input_reg = ToRegister(input); |
| 3553 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr); | 3597 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr); |
| 3554 __ JumpIfNotSmi(input_reg, deferred->entry()); | 3598 __ JumpIfNotSmi(input_reg, deferred->entry()); |
| 3555 __ SmiToInteger32(input_reg, input_reg); | 3599 __ SmiToInteger32(input_reg, input_reg); |
| 3556 __ bind(deferred->exit()); | 3600 __ bind(deferred->exit()); |
| 3557 } | 3601 } |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3974 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); | 4018 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); |
| 3975 __ j(equal, true_label); | 4019 __ j(equal, true_label); |
| 3976 __ JumpIfSmi(input, false_label); | 4020 __ JumpIfSmi(input, false_label); |
| 3977 // Check for undetectable objects => true. | 4021 // Check for undetectable objects => true. |
| 3978 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); | 4022 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); |
| 3979 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 4023 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 3980 Immediate(1 << Map::kIsUndetectable)); | 4024 Immediate(1 << Map::kIsUndetectable)); |
| 3981 final_branch_condition = not_zero; | 4025 final_branch_condition = not_zero; |
| 3982 | 4026 |
| 3983 } else if (type_name->Equals(heap()->function_symbol())) { | 4027 } else if (type_name->Equals(heap()->function_symbol())) { |
| 4028 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
| 3984 __ JumpIfSmi(input, false_label); | 4029 __ JumpIfSmi(input, false_label); |
| 3985 __ CmpObjectType(input, FIRST_CALLABLE_SPEC_OBJECT_TYPE, input); | 4030 __ CmpObjectType(input, JS_FUNCTION_TYPE, input); |
| 3986 final_branch_condition = above_equal; | 4031 __ j(equal, true_label); |
| 4032 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); |
| 4033 final_branch_condition = equal; |
| 3987 | 4034 |
| 3988 } else if (type_name->Equals(heap()->object_symbol())) { | 4035 } else if (type_name->Equals(heap()->object_symbol())) { |
| 3989 __ JumpIfSmi(input, false_label); | 4036 __ JumpIfSmi(input, false_label); |
| 3990 if (!FLAG_harmony_typeof) { | 4037 if (!FLAG_harmony_typeof) { |
| 3991 __ CompareRoot(input, Heap::kNullValueRootIndex); | 4038 __ CompareRoot(input, Heap::kNullValueRootIndex); |
| 3992 __ j(equal, true_label); | 4039 __ j(equal, true_label); |
| 3993 } | 4040 } |
| 3994 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); | 4041 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); |
| 3995 __ j(below, false_label); | 4042 __ j(below, false_label); |
| 3996 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); | 4043 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4102 safepoints_.SetPcAfterGap(pc); | 4149 safepoints_.SetPcAfterGap(pc); |
| 4103 } | 4150 } |
| 4104 | 4151 |
| 4105 | 4152 |
| 4106 void LCodeGen::DoStackCheck(LStackCheck* instr) { | 4153 void LCodeGen::DoStackCheck(LStackCheck* instr) { |
| 4107 class DeferredStackCheck: public LDeferredCode { | 4154 class DeferredStackCheck: public LDeferredCode { |
| 4108 public: | 4155 public: |
| 4109 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) | 4156 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) |
| 4110 : LDeferredCode(codegen), instr_(instr) { } | 4157 : LDeferredCode(codegen), instr_(instr) { } |
| 4111 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } | 4158 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } |
| 4159 virtual LInstruction* instr() { return instr_; } |
| 4112 private: | 4160 private: |
| 4113 LStackCheck* instr_; | 4161 LStackCheck* instr_; |
| 4114 }; | 4162 }; |
| 4115 | 4163 |
| 4116 if (instr->hydrogen()->is_function_entry()) { | 4164 if (instr->hydrogen()->is_function_entry()) { |
| 4117 // Perform stack overflow check. | 4165 // Perform stack overflow check. |
| 4118 Label done; | 4166 Label done; |
| 4119 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 4167 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 4120 __ j(above_equal, &done, Label::kNear); | 4168 __ j(above_equal, &done, Label::kNear); |
| 4121 StackCheckStub stub; | 4169 StackCheckStub stub; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 4148 RegisterEnvironmentForDeoptimization(environment); | 4196 RegisterEnvironmentForDeoptimization(environment); |
| 4149 ASSERT(osr_pc_offset_ == -1); | 4197 ASSERT(osr_pc_offset_ == -1); |
| 4150 osr_pc_offset_ = masm()->pc_offset(); | 4198 osr_pc_offset_ = masm()->pc_offset(); |
| 4151 } | 4199 } |
| 4152 | 4200 |
| 4153 #undef __ | 4201 #undef __ |
| 4154 | 4202 |
| 4155 } } // namespace v8::internal | 4203 } } // namespace v8::internal |
| 4156 | 4204 |
| 4157 #endif // V8_TARGET_ARCH_X64 | 4205 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |