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 2029 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |