| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 2609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2620 PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true); | 2620 PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true); |
| 2621 | 2621 |
| 2622 VisitForControl(expr->expression(), if_true, if_false); | 2622 VisitForControl(expr->expression(), if_true, if_false); |
| 2623 | 2623 |
| 2624 Apply(context_, if_false, if_true); // Labels swapped. | 2624 Apply(context_, if_false, if_true); // Labels swapped. |
| 2625 break; | 2625 break; |
| 2626 } | 2626 } |
| 2627 | 2627 |
| 2628 case Token::TYPEOF: { | 2628 case Token::TYPEOF: { |
| 2629 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 2629 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
| 2630 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 2630 VisitForTypeofValue(expr->expression(), kStack); |
| 2631 if (proxy != NULL && | |
| 2632 !proxy->var()->is_this() && | |
| 2633 proxy->var()->is_global()) { | |
| 2634 Comment cmnt(masm_, "Global variable"); | |
| 2635 __ Move(rcx, proxy->name()); | |
| 2636 __ movq(rax, CodeGenerator::GlobalObject()); | |
| 2637 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | |
| 2638 // Use a regular load, not a contextual load, to avoid a reference | |
| 2639 // error. | |
| 2640 __ Call(ic, RelocInfo::CODE_TARGET); | |
| 2641 __ push(rax); | |
| 2642 } else if (proxy != NULL && | |
| 2643 proxy->var()->slot() != NULL && | |
| 2644 proxy->var()->slot()->type() == Slot::LOOKUP) { | |
| 2645 __ push(rsi); | |
| 2646 __ Push(proxy->name()); | |
| 2647 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | |
| 2648 __ push(rax); | |
| 2649 } else { | |
| 2650 // This expression cannot throw a reference error at the top level. | |
| 2651 VisitForValue(expr->expression(), kStack); | |
| 2652 } | |
| 2653 | |
| 2654 __ CallRuntime(Runtime::kTypeof, 1); | 2631 __ CallRuntime(Runtime::kTypeof, 1); |
| 2655 Apply(context_, rax); | 2632 Apply(context_, rax); |
| 2656 break; | 2633 break; |
| 2657 } | 2634 } |
| 2658 | 2635 |
| 2659 case Token::ADD: { | 2636 case Token::ADD: { |
| 2660 Comment cmt(masm_, "[ UnaryOperation (ADD)"); | 2637 Comment cmt(masm_, "[ UnaryOperation (ADD)"); |
| 2661 VisitForValue(expr->expression(), kAccumulator); | 2638 VisitForValue(expr->expression(), kAccumulator); |
| 2662 Label no_conversion; | 2639 Label no_conversion; |
| 2663 Condition is_smi = masm_->CheckSmi(result_register()); | 2640 Condition is_smi = masm_->CheckSmi(result_register()); |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2881 } | 2858 } |
| 2882 } else { | 2859 } else { |
| 2883 Apply(context_, rax); | 2860 Apply(context_, rax); |
| 2884 } | 2861 } |
| 2885 break; | 2862 break; |
| 2886 } | 2863 } |
| 2887 } | 2864 } |
| 2888 } | 2865 } |
| 2889 | 2866 |
| 2890 | 2867 |
| 2891 void FullCodeGenerator::EmitNullCompare(bool strict, | 2868 void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) { |
| 2892 Register obj, | 2869 VariableProxy* proxy = expr->AsVariableProxy(); |
| 2893 Register null_const, | 2870 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
| 2894 Label* if_true, | 2871 Comment cmnt(masm_, "Global variable"); |
| 2895 Label* if_false, | 2872 __ Move(rcx, proxy->name()); |
| 2896 Register scratch) { | 2873 __ movq(rax, CodeGenerator::GlobalObject()); |
| 2897 __ cmpq(obj, null_const); | 2874 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 2898 if (strict) { | 2875 // Use a regular load, not a contextual load, to avoid a reference |
| 2899 Split(equal, if_true, if_false, NULL); | 2876 // error. |
| 2877 __ Call(ic, RelocInfo::CODE_TARGET); |
| 2878 if (where == kStack) __ push(rax); |
| 2879 } else if (proxy != NULL && |
| 2880 proxy->var()->slot() != NULL && |
| 2881 proxy->var()->slot()->type() == Slot::LOOKUP) { |
| 2882 __ push(rsi); |
| 2883 __ Push(proxy->name()); |
| 2884 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 2885 if (where == kStack) __ push(rax); |
| 2900 } else { | 2886 } else { |
| 2901 __ j(equal, if_true); | 2887 // This expression cannot throw a reference error at the top level. |
| 2902 __ CompareRoot(obj, Heap::kUndefinedValueRootIndex); | 2888 VisitForValue(expr, where); |
| 2903 __ j(equal, if_true); | |
| 2904 __ JumpIfSmi(obj, if_false); | |
| 2905 // It can be an undetectable object. | |
| 2906 __ movq(scratch, FieldOperand(obj, HeapObject::kMapOffset)); | |
| 2907 __ testb(FieldOperand(scratch, Map::kBitFieldOffset), | |
| 2908 Immediate(1 << Map::kIsUndetectable)); | |
| 2909 Split(not_zero, if_true, if_false, NULL); | |
| 2910 } | 2889 } |
| 2911 } | 2890 } |
| 2912 | 2891 |
| 2913 | 2892 |
| 2893 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, |
| 2894 Expression* left, |
| 2895 Expression* right, |
| 2896 Label* if_true, |
| 2897 Label* if_false, |
| 2898 Label* fall_through) { |
| 2899 if (op != Token::EQ && op != Token::EQ_STRICT) return false; |
| 2900 |
| 2901 // Check for the pattern: typeof <expression> == <string literal>. |
| 2902 Literal* right_literal = right->AsLiteral(); |
| 2903 if (right_literal == NULL) return false; |
| 2904 Handle<Object> right_literal_value = right_literal->handle(); |
| 2905 if (!right_literal_value->IsString()) return false; |
| 2906 UnaryOperation* left_unary = left->AsUnaryOperation(); |
| 2907 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
| 2908 Handle<String> check = Handle<String>::cast(right_literal_value); |
| 2909 |
| 2910 VisitForTypeofValue(left_unary->expression(), kAccumulator); |
| 2911 if (check->Equals(Heap::number_symbol())) { |
| 2912 Condition is_smi = masm_->CheckSmi(rax); |
| 2913 __ j(is_smi, if_true); |
| 2914 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
| 2915 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); |
| 2916 Split(equal, if_true, if_false, fall_through); |
| 2917 } else if (check->Equals(Heap::string_symbol())) { |
| 2918 Condition is_smi = masm_->CheckSmi(rax); |
| 2919 __ j(is_smi, if_false); |
| 2920 // Check for undetectable objects => false. |
| 2921 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 2922 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 2923 Immediate(1 << Map::kIsUndetectable)); |
| 2924 __ j(not_zero, if_false); |
| 2925 __ CmpInstanceType(rdx, FIRST_NONSTRING_TYPE); |
| 2926 Split(below, if_true, if_false, fall_through); |
| 2927 } else if (check->Equals(Heap::boolean_symbol())) { |
| 2928 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 2929 __ j(equal, if_true); |
| 2930 __ CompareRoot(rax, Heap::kFalseValueRootIndex); |
| 2931 Split(equal, if_true, if_false, fall_through); |
| 2932 } else if (check->Equals(Heap::undefined_symbol())) { |
| 2933 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 2934 __ j(equal, if_true); |
| 2935 Condition is_smi = masm_->CheckSmi(rax); |
| 2936 __ j(is_smi, if_false); |
| 2937 // Check for undetectable objects => true. |
| 2938 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 2939 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 2940 Immediate(1 << Map::kIsUndetectable)); |
| 2941 Split(not_zero, if_true, if_false, fall_through); |
| 2942 } else if (check->Equals(Heap::function_symbol())) { |
| 2943 Condition is_smi = masm_->CheckSmi(rax); |
| 2944 __ j(is_smi, if_false); |
| 2945 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx); |
| 2946 __ j(equal, if_true); |
| 2947 // Regular expressions => 'function' (they are callable). |
| 2948 __ CmpInstanceType(rdx, JS_REGEXP_TYPE); |
| 2949 Split(equal, if_true, if_false, fall_through); |
| 2950 } else if (check->Equals(Heap::object_symbol())) { |
| 2951 Condition is_smi = masm_->CheckSmi(rax); |
| 2952 __ j(is_smi, if_false); |
| 2953 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 2954 __ j(equal, if_true); |
| 2955 // Regular expressions => 'function', not 'object'. |
| 2956 __ CmpObjectType(rax, JS_REGEXP_TYPE, rdx); |
| 2957 __ j(equal, if_false); |
| 2958 // Check for undetectable objects => false. |
| 2959 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 2960 Immediate(1 << Map::kIsUndetectable)); |
| 2961 __ j(not_zero, if_false); |
| 2962 // Check for JS objects => true. |
| 2963 __ CmpInstanceType(rdx, FIRST_JS_OBJECT_TYPE); |
| 2964 __ j(below, if_false); |
| 2965 __ CmpInstanceType(rdx, LAST_JS_OBJECT_TYPE); |
| 2966 Split(below_equal, if_true, if_false, fall_through); |
| 2967 } else { |
| 2968 if (if_false != fall_through) __ jmp(if_false); |
| 2969 } |
| 2970 |
| 2971 return true; |
| 2972 } |
| 2973 |
| 2974 |
| 2914 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 2975 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 2915 Comment cmnt(masm_, "[ CompareOperation"); | 2976 Comment cmnt(masm_, "[ CompareOperation"); |
| 2916 | 2977 |
| 2917 // Always perform the comparison for its control flow. Pack the result | 2978 // Always perform the comparison for its control flow. Pack the result |
| 2918 // into the expression's context after the comparison is performed. | 2979 // into the expression's context after the comparison is performed. |
| 2919 Label materialize_true, materialize_false; | 2980 Label materialize_true, materialize_false; |
| 2920 Label* if_true = NULL; | 2981 Label* if_true = NULL; |
| 2921 Label* if_false = NULL; | 2982 Label* if_false = NULL; |
| 2922 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); | 2983 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 2923 | 2984 |
| 2985 // First we try a fast inlined version of the compare when one of |
| 2986 // the operands is a literal. |
| 2987 Token::Value op = expr->op(); |
| 2988 Expression* left = expr->left(); |
| 2989 Expression* right = expr->right(); |
| 2990 if (TryLiteralCompare(op, left, right, if_true, if_false, NULL)) { |
| 2991 Apply(context_, if_true, if_false); |
| 2992 return; |
| 2993 } |
| 2994 |
| 2924 VisitForValue(expr->left(), kStack); | 2995 VisitForValue(expr->left(), kStack); |
| 2925 switch (expr->op()) { | 2996 switch (expr->op()) { |
| 2926 case Token::IN: | 2997 case Token::IN: |
| 2927 VisitForValue(expr->right(), kStack); | 2998 VisitForValue(expr->right(), kStack); |
| 2928 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 2999 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 2929 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 3000 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 2930 Split(equal, if_true, if_false, NULL); | 3001 Split(equal, if_true, if_false, NULL); |
| 2931 break; | 3002 break; |
| 2932 | 3003 |
| 2933 case Token::INSTANCEOF: { | 3004 case Token::INSTANCEOF: { |
| 2934 VisitForValue(expr->right(), kStack); | 3005 VisitForValue(expr->right(), kStack); |
| 2935 InstanceofStub stub; | 3006 InstanceofStub stub; |
| 2936 __ CallStub(&stub); | 3007 __ CallStub(&stub); |
| 2937 __ testq(rax, rax); | 3008 __ testq(rax, rax); |
| 2938 // The stub returns 0 for true. | 3009 // The stub returns 0 for true. |
| 2939 Split(zero, if_true, if_false, NULL); | 3010 Split(zero, if_true, if_false, NULL); |
| 2940 break; | 3011 break; |
| 2941 } | 3012 } |
| 2942 | 3013 |
| 2943 default: { | 3014 default: { |
| 2944 VisitForValue(expr->right(), kAccumulator); | 3015 VisitForValue(expr->right(), kAccumulator); |
| 2945 Condition cc = no_condition; | 3016 Condition cc = no_condition; |
| 2946 bool strict = false; | 3017 bool strict = false; |
| 2947 switch (expr->op()) { | 3018 switch (expr->op()) { |
| 2948 case Token::EQ_STRICT: | 3019 case Token::EQ_STRICT: |
| 2949 strict = true; | 3020 strict = true; |
| 2950 // Fall through. | 3021 // Fall through. |
| 2951 case Token::EQ: { | 3022 case Token::EQ: |
| 2952 cc = equal; | 3023 cc = equal; |
| 2953 __ pop(rdx); | 3024 __ pop(rdx); |
| 2954 // If either operand is constant null we do a fast compare | |
| 2955 // against null. | |
| 2956 Literal* right_literal = expr->right()->AsLiteral(); | |
| 2957 Literal* left_literal = expr->left()->AsLiteral(); | |
| 2958 if (right_literal != NULL && right_literal->handle()->IsNull()) { | |
| 2959 EmitNullCompare(strict, rdx, rax, if_true, if_false, rcx); | |
| 2960 Apply(context_, if_true, if_false); | |
| 2961 return; | |
| 2962 } else if (left_literal != NULL && left_literal->handle()->IsNull()) { | |
| 2963 EmitNullCompare(strict, rax, rdx, if_true, if_false, rcx); | |
| 2964 Apply(context_, if_true, if_false); | |
| 2965 return; | |
| 2966 } | |
| 2967 break; | 3025 break; |
| 2968 } | |
| 2969 case Token::LT: | 3026 case Token::LT: |
| 2970 cc = less; | 3027 cc = less; |
| 2971 __ pop(rdx); | 3028 __ pop(rdx); |
| 2972 break; | 3029 break; |
| 2973 case Token::GT: | 3030 case Token::GT: |
| 2974 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 3031 // Reverse left and right sizes to obtain ECMA-262 conversion order. |
| 2975 cc = less; | 3032 cc = less; |
| 2976 __ movq(rdx, result_register()); | 3033 __ movq(rdx, result_register()); |
| 2977 __ pop(rax); | 3034 __ pop(rax); |
| 2978 break; | 3035 break; |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3097 __ ret(0); | 3154 __ ret(0); |
| 3098 } | 3155 } |
| 3099 | 3156 |
| 3100 | 3157 |
| 3101 #undef __ | 3158 #undef __ |
| 3102 | 3159 |
| 3103 | 3160 |
| 3104 } } // namespace v8::internal | 3161 } } // namespace v8::internal |
| 3105 | 3162 |
| 3106 #endif // V8_TARGET_ARCH_X64 | 3163 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |