| 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 3071 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3082 // If there was no control flow to slow, we can exit early. | 3082 // If there was no control flow to slow, we can exit early. |
| 3083 if (!slow.is_linked()) { | 3083 if (!slow.is_linked()) { |
| 3084 frame_->Push(&value); | 3084 frame_->Push(&value); |
| 3085 return; | 3085 return; |
| 3086 } | 3086 } |
| 3087 | 3087 |
| 3088 done.Jump(&value); | 3088 done.Jump(&value); |
| 3089 | 3089 |
| 3090 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | 3090 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 3091 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); | 3091 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); |
| 3092 // Allocate a fresh register to use as a temp in | 3092 // Only generate the fast case for locals that rewrite to slots. |
| 3093 // ContextSlotOperandCheckExtensions and to hold the result | 3093 // This rules out argument loads. |
| 3094 // value. | 3094 if (potential_slot != NULL) { |
| 3095 value = allocator_->Allocate(); | 3095 // Allocate a fresh register to use as a temp in |
| 3096 ASSERT(value.is_valid()); | 3096 // ContextSlotOperandCheckExtensions and to hold the result |
| 3097 __ mov(value.reg(), | 3097 // value. |
| 3098 ContextSlotOperandCheckExtensions(potential_slot, value, &slow)); | 3098 value = allocator_->Allocate(); |
| 3099 // There is always control flow to slow from | 3099 ASSERT(value.is_valid()); |
| 3100 // ContextSlotOperandCheckExtensions. | 3100 __ mov(value.reg(), |
| 3101 done.Jump(&value); | 3101 ContextSlotOperandCheckExtensions(potential_slot, |
| 3102 value, |
| 3103 &slow)); |
| 3104 // There is always control flow to slow from |
| 3105 // ContextSlotOperandCheckExtensions. |
| 3106 done.Jump(&value); |
| 3107 } |
| 3102 } | 3108 } |
| 3103 | 3109 |
| 3104 slow.Bind(); | 3110 slow.Bind(); |
| 3105 frame_->Push(esi); | 3111 frame_->Push(esi); |
| 3106 frame_->Push(slot->var()->name()); | 3112 frame_->Push(slot->var()->name()); |
| 3107 if (typeof_state == INSIDE_TYPEOF) { | 3113 if (typeof_state == INSIDE_TYPEOF) { |
| 3108 value = | 3114 value = |
| 3109 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3115 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3110 } else { | 3116 } else { |
| 3111 value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 3117 value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3153 | 3159 |
| 3154 | 3160 |
| 3155 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( | 3161 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( |
| 3156 Slot* slot, | 3162 Slot* slot, |
| 3157 TypeofState typeof_state, | 3163 TypeofState typeof_state, |
| 3158 JumpTarget* slow) { | 3164 JumpTarget* slow) { |
| 3159 // Check that no extension objects have been created by calls to | 3165 // Check that no extension objects have been created by calls to |
| 3160 // eval from the current scope to the global scope. | 3166 // eval from the current scope to the global scope. |
| 3161 Result context(esi, this); | 3167 Result context(esi, this); |
| 3162 Result tmp = allocator_->Allocate(); | 3168 Result tmp = allocator_->Allocate(); |
| 3163 ASSERT(tmp.is_valid()); // Called with all non-reserved registers available. | 3169 ASSERT(tmp.is_valid()); // All non-reserved registers were available. |
| 3164 | 3170 |
| 3165 for (Scope* s = scope(); s != NULL; s = s->outer_scope()) { | 3171 Scope* s = scope(); |
| 3172 while (s != NULL) { |
| 3166 if (s->num_heap_slots() > 0) { | 3173 if (s->num_heap_slots() > 0) { |
| 3167 if (s->calls_eval()) { | 3174 if (s->calls_eval()) { |
| 3168 // Check that extension is NULL. | 3175 // Check that extension is NULL. |
| 3169 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX), | 3176 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX), |
| 3170 Immediate(0)); | 3177 Immediate(0)); |
| 3171 slow->Branch(not_equal, not_taken); | 3178 slow->Branch(not_equal, not_taken); |
| 3172 } | 3179 } |
| 3173 // Load next context in chain. | 3180 // Load next context in chain. |
| 3174 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::CLOSURE_INDEX)); | 3181 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::CLOSURE_INDEX)); |
| 3175 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); | 3182 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); |
| 3176 context = tmp; | 3183 context = tmp; |
| 3177 } | 3184 } |
| 3178 // If no outer scope calls eval, we do not need to check more | 3185 // If no outer scope calls eval, we do not need to check more |
| 3179 // context extensions. | 3186 // context extensions. If we have reached an eval scope, we check |
| 3180 if (!s->outer_scope_calls_eval()) break; | 3187 // all extensions from this point. |
| 3188 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; |
| 3189 s = s->outer_scope(); |
| 3190 } |
| 3191 |
| 3192 if (s->is_eval_scope()) { |
| 3193 // Loop up the context chain. There is no frame effect so it is |
| 3194 // safe to use raw labels here. |
| 3195 Label next, fast; |
| 3196 if (!context.reg().is(tmp.reg())) __ mov(tmp.reg(), context.reg()); |
| 3197 __ bind(&next); |
| 3198 // Terminate at global context. |
| 3199 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), |
| 3200 Immediate(Factory::global_context_map())); |
| 3201 __ j(equal, &fast); |
| 3202 // Check that extension is NULL. |
| 3203 __ cmp(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0)); |
| 3204 slow->Branch(not_equal, not_taken); |
| 3205 // Load next context in chain. |
| 3206 __ mov(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX)); |
| 3207 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); |
| 3208 __ jmp(&next); |
| 3209 __ bind(&fast); |
| 3181 } | 3210 } |
| 3182 context.Unuse(); | 3211 context.Unuse(); |
| 3183 tmp.Unuse(); | 3212 tmp.Unuse(); |
| 3184 | 3213 |
| 3185 // All extension objects were empty and it is safe to use a global | 3214 // All extension objects were empty and it is safe to use a global |
| 3186 // load IC call. | 3215 // load IC call. |
| 3187 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3216 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 3188 // Load the global object. | 3217 // Load the global object. |
| 3189 LoadGlobal(); | 3218 LoadGlobal(); |
| 3190 // Setup the name register. All non-reserved registers are available. | 3219 // Setup the name register. All non-reserved registers are available. |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3632 | 3661 |
| 3633 { Reference target(this, node->target()); | 3662 { Reference target(this, node->target()); |
| 3634 if (target.is_illegal()) { | 3663 if (target.is_illegal()) { |
| 3635 // Fool the virtual frame into thinking that we left the assignment's | 3664 // Fool the virtual frame into thinking that we left the assignment's |
| 3636 // value on the frame. | 3665 // value on the frame. |
| 3637 frame_->Push(Smi::FromInt(0)); | 3666 frame_->Push(Smi::FromInt(0)); |
| 3638 return; | 3667 return; |
| 3639 } | 3668 } |
| 3640 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 3669 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 3641 | 3670 |
| 3671 if (node->starts_initialization_block()) { |
| 3672 ASSERT(target.type() == Reference::NAMED || |
| 3673 target.type() == Reference::KEYED); |
| 3674 // Change to slow case in the beginning of an initialization |
| 3675 // block to avoid the quadratic behavior of repeatedly adding |
| 3676 // fast properties. |
| 3677 |
| 3678 // The receiver is the argument to the runtime call. It is the |
| 3679 // first value pushed when the reference was loaded to the |
| 3680 // frame. |
| 3681 frame_->PushElementAt(target.size() - 1); |
| 3682 Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); |
| 3683 } |
| 3642 if (node->op() == Token::ASSIGN || | 3684 if (node->op() == Token::ASSIGN || |
| 3643 node->op() == Token::INIT_VAR || | 3685 node->op() == Token::INIT_VAR || |
| 3644 node->op() == Token::INIT_CONST) { | 3686 node->op() == Token::INIT_CONST) { |
| 3645 Load(node->value()); | 3687 Load(node->value()); |
| 3688 |
| 3646 } else { | 3689 } else { |
| 3647 Literal* literal = node->value()->AsLiteral(); | 3690 Literal* literal = node->value()->AsLiteral(); |
| 3648 Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); | 3691 Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); |
| 3649 // There are two cases where the target is not read in the right hand | 3692 // There are two cases where the target is not read in the right hand |
| 3650 // side, that are easy to test for: the right hand side is a literal, | 3693 // side, that are easy to test for: the right hand side is a literal, |
| 3651 // or the right hand side is a different variable. TakeValue invalidates | 3694 // or the right hand side is a different variable. TakeValue invalidates |
| 3652 // the target, with an implicit promise that it will be written to again | 3695 // the target, with an implicit promise that it will be written to again |
| 3653 // before it is read. | 3696 // before it is read. |
| 3654 if (literal != NULL || (right_var != NULL && right_var != var)) { | 3697 if (literal != NULL || (right_var != NULL && right_var != var)) { |
| 3655 target.TakeValue(NOT_INSIDE_TYPEOF); | 3698 target.TakeValue(NOT_INSIDE_TYPEOF); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3672 } else { | 3715 } else { |
| 3673 CodeForSourcePosition(node->position()); | 3716 CodeForSourcePosition(node->position()); |
| 3674 if (node->op() == Token::INIT_CONST) { | 3717 if (node->op() == Token::INIT_CONST) { |
| 3675 // Dynamic constant initializations must use the function context | 3718 // Dynamic constant initializations must use the function context |
| 3676 // and initialize the actual constant declared. Dynamic variable | 3719 // and initialize the actual constant declared. Dynamic variable |
| 3677 // initializations are simply assignments and use SetValue. | 3720 // initializations are simply assignments and use SetValue. |
| 3678 target.SetValue(CONST_INIT); | 3721 target.SetValue(CONST_INIT); |
| 3679 } else { | 3722 } else { |
| 3680 target.SetValue(NOT_CONST_INIT); | 3723 target.SetValue(NOT_CONST_INIT); |
| 3681 } | 3724 } |
| 3725 if (node->ends_initialization_block()) { |
| 3726 ASSERT(target.type() == Reference::NAMED || |
| 3727 target.type() == Reference::KEYED); |
| 3728 // End of initialization block. Revert to fast case. The |
| 3729 // argument to the runtime call is the receiver, which is the |
| 3730 // first value pushed as part of the reference, which is below |
| 3731 // the lhs value. |
| 3732 frame_->PushElementAt(target.size()); |
| 3733 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
| 3734 } |
| 3682 } | 3735 } |
| 3683 } | 3736 } |
| 3684 } | 3737 } |
| 3685 | 3738 |
| 3686 | 3739 |
| 3687 void CodeGenerator::VisitThrow(Throw* node) { | 3740 void CodeGenerator::VisitThrow(Throw* node) { |
| 3688 Comment cmnt(masm_, "[ Throw"); | 3741 Comment cmnt(masm_, "[ Throw"); |
| 3689 CodeForStatementPosition(node); | 3742 CodeForStatementPosition(node); |
| 3690 | 3743 |
| 3691 Load(node->exception()); | 3744 Load(node->exception()); |
| (...skipping 2187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5879 } | 5932 } |
| 5880 case Token::BIT_OR: | 5933 case Token::BIT_OR: |
| 5881 case Token::BIT_AND: | 5934 case Token::BIT_AND: |
| 5882 case Token::BIT_XOR: | 5935 case Token::BIT_XOR: |
| 5883 case Token::SAR: | 5936 case Token::SAR: |
| 5884 case Token::SHL: | 5937 case Token::SHL: |
| 5885 case Token::SHR: { | 5938 case Token::SHR: { |
| 5886 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); | 5939 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); |
| 5887 FloatingPointHelper::LoadFloatOperands(masm, ecx); | 5940 FloatingPointHelper::LoadFloatOperands(masm, ecx); |
| 5888 | 5941 |
| 5889 Label non_int32_operands, non_smi_result, skip_allocation; | 5942 Label skip_allocation, non_smi_result, operand_conversion_failure; |
| 5943 |
| 5890 // Reserve space for converted numbers. | 5944 // Reserve space for converted numbers. |
| 5891 __ sub(Operand(esp), Immediate(2 * kPointerSize)); | 5945 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
| 5892 | 5946 |
| 5893 // Check if right operand is int32. | 5947 bool use_sse3 = CpuFeatures::IsSupported(CpuFeatures::SSE3); |
| 5894 __ fist_s(Operand(esp, 1 * kPointerSize)); | 5948 if (use_sse3) { |
| 5895 __ fild_s(Operand(esp, 1 * kPointerSize)); | 5949 // Truncate the operands to 32-bit integers and check for |
| 5896 __ fucompp(); | 5950 // exceptions in doing so. |
| 5897 __ fnstsw_ax(); | 5951 CpuFeatures::Scope scope(CpuFeatures::SSE3); |
| 5898 __ sahf(); | 5952 __ fisttp_s(Operand(esp, 0 * kPointerSize)); |
| 5899 __ j(not_zero, &non_int32_operands); | 5953 __ fisttp_s(Operand(esp, 1 * kPointerSize)); |
| 5900 __ j(parity_even, &non_int32_operands); | 5954 __ fnstsw_ax(); |
| 5955 __ test(eax, Immediate(1)); |
| 5956 __ j(not_zero, &operand_conversion_failure); |
| 5957 } else { |
| 5958 // Check if right operand is int32. |
| 5959 __ fist_s(Operand(esp, 0 * kPointerSize)); |
| 5960 __ fild_s(Operand(esp, 0 * kPointerSize)); |
| 5961 __ fucompp(); |
| 5962 __ fnstsw_ax(); |
| 5963 __ sahf(); |
| 5964 __ j(not_zero, &operand_conversion_failure); |
| 5965 __ j(parity_even, &operand_conversion_failure); |
| 5901 | 5966 |
| 5902 // Check if left operand is int32. | 5967 // Check if left operand is int32. |
| 5903 __ fist_s(Operand(esp, 0 * kPointerSize)); | 5968 __ fist_s(Operand(esp, 1 * kPointerSize)); |
| 5904 __ fild_s(Operand(esp, 0 * kPointerSize)); | 5969 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 5905 __ fucompp(); | 5970 __ fucompp(); |
| 5906 __ fnstsw_ax(); | 5971 __ fnstsw_ax(); |
| 5907 __ sahf(); | 5972 __ sahf(); |
| 5908 __ j(not_zero, &non_int32_operands); | 5973 __ j(not_zero, &operand_conversion_failure); |
| 5909 __ j(parity_even, &non_int32_operands); | 5974 __ j(parity_even, &operand_conversion_failure); |
| 5975 } |
| 5910 | 5976 |
| 5911 // Get int32 operands and perform bitop. | 5977 // Get int32 operands and perform bitop. |
| 5978 __ pop(ecx); |
| 5912 __ pop(eax); | 5979 __ pop(eax); |
| 5913 __ pop(ecx); | |
| 5914 switch (op_) { | 5980 switch (op_) { |
| 5915 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; | 5981 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; |
| 5916 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; | 5982 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; |
| 5917 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; | 5983 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; |
| 5918 case Token::SAR: __ sar(eax); break; | 5984 case Token::SAR: __ sar(eax); break; |
| 5919 case Token::SHL: __ shl(eax); break; | 5985 case Token::SHL: __ shl(eax); break; |
| 5920 case Token::SHR: __ shr(eax); break; | 5986 case Token::SHR: __ shr(eax); break; |
| 5921 default: UNREACHABLE(); | 5987 default: UNREACHABLE(); |
| 5922 } | 5988 } |
| 5923 | 5989 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 5951 __ bind(&skip_allocation); | 6017 __ bind(&skip_allocation); |
| 5952 break; | 6018 break; |
| 5953 default: UNREACHABLE(); | 6019 default: UNREACHABLE(); |
| 5954 } | 6020 } |
| 5955 // Store the result in the HeapNumber and return. | 6021 // Store the result in the HeapNumber and return. |
| 5956 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 6022 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
| 5957 __ fild_s(Operand(esp, 1 * kPointerSize)); | 6023 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 5958 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 6024 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 5959 __ ret(2 * kPointerSize); | 6025 __ ret(2 * kPointerSize); |
| 5960 } | 6026 } |
| 5961 __ bind(&non_int32_operands); | 6027 |
| 5962 // Restore stacks and operands before calling runtime. | 6028 // Clear the FPU exception flag and reset the stack before calling |
| 5963 __ ffree(0); | 6029 // the runtime system. |
| 6030 __ bind(&operand_conversion_failure); |
| 5964 __ add(Operand(esp), Immediate(2 * kPointerSize)); | 6031 __ add(Operand(esp), Immediate(2 * kPointerSize)); |
| 6032 if (use_sse3) { |
| 6033 // If we've used the SSE3 instructions for truncating the |
| 6034 // floating point values to integers and it failed, we have a |
| 6035 // pending #IA exception. Clear it. |
| 6036 __ fnclex(); |
| 6037 } else { |
| 6038 // The non-SSE3 variant does early bailout if the right |
| 6039 // operand isn't a 32-bit integer, so we may have a single |
| 6040 // value on the FPU stack we need to get rid of. |
| 6041 __ ffree(0); |
| 6042 } |
| 5965 | 6043 |
| 5966 // SHR should return uint32 - go to runtime for non-smi/negative result. | 6044 // SHR should return uint32 - go to runtime for non-smi/negative result. |
| 5967 if (op_ == Token::SHR) __ bind(&non_smi_result); | 6045 if (op_ == Token::SHR) __ bind(&non_smi_result); |
| 5968 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 6046 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 5969 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 6047 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 5970 break; | 6048 break; |
| 5971 } | 6049 } |
| 5972 default: UNREACHABLE(); break; | 6050 default: UNREACHABLE(); break; |
| 5973 } | 6051 } |
| 5974 | 6052 |
| (...skipping 851 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6826 | 6904 |
| 6827 // Slow-case: Go through the JavaScript implementation. | 6905 // Slow-case: Go through the JavaScript implementation. |
| 6828 __ bind(&slow); | 6906 __ bind(&slow); |
| 6829 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6907 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6830 } | 6908 } |
| 6831 | 6909 |
| 6832 | 6910 |
| 6833 #undef __ | 6911 #undef __ |
| 6834 | 6912 |
| 6835 } } // namespace v8::internal | 6913 } } // namespace v8::internal |
| OLD | NEW |