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