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

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

Issue 16567: Enable register allocation for return statements. Make sure to... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: '' Created 11 years, 11 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
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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 bool is_eval) 76 bool is_eval)
77 : is_eval_(is_eval), 77 : is_eval_(is_eval),
78 script_(script), 78 script_(script),
79 deferred_(8), 79 deferred_(8),
80 masm_(new MacroAssembler(NULL, buffer_size)), 80 masm_(new MacroAssembler(NULL, buffer_size)),
81 scope_(NULL), 81 scope_(NULL),
82 frame_(NULL), 82 frame_(NULL),
83 allocator_(NULL), 83 allocator_(NULL),
84 cc_reg_(no_condition), 84 cc_reg_(no_condition),
85 state_(NULL), 85 state_(NULL),
86 is_inside_try_(false),
87 break_stack_height_(0), 86 break_stack_height_(0),
88 loop_nesting_(0), 87 loop_nesting_(0),
89 function_return_is_shadowed_(false), 88 function_return_is_shadowed_(false),
90 in_spilled_code_(false) { 89 in_spilled_code_(false) {
91 } 90 }
92 91
93 92
94 void CodeGenerator::SetFrame(VirtualFrame* new_frame) { 93 void CodeGenerator::SetFrame(VirtualFrame* new_frame) {
95 if (has_valid_frame()) { 94 if (has_valid_frame()) {
96 frame_->DetachFromCodeGenerator(); 95 frame_->DetachFromCodeGenerator();
(...skipping 1523 matching lines...) Expand 10 before | Expand all | Expand 10 after
1620 ASSERT(!in_spilled_code()); 1619 ASSERT(!in_spilled_code());
1621 Comment cmnt(masm_, "[ BreakStatement"); 1620 Comment cmnt(masm_, "[ BreakStatement");
1622 CodeForStatement(node); 1621 CodeForStatement(node);
1623 CleanStack(break_stack_height_ - node->target()->break_stack_height()); 1622 CleanStack(break_stack_height_ - node->target()->break_stack_height());
1624 node->target()->break_target()->Jump(); 1623 node->target()->break_target()->Jump();
1625 } 1624 }
1626 1625
1627 1626
1628 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { 1627 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
1629 ASSERT(!in_spilled_code()); 1628 ASSERT(!in_spilled_code());
1630 VirtualFrame::SpilledScope spilled_scope(this);
1631 Comment cmnt(masm_, "[ ReturnStatement"); 1629 Comment cmnt(masm_, "[ ReturnStatement");
1632 CodeForStatement(node);
1633 LoadAndSpill(node->expression());
1634 1630
1635 // Move the function result into eax 1631 if (function_return_is_shadowed_) {
1636 frame_->EmitPop(eax); 1632 // If the function return is shadowed, we spill all information
1637 1633 // and just jump to the label.
1638 // If we're inside a try statement or the return instruction 1634 VirtualFrame::SpilledScope spilled_scope(this);
1639 // sequence has been generated, we just jump to that 1635 CodeForStatement(node);
1640 // point. Otherwise, we generate the return instruction sequence and 1636 LoadAndSpill(node->expression());
1641 // bind the function return label. 1637 frame_->EmitPop(eax);
1642 if (is_inside_try_ || function_return_.is_bound()) {
1643 function_return_.Jump(); 1638 function_return_.Jump();
1644 } else { 1639 } else {
1645 function_return_.Bind(); 1640 // Load the returned value.
1646 if (FLAG_trace) { 1641 CodeForStatement(node);
1647 frame_->EmitPush(eax); // undo the pop(eax) from above 1642 Load(node->expression());
1648 frame_->CallRuntime(Runtime::kTraceExit, 1); 1643
1644 // Pop the result from the frame and prepare the frame for
1645 // returning thus making it easier to merge.
1646 Result result = frame_->Pop();
1647 frame_->PrepareForReturn();
1648
1649 // Move the result into register eax where it belongs.
1650 result.ToRegister(eax);
1651 result.Unuse();
Kevin Millikin (Chromium) 2009/01/07 10:25:12 Since the reference to eax is live in the next bas
1652
1653 // If the function return label is already bound, we reuse the
1654 // code by jumping to the return site.
1655 if (function_return_.is_bound()) {
1656 function_return_.Jump();
1657 } else {
1658 function_return_.Bind();
1659 if (FLAG_trace) {
1660 frame_->EmitPush(eax); // Materialize result on the stack.
Kevin Millikin (Chromium) 2009/01/07 10:25:12 EmitPush assumes the frame is spilled. This shoul
1661 frame_->CallRuntime(Runtime::kTraceExit, 1);
1662 }
1663
1664 // Add a label for checking the size of the code used for returning.
1665 Label check_exit_codesize;
1666 __ bind(&check_exit_codesize);
1667
1668 // Leave the frame and return popping the arguments and the
1669 // receiver.
1670 frame_->Exit();
1671 __ ret((scope_->num_parameters() + 1) * kPointerSize);
1672 DeleteFrame();
1673
1674 // Check that the size of the code used for returning matches what is
1675 // expected by the debugger.
1676 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
1677 __ SizeOfCodeGeneratedSince(&check_exit_codesize));
1649 } 1678 }
1650
1651 // Add a label for checking the size of the code used for returning.
1652 Label check_exit_codesize;
1653 __ bind(&check_exit_codesize);
1654
1655 // Leave the frame and return popping the arguments and the
1656 // receiver.
1657 frame_->Exit();
1658 __ ret((scope_->num_parameters() + 1) * kPointerSize);
1659 DeleteFrame();
1660
1661 // Check that the size of the code used for returning matches what is
1662 // expected by the debugger.
1663 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
1664 __ SizeOfCodeGeneratedSince(&check_exit_codesize));
1665 } 1679 }
1666 } 1680 }
1667 1681
1668 1682
1669 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { 1683 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
1670 ASSERT(!in_spilled_code()); 1684 ASSERT(!in_spilled_code());
1671 Comment cmnt(masm_, "[ WithEnterStatement"); 1685 Comment cmnt(masm_, "[ WithEnterStatement");
1672 CodeForStatement(node); 1686 CodeForStatement(node);
1673 Load(node->expression()); 1687 Load(node->expression());
1674 Result context(this); 1688 Result context(this);
(...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after
2303 2317
2304 // Shadow the jump targets for all escapes from the try block, including 2318 // Shadow the jump targets for all escapes from the try block, including
2305 // returns. During shadowing, the original target is hidden as the 2319 // returns. During shadowing, the original target is hidden as the
2306 // ShadowTarget and operations on the original actually affect the 2320 // ShadowTarget and operations on the original actually affect the
2307 // shadowing target. 2321 // shadowing target.
2308 // 2322 //
2309 // We should probably try to unify the escaping targets and the return 2323 // We should probably try to unify the escaping targets and the return
2310 // target. 2324 // target.
2311 int nof_escapes = node->escaping_targets()->length(); 2325 int nof_escapes = node->escaping_targets()->length();
2312 List<ShadowTarget*> shadows(1 + nof_escapes); 2326 List<ShadowTarget*> shadows(1 + nof_escapes);
2327
2328 // Add the shadow target for the function return.
2329 static const int kReturnShadowIndex = 0;
2313 shadows.Add(new ShadowTarget(&function_return_)); 2330 shadows.Add(new ShadowTarget(&function_return_));
2331 bool function_return_was_shadowed = function_return_is_shadowed_;
2332 function_return_is_shadowed_ = true;
2333 ASSERT(shadows[kReturnShadowIndex]->original_target() == &function_return_);
2334
2335 // Add the remaining shadow targets.
2314 for (int i = 0; i < nof_escapes; i++) { 2336 for (int i = 0; i < nof_escapes; i++) {
2315 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); 2337 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
2316 } 2338 }
2317 bool function_return_was_shadowed = function_return_is_shadowed_;
2318 function_return_is_shadowed_ = true;
2319 2339
2320 // Generate code for the statements in the try block. 2340 // Generate code for the statements in the try block.
2321 { TempAssign<bool> temp(&is_inside_try_, true); 2341 VisitStatementsAndSpill(node->try_block()->statements());
2322 VisitStatementsAndSpill(node->try_block()->statements());
2323 }
2324 2342
2325 // Stop the introduced shadowing and count the number of required unlinks. 2343 // Stop the introduced shadowing and count the number of required unlinks.
2326 // After shadowing stops, the original targets are unshadowed and the 2344 // After shadowing stops, the original targets are unshadowed and the
2327 // ShadowTargets represent the formerly shadowing targets. 2345 // ShadowTargets represent the formerly shadowing targets.
2328 int nof_unlinks = 0; 2346 int nof_unlinks = 0;
2329 for (int i = 0; i <= nof_escapes; i++) { 2347 for (int i = 0; i <= nof_escapes; i++) {
2330 shadows[i]->StopShadowing(); 2348 shadows[i]->StopShadowing();
2331 if (shadows[i]->is_linked()) nof_unlinks++; 2349 if (shadows[i]->is_linked()) nof_unlinks++;
2332 } 2350 }
2333 function_return_is_shadowed_ = function_return_was_shadowed; 2351 function_return_is_shadowed_ = function_return_was_shadowed;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
2370 // break from (eg, for...in) may have left stuff on the stack. 2388 // break from (eg, for...in) may have left stuff on the stack.
2371 __ mov(edx, Operand::StaticVariable(handler_address)); 2389 __ mov(edx, Operand::StaticVariable(handler_address));
2372 const int kNextOffset = StackHandlerConstants::kNextOffset + 2390 const int kNextOffset = StackHandlerConstants::kNextOffset +
2373 StackHandlerConstants::kAddressDisplacement; 2391 StackHandlerConstants::kAddressDisplacement;
2374 __ lea(esp, Operand(edx, kNextOffset)); 2392 __ lea(esp, Operand(edx, kNextOffset));
2375 frame_->Forget(frame_->height() - handler_height); 2393 frame_->Forget(frame_->height() - handler_height);
2376 2394
2377 frame_->EmitPop(Operand::StaticVariable(handler_address)); 2395 frame_->EmitPop(Operand::StaticVariable(handler_address));
2378 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 2396 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2379 // next_sp popped. 2397 // next_sp popped.
2398
2399 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) {
2400 frame_->PrepareForReturn();
2401 }
2380 shadows[i]->original_target()->Jump(); 2402 shadows[i]->original_target()->Jump();
2381 } 2403 }
2382 } 2404 }
2383 2405
2384 exit.Bind(); 2406 exit.Bind();
2385 } 2407 }
2386 2408
2387 2409
2388 void CodeGenerator::VisitTryFinally(TryFinally* node) { 2410 void CodeGenerator::VisitTryFinally(TryFinally* node) {
2389 ASSERT(!in_spilled_code()); 2411 ASSERT(!in_spilled_code());
(...skipping 26 matching lines...) Expand all
2416 2438
2417 // Shadow the jump targets for all escapes from the try block, including 2439 // Shadow the jump targets for all escapes from the try block, including
2418 // returns. During shadowing, the original target is hidden as the 2440 // returns. During shadowing, the original target is hidden as the
2419 // ShadowTarget and operations on the original actually affect the 2441 // ShadowTarget and operations on the original actually affect the
2420 // shadowing target. 2442 // shadowing target.
2421 // 2443 //
2422 // We should probably try to unify the escaping targets and the return 2444 // We should probably try to unify the escaping targets and the return
2423 // target. 2445 // target.
2424 int nof_escapes = node->escaping_targets()->length(); 2446 int nof_escapes = node->escaping_targets()->length();
2425 List<ShadowTarget*> shadows(1 + nof_escapes); 2447 List<ShadowTarget*> shadows(1 + nof_escapes);
2448
2449 // Add the shadow target for the function return.
2450 static const int kReturnShadowIndex = 0;
2426 shadows.Add(new ShadowTarget(&function_return_)); 2451 shadows.Add(new ShadowTarget(&function_return_));
2452 bool function_return_was_shadowed = function_return_is_shadowed_;
2453 function_return_is_shadowed_ = true;
2454 ASSERT(shadows[kReturnShadowIndex]->original_target() == &function_return_);
2455
2456 // Add the remaining shadow targets.
2427 for (int i = 0; i < nof_escapes; i++) { 2457 for (int i = 0; i < nof_escapes; i++) {
2428 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); 2458 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
2429 } 2459 }
2430 bool function_return_was_shadowed = function_return_is_shadowed_;
2431 function_return_is_shadowed_ = true;
2432 2460
2433 // Generate code for the statements in the try block. 2461 // Generate code for the statements in the try block.
2434 { TempAssign<bool> temp(&is_inside_try_, true); 2462 VisitStatementsAndSpill(node->try_block()->statements());
2435 VisitStatementsAndSpill(node->try_block()->statements());
2436 }
2437 2463
2438 // Stop the introduced shadowing and count the number of required unlinks. 2464 // Stop the introduced shadowing and count the number of required unlinks.
2439 // After shadowing stops, the original targets are unshadowed and the 2465 // After shadowing stops, the original targets are unshadowed and the
2440 // ShadowTargets represent the formerly shadowing targets. 2466 // ShadowTargets represent the formerly shadowing targets.
2441 int nof_unlinks = 0; 2467 int nof_unlinks = 0;
2442 for (int i = 0; i <= nof_escapes; i++) { 2468 for (int i = 0; i <= nof_escapes; i++) {
2443 shadows[i]->StopShadowing(); 2469 shadows[i]->StopShadowing();
2444 if (shadows[i]->is_linked()) nof_unlinks++; 2470 if (shadows[i]->is_linked()) nof_unlinks++;
2445 } 2471 }
2446 function_return_is_shadowed_ = function_return_was_shadowed; 2472 function_return_is_shadowed_ = function_return_was_shadowed;
2447 2473
2448 // If we can fall off the end of the try block, set the state on the stack 2474 // If we can fall off the end of the try block, set the state on the stack
2449 // to FALLING. 2475 // to FALLING.
2450 if (has_valid_frame()) { 2476 if (has_valid_frame()) {
2451 frame_->EmitPush(Immediate(Factory::undefined_value())); // fake TOS 2477 frame_->EmitPush(Immediate(Factory::undefined_value())); // fake TOS
2452 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); 2478 __ Set(ecx, Immediate(Smi::FromInt(FALLING)));
2453 if (nof_unlinks > 0) { 2479 if (nof_unlinks > 0) {
2454 unlink.Jump(); 2480 unlink.Jump();
2455 } 2481 }
2456 } 2482 }
2457 2483
2458 // Generate code to set the state for the (formerly) shadowing targets that 2484 // Generate code to set the state for the (formerly) shadowing targets that
2459 // have been jumped to. 2485 // have been jumped to.
2460 for (int i = 0; i <= nof_escapes; i++) { 2486 for (int i = 0; i <= nof_escapes; i++) {
2461 if (shadows[i]->is_linked()) { 2487 if (shadows[i]->is_linked()) {
2462 // Because we can be jumping here (to spilled code) from unspilled 2488 // Because we can be jumping here (to spilled code) from
2463 // code, we need to reestablish a spilled frame at this block. 2489 // unspilled code, we need to reestablish a spilled frame at
2490 // this block.
2464 shadows[i]->Bind(); 2491 shadows[i]->Bind();
2465 frame_->SpillAll(); 2492 frame_->SpillAll();
2466 if (shadows[i]->original_target() == &function_return_) { 2493 if (i == kReturnShadowIndex) {
2467 // If this target shadowed the function return, materialize the 2494 // If this target shadowed the function return, materialize
2468 // return value on the stack. 2495 // the return value on the stack.
2469 frame_->EmitPush(eax); 2496 frame_->EmitPush(eax);
2470 } else { 2497 } else {
2471 // Fake TOS for targets that shadowed breaks and continues. 2498 // Fake TOS for targets that shadowed breaks and continues.
2472 frame_->EmitPush(Immediate(Factory::undefined_value())); 2499 frame_->EmitPush(Immediate(Factory::undefined_value()));
2473 } 2500 }
2474 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); 2501 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i)));
2475 unlink.Jump(); 2502 unlink.Jump();
2476 } 2503 }
2477 } 2504 }
2478 2505
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
2511 VisitStatementsAndSpill(node->finally_block()->statements()); 2538 VisitStatementsAndSpill(node->finally_block()->statements());
2512 2539
2513 break_stack_height_ -= kFinallyStackSize; 2540 break_stack_height_ -= kFinallyStackSize;
2514 if (has_valid_frame()) { 2541 if (has_valid_frame()) {
2515 JumpTarget exit(this); 2542 JumpTarget exit(this);
2516 // Restore state and return value or faked TOS. 2543 // Restore state and return value or faked TOS.
2517 frame_->EmitPop(ecx); 2544 frame_->EmitPop(ecx);
2518 frame_->EmitPop(eax); 2545 frame_->EmitPop(eax);
2519 2546
2520 // Generate code to jump to the right destination for all used 2547 // Generate code to jump to the right destination for all used
2521 // (formerly) shadowing targets. 2548 // formerly shadowing targets.
2522 for (int i = 0; i <= nof_escapes; i++) { 2549 for (int i = 0; i <= nof_escapes; i++) {
2523 if (shadows[i]->is_bound()) { 2550 if (shadows[i]->is_bound()) {
2551 JumpTarget* original = shadows[i]->original_target();
2524 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); 2552 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i)));
2525 shadows[i]->original_target()->Branch(equal); 2553 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) {
2554 JumpTarget skip(this);
2555 skip.Branch(not_equal);
2556 frame_->PrepareForReturn();
2557 original->Jump();
2558 skip.Bind();
2559 } else {
2560 original->Branch(equal);
2561 }
2526 } 2562 }
2527 } 2563 }
2528 2564
2529 // Check if we need to rethrow the exception. 2565 // Check if we need to rethrow the exception.
2530 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); 2566 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING)));
2531 exit.Branch(not_equal); 2567 exit.Branch(not_equal);
2532 2568
2533 // Rethrow exception. 2569 // Rethrow exception.
2534 frame_->EmitPush(eax); // undo pop from above 2570 frame_->EmitPush(eax); // undo pop from above
2535 frame_->CallRuntime(Runtime::kReThrow, 1); 2571 frame_->CallRuntime(Runtime::kReThrow, 1);
(...skipping 1757 matching lines...) Expand 10 before | Expand all | Expand 10 after
4293 SmiComparison(cc, right->AsLiteral()->handle(), strict); 4329 SmiComparison(cc, right->AsLiteral()->handle(), strict);
4294 return; 4330 return;
4295 } 4331 }
4296 4332
4297 Load(left); 4333 Load(left);
4298 Load(right); 4334 Load(right);
4299 Comparison(cc, strict); 4335 Comparison(cc, strict);
4300 } 4336 }
4301 4337
4302 4338
4303 bool CodeGenerator::IsActualFunctionReturn(JumpTarget* target) {
4304 return (target == &function_return_ && !function_return_is_shadowed_);
4305 }
4306
4307
4308 #ifdef DEBUG 4339 #ifdef DEBUG
4309 bool CodeGenerator::HasValidEntryRegisters() { 4340 bool CodeGenerator::HasValidEntryRegisters() {
4310 return (allocator()->count(eax) - frame()->register_count(eax) == 0) 4341 return (allocator()->count(eax) == frame()->register_count(eax))
4311 && (allocator()->count(ebx) - frame()->register_count(ebx) == 0) 4342 && (allocator()->count(ebx) == frame()->register_count(ebx))
4312 && (allocator()->count(ecx) - frame()->register_count(ecx) == 0) 4343 && (allocator()->count(ecx) == frame()->register_count(ecx))
4313 && (allocator()->count(edx) - frame()->register_count(edx) == 0) 4344 && (allocator()->count(edx) == frame()->register_count(edx))
4314 && (allocator()->count(edi) - frame()->register_count(edi) == 0); 4345 && (allocator()->count(edi) == frame()->register_count(edi));
4315 } 4346 }
4316 #endif 4347 #endif
4317 4348
4318 4349
4319 class DeferredReferenceGetKeyedValue: public DeferredCode { 4350 class DeferredReferenceGetKeyedValue: public DeferredCode {
4320 public: 4351 public:
4321 DeferredReferenceGetKeyedValue(CodeGenerator* generator, bool is_global) 4352 DeferredReferenceGetKeyedValue(CodeGenerator* generator, bool is_global)
4322 : DeferredCode(generator), is_global_(is_global) { 4353 : DeferredCode(generator), is_global_(is_global) {
4323 set_comment("[ DeferredReferenceGetKeyedValue"); 4354 set_comment("[ DeferredReferenceGetKeyedValue");
4324 } 4355 }
(...skipping 1619 matching lines...) Expand 10 before | Expand all | Expand 10 after
5944 5975
5945 // Slow-case: Go through the JavaScript implementation. 5976 // Slow-case: Go through the JavaScript implementation.
5946 __ bind(&slow); 5977 __ bind(&slow);
5947 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 5978 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
5948 } 5979 }
5949 5980
5950 5981
5951 #undef __ 5982 #undef __
5952 5983
5953 } } // namespace v8::internal 5984 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-ia32.h ('k') | src/jump-target-ia32.cc » ('j') | src/virtual-frame-ia32.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698