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 |