| 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 |