| 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 3110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3121 | 3121 |
| 3122 | 3122 |
| 3123 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 3123 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 3124 Comment cmnt(masm_, "[ CompareOperation"); | 3124 Comment cmnt(masm_, "[ CompareOperation"); |
| 3125 | 3125 |
| 3126 // Get the expressions from the node. | 3126 // Get the expressions from the node. |
| 3127 Expression* left = node->left(); | 3127 Expression* left = node->left(); |
| 3128 Expression* right = node->right(); | 3128 Expression* right = node->right(); |
| 3129 Token::Value op = node->op(); | 3129 Token::Value op = node->op(); |
| 3130 | 3130 |
| 3131 // NOTE: To make null checks efficient, we check if either left or | 3131 // To make null checks efficient, we check if either left or right is the |
| 3132 // right is the literal 'null'. If so, we optimize the code by | 3132 // literal 'null'. If so, we optimize the code by inlining a null check |
| 3133 // inlining a null check instead of calling the (very) general | 3133 // instead of calling the (very) general runtime routine for checking |
| 3134 // runtime routine for checking equality. | 3134 // equality. |
| 3135 | |
| 3136 if (op == Token::EQ || op == Token::EQ_STRICT) { | 3135 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 3137 bool left_is_null = | 3136 bool left_is_null = |
| 3138 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 3137 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
| 3139 bool right_is_null = | 3138 bool right_is_null = |
| 3140 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 3139 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
| 3141 // The 'null' value is only equal to 'null' or 'undefined'. | 3140 // The 'null' value can only be equal to 'null' or 'undefined'. |
| 3142 if (left_is_null || right_is_null) { | 3141 if (left_is_null || right_is_null) { |
| 3143 Load(left_is_null ? right : left); | 3142 Load(left_is_null ? right : left); |
| 3144 JumpTarget exit(this); | |
| 3145 JumpTarget undetectable(this); | |
| 3146 frame_->Pop(r0); | 3143 frame_->Pop(r0); |
| 3147 __ cmp(r0, Operand(Factory::null_value())); | 3144 __ cmp(r0, Operand(Factory::null_value())); |
| 3148 | 3145 |
| 3149 // The 'null' value is only equal to 'undefined' if using | 3146 // The 'null' value is only equal to 'undefined' if using non-strict |
| 3150 // non-strict comparisons. | 3147 // comparisons. |
| 3151 if (op != Token::EQ_STRICT) { | 3148 if (op != Token::EQ_STRICT) { |
| 3152 exit.Branch(eq); | 3149 true_target()->Branch(); |
| 3150 |
| 3153 __ cmp(r0, Operand(Factory::undefined_value())); | 3151 __ cmp(r0, Operand(Factory::undefined_value())); |
| 3152 true_target()->Branch(eq); |
| 3154 | 3153 |
| 3155 // NOTE: it can be undetectable object. | |
| 3156 exit.Branch(eq); | |
| 3157 __ tst(r0, Operand(kSmiTagMask)); | 3154 __ tst(r0, Operand(kSmiTagMask)); |
| 3155 false_target()->Branch(eq); |
| 3158 | 3156 |
| 3159 undetectable.Branch(ne); | 3157 // It can be an undetectable object. |
| 3160 false_target()->Jump(); | 3158 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 3161 | 3159 __ ldrb(r0, FieldMemOperand(r0, Map::kBitFieldOffset)); |
| 3162 undetectable.Bind(); | 3160 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable)); |
| 3163 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 3161 __ cmp(r0, Operand(1 << Map::kIsUndetectable)); |
| 3164 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | |
| 3165 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | |
| 3166 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | |
| 3167 } | 3162 } |
| 3168 | 3163 |
| 3169 exit.Bind(); | |
| 3170 | |
| 3171 cc_reg_ = eq; | 3164 cc_reg_ = eq; |
| 3172 return; | 3165 return; |
| 3173 } | 3166 } |
| 3174 } | 3167 } |
| 3175 | 3168 |
| 3176 | 3169 // To make typeof testing for natives implemented in JavaScript really |
| 3177 // NOTE: To make typeof testing for natives implemented in | 3170 // efficient, we generate special code for expressions of the form: |
| 3178 // JavaScript really efficient, we generate special code for | 3171 // 'typeof <expression> == <string>'. |
| 3179 // expressions of the form: 'typeof <expression> == <string>'. | |
| 3180 | |
| 3181 UnaryOperation* operation = left->AsUnaryOperation(); | 3172 UnaryOperation* operation = left->AsUnaryOperation(); |
| 3182 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 3173 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 3183 (operation != NULL && operation->op() == Token::TYPEOF) && | 3174 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 3184 (right->AsLiteral() != NULL && | 3175 (right->AsLiteral() != NULL && |
| 3185 right->AsLiteral()->handle()->IsString())) { | 3176 right->AsLiteral()->handle()->IsString())) { |
| 3186 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 3177 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 3187 | 3178 |
| 3188 // Load the operand, move it to register r1. | 3179 // Load the operand, move it to register r1. |
| 3189 LoadTypeofExpression(operation->expression()); | 3180 LoadTypeofExpression(operation->expression()); |
| 3190 frame_->Pop(r1); | 3181 frame_->Pop(r1); |
| 3191 | 3182 |
| 3192 if (check->Equals(Heap::number_symbol())) { | 3183 if (check->Equals(Heap::number_symbol())) { |
| 3193 __ tst(r1, Operand(kSmiTagMask)); | 3184 __ tst(r1, Operand(kSmiTagMask)); |
| 3194 true_target()->Branch(eq); | 3185 true_target()->Branch(eq); |
| 3195 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3186 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3196 __ cmp(r1, Operand(Factory::heap_number_map())); | 3187 __ cmp(r1, Operand(Factory::heap_number_map())); |
| 3197 cc_reg_ = eq; | 3188 cc_reg_ = eq; |
| 3198 | 3189 |
| 3199 } else if (check->Equals(Heap::string_symbol())) { | 3190 } else if (check->Equals(Heap::string_symbol())) { |
| 3200 __ tst(r1, Operand(kSmiTagMask)); | 3191 __ tst(r1, Operand(kSmiTagMask)); |
| 3201 false_target()->Branch(eq); | 3192 false_target()->Branch(eq); |
| 3202 | 3193 |
| 3203 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3194 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3204 | 3195 |
| 3205 // NOTE: it might be an undetectable string object | 3196 // It can be an undetectable string object. |
| 3206 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | 3197 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); |
| 3207 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | 3198 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); |
| 3208 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | 3199 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); |
| 3209 false_target()->Branch(eq); | 3200 false_target()->Branch(eq); |
| 3210 | 3201 |
| 3211 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 3202 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 3212 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE)); | 3203 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE)); |
| 3213 cc_reg_ = lt; | 3204 cc_reg_ = lt; |
| 3214 | 3205 |
| 3215 } else if (check->Equals(Heap::boolean_symbol())) { | 3206 } else if (check->Equals(Heap::boolean_symbol())) { |
| 3216 __ cmp(r1, Operand(Factory::true_value())); | 3207 __ cmp(r1, Operand(Factory::true_value())); |
| 3217 true_target()->Branch(eq); | 3208 true_target()->Branch(eq); |
| 3218 __ cmp(r1, Operand(Factory::false_value())); | 3209 __ cmp(r1, Operand(Factory::false_value())); |
| 3219 cc_reg_ = eq; | 3210 cc_reg_ = eq; |
| 3220 | 3211 |
| 3221 } else if (check->Equals(Heap::undefined_symbol())) { | 3212 } else if (check->Equals(Heap::undefined_symbol())) { |
| 3222 __ cmp(r1, Operand(Factory::undefined_value())); | 3213 __ cmp(r1, Operand(Factory::undefined_value())); |
| 3223 true_target()->Branch(eq); | 3214 true_target()->Branch(eq); |
| 3224 | 3215 |
| 3225 __ tst(r1, Operand(kSmiTagMask)); | 3216 __ tst(r1, Operand(kSmiTagMask)); |
| 3226 false_target()->Branch(eq); | 3217 false_target()->Branch(eq); |
| 3227 | 3218 |
| 3228 // NOTE: it can be undetectable object. | 3219 // It can be an undetectable object. |
| 3229 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3220 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3230 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | 3221 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); |
| 3231 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | 3222 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); |
| 3232 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | 3223 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); |
| 3233 | 3224 |
| 3234 cc_reg_ = eq; | 3225 cc_reg_ = eq; |
| 3235 | 3226 |
| 3236 } else if (check->Equals(Heap::function_symbol())) { | 3227 } else if (check->Equals(Heap::function_symbol())) { |
| 3237 __ tst(r1, Operand(kSmiTagMask)); | 3228 __ tst(r1, Operand(kSmiTagMask)); |
| 3238 false_target()->Branch(eq); | 3229 false_target()->Branch(eq); |
| 3239 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3230 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3240 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 3231 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 3241 __ cmp(r1, Operand(JS_FUNCTION_TYPE)); | 3232 __ cmp(r1, Operand(JS_FUNCTION_TYPE)); |
| 3242 cc_reg_ = eq; | 3233 cc_reg_ = eq; |
| 3243 | 3234 |
| 3244 } else if (check->Equals(Heap::object_symbol())) { | 3235 } else if (check->Equals(Heap::object_symbol())) { |
| 3245 __ tst(r1, Operand(kSmiTagMask)); | 3236 __ tst(r1, Operand(kSmiTagMask)); |
| 3246 false_target()->Branch(eq); | 3237 false_target()->Branch(eq); |
| 3247 | 3238 |
| 3248 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3239 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3249 __ cmp(r1, Operand(Factory::null_value())); | 3240 __ cmp(r1, Operand(Factory::null_value())); |
| 3250 true_target()->Branch(eq); | 3241 true_target()->Branch(eq); |
| 3251 | 3242 |
| 3252 // NOTE: it might be an undetectable object. | 3243 // It can be an undetectable object. |
| 3253 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset)); | 3244 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset)); |
| 3254 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); | 3245 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); |
| 3255 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); | 3246 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); |
| 3256 false_target()->Branch(eq); | 3247 false_target()->Branch(eq); |
| 3257 | 3248 |
| 3258 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 3249 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 3259 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); | 3250 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); |
| 3260 false_target()->Branch(lt); | 3251 false_target()->Branch(lt); |
| 3261 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE)); | 3252 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE)); |
| 3262 cc_reg_ = le; | 3253 cc_reg_ = le; |
| 3263 | 3254 |
| 3264 } else { | 3255 } else { |
| 3265 // Uncommon case: Typeof testing against a string literal that | 3256 // Uncommon case: typeof testing against a string literal that is |
| 3266 // is never returned from the typeof operator. | 3257 // never returned from the typeof operator. |
| 3267 false_target()->Jump(); | 3258 false_target()->Jump(); |
| 3268 } | 3259 } |
| 3269 return; | 3260 return; |
| 3270 } | 3261 } |
| 3271 | 3262 |
| 3272 Load(left); | 3263 Load(left); |
| 3273 Load(right); | 3264 Load(right); |
| 3274 switch (op) { | 3265 switch (op) { |
| 3275 case Token::EQ: | 3266 case Token::EQ: |
| 3276 Comparison(eq, false); | 3267 Comparison(eq, false); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3384 } | 3375 } |
| 3385 frame->Push(r0); | 3376 frame->Push(r0); |
| 3386 break; | 3377 break; |
| 3387 } | 3378 } |
| 3388 | 3379 |
| 3389 case KEYED: { | 3380 case KEYED: { |
| 3390 // TODO(1241834): Make sure that this it is safe to ignore the | 3381 // TODO(1241834): Make sure that this it is safe to ignore the |
| 3391 // distinction between expressions in a typeof and not in a typeof. | 3382 // distinction between expressions in a typeof and not in a typeof. |
| 3392 Comment cmnt(masm, "[ Load from keyed Property"); | 3383 Comment cmnt(masm, "[ Load from keyed Property"); |
| 3393 ASSERT(property != NULL); | 3384 ASSERT(property != NULL); |
| 3394 // TODO(1224671): Implement inline caching for keyed loads as on ia32. | 3385 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 3395 GetPropertyStub stub; | 3386 |
| 3396 frame->CallStub(&stub, 0); | 3387 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 3388 if (var != NULL) { |
| 3389 ASSERT(var->is_global()); |
| 3390 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 3391 } else { |
| 3392 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 3393 } |
| 3397 frame->Push(r0); | 3394 frame->Push(r0); |
| 3398 break; | 3395 break; |
| 3399 } | 3396 } |
| 3400 | 3397 |
| 3401 default: | 3398 default: |
| 3402 UNREACHABLE(); | 3399 UNREACHABLE(); |
| 3403 } | 3400 } |
| 3404 } | 3401 } |
| 3405 | 3402 |
| 3406 | 3403 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3493 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { | 3490 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { |
| 3494 exit.Bind(); | 3491 exit.Bind(); |
| 3495 } | 3492 } |
| 3496 } | 3493 } |
| 3497 break; | 3494 break; |
| 3498 } | 3495 } |
| 3499 | 3496 |
| 3500 case NAMED: { | 3497 case NAMED: { |
| 3501 Comment cmnt(masm, "[ Store to named Property"); | 3498 Comment cmnt(masm, "[ Store to named Property"); |
| 3502 // Call the appropriate IC code. | 3499 // Call the appropriate IC code. |
| 3500 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 3503 frame->Pop(r0); // value | 3501 frame->Pop(r0); // value |
| 3504 // Setup the name register. | 3502 // Setup the name register. |
| 3505 Handle<String> name(GetName()); | 3503 Handle<String> name(GetName()); |
| 3506 __ mov(r2, Operand(name)); | 3504 __ mov(r2, Operand(name)); |
| 3507 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | |
| 3508 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 3505 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 3509 frame->Push(r0); | 3506 frame->Push(r0); |
| 3510 break; | 3507 break; |
| 3511 } | 3508 } |
| 3512 | 3509 |
| 3513 case KEYED: { | 3510 case KEYED: { |
| 3514 Comment cmnt(masm, "[ Store to keyed Property"); | 3511 Comment cmnt(masm, "[ Store to keyed Property"); |
| 3515 Property* property = expression_->AsProperty(); | 3512 Property* property = expression_->AsProperty(); |
| 3516 ASSERT(property != NULL); | 3513 ASSERT(property != NULL); |
| 3517 __ RecordPosition(property->position()); | 3514 __ RecordPosition(property->position()); |
| 3515 |
| 3516 // Call IC code. |
| 3517 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 3518 // TODO(1222589): Make the IC grab the values from the stack. |
| 3518 frame->Pop(r0); // value | 3519 frame->Pop(r0); // value |
| 3519 SetPropertyStub stub; | 3520 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 3520 frame->CallStub(&stub, 0); | |
| 3521 frame->Push(r0); | 3521 frame->Push(r0); |
| 3522 break; | 3522 break; |
| 3523 } | 3523 } |
| 3524 | 3524 |
| 3525 default: | 3525 default: |
| 3526 UNREACHABLE(); | 3526 UNREACHABLE(); |
| 3527 } | 3527 } |
| 3528 } | 3528 } |
| 3529 | 3529 |
| 3530 | 3530 |
| (...skipping 899 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4430 __ mov(r2, Operand(0)); | 4430 __ mov(r2, Operand(0)); |
| 4431 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); | 4431 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); |
| 4432 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), | 4432 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), |
| 4433 RelocInfo::CODE_TARGET); | 4433 RelocInfo::CODE_TARGET); |
| 4434 } | 4434 } |
| 4435 | 4435 |
| 4436 | 4436 |
| 4437 #undef __ | 4437 #undef __ |
| 4438 | 4438 |
| 4439 } } // namespace v8::internal | 4439 } } // namespace v8::internal |
| OLD | NEW |