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 2606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2617 dest->true_target()->Branch(equal); | 2617 dest->true_target()->Branch(equal); |
2618 __ test(operand.reg(), Immediate(kSmiTagMask)); | 2618 __ test(operand.reg(), Immediate(kSmiTagMask)); |
2619 dest->false_target()->Branch(equal); | 2619 dest->false_target()->Branch(equal); |
2620 | 2620 |
2621 // It can be an undetectable object. | 2621 // It can be an undetectable object. |
2622 // Use a scratch register in preference to spilling operand.reg(). | 2622 // Use a scratch register in preference to spilling operand.reg(). |
2623 Result temp = allocator()->Allocate(); | 2623 Result temp = allocator()->Allocate(); |
2624 ASSERT(temp.is_valid()); | 2624 ASSERT(temp.is_valid()); |
2625 __ mov(temp.reg(), | 2625 __ mov(temp.reg(), |
2626 FieldOperand(operand.reg(), HeapObject::kMapOffset)); | 2626 FieldOperand(operand.reg(), HeapObject::kMapOffset)); |
2627 __ movzx_b(temp.reg(), | 2627 __ test_b(FieldOperand(temp.reg(), Map::kBitFieldOffset), |
2628 FieldOperand(temp.reg(), Map::kBitFieldOffset)); | 2628 1 << Map::kIsUndetectable); |
2629 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); | |
2630 temp.Unuse(); | 2629 temp.Unuse(); |
2631 operand.Unuse(); | 2630 operand.Unuse(); |
2632 dest->Split(not_zero); | 2631 dest->Split(not_zero); |
2633 } | 2632 } |
2634 } else if (left_side_constant_1_char_string || | 2633 } else if (left_side_constant_1_char_string || |
2635 right_side_constant_1_char_string) { | 2634 right_side_constant_1_char_string) { |
2636 if (left_side_constant_1_char_string && right_side_constant_1_char_string) { | 2635 if (left_side_constant_1_char_string && right_side_constant_1_char_string) { |
2637 // Trivial case, comparing two constants. | 2636 // Trivial case, comparing two constants. |
2638 int left_value = String::cast(*left_side.handle())->Get(0); | 2637 int left_value = String::cast(*left_side.handle())->Get(0); |
2639 int right_value = String::cast(*right_side.handle())->Get(0); | 2638 int right_value = String::cast(*right_side.handle())->Get(0); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2713 result.ToRegister(); | 2712 result.ToRegister(); |
2714 __ cmp(result.reg(), 0); | 2713 __ cmp(result.reg(), 0); |
2715 result.Unuse(); | 2714 result.Unuse(); |
2716 dest->true_target()->Branch(cc); | 2715 dest->true_target()->Branch(cc); |
2717 dest->false_target()->Jump(); | 2716 dest->false_target()->Jump(); |
2718 | 2717 |
2719 is_string.Bind(&left_side); | 2718 is_string.Bind(&left_side); |
2720 // left_side is a sequential ASCII string. | 2719 // left_side is a sequential ASCII string. |
2721 left_side = Result(left_reg); | 2720 left_side = Result(left_reg); |
2722 right_side = Result(right_val); | 2721 right_side = Result(right_val); |
2723 Result temp2 = allocator_->Allocate(); | |
2724 ASSERT(temp2.is_valid()); | |
2725 // Test string equality and comparison. | 2722 // Test string equality and comparison. |
| 2723 Label comparison_done; |
2726 if (cc == equal) { | 2724 if (cc == equal) { |
2727 Label comparison_done; | |
2728 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), | 2725 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
2729 Immediate(Smi::FromInt(1))); | 2726 Immediate(Smi::FromInt(1))); |
2730 __ j(not_equal, &comparison_done); | 2727 __ j(not_equal, &comparison_done); |
2731 uint8_t char_value = | 2728 uint8_t char_value = |
2732 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); | 2729 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); |
2733 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), | 2730 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), |
2734 char_value); | 2731 char_value); |
2735 __ bind(&comparison_done); | |
2736 } else { | 2732 } else { |
2737 __ mov(temp2.reg(), | 2733 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
2738 FieldOperand(left_side.reg(), String::kLengthOffset)); | 2734 Immediate(Smi::FromInt(1))); |
2739 __ SmiUntag(temp2.reg()); | 2735 // If the length is 0 then the jump is taken and the flags |
2740 __ sub(Operand(temp2.reg()), Immediate(1)); | 2736 // correctly represent being less than the one-character string. |
2741 Label comparison; | 2737 __ j(below, &comparison_done); |
2742 // If the length is 0 then the subtraction gave -1 which compares less | |
2743 // than any character. | |
2744 __ j(negative, &comparison); | |
2745 // Otherwise load the first character. | |
2746 __ movzx_b(temp2.reg(), | |
2747 FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize)); | |
2748 __ bind(&comparison); | |
2749 // Compare the first character of the string with the | 2738 // Compare the first character of the string with the |
2750 // constant 1-character string. | 2739 // constant 1-character string. |
2751 uint8_t char_value = | 2740 uint8_t char_value = |
2752 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); | 2741 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); |
2753 __ cmp(Operand(temp2.reg()), Immediate(char_value)); | 2742 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), |
2754 Label characters_were_different; | 2743 char_value); |
2755 __ j(not_equal, &characters_were_different); | 2744 __ j(not_equal, &comparison_done); |
2756 // If the first character is the same then the long string sorts after | 2745 // If the first character is the same then the long string sorts after |
2757 // the short one. | 2746 // the short one. |
2758 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), | 2747 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
2759 Immediate(Smi::FromInt(1))); | 2748 Immediate(Smi::FromInt(1))); |
2760 __ bind(&characters_were_different); | |
2761 } | 2749 } |
2762 temp2.Unuse(); | 2750 __ bind(&comparison_done); |
2763 left_side.Unuse(); | 2751 left_side.Unuse(); |
2764 right_side.Unuse(); | 2752 right_side.Unuse(); |
2765 dest->Split(cc); | 2753 dest->Split(cc); |
2766 } | 2754 } |
2767 } else { | 2755 } else { |
2768 // Neither side is a constant Smi, constant 1-char string or constant null. | 2756 // Neither side is a constant Smi, constant 1-char string or constant null. |
2769 // If either side is a non-smi constant, or known to be a heap number skip | 2757 // If either side is a non-smi constant, or known to be a heap number skip |
2770 // the smi check. | 2758 // the smi check. |
2771 bool known_non_smi = | 2759 bool known_non_smi = |
2772 (left_side.is_constant() && !left_side.handle()->IsSmi()) || | 2760 (left_side.is_constant() && !left_side.handle()->IsSmi()) || |
(...skipping 1368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4141 // [iteration counter (smi)] <- slot 0 | 4129 // [iteration counter (smi)] <- slot 0 |
4142 // [length of array] <- slot 1 | 4130 // [length of array] <- slot 1 |
4143 // [FixedArray] <- slot 2 | 4131 // [FixedArray] <- slot 2 |
4144 // [Map or 0] <- slot 3 | 4132 // [Map or 0] <- slot 3 |
4145 // [Object] <- slot 4 | 4133 // [Object] <- slot 4 |
4146 | 4134 |
4147 // Check if enumerable is already a JSObject | 4135 // Check if enumerable is already a JSObject |
4148 // eax: value to be iterated over | 4136 // eax: value to be iterated over |
4149 __ test(eax, Immediate(kSmiTagMask)); | 4137 __ test(eax, Immediate(kSmiTagMask)); |
4150 primitive.Branch(zero); | 4138 primitive.Branch(zero); |
4151 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 4139 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
4152 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
4153 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | |
4154 jsobject.Branch(above_equal); | 4140 jsobject.Branch(above_equal); |
4155 | 4141 |
4156 primitive.Bind(); | 4142 primitive.Bind(); |
4157 frame_->EmitPush(eax); | 4143 frame_->EmitPush(eax); |
4158 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); | 4144 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); |
4159 // function call returns the value in eax, which is where we want it below | 4145 // function call returns the value in eax, which is where we want it below |
4160 | 4146 |
4161 jsobject.Bind(); | 4147 jsobject.Bind(); |
4162 // Get the set of properties (as a FixedArray or Map). | 4148 // Get the set of properties (as a FixedArray or Map). |
4163 // eax: value to be iterated over | 4149 // eax: value to be iterated over |
(...skipping 2146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6310 | 6296 |
6311 __ test(obj.reg(), Immediate(kSmiTagMask)); | 6297 __ test(obj.reg(), Immediate(kSmiTagMask)); |
6312 destination()->false_target()->Branch(zero); | 6298 destination()->false_target()->Branch(zero); |
6313 __ cmp(obj.reg(), Factory::null_value()); | 6299 __ cmp(obj.reg(), Factory::null_value()); |
6314 destination()->true_target()->Branch(equal); | 6300 destination()->true_target()->Branch(equal); |
6315 | 6301 |
6316 Result map = allocator()->Allocate(); | 6302 Result map = allocator()->Allocate(); |
6317 ASSERT(map.is_valid()); | 6303 ASSERT(map.is_valid()); |
6318 __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset)); | 6304 __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset)); |
6319 // Undetectable objects behave like undefined when tested with typeof. | 6305 // Undetectable objects behave like undefined when tested with typeof. |
6320 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset)); | 6306 __ test_b(FieldOperand(map.reg(), Map::kBitFieldOffset), |
6321 __ test(map.reg(), Immediate(1 << Map::kIsUndetectable)); | 6307 1 << Map::kIsUndetectable); |
6322 destination()->false_target()->Branch(not_zero); | 6308 destination()->false_target()->Branch(not_zero); |
6323 __ mov(map.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset)); | 6309 // Do a range test for JSObject type. We can't use |
| 6310 // MacroAssembler::IsInstanceJSObjectType, because we are using a |
| 6311 // ControlDestination, so we copy its implementation here. |
6324 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset)); | 6312 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset)); |
6325 __ cmp(map.reg(), FIRST_JS_OBJECT_TYPE); | 6313 __ sub(Operand(map.reg()), Immediate(FIRST_JS_OBJECT_TYPE)); |
6326 destination()->false_target()->Branch(below); | 6314 __ cmp(map.reg(), LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE); |
6327 __ cmp(map.reg(), LAST_JS_OBJECT_TYPE); | |
6328 obj.Unuse(); | 6315 obj.Unuse(); |
6329 map.Unuse(); | 6316 map.Unuse(); |
6330 destination()->Split(below_equal); | 6317 destination()->Split(below_equal); |
6331 } | 6318 } |
6332 | 6319 |
6333 | 6320 |
6334 void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { | 6321 void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { |
6335 // This generates a fast version of: | 6322 // This generates a fast version of: |
6336 // (%_ClassOf(arg) === 'Function') | 6323 // (%_ClassOf(arg) === 'Function') |
6337 ASSERT(args->length() == 1); | 6324 ASSERT(args->length() == 1); |
(...skipping 15 matching lines...) Expand all Loading... |
6353 ASSERT(args->length() == 1); | 6340 ASSERT(args->length() == 1); |
6354 Load(args->at(0)); | 6341 Load(args->at(0)); |
6355 Result obj = frame_->Pop(); | 6342 Result obj = frame_->Pop(); |
6356 obj.ToRegister(); | 6343 obj.ToRegister(); |
6357 __ test(obj.reg(), Immediate(kSmiTagMask)); | 6344 __ test(obj.reg(), Immediate(kSmiTagMask)); |
6358 destination()->false_target()->Branch(zero); | 6345 destination()->false_target()->Branch(zero); |
6359 Result temp = allocator()->Allocate(); | 6346 Result temp = allocator()->Allocate(); |
6360 ASSERT(temp.is_valid()); | 6347 ASSERT(temp.is_valid()); |
6361 __ mov(temp.reg(), | 6348 __ mov(temp.reg(), |
6362 FieldOperand(obj.reg(), HeapObject::kMapOffset)); | 6349 FieldOperand(obj.reg(), HeapObject::kMapOffset)); |
6363 __ movzx_b(temp.reg(), | 6350 __ test_b(FieldOperand(temp.reg(), Map::kBitFieldOffset), |
6364 FieldOperand(temp.reg(), Map::kBitFieldOffset)); | 6351 1 << Map::kIsUndetectable); |
6365 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); | |
6366 obj.Unuse(); | 6352 obj.Unuse(); |
6367 temp.Unuse(); | 6353 temp.Unuse(); |
6368 destination()->Split(not_zero); | 6354 destination()->Split(not_zero); |
6369 } | 6355 } |
6370 | 6356 |
6371 | 6357 |
6372 void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { | 6358 void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { |
6373 ASSERT(args->length() == 0); | 6359 ASSERT(args->length() == 0); |
6374 | 6360 |
6375 // Get the frame pointer for the calling frame. | 6361 // Get the frame pointer for the calling frame. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6429 Result obj = frame_->Pop(); | 6415 Result obj = frame_->Pop(); |
6430 obj.ToRegister(); | 6416 obj.ToRegister(); |
6431 frame_->Spill(obj.reg()); | 6417 frame_->Spill(obj.reg()); |
6432 | 6418 |
6433 // If the object is a smi, we return null. | 6419 // If the object is a smi, we return null. |
6434 __ test(obj.reg(), Immediate(kSmiTagMask)); | 6420 __ test(obj.reg(), Immediate(kSmiTagMask)); |
6435 null.Branch(zero); | 6421 null.Branch(zero); |
6436 | 6422 |
6437 // Check that the object is a JS object but take special care of JS | 6423 // Check that the object is a JS object but take special care of JS |
6438 // functions to make sure they have 'Function' as their class. | 6424 // functions to make sure they have 'Function' as their class. |
6439 { Result tmp = allocator()->Allocate(); | 6425 __ CmpObjectType(obj.reg(), FIRST_JS_OBJECT_TYPE, obj.reg()); |
6440 __ mov(obj.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset)); | 6426 null.Branch(below); |
6441 __ movzx_b(tmp.reg(), FieldOperand(obj.reg(), Map::kInstanceTypeOffset)); | |
6442 __ cmp(tmp.reg(), FIRST_JS_OBJECT_TYPE); | |
6443 null.Branch(below); | |
6444 | 6427 |
6445 // As long as JS_FUNCTION_TYPE is the last instance type and it is | 6428 // As long as JS_FUNCTION_TYPE is the last instance type and it is |
6446 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for | 6429 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for |
6447 // LAST_JS_OBJECT_TYPE. | 6430 // LAST_JS_OBJECT_TYPE. |
6448 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 6431 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
6449 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 6432 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); |
6450 __ cmp(tmp.reg(), JS_FUNCTION_TYPE); | 6433 __ CmpInstanceType(obj.reg(), JS_FUNCTION_TYPE); |
6451 function.Branch(equal); | 6434 function.Branch(equal); |
6452 } | |
6453 | 6435 |
6454 // Check if the constructor in the map is a function. | 6436 // Check if the constructor in the map is a function. |
6455 { Result tmp = allocator()->Allocate(); | 6437 { Result tmp = allocator()->Allocate(); |
6456 __ mov(obj.reg(), FieldOperand(obj.reg(), Map::kConstructorOffset)); | 6438 __ mov(obj.reg(), FieldOperand(obj.reg(), Map::kConstructorOffset)); |
6457 __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, tmp.reg()); | 6439 __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, tmp.reg()); |
6458 non_function_constructor.Branch(not_equal); | 6440 non_function_constructor.Branch(not_equal); |
6459 } | 6441 } |
6460 | 6442 |
6461 // The map register now contains the constructor function. Grab the | 6443 // The map register now contains the constructor function. Grab the |
6462 // instance class name from there. | 6444 // instance class name from there. |
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7023 | 7005 |
7024 DeferredSwapElements* deferred = new DeferredSwapElements(object.reg(), | 7006 DeferredSwapElements* deferred = new DeferredSwapElements(object.reg(), |
7025 index1.reg(), | 7007 index1.reg(), |
7026 index2.reg()); | 7008 index2.reg()); |
7027 | 7009 |
7028 // Fetch the map and check if array is in fast case. | 7010 // Fetch the map and check if array is in fast case. |
7029 // Check that object doesn't require security checks and | 7011 // Check that object doesn't require security checks and |
7030 // has no indexed interceptor. | 7012 // has no indexed interceptor. |
7031 __ CmpObjectType(object.reg(), FIRST_JS_OBJECT_TYPE, tmp1.reg()); | 7013 __ CmpObjectType(object.reg(), FIRST_JS_OBJECT_TYPE, tmp1.reg()); |
7032 deferred->Branch(below); | 7014 deferred->Branch(below); |
7033 __ movzx_b(tmp1.reg(), FieldOperand(tmp1.reg(), Map::kBitFieldOffset)); | 7015 __ test_b(FieldOperand(tmp1.reg(), Map::kBitFieldOffset), |
7034 __ test(tmp1.reg(), Immediate(KeyedLoadIC::kSlowCaseBitFieldMask)); | 7016 KeyedLoadIC::kSlowCaseBitFieldMask); |
7035 deferred->Branch(not_zero); | 7017 deferred->Branch(not_zero); |
7036 | 7018 |
7037 // Check the object's elements are in fast case. | 7019 // Check the object's elements are in fast case. |
7038 __ mov(tmp1.reg(), FieldOperand(object.reg(), JSObject::kElementsOffset)); | 7020 __ mov(tmp1.reg(), FieldOperand(object.reg(), JSObject::kElementsOffset)); |
7039 __ cmp(FieldOperand(tmp1.reg(), HeapObject::kMapOffset), | 7021 __ cmp(FieldOperand(tmp1.reg(), HeapObject::kMapOffset), |
7040 Immediate(Factory::fixed_array_map())); | 7022 Immediate(Factory::fixed_array_map())); |
7041 deferred->Branch(not_equal); | 7023 deferred->Branch(not_equal); |
7042 | 7024 |
7043 // Smi-tagging is equivalent to multiplying by 2. | 7025 // Smi-tagging is equivalent to multiplying by 2. |
7044 STATIC_ASSERT(kSmiTag == 0); | 7026 STATIC_ASSERT(kSmiTag == 0); |
(...skipping 1233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8278 destination()->Split(equal); | 8260 destination()->Split(equal); |
8279 | 8261 |
8280 } else if (check->Equals(Heap::string_symbol())) { | 8262 } else if (check->Equals(Heap::string_symbol())) { |
8281 __ test(answer.reg(), Immediate(kSmiTagMask)); | 8263 __ test(answer.reg(), Immediate(kSmiTagMask)); |
8282 destination()->false_target()->Branch(zero); | 8264 destination()->false_target()->Branch(zero); |
8283 | 8265 |
8284 // It can be an undetectable string object. | 8266 // It can be an undetectable string object. |
8285 Result temp = allocator()->Allocate(); | 8267 Result temp = allocator()->Allocate(); |
8286 ASSERT(temp.is_valid()); | 8268 ASSERT(temp.is_valid()); |
8287 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 8269 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
8288 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset)); | 8270 __ test_b(FieldOperand(temp.reg(), Map::kBitFieldOffset), |
8289 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); | 8271 1 << Map::kIsUndetectable); |
8290 destination()->false_target()->Branch(not_zero); | 8272 destination()->false_target()->Branch(not_zero); |
8291 __ CmpObjectType(answer.reg(), FIRST_NONSTRING_TYPE, temp.reg()); | 8273 __ CmpInstanceType(temp.reg(), FIRST_NONSTRING_TYPE); |
8292 temp.Unuse(); | 8274 temp.Unuse(); |
8293 answer.Unuse(); | 8275 answer.Unuse(); |
8294 destination()->Split(below); | 8276 destination()->Split(below); |
8295 | 8277 |
8296 } else if (check->Equals(Heap::boolean_symbol())) { | 8278 } else if (check->Equals(Heap::boolean_symbol())) { |
8297 __ cmp(answer.reg(), Factory::true_value()); | 8279 __ cmp(answer.reg(), Factory::true_value()); |
8298 destination()->true_target()->Branch(equal); | 8280 destination()->true_target()->Branch(equal); |
8299 __ cmp(answer.reg(), Factory::false_value()); | 8281 __ cmp(answer.reg(), Factory::false_value()); |
8300 answer.Unuse(); | 8282 answer.Unuse(); |
8301 destination()->Split(equal); | 8283 destination()->Split(equal); |
8302 | 8284 |
8303 } else if (check->Equals(Heap::undefined_symbol())) { | 8285 } else if (check->Equals(Heap::undefined_symbol())) { |
8304 __ cmp(answer.reg(), Factory::undefined_value()); | 8286 __ cmp(answer.reg(), Factory::undefined_value()); |
8305 destination()->true_target()->Branch(equal); | 8287 destination()->true_target()->Branch(equal); |
8306 | 8288 |
8307 __ test(answer.reg(), Immediate(kSmiTagMask)); | 8289 __ test(answer.reg(), Immediate(kSmiTagMask)); |
8308 destination()->false_target()->Branch(zero); | 8290 destination()->false_target()->Branch(zero); |
8309 | 8291 |
8310 // It can be an undetectable object. | 8292 // It can be an undetectable object. |
8311 frame_->Spill(answer.reg()); | 8293 frame_->Spill(answer.reg()); |
8312 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 8294 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
8313 __ movzx_b(answer.reg(), | 8295 __ test_b(FieldOperand(answer.reg(), Map::kBitFieldOffset), |
8314 FieldOperand(answer.reg(), Map::kBitFieldOffset)); | 8296 1 << Map::kIsUndetectable); |
8315 __ test(answer.reg(), Immediate(1 << Map::kIsUndetectable)); | |
8316 answer.Unuse(); | 8297 answer.Unuse(); |
8317 destination()->Split(not_zero); | 8298 destination()->Split(not_zero); |
8318 | 8299 |
8319 } else if (check->Equals(Heap::function_symbol())) { | 8300 } else if (check->Equals(Heap::function_symbol())) { |
8320 __ test(answer.reg(), Immediate(kSmiTagMask)); | 8301 __ test(answer.reg(), Immediate(kSmiTagMask)); |
8321 destination()->false_target()->Branch(zero); | 8302 destination()->false_target()->Branch(zero); |
8322 frame_->Spill(answer.reg()); | 8303 frame_->Spill(answer.reg()); |
8323 __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); | 8304 __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); |
8324 destination()->true_target()->Branch(equal); | 8305 destination()->true_target()->Branch(equal); |
8325 // Regular expressions are callable so typeof == 'function'. | 8306 // Regular expressions are callable so typeof == 'function'. |
8326 __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE); | 8307 __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE); |
8327 answer.Unuse(); | 8308 answer.Unuse(); |
8328 destination()->Split(equal); | 8309 destination()->Split(equal); |
8329 } else if (check->Equals(Heap::object_symbol())) { | 8310 } else if (check->Equals(Heap::object_symbol())) { |
8330 __ test(answer.reg(), Immediate(kSmiTagMask)); | 8311 __ test(answer.reg(), Immediate(kSmiTagMask)); |
8331 destination()->false_target()->Branch(zero); | 8312 destination()->false_target()->Branch(zero); |
8332 __ cmp(answer.reg(), Factory::null_value()); | 8313 __ cmp(answer.reg(), Factory::null_value()); |
8333 destination()->true_target()->Branch(equal); | 8314 destination()->true_target()->Branch(equal); |
8334 | 8315 |
8335 Result map = allocator()->Allocate(); | 8316 Result map = allocator()->Allocate(); |
8336 ASSERT(map.is_valid()); | 8317 ASSERT(map.is_valid()); |
8337 // Regular expressions are typeof == 'function', not 'object'. | 8318 // Regular expressions are typeof == 'function', not 'object'. |
8338 __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, map.reg()); | 8319 __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, map.reg()); |
8339 destination()->false_target()->Branch(equal); | 8320 destination()->false_target()->Branch(equal); |
8340 | 8321 |
8341 // It can be an undetectable object. | 8322 // It can be an undetectable object. |
8342 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset)); | 8323 __ test_b(FieldOperand(map.reg(), Map::kBitFieldOffset), |
8343 __ test(map.reg(), Immediate(1 << Map::kIsUndetectable)); | 8324 1 << Map::kIsUndetectable); |
8344 destination()->false_target()->Branch(not_zero); | 8325 destination()->false_target()->Branch(not_zero); |
8345 __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 8326 // Do a range test for JSObject type. We can't use |
| 8327 // MacroAssembler::IsInstanceJSObjectType, because we are using a |
| 8328 // ControlDestination, so we copy its implementation here. |
8346 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset)); | 8329 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset)); |
8347 __ cmp(map.reg(), FIRST_JS_OBJECT_TYPE); | 8330 __ sub(Operand(map.reg()), Immediate(FIRST_JS_OBJECT_TYPE)); |
8348 destination()->false_target()->Branch(below); | 8331 __ cmp(map.reg(), LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE); |
8349 __ cmp(map.reg(), LAST_JS_OBJECT_TYPE); | |
8350 answer.Unuse(); | 8332 answer.Unuse(); |
8351 map.Unuse(); | 8333 map.Unuse(); |
8352 destination()->Split(below_equal); | 8334 destination()->Split(below_equal); |
8353 } else { | 8335 } else { |
8354 // Uncommon case: typeof testing against a string literal that is | 8336 // Uncommon case: typeof testing against a string literal that is |
8355 // never returned from the typeof operator. | 8337 // never returned from the typeof operator. |
8356 answer.Unuse(); | 8338 answer.Unuse(); |
8357 destination()->Goto(false); | 8339 destination()->Goto(false); |
8358 } | 8340 } |
8359 return; | 8341 return; |
(...skipping 906 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9266 | 9248 |
9267 // 'null' => false. | 9249 // 'null' => false. |
9268 __ cmp(eax, Factory::null_value()); | 9250 __ cmp(eax, Factory::null_value()); |
9269 __ j(equal, &false_result); | 9251 __ j(equal, &false_result); |
9270 | 9252 |
9271 // Get the map and type of the heap object. | 9253 // Get the map and type of the heap object. |
9272 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 9254 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
9273 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 9255 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
9274 | 9256 |
9275 // Undetectable => false. | 9257 // Undetectable => false. |
9276 __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset)); | 9258 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), |
9277 __ and_(ebx, 1 << Map::kIsUndetectable); | 9259 1 << Map::kIsUndetectable); |
9278 __ j(not_zero, &false_result); | 9260 __ j(not_zero, &false_result); |
9279 | 9261 |
9280 // JavaScript object => true. | 9262 // JavaScript object => true. |
9281 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 9263 __ CmpInstanceType(edx, FIRST_JS_OBJECT_TYPE); |
9282 __ j(above_equal, &true_result); | 9264 __ j(above_equal, &true_result); |
9283 | 9265 |
9284 // String value => false iff empty. | 9266 // String value => false iff empty. |
9285 __ cmp(ecx, FIRST_NONSTRING_TYPE); | 9267 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE); |
9286 __ j(above_equal, ¬_string); | 9268 __ j(above_equal, ¬_string); |
9287 __ mov(edx, FieldOperand(eax, String::kLengthOffset)); | |
9288 ASSERT(kSmiTag == 0); | 9269 ASSERT(kSmiTag == 0); |
9289 __ test(edx, Operand(edx)); | 9270 __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); |
9290 __ j(zero, &false_result); | 9271 __ j(zero, &false_result); |
9291 __ jmp(&true_result); | 9272 __ jmp(&true_result); |
9292 | 9273 |
9293 __ bind(¬_string); | 9274 __ bind(¬_string); |
9294 // HeapNumber => false iff +0, -0, or NaN. | 9275 // HeapNumber => false iff +0, -0, or NaN. |
9295 __ cmp(edx, Factory::heap_number_map()); | 9276 __ cmp(edx, Factory::heap_number_map()); |
9296 __ j(not_equal, &true_result); | 9277 __ j(not_equal, &true_result); |
9297 __ fldz(); | 9278 __ fldz(); |
9298 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 9279 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
9299 __ FCmp(); | 9280 __ FCmp(); |
(...skipping 2435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11735 __ ret(0); | 11716 __ ret(0); |
11736 | 11717 |
11737 __ bind(¬_smis); | 11718 __ bind(¬_smis); |
11738 } | 11719 } |
11739 | 11720 |
11740 // If either operand is a JSObject or an oddball value, then they are not | 11721 // If either operand is a JSObject or an oddball value, then they are not |
11741 // equal since their pointers are different | 11722 // equal since their pointers are different |
11742 // There is no test for undetectability in strict equality. | 11723 // There is no test for undetectability in strict equality. |
11743 | 11724 |
11744 // Get the type of the first operand. | 11725 // Get the type of the first operand. |
11745 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | |
11746 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
11747 | |
11748 // If the first object is a JS object, we have done pointer comparison. | 11726 // If the first object is a JS object, we have done pointer comparison. |
| 11727 Label first_non_object; |
11749 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 11728 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
11750 Label first_non_object; | 11729 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
11751 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | |
11752 __ j(below, &first_non_object); | 11730 __ j(below, &first_non_object); |
11753 | 11731 |
11754 // Return non-zero (eax is not zero) | 11732 // Return non-zero (eax is not zero) |
11755 Label return_not_equal; | 11733 Label return_not_equal; |
11756 ASSERT(kHeapObjectTag != 0); | 11734 ASSERT(kHeapObjectTag != 0); |
11757 __ bind(&return_not_equal); | 11735 __ bind(&return_not_equal); |
11758 __ ret(0); | 11736 __ ret(0); |
11759 | 11737 |
11760 __ bind(&first_non_object); | 11738 __ bind(&first_non_object); |
11761 // Check for oddballs: true, false, null, undefined. | 11739 // Check for oddballs: true, false, null, undefined. |
11762 __ cmp(ecx, ODDBALL_TYPE); | 11740 __ CmpInstanceType(ecx, ODDBALL_TYPE); |
11763 __ j(equal, &return_not_equal); | 11741 __ j(equal, &return_not_equal); |
11764 | 11742 |
11765 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 11743 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx); |
11766 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
11767 | |
11768 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | |
11769 __ j(above_equal, &return_not_equal); | 11744 __ j(above_equal, &return_not_equal); |
11770 | 11745 |
11771 // Check for oddballs: true, false, null, undefined. | 11746 // Check for oddballs: true, false, null, undefined. |
11772 __ cmp(ecx, ODDBALL_TYPE); | 11747 __ CmpInstanceType(ecx, ODDBALL_TYPE); |
11773 __ j(equal, &return_not_equal); | 11748 __ j(equal, &return_not_equal); |
11774 | 11749 |
11775 // Fall through to the general case. | 11750 // Fall through to the general case. |
11776 } | 11751 } |
11777 __ bind(&slow); | 11752 __ bind(&slow); |
11778 } | 11753 } |
11779 | 11754 |
11780 // Push arguments below the return address. | 11755 // Push arguments below the return address. |
11781 __ pop(ecx); | 11756 __ pop(ecx); |
11782 __ push(eax); | 11757 __ push(eax); |
(...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12404 | 12379 |
12405 | 12380 |
12406 void InstanceofStub::Generate(MacroAssembler* masm) { | 12381 void InstanceofStub::Generate(MacroAssembler* masm) { |
12407 // Get the object - go slow case if it's a smi. | 12382 // Get the object - go slow case if it's a smi. |
12408 Label slow; | 12383 Label slow; |
12409 __ mov(eax, Operand(esp, 2 * kPointerSize)); // 2 ~ return address, function | 12384 __ mov(eax, Operand(esp, 2 * kPointerSize)); // 2 ~ return address, function |
12410 __ test(eax, Immediate(kSmiTagMask)); | 12385 __ test(eax, Immediate(kSmiTagMask)); |
12411 __ j(zero, &slow, not_taken); | 12386 __ j(zero, &slow, not_taken); |
12412 | 12387 |
12413 // Check that the left hand is a JS object. | 12388 // Check that the left hand is a JS object. |
12414 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); // eax - object map | 12389 __ IsObjectJSObjectType(eax, eax, edx, &slow); |
12415 __ movzx_b(ecx, FieldOperand(eax, Map::kInstanceTypeOffset)); // ecx - type | |
12416 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | |
12417 __ j(below, &slow, not_taken); | |
12418 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | |
12419 __ j(above, &slow, not_taken); | |
12420 | 12390 |
12421 // Get the prototype of the function. | 12391 // Get the prototype of the function. |
12422 __ mov(edx, Operand(esp, 1 * kPointerSize)); // 1 ~ return address | 12392 __ mov(edx, Operand(esp, 1 * kPointerSize)); // 1 ~ return address |
12423 // edx is function, eax is map. | 12393 // edx is function, eax is map. |
12424 | 12394 |
12425 // Look up the function and the map in the instanceof cache. | 12395 // Look up the function and the map in the instanceof cache. |
12426 Label miss; | 12396 Label miss; |
12427 ExternalReference roots_address = ExternalReference::roots_address(); | 12397 ExternalReference roots_address = ExternalReference::roots_address(); |
12428 __ mov(ecx, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); | 12398 __ mov(ecx, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
12429 __ cmp(edx, Operand::StaticArray(ecx, times_pointer_size, roots_address)); | 12399 __ cmp(edx, Operand::StaticArray(ecx, times_pointer_size, roots_address)); |
12430 __ j(not_equal, &miss); | 12400 __ j(not_equal, &miss); |
12431 __ mov(ecx, Immediate(Heap::kInstanceofCacheMapRootIndex)); | 12401 __ mov(ecx, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
12432 __ cmp(eax, Operand::StaticArray(ecx, times_pointer_size, roots_address)); | 12402 __ cmp(eax, Operand::StaticArray(ecx, times_pointer_size, roots_address)); |
12433 __ j(not_equal, &miss); | 12403 __ j(not_equal, &miss); |
12434 __ mov(ecx, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 12404 __ mov(ecx, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
12435 __ mov(eax, Operand::StaticArray(ecx, times_pointer_size, roots_address)); | 12405 __ mov(eax, Operand::StaticArray(ecx, times_pointer_size, roots_address)); |
12436 __ ret(2 * kPointerSize); | 12406 __ ret(2 * kPointerSize); |
12437 | 12407 |
12438 __ bind(&miss); | 12408 __ bind(&miss); |
12439 __ TryGetFunctionPrototype(edx, ebx, ecx, &slow); | 12409 __ TryGetFunctionPrototype(edx, ebx, ecx, &slow); |
12440 | 12410 |
12441 // Check that the function prototype is a JS object. | 12411 // Check that the function prototype is a JS object. |
12442 __ test(ebx, Immediate(kSmiTagMask)); | 12412 __ test(ebx, Immediate(kSmiTagMask)); |
12443 __ j(zero, &slow, not_taken); | 12413 __ j(zero, &slow, not_taken); |
12444 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); | 12414 __ IsObjectJSObjectType(ebx, ecx, ecx, &slow); |
12445 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
12446 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | |
12447 __ j(below, &slow, not_taken); | |
12448 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | |
12449 __ j(above, &slow, not_taken); | |
12450 | 12415 |
12451 // Register mapping: | 12416 // Register mapping: |
12452 // eax is object map. | 12417 // eax is object map. |
12453 // edx is function. | 12418 // edx is function. |
12454 // ebx is function prototype. | 12419 // ebx is function prototype. |
12455 __ mov(ecx, Immediate(Heap::kInstanceofCacheMapRootIndex)); | 12420 __ mov(ecx, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
12456 __ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), eax); | 12421 __ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), eax); |
12457 __ mov(ecx, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); | 12422 __ mov(ecx, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
12458 __ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), edx); | 12423 __ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), edx); |
12459 | 12424 |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12874 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 12839 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
12875 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12840 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
12876 __ and_(ecx, kStringRepresentationMask); | 12841 __ and_(ecx, kStringRepresentationMask); |
12877 __ cmp(ecx, kExternalStringTag); | 12842 __ cmp(ecx, kExternalStringTag); |
12878 __ j(equal, &string_add_runtime); | 12843 __ j(equal, &string_add_runtime); |
12879 // Now check if both strings are ascii strings. | 12844 // Now check if both strings are ascii strings. |
12880 // eax: first string | 12845 // eax: first string |
12881 // ebx: length of resulting flat string as a smi | 12846 // ebx: length of resulting flat string as a smi |
12882 // edx: second string | 12847 // edx: second string |
12883 Label non_ascii_string_add_flat_result; | 12848 Label non_ascii_string_add_flat_result; |
| 12849 ASSERT(kStringEncodingMask == kAsciiStringTag); |
12884 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 12850 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
12885 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12851 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); |
12886 ASSERT(kStringEncodingMask == kAsciiStringTag); | |
12887 __ test(ecx, Immediate(kAsciiStringTag)); | |
12888 __ j(zero, &non_ascii_string_add_flat_result); | 12852 __ j(zero, &non_ascii_string_add_flat_result); |
12889 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 12853 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
12890 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12854 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); |
12891 __ test(ecx, Immediate(kAsciiStringTag)); | |
12892 __ j(zero, &string_add_runtime); | 12855 __ j(zero, &string_add_runtime); |
12893 | 12856 |
12894 __ bind(&make_flat_ascii_string); | 12857 __ bind(&make_flat_ascii_string); |
12895 // Both strings are ascii strings. As they are short they are both flat. | 12858 // Both strings are ascii strings. As they are short they are both flat. |
12896 // ebx: length of resulting flat string as a smi | 12859 // ebx: length of resulting flat string as a smi |
12897 __ SmiUntag(ebx); | 12860 __ SmiUntag(ebx); |
12898 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 12861 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); |
12899 // eax: result string | 12862 // eax: result string |
12900 __ mov(ecx, eax); | 12863 __ mov(ecx, eax); |
12901 // Locate first character of result. | 12864 // Locate first character of result. |
(...skipping 20 matching lines...) Expand all Loading... |
12922 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 12885 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
12923 __ IncrementCounter(&Counters::string_add_native, 1); | 12886 __ IncrementCounter(&Counters::string_add_native, 1); |
12924 __ ret(2 * kPointerSize); | 12887 __ ret(2 * kPointerSize); |
12925 | 12888 |
12926 // Handle creating a flat two byte result. | 12889 // Handle creating a flat two byte result. |
12927 // eax: first string - known to be two byte | 12890 // eax: first string - known to be two byte |
12928 // ebx: length of resulting flat string as a smi | 12891 // ebx: length of resulting flat string as a smi |
12929 // edx: second string | 12892 // edx: second string |
12930 __ bind(&non_ascii_string_add_flat_result); | 12893 __ bind(&non_ascii_string_add_flat_result); |
12931 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 12894 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
12932 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12895 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); |
12933 __ and_(ecx, kAsciiStringTag); | |
12934 __ j(not_zero, &string_add_runtime); | 12896 __ j(not_zero, &string_add_runtime); |
12935 // Both strings are two byte strings. As they are short they are both | 12897 // Both strings are two byte strings. As they are short they are both |
12936 // flat. | 12898 // flat. |
12937 __ SmiUntag(ebx); | 12899 __ SmiUntag(ebx); |
12938 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 12900 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); |
12939 // eax: result string | 12901 // eax: result string |
12940 __ mov(ecx, eax); | 12902 __ mov(ecx, eax); |
12941 // Locate first character of result. | 12903 // Locate first character of result. |
12942 __ add(Operand(ecx), | 12904 __ add(Operand(ecx), |
12943 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 12905 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
(...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13492 // tagged as a small integer. | 13454 // tagged as a small integer. |
13493 __ bind(&runtime); | 13455 __ bind(&runtime); |
13494 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 13456 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
13495 } | 13457 } |
13496 | 13458 |
13497 #undef __ | 13459 #undef __ |
13498 | 13460 |
13499 } } // namespace v8::internal | 13461 } } // namespace v8::internal |
13500 | 13462 |
13501 #endif // V8_TARGET_ARCH_IA32 | 13463 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |