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 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 bool is_builtin = Bootstrapper::IsActive(); | 279 bool is_builtin = Bootstrapper::IsActive(); |
| 280 bool should_trace = | 280 bool should_trace = |
| 281 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; | 281 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; |
| 282 if (should_trace) { | 282 if (should_trace) { |
| 283 frame_->CallRuntime(Runtime::kDebugTrace, 0); | 283 frame_->CallRuntime(Runtime::kDebugTrace, 0); |
| 284 // Ignore the return value. | 284 // Ignore the return value. |
| 285 } | 285 } |
| 286 #endif | 286 #endif |
| 287 VisitStatements(body); | 287 VisitStatements(body); |
| 288 | 288 |
| 289 // Generate a return statement if necessary. A NULL frame indicates | 289 // Handle the return from the function. If there is a valid frame, |
| 290 // that control flow leaves the body on all paths and cannot fall | 290 // control flow can fall off the end of the body. Compiling a return |
| 291 // through. | 291 // statement will jump to the return sequence if it is already |
| 292 // generated or generate it if not. | |
| 292 if (has_valid_frame()) { | 293 if (has_valid_frame()) { |
| 294 ASSERT(!function_return_is_shadowed_); | |
| 293 Literal undefined(Factory::undefined_value()); | 295 Literal undefined(Factory::undefined_value()); |
| 294 ReturnStatement statement(&undefined); | 296 ReturnStatement statement(&undefined); |
| 295 statement.set_statement_pos(fun->end_position()); | 297 statement.set_statement_pos(fun->end_position()); |
| 296 VisitReturnStatement(&statement); | 298 VisitReturnStatement(&statement); |
| 297 } | 299 } |
| 300 | |
| 301 // If the return target has dangling jumps to it, then we have not yet | |
| 302 // generated the return sequence. This can happen when (a) control | |
| 303 // does not flow off the end of the body so we did not compile an | |
| 304 // artificial return statement just above, and (b) there are return | |
| 305 // statements in the body but (c) they are all shadowed. | |
| 306 if (function_return_.is_linked()) { | |
|
Kasper Lund
2009/01/08 06:55:13
Should (or could) this really be an else if?
Kevin Millikin (Chromium)
2009/01/08 09:32:08
(It could and) maybe it should. I've changed it.
| |
| 307 // There is no valid frame here. It is safe (also necessary) to | |
| 308 // load the return value into eax because the frame we will pick up by | |
| 309 // binding the function return target is prepared for the return by | |
| 310 // spilling all registers, and binding it will not generate merge | |
| 311 // code that could use eax. | |
| 312 ASSERT(!has_valid_frame()); | |
| 313 __ mov(eax, Immediate(Factory::undefined_value())); | |
| 314 GenerateReturnSequence(); | |
| 315 } | |
| 298 } | 316 } |
| 299 } | 317 } |
| 300 | 318 |
| 301 // Adjust for function-level loop nesting. | 319 // Adjust for function-level loop nesting. |
| 302 loop_nesting_ -= fun->loop_nesting(); | 320 loop_nesting_ -= fun->loop_nesting(); |
| 303 | 321 |
| 304 // Code generation state must be reset. | 322 // Code generation state must be reset. |
| 305 ASSERT(state_ == NULL); | 323 ASSERT(state_ == NULL); |
| 306 ASSERT(loop_nesting() == 0); | 324 ASSERT(loop_nesting() == 0); |
| 307 ASSERT(!function_return_is_shadowed_); | 325 ASSERT(!function_return_is_shadowed_); |
| (...skipping 1332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1640 result.ToRegister(eax); | 1658 result.ToRegister(eax); |
| 1641 // TODO(): Instead of explictly calling Unuse on the result, it | 1659 // TODO(): Instead of explictly calling Unuse on the result, it |
| 1642 // might be better to pass the result to Jump and Bind below. | 1660 // might be better to pass the result to Jump and Bind below. |
| 1643 result.Unuse(); | 1661 result.Unuse(); |
| 1644 | 1662 |
| 1645 // If the function return label is already bound, we reuse the | 1663 // If the function return label is already bound, we reuse the |
| 1646 // code by jumping to the return site. | 1664 // code by jumping to the return site. |
| 1647 if (function_return_.is_bound()) { | 1665 if (function_return_.is_bound()) { |
| 1648 function_return_.Jump(); | 1666 function_return_.Jump(); |
| 1649 } else { | 1667 } else { |
| 1650 function_return_.Bind(); | 1668 GenerateReturnSequence(); |
| 1651 if (FLAG_trace) { | |
| 1652 frame_->Push(eax); // Materialize result on the stack. | |
| 1653 frame_->CallRuntime(Runtime::kTraceExit, 1); | |
| 1654 } | |
| 1655 | |
| 1656 // Add a label for checking the size of the code used for returning. | |
| 1657 Label check_exit_codesize; | |
| 1658 __ bind(&check_exit_codesize); | |
| 1659 | |
| 1660 // Leave the frame and return popping the arguments and the | |
| 1661 // receiver. | |
| 1662 frame_->Exit(); | |
| 1663 __ ret((scope_->num_parameters() + 1) * kPointerSize); | |
| 1664 DeleteFrame(); | |
| 1665 | |
| 1666 // Check that the size of the code used for returning matches what is | |
| 1667 // expected by the debugger. | |
| 1668 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, | |
| 1669 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); | |
| 1670 } | 1669 } |
| 1671 } | 1670 } |
| 1672 } | 1671 } |
| 1673 | 1672 |
| 1674 | 1673 |
| 1674 void CodeGenerator::GenerateReturnSequence() { | |
| 1675 // The return value is a live (but not currently reference counted) | |
| 1676 // reference to eax. This is safe because the frame we will pick up by | |
| 1677 // binding the function return target does not contain a reference to eax | |
| 1678 // (it is prepared for the return by spilling all registers) and binding | |
| 1679 // will not emit merge code that could potentially use eax. | |
| 1680 function_return_.Bind(); | |
| 1681 if (FLAG_trace) { | |
| 1682 frame_->Push(eax); // Materialize result on the stack. | |
|
Kasper Lund
2009/01/08 06:55:13
Is this really okay when the frame is invalid? Can
Kevin Millikin (Chromium)
2009/01/08 09:32:08
It's OK here because we actually have a valid fram
| |
| 1683 frame_->CallRuntime(Runtime::kTraceExit, 1); | |
| 1684 } | |
| 1685 | |
| 1686 // Add a label for checking the size of the code used for returning. | |
| 1687 Label check_exit_codesize; | |
|
Kasper Lund
2009/01/08 06:55:13
The more I look at this size checking construct, t
Kevin Millikin (Chromium)
2009/01/08 09:32:08
I think it's OK. The label's lifetime ends pretty
| |
| 1688 __ bind(&check_exit_codesize); | |
| 1689 | |
| 1690 // Leave the frame and return popping the arguments and the | |
| 1691 // receiver. | |
| 1692 frame_->Exit(); | |
| 1693 __ ret((scope_->num_parameters() + 1) * kPointerSize); | |
| 1694 DeleteFrame(); | |
| 1695 | |
| 1696 // Check that the size of the code used for returning matches what is | |
| 1697 // expected by the debugger. | |
| 1698 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, | |
| 1699 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); | |
| 1700 } | |
| 1701 | |
| 1702 | |
| 1675 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1703 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1676 ASSERT(!in_spilled_code()); | 1704 ASSERT(!in_spilled_code()); |
| 1677 Comment cmnt(masm_, "[ WithEnterStatement"); | 1705 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1678 CodeForStatement(node); | 1706 CodeForStatement(node); |
| 1679 Load(node->expression()); | 1707 Load(node->expression()); |
| 1680 Result context(this); | 1708 Result context(this); |
| 1681 if (node->is_catch_block()) { | 1709 if (node->is_catch_block()) { |
| 1682 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); | 1710 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); |
| 1683 } else { | 1711 } else { |
| 1684 context = frame_->CallRuntime(Runtime::kPushContext, 1); | 1712 context = frame_->CallRuntime(Runtime::kPushContext, 1); |
| (...skipping 4282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5967 | 5995 |
| 5968 // Slow-case: Go through the JavaScript implementation. | 5996 // Slow-case: Go through the JavaScript implementation. |
| 5969 __ bind(&slow); | 5997 __ bind(&slow); |
| 5970 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5998 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5971 } | 5999 } |
| 5972 | 6000 |
| 5973 | 6001 |
| 5974 #undef __ | 6002 #undef __ |
| 5975 | 6003 |
| 5976 } } // namespace v8::internal | 6004 } } // namespace v8::internal |
| OLD | NEW |