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 |