| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 141 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| 142 __ stop("stop-at"); | 142 __ stop("stop-at"); |
| 143 } | 143 } |
| 144 #endif | 144 #endif |
| 145 | 145 |
| 146 // Strict mode functions and builtins need to replace the receiver | 146 // Strict mode functions and builtins need to replace the receiver |
| 147 // with undefined when called as functions (without an explicit | 147 // with undefined when called as functions (without an explicit |
| 148 // receiver object). r5 is zero for method calls and non-zero for | 148 // receiver object). r5 is zero for method calls and non-zero for |
| 149 // function calls. | 149 // function calls. |
| 150 if (!info->is_classic_mode() || info->is_native()) { | 150 if (!info->is_classic_mode() || info->is_native()) { |
| 151 Label ok; | |
| 152 __ cmp(r5, Operand::Zero()); | 151 __ cmp(r5, Operand::Zero()); |
| 153 __ b(eq, &ok); | |
| 154 int receiver_offset = info->scope()->num_parameters() * kPointerSize; | 152 int receiver_offset = info->scope()->num_parameters() * kPointerSize; |
| 155 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); | 153 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
| 156 __ str(r2, MemOperand(sp, receiver_offset)); | 154 __ str(r2, MemOperand(sp, receiver_offset), ne); |
| 157 __ bind(&ok); | |
| 158 } | 155 } |
| 159 | 156 |
| 160 // Open a frame scope to indicate that there is a frame on the stack. The | 157 // Open a frame scope to indicate that there is a frame on the stack. The |
| 161 // MANUAL indicates that the scope shouldn't actually generate code to set up | 158 // MANUAL indicates that the scope shouldn't actually generate code to set up |
| 162 // the frame (that is done below). | 159 // the frame (that is done below). |
| 163 FrameScope frame_scope(masm_, StackFrame::MANUAL); | 160 FrameScope frame_scope(masm_, StackFrame::MANUAL); |
| 164 | 161 |
| 165 info->set_prologue_offset(masm_->pc_offset()); | 162 info->set_prologue_offset(masm_->pc_offset()); |
| 166 __ Prologue(BUILD_FUNCTION_FRAME); | 163 __ Prologue(BUILD_FUNCTION_FRAME); |
| 167 info->AddNoFrameRange(0, masm_->pc_offset()); | 164 info->AddNoFrameRange(0, masm_->pc_offset()); |
| 168 | 165 |
| 169 { Comment cmnt(masm_, "[ Allocate locals"); | 166 { Comment cmnt(masm_, "[ Allocate locals"); |
| 170 int locals_count = info->scope()->num_stack_slots(); | 167 int locals_count = info->scope()->num_stack_slots(); |
| 171 // Generators allocate locals, if any, in context slots. | 168 // Generators allocate locals, if any, in context slots. |
| 172 ASSERT(!info->function()->is_generator() || locals_count == 0); | 169 ASSERT(!info->function()->is_generator() || locals_count == 0); |
| 173 if (locals_count > 0) { | 170 if (locals_count > 0) { |
| 174 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 171 // Emit a loop to initialize stack cells for locals when optimizing for |
| 175 for (int i = 0; i < locals_count; i++) { | 172 // size. Otherwise, unroll the loop for maximum performance. |
| 176 __ push(ip); | 173 __ LoadRoot(r9, Heap::kUndefinedValueRootIndex); |
| 174 if (FLAG_optimize_for_size && locals_count > 4) { |
| 175 Label loop; |
| 176 __ mov(r2, Operand(locals_count)); |
| 177 __ bind(&loop); |
| 178 __ sub(r2, r2, Operand(1), SetCC); |
| 179 __ push(r9); |
| 180 __ b(&loop, ne); |
| 181 } else { |
| 182 for (int i = 0; i < locals_count; i++) { |
| 183 __ push(r9); |
| 184 } |
| 177 } | 185 } |
| 178 } | 186 } |
| 179 } | 187 } |
| 180 | 188 |
| 181 bool function_in_register = true; | 189 bool function_in_register = true; |
| 182 | 190 |
| 183 // Possibly allocate a local context. | 191 // Possibly allocate a local context. |
| 184 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 192 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 185 if (heap_slots > 0) { | 193 if (heap_slots > 0) { |
| 186 // Argument to NewContext is the function, which is still in r1. | 194 // Argument to NewContext is the function, which is still in r1. |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 609 __ bind(&done); | 617 __ bind(&done); |
| 610 } | 618 } |
| 611 | 619 |
| 612 | 620 |
| 613 void FullCodeGenerator::StackValueContext::Plug( | 621 void FullCodeGenerator::StackValueContext::Plug( |
| 614 Label* materialize_true, | 622 Label* materialize_true, |
| 615 Label* materialize_false) const { | 623 Label* materialize_false) const { |
| 616 Label done; | 624 Label done; |
| 617 __ bind(materialize_true); | 625 __ bind(materialize_true); |
| 618 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 626 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 619 __ push(ip); | |
| 620 __ jmp(&done); | 627 __ jmp(&done); |
| 621 __ bind(materialize_false); | 628 __ bind(materialize_false); |
| 622 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 629 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| 630 __ bind(&done); |
| 623 __ push(ip); | 631 __ push(ip); |
| 624 __ bind(&done); | |
| 625 } | 632 } |
| 626 | 633 |
| 627 | 634 |
| 628 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, | 635 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, |
| 629 Label* materialize_false) const { | 636 Label* materialize_false) const { |
| 630 ASSERT(materialize_true == true_label_); | 637 ASSERT(materialize_true == true_label_); |
| 631 ASSERT(materialize_false == false_label_); | 638 ASSERT(materialize_false == false_label_); |
| 632 } | 639 } |
| 633 | 640 |
| 634 | 641 |
| (...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1151 __ jmp(&exit); | 1158 __ jmp(&exit); |
| 1152 | 1159 |
| 1153 // We got a fixed array in register r0. Iterate through that. | 1160 // We got a fixed array in register r0. Iterate through that. |
| 1154 Label non_proxy; | 1161 Label non_proxy; |
| 1155 __ bind(&fixed_array); | 1162 __ bind(&fixed_array); |
| 1156 | 1163 |
| 1157 Handle<Cell> cell = isolate()->factory()->NewCell( | 1164 Handle<Cell> cell = isolate()->factory()->NewCell( |
| 1158 Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), | 1165 Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), |
| 1159 isolate())); | 1166 isolate())); |
| 1160 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); | 1167 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); |
| 1161 __ LoadHeapObject(r1, cell); | 1168 __ Move(r1, cell); |
| 1162 __ mov(r2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); | 1169 __ mov(r2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); |
| 1163 __ str(r2, FieldMemOperand(r1, Cell::kValueOffset)); | 1170 __ str(r2, FieldMemOperand(r1, Cell::kValueOffset)); |
| 1164 | 1171 |
| 1165 __ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check | 1172 __ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check |
| 1166 __ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object | 1173 __ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object |
| 1167 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 1174 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 1168 __ CompareObjectType(r2, r3, r3, LAST_JS_PROXY_TYPE); | 1175 __ CompareObjectType(r2, r3, r3, LAST_JS_PROXY_TYPE); |
| 1169 __ b(gt, &non_proxy); | 1176 __ b(gt, &non_proxy); |
| 1170 __ mov(r1, Operand(Smi::FromInt(0))); // Zero indicates proxy | 1177 __ mov(r1, Operand(Smi::FromInt(0))); // Zero indicates proxy |
| 1171 __ bind(&non_proxy); | 1178 __ bind(&non_proxy); |
| (...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1593 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 1600 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 1594 __ mov(r5, r0); | 1601 __ mov(r5, r0); |
| 1595 | 1602 |
| 1596 __ bind(&materialized); | 1603 __ bind(&materialized); |
| 1597 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; | 1604 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; |
| 1598 Label allocated, runtime_allocate; | 1605 Label allocated, runtime_allocate; |
| 1599 __ Allocate(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT); | 1606 __ Allocate(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT); |
| 1600 __ jmp(&allocated); | 1607 __ jmp(&allocated); |
| 1601 | 1608 |
| 1602 __ bind(&runtime_allocate); | 1609 __ bind(&runtime_allocate); |
| 1603 __ push(r5); | |
| 1604 __ mov(r0, Operand(Smi::FromInt(size))); | 1610 __ mov(r0, Operand(Smi::FromInt(size))); |
| 1605 __ push(r0); | 1611 __ Push(r5, r0); |
| 1606 __ CallRuntime(Runtime::kAllocateInNewSpace, 1); | 1612 __ CallRuntime(Runtime::kAllocateInNewSpace, 1); |
| 1607 __ pop(r5); | 1613 __ pop(r5); |
| 1608 | 1614 |
| 1609 __ bind(&allocated); | 1615 __ bind(&allocated); |
| 1610 // After this, registers are used as follows: | 1616 // After this, registers are used as follows: |
| 1611 // r0: Newly allocated regexp. | 1617 // r0: Newly allocated regexp. |
| 1612 // r5: Materialized regexp. | 1618 // r5: Materialized regexp. |
| 1613 // r2: temp. | 1619 // r2: temp. |
| 1614 __ CopyFields(r0, r5, d0, size / kPointerSize); | 1620 __ CopyFields(r0, r5, d0, size / kPointerSize); |
| 1615 context()->Plug(r0); | 1621 context()->Plug(r0); |
| 1616 } | 1622 } |
| 1617 | 1623 |
| 1618 | 1624 |
| 1619 void FullCodeGenerator::EmitAccessor(Expression* expression) { | 1625 void FullCodeGenerator::EmitAccessor(Expression* expression) { |
| 1620 if (expression == NULL) { | 1626 if (expression == NULL) { |
| 1621 __ LoadRoot(r1, Heap::kNullValueRootIndex); | 1627 __ LoadRoot(r1, Heap::kNullValueRootIndex); |
| 1622 __ push(r1); | 1628 __ push(r1); |
| 1623 } else { | 1629 } else { |
| 1624 VisitForStackValue(expression); | 1630 VisitForStackValue(expression); |
| 1625 } | 1631 } |
| 1626 } | 1632 } |
| 1627 | 1633 |
| 1628 | 1634 |
| 1629 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 1635 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
| 1630 Comment cmnt(masm_, "[ ObjectLiteral"); | 1636 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 1637 |
| 1638 int depth = 1; |
| 1639 expr->BuildConstantProperties(isolate(), &depth); |
| 1631 Handle<FixedArray> constant_properties = expr->constant_properties(); | 1640 Handle<FixedArray> constant_properties = expr->constant_properties(); |
| 1632 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 1641 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1633 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); | 1642 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); |
| 1634 __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); | 1643 __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); |
| 1635 __ mov(r1, Operand(constant_properties)); | 1644 __ mov(r1, Operand(constant_properties)); |
| 1636 int flags = expr->fast_elements() | 1645 int flags = expr->fast_elements() |
| 1637 ? ObjectLiteral::kFastElements | 1646 ? ObjectLiteral::kFastElements |
| 1638 : ObjectLiteral::kNoFlags; | 1647 : ObjectLiteral::kNoFlags; |
| 1639 flags |= expr->has_function() | 1648 flags |= expr->has_function() |
| 1640 ? ObjectLiteral::kHasFunction | 1649 ? ObjectLiteral::kHasFunction |
| 1641 : ObjectLiteral::kNoFlags; | 1650 : ObjectLiteral::kNoFlags; |
| 1642 __ mov(r0, Operand(Smi::FromInt(flags))); | 1651 __ mov(r0, Operand(Smi::FromInt(flags))); |
| 1643 int properties_count = constant_properties->length() / 2; | 1652 int properties_count = constant_properties->length() / 2; |
| 1644 if ((FLAG_track_double_fields && expr->may_store_doubles()) || | 1653 if ((FLAG_track_double_fields && expr->may_store_doubles()) || |
| 1645 expr->depth() > 1 || Serializer::enabled() || | 1654 depth > 1 || Serializer::enabled() || |
| 1646 flags != ObjectLiteral::kFastElements || | 1655 flags != ObjectLiteral::kFastElements || |
| 1647 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { | 1656 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { |
| 1648 __ Push(r3, r2, r1, r0); | 1657 __ Push(r3, r2, r1, r0); |
| 1649 __ CallRuntime(Runtime::kCreateObjectLiteral, 4); | 1658 __ CallRuntime(Runtime::kCreateObjectLiteral, 4); |
| 1650 } else { | 1659 } else { |
| 1651 FastCloneShallowObjectStub stub(properties_count); | 1660 FastCloneShallowObjectStub stub(properties_count); |
| 1652 __ CallStub(&stub); | 1661 __ CallStub(&stub); |
| 1653 } | 1662 } |
| 1654 | 1663 |
| 1655 // If result_saved is true the result is on top of the stack. If | 1664 // If result_saved is true the result is on top of the stack. If |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1754 context()->PlugTOS(); | 1763 context()->PlugTOS(); |
| 1755 } else { | 1764 } else { |
| 1756 context()->Plug(r0); | 1765 context()->Plug(r0); |
| 1757 } | 1766 } |
| 1758 } | 1767 } |
| 1759 | 1768 |
| 1760 | 1769 |
| 1761 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 1770 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 1762 Comment cmnt(masm_, "[ ArrayLiteral"); | 1771 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 1763 | 1772 |
| 1773 int depth = 1; |
| 1774 expr->BuildConstantElements(isolate(), &depth); |
| 1764 ZoneList<Expression*>* subexprs = expr->values(); | 1775 ZoneList<Expression*>* subexprs = expr->values(); |
| 1765 int length = subexprs->length(); | 1776 int length = subexprs->length(); |
| 1766 Handle<FixedArray> constant_elements = expr->constant_elements(); | 1777 Handle<FixedArray> constant_elements = expr->constant_elements(); |
| 1767 ASSERT_EQ(2, constant_elements->length()); | 1778 ASSERT_EQ(2, constant_elements->length()); |
| 1768 ElementsKind constant_elements_kind = | 1779 ElementsKind constant_elements_kind = |
| 1769 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); | 1780 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); |
| 1770 bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind); | 1781 bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind); |
| 1771 Handle<FixedArrayBase> constant_elements_values( | 1782 Handle<FixedArrayBase> constant_elements_values( |
| 1772 FixedArrayBase::cast(constant_elements->get(1))); | 1783 FixedArrayBase::cast(constant_elements->get(1))); |
| 1773 | 1784 |
| 1774 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 1785 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1775 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); | 1786 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); |
| 1776 __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); | 1787 __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); |
| 1777 __ mov(r1, Operand(constant_elements)); | 1788 __ mov(r1, Operand(constant_elements)); |
| 1778 if (has_fast_elements && constant_elements_values->map() == | 1789 if (has_fast_elements && constant_elements_values->map() == |
| 1779 isolate()->heap()->fixed_cow_array_map()) { | 1790 isolate()->heap()->fixed_cow_array_map()) { |
| 1780 FastCloneShallowArrayStub stub( | 1791 FastCloneShallowArrayStub stub( |
| 1781 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, | 1792 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, |
| 1782 DONT_TRACK_ALLOCATION_SITE, | 1793 DONT_TRACK_ALLOCATION_SITE, |
| 1783 length); | 1794 length); |
| 1784 __ CallStub(&stub); | 1795 __ CallStub(&stub); |
| 1785 __ IncrementCounter( | 1796 __ IncrementCounter( |
| 1786 isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2); | 1797 isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2); |
| 1787 } else if (expr->depth() > 1) { | 1798 } else if (depth > 1 || Serializer::enabled() || |
| 1799 length > FastCloneShallowArrayStub::kMaximumClonedLength) { |
| 1788 __ Push(r3, r2, r1); | 1800 __ Push(r3, r2, r1); |
| 1789 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); | 1801 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); |
| 1790 } else if (Serializer::enabled() || | |
| 1791 length > FastCloneShallowArrayStub::kMaximumClonedLength) { | |
| 1792 __ Push(r3, r2, r1); | |
| 1793 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | |
| 1794 } else { | 1802 } else { |
| 1795 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) || | 1803 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) || |
| 1796 FLAG_smi_only_arrays); | 1804 FLAG_smi_only_arrays); |
| 1797 FastCloneShallowArrayStub::Mode mode = | 1805 FastCloneShallowArrayStub::Mode mode = |
| 1798 FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS; | 1806 FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS; |
| 1799 AllocationSiteMode allocation_site_mode = FLAG_track_allocation_sites | 1807 AllocationSiteMode allocation_site_mode = FLAG_track_allocation_sites |
| 1800 ? TRACK_ALLOCATION_SITE : DONT_TRACK_ALLOCATION_SITE; | 1808 ? TRACK_ALLOCATION_SITE : DONT_TRACK_ALLOCATION_SITE; |
| 1801 | 1809 |
| 1802 if (has_fast_elements) { | 1810 if (has_fast_elements) { |
| 1803 mode = FastCloneShallowArrayStub::CLONE_ELEMENTS; | 1811 mode = FastCloneShallowArrayStub::CLONE_ELEMENTS; |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2032 Label l_next, l_call, l_loop; | 2040 Label l_next, l_call, l_loop; |
| 2033 // Initial send value is undefined. | 2041 // Initial send value is undefined. |
| 2034 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 2042 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| 2035 __ b(&l_next); | 2043 __ b(&l_next); |
| 2036 | 2044 |
| 2037 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } | 2045 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } |
| 2038 __ bind(&l_catch); | 2046 __ bind(&l_catch); |
| 2039 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); | 2047 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); |
| 2040 __ LoadRoot(r2, Heap::kthrow_stringRootIndex); // "throw" | 2048 __ LoadRoot(r2, Heap::kthrow_stringRootIndex); // "throw" |
| 2041 __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter | 2049 __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter |
| 2042 __ push(r3); // iter | 2050 __ Push(r3, r0); // iter, exception |
| 2043 __ push(r0); // exception | |
| 2044 __ jmp(&l_call); | 2051 __ jmp(&l_call); |
| 2045 | 2052 |
| 2046 // try { received = %yield result } | 2053 // try { received = %yield result } |
| 2047 // Shuffle the received result above a try handler and yield it without | 2054 // Shuffle the received result above a try handler and yield it without |
| 2048 // re-boxing. | 2055 // re-boxing. |
| 2049 __ bind(&l_try); | 2056 __ bind(&l_try); |
| 2050 __ pop(r0); // result | 2057 __ pop(r0); // result |
| 2051 __ PushTryHandler(StackHandler::CATCH, expr->index()); | 2058 __ PushTryHandler(StackHandler::CATCH, expr->index()); |
| 2052 const int handler_size = StackHandlerConstants::kSize; | 2059 const int handler_size = StackHandlerConstants::kSize; |
| 2053 __ push(r0); // result | 2060 __ push(r0); // result |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2069 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2076 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2070 __ pop(r0); // result | 2077 __ pop(r0); // result |
| 2071 EmitReturnSequence(); | 2078 EmitReturnSequence(); |
| 2072 __ bind(&l_resume); // received in r0 | 2079 __ bind(&l_resume); // received in r0 |
| 2073 __ PopTryHandler(); | 2080 __ PopTryHandler(); |
| 2074 | 2081 |
| 2075 // receiver = iter; f = 'next'; arg = received; | 2082 // receiver = iter; f = 'next'; arg = received; |
| 2076 __ bind(&l_next); | 2083 __ bind(&l_next); |
| 2077 __ LoadRoot(r2, Heap::knext_stringRootIndex); // "next" | 2084 __ LoadRoot(r2, Heap::knext_stringRootIndex); // "next" |
| 2078 __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter | 2085 __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter |
| 2079 __ push(r3); // iter | 2086 __ Push(r3, r0); // iter, received |
| 2080 __ push(r0); // received | |
| 2081 | 2087 |
| 2082 // result = receiver[f](arg); | 2088 // result = receiver[f](arg); |
| 2083 __ bind(&l_call); | 2089 __ bind(&l_call); |
| 2084 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); | 2090 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); |
| 2085 CallIC(ic); | 2091 CallIC(ic); |
| 2086 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2092 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2087 | 2093 |
| 2088 // if (!result.done) goto l_try; | 2094 // if (!result.done) goto l_try; |
| 2089 __ bind(&l_loop); | 2095 __ bind(&l_loop); |
| 2090 __ push(r0); // save result | 2096 __ push(r0); // save result |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2146 __ push(r2); | 2152 __ push(r2); |
| 2147 __ jmp(&push_argument_holes); | 2153 __ jmp(&push_argument_holes); |
| 2148 | 2154 |
| 2149 // Enter a new JavaScript frame, and initialize its slots as they were when | 2155 // Enter a new JavaScript frame, and initialize its slots as they were when |
| 2150 // the generator was suspended. | 2156 // the generator was suspended. |
| 2151 Label resume_frame; | 2157 Label resume_frame; |
| 2152 __ bind(&push_frame); | 2158 __ bind(&push_frame); |
| 2153 __ bl(&resume_frame); | 2159 __ bl(&resume_frame); |
| 2154 __ jmp(&done); | 2160 __ jmp(&done); |
| 2155 __ bind(&resume_frame); | 2161 __ bind(&resume_frame); |
| 2156 __ push(lr); // Return address. | 2162 // lr = return address. |
| 2157 __ push(fp); // Caller's frame pointer. | 2163 // fp = caller's frame pointer. |
| 2158 __ mov(fp, sp); | 2164 // cp = callee's context, |
| 2159 __ push(cp); // Callee's context. | 2165 // r4 = callee's JS function. |
| 2160 __ push(r4); // Callee's JS Function. | 2166 __ Push(lr, fp, cp, r4); |
| 2167 // Adjust FP to point to saved FP. |
| 2168 __ add(fp, sp, Operand(2 * kPointerSize)); |
| 2161 | 2169 |
| 2162 // Load the operand stack size. | 2170 // Load the operand stack size. |
| 2163 __ ldr(r3, FieldMemOperand(r1, JSGeneratorObject::kOperandStackOffset)); | 2171 __ ldr(r3, FieldMemOperand(r1, JSGeneratorObject::kOperandStackOffset)); |
| 2164 __ ldr(r3, FieldMemOperand(r3, FixedArray::kLengthOffset)); | 2172 __ ldr(r3, FieldMemOperand(r3, FixedArray::kLengthOffset)); |
| 2165 __ SmiUntag(r3); | 2173 __ SmiUntag(r3); |
| 2166 | 2174 |
| 2167 // If we are sending a value and there is no operand stack, we can jump back | 2175 // If we are sending a value and there is no operand stack, we can jump back |
| 2168 // in directly. | 2176 // in directly. |
| 2169 if (resume_mode == JSGeneratorObject::NEXT) { | 2177 if (resume_mode == JSGeneratorObject::NEXT) { |
| 2170 Label slow_resume; | 2178 Label slow_resume; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2182 | 2190 |
| 2183 // Otherwise, we push holes for the operand stack and call the runtime to fix | 2191 // Otherwise, we push holes for the operand stack and call the runtime to fix |
| 2184 // up the stack and the handlers. | 2192 // up the stack and the handlers. |
| 2185 Label push_operand_holes, call_resume; | 2193 Label push_operand_holes, call_resume; |
| 2186 __ bind(&push_operand_holes); | 2194 __ bind(&push_operand_holes); |
| 2187 __ sub(r3, r3, Operand(1), SetCC); | 2195 __ sub(r3, r3, Operand(1), SetCC); |
| 2188 __ b(mi, &call_resume); | 2196 __ b(mi, &call_resume); |
| 2189 __ push(r2); | 2197 __ push(r2); |
| 2190 __ b(&push_operand_holes); | 2198 __ b(&push_operand_holes); |
| 2191 __ bind(&call_resume); | 2199 __ bind(&call_resume); |
| 2192 __ push(r1); | 2200 ASSERT(!result_register().is(r1)); |
| 2193 __ push(result_register()); | 2201 __ Push(r1, result_register()); |
| 2194 __ Push(Smi::FromInt(resume_mode)); | 2202 __ Push(Smi::FromInt(resume_mode)); |
| 2195 __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3); | 2203 __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3); |
| 2196 // Not reached: the runtime call returns elsewhere. | 2204 // Not reached: the runtime call returns elsewhere. |
| 2197 __ stop("not-reached"); | 2205 __ stop("not-reached"); |
| 2198 | 2206 |
| 2199 // Throw error if we attempt to operate on a running generator. | 2207 // Throw error if we attempt to operate on a running generator. |
| 2200 __ bind(&wrong_state); | 2208 __ bind(&wrong_state); |
| 2201 __ push(r1); | 2209 __ push(r1); |
| 2202 __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); | 2210 __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); |
| 2203 | 2211 |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2405 ? isolate()->builtins()->StoreIC_Initialize() | 2413 ? isolate()->builtins()->StoreIC_Initialize() |
| 2406 : isolate()->builtins()->StoreIC_Initialize_Strict(); | 2414 : isolate()->builtins()->StoreIC_Initialize_Strict(); |
| 2407 CallIC(ic); | 2415 CallIC(ic); |
| 2408 break; | 2416 break; |
| 2409 } | 2417 } |
| 2410 case KEYED_PROPERTY: { | 2418 case KEYED_PROPERTY: { |
| 2411 __ push(r0); // Preserve value. | 2419 __ push(r0); // Preserve value. |
| 2412 VisitForStackValue(prop->obj()); | 2420 VisitForStackValue(prop->obj()); |
| 2413 VisitForAccumulatorValue(prop->key()); | 2421 VisitForAccumulatorValue(prop->key()); |
| 2414 __ mov(r1, r0); | 2422 __ mov(r1, r0); |
| 2415 __ pop(r2); | 2423 __ Pop(r0, r2); // r0 = restored value. |
| 2416 __ pop(r0); // Restore value. | |
| 2417 Handle<Code> ic = is_classic_mode() | 2424 Handle<Code> ic = is_classic_mode() |
| 2418 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2425 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2419 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2426 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2420 CallIC(ic); | 2427 CallIC(ic); |
| 2421 break; | 2428 break; |
| 2422 } | 2429 } |
| 2423 } | 2430 } |
| 2424 context()->Plug(r0); | 2431 context()->Plug(r0); |
| 2425 } | 2432 } |
| 2426 | 2433 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2540 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2547 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2541 context()->Plug(r0); | 2548 context()->Plug(r0); |
| 2542 } | 2549 } |
| 2543 | 2550 |
| 2544 | 2551 |
| 2545 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2552 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 2546 // Assignment to a property, using a keyed store IC. | 2553 // Assignment to a property, using a keyed store IC. |
| 2547 | 2554 |
| 2548 // Record source code position before IC call. | 2555 // Record source code position before IC call. |
| 2549 SetSourcePosition(expr->position()); | 2556 SetSourcePosition(expr->position()); |
| 2550 __ pop(r1); // Key. | 2557 __ Pop(r2, r1); // r1 = key. |
| 2551 __ pop(r2); | |
| 2552 | 2558 |
| 2553 Handle<Code> ic = is_classic_mode() | 2559 Handle<Code> ic = is_classic_mode() |
| 2554 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2560 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2555 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2561 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2556 CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); | 2562 CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); |
| 2557 | 2563 |
| 2558 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2564 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2559 context()->Plug(r0); | 2565 context()->Plug(r0); |
| 2560 } | 2566 } |
| 2561 | 2567 |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2670 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); | 2676 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 2671 __ CallStub(&stub, expr->CallFeedbackId()); | 2677 __ CallStub(&stub, expr->CallFeedbackId()); |
| 2672 RecordJSReturnSite(expr); | 2678 RecordJSReturnSite(expr); |
| 2673 // Restore context register. | 2679 // Restore context register. |
| 2674 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2680 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2675 context()->DropAndPlug(1, r0); | 2681 context()->DropAndPlug(1, r0); |
| 2676 } | 2682 } |
| 2677 | 2683 |
| 2678 | 2684 |
| 2679 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { | 2685 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { |
| 2680 // Push copy of the first argument or undefined if it doesn't exist. | 2686 // r4: copy of the first argument or undefined if it doesn't exist. |
| 2681 if (arg_count > 0) { | 2687 if (arg_count > 0) { |
| 2682 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize)); | 2688 __ ldr(r4, MemOperand(sp, arg_count * kPointerSize)); |
| 2683 } else { | 2689 } else { |
| 2684 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); | 2690 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); |
| 2685 } | 2691 } |
| 2686 __ push(r1); | |
| 2687 | 2692 |
| 2688 // Push the receiver of the enclosing function. | 2693 // r3: the receiver of the enclosing function. |
| 2689 int receiver_offset = 2 + info_->scope()->num_parameters(); | 2694 int receiver_offset = 2 + info_->scope()->num_parameters(); |
| 2690 __ ldr(r1, MemOperand(fp, receiver_offset * kPointerSize)); | 2695 __ ldr(r3, MemOperand(fp, receiver_offset * kPointerSize)); |
| 2691 __ push(r1); | |
| 2692 // Push the language mode. | |
| 2693 __ mov(r1, Operand(Smi::FromInt(language_mode()))); | |
| 2694 __ push(r1); | |
| 2695 | 2696 |
| 2696 // Push the start position of the scope the calls resides in. | 2697 // r2: the language mode. |
| 2698 __ mov(r2, Operand(Smi::FromInt(language_mode()))); |
| 2699 |
| 2700 // r1: the start position of the scope the calls resides in. |
| 2697 __ mov(r1, Operand(Smi::FromInt(scope()->start_position()))); | 2701 __ mov(r1, Operand(Smi::FromInt(scope()->start_position()))); |
| 2698 __ push(r1); | |
| 2699 | 2702 |
| 2700 // Do the runtime call. | 2703 // Do the runtime call. |
| 2704 __ Push(r4, r3, r2, r1); |
| 2701 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); | 2705 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); |
| 2702 } | 2706 } |
| 2703 | 2707 |
| 2704 | 2708 |
| 2705 void FullCodeGenerator::VisitCall(Call* expr) { | 2709 void FullCodeGenerator::VisitCall(Call* expr) { |
| 2706 #ifdef DEBUG | 2710 #ifdef DEBUG |
| 2707 // We want to verify that RecordJSReturnSite gets called on all paths | 2711 // We want to verify that RecordJSReturnSite gets called on all paths |
| 2708 // through this function. Avoid early returns. | 2712 // through this function. Avoid early returns. |
| 2709 expr->return_is_recorded_ = false; | 2713 expr->return_is_recorded_ = false; |
| 2710 #endif | 2714 #endif |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2764 | 2768 |
| 2765 { PreservePositionScope scope(masm()->positions_recorder()); | 2769 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2766 // Generate code for loading from variables potentially shadowed | 2770 // Generate code for loading from variables potentially shadowed |
| 2767 // by eval-introduced variables. | 2771 // by eval-introduced variables. |
| 2768 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); | 2772 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); |
| 2769 } | 2773 } |
| 2770 | 2774 |
| 2771 __ bind(&slow); | 2775 __ bind(&slow); |
| 2772 // Call the runtime to find the function to call (returned in r0) | 2776 // Call the runtime to find the function to call (returned in r0) |
| 2773 // and the object holding it (returned in edx). | 2777 // and the object holding it (returned in edx). |
| 2774 __ push(context_register()); | 2778 ASSERT(!context_register().is(r2)); |
| 2775 __ mov(r2, Operand(proxy->name())); | 2779 __ mov(r2, Operand(proxy->name())); |
| 2776 __ push(r2); | 2780 __ Push(context_register(), r2); |
| 2777 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2781 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2778 __ Push(r0, r1); // Function, receiver. | 2782 __ Push(r0, r1); // Function, receiver. |
| 2779 | 2783 |
| 2780 // If fast case code has been generated, emit code to push the | 2784 // If fast case code has been generated, emit code to push the |
| 2781 // function and receiver and have the slow path jump around this | 2785 // function and receiver and have the slow path jump around this |
| 2782 // code. | 2786 // code. |
| 2783 if (done.is_linked()) { | 2787 if (done.is_linked()) { |
| 2784 Label call; | 2788 Label call; |
| 2785 __ b(&call); | 2789 __ b(&call); |
| 2786 __ bind(&done); | 2790 __ bind(&done); |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3093 | 3097 |
| 3094 __ JumpIfSmi(r0, if_false); | 3098 __ JumpIfSmi(r0, if_false); |
| 3095 __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE); | 3099 __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE); |
| 3096 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 3100 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 3097 Split(eq, if_true, if_false, fall_through); | 3101 Split(eq, if_true, if_false, fall_through); |
| 3098 | 3102 |
| 3099 context()->Plug(if_true, if_false); | 3103 context()->Plug(if_true, if_false); |
| 3100 } | 3104 } |
| 3101 | 3105 |
| 3102 | 3106 |
| 3107 void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) { |
| 3108 ZoneList<Expression*>* args = expr->arguments(); |
| 3109 ASSERT(args->length() == 1); |
| 3110 |
| 3111 VisitForAccumulatorValue(args->at(0)); |
| 3112 |
| 3113 Label materialize_true, materialize_false; |
| 3114 Label* if_true = NULL; |
| 3115 Label* if_false = NULL; |
| 3116 Label* fall_through = NULL; |
| 3117 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3118 &if_true, &if_false, &fall_through); |
| 3119 |
| 3120 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, if_false, DO_SMI_CHECK); |
| 3121 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
| 3122 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); |
| 3123 __ cmp(r2, Operand(0x80000000)); |
| 3124 __ cmp(r1, Operand(0x00000000), eq); |
| 3125 |
| 3126 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 3127 Split(eq, if_true, if_false, fall_through); |
| 3128 |
| 3129 context()->Plug(if_true, if_false); |
| 3130 } |
| 3131 |
| 3132 |
| 3103 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { | 3133 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { |
| 3104 ZoneList<Expression*>* args = expr->arguments(); | 3134 ZoneList<Expression*>* args = expr->arguments(); |
| 3105 ASSERT(args->length() == 1); | 3135 ASSERT(args->length() == 1); |
| 3106 | 3136 |
| 3107 VisitForAccumulatorValue(args->at(0)); | 3137 VisitForAccumulatorValue(args->at(0)); |
| 3108 | 3138 |
| 3109 Label materialize_true, materialize_false; | 3139 Label materialize_true, materialize_false; |
| 3110 Label* if_true = NULL; | 3140 Label* if_true = NULL; |
| 3111 Label* if_false = NULL; | 3141 Label* if_false = NULL; |
| 3112 Label* fall_through = NULL; | 3142 Label* fall_through = NULL; |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3483 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { | 3513 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { |
| 3484 ZoneList<Expression*>* args = expr->arguments(); | 3514 ZoneList<Expression*>* args = expr->arguments(); |
| 3485 ASSERT_EQ(3, args->length()); | 3515 ASSERT_EQ(3, args->length()); |
| 3486 | 3516 |
| 3487 Register string = r0; | 3517 Register string = r0; |
| 3488 Register index = r1; | 3518 Register index = r1; |
| 3489 Register value = r2; | 3519 Register value = r2; |
| 3490 | 3520 |
| 3491 VisitForStackValue(args->at(1)); // index | 3521 VisitForStackValue(args->at(1)); // index |
| 3492 VisitForStackValue(args->at(2)); // value | 3522 VisitForStackValue(args->at(2)); // value |
| 3493 __ pop(value); | 3523 __ Pop(index, value); |
| 3494 __ pop(index); | |
| 3495 VisitForAccumulatorValue(args->at(0)); // string | 3524 VisitForAccumulatorValue(args->at(0)); // string |
| 3496 | 3525 |
| 3497 if (FLAG_debug_code) { | 3526 if (FLAG_debug_code) { |
| 3498 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; | 3527 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
| 3499 EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); | 3528 EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); |
| 3500 } | 3529 } |
| 3501 | 3530 |
| 3502 __ SmiUntag(value, value); | 3531 __ SmiUntag(value, value); |
| 3503 __ add(ip, | 3532 __ add(ip, |
| 3504 string, | 3533 string, |
| 3505 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 3534 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 3506 __ strb(value, MemOperand(ip, index, LSR, kSmiTagSize)); | 3535 __ strb(value, MemOperand(ip, index, LSR, kSmiTagSize)); |
| 3507 context()->Plug(string); | 3536 context()->Plug(string); |
| 3508 } | 3537 } |
| 3509 | 3538 |
| 3510 | 3539 |
| 3511 void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) { | 3540 void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) { |
| 3512 ZoneList<Expression*>* args = expr->arguments(); | 3541 ZoneList<Expression*>* args = expr->arguments(); |
| 3513 ASSERT_EQ(3, args->length()); | 3542 ASSERT_EQ(3, args->length()); |
| 3514 | 3543 |
| 3515 Register string = r0; | 3544 Register string = r0; |
| 3516 Register index = r1; | 3545 Register index = r1; |
| 3517 Register value = r2; | 3546 Register value = r2; |
| 3518 | 3547 |
| 3519 VisitForStackValue(args->at(1)); // index | 3548 VisitForStackValue(args->at(1)); // index |
| 3520 VisitForStackValue(args->at(2)); // value | 3549 VisitForStackValue(args->at(2)); // value |
| 3521 __ pop(value); | 3550 __ Pop(index, value); |
| 3522 __ pop(index); | |
| 3523 VisitForAccumulatorValue(args->at(0)); // string | 3551 VisitForAccumulatorValue(args->at(0)); // string |
| 3524 | 3552 |
| 3525 if (FLAG_debug_code) { | 3553 if (FLAG_debug_code) { |
| 3526 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; | 3554 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
| 3527 EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); | 3555 EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); |
| 3528 } | 3556 } |
| 3529 | 3557 |
| 3530 __ SmiUntag(value, value); | 3558 __ SmiUntag(value, value); |
| 3531 __ add(ip, | 3559 __ add(ip, |
| 3532 string, | 3560 string, |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3696 generator.GenerateSlow(masm_, call_helper); | 3724 generator.GenerateSlow(masm_, call_helper); |
| 3697 | 3725 |
| 3698 __ bind(&done); | 3726 __ bind(&done); |
| 3699 context()->Plug(result); | 3727 context()->Plug(result); |
| 3700 } | 3728 } |
| 3701 | 3729 |
| 3702 | 3730 |
| 3703 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { | 3731 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { |
| 3704 ZoneList<Expression*>* args = expr->arguments(); | 3732 ZoneList<Expression*>* args = expr->arguments(); |
| 3705 ASSERT_EQ(2, args->length()); | 3733 ASSERT_EQ(2, args->length()); |
| 3706 VisitForStackValue(args->at(0)); | |
| 3707 VisitForStackValue(args->at(1)); | |
| 3708 | 3734 |
| 3709 StringAddStub stub(STRING_ADD_CHECK_BOTH); | 3735 if (FLAG_new_string_add) { |
| 3710 __ CallStub(&stub); | 3736 VisitForStackValue(args->at(0)); |
| 3737 VisitForAccumulatorValue(args->at(1)); |
| 3738 |
| 3739 __ pop(r1); |
| 3740 NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); |
| 3741 __ CallStub(&stub); |
| 3742 } else { |
| 3743 VisitForStackValue(args->at(0)); |
| 3744 VisitForStackValue(args->at(1)); |
| 3745 |
| 3746 StringAddStub stub(STRING_ADD_CHECK_BOTH); |
| 3747 __ CallStub(&stub); |
| 3748 } |
| 3711 context()->Plug(r0); | 3749 context()->Plug(r0); |
| 3712 } | 3750 } |
| 3713 | 3751 |
| 3714 | 3752 |
| 3715 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { | 3753 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { |
| 3716 ZoneList<Expression*>* args = expr->arguments(); | 3754 ZoneList<Expression*>* args = expr->arguments(); |
| 3717 ASSERT_EQ(2, args->length()); | 3755 ASSERT_EQ(2, args->length()); |
| 3718 VisitForStackValue(args->at(0)); | 3756 VisitForStackValue(args->at(0)); |
| 3719 VisitForStackValue(args->at(1)); | 3757 VisitForStackValue(args->at(1)); |
| 3720 | 3758 |
| 3721 StringCompareStub stub; | 3759 StringCompareStub stub; |
| 3722 __ CallStub(&stub); | 3760 __ CallStub(&stub); |
| 3723 context()->Plug(r0); | 3761 context()->Plug(r0); |
| 3724 } | 3762 } |
| 3725 | 3763 |
| 3726 | 3764 |
| 3727 void FullCodeGenerator::EmitMathSin(CallRuntime* expr) { | |
| 3728 // Load the argument on the stack and call the stub. | |
| 3729 TranscendentalCacheStub stub(TranscendentalCache::SIN, | |
| 3730 TranscendentalCacheStub::TAGGED); | |
| 3731 ZoneList<Expression*>* args = expr->arguments(); | |
| 3732 ASSERT(args->length() == 1); | |
| 3733 VisitForStackValue(args->at(0)); | |
| 3734 __ CallStub(&stub); | |
| 3735 context()->Plug(r0); | |
| 3736 } | |
| 3737 | |
| 3738 | |
| 3739 void FullCodeGenerator::EmitMathCos(CallRuntime* expr) { | |
| 3740 // Load the argument on the stack and call the stub. | |
| 3741 TranscendentalCacheStub stub(TranscendentalCache::COS, | |
| 3742 TranscendentalCacheStub::TAGGED); | |
| 3743 ZoneList<Expression*>* args = expr->arguments(); | |
| 3744 ASSERT(args->length() == 1); | |
| 3745 VisitForStackValue(args->at(0)); | |
| 3746 __ CallStub(&stub); | |
| 3747 context()->Plug(r0); | |
| 3748 } | |
| 3749 | |
| 3750 | |
| 3751 void FullCodeGenerator::EmitMathTan(CallRuntime* expr) { | |
| 3752 // Load the argument on the stack and call the stub. | |
| 3753 TranscendentalCacheStub stub(TranscendentalCache::TAN, | |
| 3754 TranscendentalCacheStub::TAGGED); | |
| 3755 ZoneList<Expression*>* args = expr->arguments(); | |
| 3756 ASSERT(args->length() == 1); | |
| 3757 VisitForStackValue(args->at(0)); | |
| 3758 __ CallStub(&stub); | |
| 3759 context()->Plug(r0); | |
| 3760 } | |
| 3761 | |
| 3762 | |
| 3763 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) { | 3765 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) { |
| 3764 // Load the argument on the stack and call the stub. | 3766 // Load the argument on the stack and call the stub. |
| 3765 TranscendentalCacheStub stub(TranscendentalCache::LOG, | 3767 TranscendentalCacheStub stub(TranscendentalCache::LOG, |
| 3766 TranscendentalCacheStub::TAGGED); | 3768 TranscendentalCacheStub::TAGGED); |
| 3767 ZoneList<Expression*>* args = expr->arguments(); | 3769 ZoneList<Expression*>* args = expr->arguments(); |
| 3768 ASSERT(args->length() == 1); | 3770 ASSERT(args->length() == 1); |
| 3769 VisitForStackValue(args->at(0)); | 3771 VisitForStackValue(args->at(0)); |
| 3770 __ CallStub(&stub); | 3772 __ CallStub(&stub); |
| 3771 context()->Plug(r0); | 3773 context()->Plug(r0); |
| 3772 } | 3774 } |
| (...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4256 __ Push(r2, r1, r0); | 4258 __ Push(r2, r1, r0); |
| 4257 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 4259 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 4258 context()->Plug(r0); | 4260 context()->Plug(r0); |
| 4259 } else if (var->IsStackAllocated() || var->IsContextSlot()) { | 4261 } else if (var->IsStackAllocated() || var->IsContextSlot()) { |
| 4260 // Result of deleting non-global, non-dynamic variables is false. | 4262 // Result of deleting non-global, non-dynamic variables is false. |
| 4261 // The subexpression does not have side effects. | 4263 // The subexpression does not have side effects. |
| 4262 context()->Plug(var->is_this()); | 4264 context()->Plug(var->is_this()); |
| 4263 } else { | 4265 } else { |
| 4264 // Non-global variable. Call the runtime to try to delete from the | 4266 // Non-global variable. Call the runtime to try to delete from the |
| 4265 // context where the variable was introduced. | 4267 // context where the variable was introduced. |
| 4266 __ push(context_register()); | 4268 ASSERT(!context_register().is(r2)); |
| 4267 __ mov(r2, Operand(var->name())); | 4269 __ mov(r2, Operand(var->name())); |
| 4268 __ push(r2); | 4270 __ Push(context_register(), r2); |
| 4269 __ CallRuntime(Runtime::kDeleteContextSlot, 2); | 4271 __ CallRuntime(Runtime::kDeleteContextSlot, 2); |
| 4270 context()->Plug(r0); | 4272 context()->Plug(r0); |
| 4271 } | 4273 } |
| 4272 } else { | 4274 } else { |
| 4273 // Result of deleting non-property, non-variable reference is true. | 4275 // Result of deleting non-property, non-variable reference is true. |
| 4274 // The subexpression may have side effects. | 4276 // The subexpression may have side effects. |
| 4275 VisitForEffect(expr->expression()); | 4277 VisitForEffect(expr->expression()); |
| 4276 context()->Plug(true); | 4278 context()->Plug(true); |
| 4277 } | 4279 } |
| 4278 break; | 4280 break; |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4389 } | 4391 } |
| 4390 | 4392 |
| 4391 // We need a second deoptimization point after loading the value | 4393 // We need a second deoptimization point after loading the value |
| 4392 // in case evaluating the property load my have a side effect. | 4394 // in case evaluating the property load my have a side effect. |
| 4393 if (assign_type == VARIABLE) { | 4395 if (assign_type == VARIABLE) { |
| 4394 PrepareForBailout(expr->expression(), TOS_REG); | 4396 PrepareForBailout(expr->expression(), TOS_REG); |
| 4395 } else { | 4397 } else { |
| 4396 PrepareForBailoutForId(prop->LoadId(), TOS_REG); | 4398 PrepareForBailoutForId(prop->LoadId(), TOS_REG); |
| 4397 } | 4399 } |
| 4398 | 4400 |
| 4399 // Call ToNumber only if operand is not a smi. | 4401 // Inline smi case if we are in a loop. |
| 4400 Label no_conversion; | 4402 Label stub_call, done; |
| 4403 JumpPatchSite patch_site(masm_); |
| 4404 |
| 4405 int count_value = expr->op() == Token::INC ? 1 : -1; |
| 4401 if (ShouldInlineSmiCase(expr->op())) { | 4406 if (ShouldInlineSmiCase(expr->op())) { |
| 4402 __ JumpIfSmi(r0, &no_conversion); | 4407 Label slow; |
| 4408 patch_site.EmitJumpIfNotSmi(r0, &slow); |
| 4409 |
| 4410 // Save result for postfix expressions. |
| 4411 if (expr->is_postfix()) { |
| 4412 if (!context()->IsEffect()) { |
| 4413 // Save the result on the stack. If we have a named or keyed property |
| 4414 // we store the result under the receiver that is currently on top |
| 4415 // of the stack. |
| 4416 switch (assign_type) { |
| 4417 case VARIABLE: |
| 4418 __ push(r0); |
| 4419 break; |
| 4420 case NAMED_PROPERTY: |
| 4421 __ str(r0, MemOperand(sp, kPointerSize)); |
| 4422 break; |
| 4423 case KEYED_PROPERTY: |
| 4424 __ str(r0, MemOperand(sp, 2 * kPointerSize)); |
| 4425 break; |
| 4426 } |
| 4427 } |
| 4428 } |
| 4429 |
| 4430 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC); |
| 4431 __ b(vc, &done); |
| 4432 // Call stub. Undo operation first. |
| 4433 __ sub(r0, r0, Operand(Smi::FromInt(count_value))); |
| 4434 __ jmp(&stub_call); |
| 4435 __ bind(&slow); |
| 4403 } | 4436 } |
| 4404 ToNumberStub convert_stub; | 4437 ToNumberStub convert_stub; |
| 4405 __ CallStub(&convert_stub); | 4438 __ CallStub(&convert_stub); |
| 4406 __ bind(&no_conversion); | |
| 4407 | 4439 |
| 4408 // Save result for postfix expressions. | 4440 // Save result for postfix expressions. |
| 4409 if (expr->is_postfix()) { | 4441 if (expr->is_postfix()) { |
| 4410 if (!context()->IsEffect()) { | 4442 if (!context()->IsEffect()) { |
| 4411 // Save the result on the stack. If we have a named or keyed property | 4443 // Save the result on the stack. If we have a named or keyed property |
| 4412 // we store the result under the receiver that is currently on top | 4444 // we store the result under the receiver that is currently on top |
| 4413 // of the stack. | 4445 // of the stack. |
| 4414 switch (assign_type) { | 4446 switch (assign_type) { |
| 4415 case VARIABLE: | 4447 case VARIABLE: |
| 4416 __ push(r0); | 4448 __ push(r0); |
| 4417 break; | 4449 break; |
| 4418 case NAMED_PROPERTY: | 4450 case NAMED_PROPERTY: |
| 4419 __ str(r0, MemOperand(sp, kPointerSize)); | 4451 __ str(r0, MemOperand(sp, kPointerSize)); |
| 4420 break; | 4452 break; |
| 4421 case KEYED_PROPERTY: | 4453 case KEYED_PROPERTY: |
| 4422 __ str(r0, MemOperand(sp, 2 * kPointerSize)); | 4454 __ str(r0, MemOperand(sp, 2 * kPointerSize)); |
| 4423 break; | 4455 break; |
| 4424 } | 4456 } |
| 4425 } | 4457 } |
| 4426 } | 4458 } |
| 4427 | 4459 |
| 4428 | 4460 |
| 4429 // Inline smi case if we are in a loop. | 4461 __ bind(&stub_call); |
| 4430 Label stub_call, done; | |
| 4431 JumpPatchSite patch_site(masm_); | |
| 4432 | |
| 4433 int count_value = expr->op() == Token::INC ? 1 : -1; | |
| 4434 if (ShouldInlineSmiCase(expr->op())) { | |
| 4435 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC); | |
| 4436 __ b(vs, &stub_call); | |
| 4437 // We could eliminate this smi check if we split the code at | |
| 4438 // the first smi check before calling ToNumber. | |
| 4439 patch_site.EmitJumpIfSmi(r0, &done); | |
| 4440 | |
| 4441 __ bind(&stub_call); | |
| 4442 // Call stub. Undo operation first. | |
| 4443 __ sub(r0, r0, Operand(Smi::FromInt(count_value))); | |
| 4444 } | |
| 4445 __ mov(r1, r0); | 4462 __ mov(r1, r0); |
| 4446 __ mov(r0, Operand(Smi::FromInt(count_value))); | 4463 __ mov(r0, Operand(Smi::FromInt(count_value))); |
| 4447 | 4464 |
| 4448 // Record position before stub call. | 4465 // Record position before stub call. |
| 4449 SetSourcePosition(expr->position()); | 4466 SetSourcePosition(expr->position()); |
| 4450 | 4467 |
| 4451 BinaryOpStub stub(Token::ADD, NO_OVERWRITE); | 4468 BinaryOpStub stub(Token::ADD, NO_OVERWRITE); |
| 4452 CallIC(stub.GetCode(isolate()), | 4469 CallIC(stub.GetCode(isolate()), |
| 4453 RelocInfo::CODE_TARGET, | 4470 RelocInfo::CODE_TARGET, |
| 4454 expr->CountBinOpFeedbackId()); | 4471 expr->CountBinOpFeedbackId()); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4488 if (expr->is_postfix()) { | 4505 if (expr->is_postfix()) { |
| 4489 if (!context()->IsEffect()) { | 4506 if (!context()->IsEffect()) { |
| 4490 context()->PlugTOS(); | 4507 context()->PlugTOS(); |
| 4491 } | 4508 } |
| 4492 } else { | 4509 } else { |
| 4493 context()->Plug(r0); | 4510 context()->Plug(r0); |
| 4494 } | 4511 } |
| 4495 break; | 4512 break; |
| 4496 } | 4513 } |
| 4497 case KEYED_PROPERTY: { | 4514 case KEYED_PROPERTY: { |
| 4498 __ pop(r1); // Key. | 4515 __ Pop(r2, r1); // r1 = key. r2 = receiver. |
| 4499 __ pop(r2); // Receiver. | |
| 4500 Handle<Code> ic = is_classic_mode() | 4516 Handle<Code> ic = is_classic_mode() |
| 4501 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4517 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 4502 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4518 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 4503 CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId()); | 4519 CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId()); |
| 4504 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4520 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4505 if (expr->is_postfix()) { | 4521 if (expr->is_postfix()) { |
| 4506 if (!context()->IsEffect()) { | 4522 if (!context()->IsEffect()) { |
| 4507 context()->PlugTOS(); | 4523 context()->PlugTOS(); |
| 4508 } | 4524 } |
| 4509 } else { | 4525 } else { |
| (...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4962 ASSERT(Memory::uint32_at(interrupt_address_pointer) == | 4978 ASSERT(Memory::uint32_at(interrupt_address_pointer) == |
| 4963 reinterpret_cast<uint32_t>( | 4979 reinterpret_cast<uint32_t>( |
| 4964 isolate->builtins()->OsrAfterStackCheck()->entry())); | 4980 isolate->builtins()->OsrAfterStackCheck()->entry())); |
| 4965 return OSR_AFTER_STACK_CHECK; | 4981 return OSR_AFTER_STACK_CHECK; |
| 4966 } | 4982 } |
| 4967 | 4983 |
| 4968 | 4984 |
| 4969 } } // namespace v8::internal | 4985 } } // namespace v8::internal |
| 4970 | 4986 |
| 4971 #endif // V8_TARGET_ARCH_ARM | 4987 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |