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

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

Issue 27200: Experimental: fix a bug in our compilation of switch statements.... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
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 | « no previous file | 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 2029 matching lines...) Expand 10 before | Expand all | Expand 10 after
2040 } 2040 }
2041 2041
2042 JumpTarget next_test(this); 2042 JumpTarget next_test(this);
2043 JumpTarget fall_through(this); 2043 JumpTarget fall_through(this);
2044 JumpTarget default_entry(this); 2044 JumpTarget default_entry(this);
2045 JumpTarget default_exit(this, JumpTarget::BIDIRECTIONAL); 2045 JumpTarget default_exit(this, JumpTarget::BIDIRECTIONAL);
2046 ZoneList<CaseClause*>* cases = node->cases(); 2046 ZoneList<CaseClause*>* cases = node->cases();
2047 int length = cases->length(); 2047 int length = cases->length();
2048 CaseClause* default_clause = NULL; 2048 CaseClause* default_clause = NULL;
2049 2049
2050 for (int i = 0; i < length; i++) { 2050 // Loop over the cases, compiling tests and bodies. Skip the
2051 CaseClause* clause = cases->at(i); 2051 // default if found and compile it at the end. Exit early if an
2052 // unconditionally true match occurs (which can happen, eg, in the
2053 // event the switch value is a compile-time constant).
2054 //
2055 // Bind the next_test target before entering the loop so we can use
2056 // its state to detect whether the switch value needs to be dropped
2057 // from the frame.
2058 next_test.Bind();
2059 int index = 0;
2060 for (; index < length; index++) {
2061 CaseClause* clause = cases->at(index);
2052 if (clause->is_default()) { 2062 if (clause->is_default()) {
2053 // Remember the default clause and compile it at the end. 2063 // Remember the default clause and compile it at the end.
2054 default_clause = clause; 2064 default_clause = clause;
2055 continue; 2065 continue;
2056 } 2066 }
2057 2067
2058 // Compile each non-default clause. 2068 // Compile each non-default clause.
2059 Comment cmnt(masm_, "[ Case clause"); 2069 Comment cmnt(masm_, "[ Case clause");
2060 if (next_test.is_linked()) { 2070 // Recycle the same target for each test.
2061 // Recycle the same label for each test. 2071 if (!next_test.is_unused()) {
2062 next_test.Bind(); 2072 // The next test target may be linked (as the target of a
2073 // previous match failure) or bound (if the previous comparison
2074 // was unconditionally false or this is the first non-default
2075 // comparison).
2076 if (next_test.is_linked()) {
2077 next_test.Bind();
2078 }
2063 next_test.Unuse(); 2079 next_test.Unuse();
2064 } 2080 }
2065 2081
2082 // Duplicate the switch value.
2083 frame_->Dup();
2084
2085 // Compile the clause's label expression.
2086 Load(clause->label());
2087
2088 // Compare and branch to the body if true and to the next test if
2089 // false.
2066 JumpTarget enter_body(this); 2090 JumpTarget enter_body(this);
2067 ControlDestination dest(&enter_body, &next_test, true); 2091 ControlDestination dest(&enter_body, &next_test, true);
2068 // Control flow reaches this test if it is the first non-default case, 2092 Comparison(equal, true, &dest);
2069 // or if a previous test links to this as the next test through the
2070 // next_test JumpTarget. If so, then has_valid_frame() is true.
2071 if (has_valid_frame()) {
2072 // Duplicate the switch value.
2073 frame_->Dup();
2074 Load(clause->label());
2075 Comparison(equal, true, &dest);
2076 }
2077 2093
2078 bool previous_was_default = (i > 0 && cases->at(i - 1)->is_default()); 2094 bool previous_was_default =
2079 2095 index > 0 && cases->at(index - 1)->is_default();
2080 if (dest.false_was_fall_through()) { 2096 if (dest.false_was_fall_through()) {
2081 // The next_test target was just bound. We may have control 2097 // The false target next_test was bound as the fall-through.
2082 // flow to enter_body as well. 2098 // This may indicate that the comparison was unconditionally
2083 next_test.Unuse(); 2099 // false if there are no dangling jumps to enter_body. Even
2100 // then we may still need to compile the body if it is reachable
2101 // as a fall through.
2084 2102
2085 // We do not need to compile the body if control cannot reach 2103 // We do not need to compile the body if control cannot reach
2086 // it. Possible avenues to reach the body are (1) from the test 2104 // it. Control could reach the body (1) from the comparison by
2087 // by branching to enter_body, (2) as the fall through of a 2105 // a branch to enter_body, (2) as the fall through of some
2088 // previous case, or (3) possibly from a default. 2106 // previous case, or (3) possibly via a backward jump from the
2107 // default.
2089 if (!enter_body.is_linked() && 2108 if (!enter_body.is_linked() &&
2090 !fall_through.is_linked() && 2109 !fall_through.is_linked() &&
2091 !previous_was_default) { 2110 !previous_was_default) {
2092 continue; 2111 continue;
2093 } 2112 }
2094 2113
2095 // Otherwise we have to jump around the body on this path. 2114 // We will compile the body and we have to jump around it on
2115 // this path where the comparison failed.
2116 next_test.Unuse();
2096 next_test.Jump(); 2117 next_test.Jump();
2097 if (enter_body.is_linked()) { 2118 if (enter_body.is_linked()) {
2098 enter_body.Bind(); 2119 enter_body.Bind();
2099 } 2120 }
2100 } 2121 }
2101 2122
2123 // The body entry target may have been bound, indicating control
2124 // flow can reach the body via the comparison.
2102 if (enter_body.is_bound()) { 2125 if (enter_body.is_bound()) {
2103 // We had control flow to the body from the test. The switch 2126 // The switch value is no longer needed.
2104 // value is no longer needed.
2105 frame_->Drop(); 2127 frame_->Drop();
2106 } else { 2128 } else {
2107 // The test was unconditionally false or else the tests are 2129 // The test was unconditionally false but we will compile the
2108 // being skipped due to an earlier unconditional match, and only 2130 // body as a fall through.
2109 // fall-through to bodies is generating control flow.
2110 ASSERT(!has_valid_frame()); 2131 ASSERT(!has_valid_frame());
2111 } 2132 }
2112 2133
2113 // Label the body so that fall through is enabled. 2134 // Label the body if needed for fall through.
2114 if (previous_was_default) { 2135 if (previous_was_default) {
2115 // Because the default is compiled last, there is always a potential 2136 // Because the default is compiled last, there is always a potential
2116 // backwards edge to here, falling through from the default. 2137 // backwards edge to here, falling through from the default.
2117 default_exit.Bind(); 2138 default_exit.Bind();
2118 } else if (fall_through.is_linked()) { 2139 } else {
2119 // Recycle the same label for each fall through. 2140 // Recycle the same target for each fall through.
2120 fall_through.Bind(); 2141 fall_through.Bind();
2121 fall_through.Unuse(); 2142 fall_through.Unuse();
2122 } 2143 }
2123 VisitStatements(clause->statements());
2124 2144
2125 // If control flow can fall through from the body jump to the next body 2145 // Compile the body.
2126 // or the end of the statement. 2146 ASSERT(has_valid_frame());
2127 if (has_valid_frame()) { 2147 { Comment body_cmnt(masm_, "[ Case body");
2128 if (i < length - 1 && cases->at(i + 1)->is_default()) { 2148 VisitStatements(clause->statements());
2129 // The next case is the default. 2149 }
2150
2151 // The test may have been unconditionally true. In that case,
2152 // exit this loop and stop compiling tests and bodies. Otherwise,
2153 // if control flow can fall off the end of the body jump to the
2154 // body of the next case as fall through unless this is the last
2155 // 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.
2130 default_entry.Jump(); 2162 default_entry.Jump();
2131 } else { 2163 } else if (index < length - 1) { // This is not the last case.
2132 fall_through.Jump(); 2164 fall_through.Jump();
2133 } 2165 }
2134 } 2166 }
2135 } 2167 }
2136 2168
William Hesse 2009/02/26 14:09:06 Could you put a comment here, indicating the possi
Kevin Millikin (Chromium) 2009/02/26 15:00:04 Not here but I've clarified some of the other comm
2137 // The block at the final "test" label removes the switch value. 2169 // If we did not compile all the cases then we must have hit one
2138 if (next_test.is_linked()) { 2170 // that was unconditionally true. We do not need to compile any
2139 // JumpTarget next_test could have been bound, rather than linked to, 2171 // more tests but we may have (and continue to have) fall through.
2140 // if the previous test was unconditionally false. 2172 for (; index < length && has_valid_frame(); index++) {
2141 next_test.Bind(); 2173 Comment cmnt(masm_, "[ Case fall-through");
2174 VisitStatements(cases->at(index)->statements());
William Hesse 2009/02/26 14:09:06 Should you break on no frame here, or is VisitStat
Kevin Millikin (Chromium) 2009/02/26 15:00:04 Done.
2142 } 2175 }
2143 if (has_valid_frame()) { 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 clause compiled was unconditionally true. We still
William Hesse 2009/02/26 14:09:06 The last test compiled? Can't many fall-through cl
Kevin Millikin (Chromium) 2009/02/26 15:00:04 Done.
2181 // need to compile the default if we found one and it can be
2182 // targeted 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()) {
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();
2206 }
2144 frame_->Drop(); 2207 frame_->Drop();
2145 } 2208
2146 // If there is a default clause, compile it now. If it is determined 2209 // If there was a default clause, compile it now.
2147 // at compile time to be unreachable, then it has no valid entry frame, 2210 if (default_clause != NULL) {
2148 // and it is not compiled. 2211 Comment cmnt(masm_, "[ Default clause");
2149 if (default_clause != NULL) { 2212 if (default_entry.is_linked()) {
2150 Comment cmnt(masm_, "[ Default clause"); 2213 default_entry.Bind();
2151 default_entry.Bind(); 2214 }
2152 if (has_valid_frame()) {
2153 VisitStatements(default_clause->statements()); 2215 VisitStatements(default_clause->statements());
2154 } 2216 // If control flow can fall off the end of the default and there
2155 // If control flow can fall out of the default and there is a case after 2217 // was a case after it, jump to that case's body.
2156 // it, jump to that case's body. 2218 if (has_valid_frame() && default_exit.is_bound()) {
2157 if (has_valid_frame() && default_exit.is_bound()) { 2219 default_exit.Jump();
2158 default_exit.Jump(); 2220 }
2159 } 2221 }
2160 } 2222 }
2161 2223
2162 if (fall_through.is_linked()) { 2224 if (fall_through.is_linked()) {
2163 fall_through.Bind(); 2225 fall_through.Bind();
2164 } 2226 }
2165 if (node->break_target()->is_linked()) { 2227 if (node->break_target()->is_linked()) {
2166 node->break_target()->Bind(); 2228 node->break_target()->Bind();
2167 } 2229 }
2168 } 2230 }
(...skipping 4592 matching lines...) Expand 10 before | Expand all | Expand 10 after
6761 6823
6762 // Slow-case: Go through the JavaScript implementation. 6824 // Slow-case: Go through the JavaScript implementation.
6763 __ bind(&slow); 6825 __ bind(&slow);
6764 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 6826 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
6765 } 6827 }
6766 6828
6767 6829
6768 #undef __ 6830 #undef __
6769 6831
6770 } } // namespace v8::internal 6832 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698