Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(35)

Side by Side Diff: src/codegen-ia32.cc

Issue 28296: Simplify the way that we compile slow-case switch statements. Compile... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ast.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « src/ast.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698