OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 133 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
134 frame_->SpillAll(); | 134 frame_->SpillAll(); |
135 __ int3(); | 135 __ int3(); |
136 } | 136 } |
137 #endif | 137 #endif |
138 | 138 |
139 // Allocate space for locals and initialize them. | 139 // Allocate space for locals and initialize them. |
140 frame_->AllocateStackSlots(scope_->num_stack_slots()); | 140 frame_->AllocateStackSlots(scope_->num_stack_slots()); |
141 // Initialize the function return target after the locals are set | 141 // Initialize the function return target after the locals are set |
142 // up, because it needs the expected frame height from the frame. | 142 // up, because it needs the expected frame height from the frame. |
143 function_return_.Initialize(this, JumpTarget::BIDIRECTIONAL); | 143 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); |
144 function_return_is_shadowed_ = false; | 144 function_return_is_shadowed_ = false; |
145 | 145 |
146 // Allocate the arguments object and copy the parameters into it. | 146 // Allocate the arguments object and copy the parameters into it. |
147 if (scope_->arguments() != NULL) { | 147 if (scope_->arguments() != NULL) { |
148 ASSERT(scope_->arguments_shadow() != NULL); | 148 ASSERT(scope_->arguments_shadow() != NULL); |
149 Comment cmnt(masm_, "[ Allocate arguments object"); | 149 Comment cmnt(masm_, "[ Allocate arguments object"); |
150 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 150 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
151 frame_->PushFunction(); | 151 frame_->PushFunction(); |
152 frame_->PushReceiverSlotAddress(); | 152 frame_->PushReceiverSlotAddress(); |
153 frame_->Push(Smi::FromInt(scope_->num_parameters())); | 153 frame_->Push(Smi::FromInt(scope_->num_parameters())); |
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 frame_->SpillAll(); | 460 frame_->SpillAll(); |
461 set_in_spilled_code(true); | 461 set_in_spilled_code(true); |
462 } | 462 } |
463 | 463 |
464 | 464 |
465 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 465 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
466 #ifdef DEBUG | 466 #ifdef DEBUG |
467 int original_height = frame_->height(); | 467 int original_height = frame_->height(); |
468 #endif | 468 #endif |
469 ASSERT(!in_spilled_code()); | 469 ASSERT(!in_spilled_code()); |
470 JumpTarget true_target(this); | 470 JumpTarget true_target; |
471 JumpTarget false_target(this); | 471 JumpTarget false_target; |
472 ControlDestination dest(&true_target, &false_target, true); | 472 ControlDestination dest(&true_target, &false_target, true); |
473 LoadCondition(x, typeof_state, &dest, false); | 473 LoadCondition(x, typeof_state, &dest, false); |
474 | 474 |
475 if (dest.false_was_fall_through()) { | 475 if (dest.false_was_fall_through()) { |
476 // The false target was just bound. | 476 // The false target was just bound. |
477 JumpTarget loaded(this); | 477 JumpTarget loaded; |
478 frame_->Push(Factory::false_value()); | 478 frame_->Push(Factory::false_value()); |
479 // There may be dangling jumps to the true target. | 479 // There may be dangling jumps to the true target. |
480 if (true_target.is_linked()) { | 480 if (true_target.is_linked()) { |
481 loaded.Jump(); | 481 loaded.Jump(); |
482 true_target.Bind(); | 482 true_target.Bind(); |
483 frame_->Push(Factory::true_value()); | 483 frame_->Push(Factory::true_value()); |
484 loaded.Bind(); | 484 loaded.Bind(); |
485 } | 485 } |
486 | 486 |
487 } else if (dest.is_used()) { | 487 } else if (dest.is_used()) { |
488 // There is true, and possibly false, control flow (with true as | 488 // There is true, and possibly false, control flow (with true as |
489 // the fall through). | 489 // the fall through). |
490 JumpTarget loaded(this); | 490 JumpTarget loaded; |
491 frame_->Push(Factory::true_value()); | 491 frame_->Push(Factory::true_value()); |
492 if (false_target.is_linked()) { | 492 if (false_target.is_linked()) { |
493 loaded.Jump(); | 493 loaded.Jump(); |
494 false_target.Bind(); | 494 false_target.Bind(); |
495 frame_->Push(Factory::false_value()); | 495 frame_->Push(Factory::false_value()); |
496 loaded.Bind(); | 496 loaded.Bind(); |
497 } | 497 } |
498 | 498 |
499 } else { | 499 } else { |
500 // We have a valid value on top of the frame, but we still may | 500 // We have a valid value on top of the frame, but we still may |
501 // have dangling jumps to the true and false targets from nested | 501 // have dangling jumps to the true and false targets from nested |
502 // subexpressions (eg, the left subexpressions of the | 502 // subexpressions (eg, the left subexpressions of the |
503 // short-circuited boolean operators). | 503 // short-circuited boolean operators). |
504 ASSERT(has_valid_frame()); | 504 ASSERT(has_valid_frame()); |
505 if (true_target.is_linked() || false_target.is_linked()) { | 505 if (true_target.is_linked() || false_target.is_linked()) { |
506 JumpTarget loaded(this); | 506 JumpTarget loaded; |
507 loaded.Jump(); // Don't lose the current TOS. | 507 loaded.Jump(); // Don't lose the current TOS. |
508 if (true_target.is_linked()) { | 508 if (true_target.is_linked()) { |
509 true_target.Bind(); | 509 true_target.Bind(); |
510 frame_->Push(Factory::true_value()); | 510 frame_->Push(Factory::true_value()); |
511 if (false_target.is_linked()) { | 511 if (false_target.is_linked()) { |
512 loaded.Jump(); | 512 loaded.Jump(); |
513 } | 513 } |
514 } | 514 } |
515 if (false_target.is_linked()) { | 515 if (false_target.is_linked()) { |
516 false_target.Bind(); | 516 false_target.Bind(); |
(...skipping 1016 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1533 left_side = right_side; | 1533 left_side = right_side; |
1534 right_side = temp; | 1534 right_side = temp; |
1535 cc = ReverseCondition(cc); | 1535 cc = ReverseCondition(cc); |
1536 // This may reintroduce greater or less_equal as the value of cc. | 1536 // This may reintroduce greater or less_equal as the value of cc. |
1537 // CompareStub and the inline code both support all values of cc. | 1537 // CompareStub and the inline code both support all values of cc. |
1538 } | 1538 } |
1539 // Implement comparison against a constant Smi, inlining the case | 1539 // Implement comparison against a constant Smi, inlining the case |
1540 // where both sides are Smis. | 1540 // where both sides are Smis. |
1541 left_side.ToRegister(); | 1541 left_side.ToRegister(); |
1542 ASSERT(left_side.is_valid()); | 1542 ASSERT(left_side.is_valid()); |
1543 JumpTarget is_smi(this); | 1543 JumpTarget is_smi; |
1544 __ test(left_side.reg(), Immediate(kSmiTagMask)); | 1544 __ test(left_side.reg(), Immediate(kSmiTagMask)); |
1545 is_smi.Branch(zero, &left_side, &right_side, taken); | 1545 is_smi.Branch(zero, &left_side, &right_side, taken); |
1546 | 1546 |
1547 // Setup and call the compare stub, which expects its arguments | 1547 // Setup and call the compare stub, which expects its arguments |
1548 // in registers. | 1548 // in registers. |
1549 CompareStub stub(cc, strict); | 1549 CompareStub stub(cc, strict); |
1550 Result result = frame_->CallStub(&stub, &left_side, &right_side); | 1550 Result result = frame_->CallStub(&stub, &left_side, &right_side); |
1551 result.ToRegister(); | 1551 result.ToRegister(); |
1552 __ cmp(result.reg(), 0); | 1552 __ cmp(result.reg(), 0); |
1553 result.Unuse(); | 1553 result.Unuse(); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1604 operand.Unuse(); | 1604 operand.Unuse(); |
1605 dest->Split(not_zero); | 1605 dest->Split(not_zero); |
1606 } | 1606 } |
1607 } else { // Neither side is a constant Smi or null. | 1607 } else { // Neither side is a constant Smi or null. |
1608 // If either side is a non-smi constant, skip the smi check. | 1608 // If either side is a non-smi constant, skip the smi check. |
1609 bool known_non_smi = | 1609 bool known_non_smi = |
1610 (left_side.is_constant() && !left_side.handle()->IsSmi()) || | 1610 (left_side.is_constant() && !left_side.handle()->IsSmi()) || |
1611 (right_side.is_constant() && !right_side.handle()->IsSmi()); | 1611 (right_side.is_constant() && !right_side.handle()->IsSmi()); |
1612 left_side.ToRegister(); | 1612 left_side.ToRegister(); |
1613 right_side.ToRegister(); | 1613 right_side.ToRegister(); |
1614 JumpTarget is_smi(this); | 1614 JumpTarget is_smi; |
1615 if (!known_non_smi) { | 1615 if (!known_non_smi) { |
1616 // Check for the smi case. | 1616 // Check for the smi case. |
1617 Result temp = allocator_->Allocate(); | 1617 Result temp = allocator_->Allocate(); |
1618 ASSERT(temp.is_valid()); | 1618 ASSERT(temp.is_valid()); |
1619 __ mov(temp.reg(), left_side.reg()); | 1619 __ mov(temp.reg(), left_side.reg()); |
1620 __ or_(temp.reg(), Operand(right_side.reg())); | 1620 __ or_(temp.reg(), Operand(right_side.reg())); |
1621 __ test(temp.reg(), Immediate(kSmiTagMask)); | 1621 __ test(temp.reg(), Immediate(kSmiTagMask)); |
1622 temp.Unuse(); | 1622 temp.Unuse(); |
1623 is_smi.Branch(zero, &left_side, &right_side, taken); | 1623 is_smi.Branch(zero, &left_side, &right_side, taken); |
1624 } | 1624 } |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1749 for (int i = 0; has_valid_frame() && i < statements->length(); i++) { | 1749 for (int i = 0; has_valid_frame() && i < statements->length(); i++) { |
1750 Visit(statements->at(i)); | 1750 Visit(statements->at(i)); |
1751 } | 1751 } |
1752 } | 1752 } |
1753 | 1753 |
1754 | 1754 |
1755 void CodeGenerator::VisitBlock(Block* node) { | 1755 void CodeGenerator::VisitBlock(Block* node) { |
1756 ASSERT(!in_spilled_code()); | 1756 ASSERT(!in_spilled_code()); |
1757 Comment cmnt(masm_, "[ Block"); | 1757 Comment cmnt(masm_, "[ Block"); |
1758 CodeForStatementPosition(node); | 1758 CodeForStatementPosition(node); |
1759 node->break_target()->Initialize(this); | 1759 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
1760 VisitStatements(node->statements()); | 1760 VisitStatements(node->statements()); |
1761 if (node->break_target()->is_linked()) { | 1761 if (node->break_target()->is_linked()) { |
1762 node->break_target()->Bind(); | 1762 node->break_target()->Bind(); |
1763 } | 1763 } |
1764 node->break_target()->Unuse(); | 1764 node->break_target()->Unuse(); |
1765 } | 1765 } |
1766 | 1766 |
1767 | 1767 |
1768 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1768 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
1769 frame_->Push(pairs); | 1769 frame_->Push(pairs); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1863 | 1863 |
1864 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1864 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
1865 ASSERT(!in_spilled_code()); | 1865 ASSERT(!in_spilled_code()); |
1866 Comment cmnt(masm_, "[ IfStatement"); | 1866 Comment cmnt(masm_, "[ IfStatement"); |
1867 // Generate different code depending on which parts of the if statement | 1867 // Generate different code depending on which parts of the if statement |
1868 // are present or not. | 1868 // are present or not. |
1869 bool has_then_stm = node->HasThenStatement(); | 1869 bool has_then_stm = node->HasThenStatement(); |
1870 bool has_else_stm = node->HasElseStatement(); | 1870 bool has_else_stm = node->HasElseStatement(); |
1871 | 1871 |
1872 CodeForStatementPosition(node); | 1872 CodeForStatementPosition(node); |
1873 JumpTarget exit(this); | 1873 JumpTarget exit; |
1874 if (has_then_stm && has_else_stm) { | 1874 if (has_then_stm && has_else_stm) { |
1875 JumpTarget then(this); | 1875 JumpTarget then; |
1876 JumpTarget else_(this); | 1876 JumpTarget else_; |
1877 ControlDestination dest(&then, &else_, true); | 1877 ControlDestination dest(&then, &else_, true); |
1878 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 1878 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); |
1879 | 1879 |
1880 if (dest.false_was_fall_through()) { | 1880 if (dest.false_was_fall_through()) { |
1881 // The else target was bound, so we compile the else part first. | 1881 // The else target was bound, so we compile the else part first. |
1882 Visit(node->else_statement()); | 1882 Visit(node->else_statement()); |
1883 | 1883 |
1884 // We may have dangling jumps to the then part. | 1884 // We may have dangling jumps to the then part. |
1885 if (then.is_linked()) { | 1885 if (then.is_linked()) { |
1886 if (has_valid_frame()) exit.Jump(); | 1886 if (has_valid_frame()) exit.Jump(); |
1887 then.Bind(); | 1887 then.Bind(); |
1888 Visit(node->then_statement()); | 1888 Visit(node->then_statement()); |
1889 } | 1889 } |
1890 } else { | 1890 } else { |
1891 // The then target was bound, so we compile the then part first. | 1891 // The then target was bound, so we compile the then part first. |
1892 Visit(node->then_statement()); | 1892 Visit(node->then_statement()); |
1893 | 1893 |
1894 if (else_.is_linked()) { | 1894 if (else_.is_linked()) { |
1895 if (has_valid_frame()) exit.Jump(); | 1895 if (has_valid_frame()) exit.Jump(); |
1896 else_.Bind(); | 1896 else_.Bind(); |
1897 Visit(node->else_statement()); | 1897 Visit(node->else_statement()); |
1898 } | 1898 } |
1899 } | 1899 } |
1900 | 1900 |
1901 } else if (has_then_stm) { | 1901 } else if (has_then_stm) { |
1902 ASSERT(!has_else_stm); | 1902 ASSERT(!has_else_stm); |
1903 JumpTarget then(this); | 1903 JumpTarget then; |
1904 ControlDestination dest(&then, &exit, true); | 1904 ControlDestination dest(&then, &exit, true); |
1905 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 1905 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); |
1906 | 1906 |
1907 if (dest.false_was_fall_through()) { | 1907 if (dest.false_was_fall_through()) { |
1908 // The exit label was bound. We may have dangling jumps to the | 1908 // The exit label was bound. We may have dangling jumps to the |
1909 // then part. | 1909 // then part. |
1910 if (then.is_linked()) { | 1910 if (then.is_linked()) { |
1911 exit.Unuse(); | 1911 exit.Unuse(); |
1912 exit.Jump(); | 1912 exit.Jump(); |
1913 then.Bind(); | 1913 then.Bind(); |
1914 Visit(node->then_statement()); | 1914 Visit(node->then_statement()); |
1915 } | 1915 } |
1916 } else { | 1916 } else { |
1917 // The then label was bound. | 1917 // The then label was bound. |
1918 Visit(node->then_statement()); | 1918 Visit(node->then_statement()); |
1919 } | 1919 } |
1920 | 1920 |
1921 } else if (has_else_stm) { | 1921 } else if (has_else_stm) { |
1922 ASSERT(!has_then_stm); | 1922 ASSERT(!has_then_stm); |
1923 JumpTarget else_(this); | 1923 JumpTarget else_; |
1924 ControlDestination dest(&exit, &else_, false); | 1924 ControlDestination dest(&exit, &else_, false); |
1925 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 1925 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); |
1926 | 1926 |
1927 if (dest.true_was_fall_through()) { | 1927 if (dest.true_was_fall_through()) { |
1928 // The exit label was bound. We may have dangling jumps to the | 1928 // The exit label was bound. We may have dangling jumps to the |
1929 // else part. | 1929 // else part. |
1930 if (else_.is_linked()) { | 1930 if (else_.is_linked()) { |
1931 exit.Unuse(); | 1931 exit.Unuse(); |
1932 exit.Jump(); | 1932 exit.Jump(); |
1933 else_.Bind(); | 1933 else_.Bind(); |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2080 Vector<Label*> case_targets, | 2080 Vector<Label*> case_targets, |
2081 Vector<Label> case_labels) { | 2081 Vector<Label> case_labels) { |
2082 // Notice: Internal references, used by both the jmp instruction and | 2082 // Notice: Internal references, used by both the jmp instruction and |
2083 // the table entries, need to be relocated if the buffer grows. This | 2083 // the table entries, need to be relocated if the buffer grows. This |
2084 // prevents the forward use of Labels, since a displacement cannot | 2084 // prevents the forward use of Labels, since a displacement cannot |
2085 // survive relocation, and it also cannot safely be distinguished | 2085 // survive relocation, and it also cannot safely be distinguished |
2086 // from a real address. Instead we put in zero-values as | 2086 // from a real address. Instead we put in zero-values as |
2087 // placeholders, and fill in the addresses after the labels have been | 2087 // placeholders, and fill in the addresses after the labels have been |
2088 // bound. | 2088 // bound. |
2089 | 2089 |
2090 JumpTarget setup_default(this); | 2090 JumpTarget setup_default; |
2091 JumpTarget is_smi(this); | 2091 JumpTarget is_smi; |
2092 | 2092 |
2093 // A non-null default label pointer indicates a default case among | 2093 // A non-null default label pointer indicates a default case among |
2094 // the case labels. Otherwise we use the break target as a | 2094 // the case labels. Otherwise we use the break target as a |
2095 // "default". | 2095 // "default". |
2096 JumpTarget* default_target = | 2096 JumpTarget* default_target = |
2097 (default_label == NULL) ? node->break_target() : &setup_default; | 2097 (default_label == NULL) ? node->break_target() : &setup_default; |
2098 | 2098 |
2099 // Test whether input is a smi. | 2099 // Test whether input is a smi. |
2100 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 2100 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
2101 Result switch_value = frame_->Pop(); | 2101 Result switch_value = frame_->Pop(); |
(...skipping 24 matching lines...) Expand all Loading... |
2126 __ test(smi_value.reg(), Immediate(0x80000000 | kSmiTagMask)); | 2126 __ test(smi_value.reg(), Immediate(0x80000000 | kSmiTagMask)); |
2127 default_target->Branch(not_equal, not_taken); | 2127 default_target->Branch(not_equal, not_taken); |
2128 __ cmp(smi_value.reg(), range << kSmiTagSize); | 2128 __ cmp(smi_value.reg(), range << kSmiTagSize); |
2129 default_target->Branch(greater_equal, not_taken); | 2129 default_target->Branch(greater_equal, not_taken); |
2130 | 2130 |
2131 // The expected frame at all the case labels is a version of the | 2131 // The expected frame at all the case labels is a version of the |
2132 // current one (the bidirectional entry frame, which an arbitrary | 2132 // current one (the bidirectional entry frame, which an arbitrary |
2133 // frame of the correct height can be merged to). Keep a copy to | 2133 // frame of the correct height can be merged to). Keep a copy to |
2134 // restore at the start of every label. Create a jump target and | 2134 // restore at the start of every label. Create a jump target and |
2135 // bind it to set its entry frame properly. | 2135 // bind it to set its entry frame properly. |
2136 JumpTarget entry_target(this, JumpTarget::BIDIRECTIONAL); | 2136 JumpTarget entry_target(JumpTarget::BIDIRECTIONAL); |
2137 entry_target.Bind(&smi_value); | 2137 entry_target.Bind(&smi_value); |
2138 VirtualFrame* start_frame = new VirtualFrame(frame_); | 2138 VirtualFrame* start_frame = new VirtualFrame(frame_); |
2139 | 2139 |
2140 // 0 is placeholder. | 2140 // 0 is placeholder. |
2141 // Jump to the address at table_address + 2 * smi_value.reg(). | 2141 // Jump to the address at table_address + 2 * smi_value.reg(). |
2142 // The target of the jump is read from table_address + 4 * switch_value. | 2142 // The target of the jump is read from table_address + 4 * switch_value. |
2143 // The Smi encoding of smi_value.reg() is 2 * switch_value. | 2143 // The Smi encoding of smi_value.reg() is 2 * switch_value. |
2144 smi_value.ToRegister(); | 2144 smi_value.ToRegister(); |
2145 __ jmp(Operand(smi_value.reg(), smi_value.reg(), | 2145 __ jmp(Operand(smi_value.reg(), smi_value.reg(), |
2146 times_1, 0x0, RelocInfo::INTERNAL_REFERENCE)); | 2146 times_1, 0x0, RelocInfo::INTERNAL_REFERENCE)); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2183 __ WriteInternalReference(entry_pos, *case_targets[i]); | 2183 __ WriteInternalReference(entry_pos, *case_targets[i]); |
2184 } | 2184 } |
2185 } | 2185 } |
2186 } | 2186 } |
2187 | 2187 |
2188 | 2188 |
2189 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 2189 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
2190 ASSERT(!in_spilled_code()); | 2190 ASSERT(!in_spilled_code()); |
2191 Comment cmnt(masm_, "[ SwitchStatement"); | 2191 Comment cmnt(masm_, "[ SwitchStatement"); |
2192 CodeForStatementPosition(node); | 2192 CodeForStatementPosition(node); |
2193 node->break_target()->Initialize(this); | 2193 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2194 | 2194 |
2195 // Compile the switch value. | 2195 // Compile the switch value. |
2196 Load(node->tag()); | 2196 Load(node->tag()); |
2197 | 2197 |
2198 if (TryGenerateFastCaseSwitchStatement(node)) { | 2198 if (TryGenerateFastCaseSwitchStatement(node)) { |
2199 return; | 2199 return; |
2200 } | 2200 } |
2201 | 2201 |
2202 ZoneList<CaseClause*>* cases = node->cases(); | 2202 ZoneList<CaseClause*>* cases = node->cases(); |
2203 int length = cases->length(); | 2203 int length = cases->length(); |
2204 CaseClause* default_clause = NULL; | 2204 CaseClause* default_clause = NULL; |
2205 | 2205 |
2206 JumpTarget next_test(this); | 2206 JumpTarget next_test; |
2207 // Compile the case label expressions and comparisons. Exit early | 2207 // Compile the case label expressions and comparisons. Exit early |
2208 // if a comparison is unconditionally true. The target next_test is | 2208 // if a comparison is unconditionally true. The target next_test is |
2209 // bound before the loop in order to indicate control flow to the | 2209 // bound before the loop in order to indicate control flow to the |
2210 // first comparison. | 2210 // first comparison. |
2211 next_test.Bind(); | 2211 next_test.Bind(); |
2212 for (int i = 0; i < length && !next_test.is_unused(); i++) { | 2212 for (int i = 0; i < length && !next_test.is_unused(); i++) { |
2213 CaseClause* clause = cases->at(i); | 2213 CaseClause* clause = cases->at(i); |
2214 clause->body_target()->Initialize(this); | |
2215 // The default is not a test, but remember it for later. | 2214 // The default is not a test, but remember it for later. |
2216 if (clause->is_default()) { | 2215 if (clause->is_default()) { |
2217 default_clause = clause; | 2216 default_clause = clause; |
2218 continue; | 2217 continue; |
2219 } | 2218 } |
2220 | 2219 |
2221 Comment cmnt(masm_, "[ Case comparison"); | 2220 Comment cmnt(masm_, "[ Case comparison"); |
2222 // We recycle the same target next_test for each test. Bind it if | 2221 // We recycle the same target next_test for each test. Bind it if |
2223 // the previous test has not done so and then unuse it for the | 2222 // the previous test has not done so and then unuse it for the |
2224 // loop. | 2223 // loop. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2275 if (clause->body_target()->is_linked() || has_valid_frame()) { | 2274 if (clause->body_target()->is_linked() || has_valid_frame()) { |
2276 if (clause->body_target()->is_linked()) { | 2275 if (clause->body_target()->is_linked()) { |
2277 if (has_valid_frame()) { | 2276 if (has_valid_frame()) { |
2278 // If we have both a jump to the test and a fall through, put | 2277 // If we have both a jump to the test and a fall through, put |
2279 // a jump on the fall through path to avoid the dropping of | 2278 // a jump on the fall through path to avoid the dropping of |
2280 // the switch value on the test path. The exception is the | 2279 // the switch value on the test path. The exception is the |
2281 // default which has already had the switch value dropped. | 2280 // default which has already had the switch value dropped. |
2282 if (clause->is_default()) { | 2281 if (clause->is_default()) { |
2283 clause->body_target()->Bind(); | 2282 clause->body_target()->Bind(); |
2284 } else { | 2283 } else { |
2285 JumpTarget body(this); | 2284 JumpTarget body; |
2286 body.Jump(); | 2285 body.Jump(); |
2287 clause->body_target()->Bind(); | 2286 clause->body_target()->Bind(); |
2288 frame_->Drop(); | 2287 frame_->Drop(); |
2289 body.Bind(); | 2288 body.Bind(); |
2290 } | 2289 } |
2291 } else { | 2290 } else { |
2292 // No fall through to worry about. | 2291 // No fall through to worry about. |
2293 clause->body_target()->Bind(); | 2292 clause->body_target()->Bind(); |
2294 if (!clause->is_default()) { | 2293 if (!clause->is_default()) { |
2295 frame_->Drop(); | 2294 frame_->Drop(); |
(...skipping 17 matching lines...) Expand all Loading... |
2313 node->break_target()->Bind(); | 2312 node->break_target()->Bind(); |
2314 } | 2313 } |
2315 node->break_target()->Unuse(); | 2314 node->break_target()->Unuse(); |
2316 } | 2315 } |
2317 | 2316 |
2318 | 2317 |
2319 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 2318 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
2320 ASSERT(!in_spilled_code()); | 2319 ASSERT(!in_spilled_code()); |
2321 Comment cmnt(masm_, "[ LoopStatement"); | 2320 Comment cmnt(masm_, "[ LoopStatement"); |
2322 CodeForStatementPosition(node); | 2321 CodeForStatementPosition(node); |
2323 node->break_target()->Initialize(this); | 2322 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2324 | 2323 |
2325 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a | 2324 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
2326 // known result for the test expression, with no side effects. | 2325 // known result for the test expression, with no side effects. |
2327 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 2326 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
2328 if (node->cond() == NULL) { | 2327 if (node->cond() == NULL) { |
2329 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 2328 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
2330 info = ALWAYS_TRUE; | 2329 info = ALWAYS_TRUE; |
2331 } else { | 2330 } else { |
2332 Literal* lit = node->cond()->AsLiteral(); | 2331 Literal* lit = node->cond()->AsLiteral(); |
2333 if (lit != NULL) { | 2332 if (lit != NULL) { |
2334 if (lit->IsTrue()) { | 2333 if (lit->IsTrue()) { |
2335 info = ALWAYS_TRUE; | 2334 info = ALWAYS_TRUE; |
2336 } else if (lit->IsFalse()) { | 2335 } else if (lit->IsFalse()) { |
2337 info = ALWAYS_FALSE; | 2336 info = ALWAYS_FALSE; |
2338 } | 2337 } |
2339 } | 2338 } |
2340 } | 2339 } |
2341 | 2340 |
2342 switch (node->type()) { | 2341 switch (node->type()) { |
2343 case LoopStatement::DO_LOOP: { | 2342 case LoopStatement::DO_LOOP: { |
2344 JumpTarget body(this, JumpTarget::BIDIRECTIONAL); | 2343 JumpTarget body(JumpTarget::BIDIRECTIONAL); |
2345 IncrementLoopNesting(); | 2344 IncrementLoopNesting(); |
2346 | 2345 |
2347 // Label the top of the loop for the backward jump if necessary. | 2346 // Label the top of the loop for the backward jump if necessary. |
2348 if (info == ALWAYS_TRUE) { | 2347 if (info == ALWAYS_TRUE) { |
2349 // Use the continue target. | 2348 // Use the continue target. |
2350 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 2349 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
2351 node->continue_target()->Bind(); | 2350 node->continue_target()->Bind(); |
2352 } else if (info == ALWAYS_FALSE) { | 2351 } else if (info == ALWAYS_FALSE) { |
2353 // No need to label it. | 2352 // No need to label it. |
2354 node->continue_target()->Initialize(this); | 2353 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2355 } else { | 2354 } else { |
2356 // Continue is the test, so use the backward body target. | 2355 // Continue is the test, so use the backward body target. |
2357 ASSERT(info == DONT_KNOW); | 2356 ASSERT(info == DONT_KNOW); |
2358 node->continue_target()->Initialize(this); | 2357 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2359 body.Bind(); | 2358 body.Bind(); |
2360 } | 2359 } |
2361 | 2360 |
2362 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2361 CheckStack(); // TODO(1222600): ignore if body contains calls. |
2363 Visit(node->body()); | 2362 Visit(node->body()); |
2364 | 2363 |
2365 // Compile the test. | 2364 // Compile the test. |
2366 if (info == ALWAYS_TRUE) { | 2365 if (info == ALWAYS_TRUE) { |
2367 // If control flow can fall off the end of the body, jump back | 2366 // If control flow can fall off the end of the body, jump back |
2368 // to the top and bind the break target at the exit. | 2367 // to the top and bind the break target at the exit. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2407 bool test_at_bottom = !node->may_have_function_literal(); | 2406 bool test_at_bottom = !node->may_have_function_literal(); |
2408 | 2407 |
2409 IncrementLoopNesting(); | 2408 IncrementLoopNesting(); |
2410 | 2409 |
2411 // If the condition is always false and has no side effects, we | 2410 // If the condition is always false and has no side effects, we |
2412 // do not need to compile anything. | 2411 // do not need to compile anything. |
2413 if (info == ALWAYS_FALSE) break; | 2412 if (info == ALWAYS_FALSE) break; |
2414 | 2413 |
2415 JumpTarget body; | 2414 JumpTarget body; |
2416 if (test_at_bottom) { | 2415 if (test_at_bottom) { |
2417 body.Initialize(this, JumpTarget::BIDIRECTIONAL); | 2416 body.set_direction(JumpTarget::BIDIRECTIONAL); |
2418 } else { | |
2419 body.Initialize(this); | |
2420 } | 2417 } |
2421 | 2418 |
2422 // Based on the condition analysis, compile the test as necessary. | 2419 // Based on the condition analysis, compile the test as necessary. |
2423 if (info == ALWAYS_TRUE) { | 2420 if (info == ALWAYS_TRUE) { |
2424 // We will not compile the test expression. Label the top of | 2421 // We will not compile the test expression. Label the top of |
2425 // the loop with the continue target. | 2422 // the loop with the continue target. |
2426 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 2423 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
2427 node->continue_target()->Bind(); | 2424 node->continue_target()->Bind(); |
2428 } else { | 2425 } else { |
2429 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. | 2426 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. |
2430 if (test_at_bottom) { | 2427 if (test_at_bottom) { |
2431 // Continue is the test at the bottom, no need to label the | 2428 // Continue is the test at the bottom, no need to label the |
2432 // test at the top. The body is a backward target. | 2429 // test at the top. The body is a backward target. |
2433 node->continue_target()->Initialize(this); | 2430 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2434 } else { | 2431 } else { |
2435 // Label the test at the top as the continue target. The | 2432 // Label the test at the top as the continue target. The |
2436 // body is a forward-only target. | 2433 // body is a forward-only target. |
2437 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 2434 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
2438 node->continue_target()->Bind(); | 2435 node->continue_target()->Bind(); |
2439 } | 2436 } |
2440 // Compile the test with the body as the true target and | 2437 // Compile the test with the body as the true target and |
2441 // preferred fall-through and with the break target as the | 2438 // preferred fall-through and with the break target as the |
2442 // false target. | 2439 // false target. |
2443 ControlDestination dest(&body, node->break_target(), true); | 2440 ControlDestination dest(&body, node->break_target(), true); |
2444 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2441 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
2445 | 2442 |
2446 if (dest.false_was_fall_through()) { | 2443 if (dest.false_was_fall_through()) { |
2447 // If we got the break target as fall-through, the test may | 2444 // If we got the break target as fall-through, the test may |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2510 } | 2507 } |
2511 | 2508 |
2512 IncrementLoopNesting(); | 2509 IncrementLoopNesting(); |
2513 | 2510 |
2514 // If the condition is always false and has no side effects, we | 2511 // If the condition is always false and has no side effects, we |
2515 // do not need to compile anything else. | 2512 // do not need to compile anything else. |
2516 if (info == ALWAYS_FALSE) break; | 2513 if (info == ALWAYS_FALSE) break; |
2517 | 2514 |
2518 // Target for backward edge if no test at the bottom, otherwise | 2515 // Target for backward edge if no test at the bottom, otherwise |
2519 // unused. | 2516 // unused. |
2520 JumpTarget loop(this, JumpTarget::BIDIRECTIONAL); | 2517 JumpTarget loop(JumpTarget::BIDIRECTIONAL); |
2521 | 2518 |
2522 // Target for backward edge if there is a test at the bottom, | 2519 // Target for backward edge if there is a test at the bottom, |
2523 // otherwise used as target for test at the top. | 2520 // otherwise used as target for test at the top. |
2524 JumpTarget body; | 2521 JumpTarget body; |
2525 if (test_at_bottom) { | 2522 if (test_at_bottom) { |
2526 body.Initialize(this, JumpTarget::BIDIRECTIONAL); | 2523 body.set_direction(JumpTarget::BIDIRECTIONAL); |
2527 } else { | |
2528 body.Initialize(this); | |
2529 } | 2524 } |
2530 | 2525 |
2531 // Based on the condition analysis, compile the test as necessary. | 2526 // Based on the condition analysis, compile the test as necessary. |
2532 if (info == ALWAYS_TRUE) { | 2527 if (info == ALWAYS_TRUE) { |
2533 // We will not compile the test expression. Label the top of | 2528 // We will not compile the test expression. Label the top of |
2534 // the loop. | 2529 // the loop. |
2535 if (node->next() == NULL) { | 2530 if (node->next() == NULL) { |
2536 // Use the continue target if there is no update expression. | 2531 // Use the continue target if there is no update expression. |
2537 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 2532 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
2538 node->continue_target()->Bind(); | 2533 node->continue_target()->Bind(); |
2539 } else { | 2534 } else { |
2540 // Otherwise use the backward loop target. | 2535 // Otherwise use the backward loop target. |
2541 node->continue_target()->Initialize(this); | 2536 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2542 loop.Bind(); | 2537 loop.Bind(); |
2543 } | 2538 } |
2544 } else { | 2539 } else { |
2545 ASSERT(info == DONT_KNOW); | 2540 ASSERT(info == DONT_KNOW); |
2546 if (test_at_bottom) { | 2541 if (test_at_bottom) { |
2547 // Continue is either the update expression or the test at | 2542 // Continue is either the update expression or the test at |
2548 // the bottom, no need to label the test at the top. | 2543 // the bottom, no need to label the test at the top. |
2549 node->continue_target()->Initialize(this); | 2544 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2550 } else if (node->next() == NULL) { | 2545 } else if (node->next() == NULL) { |
2551 // We are not recompiling the test at the bottom and there | 2546 // We are not recompiling the test at the bottom and there |
2552 // is no update expression. | 2547 // is no update expression. |
2553 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 2548 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
2554 node->continue_target()->Bind(); | 2549 node->continue_target()->Bind(); |
2555 } else { | 2550 } else { |
2556 // We are not recompiling the test at the bottom and there | 2551 // We are not recompiling the test at the bottom and there |
2557 // is an update expression. | 2552 // is an update expression. |
2558 node->continue_target()->Initialize(this); | 2553 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2559 loop.Bind(); | 2554 loop.Bind(); |
2560 } | 2555 } |
2561 | 2556 |
2562 // Compile the test with the body as the true target and | 2557 // Compile the test with the body as the true target and |
2563 // preferred fall-through and with the break target as the | 2558 // preferred fall-through and with the break target as the |
2564 // false target. | 2559 // false target. |
2565 ControlDestination dest(&body, node->break_target(), true); | 2560 ControlDestination dest(&body, node->break_target(), true); |
2566 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2561 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
2567 | 2562 |
2568 if (dest.false_was_fall_through()) { | 2563 if (dest.false_was_fall_through()) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2652 node->break_target()->Unuse(); | 2647 node->break_target()->Unuse(); |
2653 } | 2648 } |
2654 | 2649 |
2655 | 2650 |
2656 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 2651 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
2657 ASSERT(!in_spilled_code()); | 2652 ASSERT(!in_spilled_code()); |
2658 VirtualFrame::SpilledScope spilled_scope(this); | 2653 VirtualFrame::SpilledScope spilled_scope(this); |
2659 Comment cmnt(masm_, "[ ForInStatement"); | 2654 Comment cmnt(masm_, "[ ForInStatement"); |
2660 CodeForStatementPosition(node); | 2655 CodeForStatementPosition(node); |
2661 | 2656 |
2662 JumpTarget primitive(this); | 2657 JumpTarget primitive; |
2663 JumpTarget jsobject(this); | 2658 JumpTarget jsobject; |
2664 JumpTarget fixed_array(this); | 2659 JumpTarget fixed_array; |
2665 JumpTarget entry(this, JumpTarget::BIDIRECTIONAL); | 2660 JumpTarget entry(JumpTarget::BIDIRECTIONAL); |
2666 JumpTarget end_del_check(this); | 2661 JumpTarget end_del_check; |
2667 JumpTarget exit(this); | 2662 JumpTarget exit; |
2668 | 2663 |
2669 // Get the object to enumerate over (converted to JSObject). | 2664 // Get the object to enumerate over (converted to JSObject). |
2670 LoadAndSpill(node->enumerable()); | 2665 LoadAndSpill(node->enumerable()); |
2671 | 2666 |
2672 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 2667 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
2673 // to the specification. 12.6.4 mandates a call to ToObject. | 2668 // to the specification. 12.6.4 mandates a call to ToObject. |
2674 frame_->EmitPop(eax); | 2669 frame_->EmitPop(eax); |
2675 | 2670 |
2676 // eax: value to be iterated over | 2671 // eax: value to be iterated over |
2677 __ cmp(eax, Factory::undefined_value()); | 2672 __ cmp(eax, Factory::undefined_value()); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2742 // Push the length of the array and the initial index onto the stack. | 2737 // Push the length of the array and the initial index onto the stack. |
2743 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); | 2738 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
2744 __ shl(eax, kSmiTagSize); | 2739 __ shl(eax, kSmiTagSize); |
2745 frame_->EmitPush(eax); // <- slot 1 | 2740 frame_->EmitPush(eax); // <- slot 1 |
2746 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 | 2741 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 |
2747 | 2742 |
2748 // Condition. | 2743 // Condition. |
2749 entry.Bind(); | 2744 entry.Bind(); |
2750 // Grab the current frame's height for the break and continue | 2745 // Grab the current frame's height for the break and continue |
2751 // targets only after all the state is pushed on the frame. | 2746 // targets only after all the state is pushed on the frame. |
2752 node->break_target()->Initialize(this); | 2747 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2753 node->continue_target()->Initialize(this); | 2748 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
2754 | 2749 |
2755 __ mov(eax, frame_->ElementAt(0)); // load the current count | 2750 __ mov(eax, frame_->ElementAt(0)); // load the current count |
2756 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length | 2751 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length |
2757 node->break_target()->Branch(above_equal); | 2752 node->break_target()->Branch(above_equal); |
2758 | 2753 |
2759 // Get the i'th entry of the array. | 2754 // Get the i'th entry of the array. |
2760 __ mov(edx, frame_->ElementAt(2)); | 2755 __ mov(edx, frame_->ElementAt(2)); |
2761 __ mov(ebx, Operand(edx, eax, times_2, | 2756 __ mov(ebx, Operand(edx, eax, times_2, |
2762 FixedArray::kHeaderSize - kHeapObjectTag)); | 2757 FixedArray::kHeaderSize - kHeapObjectTag)); |
2763 | 2758 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2842 node->break_target()->Unuse(); | 2837 node->break_target()->Unuse(); |
2843 } | 2838 } |
2844 | 2839 |
2845 | 2840 |
2846 void CodeGenerator::VisitTryCatch(TryCatch* node) { | 2841 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
2847 ASSERT(!in_spilled_code()); | 2842 ASSERT(!in_spilled_code()); |
2848 VirtualFrame::SpilledScope spilled_scope(this); | 2843 VirtualFrame::SpilledScope spilled_scope(this); |
2849 Comment cmnt(masm_, "[ TryCatch"); | 2844 Comment cmnt(masm_, "[ TryCatch"); |
2850 CodeForStatementPosition(node); | 2845 CodeForStatementPosition(node); |
2851 | 2846 |
2852 JumpTarget try_block(this); | 2847 JumpTarget try_block; |
2853 JumpTarget exit(this); | 2848 JumpTarget exit; |
2854 | 2849 |
2855 try_block.Call(); | 2850 try_block.Call(); |
2856 // --- Catch block --- | 2851 // --- Catch block --- |
2857 frame_->EmitPush(eax); | 2852 frame_->EmitPush(eax); |
2858 | 2853 |
2859 // Store the caught exception in the catch variable. | 2854 // Store the caught exception in the catch variable. |
2860 { Reference ref(this, node->catch_var()); | 2855 { Reference ref(this, node->catch_var()); |
2861 ASSERT(ref.is_slot()); | 2856 ASSERT(ref.is_slot()); |
2862 // Load the exception to the top of the stack. Here we make use of the | 2857 // Load the exception to the top of the stack. Here we make use of the |
2863 // convenient property that it doesn't matter whether a value is | 2858 // convenient property that it doesn't matter whether a value is |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2986 ASSERT(!in_spilled_code()); | 2981 ASSERT(!in_spilled_code()); |
2987 VirtualFrame::SpilledScope spilled_scope(this); | 2982 VirtualFrame::SpilledScope spilled_scope(this); |
2988 Comment cmnt(masm_, "[ TryFinally"); | 2983 Comment cmnt(masm_, "[ TryFinally"); |
2989 CodeForStatementPosition(node); | 2984 CodeForStatementPosition(node); |
2990 | 2985 |
2991 // State: Used to keep track of reason for entering the finally | 2986 // State: Used to keep track of reason for entering the finally |
2992 // block. Should probably be extended to hold information for | 2987 // block. Should probably be extended to hold information for |
2993 // break/continue from within the try block. | 2988 // break/continue from within the try block. |
2994 enum { FALLING, THROWING, JUMPING }; | 2989 enum { FALLING, THROWING, JUMPING }; |
2995 | 2990 |
2996 JumpTarget try_block(this); | 2991 JumpTarget try_block; |
2997 JumpTarget finally_block(this); | 2992 JumpTarget finally_block; |
2998 | 2993 |
2999 try_block.Call(); | 2994 try_block.Call(); |
3000 | 2995 |
3001 frame_->EmitPush(eax); | 2996 frame_->EmitPush(eax); |
3002 // In case of thrown exceptions, this is where we continue. | 2997 // In case of thrown exceptions, this is where we continue. |
3003 __ Set(ecx, Immediate(Smi::FromInt(THROWING))); | 2998 __ Set(ecx, Immediate(Smi::FromInt(THROWING))); |
3004 finally_block.Jump(); | 2999 finally_block.Jump(); |
3005 | 3000 |
3006 // --- Try block --- | 3001 // --- Try block --- |
3007 try_block.Bind(); | 3002 try_block.Bind(); |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3139 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); | 3134 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); |
3140 if (i == kReturnShadowIndex) { | 3135 if (i == kReturnShadowIndex) { |
3141 // The return value is (already) in eax. | 3136 // The return value is (already) in eax. |
3142 Result return_value = allocator_->Allocate(eax); | 3137 Result return_value = allocator_->Allocate(eax); |
3143 ASSERT(return_value.is_valid()); | 3138 ASSERT(return_value.is_valid()); |
3144 if (function_return_is_shadowed_) { | 3139 if (function_return_is_shadowed_) { |
3145 original->Branch(equal, &return_value); | 3140 original->Branch(equal, &return_value); |
3146 } else { | 3141 } else { |
3147 // Branch around the preparation for return which may emit | 3142 // Branch around the preparation for return which may emit |
3148 // code. | 3143 // code. |
3149 JumpTarget skip(this); | 3144 JumpTarget skip; |
3150 skip.Branch(not_equal); | 3145 skip.Branch(not_equal); |
3151 frame_->PrepareForReturn(); | 3146 frame_->PrepareForReturn(); |
3152 original->Jump(&return_value); | 3147 original->Jump(&return_value); |
3153 skip.Bind(); | 3148 skip.Bind(); |
3154 } | 3149 } |
3155 } else { | 3150 } else { |
3156 original->Branch(equal); | 3151 original->Branch(equal); |
3157 } | 3152 } |
3158 } | 3153 } |
3159 } | 3154 } |
3160 | 3155 |
3161 if (has_valid_frame()) { | 3156 if (has_valid_frame()) { |
3162 // Check if we need to rethrow the exception. | 3157 // Check if we need to rethrow the exception. |
3163 JumpTarget exit(this); | 3158 JumpTarget exit; |
3164 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); | 3159 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); |
3165 exit.Branch(not_equal); | 3160 exit.Branch(not_equal); |
3166 | 3161 |
3167 // Rethrow exception. | 3162 // Rethrow exception. |
3168 frame_->EmitPush(eax); // undo pop from above | 3163 frame_->EmitPush(eax); // undo pop from above |
3169 frame_->CallRuntime(Runtime::kReThrow, 1); | 3164 frame_->CallRuntime(Runtime::kReThrow, 1); |
3170 | 3165 |
3171 // Done. | 3166 // Done. |
3172 exit.Bind(); | 3167 exit.Bind(); |
3173 } | 3168 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3213 | 3208 |
3214 void CodeGenerator::VisitFunctionBoilerplateLiteral( | 3209 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
3215 FunctionBoilerplateLiteral* node) { | 3210 FunctionBoilerplateLiteral* node) { |
3216 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 3211 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
3217 InstantiateBoilerplate(node->boilerplate()); | 3212 InstantiateBoilerplate(node->boilerplate()); |
3218 } | 3213 } |
3219 | 3214 |
3220 | 3215 |
3221 void CodeGenerator::VisitConditional(Conditional* node) { | 3216 void CodeGenerator::VisitConditional(Conditional* node) { |
3222 Comment cmnt(masm_, "[ Conditional"); | 3217 Comment cmnt(masm_, "[ Conditional"); |
3223 JumpTarget then(this); | 3218 JumpTarget then; |
3224 JumpTarget else_(this); | 3219 JumpTarget else_; |
3225 JumpTarget exit(this); | 3220 JumpTarget exit; |
3226 ControlDestination dest(&then, &else_, true); | 3221 ControlDestination dest(&then, &else_, true); |
3227 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); | 3222 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true); |
3228 | 3223 |
3229 if (dest.false_was_fall_through()) { | 3224 if (dest.false_was_fall_through()) { |
3230 // The else target was bound, so we compile the else part first. | 3225 // The else target was bound, so we compile the else part first. |
3231 Load(node->else_expression(), typeof_state()); | 3226 Load(node->else_expression(), typeof_state()); |
3232 | 3227 |
3233 if (then.is_linked()) { | 3228 if (then.is_linked()) { |
3234 exit.Jump(); | 3229 exit.Jump(); |
3235 then.Bind(); | 3230 then.Bind(); |
(...skipping 11 matching lines...) Expand all Loading... |
3247 } | 3242 } |
3248 | 3243 |
3249 exit.Bind(); | 3244 exit.Bind(); |
3250 } | 3245 } |
3251 | 3246 |
3252 | 3247 |
3253 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 3248 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
3254 if (slot->type() == Slot::LOOKUP) { | 3249 if (slot->type() == Slot::LOOKUP) { |
3255 ASSERT(slot->var()->is_dynamic()); | 3250 ASSERT(slot->var()->is_dynamic()); |
3256 | 3251 |
3257 JumpTarget slow(this); | 3252 JumpTarget slow; |
3258 JumpTarget done(this); | 3253 JumpTarget done; |
3259 Result value; | 3254 Result value; |
3260 | 3255 |
3261 // Generate fast-case code for variables that might be shadowed by | 3256 // Generate fast-case code for variables that might be shadowed by |
3262 // eval-introduced variables. Eval is used a lot without | 3257 // eval-introduced variables. Eval is used a lot without |
3263 // introducing variables. In those cases, we do not want to | 3258 // introducing variables. In those cases, we do not want to |
3264 // perform a runtime call for all variables in the scope | 3259 // perform a runtime call for all variables in the scope |
3265 // containing the eval. | 3260 // containing the eval. |
3266 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 3261 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
3267 value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); | 3262 value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); |
3268 // If there was no control flow to slow, we can exit early. | 3263 // If there was no control flow to slow, we can exit early. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3314 | 3309 |
3315 } else if (slot->var()->mode() == Variable::CONST) { | 3310 } else if (slot->var()->mode() == Variable::CONST) { |
3316 // Const slots may contain 'the hole' value (the constant hasn't been | 3311 // Const slots may contain 'the hole' value (the constant hasn't been |
3317 // initialized yet) which needs to be converted into the 'undefined' | 3312 // initialized yet) which needs to be converted into the 'undefined' |
3318 // value. | 3313 // value. |
3319 // | 3314 // |
3320 // We currently spill the virtual frame because constants use the | 3315 // We currently spill the virtual frame because constants use the |
3321 // potentially unsafe direct-frame access of SlotOperand. | 3316 // potentially unsafe direct-frame access of SlotOperand. |
3322 VirtualFrame::SpilledScope spilled_scope(this); | 3317 VirtualFrame::SpilledScope spilled_scope(this); |
3323 Comment cmnt(masm_, "[ Load const"); | 3318 Comment cmnt(masm_, "[ Load const"); |
3324 JumpTarget exit(this); | 3319 JumpTarget exit; |
3325 __ mov(ecx, SlotOperand(slot, ecx)); | 3320 __ mov(ecx, SlotOperand(slot, ecx)); |
3326 __ cmp(ecx, Factory::the_hole_value()); | 3321 __ cmp(ecx, Factory::the_hole_value()); |
3327 exit.Branch(not_equal); | 3322 exit.Branch(not_equal); |
3328 __ mov(ecx, Factory::undefined_value()); | 3323 __ mov(ecx, Factory::undefined_value()); |
3329 exit.Bind(); | 3324 exit.Bind(); |
3330 frame_->EmitPush(ecx); | 3325 frame_->EmitPush(ecx); |
3331 | 3326 |
3332 } else if (slot->type() == Slot::PARAMETER) { | 3327 } else if (slot->type() == Slot::PARAMETER) { |
3333 frame_->PushParameterAt(slot->index()); | 3328 frame_->PushParameterAt(slot->index()); |
3334 | 3329 |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3452 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3); | 3447 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3); |
3453 } | 3448 } |
3454 // Storing a variable must keep the (new) value on the expression | 3449 // Storing a variable must keep the (new) value on the expression |
3455 // stack. This is necessary for compiling chained assignment | 3450 // stack. This is necessary for compiling chained assignment |
3456 // expressions. | 3451 // expressions. |
3457 frame_->Push(&value); | 3452 frame_->Push(&value); |
3458 | 3453 |
3459 } else { | 3454 } else { |
3460 ASSERT(!slot->var()->is_dynamic()); | 3455 ASSERT(!slot->var()->is_dynamic()); |
3461 | 3456 |
3462 JumpTarget exit(this); | 3457 JumpTarget exit; |
3463 if (init_state == CONST_INIT) { | 3458 if (init_state == CONST_INIT) { |
3464 ASSERT(slot->var()->mode() == Variable::CONST); | 3459 ASSERT(slot->var()->mode() == Variable::CONST); |
3465 // Only the first const initialization must be executed (the slot | 3460 // Only the first const initialization must be executed (the slot |
3466 // still contains 'the hole' value). When the assignment is executed, | 3461 // still contains 'the hole' value). When the assignment is executed, |
3467 // the code is identical to a normal store (see below). | 3462 // the code is identical to a normal store (see below). |
3468 // | 3463 // |
3469 // We spill the frame in the code below because the direct-frame | 3464 // We spill the frame in the code below because the direct-frame |
3470 // access of SlotOperand is potentially unsafe with an unspilled | 3465 // access of SlotOperand is potentially unsafe with an unspilled |
3471 // frame. | 3466 // frame. |
3472 VirtualFrame::SpilledScope spilled_scope(this); | 3467 VirtualFrame::SpilledScope spilled_scope(this); |
(...skipping 804 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4277 | 4272 |
4278 // This generates code that performs a charCodeAt() call or returns | 4273 // This generates code that performs a charCodeAt() call or returns |
4279 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 4274 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
4280 // It can handle flat and sliced strings, 8 and 16 bit characters and | 4275 // It can handle flat and sliced strings, 8 and 16 bit characters and |
4281 // cons strings where the answer is found in the left hand branch of the | 4276 // cons strings where the answer is found in the left hand branch of the |
4282 // cons. The slow case will flatten the string, which will ensure that | 4277 // cons. The slow case will flatten the string, which will ensure that |
4283 // the answer is in the left hand side the next time around. | 4278 // the answer is in the left hand side the next time around. |
4284 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 4279 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
4285 ASSERT(args->length() == 2); | 4280 ASSERT(args->length() == 2); |
4286 | 4281 |
4287 JumpTarget slow_case(this); | 4282 JumpTarget slow_case; |
4288 JumpTarget end(this); | 4283 JumpTarget end; |
4289 JumpTarget not_a_flat_string(this); | 4284 JumpTarget not_a_flat_string; |
4290 JumpTarget a_cons_string(this); | 4285 JumpTarget a_cons_string; |
4291 JumpTarget try_again_with_new_string(this, JumpTarget::BIDIRECTIONAL); | 4286 JumpTarget try_again_with_new_string(JumpTarget::BIDIRECTIONAL); |
4292 JumpTarget ascii_string(this); | 4287 JumpTarget ascii_string; |
4293 JumpTarget got_char_code(this); | 4288 JumpTarget got_char_code; |
4294 | 4289 |
4295 Load(args->at(0)); | 4290 Load(args->at(0)); |
4296 Load(args->at(1)); | 4291 Load(args->at(1)); |
4297 // Reserve register ecx, to use as shift amount later | 4292 // Reserve register ecx, to use as shift amount later |
4298 Result shift_amount = allocator()->Allocate(ecx); | 4293 Result shift_amount = allocator()->Allocate(ecx); |
4299 ASSERT(shift_amount.is_valid()); | 4294 ASSERT(shift_amount.is_valid()); |
4300 Result index = frame_->Pop(); | 4295 Result index = frame_->Pop(); |
4301 index.ToRegister(); | 4296 index.ToRegister(); |
4302 Result object = frame_->Pop(); | 4297 Result object = frame_->Pop(); |
4303 object.ToRegister(); | 4298 object.ToRegister(); |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4441 Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters()))); | 4436 Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters()))); |
4442 // Call the shared stub to get to the arguments.length. | 4437 // Call the shared stub to get to the arguments.length. |
4443 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 4438 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
4444 Result result = frame_->CallStub(&stub, &count); | 4439 Result result = frame_->CallStub(&stub, &count); |
4445 frame_->Push(&result); | 4440 frame_->Push(&result); |
4446 } | 4441 } |
4447 | 4442 |
4448 | 4443 |
4449 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 4444 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
4450 ASSERT(args->length() == 1); | 4445 ASSERT(args->length() == 1); |
4451 JumpTarget leave(this); | 4446 JumpTarget leave; |
4452 Load(args->at(0)); // Load the object. | 4447 Load(args->at(0)); // Load the object. |
4453 frame_->Dup(); | 4448 frame_->Dup(); |
4454 Result object = frame_->Pop(); | 4449 Result object = frame_->Pop(); |
4455 object.ToRegister(); | 4450 object.ToRegister(); |
4456 ASSERT(object.is_valid()); | 4451 ASSERT(object.is_valid()); |
4457 // if (object->IsSmi()) return object. | 4452 // if (object->IsSmi()) return object. |
4458 __ test(object.reg(), Immediate(kSmiTagMask)); | 4453 __ test(object.reg(), Immediate(kSmiTagMask)); |
4459 leave.Branch(zero, taken); | 4454 leave.Branch(zero, taken); |
4460 // It is a heap object - get map. | 4455 // It is a heap object - get map. |
4461 Result temp = allocator()->Allocate(); | 4456 Result temp = allocator()->Allocate(); |
4462 ASSERT(temp.is_valid()); | 4457 ASSERT(temp.is_valid()); |
4463 // if (!object->IsJSValue()) return object. | 4458 // if (!object->IsJSValue()) return object. |
4464 __ CmpObjectType(object.reg(), JS_VALUE_TYPE, temp.reg()); | 4459 __ CmpObjectType(object.reg(), JS_VALUE_TYPE, temp.reg()); |
4465 leave.Branch(not_equal, not_taken); | 4460 leave.Branch(not_equal, not_taken); |
4466 __ mov(temp.reg(), FieldOperand(object.reg(), JSValue::kValueOffset)); | 4461 __ mov(temp.reg(), FieldOperand(object.reg(), JSValue::kValueOffset)); |
4467 object.Unuse(); | 4462 object.Unuse(); |
4468 frame_->SetElementAt(0, &temp); | 4463 frame_->SetElementAt(0, &temp); |
4469 leave.Bind(); | 4464 leave.Bind(); |
4470 } | 4465 } |
4471 | 4466 |
4472 | 4467 |
4473 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 4468 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
4474 ASSERT(args->length() == 2); | 4469 ASSERT(args->length() == 2); |
4475 JumpTarget leave(this); | 4470 JumpTarget leave; |
4476 Load(args->at(0)); // Load the object. | 4471 Load(args->at(0)); // Load the object. |
4477 Load(args->at(1)); // Load the value. | 4472 Load(args->at(1)); // Load the value. |
4478 Result value = frame_->Pop(); | 4473 Result value = frame_->Pop(); |
4479 Result object = frame_->Pop(); | 4474 Result object = frame_->Pop(); |
4480 value.ToRegister(); | 4475 value.ToRegister(); |
4481 object.ToRegister(); | 4476 object.ToRegister(); |
4482 | 4477 |
4483 // if (object->IsSmi()) return value. | 4478 // if (object->IsSmi()) return value. |
4484 __ test(object.reg(), Immediate(kSmiTagMask)); | 4479 __ test(object.reg(), Immediate(kSmiTagMask)); |
4485 leave.Branch(zero, &value, taken); | 4480 leave.Branch(zero, &value, taken); |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4694 UnarySubStub stub; | 4689 UnarySubStub stub; |
4695 // TODO(1222589): remove dependency of TOS being cached inside stub | 4690 // TODO(1222589): remove dependency of TOS being cached inside stub |
4696 Result operand = frame_->Pop(); | 4691 Result operand = frame_->Pop(); |
4697 Result answer = frame_->CallStub(&stub, &operand); | 4692 Result answer = frame_->CallStub(&stub, &operand); |
4698 frame_->Push(&answer); | 4693 frame_->Push(&answer); |
4699 break; | 4694 break; |
4700 } | 4695 } |
4701 | 4696 |
4702 case Token::BIT_NOT: { | 4697 case Token::BIT_NOT: { |
4703 // Smi check. | 4698 // Smi check. |
4704 JumpTarget smi_label(this); | 4699 JumpTarget smi_label; |
4705 JumpTarget continue_label(this); | 4700 JumpTarget continue_label; |
4706 Result operand = frame_->Pop(); | 4701 Result operand = frame_->Pop(); |
4707 operand.ToRegister(); | 4702 operand.ToRegister(); |
4708 __ test(operand.reg(), Immediate(kSmiTagMask)); | 4703 __ test(operand.reg(), Immediate(kSmiTagMask)); |
4709 smi_label.Branch(zero, &operand, taken); | 4704 smi_label.Branch(zero, &operand, taken); |
4710 | 4705 |
4711 frame_->Push(&operand); // undo popping of TOS | 4706 frame_->Push(&operand); // undo popping of TOS |
4712 Result answer = frame_->InvokeBuiltin(Builtins::BIT_NOT, | 4707 Result answer = frame_->InvokeBuiltin(Builtins::BIT_NOT, |
4713 CALL_FUNCTION, 1); | 4708 CALL_FUNCTION, 1); |
4714 | 4709 |
4715 continue_label.Jump(&answer); | 4710 continue_label.Jump(&answer); |
4716 smi_label.Bind(&answer); | 4711 smi_label.Bind(&answer); |
4717 answer.ToRegister(); | 4712 answer.ToRegister(); |
4718 frame_->Spill(answer.reg()); | 4713 frame_->Spill(answer.reg()); |
4719 __ not_(answer.reg()); | 4714 __ not_(answer.reg()); |
4720 __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag. | 4715 __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag. |
4721 continue_label.Bind(&answer); | 4716 continue_label.Bind(&answer); |
4722 frame_->Push(&answer); | 4717 frame_->Push(&answer); |
4723 break; | 4718 break; |
4724 } | 4719 } |
4725 | 4720 |
4726 case Token::ADD: { | 4721 case Token::ADD: { |
4727 // Smi check. | 4722 // Smi check. |
4728 JumpTarget continue_label(this); | 4723 JumpTarget continue_label; |
4729 Result operand = frame_->Pop(); | 4724 Result operand = frame_->Pop(); |
4730 operand.ToRegister(); | 4725 operand.ToRegister(); |
4731 __ test(operand.reg(), Immediate(kSmiTagMask)); | 4726 __ test(operand.reg(), Immediate(kSmiTagMask)); |
4732 continue_label.Branch(zero, &operand, taken); | 4727 continue_label.Branch(zero, &operand, taken); |
4733 | 4728 |
4734 frame_->Push(&operand); | 4729 frame_->Push(&operand); |
4735 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, | 4730 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, |
4736 CALL_FUNCTION, 1); | 4731 CALL_FUNCTION, 1); |
4737 | 4732 |
4738 continue_label.Bind(&answer); | 4733 continue_label.Bind(&answer); |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4913 // According to ECMA-262 section 11.11, page 58, the binary logical | 4908 // According to ECMA-262 section 11.11, page 58, the binary logical |
4914 // operators must yield the result of one of the two expressions | 4909 // operators must yield the result of one of the two expressions |
4915 // before any ToBoolean() conversions. This means that the value | 4910 // before any ToBoolean() conversions. This means that the value |
4916 // produced by a && or || operator is not necessarily a boolean. | 4911 // produced by a && or || operator is not necessarily a boolean. |
4917 | 4912 |
4918 // NOTE: If the left hand side produces a materialized value (not | 4913 // NOTE: If the left hand side produces a materialized value (not |
4919 // control flow), we force the right hand side to do the same. This | 4914 // control flow), we force the right hand side to do the same. This |
4920 // is necessary because we assume that if we get control flow on the | 4915 // is necessary because we assume that if we get control flow on the |
4921 // last path out of an expression we got it on all paths. | 4916 // last path out of an expression we got it on all paths. |
4922 if (op == Token::AND) { | 4917 if (op == Token::AND) { |
4923 JumpTarget is_true(this); | 4918 JumpTarget is_true; |
4924 ControlDestination dest(&is_true, destination()->false_target(), true); | 4919 ControlDestination dest(&is_true, destination()->false_target(), true); |
4925 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false); | 4920 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false); |
4926 | 4921 |
4927 if (dest.false_was_fall_through()) { | 4922 if (dest.false_was_fall_through()) { |
4928 // The current false target was used as the fall-through. If | 4923 // The current false target was used as the fall-through. If |
4929 // there are no dangling jumps to is_true then the left | 4924 // there are no dangling jumps to is_true then the left |
4930 // subexpression was unconditionally false. Otherwise we have | 4925 // subexpression was unconditionally false. Otherwise we have |
4931 // paths where we do have to evaluate the right subexpression. | 4926 // paths where we do have to evaluate the right subexpression. |
4932 if (is_true.is_linked()) { | 4927 if (is_true.is_linked()) { |
4933 // We need to compile the right subexpression. If the jump to | 4928 // We need to compile the right subexpression. If the jump to |
(...skipping 17 matching lines...) Expand all Loading... |
4951 | 4946 |
4952 } else if (dest.is_used()) { | 4947 } else if (dest.is_used()) { |
4953 // The left subexpression compiled to control flow (and is_true | 4948 // The left subexpression compiled to control flow (and is_true |
4954 // was just bound), so the right is free to do so as well. | 4949 // was just bound), so the right is free to do so as well. |
4955 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); | 4950 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); |
4956 | 4951 |
4957 } else { | 4952 } else { |
4958 // We have a materialized value on the frame, so we exit with | 4953 // We have a materialized value on the frame, so we exit with |
4959 // one on all paths. There are possibly also jumps to is_true | 4954 // one on all paths. There are possibly also jumps to is_true |
4960 // from nested subexpressions. | 4955 // from nested subexpressions. |
4961 JumpTarget pop_and_continue(this); | 4956 JumpTarget pop_and_continue; |
4962 JumpTarget exit(this); | 4957 JumpTarget exit; |
4963 | 4958 |
4964 // Avoid popping the result if it converts to 'false' using the | 4959 // Avoid popping the result if it converts to 'false' using the |
4965 // standard ToBoolean() conversion as described in ECMA-262, | 4960 // standard ToBoolean() conversion as described in ECMA-262, |
4966 // section 9.2, page 30. | 4961 // section 9.2, page 30. |
4967 // | 4962 // |
4968 // Duplicate the TOS value. The duplicate will be popped by | 4963 // Duplicate the TOS value. The duplicate will be popped by |
4969 // ToBoolean. | 4964 // ToBoolean. |
4970 frame_->Dup(); | 4965 frame_->Dup(); |
4971 ControlDestination dest(&pop_and_continue, &exit, true); | 4966 ControlDestination dest(&pop_and_continue, &exit, true); |
4972 ToBoolean(&dest); | 4967 ToBoolean(&dest); |
4973 | 4968 |
4974 // Pop the result of evaluating the first part. | 4969 // Pop the result of evaluating the first part. |
4975 frame_->Drop(); | 4970 frame_->Drop(); |
4976 | 4971 |
4977 // Compile right side expression. | 4972 // Compile right side expression. |
4978 is_true.Bind(); | 4973 is_true.Bind(); |
4979 Load(node->right()); | 4974 Load(node->right()); |
4980 | 4975 |
4981 // Exit (always with a materialized value). | 4976 // Exit (always with a materialized value). |
4982 exit.Bind(); | 4977 exit.Bind(); |
4983 } | 4978 } |
4984 | 4979 |
4985 } else if (op == Token::OR) { | 4980 } else if (op == Token::OR) { |
4986 JumpTarget is_false(this); | 4981 JumpTarget is_false; |
4987 ControlDestination dest(destination()->true_target(), &is_false, false); | 4982 ControlDestination dest(destination()->true_target(), &is_false, false); |
4988 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false); | 4983 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false); |
4989 | 4984 |
4990 if (dest.true_was_fall_through()) { | 4985 if (dest.true_was_fall_through()) { |
4991 // The current true target was used as the fall-through. If | 4986 // The current true target was used as the fall-through. If |
4992 // there are no dangling jumps to is_false then the left | 4987 // there are no dangling jumps to is_false then the left |
4993 // subexpression was unconditionally true. Otherwise we have | 4988 // subexpression was unconditionally true. Otherwise we have |
4994 // paths where we do have to evaluate the right subexpression. | 4989 // paths where we do have to evaluate the right subexpression. |
4995 if (is_false.is_linked()) { | 4990 if (is_false.is_linked()) { |
4996 // We need to compile the right subexpression. If the jump to | 4991 // We need to compile the right subexpression. If the jump to |
(...skipping 16 matching lines...) Expand all Loading... |
5013 | 5008 |
5014 } else if (dest.is_used()) { | 5009 } else if (dest.is_used()) { |
5015 // The left subexpression compiled to control flow (and is_false | 5010 // The left subexpression compiled to control flow (and is_false |
5016 // was just bound), so the right is free to do so as well. | 5011 // was just bound), so the right is free to do so as well. |
5017 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); | 5012 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false); |
5018 | 5013 |
5019 } else { | 5014 } else { |
5020 // We have a materialized value on the frame, so we exit with | 5015 // We have a materialized value on the frame, so we exit with |
5021 // one on all paths. There are possibly also jumps to is_false | 5016 // one on all paths. There are possibly also jumps to is_false |
5022 // from nested subexpressions. | 5017 // from nested subexpressions. |
5023 JumpTarget pop_and_continue(this); | 5018 JumpTarget pop_and_continue; |
5024 JumpTarget exit(this); | 5019 JumpTarget exit; |
5025 | 5020 |
5026 // Avoid popping the result if it converts to 'true' using the | 5021 // Avoid popping the result if it converts to 'true' using the |
5027 // standard ToBoolean() conversion as described in ECMA-262, | 5022 // standard ToBoolean() conversion as described in ECMA-262, |
5028 // section 9.2, page 30. | 5023 // section 9.2, page 30. |
5029 // | 5024 // |
5030 // Duplicate the TOS value. The duplicate will be popped by | 5025 // Duplicate the TOS value. The duplicate will be popped by |
5031 // ToBoolean. | 5026 // ToBoolean. |
5032 frame_->Dup(); | 5027 frame_->Dup(); |
5033 ControlDestination dest(&exit, &pop_and_continue, false); | 5028 ControlDestination dest(&exit, &pop_and_continue, false); |
5034 ToBoolean(&dest); | 5029 ToBoolean(&dest); |
(...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5968 // Check that the *unsigned* result fits in a smi. | 5963 // Check that the *unsigned* result fits in a smi. |
5969 // Neither of the two high-order bits can be set: | 5964 // Neither of the two high-order bits can be set: |
5970 // - 0x80000000: high bit would be lost when smi tagging. | 5965 // - 0x80000000: high bit would be lost when smi tagging. |
5971 // - 0x40000000: this number would convert to negative when | 5966 // - 0x40000000: this number would convert to negative when |
5972 // Smi tagging these two cases can only happen with shifts | 5967 // Smi tagging these two cases can only happen with shifts |
5973 // by 0 or 1 when handed a valid smi. | 5968 // by 0 or 1 when handed a valid smi. |
5974 // If the answer cannot be represented by a SMI, restore | 5969 // If the answer cannot be represented by a SMI, restore |
5975 // the left and right arguments, and jump to slow case. | 5970 // the left and right arguments, and jump to slow case. |
5976 // The low bit of the left argument may be lost, but only | 5971 // The low bit of the left argument may be lost, but only |
5977 // in a case where it is dropped anyway. | 5972 // in a case where it is dropped anyway. |
5978 JumpTarget result_ok(generator()); | 5973 JumpTarget result_ok; |
5979 __ test(left->reg(), Immediate(0xc0000000)); | 5974 __ test(left->reg(), Immediate(0xc0000000)); |
5980 result_ok.Branch(zero, left, taken); | 5975 result_ok.Branch(zero, left, taken); |
5981 __ shl(left->reg()); | 5976 __ shl(left->reg()); |
5982 ASSERT(kSmiTag == 0); | 5977 ASSERT(kSmiTag == 0); |
5983 __ shl(left->reg(), kSmiTagSize); | 5978 __ shl(left->reg(), kSmiTagSize); |
5984 __ shl(right->reg(), kSmiTagSize); | 5979 __ shl(right->reg(), kSmiTagSize); |
5985 enter()->Jump(left, right); | 5980 enter()->Jump(left, right); |
5986 result_ok.Bind(left); | 5981 result_ok.Bind(left); |
5987 break; | 5982 break; |
5988 } | 5983 } |
5989 case Token::SHL: { | 5984 case Token::SHL: { |
5990 __ shl(left->reg()); | 5985 __ shl(left->reg()); |
5991 // Check that the *signed* result fits in a smi. | 5986 // Check that the *signed* result fits in a smi. |
5992 JumpTarget result_ok(generator()); | 5987 JumpTarget result_ok; |
5993 __ cmp(left->reg(), 0xc0000000); | 5988 __ cmp(left->reg(), 0xc0000000); |
5994 result_ok.Branch(positive, left, taken); | 5989 result_ok.Branch(positive, left, taken); |
5995 | 5990 |
5996 __ shr(left->reg()); | 5991 __ shr(left->reg()); |
5997 ASSERT(kSmiTag == 0); | 5992 ASSERT(kSmiTag == 0); |
5998 __ shl(left->reg(), kSmiTagSize); | 5993 __ shl(left->reg(), kSmiTagSize); |
5999 __ shl(right->reg(), kSmiTagSize); | 5994 __ shl(right->reg(), kSmiTagSize); |
6000 enter()->Jump(left, right); | 5995 enter()->Jump(left, right); |
6001 result_ok.Bind(left); | 5996 result_ok.Bind(left); |
6002 break; | 5997 break; |
(...skipping 1235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7238 | 7233 |
7239 // Slow-case: Go through the JavaScript implementation. | 7234 // Slow-case: Go through the JavaScript implementation. |
7240 __ bind(&slow); | 7235 __ bind(&slow); |
7241 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 7236 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
7242 } | 7237 } |
7243 | 7238 |
7244 | 7239 |
7245 #undef __ | 7240 #undef __ |
7246 | 7241 |
7247 } } // namespace v8::internal | 7242 } } // namespace v8::internal |
OLD | NEW |