Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 2013 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2024 } | 2024 } |
| 2025 | 2025 |
| 2026 | 2026 |
| 2027 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 2027 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 2028 ASSERT(!in_spilled_code()); | 2028 ASSERT(!in_spilled_code()); |
| 2029 Comment cmnt(masm_, "[ SwitchStatement"); | 2029 Comment cmnt(masm_, "[ SwitchStatement"); |
| 2030 CodeForStatementPosition(node); | 2030 CodeForStatementPosition(node); |
| 2031 node->set_break_stack_height(break_stack_height_); | 2031 node->set_break_stack_height(break_stack_height_); |
| 2032 node->break_target()->Initialize(this); | 2032 node->break_target()->Initialize(this); |
| 2033 | 2033 |
| 2034 // Compile the switch value. | |
| 2034 Load(node->tag()); | 2035 Load(node->tag()); |
| 2036 | |
| 2035 if (TryGenerateFastCaseSwitchStatement(node)) { | 2037 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 2036 return; | 2038 return; |
| 2037 } | 2039 } |
| 2038 | 2040 |
| 2039 JumpTarget next_test(this); | |
| 2040 JumpTarget fall_through(this); | |
| 2041 JumpTarget default_entry(this); | |
| 2042 JumpTarget default_exit(this, JumpTarget::BIDIRECTIONAL); | |
| 2043 ZoneList<CaseClause*>* cases = node->cases(); | 2041 ZoneList<CaseClause*>* cases = node->cases(); |
| 2044 int length = cases->length(); | 2042 int length = cases->length(); |
| 2045 CaseClause* default_clause = NULL; | 2043 CaseClause* default_clause = NULL; |
| 2046 | 2044 |
| 2047 // Loop over the cases, compiling tests and bodies. Skip the | 2045 JumpTarget next_test(this); |
| 2048 // default if found and compile it at the end. Exit early if an | 2046 // Compile the case label expressions and comparisons. Exit early |
| 2049 // unconditionally true match occurs (which can happen, eg, in the | 2047 // if a comparison is unconditionally true. The target next_test is |
| 2050 // event the switch value is a compile-time constant). | 2048 // bound before the loop in order to indicate control flow to the |
| 2051 // | 2049 // first comparison. |
| 2052 // Bind the next_test target before entering the loop so we can use | |
| 2053 // its state to detect whether the switch value needs to be dropped | |
| 2054 // from the frame. | |
| 2055 next_test.Bind(); | 2050 next_test.Bind(); |
| 2056 int index = 0; | 2051 for (int i = 0; i < length && !next_test.is_unused(); i++) { |
| 2057 for (; index < length; index++) { | 2052 CaseClause* clause = cases->at(i); |
| 2058 CaseClause* clause = cases->at(index); | 2053 clause->body_target()->Initialize(this); |
| 2054 // The default is not a test, but remember it for later. | |
| 2059 if (clause->is_default()) { | 2055 if (clause->is_default()) { |
| 2060 // Remember the default clause and compile it at the end. | |
| 2061 default_clause = clause; | 2056 default_clause = clause; |
| 2062 continue; | 2057 continue; |
| 2063 } | 2058 } |
| 2064 | 2059 |
| 2065 // Compile each non-default clause. | 2060 Comment cmnt(masm_, "[ Case comparison"); |
| 2066 Comment cmnt(masm_, "[ Case clause"); | 2061 // We recycle the same target next_test for each test. Bind it if |
| 2067 // Recycle the same target for each test. | 2062 // the previous test has not done so and then unuse it for the |
| 2068 if (!next_test.is_unused()) { | 2063 // loop. |
| 2069 // The next test target may be linked (as the target of a | 2064 if (next_test.is_linked()) { |
| 2070 // previous match failure) or bound (if the previous comparison | 2065 next_test.Bind(); |
| 2071 // was unconditionally false or this is the first non-default | |
| 2072 // comparison). | |
| 2073 if (next_test.is_linked()) { | |
| 2074 next_test.Bind(); | |
| 2075 } | |
| 2076 next_test.Unuse(); | |
| 2077 } | 2066 } |
| 2067 next_test.Unuse(); | |
| 2078 | 2068 |
| 2079 // Duplicate the switch value. | 2069 // Duplicate the switch value. |
| 2080 frame_->Dup(); | 2070 frame_->Dup(); |
| 2081 | 2071 |
| 2082 // Compile the clause's label expression. | 2072 // Compile the label expression. |
| 2083 Load(clause->label()); | 2073 Load(clause->label()); |
| 2084 | 2074 |
| 2085 // Compare and branch to the body if true and to the next test if | 2075 // Compare and branch to the body if true or the next test if |
| 2086 // false. | 2076 // false. Prefer the next test as a fall through. |
| 2087 JumpTarget enter_body(this); | 2077 ControlDestination dest(clause->body_target(), &next_test, false); |
| 2088 ControlDestination dest(&enter_body, &next_test, true); | |
| 2089 Comparison(equal, true, &dest); | 2078 Comparison(equal, true, &dest); |
| 2090 | 2079 |
| 2091 bool previous_was_default = | 2080 // If the comparison fell through to the true target, jump to the |
| 2092 index > 0 && cases->at(index - 1)->is_default(); | 2081 // actual body. |
| 2093 if (dest.false_was_fall_through()) { | 2082 if (dest.true_was_fall_through()) { |
| 2094 // The false target next_test was bound as the fall-through. | 2083 clause->body_target()->Unuse(); |
| 2095 // This may indicate that the comparison was unconditionally | 2084 clause->body_target()->Jump(); |
| 2096 // false if there are no dangling jumps to enter_body. Even | |
| 2097 // then we may still need to compile the body if it is reachable | |
| 2098 // as a fall through. | |
| 2099 | |
| 2100 // We do not need to compile the body if control cannot reach | |
| 2101 // it. Control could reach the body (1) from the comparison by | |
| 2102 // a branch to enter_body, (2) as the fall through of some | |
| 2103 // previous case, or (3) possibly via a backward jump from the | |
| 2104 // default. | |
| 2105 if (!enter_body.is_linked() && | |
| 2106 !fall_through.is_linked() && | |
| 2107 !previous_was_default) { | |
| 2108 continue; | |
| 2109 } | |
| 2110 | |
| 2111 // We will compile the body and we have to jump around it on | |
| 2112 // this path where the comparison failed. | |
| 2113 next_test.Unuse(); | |
| 2114 next_test.Jump(); | |
| 2115 if (enter_body.is_linked()) { | |
| 2116 enter_body.Bind(); | |
| 2117 } | |
| 2118 } | |
| 2119 | |
| 2120 // The body entry target may have been bound, indicating control | |
| 2121 // flow can reach the body via the comparison. | |
| 2122 if (enter_body.is_bound()) { | |
| 2123 // The switch value is no longer needed. | |
| 2124 frame_->Drop(); | |
| 2125 } else { | |
| 2126 // The test was unconditionally false but we will compile the | |
| 2127 // body as a fall through. | |
| 2128 ASSERT(!has_valid_frame()); | |
| 2129 } | |
| 2130 | |
| 2131 // Label the body if needed for fall through. | |
| 2132 if (previous_was_default) { | |
| 2133 // Because the default is compiled last, there is always a potential | |
| 2134 // backwards edge to here, falling through from the default. | |
| 2135 default_exit.Bind(); | |
| 2136 } else { | |
| 2137 // Recycle the same target for each fall through. | |
| 2138 fall_through.Bind(); | |
| 2139 fall_through.Unuse(); | |
| 2140 } | |
| 2141 | |
| 2142 // Compile the body. | |
| 2143 ASSERT(has_valid_frame()); | |
| 2144 { Comment body_cmnt(masm_, "[ Case body"); | |
| 2145 VisitStatements(clause->statements()); | |
| 2146 } | |
| 2147 | |
| 2148 // The test may have been unconditionally true, which is indicated | |
| 2149 // by the absence of any control flow to the next_test target. In | |
| 2150 // that case, exit this loop and stop compiling both tests and | |
| 2151 // bodies (and begin compiling only bodies if necessary). | |
| 2152 | |
| 2153 // Otherwise, if control flow can fall off the end of the body | |
| 2154 // jump to the body of the next case as fall through unless this | |
| 2155 // is the last non-default case. | |
| 2156 if (!next_test.is_linked()) { | |
| 2157 index++; | |
| 2158 break; | |
| 2159 } else if (has_valid_frame()) { | |
| 2160 if (index < length - 2 && // There are at least two cases after this | |
| 2161 cases->at(index + 1)->is_default()) { // The next is the default. | |
| 2162 default_entry.Jump(); | |
| 2163 } else if (index < length - 1) { // This is not the last case. | |
| 2164 fall_through.Jump(); | |
| 2165 } | |
| 2166 } | 2085 } |
| 2167 } | 2086 } |
| 2168 | 2087 |
| 2169 // If we did not compile all the cases then we must have hit one | 2088 // If there was control flow to a next test from the last one |
| 2170 // that was unconditionally true. We do not need to compile any | 2089 // compiled, compile a jump to the default or break target. |
| 2171 // more tests but we may have (and continue to have) fall through. | 2090 if (!next_test.is_unused()) { |
| 2172 for (; index < length && has_valid_frame(); index++) { | |
| 2173 Comment cmnt(masm_, "[ Case fall-through"); | |
| 2174 VisitStatements(cases->at(index)->statements()); | |
| 2175 } | |
| 2176 | |
| 2177 // Complete the switch statement based on the compilation state of | |
| 2178 // the last case that was compiled. | |
| 2179 if (next_test.is_unused()) { | |
| 2180 // The last test compiled was unconditionally true. We still need | |
| 2181 // to compile the default if we found one and it can be targeted | |
| 2182 // by fall through. | |
| 2183 if (default_clause != NULL) { | |
| 2184 bool was_only_clause = length == 1 && cases->at(0) == default_clause; | |
| 2185 if (was_only_clause || default_entry.is_linked()) { | |
| 2186 Comment cmnt(masm_, "[ Default clause"); | |
| 2187 default_entry.Bind(); | |
| 2188 VisitStatements(default_clause->statements()); | |
| 2189 // If control flow can fall off the end of the default and there | |
| 2190 // was a case after it, jump to that case's body. | |
| 2191 if (has_valid_frame() && default_exit.is_bound()) { | |
| 2192 default_exit.Jump(); | |
| 2193 } | |
| 2194 } | |
| 2195 } | |
| 2196 } else { | |
| 2197 // The switch value is still on the frame. We have to drop it and | |
| 2198 // possibly compile a default case. | |
| 2199 if (next_test.is_linked()) { | 2091 if (next_test.is_linked()) { |
| 2200 if (has_valid_frame()) { | |
| 2201 // We have fall through and thus need to jump around the code | |
| 2202 // to drop the switch value. | |
| 2203 fall_through.Jump(); | |
| 2204 } | |
| 2205 next_test.Bind(); | 2092 next_test.Bind(); |
| 2206 } | 2093 } |
| 2094 // Drop the switch value. | |
| 2207 frame_->Drop(); | 2095 frame_->Drop(); |
| 2208 | |
| 2209 // If there was a default clause, compile it now. | |
| 2210 if (default_clause != NULL) { | 2096 if (default_clause != NULL) { |
| 2211 Comment cmnt(masm_, "[ Default clause"); | 2097 default_clause->body_target()->Jump(); |
| 2212 if (default_entry.is_linked()) { | 2098 } else { |
| 2213 default_entry.Bind(); | 2099 node->break_target()->Jump(); |
| 2214 } | |
| 2215 VisitStatements(default_clause->statements()); | |
| 2216 // If control flow can fall off the end of the default and there | |
| 2217 // was a case after it, jump to that case's body. | |
| 2218 if (has_valid_frame() && default_exit.is_bound()) { | |
| 2219 default_exit.Jump(); | |
| 2220 } | |
| 2221 } | 2100 } |
| 2222 } | 2101 } |
| 2223 | 2102 |
| 2224 if (fall_through.is_linked()) { | 2103 // Compile case bodies as needed. |
|
iposva
2009/03/02 10:16:20
ASSERT that you do not have a valid frame here and
| |
| 2225 fall_through.Bind(); | 2104 for (int i = 0; i < length; i++) { |
| 2105 CaseClause* clause = cases->at(i); | |
| 2106 | |
| 2107 // There are two ways to reach the body: from the corresponding | |
| 2108 // test or as the fall through of the previous body. | |
| 2109 if (!clause->body_target()->is_linked() && !has_valid_frame()) { | |
| 2110 // If we have neither, skip this body. | |
| 2111 continue; | |
| 2112 } else if (clause->body_target()->is_linked() && has_valid_frame()) { | |
| 2113 // If we have both, put a jump on the fall through path to avoid | |
| 2114 // the dropping of the switch value on the test path. The | |
| 2115 // exception is the default which has already had the switch | |
| 2116 // value dropped. | |
| 2117 if (clause->is_default()) { | |
| 2118 clause->body_target()->Bind(); | |
| 2119 } else { | |
| 2120 JumpTarget body(this); | |
| 2121 body.Jump(); | |
| 2122 clause->body_target()->Bind(); | |
| 2123 frame_->Drop(); | |
| 2124 body.Bind(); | |
| 2125 } | |
| 2126 } else if (clause->body_target()->is_linked()) { | |
| 2127 // No fall through to worry about. | |
| 2128 clause->body_target()->Bind(); | |
| 2129 if (!clause->is_default()) { | |
| 2130 frame_->Drop(); | |
| 2131 } | |
| 2132 } | |
|
iposva
2009/03/02 10:16:20
Add else case here for the only fall-through case
| |
| 2133 // Otherwise, we have only fall through. In any case, we are | |
| 2134 // prepared to compile the body. | |
| 2135 Comment cmnt(masm_, "[ Case body"); | |
| 2136 VisitStatements(clause->statements()); | |
| 2226 } | 2137 } |
| 2138 | |
| 2139 // We may not have a valid frame here so bind the break target only | |
| 2140 // if needed. | |
| 2227 if (node->break_target()->is_linked()) { | 2141 if (node->break_target()->is_linked()) { |
| 2228 node->break_target()->Bind(); | 2142 node->break_target()->Bind(); |
| 2229 } | 2143 } |
| 2230 } | 2144 } |
| 2231 | 2145 |
| 2232 | 2146 |
| 2233 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 2147 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 2234 ASSERT(!in_spilled_code()); | 2148 ASSERT(!in_spilled_code()); |
| 2235 Comment cmnt(masm_, "[ LoopStatement"); | 2149 Comment cmnt(masm_, "[ LoopStatement"); |
| 2236 CodeForStatementPosition(node); | 2150 CodeForStatementPosition(node); |
| (...skipping 4664 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6901 | 6815 |
| 6902 // Slow-case: Go through the JavaScript implementation. | 6816 // Slow-case: Go through the JavaScript implementation. |
| 6903 __ bind(&slow); | 6817 __ bind(&slow); |
| 6904 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6818 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6905 } | 6819 } |
| 6906 | 6820 |
| 6907 | 6821 |
| 6908 #undef __ | 6822 #undef __ |
| 6909 | 6823 |
| 6910 } } // namespace v8::internal | 6824 } } // namespace v8::internal |
| OLD | NEW |