OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |