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 2156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2167 info = ALWAYS_FALSE; | 2167 info = ALWAYS_FALSE; |
2168 } | 2168 } |
2169 } | 2169 } |
2170 } | 2170 } |
2171 | 2171 |
2172 switch (node->type()) { | 2172 switch (node->type()) { |
2173 case LoopStatement::DO_LOOP: { | 2173 case LoopStatement::DO_LOOP: { |
2174 JumpTarget body(this, JumpTarget::BIDIRECTIONAL); | 2174 JumpTarget body(this, JumpTarget::BIDIRECTIONAL); |
2175 IncrementLoopNesting(); | 2175 IncrementLoopNesting(); |
2176 | 2176 |
2177 // Label the top of the loop for the backward CFG edge. If the test | 2177 // Label the top of the loop for the backward jump if necessary. |
2178 // is always true we can use the continue target, and if the test is | |
2179 // always false there is no need. | |
2180 if (info == ALWAYS_TRUE) { | 2178 if (info == ALWAYS_TRUE) { |
| 2179 // Use the continue target. |
2181 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 2180 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
2182 node->continue_target()->Bind(); | 2181 node->continue_target()->Bind(); |
2183 } else if (info == ALWAYS_FALSE) { | 2182 } else if (info == ALWAYS_FALSE) { |
| 2183 // No need to label it. |
2184 node->continue_target()->Initialize(this); | 2184 node->continue_target()->Initialize(this); |
2185 } else { | 2185 } else { |
| 2186 // Continue is the test, so use the backward body target. |
2186 ASSERT(info == DONT_KNOW); | 2187 ASSERT(info == DONT_KNOW); |
2187 node->continue_target()->Initialize(this); | 2188 node->continue_target()->Initialize(this); |
2188 body.Bind(); | 2189 body.Bind(); |
2189 } | 2190 } |
2190 | 2191 |
2191 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2192 CheckStack(); // TODO(1222600): ignore if body contains calls. |
2192 Visit(node->body()); | 2193 Visit(node->body()); |
2193 | 2194 |
2194 // Compile the test. | 2195 // Compile the test. |
2195 if (info == ALWAYS_TRUE) { | 2196 if (info == ALWAYS_TRUE) { |
2196 // If control flow can fall off the end of the body, jump back to | 2197 // If control flow can fall off the end of the body, jump back |
2197 // the top and bind the break target as the exit. | 2198 // to the top and bind the break target at the exit. |
2198 if (has_valid_frame()) { | 2199 if (has_valid_frame()) { |
2199 node->continue_target()->Jump(); | 2200 node->continue_target()->Jump(); |
2200 } | 2201 } |
2201 if (node->break_target()->is_linked()) { | 2202 if (node->break_target()->is_linked()) { |
2202 node->break_target()->Bind(); | 2203 node->break_target()->Bind(); |
2203 } | 2204 } |
2204 | 2205 |
2205 } else if (info == ALWAYS_FALSE) { | 2206 } else if (info == ALWAYS_FALSE) { |
2206 // We may have had continues or breaks in the body. | 2207 // We may have had continues or breaks in the body. |
2207 if (node->continue_target()->is_linked()) { | 2208 if (node->continue_target()->is_linked()) { |
(...skipping 15 matching lines...) Expand all Loading... |
2223 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2224 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
2224 } | 2225 } |
2225 if (node->break_target()->is_linked()) { | 2226 if (node->break_target()->is_linked()) { |
2226 node->break_target()->Bind(); | 2227 node->break_target()->Bind(); |
2227 } | 2228 } |
2228 } | 2229 } |
2229 break; | 2230 break; |
2230 } | 2231 } |
2231 | 2232 |
2232 case LoopStatement::WHILE_LOOP: { | 2233 case LoopStatement::WHILE_LOOP: { |
2233 JumpTarget body(this, JumpTarget::BIDIRECTIONAL); | 2234 // TODO(260): This flag controls whether to duplicate the test |
| 2235 // at the bottom of the loop. Replace it with a better |
| 2236 // indication of when it is safe to do so. |
| 2237 static const bool test_at_bottom = false; |
| 2238 |
| 2239 JumpTarget body; // Uninitialized. |
2234 IncrementLoopNesting(); | 2240 IncrementLoopNesting(); |
2235 | 2241 |
2236 // If the condition is always false and has no side effects, we | 2242 // If the condition is always false and has no side effects, we |
2237 // do not need to compile anything. | 2243 // do not need to compile anything. |
2238 if (info == ALWAYS_FALSE) break; | 2244 if (info == ALWAYS_FALSE) break; |
2239 | 2245 |
2240 // Based on the condition analysis, compile the test if | 2246 // Based on the condition analysis, compile the test as necessary. |
2241 // necessary and label the body if necessary. | |
2242 if (info == ALWAYS_TRUE) { | 2247 if (info == ALWAYS_TRUE) { |
2243 // We will not compile the test expression. Label the top of | 2248 // We will not compile the test expression. Label the top of |
2244 // the loop with the continue target. | 2249 // the loop with the continue target. |
2245 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 2250 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
2246 node->continue_target()->Bind(); | 2251 node->continue_target()->Bind(); |
2247 } else { | 2252 } else { |
2248 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. | 2253 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. |
2249 node->continue_target()->Initialize(this); | 2254 if (test_at_bottom) { |
| 2255 // Continue is the test at the bottom, no need to label the |
| 2256 // test at the top. The body is a backward target. |
| 2257 node->continue_target()->Initialize(this); |
| 2258 body.Initialize(this, JumpTarget::BIDIRECTIONAL); |
| 2259 } else { |
| 2260 // Label the test at the top as the continue target. The |
| 2261 // body is a forward-only target. |
| 2262 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
| 2263 node->continue_target()->Bind(); |
| 2264 body.Initialize(this); |
| 2265 } |
2250 // Compile the test with the body as the true target and | 2266 // Compile the test with the body as the true target and |
2251 // preferred fall-through and with the break target as the | 2267 // preferred fall-through and with the break target as the |
2252 // false target. | 2268 // false target. |
2253 ControlDestination dest(&body, node->break_target(), true); | 2269 ControlDestination dest(&body, node->break_target(), true); |
2254 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2270 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
2255 | 2271 |
2256 if (dest.false_was_fall_through()) { | 2272 if (dest.false_was_fall_through()) { |
2257 // If we don't have dangling jumps to the body, the test is | 2273 // If we got the break target as fall-through, the test may |
2258 // unconditionally false and we do not need to compile the | 2274 // have been unconditionally false (if there are no jumps to |
2259 // body. | 2275 // the body). |
2260 if (!body.is_linked()) break; | 2276 if (!body.is_linked()) break; |
2261 | 2277 |
2262 // Otherwise, jump around the body on the fall through and | 2278 // Otherwise, jump around the body on the fall through and |
2263 // then bind the body target. | 2279 // then bind the body target. |
2264 node->break_target()->Unuse(); | 2280 node->break_target()->Unuse(); |
2265 node->break_target()->Jump(); | 2281 node->break_target()->Jump(); |
2266 body.Bind(); | 2282 body.Bind(); |
2267 } | 2283 } |
2268 } | 2284 } |
2269 | 2285 |
2270 // The (stack check at the start of the) body was labeled. | |
2271 // Compile it. | |
2272 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2286 CheckStack(); // TODO(1222600): ignore if body contains calls. |
2273 Visit(node->body()); | 2287 Visit(node->body()); |
2274 | 2288 |
2275 // Compile the test if necessary and jump back. | 2289 // Based on the condition analysis, compile the backward jump as |
| 2290 // necessary. |
2276 if (info == ALWAYS_TRUE) { | 2291 if (info == ALWAYS_TRUE) { |
2277 // The body has been labeled with the continue target. | 2292 // The loop body has been labeled with the continue target. |
2278 if (has_valid_frame()) { | 2293 if (has_valid_frame()) { |
2279 node->continue_target()->Jump(); | 2294 node->continue_target()->Jump(); |
2280 } | 2295 } |
2281 } else { | 2296 } else { |
2282 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. | 2297 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. |
2283 if (node->continue_target()->is_linked()) { | 2298 if (test_at_bottom) { |
2284 node->continue_target()->Bind(); | 2299 // If we have chosen to recompile the test at the bottom, |
2285 } | 2300 // then it is the continue target. |
2286 | 2301 if (node->continue_target()->is_linked()) { |
2287 // If control can reach the bottom by falling off the body or | 2302 node->continue_target()->Bind(); |
2288 // a continue in the body, (re)compile the test at the bottom. | 2303 } |
2289 if (has_valid_frame()) { | 2304 if (has_valid_frame()) { |
2290 // The break target is the fall-through (body is a backward | 2305 // The break target is the fall-through (body is a backward |
2291 // jump from here). | 2306 // jump from here and thus an invalid fall-through). |
2292 ControlDestination dest(&body, node->break_target(), false); | 2307 ControlDestination dest(&body, node->break_target(), false); |
2293 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2308 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
| 2309 } |
| 2310 } else { |
| 2311 // If we have chosen not to recompile the test at the |
| 2312 // bottom, jump back to the one at the top. |
| 2313 if (has_valid_frame()) { |
| 2314 node->continue_target()->Jump(); |
| 2315 } |
2294 } | 2316 } |
2295 } | 2317 } |
2296 | 2318 |
2297 // The break target may be already bound (by the condition), or | 2319 // The break target may be already bound (by the condition), or |
2298 // there may not be a valid frame. Bind it only if needed. | 2320 // there may not be a valid frame. Bind it only if needed. |
2299 if (node->break_target()->is_linked()) { | 2321 if (node->break_target()->is_linked()) { |
2300 node->break_target()->Bind(); | 2322 node->break_target()->Bind(); |
2301 } | 2323 } |
2302 break; | 2324 break; |
2303 } | 2325 } |
2304 | 2326 |
2305 case LoopStatement::FOR_LOOP: { | 2327 case LoopStatement::FOR_LOOP: { |
2306 JumpTarget body(this, JumpTarget::BIDIRECTIONAL); | 2328 // TODO(260): This flag controls whether to duplicate the test |
| 2329 // at the bottom of the loop. Replace it with a better |
| 2330 // indication of when it is safe to do so. |
| 2331 static const bool test_at_bottom = false; |
| 2332 |
| 2333 JumpTarget loop(this, JumpTarget::BIDIRECTIONAL); |
| 2334 JumpTarget body(this); |
2307 | 2335 |
2308 // Compile the init expression if present. | 2336 // Compile the init expression if present. |
2309 if (node->init() != NULL) { | 2337 if (node->init() != NULL) { |
2310 Visit(node->init()); | 2338 Visit(node->init()); |
2311 } | 2339 } |
2312 | 2340 |
2313 IncrementLoopNesting(); | 2341 IncrementLoopNesting(); |
2314 | 2342 |
2315 // If the condition is always false and has no side effects, we | 2343 // If the condition is always false and has no side effects, we |
2316 // do not need to compile anything else. | 2344 // do not need to compile anything else. |
2317 if (info == ALWAYS_FALSE) break; | 2345 if (info == ALWAYS_FALSE) break; |
2318 | 2346 |
2319 // Based on the condition analysis, compile the test if | 2347 // Based on the condition analysis, compile the test as necessary. |
2320 // necessary and label the body if necessary. | |
2321 if (info == ALWAYS_TRUE) { | 2348 if (info == ALWAYS_TRUE) { |
2322 // We will not compile the test expression. Label the top of | 2349 // We will not compile the test expression. Label the top of |
2323 // the loop with the continue target if there is no update | 2350 // the loop. |
2324 // expression, otherwise with the body target. | |
2325 if (node->next() == NULL) { | 2351 if (node->next() == NULL) { |
| 2352 // Use the continue target if there is no update expression. |
2326 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); | 2353 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
2327 node->continue_target()->Bind(); | 2354 node->continue_target()->Bind(); |
2328 } else { | 2355 } else { |
| 2356 // Otherwise use the backward loop target. |
2329 node->continue_target()->Initialize(this); | 2357 node->continue_target()->Initialize(this); |
2330 body.Bind(); | 2358 loop.Bind(); |
2331 } | 2359 } |
2332 } else { | 2360 } else { |
2333 ASSERT(info == DONT_KNOW); | 2361 ASSERT(info == DONT_KNOW); |
2334 node->continue_target()->Initialize(this); | 2362 if (test_at_bottom) { |
| 2363 // Continue is either the update expression or the test at |
| 2364 // the bottom, no need to label the test at the top. |
| 2365 node->continue_target()->Initialize(this); |
| 2366 } else if (node->next() == NULL) { |
| 2367 // We are not recompiling the test at the bottom and there |
| 2368 // is no update expression. |
| 2369 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
| 2370 node->continue_target()->Bind(); |
| 2371 } else { |
| 2372 // We are not recompiling the test at the bottom and there |
| 2373 // is an update expression. |
| 2374 node->continue_target()->Initialize(this); |
| 2375 loop.Bind(); |
| 2376 } |
| 2377 |
2335 // Compile the test with the body as the true target and | 2378 // Compile the test with the body as the true target and |
2336 // preferred fall-through and with the break target as the | 2379 // preferred fall-through and with the break target as the |
2337 // false target. | 2380 // false target. |
2338 ControlDestination dest(&body, node->break_target(), true); | 2381 ControlDestination dest(&body, node->break_target(), true); |
2339 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2382 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
2340 | 2383 |
2341 if (dest.false_was_fall_through()) { | 2384 if (dest.false_was_fall_through()) { |
2342 // If we don't have dangling jumps to the body, the test is | 2385 // If we got the break target as fall-through, the test may |
2343 // unconditionally false and we do not need to compile the | 2386 // have been unconditionally false (if there are no jumps to |
2344 // body. | 2387 // the body). |
2345 if (!body.is_linked()) break; | 2388 if (!body.is_linked()) break; |
2346 | 2389 |
2347 // Otherwise, jump around the body on the fall through and | 2390 // Otherwise, jump around the body on the fall through and |
2348 // then bind the body target. | 2391 // then bind the body target. |
2349 node->break_target()->Unuse(); | 2392 node->break_target()->Unuse(); |
2350 node->break_target()->Jump(); | 2393 node->break_target()->Jump(); |
2351 body.Bind(); | 2394 body.Bind(); |
2352 } | 2395 } |
2353 } | 2396 } |
2354 | 2397 |
2355 // The (stack check at the start of the) body was labeled. | |
2356 // Compile it. | |
2357 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2398 CheckStack(); // TODO(1222600): ignore if body contains calls. |
2358 Visit(node->body()); | 2399 Visit(node->body()); |
2359 | 2400 |
2360 // If there is an update expression, compile it if necessary. | 2401 // If there is an update expression, compile it if necessary. |
2361 if (node->next() != NULL) { | 2402 if (node->next() != NULL) { |
2362 // We did not use the continue target for the body. | |
2363 if (node->continue_target()->is_linked()) { | 2403 if (node->continue_target()->is_linked()) { |
2364 node->continue_target()->Bind(); | 2404 node->continue_target()->Bind(); |
2365 } | 2405 } |
2366 | 2406 |
2367 // Control can reach the update by falling out of the body or | 2407 // Control can reach the update by falling out of the body or |
2368 // by a continue in the body. | 2408 // by a continue. |
2369 if (has_valid_frame()) { | 2409 if (has_valid_frame()) { |
2370 // Record the source position of the statement as this code | 2410 // Record the source position of the statement as this code |
2371 // which is after the code for the body actually belongs to | 2411 // which is after the code for the body actually belongs to |
2372 // the loop statement and not the body. | 2412 // the loop statement and not the body. |
2373 CodeForStatementPosition(node); | 2413 CodeForStatementPosition(node); |
2374 Visit(node->next()); | 2414 Visit(node->next()); |
2375 } | 2415 } |
2376 } | 2416 } |
2377 | 2417 |
2378 // Compile the test if necessary and jump back. | 2418 // Based on the condition analysis, compile the backward jump as |
| 2419 // necessary. |
2379 if (info == ALWAYS_TRUE) { | 2420 if (info == ALWAYS_TRUE) { |
2380 if (has_valid_frame()) { | 2421 if (has_valid_frame()) { |
2381 if (node->next() == NULL) { | 2422 if (node->next() == NULL) { |
2382 node->continue_target()->Jump(); | 2423 node->continue_target()->Jump(); |
2383 } else { | 2424 } else { |
2384 body.Jump(); | 2425 loop.Jump(); |
2385 } | 2426 } |
2386 } | 2427 } |
2387 } else { | 2428 } else { |
2388 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. | 2429 ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. |
2389 if (node->continue_target()->is_linked()) { | 2430 if (test_at_bottom) { |
2390 // We can have dangling jumps to the continue target if | 2431 if (node->continue_target()->is_linked()) { |
2391 // there was no update expression. | 2432 // We can have dangling jumps to the continue target if |
2392 node->continue_target()->Bind(); | 2433 // there was no update expression. |
2393 } | 2434 node->continue_target()->Bind(); |
2394 | 2435 } |
2395 // Control can reach the test at the bottom by falling out of | 2436 // Control can reach the test at the bottom by falling out |
2396 // the body, by a continue in the body, or from the update | 2437 // of the body, by a continue in the body, or from the |
2397 // expression. | 2438 // update expression. |
2398 if (has_valid_frame()) { | 2439 if (has_valid_frame()) { |
2399 // The break target is the fall-through (body is a backward | 2440 // The break target is the fall-through (body is a |
2400 // jump from here). | 2441 // backward jump from here). |
2401 ControlDestination dest(&body, node->break_target(), false); | 2442 ControlDestination dest(&body, node->break_target(), false); |
2402 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); | 2443 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
| 2444 } |
| 2445 } else { |
| 2446 // Otherwise, jump back to the test at the top. |
| 2447 if (has_valid_frame()) { |
| 2448 if (node->next() == NULL) { |
| 2449 node->continue_target()->Jump(); |
| 2450 } else { |
| 2451 loop.Jump(); |
| 2452 } |
| 2453 } |
2403 } | 2454 } |
2404 } | 2455 } |
2405 | 2456 |
2406 // The break target may be already bound (by the condition), or | 2457 // The break target may be already bound (by the condition), or |
2407 // there may not be a valid frame. Bind it only if needed. | 2458 // there may not be a valid frame. Bind it only if needed. |
2408 if (node->break_target()->is_linked()) { | 2459 if (node->break_target()->is_linked()) { |
2409 node->break_target()->Bind(); | 2460 node->break_target()->Bind(); |
2410 } | 2461 } |
2411 break; | 2462 break; |
2412 } | 2463 } |
(...skipping 4420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6833 | 6884 |
6834 // Slow-case: Go through the JavaScript implementation. | 6885 // Slow-case: Go through the JavaScript implementation. |
6835 __ bind(&slow); | 6886 __ bind(&slow); |
6836 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6887 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
6837 } | 6888 } |
6838 | 6889 |
6839 | 6890 |
6840 #undef __ | 6891 #undef __ |
6841 | 6892 |
6842 } } // namespace v8::internal | 6893 } } // namespace v8::internal |
OLD | NEW |