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