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

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

Issue 56172: Clean up return statements in the code generator by explicitly... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 8 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 | « src/codegen-ia32.h ('k') | src/jump-target.h » ('j') | 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-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 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 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 frame_->CallRuntime(Runtime::kDebugTrace, 0); 267 frame_->CallRuntime(Runtime::kDebugTrace, 0);
268 // Ignore the return value. 268 // Ignore the return value.
269 } 269 }
270 #endif 270 #endif
271 VisitStatements(body); 271 VisitStatements(body);
272 272
273 // Handle the return from the function. 273 // Handle the return from the function.
274 if (has_valid_frame()) { 274 if (has_valid_frame()) {
275 // If there is a valid frame, control flow can fall off the end of 275 // If there is a valid frame, control flow can fall off the end of
276 // the body. In that case there is an implicit return statement. 276 // the body. In that case there is an implicit return statement.
277 // Compiling a return statement will jump to the return sequence if
278 // it is already generated or generate it if not.
279 ASSERT(!function_return_is_shadowed_); 277 ASSERT(!function_return_is_shadowed_);
280 Literal undefined(Factory::undefined_value()); 278 CodeForReturnPosition(fun);
281 ReturnStatement statement(&undefined); 279 frame_->PrepareForReturn();
282 statement.set_statement_pos(fun->end_position()); 280 Result undefined(Factory::undefined_value(), this);
283 VisitReturnStatement(&statement); 281 if (function_return_.is_bound()) {
282 function_return_.Jump(&undefined);
283 } else {
284 // Though this is a (possibly) backward block, the frames
285 // can only differ on their top element.
286 function_return_.Bind(&undefined, 1);
287 GenerateReturnSequence(&undefined);
288 }
284 } else if (function_return_.is_linked()) { 289 } else if (function_return_.is_linked()) {
285 // If the return target has dangling jumps to it, then we have not 290 // If the return target has dangling jumps to it, then we have not
286 // yet generated the return sequence. This can happen when (a) 291 // yet generated the return sequence. This can happen when (a)
287 // control does not flow off the end of the body so we did not 292 // control does not flow off the end of the body so we did not
288 // compile an artificial return statement just above, and (b) there 293 // compile an artificial return statement just above, and (b) there
289 // are return statements in the body but (c) they are all shadowed. 294 // are return statements in the body but (c) they are all shadowed.
290 // 295 Result return_value(this);
291 // There is no valid frame here but it is safe (also necessary) to 296 // Though this is a (possibly) backward block, the frames can
292 // load the return value into eax. 297 // only differ on their top element.
293 __ mov(eax, Immediate(Factory::undefined_value())); 298 function_return_.Bind(&return_value, 1);
294 function_return_.Bind(); 299 GenerateReturnSequence(&return_value);
295 GenerateReturnSequence();
296 } 300 }
297 } 301 }
298 } 302 }
299 303
300 // Adjust for function-level loop nesting. 304 // Adjust for function-level loop nesting.
301 loop_nesting_ -= fun->loop_nesting(); 305 loop_nesting_ -= fun->loop_nesting();
302 306
303 // Code generation state must be reset. 307 // Code generation state must be reset.
304 ASSERT(state_ == NULL); 308 ASSERT(state_ == NULL);
305 ASSERT(loop_nesting() == 0); 309 ASSERT(loop_nesting() == 0);
(...skipping 1630 matching lines...) Expand 10 before | Expand all | Expand 10 after
1936 Comment cmnt(masm_, "[ BreakStatement"); 1940 Comment cmnt(masm_, "[ BreakStatement");
1937 CodeForStatementPosition(node); 1941 CodeForStatementPosition(node);
1938 node->target()->break_target()->Jump(); 1942 node->target()->break_target()->Jump();
1939 } 1943 }
1940 1944
1941 1945
1942 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { 1946 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
1943 ASSERT(!in_spilled_code()); 1947 ASSERT(!in_spilled_code());
1944 Comment cmnt(masm_, "[ ReturnStatement"); 1948 Comment cmnt(masm_, "[ ReturnStatement");
1945 1949
1950 CodeForStatementPosition(node);
1951 Load(node->expression());
1952 Result return_value = frame_->Pop();
1946 if (function_return_is_shadowed_) { 1953 if (function_return_is_shadowed_) {
1947 // If the function return is shadowed, we spill all information 1954 function_return_.Jump(&return_value);
1948 // and just jump to the label.
1949 VirtualFrame::SpilledScope spilled_scope(this);
1950 CodeForStatementPosition(node);
1951 LoadAndSpill(node->expression());
1952 frame_->EmitPop(eax);
1953 function_return_.Jump();
1954 } else { 1955 } else {
1955 // Load the returned value.
1956 CodeForStatementPosition(node);
1957 Load(node->expression());
1958
1959 // Pop the result from the frame and prepare the frame for
1960 // returning thus making it easier to merge.
1961 Result result = frame_->Pop();
1962 frame_->PrepareForReturn(); 1956 frame_->PrepareForReturn();
1963
1964 // Move the result into register eax where it belongs.
1965 result.ToRegister(eax);
1966 // TODO(203): Instead of explictly calling Unuse on the result, it
1967 // might be better to pass the result to Jump and Bind below.
1968 result.Unuse();
1969
1970 // If the function return label is already bound, we reuse the
1971 // code by jumping to the return site.
1972 if (function_return_.is_bound()) { 1957 if (function_return_.is_bound()) {
1973 function_return_.Jump(); 1958 // If the function return label is already bound we reuse the
1959 // code by jumping to the return site.
1960 function_return_.Jump(&return_value);
1974 } else { 1961 } else {
1975 function_return_.Bind(); 1962 // Though this is a (possibly) backward block, the frames can
1976 GenerateReturnSequence(); 1963 // only differ on their top element.
1964 function_return_.Bind(&return_value, 1);
1965 GenerateReturnSequence(&return_value);
1977 } 1966 }
1978 } 1967 }
1979 } 1968 }
1980 1969
1981 1970
1982 void CodeGenerator::GenerateReturnSequence() { 1971 void CodeGenerator::GenerateReturnSequence(Result* return_value) {
1983 // The return value is a live (but not currently reference counted) 1972 // The return value is a live (but not currently reference counted)
1984 // reference to eax. This is safe because the current frame does not 1973 // reference to eax. This is safe because the current frame does not
1985 // contain a reference to eax (it is prepared for the return by spilling 1974 // contain a reference to eax (it is prepared for the return by spilling
1986 // all registers). 1975 // all registers).
1987 ASSERT(has_valid_frame());
1988 if (FLAG_trace) { 1976 if (FLAG_trace) {
1989 frame_->Push(eax); // Materialize result on the stack. 1977 frame_->Push(return_value);
1990 frame_->CallRuntime(Runtime::kTraceExit, 1); 1978 *return_value = frame_->CallRuntime(Runtime::kTraceExit, 1);
1991 } 1979 }
1980 return_value->ToRegister(eax);
1992 1981
1993 // Add a label for checking the size of the code used for returning. 1982 // Add a label for checking the size of the code used for returning.
1994 Label check_exit_codesize; 1983 Label check_exit_codesize;
1995 __ bind(&check_exit_codesize); 1984 __ bind(&check_exit_codesize);
1996 1985
1997 // Leave the frame and return popping the arguments and the 1986 // Leave the frame and return popping the arguments and the
1998 // receiver. 1987 // receiver.
1999 frame_->Exit(); 1988 frame_->Exit();
2000 __ ret((scope_->num_parameters() + 1) * kPointerSize); 1989 __ ret((scope_->num_parameters() + 1) * kPointerSize);
2001 DeleteFrame(); 1990 DeleteFrame();
(...skipping 912 matching lines...) Expand 10 before | Expand all | Expand 10 after
2914 // The next handler address is on top of the frame. Unlink from 2903 // The next handler address is on top of the frame. Unlink from
2915 // the handler list and drop the rest of this handler from the 2904 // the handler list and drop the rest of this handler from the
2916 // frame. 2905 // frame.
2917 frame_->EmitPop(Operand::StaticVariable(handler_address)); 2906 frame_->EmitPop(Operand::StaticVariable(handler_address));
2918 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 2907 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2919 if (has_unlinks) { 2908 if (has_unlinks) {
2920 exit.Jump(); 2909 exit.Jump();
2921 } 2910 }
2922 } 2911 }
2923 2912
2924 // Generate unlink code for the (formerly) shadowing targets that have been 2913 // Generate unlink code for the (formerly) shadowing targets that
2925 // jumped to. Deallocate each shadow target. 2914 // have been jumped to. Deallocate each shadow target.
2915 Result return_value(this);
2926 for (int i = 0; i < shadows.length(); i++) { 2916 for (int i = 0; i < shadows.length(); i++) {
2927 if (shadows[i]->is_linked()) { 2917 if (shadows[i]->is_linked()) {
2928 // Unlink from try chain; be careful not to destroy the TOS. 2918 // Unlink from try chain; be careful not to destroy the TOS if
2929 shadows[i]->Bind(); 2919 // there is one.
2930 // Because we can be jumping here (to spilled code) from unspilled 2920 if (i == kReturnShadowIndex) {
2931 // code, we need to reestablish a spilled frame at this block. 2921 shadows[i]->Bind(&return_value);
2922 return_value.ToRegister(eax);
2923 } else {
2924 shadows[i]->Bind();
2925 }
2926 // Because we can be jumping here (to spilled code) from
2927 // unspilled code, we need to reestablish a spilled frame at
2928 // this block.
2932 frame_->SpillAll(); 2929 frame_->SpillAll();
2933 2930
2934 // Reload sp from the top handler, because some statements that we 2931 // Reload sp from the top handler, because some statements that we
2935 // break from (eg, for...in) may have left stuff on the stack. 2932 // break from (eg, for...in) may have left stuff on the stack.
2936 __ mov(edx, Operand::StaticVariable(handler_address)); 2933 __ mov(edx, Operand::StaticVariable(handler_address));
2937 const int kNextOffset = StackHandlerConstants::kNextOffset + 2934 const int kNextOffset = StackHandlerConstants::kNextOffset +
2938 StackHandlerConstants::kAddressDisplacement; 2935 StackHandlerConstants::kAddressDisplacement;
2939 __ lea(esp, Operand(edx, kNextOffset)); 2936 __ lea(esp, Operand(edx, kNextOffset));
2940 frame_->Forget(frame_->height() - handler_height); 2937 frame_->Forget(frame_->height() - handler_height);
2941 2938
2942 frame_->EmitPop(Operand::StaticVariable(handler_address)); 2939 frame_->EmitPop(Operand::StaticVariable(handler_address));
2943 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 2940 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2944 // next_sp popped. 2941 // next_sp popped.
2945 2942
2946 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { 2943 if (i == kReturnShadowIndex) {
2947 frame_->PrepareForReturn(); 2944 if (!function_return_is_shadowed_) frame_->PrepareForReturn();
2945 shadows[i]->other_target()->Jump(&return_value);
2946 } else {
2947 shadows[i]->other_target()->Jump();
2948 } 2948 }
2949 shadows[i]->other_target()->Jump();
2950 } 2949 }
2951 delete shadows[i]; 2950 delete shadows[i];
2952 } 2951 }
2953 2952
2954 exit.Bind(); 2953 exit.Bind();
2955 } 2954 }
2956 2955
2957 2956
2958 void CodeGenerator::VisitTryFinally(TryFinally* node) { 2957 void CodeGenerator::VisitTryFinally(TryFinally* node) {
2959 ASSERT(!in_spilled_code()); 2958 ASSERT(!in_spilled_code());
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
3036 if (nof_unlinks > 0) { 3035 if (nof_unlinks > 0) {
3037 finally_block.Jump(); 3036 finally_block.Jump();
3038 } 3037 }
3039 } 3038 }
3040 3039
3041 // Generate code to unlink and set the state for the (formerly) 3040 // Generate code to unlink and set the state for the (formerly)
3042 // shadowing targets that have been jumped to. 3041 // shadowing targets that have been jumped to.
3043 for (int i = 0; i < shadows.length(); i++) { 3042 for (int i = 0; i < shadows.length(); i++) {
3044 if (shadows[i]->is_linked()) { 3043 if (shadows[i]->is_linked()) {
3045 // If we have come from the shadowed return, the return value is 3044 // If we have come from the shadowed return, the return value is
3046 // in (a non-refcounted reference to) eax. We must preserve it 3045 // on the virtual frame. We must preserve it until it is
3047 // until it is pushed. 3046 // pushed.
3048 // 3047 if (i == kReturnShadowIndex) {
3048 Result return_value(this);
3049 shadows[i]->Bind(&return_value);
3050 return_value.ToRegister(eax);
3051 } else {
3052 shadows[i]->Bind();
3053 }
3049 // Because we can be jumping here (to spilled code) from 3054 // Because we can be jumping here (to spilled code) from
3050 // unspilled code, we need to reestablish a spilled frame at 3055 // unspilled code, we need to reestablish a spilled frame at
3051 // this block. 3056 // this block.
3052 shadows[i]->Bind();
3053 frame_->SpillAll(); 3057 frame_->SpillAll();
3054 3058
3055 // Reload sp from the top handler, because some statements that 3059 // Reload sp from the top handler, because some statements that
3056 // we break from (eg, for...in) may have left stuff on the 3060 // we break from (eg, for...in) may have left stuff on the
3057 // stack. 3061 // stack.
3058 __ mov(edx, Operand::StaticVariable(handler_address)); 3062 __ mov(edx, Operand::StaticVariable(handler_address));
3059 const int kNextOffset = StackHandlerConstants::kNextOffset + 3063 const int kNextOffset = StackHandlerConstants::kNextOffset +
3060 StackHandlerConstants::kAddressDisplacement; 3064 StackHandlerConstants::kAddressDisplacement;
3061 __ lea(esp, Operand(edx, kNextOffset)); 3065 __ lea(esp, Operand(edx, kNextOffset));
3062 frame_->Forget(frame_->height() - handler_height); 3066 frame_->Forget(frame_->height() - handler_height);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
3096 if (has_valid_frame()) { 3100 if (has_valid_frame()) {
3097 // Restore state and return value or faked TOS. 3101 // Restore state and return value or faked TOS.
3098 frame_->EmitPop(ecx); 3102 frame_->EmitPop(ecx);
3099 frame_->EmitPop(eax); 3103 frame_->EmitPop(eax);
3100 } 3104 }
3101 3105
3102 // Generate code to jump to the right destination for all used 3106 // Generate code to jump to the right destination for all used
3103 // formerly shadowing targets. Deallocate each shadow target. 3107 // formerly shadowing targets. Deallocate each shadow target.
3104 for (int i = 0; i < shadows.length(); i++) { 3108 for (int i = 0; i < shadows.length(); i++) {
3105 if (has_valid_frame() && shadows[i]->is_bound()) { 3109 if (has_valid_frame() && shadows[i]->is_bound()) {
3106 JumpTarget* original = shadows[i]->other_target(); 3110 BreakTarget* original = shadows[i]->other_target();
3107 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); 3111 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i)));
3108 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { 3112 if (i == kReturnShadowIndex) {
3109 JumpTarget skip(this); 3113 // The return value is (already) in eax.
3110 skip.Branch(not_equal); 3114 Result return_value = allocator_->Allocate(eax);
3111 frame_->PrepareForReturn(); 3115 ASSERT(return_value.is_valid());
3112 original->Jump(); 3116 if (function_return_is_shadowed_) {
3113 skip.Bind(); 3117 original->Branch(equal, &return_value);
3118 } else {
3119 // Branch around the preparation for return which may emit
3120 // code.
3121 JumpTarget skip(this);
3122 skip.Branch(not_equal);
3123 frame_->PrepareForReturn();
3124 original->Jump(&return_value);
3125 skip.Bind();
3126 }
3114 } else { 3127 } else {
3115 original->Branch(equal); 3128 original->Branch(equal);
3116 } 3129 }
3117 } 3130 }
3118 delete shadows[i]; 3131 delete shadows[i];
3119 } 3132 }
3120 3133
3121 if (has_valid_frame()) { 3134 if (has_valid_frame()) {
3122 // Check if we need to rethrow the exception. 3135 // Check if we need to rethrow the exception.
3123 JumpTarget exit(this); 3136 JumpTarget exit(this);
(...skipping 3949 matching lines...) Expand 10 before | Expand all | Expand 10 after
7073 7086
7074 // Slow-case: Go through the JavaScript implementation. 7087 // Slow-case: Go through the JavaScript implementation.
7075 __ bind(&slow); 7088 __ bind(&slow);
7076 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 7089 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
7077 } 7090 }
7078 7091
7079 7092
7080 #undef __ 7093 #undef __
7081 7094
7082 } } // namespace v8::internal 7095 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-ia32.h ('k') | src/jump-target.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698