| 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 |