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 887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
898 dest->false_target()->Branch(zero); | 898 dest->false_target()->Branch(zero); |
899 value.Unuse(); | 899 value.Unuse(); |
900 dest->Split(not_zero); | 900 dest->Split(not_zero); |
901 } else if (value.is_number()) { | 901 } else if (value.is_number()) { |
902 Comment cmnt(masm_, "ONLY_NUMBER"); | 902 Comment cmnt(masm_, "ONLY_NUMBER"); |
903 // Fast case if TypeInfo indicates only numbers. | 903 // Fast case if TypeInfo indicates only numbers. |
904 if (FLAG_debug_code) { | 904 if (FLAG_debug_code) { |
905 __ AbortIfNotNumber(value.reg()); | 905 __ AbortIfNotNumber(value.reg()); |
906 } | 906 } |
907 // Smi => false iff zero. | 907 // Smi => false iff zero. |
908 ASSERT(kSmiTag == 0); | 908 STATIC_ASSERT(kSmiTag == 0); |
909 __ test(value.reg(), Operand(value.reg())); | 909 __ test(value.reg(), Operand(value.reg())); |
910 dest->false_target()->Branch(zero); | 910 dest->false_target()->Branch(zero); |
911 __ test(value.reg(), Immediate(kSmiTagMask)); | 911 __ test(value.reg(), Immediate(kSmiTagMask)); |
912 dest->true_target()->Branch(zero); | 912 dest->true_target()->Branch(zero); |
913 __ fldz(); | 913 __ fldz(); |
914 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); | 914 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); |
915 __ FCmp(); | 915 __ FCmp(); |
916 value.Unuse(); | 916 value.Unuse(); |
917 dest->Split(not_zero); | 917 dest->Split(not_zero); |
918 } else { | 918 } else { |
919 // Fast case checks. | 919 // Fast case checks. |
920 // 'false' => false. | 920 // 'false' => false. |
921 __ cmp(value.reg(), Factory::false_value()); | 921 __ cmp(value.reg(), Factory::false_value()); |
922 dest->false_target()->Branch(equal); | 922 dest->false_target()->Branch(equal); |
923 | 923 |
924 // 'true' => true. | 924 // 'true' => true. |
925 __ cmp(value.reg(), Factory::true_value()); | 925 __ cmp(value.reg(), Factory::true_value()); |
926 dest->true_target()->Branch(equal); | 926 dest->true_target()->Branch(equal); |
927 | 927 |
928 // 'undefined' => false. | 928 // 'undefined' => false. |
929 __ cmp(value.reg(), Factory::undefined_value()); | 929 __ cmp(value.reg(), Factory::undefined_value()); |
930 dest->false_target()->Branch(equal); | 930 dest->false_target()->Branch(equal); |
931 | 931 |
932 // Smi => false iff zero. | 932 // Smi => false iff zero. |
933 ASSERT(kSmiTag == 0); | 933 STATIC_ASSERT(kSmiTag == 0); |
934 __ test(value.reg(), Operand(value.reg())); | 934 __ test(value.reg(), Operand(value.reg())); |
935 dest->false_target()->Branch(zero); | 935 dest->false_target()->Branch(zero); |
936 __ test(value.reg(), Immediate(kSmiTagMask)); | 936 __ test(value.reg(), Immediate(kSmiTagMask)); |
937 dest->true_target()->Branch(zero); | 937 dest->true_target()->Branch(zero); |
938 | 938 |
939 // Call the stub for all other cases. | 939 // Call the stub for all other cases. |
940 frame_->Push(&value); // Undo the Pop() from above. | 940 frame_->Push(&value); // Undo the Pop() from above. |
941 ToBooleanStub stub; | 941 ToBooleanStub stub; |
942 Result temp = frame_->CallStub(&stub, 1); | 942 Result temp = frame_->CallStub(&stub, 1); |
943 // Convert the result to a condition code. | 943 // Convert the result to a condition code. |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1162 __ bind(&done); | 1162 __ bind(&done); |
1163 } | 1163 } |
1164 | 1164 |
1165 | 1165 |
1166 static TypeInfo CalculateTypeInfo(TypeInfo operands_type, | 1166 static TypeInfo CalculateTypeInfo(TypeInfo operands_type, |
1167 Token::Value op, | 1167 Token::Value op, |
1168 const Result& right, | 1168 const Result& right, |
1169 const Result& left) { | 1169 const Result& left) { |
1170 // Set TypeInfo of result according to the operation performed. | 1170 // Set TypeInfo of result according to the operation performed. |
1171 // Rely on the fact that smis have a 31 bit payload on ia32. | 1171 // Rely on the fact that smis have a 31 bit payload on ia32. |
1172 ASSERT(kSmiValueSize == 31); | 1172 STATIC_ASSERT(kSmiValueSize == 31); |
1173 switch (op) { | 1173 switch (op) { |
1174 case Token::COMMA: | 1174 case Token::COMMA: |
1175 return right.type_info(); | 1175 return right.type_info(); |
1176 case Token::OR: | 1176 case Token::OR: |
1177 case Token::AND: | 1177 case Token::AND: |
1178 // Result type can be either of the two input types. | 1178 // Result type can be either of the two input types. |
1179 return operands_type; | 1179 return operands_type; |
1180 case Token::BIT_AND: { | 1180 case Token::BIT_AND: { |
1181 // Anding with positive Smis will give you a Smi. | 1181 // Anding with positive Smis will give you a Smi. |
1182 if (right.is_constant() && right.handle()->IsSmi() && | 1182 if (right.is_constant() && right.handle()->IsSmi() && |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1592 Label non_zero_result; | 1592 Label non_zero_result; |
1593 __ test(left->reg(), Operand(left->reg())); | 1593 __ test(left->reg(), Operand(left->reg())); |
1594 __ j(not_zero, &non_zero_result); | 1594 __ j(not_zero, &non_zero_result); |
1595 __ test(right->reg(), Operand(right->reg())); | 1595 __ test(right->reg(), Operand(right->reg())); |
1596 deferred->Branch(negative); | 1596 deferred->Branch(negative); |
1597 __ bind(&non_zero_result); | 1597 __ bind(&non_zero_result); |
1598 } | 1598 } |
1599 // Check for the corner case of dividing the most negative smi by | 1599 // Check for the corner case of dividing the most negative smi by |
1600 // -1. We cannot use the overflow flag, since it is not set by | 1600 // -1. We cannot use the overflow flag, since it is not set by |
1601 // idiv instruction. | 1601 // idiv instruction. |
1602 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 1602 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
1603 __ cmp(eax, 0x40000000); | 1603 __ cmp(eax, 0x40000000); |
1604 deferred->Branch(equal); | 1604 deferred->Branch(equal); |
1605 // Check that the remainder is zero. | 1605 // Check that the remainder is zero. |
1606 __ test(edx, Operand(edx)); | 1606 __ test(edx, Operand(edx)); |
1607 deferred->Branch(not_zero); | 1607 deferred->Branch(not_zero); |
1608 // Tag the result and store it in the quotient register. | 1608 // Tag the result and store it in the quotient register. |
1609 __ SmiTag(eax); | 1609 __ SmiTag(eax); |
1610 deferred->BindExit(); | 1610 deferred->BindExit(); |
1611 left->Unuse(); | 1611 left->Unuse(); |
1612 right->Unuse(); | 1612 right->Unuse(); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1782 deferred->Branch(overflow); | 1782 deferred->Branch(overflow); |
1783 break; | 1783 break; |
1784 | 1784 |
1785 case Token::SUB: | 1785 case Token::SUB: |
1786 __ sub(answer.reg(), Operand(right->reg())); | 1786 __ sub(answer.reg(), Operand(right->reg())); |
1787 deferred->Branch(overflow); | 1787 deferred->Branch(overflow); |
1788 break; | 1788 break; |
1789 | 1789 |
1790 case Token::MUL: { | 1790 case Token::MUL: { |
1791 // If the smi tag is 0 we can just leave the tag on one operand. | 1791 // If the smi tag is 0 we can just leave the tag on one operand. |
1792 ASSERT(kSmiTag == 0); // Adjust code below if not the case. | 1792 STATIC_ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
1793 // Remove smi tag from the left operand (but keep sign). | 1793 // Remove smi tag from the left operand (but keep sign). |
1794 // Left-hand operand has been copied into answer. | 1794 // Left-hand operand has been copied into answer. |
1795 __ SmiUntag(answer.reg()); | 1795 __ SmiUntag(answer.reg()); |
1796 // Do multiplication of smis, leaving result in answer. | 1796 // Do multiplication of smis, leaving result in answer. |
1797 __ imul(answer.reg(), Operand(right->reg())); | 1797 __ imul(answer.reg(), Operand(right->reg())); |
1798 // Go slow on overflows. | 1798 // Go slow on overflows. |
1799 deferred->Branch(overflow); | 1799 deferred->Branch(overflow); |
1800 // Check for negative zero result. If product is zero, and one | 1800 // Check for negative zero result. If product is zero, and one |
1801 // argument is negative, go to slow case. The frame is unchanged | 1801 // argument is negative, go to slow case. The frame is unchanged |
1802 // in this block, so local control flow can use a Label rather | 1802 // in this block, so local control flow can use a Label rather |
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2289 operand->type_info(), | 2289 operand->type_info(), |
2290 smi_value, | 2290 smi_value, |
2291 overwrite_mode); | 2291 overwrite_mode); |
2292 if (!operand->type_info().IsSmi()) { | 2292 if (!operand->type_info().IsSmi()) { |
2293 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2293 __ test(operand->reg(), Immediate(kSmiTagMask)); |
2294 deferred->Branch(not_zero); | 2294 deferred->Branch(not_zero); |
2295 } else if (FLAG_debug_code) { | 2295 } else if (FLAG_debug_code) { |
2296 __ AbortIfNotSmi(operand->reg()); | 2296 __ AbortIfNotSmi(operand->reg()); |
2297 } | 2297 } |
2298 __ mov(answer.reg(), operand->reg()); | 2298 __ mov(answer.reg(), operand->reg()); |
2299 ASSERT(kSmiTag == 0); // adjust code if not the case | 2299 STATIC_ASSERT(kSmiTag == 0); // adjust code if not the case |
2300 // We do no shifts, only the Smi conversion, if shift_value is 1. | 2300 // We do no shifts, only the Smi conversion, if shift_value is 1. |
2301 if (shift_value > 1) { | 2301 if (shift_value > 1) { |
2302 __ shl(answer.reg(), shift_value - 1); | 2302 __ shl(answer.reg(), shift_value - 1); |
2303 } | 2303 } |
2304 // Convert int result to Smi, checking that it is in int range. | 2304 // Convert int result to Smi, checking that it is in int range. |
2305 ASSERT(kSmiTagSize == 1); // adjust code if not the case | 2305 STATIC_ASSERT(kSmiTagSize == 1); // adjust code if not the case |
2306 __ add(answer.reg(), Operand(answer.reg())); | 2306 __ add(answer.reg(), Operand(answer.reg())); |
2307 deferred->Branch(overflow); | 2307 deferred->Branch(overflow); |
2308 deferred->BindExit(); | 2308 deferred->BindExit(); |
2309 operand->Unuse(); | 2309 operand->Unuse(); |
2310 } | 2310 } |
2311 } | 2311 } |
2312 break; | 2312 break; |
2313 | 2313 |
2314 case Token::BIT_OR: | 2314 case Token::BIT_OR: |
2315 case Token::BIT_XOR: | 2315 case Token::BIT_XOR: |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2363 | 2363 |
2364 DeferredInlineSmiOperation* deferred = | 2364 DeferredInlineSmiOperation* deferred = |
2365 new DeferredInlineSmiOperation(op, | 2365 new DeferredInlineSmiOperation(op, |
2366 operand->reg(), | 2366 operand->reg(), |
2367 operand->reg(), | 2367 operand->reg(), |
2368 operand->type_info(), | 2368 operand->type_info(), |
2369 smi_value, | 2369 smi_value, |
2370 overwrite_mode); | 2370 overwrite_mode); |
2371 // Check that lowest log2(value) bits of operand are zero, and test | 2371 // Check that lowest log2(value) bits of operand are zero, and test |
2372 // smi tag at the same time. | 2372 // smi tag at the same time. |
2373 ASSERT_EQ(0, kSmiTag); | 2373 STATIC_ASSERT(kSmiTag == 0); |
2374 ASSERT_EQ(1, kSmiTagSize); | 2374 STATIC_ASSERT(kSmiTagSize == 1); |
2375 __ test(operand->reg(), Immediate(3)); | 2375 __ test(operand->reg(), Immediate(3)); |
2376 deferred->Branch(not_zero); // Branch if non-smi or odd smi. | 2376 deferred->Branch(not_zero); // Branch if non-smi or odd smi. |
2377 __ sar(operand->reg(), 1); | 2377 __ sar(operand->reg(), 1); |
2378 deferred->BindExit(); | 2378 deferred->BindExit(); |
2379 answer = *operand; | 2379 answer = *operand; |
2380 } else { | 2380 } else { |
2381 // Cannot fall through MOD to default case, so we duplicate the | 2381 // Cannot fall through MOD to default case, so we duplicate the |
2382 // default case here. | 2382 // default case here. |
2383 Result constant_operand(value); | 2383 Result constant_operand(value); |
2384 if (reversed) { | 2384 if (reversed) { |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2598 ASSERT(temp.is_valid()); | 2598 ASSERT(temp.is_valid()); |
2599 __ mov(temp.reg(), | 2599 __ mov(temp.reg(), |
2600 FieldOperand(left_side.reg(), HeapObject::kMapOffset)); | 2600 FieldOperand(left_side.reg(), HeapObject::kMapOffset)); |
2601 __ movzx_b(temp.reg(), | 2601 __ movzx_b(temp.reg(), |
2602 FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); | 2602 FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); |
2603 // If we are testing for equality then make use of the symbol shortcut. | 2603 // If we are testing for equality then make use of the symbol shortcut. |
2604 // Check if the right left hand side has the same type as the left hand | 2604 // Check if the right left hand side has the same type as the left hand |
2605 // side (which is always a symbol). | 2605 // side (which is always a symbol). |
2606 if (cc == equal) { | 2606 if (cc == equal) { |
2607 Label not_a_symbol; | 2607 Label not_a_symbol; |
2608 ASSERT(kSymbolTag != 0); | 2608 STATIC_ASSERT(kSymbolTag != 0); |
2609 // Ensure that no non-strings have the symbol bit set. | 2609 // Ensure that no non-strings have the symbol bit set. |
2610 ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE); | 2610 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask); |
2611 __ test(temp.reg(), Immediate(kIsSymbolMask)); // Test the symbol bit. | 2611 __ test(temp.reg(), Immediate(kIsSymbolMask)); // Test the symbol bit. |
2612 __ j(zero, ¬_a_symbol); | 2612 __ j(zero, ¬_a_symbol); |
2613 // They are symbols, so do identity compare. | 2613 // They are symbols, so do identity compare. |
2614 __ cmp(left_side.reg(), right_side.handle()); | 2614 __ cmp(left_side.reg(), right_side.handle()); |
2615 dest->true_target()->Branch(equal); | 2615 dest->true_target()->Branch(equal); |
2616 dest->false_target()->Branch(not_equal); | 2616 dest->false_target()->Branch(not_equal); |
2617 __ bind(¬_a_symbol); | 2617 __ bind(¬_a_symbol); |
2618 } | 2618 } |
2619 // Call the compare stub if the left side is not a flat ascii string. | 2619 // Call the compare stub if the left side is not a flat ascii string. |
2620 __ and_(temp.reg(), | 2620 __ and_(temp.reg(), |
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3144 // esp[2]: applicand. | 3144 // esp[2]: applicand. |
3145 | 3145 |
3146 // Check that the receiver really is a JavaScript object. | 3146 // Check that the receiver really is a JavaScript object. |
3147 __ mov(eax, Operand(esp, 0)); | 3147 __ mov(eax, Operand(esp, 0)); |
3148 __ test(eax, Immediate(kSmiTagMask)); | 3148 __ test(eax, Immediate(kSmiTagMask)); |
3149 __ j(zero, &build_args); | 3149 __ j(zero, &build_args); |
3150 // We allow all JSObjects including JSFunctions. As long as | 3150 // We allow all JSObjects including JSFunctions. As long as |
3151 // JS_FUNCTION_TYPE is the last instance type and it is right | 3151 // JS_FUNCTION_TYPE is the last instance type and it is right |
3152 // after LAST_JS_OBJECT_TYPE, we do not have to check the upper | 3152 // after LAST_JS_OBJECT_TYPE, we do not have to check the upper |
3153 // bound. | 3153 // bound. |
3154 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 3154 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
3155 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 3155 STATIC_ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); |
3156 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 3156 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
3157 __ j(below, &build_args); | 3157 __ j(below, &build_args); |
3158 | 3158 |
3159 // Check that applicand.apply is Function.prototype.apply. | 3159 // Check that applicand.apply is Function.prototype.apply. |
3160 __ mov(eax, Operand(esp, kPointerSize)); | 3160 __ mov(eax, Operand(esp, kPointerSize)); |
3161 __ test(eax, Immediate(kSmiTagMask)); | 3161 __ test(eax, Immediate(kSmiTagMask)); |
3162 __ j(zero, &build_args); | 3162 __ j(zero, &build_args); |
3163 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ecx); | 3163 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ecx); |
3164 __ j(not_equal, &build_args); | 3164 __ j(not_equal, &build_args); |
3165 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); | 3165 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); |
(...skipping 1303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4469 __ mov(eax, Operand::StaticVariable(handler_address)); | 4469 __ mov(eax, Operand::StaticVariable(handler_address)); |
4470 __ cmp(esp, Operand(eax)); | 4470 __ cmp(esp, Operand(eax)); |
4471 __ Assert(equal, "stack pointer should point to top handler"); | 4471 __ Assert(equal, "stack pointer should point to top handler"); |
4472 } | 4472 } |
4473 | 4473 |
4474 // If we can fall off the end of the try block, unlink from try chain. | 4474 // If we can fall off the end of the try block, unlink from try chain. |
4475 if (has_valid_frame()) { | 4475 if (has_valid_frame()) { |
4476 // The next handler address is on top of the frame. Unlink from | 4476 // The next handler address is on top of the frame. Unlink from |
4477 // the handler list and drop the rest of this handler from the | 4477 // the handler list and drop the rest of this handler from the |
4478 // frame. | 4478 // frame. |
4479 ASSERT(StackHandlerConstants::kNextOffset == 0); | 4479 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
4480 frame_->EmitPop(Operand::StaticVariable(handler_address)); | 4480 frame_->EmitPop(Operand::StaticVariable(handler_address)); |
4481 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 4481 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
4482 if (has_unlinks) { | 4482 if (has_unlinks) { |
4483 exit.Jump(); | 4483 exit.Jump(); |
4484 } | 4484 } |
4485 } | 4485 } |
4486 | 4486 |
4487 // Generate unlink code for the (formerly) shadowing targets that | 4487 // Generate unlink code for the (formerly) shadowing targets that |
4488 // have been jumped to. Deallocate each shadow target. | 4488 // have been jumped to. Deallocate each shadow target. |
4489 Result return_value; | 4489 Result return_value; |
(...skipping 10 matching lines...) Expand all Loading... |
4500 // Because we can be jumping here (to spilled code) from | 4500 // Because we can be jumping here (to spilled code) from |
4501 // unspilled code, we need to reestablish a spilled frame at | 4501 // unspilled code, we need to reestablish a spilled frame at |
4502 // this block. | 4502 // this block. |
4503 frame_->SpillAll(); | 4503 frame_->SpillAll(); |
4504 | 4504 |
4505 // Reload sp from the top handler, because some statements that we | 4505 // Reload sp from the top handler, because some statements that we |
4506 // break from (eg, for...in) may have left stuff on the stack. | 4506 // break from (eg, for...in) may have left stuff on the stack. |
4507 __ mov(esp, Operand::StaticVariable(handler_address)); | 4507 __ mov(esp, Operand::StaticVariable(handler_address)); |
4508 frame_->Forget(frame_->height() - handler_height); | 4508 frame_->Forget(frame_->height() - handler_height); |
4509 | 4509 |
4510 ASSERT(StackHandlerConstants::kNextOffset == 0); | 4510 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
4511 frame_->EmitPop(Operand::StaticVariable(handler_address)); | 4511 frame_->EmitPop(Operand::StaticVariable(handler_address)); |
4512 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 4512 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
4513 | 4513 |
4514 if (i == kReturnShadowIndex) { | 4514 if (i == kReturnShadowIndex) { |
4515 if (!function_return_is_shadowed_) frame_->PrepareForReturn(); | 4515 if (!function_return_is_shadowed_) frame_->PrepareForReturn(); |
4516 shadows[i]->other_target()->Jump(&return_value); | 4516 shadows[i]->other_target()->Jump(&return_value); |
4517 } else { | 4517 } else { |
4518 shadows[i]->other_target()->Jump(); | 4518 shadows[i]->other_target()->Jump(); |
4519 } | 4519 } |
4520 } | 4520 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4586 } | 4586 } |
4587 function_return_is_shadowed_ = function_return_was_shadowed; | 4587 function_return_is_shadowed_ = function_return_was_shadowed; |
4588 | 4588 |
4589 // Get an external reference to the handler address. | 4589 // Get an external reference to the handler address. |
4590 ExternalReference handler_address(Top::k_handler_address); | 4590 ExternalReference handler_address(Top::k_handler_address); |
4591 | 4591 |
4592 // If we can fall off the end of the try block, unlink from the try | 4592 // If we can fall off the end of the try block, unlink from the try |
4593 // chain and set the state on the frame to FALLING. | 4593 // chain and set the state on the frame to FALLING. |
4594 if (has_valid_frame()) { | 4594 if (has_valid_frame()) { |
4595 // The next handler address is on top of the frame. | 4595 // The next handler address is on top of the frame. |
4596 ASSERT(StackHandlerConstants::kNextOffset == 0); | 4596 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
4597 frame_->EmitPop(Operand::StaticVariable(handler_address)); | 4597 frame_->EmitPop(Operand::StaticVariable(handler_address)); |
4598 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 4598 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
4599 | 4599 |
4600 // Fake a top of stack value (unneeded when FALLING) and set the | 4600 // Fake a top of stack value (unneeded when FALLING) and set the |
4601 // state in ecx, then jump around the unlink blocks if any. | 4601 // state in ecx, then jump around the unlink blocks if any. |
4602 frame_->EmitPush(Immediate(Factory::undefined_value())); | 4602 frame_->EmitPush(Immediate(Factory::undefined_value())); |
4603 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); | 4603 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); |
4604 if (nof_unlinks > 0) { | 4604 if (nof_unlinks > 0) { |
4605 finally_block.Jump(); | 4605 finally_block.Jump(); |
4606 } | 4606 } |
(...skipping 18 matching lines...) Expand all Loading... |
4625 // this block. | 4625 // this block. |
4626 frame_->SpillAll(); | 4626 frame_->SpillAll(); |
4627 | 4627 |
4628 // Reload sp from the top handler, because some statements that | 4628 // Reload sp from the top handler, because some statements that |
4629 // we break from (eg, for...in) may have left stuff on the | 4629 // we break from (eg, for...in) may have left stuff on the |
4630 // stack. | 4630 // stack. |
4631 __ mov(esp, Operand::StaticVariable(handler_address)); | 4631 __ mov(esp, Operand::StaticVariable(handler_address)); |
4632 frame_->Forget(frame_->height() - handler_height); | 4632 frame_->Forget(frame_->height() - handler_height); |
4633 | 4633 |
4634 // Unlink this handler and drop it from the frame. | 4634 // Unlink this handler and drop it from the frame. |
4635 ASSERT(StackHandlerConstants::kNextOffset == 0); | 4635 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
4636 frame_->EmitPop(Operand::StaticVariable(handler_address)); | 4636 frame_->EmitPop(Operand::StaticVariable(handler_address)); |
4637 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 4637 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
4638 | 4638 |
4639 if (i == kReturnShadowIndex) { | 4639 if (i == kReturnShadowIndex) { |
4640 // If this target shadowed the function return, materialize | 4640 // If this target shadowed the function return, materialize |
4641 // the return value on the stack. | 4641 // the return value on the stack. |
4642 frame_->EmitPush(eax); | 4642 frame_->EmitPush(eax); |
4643 } else { | 4643 } else { |
4644 // Fake TOS for targets that shadowed breaks and continues. | 4644 // Fake TOS for targets that shadowed breaks and continues. |
4645 frame_->EmitPush(Immediate(Factory::undefined_value())); | 4645 frame_->EmitPush(Immediate(Factory::undefined_value())); |
(...skipping 1920 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6566 null.Branch(zero); | 6566 null.Branch(zero); |
6567 | 6567 |
6568 // Check that the object is a JS object but take special care of JS | 6568 // Check that the object is a JS object but take special care of JS |
6569 // functions to make sure they have 'Function' as their class. | 6569 // functions to make sure they have 'Function' as their class. |
6570 __ CmpObjectType(obj.reg(), FIRST_JS_OBJECT_TYPE, obj.reg()); | 6570 __ CmpObjectType(obj.reg(), FIRST_JS_OBJECT_TYPE, obj.reg()); |
6571 null.Branch(below); | 6571 null.Branch(below); |
6572 | 6572 |
6573 // As long as JS_FUNCTION_TYPE is the last instance type and it is | 6573 // As long as JS_FUNCTION_TYPE is the last instance type and it is |
6574 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for | 6574 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for |
6575 // LAST_JS_OBJECT_TYPE. | 6575 // LAST_JS_OBJECT_TYPE. |
6576 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 6576 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
6577 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 6577 STATIC_ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); |
6578 __ CmpInstanceType(obj.reg(), JS_FUNCTION_TYPE); | 6578 __ CmpInstanceType(obj.reg(), JS_FUNCTION_TYPE); |
6579 function.Branch(equal); | 6579 function.Branch(equal); |
6580 | 6580 |
6581 // Check if the constructor in the map is a function. | 6581 // Check if the constructor in the map is a function. |
6582 { Result tmp = allocator()->Allocate(); | 6582 { Result tmp = allocator()->Allocate(); |
6583 __ mov(obj.reg(), FieldOperand(obj.reg(), Map::kConstructorOffset)); | 6583 __ mov(obj.reg(), FieldOperand(obj.reg(), Map::kConstructorOffset)); |
6584 __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, tmp.reg()); | 6584 __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, tmp.reg()); |
6585 non_function_constructor.Branch(not_equal); | 6585 non_function_constructor.Branch(not_equal); |
6586 } | 6586 } |
6587 | 6587 |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6708 left.ToRegister(); | 6708 left.ToRegister(); |
6709 __ cmp(right.reg(), Operand(left.reg())); | 6709 __ cmp(right.reg(), Operand(left.reg())); |
6710 right.Unuse(); | 6710 right.Unuse(); |
6711 left.Unuse(); | 6711 left.Unuse(); |
6712 destination()->Split(equal); | 6712 destination()->Split(equal); |
6713 } | 6713 } |
6714 | 6714 |
6715 | 6715 |
6716 void CodeGenerator::GenerateGetFramePointer(ZoneList<Expression*>* args) { | 6716 void CodeGenerator::GenerateGetFramePointer(ZoneList<Expression*>* args) { |
6717 ASSERT(args->length() == 0); | 6717 ASSERT(args->length() == 0); |
6718 ASSERT(kSmiTag == 0); // EBP value is aligned, so it should look like Smi. | 6718 STATIC_ASSERT(kSmiTag == 0); // EBP value is aligned, so it looks like a Smi. |
6719 Result ebp_as_smi = allocator_->Allocate(); | 6719 Result ebp_as_smi = allocator_->Allocate(); |
6720 ASSERT(ebp_as_smi.is_valid()); | 6720 ASSERT(ebp_as_smi.is_valid()); |
6721 __ mov(ebp_as_smi.reg(), Operand(ebp)); | 6721 __ mov(ebp_as_smi.reg(), Operand(ebp)); |
6722 frame_->Push(&ebp_as_smi); | 6722 frame_->Push(&ebp_as_smi); |
6723 } | 6723 } |
6724 | 6724 |
6725 | 6725 |
6726 void CodeGenerator::GenerateRandomHeapNumber( | 6726 void CodeGenerator::GenerateRandomHeapNumber( |
6727 ZoneList<Expression*>* args) { | 6727 ZoneList<Expression*>* args) { |
6728 ASSERT(args->length() == 0); | 6728 ASSERT(args->length() == 0); |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7062 FieldOperand(cache.reg(), FixedArray::OffsetOfElementAt(cache_id))); | 7062 FieldOperand(cache.reg(), FixedArray::OffsetOfElementAt(cache_id))); |
7063 | 7063 |
7064 Result tmp = allocator()->Allocate(); | 7064 Result tmp = allocator()->Allocate(); |
7065 ASSERT(tmp.is_valid()); | 7065 ASSERT(tmp.is_valid()); |
7066 | 7066 |
7067 DeferredSearchCache* deferred = new DeferredSearchCache(tmp.reg(), | 7067 DeferredSearchCache* deferred = new DeferredSearchCache(tmp.reg(), |
7068 cache.reg(), | 7068 cache.reg(), |
7069 key.reg()); | 7069 key.reg()); |
7070 | 7070 |
7071 // tmp.reg() now holds finger offset as a smi. | 7071 // tmp.reg() now holds finger offset as a smi. |
7072 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 7072 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
7073 __ mov(tmp.reg(), FieldOperand(cache.reg(), | 7073 __ mov(tmp.reg(), FieldOperand(cache.reg(), |
7074 JSFunctionResultCache::kFingerOffset)); | 7074 JSFunctionResultCache::kFingerOffset)); |
7075 __ cmp(key.reg(), FixedArrayElementOperand(cache.reg(), tmp.reg())); | 7075 __ cmp(key.reg(), FixedArrayElementOperand(cache.reg(), tmp.reg())); |
7076 deferred->Branch(not_equal); | 7076 deferred->Branch(not_equal); |
7077 | 7077 |
7078 __ mov(tmp.reg(), FixedArrayElementOperand(cache.reg(), tmp.reg(), 1)); | 7078 __ mov(tmp.reg(), FixedArrayElementOperand(cache.reg(), tmp.reg(), 1)); |
7079 | 7079 |
7080 deferred->BindExit(); | 7080 deferred->BindExit(); |
7081 frame_->Push(&tmp); | 7081 frame_->Push(&tmp); |
7082 } | 7082 } |
(...skipping 1941 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9024 __ Assert(equal, "JSObject with fast elements map has slow elements"); | 9024 __ Assert(equal, "JSObject with fast elements map has slow elements"); |
9025 } | 9025 } |
9026 | 9026 |
9027 // Check that the key is within bounds. | 9027 // Check that the key is within bounds. |
9028 __ cmp(key.reg(), | 9028 __ cmp(key.reg(), |
9029 FieldOperand(elements.reg(), FixedArray::kLengthOffset)); | 9029 FieldOperand(elements.reg(), FixedArray::kLengthOffset)); |
9030 deferred->Branch(above_equal); | 9030 deferred->Branch(above_equal); |
9031 | 9031 |
9032 // Load and check that the result is not the hole. | 9032 // Load and check that the result is not the hole. |
9033 // Key holds a smi. | 9033 // Key holds a smi. |
9034 ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); | 9034 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
9035 __ mov(elements.reg(), | 9035 __ mov(elements.reg(), |
9036 FieldOperand(elements.reg(), | 9036 FieldOperand(elements.reg(), |
9037 key.reg(), | 9037 key.reg(), |
9038 times_2, | 9038 times_2, |
9039 FixedArray::kHeaderSize)); | 9039 FixedArray::kHeaderSize)); |
9040 result = elements; | 9040 result = elements; |
9041 __ cmp(Operand(result.reg()), Immediate(Factory::the_hole_value())); | 9041 __ cmp(Operand(result.reg()), Immediate(Factory::the_hole_value())); |
9042 deferred->Branch(equal); | 9042 deferred->Branch(equal); |
9043 __ IncrementCounter(&Counters::keyed_load_inline, 1); | 9043 __ IncrementCounter(&Counters::keyed_load_inline, 1); |
9044 | 9044 |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9400 | 9400 |
9401 // All sizes here are multiples of kPointerSize. | 9401 // All sizes here are multiples of kPointerSize. |
9402 int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; | 9402 int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; |
9403 int size = JSArray::kSize + elements_size; | 9403 int size = JSArray::kSize + elements_size; |
9404 | 9404 |
9405 // Load boilerplate object into ecx and check if we need to create a | 9405 // Load boilerplate object into ecx and check if we need to create a |
9406 // boilerplate. | 9406 // boilerplate. |
9407 Label slow_case; | 9407 Label slow_case; |
9408 __ mov(ecx, Operand(esp, 3 * kPointerSize)); | 9408 __ mov(ecx, Operand(esp, 3 * kPointerSize)); |
9409 __ mov(eax, Operand(esp, 2 * kPointerSize)); | 9409 __ mov(eax, Operand(esp, 2 * kPointerSize)); |
9410 ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); | 9410 STATIC_ASSERT(kPointerSize == 4); |
| 9411 STATIC_ASSERT(kSmiTagSize == 1); |
| 9412 STATIC_ASSERT(kSmiTag == 0); |
9411 __ mov(ecx, CodeGenerator::FixedArrayElementOperand(ecx, eax)); | 9413 __ mov(ecx, CodeGenerator::FixedArrayElementOperand(ecx, eax)); |
9412 __ cmp(ecx, Factory::undefined_value()); | 9414 __ cmp(ecx, Factory::undefined_value()); |
9413 __ j(equal, &slow_case); | 9415 __ j(equal, &slow_case); |
9414 | 9416 |
9415 // Allocate both the JS array and the elements array in one big | 9417 // Allocate both the JS array and the elements array in one big |
9416 // allocation. This avoids multiple limit checks. | 9418 // allocation. This avoids multiple limit checks. |
9417 __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT); | 9419 __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT); |
9418 | 9420 |
9419 // Copy the JS array part. | 9421 // Copy the JS array part. |
9420 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { | 9422 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9464 1 << Map::kIsUndetectable); | 9466 1 << Map::kIsUndetectable); |
9465 __ j(not_zero, &false_result); | 9467 __ j(not_zero, &false_result); |
9466 | 9468 |
9467 // JavaScript object => true. | 9469 // JavaScript object => true. |
9468 __ CmpInstanceType(edx, FIRST_JS_OBJECT_TYPE); | 9470 __ CmpInstanceType(edx, FIRST_JS_OBJECT_TYPE); |
9469 __ j(above_equal, &true_result); | 9471 __ j(above_equal, &true_result); |
9470 | 9472 |
9471 // String value => false iff empty. | 9473 // String value => false iff empty. |
9472 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE); | 9474 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE); |
9473 __ j(above_equal, ¬_string); | 9475 __ j(above_equal, ¬_string); |
9474 ASSERT(kSmiTag == 0); | 9476 STATIC_ASSERT(kSmiTag == 0); |
9475 __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); | 9477 __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); |
9476 __ j(zero, &false_result); | 9478 __ j(zero, &false_result); |
9477 __ jmp(&true_result); | 9479 __ jmp(&true_result); |
9478 | 9480 |
9479 __ bind(¬_string); | 9481 __ bind(¬_string); |
9480 // HeapNumber => false iff +0, -0, or NaN. | 9482 // HeapNumber => false iff +0, -0, or NaN. |
9481 __ cmp(edx, Factory::heap_number_map()); | 9483 __ cmp(edx, Factory::heap_number_map()); |
9482 __ j(not_equal, &true_result); | 9484 __ j(not_equal, &true_result); |
9483 __ fldz(); | 9485 __ fldz(); |
9484 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 9486 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9714 __ mov(ecx, right); | 9716 __ mov(ecx, right); |
9715 __ or_(right, Operand(left)); | 9717 __ or_(right, Operand(left)); |
9716 combined = right; | 9718 combined = right; |
9717 break; | 9719 break; |
9718 | 9720 |
9719 default: | 9721 default: |
9720 break; | 9722 break; |
9721 } | 9723 } |
9722 | 9724 |
9723 // 3. Perform the smi check of the operands. | 9725 // 3. Perform the smi check of the operands. |
9724 ASSERT(kSmiTag == 0); // Adjust zero check if not the case. | 9726 STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. |
9725 __ test(combined, Immediate(kSmiTagMask)); | 9727 __ test(combined, Immediate(kSmiTagMask)); |
9726 __ j(not_zero, ¬_smis, not_taken); | 9728 __ j(not_zero, ¬_smis, not_taken); |
9727 | 9729 |
9728 // 4. Operands are both smis, perform the operation leaving the result in | 9730 // 4. Operands are both smis, perform the operation leaving the result in |
9729 // eax and check the result if necessary. | 9731 // eax and check the result if necessary. |
9730 Comment perform_smi(masm, "-- Perform smi operation"); | 9732 Comment perform_smi(masm, "-- Perform smi operation"); |
9731 Label use_fp_on_smis; | 9733 Label use_fp_on_smis; |
9732 switch (op_) { | 9734 switch (op_) { |
9733 case Token::BIT_OR: | 9735 case Token::BIT_OR: |
9734 // Nothing to do. | 9736 // Nothing to do. |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9795 break; | 9797 break; |
9796 | 9798 |
9797 case Token::SUB: | 9799 case Token::SUB: |
9798 __ sub(left, Operand(right)); | 9800 __ sub(left, Operand(right)); |
9799 __ j(overflow, &use_fp_on_smis, not_taken); | 9801 __ j(overflow, &use_fp_on_smis, not_taken); |
9800 __ mov(eax, left); | 9802 __ mov(eax, left); |
9801 break; | 9803 break; |
9802 | 9804 |
9803 case Token::MUL: | 9805 case Token::MUL: |
9804 // If the smi tag is 0 we can just leave the tag on one operand. | 9806 // If the smi tag is 0 we can just leave the tag on one operand. |
9805 ASSERT(kSmiTag == 0); // Adjust code below if not the case. | 9807 STATIC_ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
9806 // We can't revert the multiplication if the result is not a smi | 9808 // We can't revert the multiplication if the result is not a smi |
9807 // so save the right operand. | 9809 // so save the right operand. |
9808 __ mov(ebx, right); | 9810 __ mov(ebx, right); |
9809 // Remove tag from one of the operands (but keep sign). | 9811 // Remove tag from one of the operands (but keep sign). |
9810 __ SmiUntag(right); | 9812 __ SmiUntag(right); |
9811 // Do multiplication. | 9813 // Do multiplication. |
9812 __ imul(right, Operand(left)); // Multiplication is commutative. | 9814 __ imul(right, Operand(left)); // Multiplication is commutative. |
9813 __ j(overflow, &use_fp_on_smis, not_taken); | 9815 __ j(overflow, &use_fp_on_smis, not_taken); |
9814 // Check for negative zero result. Use combined = left | right. | 9816 // Check for negative zero result. Use combined = left | right. |
9815 __ NegativeZeroTest(right, combined, &use_fp_on_smis); | 9817 __ NegativeZeroTest(right, combined, &use_fp_on_smis); |
9816 break; | 9818 break; |
9817 | 9819 |
9818 case Token::DIV: | 9820 case Token::DIV: |
9819 // We can't revert the division if the result is not a smi so | 9821 // We can't revert the division if the result is not a smi so |
9820 // save the left operand. | 9822 // save the left operand. |
9821 __ mov(edi, left); | 9823 __ mov(edi, left); |
9822 // Check for 0 divisor. | 9824 // Check for 0 divisor. |
9823 __ test(right, Operand(right)); | 9825 __ test(right, Operand(right)); |
9824 __ j(zero, &use_fp_on_smis, not_taken); | 9826 __ j(zero, &use_fp_on_smis, not_taken); |
9825 // Sign extend left into edx:eax. | 9827 // Sign extend left into edx:eax. |
9826 ASSERT(left.is(eax)); | 9828 ASSERT(left.is(eax)); |
9827 __ cdq(); | 9829 __ cdq(); |
9828 // Divide edx:eax by right. | 9830 // Divide edx:eax by right. |
9829 __ idiv(right); | 9831 __ idiv(right); |
9830 // Check for the corner case of dividing the most negative smi by | 9832 // Check for the corner case of dividing the most negative smi by |
9831 // -1. We cannot use the overflow flag, since it is not set by idiv | 9833 // -1. We cannot use the overflow flag, since it is not set by idiv |
9832 // instruction. | 9834 // instruction. |
9833 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 9835 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
9834 __ cmp(eax, 0x40000000); | 9836 __ cmp(eax, 0x40000000); |
9835 __ j(equal, &use_fp_on_smis); | 9837 __ j(equal, &use_fp_on_smis); |
9836 // Check for negative zero result. Use combined = left | right. | 9838 // Check for negative zero result. Use combined = left | right. |
9837 __ NegativeZeroTest(eax, combined, &use_fp_on_smis); | 9839 __ NegativeZeroTest(eax, combined, &use_fp_on_smis); |
9838 // Check that the remainder is zero. | 9840 // Check that the remainder is zero. |
9839 __ test(edx, Operand(edx)); | 9841 __ test(edx, Operand(edx)); |
9840 __ j(not_zero, &use_fp_on_smis); | 9842 __ j(not_zero, &use_fp_on_smis); |
9841 // Tag the result and store it in register eax. | 9843 // Tag the result and store it in register eax. |
9842 __ SmiTag(eax); | 9844 __ SmiTag(eax); |
9843 break; | 9845 break; |
(...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10396 // Test that eax is a number. | 10398 // Test that eax is a number. |
10397 Label runtime_call; | 10399 Label runtime_call; |
10398 Label runtime_call_clear_stack; | 10400 Label runtime_call_clear_stack; |
10399 Label input_not_smi; | 10401 Label input_not_smi; |
10400 Label loaded; | 10402 Label loaded; |
10401 __ mov(eax, Operand(esp, kPointerSize)); | 10403 __ mov(eax, Operand(esp, kPointerSize)); |
10402 __ test(eax, Immediate(kSmiTagMask)); | 10404 __ test(eax, Immediate(kSmiTagMask)); |
10403 __ j(not_zero, &input_not_smi); | 10405 __ j(not_zero, &input_not_smi); |
10404 // Input is a smi. Untag and load it onto the FPU stack. | 10406 // Input is a smi. Untag and load it onto the FPU stack. |
10405 // Then load the low and high words of the double into ebx, edx. | 10407 // Then load the low and high words of the double into ebx, edx. |
10406 ASSERT_EQ(1, kSmiTagSize); | 10408 STATIC_ASSERT(kSmiTagSize == 1); |
10407 __ sar(eax, 1); | 10409 __ sar(eax, 1); |
10408 __ sub(Operand(esp), Immediate(2 * kPointerSize)); | 10410 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
10409 __ mov(Operand(esp, 0), eax); | 10411 __ mov(Operand(esp, 0), eax); |
10410 __ fild_s(Operand(esp, 0)); | 10412 __ fild_s(Operand(esp, 0)); |
10411 __ fst_d(Operand(esp, 0)); | 10413 __ fst_d(Operand(esp, 0)); |
10412 __ pop(edx); | 10414 __ pop(edx); |
10413 __ pop(ebx); | 10415 __ pop(ebx); |
10414 __ jmp(&loaded); | 10416 __ jmp(&loaded); |
10415 __ bind(&input_not_smi); | 10417 __ bind(&input_not_smi); |
10416 // Check if input is a HeapNumber. | 10418 // Check if input is a HeapNumber. |
(...skipping 698 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11115 CpuFeatures::IsSupported(SSE3), | 11117 CpuFeatures::IsSupported(SSE3), |
11116 &slow); | 11118 &slow); |
11117 | 11119 |
11118 // Do the bitwise operation and check if the result fits in a smi. | 11120 // Do the bitwise operation and check if the result fits in a smi. |
11119 Label try_float; | 11121 Label try_float; |
11120 __ not_(ecx); | 11122 __ not_(ecx); |
11121 __ cmp(ecx, 0xc0000000); | 11123 __ cmp(ecx, 0xc0000000); |
11122 __ j(sign, &try_float, not_taken); | 11124 __ j(sign, &try_float, not_taken); |
11123 | 11125 |
11124 // Tag the result as a smi and we're done. | 11126 // Tag the result as a smi and we're done. |
11125 ASSERT(kSmiTagSize == 1); | 11127 STATIC_ASSERT(kSmiTagSize == 1); |
11126 __ lea(eax, Operand(ecx, times_2, kSmiTag)); | 11128 __ lea(eax, Operand(ecx, times_2, kSmiTag)); |
11127 __ jmp(&done); | 11129 __ jmp(&done); |
11128 | 11130 |
11129 // Try to store the result in a heap number. | 11131 // Try to store the result in a heap number. |
11130 __ bind(&try_float); | 11132 __ bind(&try_float); |
11131 if (overwrite_ == UNARY_NO_OVERWRITE) { | 11133 if (overwrite_ == UNARY_NO_OVERWRITE) { |
11132 // Allocate a fresh heap number, but don't overwrite eax until | 11134 // Allocate a fresh heap number, but don't overwrite eax until |
11133 // we're sure we can do it without going through the slow case | 11135 // we're sure we can do it without going through the slow case |
11134 // that needs the value in eax. | 11136 // that needs the value in eax. |
11135 __ AllocateHeapNumber(ebx, edx, edi, &slow); | 11137 __ AllocateHeapNumber(ebx, edx, edi, &slow); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11191 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 11193 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
11192 __ j(equal, &adaptor); | 11194 __ j(equal, &adaptor); |
11193 | 11195 |
11194 // Check index against formal parameters count limit passed in | 11196 // Check index against formal parameters count limit passed in |
11195 // through register eax. Use unsigned comparison to get negative | 11197 // through register eax. Use unsigned comparison to get negative |
11196 // check for free. | 11198 // check for free. |
11197 __ cmp(edx, Operand(eax)); | 11199 __ cmp(edx, Operand(eax)); |
11198 __ j(above_equal, &slow, not_taken); | 11200 __ j(above_equal, &slow, not_taken); |
11199 | 11201 |
11200 // Read the argument from the stack and return it. | 11202 // Read the argument from the stack and return it. |
11201 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // shifting code depends on this | 11203 STATIC_ASSERT(kSmiTagSize == 1); |
| 11204 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. |
11202 __ lea(ebx, Operand(ebp, eax, times_2, 0)); | 11205 __ lea(ebx, Operand(ebp, eax, times_2, 0)); |
11203 __ neg(edx); | 11206 __ neg(edx); |
11204 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); | 11207 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); |
11205 __ ret(0); | 11208 __ ret(0); |
11206 | 11209 |
11207 // Arguments adaptor case: Check index against actual arguments | 11210 // Arguments adaptor case: Check index against actual arguments |
11208 // limit found in the arguments adaptor frame. Use unsigned | 11211 // limit found in the arguments adaptor frame. Use unsigned |
11209 // comparison to get negative check for free. | 11212 // comparison to get negative check for free. |
11210 __ bind(&adaptor); | 11213 __ bind(&adaptor); |
11211 __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 11214 __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
11212 __ cmp(edx, Operand(ecx)); | 11215 __ cmp(edx, Operand(ecx)); |
11213 __ j(above_equal, &slow, not_taken); | 11216 __ j(above_equal, &slow, not_taken); |
11214 | 11217 |
11215 // Read the argument from the stack and return it. | 11218 // Read the argument from the stack and return it. |
11216 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // shifting code depends on this | 11219 STATIC_ASSERT(kSmiTagSize == 1); |
| 11220 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. |
11217 __ lea(ebx, Operand(ebx, ecx, times_2, 0)); | 11221 __ lea(ebx, Operand(ebx, ecx, times_2, 0)); |
11218 __ neg(edx); | 11222 __ neg(edx); |
11219 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); | 11223 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); |
11220 __ ret(0); | 11224 __ ret(0); |
11221 | 11225 |
11222 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 11226 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
11223 // by calling the runtime system. | 11227 // by calling the runtime system. |
11224 __ bind(&slow); | 11228 __ bind(&slow); |
11225 __ pop(ebx); // Return address. | 11229 __ pop(ebx); // Return address. |
11226 __ push(edx); | 11230 __ push(edx); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11277 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); | 11281 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); |
11278 __ mov(edi, Operand(edi, offset)); | 11282 __ mov(edi, Operand(edi, offset)); |
11279 | 11283 |
11280 // Copy the JS object part. | 11284 // Copy the JS object part. |
11281 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { | 11285 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
11282 __ mov(ebx, FieldOperand(edi, i)); | 11286 __ mov(ebx, FieldOperand(edi, i)); |
11283 __ mov(FieldOperand(eax, i), ebx); | 11287 __ mov(FieldOperand(eax, i), ebx); |
11284 } | 11288 } |
11285 | 11289 |
11286 // Setup the callee in-object property. | 11290 // Setup the callee in-object property. |
11287 ASSERT(Heap::arguments_callee_index == 0); | 11291 STATIC_ASSERT(Heap::arguments_callee_index == 0); |
11288 __ mov(ebx, Operand(esp, 3 * kPointerSize)); | 11292 __ mov(ebx, Operand(esp, 3 * kPointerSize)); |
11289 __ mov(FieldOperand(eax, JSObject::kHeaderSize), ebx); | 11293 __ mov(FieldOperand(eax, JSObject::kHeaderSize), ebx); |
11290 | 11294 |
11291 // Get the length (smi tagged) and set that as an in-object property too. | 11295 // Get the length (smi tagged) and set that as an in-object property too. |
11292 ASSERT(Heap::arguments_length_index == 1); | 11296 STATIC_ASSERT(Heap::arguments_length_index == 1); |
11293 __ mov(ecx, Operand(esp, 1 * kPointerSize)); | 11297 __ mov(ecx, Operand(esp, 1 * kPointerSize)); |
11294 __ mov(FieldOperand(eax, JSObject::kHeaderSize + kPointerSize), ecx); | 11298 __ mov(FieldOperand(eax, JSObject::kHeaderSize + kPointerSize), ecx); |
11295 | 11299 |
11296 // If there are no actual arguments, we're done. | 11300 // If there are no actual arguments, we're done. |
11297 Label done; | 11301 Label done; |
11298 __ test(ecx, Operand(ecx)); | 11302 __ test(ecx, Operand(ecx)); |
11299 __ j(zero, &done); | 11303 __ j(zero, &done); |
11300 | 11304 |
11301 // Get the parameters pointer from the stack. | 11305 // Get the parameters pointer from the stack. |
11302 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 11306 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11361 ExternalReference address_of_regexp_stack_memory_address = | 11365 ExternalReference address_of_regexp_stack_memory_address = |
11362 ExternalReference::address_of_regexp_stack_memory_address(); | 11366 ExternalReference::address_of_regexp_stack_memory_address(); |
11363 ExternalReference address_of_regexp_stack_memory_size = | 11367 ExternalReference address_of_regexp_stack_memory_size = |
11364 ExternalReference::address_of_regexp_stack_memory_size(); | 11368 ExternalReference::address_of_regexp_stack_memory_size(); |
11365 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); | 11369 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |
11366 __ test(ebx, Operand(ebx)); | 11370 __ test(ebx, Operand(ebx)); |
11367 __ j(zero, &runtime, not_taken); | 11371 __ j(zero, &runtime, not_taken); |
11368 | 11372 |
11369 // Check that the first argument is a JSRegExp object. | 11373 // Check that the first argument is a JSRegExp object. |
11370 __ mov(eax, Operand(esp, kJSRegExpOffset)); | 11374 __ mov(eax, Operand(esp, kJSRegExpOffset)); |
11371 ASSERT_EQ(0, kSmiTag); | 11375 STATIC_ASSERT(kSmiTag == 0); |
11372 __ test(eax, Immediate(kSmiTagMask)); | 11376 __ test(eax, Immediate(kSmiTagMask)); |
11373 __ j(zero, &runtime); | 11377 __ j(zero, &runtime); |
11374 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); | 11378 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); |
11375 __ j(not_equal, &runtime); | 11379 __ j(not_equal, &runtime); |
11376 // Check that the RegExp has been compiled (data contains a fixed array). | 11380 // Check that the RegExp has been compiled (data contains a fixed array). |
11377 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); | 11381 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); |
11378 if (FLAG_debug_code) { | 11382 if (FLAG_debug_code) { |
11379 __ test(ecx, Immediate(kSmiTagMask)); | 11383 __ test(ecx, Immediate(kSmiTagMask)); |
11380 __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); | 11384 __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); |
11381 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); | 11385 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); |
11382 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); | 11386 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); |
11383 } | 11387 } |
11384 | 11388 |
11385 // ecx: RegExp data (FixedArray) | 11389 // ecx: RegExp data (FixedArray) |
11386 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | 11390 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
11387 __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); | 11391 __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); |
11388 __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); | 11392 __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); |
11389 __ j(not_equal, &runtime); | 11393 __ j(not_equal, &runtime); |
11390 | 11394 |
11391 // ecx: RegExp data (FixedArray) | 11395 // ecx: RegExp data (FixedArray) |
11392 // Check that the number of captures fit in the static offsets vector buffer. | 11396 // Check that the number of captures fit in the static offsets vector buffer. |
11393 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); | 11397 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); |
11394 // Calculate number of capture registers (number_of_captures + 1) * 2. This | 11398 // Calculate number of capture registers (number_of_captures + 1) * 2. This |
11395 // uses the asumption that smis are 2 * their untagged value. | 11399 // uses the asumption that smis are 2 * their untagged value. |
11396 ASSERT_EQ(0, kSmiTag); | 11400 STATIC_ASSERT(kSmiTag == 0); |
11397 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 11401 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
11398 __ add(Operand(edx), Immediate(2)); // edx was a smi. | 11402 __ add(Operand(edx), Immediate(2)); // edx was a smi. |
11399 // Check that the static offsets vector buffer is large enough. | 11403 // Check that the static offsets vector buffer is large enough. |
11400 __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); | 11404 __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); |
11401 __ j(above, &runtime); | 11405 __ j(above, &runtime); |
11402 | 11406 |
11403 // ecx: RegExp data (FixedArray) | 11407 // ecx: RegExp data (FixedArray) |
11404 // edx: Number of capture registers | 11408 // edx: Number of capture registers |
11405 // Check that the second argument is a string. | 11409 // Check that the second argument is a string. |
11406 __ mov(eax, Operand(esp, kSubjectOffset)); | 11410 __ mov(eax, Operand(esp, kSubjectOffset)); |
11407 __ test(eax, Immediate(kSmiTagMask)); | 11411 __ test(eax, Immediate(kSmiTagMask)); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11445 | 11449 |
11446 // ecx: RegExp data (FixedArray) | 11450 // ecx: RegExp data (FixedArray) |
11447 // Check the representation and encoding of the subject string. | 11451 // Check the representation and encoding of the subject string. |
11448 Label seq_ascii_string, seq_two_byte_string, check_code; | 11452 Label seq_ascii_string, seq_two_byte_string, check_code; |
11449 __ mov(eax, Operand(esp, kSubjectOffset)); | 11453 __ mov(eax, Operand(esp, kSubjectOffset)); |
11450 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 11454 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
11451 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 11455 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
11452 // First check for flat two byte string. | 11456 // First check for flat two byte string. |
11453 __ and_(ebx, | 11457 __ and_(ebx, |
11454 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); | 11458 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); |
11455 ASSERT_EQ(0, kStringTag | kSeqStringTag | kTwoByteStringTag); | 11459 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); |
11456 __ j(zero, &seq_two_byte_string); | 11460 __ j(zero, &seq_two_byte_string); |
11457 // Any other flat string must be a flat ascii string. | 11461 // Any other flat string must be a flat ascii string. |
11458 __ test(Operand(ebx), | 11462 __ test(Operand(ebx), |
11459 Immediate(kIsNotStringMask | kStringRepresentationMask)); | 11463 Immediate(kIsNotStringMask | kStringRepresentationMask)); |
11460 __ j(zero, &seq_ascii_string); | 11464 __ j(zero, &seq_ascii_string); |
11461 | 11465 |
11462 // Check for flat cons string. | 11466 // Check for flat cons string. |
11463 // A flat cons string is a cons string where the second part is the empty | 11467 // A flat cons string is a cons string where the second part is the empty |
11464 // string. In that case the subject string is just the first part of the cons | 11468 // string. In that case the subject string is just the first part of the cons |
11465 // string. Also in this case the first part of the cons string is known to be | 11469 // string. Also in this case the first part of the cons string is known to be |
11466 // a sequential string or an external string. | 11470 // a sequential string or an external string. |
11467 ASSERT(kExternalStringTag !=0); | 11471 STATIC_ASSERT(kExternalStringTag != 0); |
11468 ASSERT_EQ(0, kConsStringTag & kExternalStringTag); | 11472 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); |
11469 __ test(Operand(ebx), | 11473 __ test(Operand(ebx), |
11470 Immediate(kIsNotStringMask | kExternalStringTag)); | 11474 Immediate(kIsNotStringMask | kExternalStringTag)); |
11471 __ j(not_zero, &runtime); | 11475 __ j(not_zero, &runtime); |
11472 // String is a cons string. | 11476 // String is a cons string. |
11473 __ mov(edx, FieldOperand(eax, ConsString::kSecondOffset)); | 11477 __ mov(edx, FieldOperand(eax, ConsString::kSecondOffset)); |
11474 __ cmp(Operand(edx), Factory::empty_string()); | 11478 __ cmp(Operand(edx), Factory::empty_string()); |
11475 __ j(not_equal, &runtime); | 11479 __ j(not_equal, &runtime); |
11476 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); | 11480 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); |
11477 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 11481 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
11478 // String is a cons string with empty second part. | 11482 // String is a cons string with empty second part. |
11479 // eax: first part of cons string. | 11483 // eax: first part of cons string. |
11480 // ebx: map of first part of cons string. | 11484 // ebx: map of first part of cons string. |
11481 // Is first part a flat two byte string? | 11485 // Is first part a flat two byte string? |
11482 __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), | 11486 __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), |
11483 kStringRepresentationMask | kStringEncodingMask); | 11487 kStringRepresentationMask | kStringEncodingMask); |
11484 ASSERT_EQ(0, kSeqStringTag | kTwoByteStringTag); | 11488 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); |
11485 __ j(zero, &seq_two_byte_string); | 11489 __ j(zero, &seq_two_byte_string); |
11486 // Any other flat string must be ascii. | 11490 // Any other flat string must be ascii. |
11487 __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), | 11491 __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), |
11488 kStringRepresentationMask); | 11492 kStringRepresentationMask); |
11489 __ j(not_zero, &runtime); | 11493 __ j(not_zero, &runtime); |
11490 | 11494 |
11491 __ bind(&seq_ascii_string); | 11495 __ bind(&seq_ascii_string); |
11492 // eax: subject string (flat ascii) | 11496 // eax: subject string (flat ascii) |
11493 // ecx: RegExp data (FixedArray) | 11497 // ecx: RegExp data (FixedArray) |
11494 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset)); | 11498 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset)); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11545 __ mov(edi, FieldOperand(eax, String::kLengthOffset)); | 11549 __ mov(edi, FieldOperand(eax, String::kLengthOffset)); |
11546 __ j(zero, &setup_two_byte); | 11550 __ j(zero, &setup_two_byte); |
11547 __ SmiUntag(edi); | 11551 __ SmiUntag(edi); |
11548 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize)); | 11552 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize)); |
11549 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. | 11553 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. |
11550 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); | 11554 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); |
11551 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. | 11555 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. |
11552 __ jmp(&setup_rest); | 11556 __ jmp(&setup_rest); |
11553 | 11557 |
11554 __ bind(&setup_two_byte); | 11558 __ bind(&setup_two_byte); |
11555 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); // edi is smi (powered by 2). | 11559 STATIC_ASSERT(kSmiTag == 0); |
| 11560 STATIC_ASSERT(kSmiTagSize == 1); // edi is smi (powered by 2). |
11556 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqTwoByteString::kHeaderSize)); | 11561 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqTwoByteString::kHeaderSize)); |
11557 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. | 11562 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. |
11558 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); | 11563 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); |
11559 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. | 11564 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. |
11560 | 11565 |
11561 __ bind(&setup_rest); | 11566 __ bind(&setup_rest); |
11562 | 11567 |
11563 // Argument 2: Previous index. | 11568 // Argument 2: Previous index. |
11564 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 11569 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
11565 | 11570 |
(...skipping 27 matching lines...) Expand all Loading... |
11593 // For failure and exception return null. | 11598 // For failure and exception return null. |
11594 __ mov(Operand(eax), Factory::null_value()); | 11599 __ mov(Operand(eax), Factory::null_value()); |
11595 __ ret(4 * kPointerSize); | 11600 __ ret(4 * kPointerSize); |
11596 | 11601 |
11597 // Load RegExp data. | 11602 // Load RegExp data. |
11598 __ bind(&success); | 11603 __ bind(&success); |
11599 __ mov(eax, Operand(esp, kJSRegExpOffset)); | 11604 __ mov(eax, Operand(esp, kJSRegExpOffset)); |
11600 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); | 11605 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); |
11601 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); | 11606 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); |
11602 // Calculate number of capture registers (number_of_captures + 1) * 2. | 11607 // Calculate number of capture registers (number_of_captures + 1) * 2. |
11603 ASSERT_EQ(0, kSmiTag); | 11608 STATIC_ASSERT(kSmiTag == 0); |
11604 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 11609 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
11605 __ add(Operand(edx), Immediate(2)); // edx was a smi. | 11610 __ add(Operand(edx), Immediate(2)); // edx was a smi. |
11606 | 11611 |
11607 // edx: Number of capture registers | 11612 // edx: Number of capture registers |
11608 // Load last_match_info which is still known to be a fast case JSArray. | 11613 // Load last_match_info which is still known to be a fast case JSArray. |
11609 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); | 11614 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); |
11610 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); | 11615 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); |
11611 | 11616 |
11612 // ebx: last_match_info backing store (FixedArray) | 11617 // ebx: last_match_info backing store (FixedArray) |
11613 // edx: number of capture registers | 11618 // edx: number of capture registers |
11614 // Store the capture count. | 11619 // Store the capture count. |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11689 // number string cache for smis is just the smi value, and the hash for | 11694 // number string cache for smis is just the smi value, and the hash for |
11690 // doubles is the xor of the upper and lower words. See | 11695 // doubles is the xor of the upper and lower words. See |
11691 // Heap::GetNumberStringCache. | 11696 // Heap::GetNumberStringCache. |
11692 Label smi_hash_calculated; | 11697 Label smi_hash_calculated; |
11693 Label load_result_from_cache; | 11698 Label load_result_from_cache; |
11694 if (object_is_smi) { | 11699 if (object_is_smi) { |
11695 __ mov(scratch, object); | 11700 __ mov(scratch, object); |
11696 __ SmiUntag(scratch); | 11701 __ SmiUntag(scratch); |
11697 } else { | 11702 } else { |
11698 Label not_smi, hash_calculated; | 11703 Label not_smi, hash_calculated; |
11699 ASSERT(kSmiTag == 0); | 11704 STATIC_ASSERT(kSmiTag == 0); |
11700 __ test(object, Immediate(kSmiTagMask)); | 11705 __ test(object, Immediate(kSmiTagMask)); |
11701 __ j(not_zero, ¬_smi); | 11706 __ j(not_zero, ¬_smi); |
11702 __ mov(scratch, object); | 11707 __ mov(scratch, object); |
11703 __ SmiUntag(scratch); | 11708 __ SmiUntag(scratch); |
11704 __ jmp(&smi_hash_calculated); | 11709 __ jmp(&smi_hash_calculated); |
11705 __ bind(¬_smi); | 11710 __ bind(¬_smi); |
11706 __ cmp(FieldOperand(object, HeapObject::kMapOffset), | 11711 __ cmp(FieldOperand(object, HeapObject::kMapOffset), |
11707 Factory::heap_number_map()); | 11712 Factory::heap_number_map()); |
11708 __ j(not_equal, not_found); | 11713 __ j(not_equal, not_found); |
11709 ASSERT_EQ(8, kDoubleSize); | 11714 STATIC_ASSERT(8 == kDoubleSize); |
11710 __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); | 11715 __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); |
11711 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); | 11716 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); |
11712 // Object is heap number and hash is now in scratch. Calculate cache index. | 11717 // Object is heap number and hash is now in scratch. Calculate cache index. |
11713 __ and_(scratch, Operand(mask)); | 11718 __ and_(scratch, Operand(mask)); |
11714 Register index = scratch; | 11719 Register index = scratch; |
11715 Register probe = mask; | 11720 Register probe = mask; |
11716 __ mov(probe, | 11721 __ mov(probe, |
11717 FieldOperand(number_string_cache, | 11722 FieldOperand(number_string_cache, |
11718 index, | 11723 index, |
11719 times_twice_pointer_size, | 11724 times_twice_pointer_size, |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11830 // It is a heap number, so return non-equal if it's NaN and equal if | 11835 // It is a heap number, so return non-equal if it's NaN and equal if |
11831 // it's not NaN. | 11836 // it's not NaN. |
11832 // The representation of NaN values has all exponent bits (52..62) set, | 11837 // The representation of NaN values has all exponent bits (52..62) set, |
11833 // and not all mantissa bits (0..51) clear. | 11838 // and not all mantissa bits (0..51) clear. |
11834 // We only accept QNaNs, which have bit 51 set. | 11839 // We only accept QNaNs, which have bit 51 set. |
11835 // Read top bits of double representation (second word of value). | 11840 // Read top bits of double representation (second word of value). |
11836 | 11841 |
11837 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., | 11842 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., |
11838 // all bits in the mask are set. We only need to check the word | 11843 // all bits in the mask are set. We only need to check the word |
11839 // that contains the exponent and high bit of the mantissa. | 11844 // that contains the exponent and high bit of the mantissa. |
11840 ASSERT_NE(0, (kQuietNaNHighBitsMask << 1) & 0x80000000u); | 11845 STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); |
11841 __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); | 11846 __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); |
11842 __ xor_(eax, Operand(eax)); | 11847 __ xor_(eax, Operand(eax)); |
11843 // Shift value and mask so kQuietNaNHighBitsMask applies to topmost | 11848 // Shift value and mask so kQuietNaNHighBitsMask applies to topmost |
11844 // bits. | 11849 // bits. |
11845 __ add(edx, Operand(edx)); | 11850 __ add(edx, Operand(edx)); |
11846 __ cmp(edx, kQuietNaNHighBitsMask << 1); | 11851 __ cmp(edx, kQuietNaNHighBitsMask << 1); |
11847 if (cc_ == equal) { | 11852 if (cc_ == equal) { |
11848 ASSERT_NE(1, EQUAL); | 11853 STATIC_ASSERT(EQUAL != 1); |
11849 __ setcc(above_equal, eax); | 11854 __ setcc(above_equal, eax); |
11850 __ ret(0); | 11855 __ ret(0); |
11851 } else { | 11856 } else { |
11852 Label nan; | 11857 Label nan; |
11853 __ j(above_equal, &nan); | 11858 __ j(above_equal, &nan); |
11854 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 11859 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
11855 __ ret(0); | 11860 __ ret(0); |
11856 __ bind(&nan); | 11861 __ bind(&nan); |
11857 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); | 11862 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); |
11858 __ ret(0); | 11863 __ ret(0); |
11859 } | 11864 } |
11860 } | 11865 } |
11861 | 11866 |
11862 __ bind(¬_identical); | 11867 __ bind(¬_identical); |
11863 } | 11868 } |
11864 | 11869 |
11865 // Strict equality can quickly decide whether objects are equal. | 11870 // Strict equality can quickly decide whether objects are equal. |
11866 // Non-strict object equality is slower, so it is handled later in the stub. | 11871 // Non-strict object equality is slower, so it is handled later in the stub. |
11867 if (cc_ == equal && strict_) { | 11872 if (cc_ == equal && strict_) { |
11868 Label slow; // Fallthrough label. | 11873 Label slow; // Fallthrough label. |
11869 Label not_smis; | 11874 Label not_smis; |
11870 // If we're doing a strict equality comparison, we don't have to do | 11875 // If we're doing a strict equality comparison, we don't have to do |
11871 // type conversion, so we generate code to do fast comparison for objects | 11876 // type conversion, so we generate code to do fast comparison for objects |
11872 // and oddballs. Non-smi numbers and strings still go through the usual | 11877 // and oddballs. Non-smi numbers and strings still go through the usual |
11873 // slow-case code. | 11878 // slow-case code. |
11874 // If either is a Smi (we know that not both are), then they can only | 11879 // If either is a Smi (we know that not both are), then they can only |
11875 // be equal if the other is a HeapNumber. If so, use the slow case. | 11880 // be equal if the other is a HeapNumber. If so, use the slow case. |
11876 ASSERT_EQ(0, kSmiTag); | 11881 STATIC_ASSERT(kSmiTag == 0); |
11877 ASSERT_EQ(0, Smi::FromInt(0)); | 11882 ASSERT_EQ(0, Smi::FromInt(0)); |
11878 __ mov(ecx, Immediate(kSmiTagMask)); | 11883 __ mov(ecx, Immediate(kSmiTagMask)); |
11879 __ and_(ecx, Operand(eax)); | 11884 __ and_(ecx, Operand(eax)); |
11880 __ test(ecx, Operand(edx)); | 11885 __ test(ecx, Operand(edx)); |
11881 __ j(not_zero, ¬_smis); | 11886 __ j(not_zero, ¬_smis); |
11882 // One operand is a smi. | 11887 // One operand is a smi. |
11883 | 11888 |
11884 // Check whether the non-smi is a heap number. | 11889 // Check whether the non-smi is a heap number. |
11885 ASSERT_EQ(1, kSmiTagMask); | 11890 STATIC_ASSERT(kSmiTagMask == 1); |
11886 // ecx still holds eax & kSmiTag, which is either zero or one. | 11891 // ecx still holds eax & kSmiTag, which is either zero or one. |
11887 __ sub(Operand(ecx), Immediate(0x01)); | 11892 __ sub(Operand(ecx), Immediate(0x01)); |
11888 __ mov(ebx, edx); | 11893 __ mov(ebx, edx); |
11889 __ xor_(ebx, Operand(eax)); | 11894 __ xor_(ebx, Operand(eax)); |
11890 __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx. | 11895 __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx. |
11891 __ xor_(ebx, Operand(eax)); | 11896 __ xor_(ebx, Operand(eax)); |
11892 // if eax was smi, ebx is now edx, else eax. | 11897 // if eax was smi, ebx is now edx, else eax. |
11893 | 11898 |
11894 // Check if the non-smi operand is a heap number. | 11899 // Check if the non-smi operand is a heap number. |
11895 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 11900 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
11896 Immediate(Factory::heap_number_map())); | 11901 Immediate(Factory::heap_number_map())); |
11897 // If heap number, handle it in the slow case. | 11902 // If heap number, handle it in the slow case. |
11898 __ j(equal, &slow); | 11903 __ j(equal, &slow); |
11899 // Return non-equal (ebx is not zero) | 11904 // Return non-equal (ebx is not zero) |
11900 __ mov(eax, ebx); | 11905 __ mov(eax, ebx); |
11901 __ ret(0); | 11906 __ ret(0); |
11902 | 11907 |
11903 __ bind(¬_smis); | 11908 __ bind(¬_smis); |
11904 // If either operand is a JSObject or an oddball value, then they are not | 11909 // If either operand is a JSObject or an oddball value, then they are not |
11905 // equal since their pointers are different | 11910 // equal since their pointers are different |
11906 // There is no test for undetectability in strict equality. | 11911 // There is no test for undetectability in strict equality. |
11907 | 11912 |
11908 // Get the type of the first operand. | 11913 // Get the type of the first operand. |
11909 // If the first object is a JS object, we have done pointer comparison. | 11914 // If the first object is a JS object, we have done pointer comparison. |
11910 Label first_non_object; | 11915 Label first_non_object; |
11911 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 11916 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
11912 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 11917 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
11913 __ j(below, &first_non_object); | 11918 __ j(below, &first_non_object); |
11914 | 11919 |
11915 // Return non-zero (eax is not zero) | 11920 // Return non-zero (eax is not zero) |
11916 Label return_not_equal; | 11921 Label return_not_equal; |
11917 ASSERT(kHeapObjectTag != 0); | 11922 STATIC_ASSERT(kHeapObjectTag != 0); |
11918 __ bind(&return_not_equal); | 11923 __ bind(&return_not_equal); |
11919 __ ret(0); | 11924 __ ret(0); |
11920 | 11925 |
11921 __ bind(&first_non_object); | 11926 __ bind(&first_non_object); |
11922 // Check for oddballs: true, false, null, undefined. | 11927 // Check for oddballs: true, false, null, undefined. |
11923 __ CmpInstanceType(ecx, ODDBALL_TYPE); | 11928 __ CmpInstanceType(ecx, ODDBALL_TYPE); |
11924 __ j(equal, &return_not_equal); | 11929 __ j(equal, &return_not_equal); |
11925 | 11930 |
11926 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx); | 11931 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx); |
11927 __ j(above_equal, &return_not_equal); | 11932 __ j(above_equal, &return_not_equal); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12027 __ bind(&check_unequal_objects); | 12032 __ bind(&check_unequal_objects); |
12028 if (cc_ == equal && !strict_) { | 12033 if (cc_ == equal && !strict_) { |
12029 // Non-strict equality. Objects are unequal if | 12034 // Non-strict equality. Objects are unequal if |
12030 // they are both JSObjects and not undetectable, | 12035 // they are both JSObjects and not undetectable, |
12031 // and their pointers are different. | 12036 // and their pointers are different. |
12032 Label not_both_objects; | 12037 Label not_both_objects; |
12033 Label return_unequal; | 12038 Label return_unequal; |
12034 // At most one is a smi, so we can test for smi by adding the two. | 12039 // At most one is a smi, so we can test for smi by adding the two. |
12035 // A smi plus a heap object has the low bit set, a heap object plus | 12040 // A smi plus a heap object has the low bit set, a heap object plus |
12036 // a heap object has the low bit clear. | 12041 // a heap object has the low bit clear. |
12037 ASSERT_EQ(0, kSmiTag); | 12042 STATIC_ASSERT(kSmiTag == 0); |
12038 ASSERT_EQ(1, kSmiTagMask); | 12043 STATIC_ASSERT(kSmiTagMask == 1); |
12039 __ lea(ecx, Operand(eax, edx, times_1, 0)); | 12044 __ lea(ecx, Operand(eax, edx, times_1, 0)); |
12040 __ test(ecx, Immediate(kSmiTagMask)); | 12045 __ test(ecx, Immediate(kSmiTagMask)); |
12041 __ j(not_zero, ¬_both_objects); | 12046 __ j(not_zero, ¬_both_objects); |
12042 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 12047 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
12043 __ j(below, ¬_both_objects); | 12048 __ j(below, ¬_both_objects); |
12044 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ebx); | 12049 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ebx); |
12045 __ j(below, ¬_both_objects); | 12050 __ j(below, ¬_both_objects); |
12046 // We do not bail out after this point. Both are JSObjects, and | 12051 // We do not bail out after this point. Both are JSObjects, and |
12047 // they are equal if and only if both are undetectable. | 12052 // they are equal if and only if both are undetectable. |
12048 // The and of the undetectable flags is 1 if and only if they are equal. | 12053 // The and of the undetectable flags is 1 if and only if they are equal. |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12168 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | 12173 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
12169 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); | 12174 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); |
12170 __ jmp(adaptor, RelocInfo::CODE_TARGET); | 12175 __ jmp(adaptor, RelocInfo::CODE_TARGET); |
12171 } | 12176 } |
12172 | 12177 |
12173 | 12178 |
12174 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { | 12179 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { |
12175 // eax holds the exception. | 12180 // eax holds the exception. |
12176 | 12181 |
12177 // Adjust this code if not the case. | 12182 // Adjust this code if not the case. |
12178 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); | 12183 STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); |
12179 | 12184 |
12180 // Drop the sp to the top of the handler. | 12185 // Drop the sp to the top of the handler. |
12181 ExternalReference handler_address(Top::k_handler_address); | 12186 ExternalReference handler_address(Top::k_handler_address); |
12182 __ mov(esp, Operand::StaticVariable(handler_address)); | 12187 __ mov(esp, Operand::StaticVariable(handler_address)); |
12183 | 12188 |
12184 // Restore next handler and frame pointer, discard handler state. | 12189 // Restore next handler and frame pointer, discard handler state. |
12185 ASSERT(StackHandlerConstants::kNextOffset == 0); | 12190 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
12186 __ pop(Operand::StaticVariable(handler_address)); | 12191 __ pop(Operand::StaticVariable(handler_address)); |
12187 ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize); | 12192 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize); |
12188 __ pop(ebp); | 12193 __ pop(ebp); |
12189 __ pop(edx); // Remove state. | 12194 __ pop(edx); // Remove state. |
12190 | 12195 |
12191 // Before returning we restore the context from the frame pointer if | 12196 // Before returning we restore the context from the frame pointer if |
12192 // not NULL. The frame pointer is NULL in the exception handler of | 12197 // not NULL. The frame pointer is NULL in the exception handler of |
12193 // a JS entry frame. | 12198 // a JS entry frame. |
12194 __ xor_(esi, Operand(esi)); // Tentatively set context pointer to NULL. | 12199 __ xor_(esi, Operand(esi)); // Tentatively set context pointer to NULL. |
12195 Label skip; | 12200 Label skip; |
12196 __ cmp(ebp, 0); | 12201 __ cmp(ebp, 0); |
12197 __ j(equal, &skip, not_taken); | 12202 __ j(equal, &skip, not_taken); |
12198 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 12203 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
12199 __ bind(&skip); | 12204 __ bind(&skip); |
12200 | 12205 |
12201 ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | 12206 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
12202 __ ret(0); | 12207 __ ret(0); |
12203 } | 12208 } |
12204 | 12209 |
12205 | 12210 |
12206 // If true, a Handle<T> passed by value is passed and returned by | 12211 // If true, a Handle<T> passed by value is passed and returned by |
12207 // using the location_ field directly. If false, it is passed and | 12212 // using the location_ field directly. If false, it is passed and |
12208 // returned as a pointer to a handle. | 12213 // returned as a pointer to a handle. |
12209 #ifdef USING_BSD_ABI | 12214 #ifdef USING_BSD_ABI |
12210 static const bool kPassHandlesDirectly = true; | 12215 static const bool kPassHandlesDirectly = true; |
12211 #else | 12216 #else |
12212 static const bool kPassHandlesDirectly = false; | 12217 static const bool kPassHandlesDirectly = false; |
12213 #endif | 12218 #endif |
12214 | 12219 |
12215 | 12220 |
12216 void ApiGetterEntryStub::Generate(MacroAssembler* masm) { | 12221 void ApiGetterEntryStub::Generate(MacroAssembler* masm) { |
12217 Label get_result; | 12222 Label get_result; |
12218 Label prologue; | 12223 Label prologue; |
12219 Label promote_scheduled_exception; | 12224 Label promote_scheduled_exception; |
12220 __ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, kArgc); | 12225 __ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, kArgc); |
12221 ASSERT_EQ(kArgc, 4); | 12226 STATIC_ASSERT(kArgc == 4); |
12222 if (kPassHandlesDirectly) { | 12227 if (kPassHandlesDirectly) { |
12223 // When handles as passed directly we don't have to allocate extra | 12228 // When handles as passed directly we don't have to allocate extra |
12224 // space for and pass an out parameter. | 12229 // space for and pass an out parameter. |
12225 __ mov(Operand(esp, 0 * kPointerSize), ebx); // name. | 12230 __ mov(Operand(esp, 0 * kPointerSize), ebx); // name. |
12226 __ mov(Operand(esp, 1 * kPointerSize), eax); // arguments pointer. | 12231 __ mov(Operand(esp, 1 * kPointerSize), eax); // arguments pointer. |
12227 } else { | 12232 } else { |
12228 // The function expects three arguments to be passed but we allocate | 12233 // The function expects three arguments to be passed but we allocate |
12229 // four to get space for the output cell. The argument slots are filled | 12234 // four to get space for the output cell. The argument slots are filled |
12230 // as follows: | 12235 // as follows: |
12231 // | 12236 // |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12326 if (FLAG_debug_code) { | 12331 if (FLAG_debug_code) { |
12327 Label okay; | 12332 Label okay; |
12328 __ cmp(eax, Factory::the_hole_value()); | 12333 __ cmp(eax, Factory::the_hole_value()); |
12329 __ j(not_equal, &okay); | 12334 __ j(not_equal, &okay); |
12330 __ int3(); | 12335 __ int3(); |
12331 __ bind(&okay); | 12336 __ bind(&okay); |
12332 } | 12337 } |
12333 | 12338 |
12334 // Check for failure result. | 12339 // Check for failure result. |
12335 Label failure_returned; | 12340 Label failure_returned; |
12336 ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); | 12341 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); |
12337 __ lea(ecx, Operand(eax, 1)); | 12342 __ lea(ecx, Operand(eax, 1)); |
12338 // Lower 2 bits of ecx are 0 iff eax has failure tag. | 12343 // Lower 2 bits of ecx are 0 iff eax has failure tag. |
12339 __ test(ecx, Immediate(kFailureTagMask)); | 12344 __ test(ecx, Immediate(kFailureTagMask)); |
12340 __ j(zero, &failure_returned, not_taken); | 12345 __ j(zero, &failure_returned, not_taken); |
12341 | 12346 |
12342 // Exit the JavaScript to C++ exit frame. | 12347 // Exit the JavaScript to C++ exit frame. |
12343 __ LeaveExitFrame(mode_); | 12348 __ LeaveExitFrame(mode_); |
12344 __ ret(0); | 12349 __ ret(0); |
12345 | 12350 |
12346 // Handling of failure. | 12351 // Handling of failure. |
12347 __ bind(&failure_returned); | 12352 __ bind(&failure_returned); |
12348 | 12353 |
12349 Label retry; | 12354 Label retry; |
12350 // If the returned exception is RETRY_AFTER_GC continue at retry label | 12355 // If the returned exception is RETRY_AFTER_GC continue at retry label |
12351 ASSERT(Failure::RETRY_AFTER_GC == 0); | 12356 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); |
12352 __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); | 12357 __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); |
12353 __ j(zero, &retry, taken); | 12358 __ j(zero, &retry, taken); |
12354 | 12359 |
12355 // Special handling of out of memory exceptions. | 12360 // Special handling of out of memory exceptions. |
12356 __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException())); | 12361 __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException())); |
12357 __ j(equal, throw_out_of_memory_exception); | 12362 __ j(equal, throw_out_of_memory_exception); |
12358 | 12363 |
12359 // Retrieve the pending exception and clear the variable. | 12364 // Retrieve the pending exception and clear the variable. |
12360 ExternalReference pending_exception_address(Top::k_pending_exception_address); | 12365 ExternalReference pending_exception_address(Top::k_pending_exception_address); |
12361 __ mov(eax, Operand::StaticVariable(pending_exception_address)); | 12366 __ mov(eax, Operand::StaticVariable(pending_exception_address)); |
(...skipping 10 matching lines...) Expand all Loading... |
12372 __ jmp(throw_normal_exception); | 12377 __ jmp(throw_normal_exception); |
12373 | 12378 |
12374 // Retry. | 12379 // Retry. |
12375 __ bind(&retry); | 12380 __ bind(&retry); |
12376 } | 12381 } |
12377 | 12382 |
12378 | 12383 |
12379 void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, | 12384 void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, |
12380 UncatchableExceptionType type) { | 12385 UncatchableExceptionType type) { |
12381 // Adjust this code if not the case. | 12386 // Adjust this code if not the case. |
12382 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); | 12387 STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); |
12383 | 12388 |
12384 // Drop sp to the top stack handler. | 12389 // Drop sp to the top stack handler. |
12385 ExternalReference handler_address(Top::k_handler_address); | 12390 ExternalReference handler_address(Top::k_handler_address); |
12386 __ mov(esp, Operand::StaticVariable(handler_address)); | 12391 __ mov(esp, Operand::StaticVariable(handler_address)); |
12387 | 12392 |
12388 // Unwind the handlers until the ENTRY handler is found. | 12393 // Unwind the handlers until the ENTRY handler is found. |
12389 Label loop, done; | 12394 Label loop, done; |
12390 __ bind(&loop); | 12395 __ bind(&loop); |
12391 // Load the type of the current stack handler. | 12396 // Load the type of the current stack handler. |
12392 const int kStateOffset = StackHandlerConstants::kStateOffset; | 12397 const int kStateOffset = StackHandlerConstants::kStateOffset; |
12393 __ cmp(Operand(esp, kStateOffset), Immediate(StackHandler::ENTRY)); | 12398 __ cmp(Operand(esp, kStateOffset), Immediate(StackHandler::ENTRY)); |
12394 __ j(equal, &done); | 12399 __ j(equal, &done); |
12395 // Fetch the next handler in the list. | 12400 // Fetch the next handler in the list. |
12396 const int kNextOffset = StackHandlerConstants::kNextOffset; | 12401 const int kNextOffset = StackHandlerConstants::kNextOffset; |
12397 __ mov(esp, Operand(esp, kNextOffset)); | 12402 __ mov(esp, Operand(esp, kNextOffset)); |
12398 __ jmp(&loop); | 12403 __ jmp(&loop); |
12399 __ bind(&done); | 12404 __ bind(&done); |
12400 | 12405 |
12401 // Set the top handler address to next handler past the current ENTRY handler. | 12406 // Set the top handler address to next handler past the current ENTRY handler. |
12402 ASSERT(StackHandlerConstants::kNextOffset == 0); | 12407 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
12403 __ pop(Operand::StaticVariable(handler_address)); | 12408 __ pop(Operand::StaticVariable(handler_address)); |
12404 | 12409 |
12405 if (type == OUT_OF_MEMORY) { | 12410 if (type == OUT_OF_MEMORY) { |
12406 // Set external caught exception to false. | 12411 // Set external caught exception to false. |
12407 ExternalReference external_caught(Top::k_external_caught_exception_address); | 12412 ExternalReference external_caught(Top::k_external_caught_exception_address); |
12408 __ mov(eax, false); | 12413 __ mov(eax, false); |
12409 __ mov(Operand::StaticVariable(external_caught), eax); | 12414 __ mov(Operand::StaticVariable(external_caught), eax); |
12410 | 12415 |
12411 // Set pending exception and eax to out of memory exception. | 12416 // Set pending exception and eax to out of memory exception. |
12412 ExternalReference pending_exception(Top::k_pending_exception_address); | 12417 ExternalReference pending_exception(Top::k_pending_exception_address); |
12413 __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException())); | 12418 __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException())); |
12414 __ mov(Operand::StaticVariable(pending_exception), eax); | 12419 __ mov(Operand::StaticVariable(pending_exception), eax); |
12415 } | 12420 } |
12416 | 12421 |
12417 // Clear the context pointer. | 12422 // Clear the context pointer. |
12418 __ xor_(esi, Operand(esi)); | 12423 __ xor_(esi, Operand(esi)); |
12419 | 12424 |
12420 // Restore fp from handler and discard handler state. | 12425 // Restore fp from handler and discard handler state. |
12421 ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize); | 12426 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize); |
12422 __ pop(ebp); | 12427 __ pop(ebp); |
12423 __ pop(edx); // State. | 12428 __ pop(edx); // State. |
12424 | 12429 |
12425 ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | 12430 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
12426 __ ret(0); | 12431 __ ret(0); |
12427 } | 12432 } |
12428 | 12433 |
12429 | 12434 |
12430 void CEntryStub::Generate(MacroAssembler* masm) { | 12435 void CEntryStub::Generate(MacroAssembler* masm) { |
12431 // eax: number of arguments including receiver | 12436 // eax: number of arguments including receiver |
12432 // ebx: pointer to C function (C callee-saved) | 12437 // ebx: pointer to C function (C callee-saved) |
12433 // ebp: frame pointer (restored after C call) | 12438 // ebp: frame pointer (restored after C call) |
12434 // esp: stack pointer (restored after C call) | 12439 // esp: stack pointer (restored after C call) |
12435 // esi: current context (C callee-saved) | 12440 // esi: current context (C callee-saved) |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12726 | 12731 |
12727 // ------------------------------------------------------------------------- | 12732 // ------------------------------------------------------------------------- |
12728 // StringCharCodeAtGenerator | 12733 // StringCharCodeAtGenerator |
12729 | 12734 |
12730 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 12735 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
12731 Label flat_string; | 12736 Label flat_string; |
12732 Label ascii_string; | 12737 Label ascii_string; |
12733 Label got_char_code; | 12738 Label got_char_code; |
12734 | 12739 |
12735 // If the receiver is a smi trigger the non-string case. | 12740 // If the receiver is a smi trigger the non-string case. |
12736 ASSERT(kSmiTag == 0); | 12741 STATIC_ASSERT(kSmiTag == 0); |
12737 __ test(object_, Immediate(kSmiTagMask)); | 12742 __ test(object_, Immediate(kSmiTagMask)); |
12738 __ j(zero, receiver_not_string_); | 12743 __ j(zero, receiver_not_string_); |
12739 | 12744 |
12740 // Fetch the instance type of the receiver into result register. | 12745 // Fetch the instance type of the receiver into result register. |
12741 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 12746 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
12742 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 12747 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
12743 // If the receiver is not a string trigger the non-string case. | 12748 // If the receiver is not a string trigger the non-string case. |
12744 __ test(result_, Immediate(kIsNotStringMask)); | 12749 __ test(result_, Immediate(kIsNotStringMask)); |
12745 __ j(not_zero, receiver_not_string_); | 12750 __ j(not_zero, receiver_not_string_); |
12746 | 12751 |
12747 // If the index is non-smi trigger the non-smi case. | 12752 // If the index is non-smi trigger the non-smi case. |
12748 ASSERT(kSmiTag == 0); | 12753 STATIC_ASSERT(kSmiTag == 0); |
12749 __ test(index_, Immediate(kSmiTagMask)); | 12754 __ test(index_, Immediate(kSmiTagMask)); |
12750 __ j(not_zero, &index_not_smi_); | 12755 __ j(not_zero, &index_not_smi_); |
12751 | 12756 |
12752 // Put smi-tagged index into scratch register. | 12757 // Put smi-tagged index into scratch register. |
12753 __ mov(scratch_, index_); | 12758 __ mov(scratch_, index_); |
12754 __ bind(&got_smi_index_); | 12759 __ bind(&got_smi_index_); |
12755 | 12760 |
12756 // Check for index out of range. | 12761 // Check for index out of range. |
12757 __ cmp(scratch_, FieldOperand(object_, String::kLengthOffset)); | 12762 __ cmp(scratch_, FieldOperand(object_, String::kLengthOffset)); |
12758 __ j(above_equal, index_out_of_range_); | 12763 __ j(above_equal, index_out_of_range_); |
12759 | 12764 |
12760 // We need special handling for non-flat strings. | 12765 // We need special handling for non-flat strings. |
12761 ASSERT(kSeqStringTag == 0); | 12766 STATIC_ASSERT(kSeqStringTag == 0); |
12762 __ test(result_, Immediate(kStringRepresentationMask)); | 12767 __ test(result_, Immediate(kStringRepresentationMask)); |
12763 __ j(zero, &flat_string); | 12768 __ j(zero, &flat_string); |
12764 | 12769 |
12765 // Handle non-flat strings. | 12770 // Handle non-flat strings. |
12766 __ test(result_, Immediate(kIsConsStringMask)); | 12771 __ test(result_, Immediate(kIsConsStringMask)); |
12767 __ j(zero, &call_runtime_); | 12772 __ j(zero, &call_runtime_); |
12768 | 12773 |
12769 // ConsString. | 12774 // ConsString. |
12770 // Check whether the right hand side is the empty string (i.e. if | 12775 // Check whether the right hand side is the empty string (i.e. if |
12771 // this is really a flat string in a cons string). If that is not | 12776 // this is really a flat string in a cons string). If that is not |
12772 // the case we would rather go to the runtime system now to flatten | 12777 // the case we would rather go to the runtime system now to flatten |
12773 // the string. | 12778 // the string. |
12774 __ cmp(FieldOperand(object_, ConsString::kSecondOffset), | 12779 __ cmp(FieldOperand(object_, ConsString::kSecondOffset), |
12775 Immediate(Factory::empty_string())); | 12780 Immediate(Factory::empty_string())); |
12776 __ j(not_equal, &call_runtime_); | 12781 __ j(not_equal, &call_runtime_); |
12777 // Get the first of the two strings and load its instance type. | 12782 // Get the first of the two strings and load its instance type. |
12778 __ mov(object_, FieldOperand(object_, ConsString::kFirstOffset)); | 12783 __ mov(object_, FieldOperand(object_, ConsString::kFirstOffset)); |
12779 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 12784 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
12780 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 12785 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
12781 // If the first cons component is also non-flat, then go to runtime. | 12786 // If the first cons component is also non-flat, then go to runtime. |
12782 ASSERT(kSeqStringTag == 0); | 12787 STATIC_ASSERT(kSeqStringTag == 0); |
12783 __ test(result_, Immediate(kStringRepresentationMask)); | 12788 __ test(result_, Immediate(kStringRepresentationMask)); |
12784 __ j(not_zero, &call_runtime_); | 12789 __ j(not_zero, &call_runtime_); |
12785 | 12790 |
12786 // Check for 1-byte or 2-byte string. | 12791 // Check for 1-byte or 2-byte string. |
12787 __ bind(&flat_string); | 12792 __ bind(&flat_string); |
12788 ASSERT(kAsciiStringTag != 0); | 12793 STATIC_ASSERT(kAsciiStringTag != 0); |
12789 __ test(result_, Immediate(kStringEncodingMask)); | 12794 __ test(result_, Immediate(kStringEncodingMask)); |
12790 __ j(not_zero, &ascii_string); | 12795 __ j(not_zero, &ascii_string); |
12791 | 12796 |
12792 // 2-byte string. | 12797 // 2-byte string. |
12793 // Load the 2-byte character code into the result register. | 12798 // Load the 2-byte character code into the result register. |
12794 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 12799 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
12795 __ movzx_w(result_, FieldOperand(object_, | 12800 __ movzx_w(result_, FieldOperand(object_, |
12796 scratch_, times_1, // Scratch is smi-tagged. | 12801 scratch_, times_1, // Scratch is smi-tagged. |
12797 SeqTwoByteString::kHeaderSize)); | 12802 SeqTwoByteString::kHeaderSize)); |
12798 __ jmp(&got_char_code); | 12803 __ jmp(&got_char_code); |
12799 | 12804 |
12800 // ASCII string. | 12805 // ASCII string. |
12801 // Load the byte into the result register. | 12806 // Load the byte into the result register. |
12802 __ bind(&ascii_string); | 12807 __ bind(&ascii_string); |
12803 __ SmiUntag(scratch_); | 12808 __ SmiUntag(scratch_); |
12804 __ movzx_b(result_, FieldOperand(object_, | 12809 __ movzx_b(result_, FieldOperand(object_, |
(...skipping 29 matching lines...) Expand all Loading... |
12834 // have a chance to overwrite it. | 12839 // have a chance to overwrite it. |
12835 __ mov(scratch_, eax); | 12840 __ mov(scratch_, eax); |
12836 } | 12841 } |
12837 __ pop(index_); | 12842 __ pop(index_); |
12838 __ pop(object_); | 12843 __ pop(object_); |
12839 // Reload the instance type. | 12844 // Reload the instance type. |
12840 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 12845 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
12841 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 12846 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
12842 call_helper.AfterCall(masm); | 12847 call_helper.AfterCall(masm); |
12843 // If index is still not a smi, it must be out of range. | 12848 // If index is still not a smi, it must be out of range. |
12844 ASSERT(kSmiTag == 0); | 12849 STATIC_ASSERT(kSmiTag == 0); |
12845 __ test(scratch_, Immediate(kSmiTagMask)); | 12850 __ test(scratch_, Immediate(kSmiTagMask)); |
12846 __ j(not_zero, index_out_of_range_); | 12851 __ j(not_zero, index_out_of_range_); |
12847 // Otherwise, return to the fast path. | 12852 // Otherwise, return to the fast path. |
12848 __ jmp(&got_smi_index_); | 12853 __ jmp(&got_smi_index_); |
12849 | 12854 |
12850 // Call runtime. We get here when the receiver is a string and the | 12855 // Call runtime. We get here when the receiver is a string and the |
12851 // index is a number, but the code of getting the actual character | 12856 // index is a number, but the code of getting the actual character |
12852 // is too complex (e.g., when the string needs to be flattened). | 12857 // is too complex (e.g., when the string needs to be flattened). |
12853 __ bind(&call_runtime_); | 12858 __ bind(&call_runtime_); |
12854 call_helper.BeforeCall(masm); | 12859 call_helper.BeforeCall(masm); |
12855 __ push(object_); | 12860 __ push(object_); |
12856 __ push(index_); | 12861 __ push(index_); |
12857 __ CallRuntime(Runtime::kStringCharCodeAt, 2); | 12862 __ CallRuntime(Runtime::kStringCharCodeAt, 2); |
12858 if (!result_.is(eax)) { | 12863 if (!result_.is(eax)) { |
12859 __ mov(result_, eax); | 12864 __ mov(result_, eax); |
12860 } | 12865 } |
12861 call_helper.AfterCall(masm); | 12866 call_helper.AfterCall(masm); |
12862 __ jmp(&exit_); | 12867 __ jmp(&exit_); |
12863 | 12868 |
12864 __ Abort("Unexpected fallthrough from CharCodeAt slow case"); | 12869 __ Abort("Unexpected fallthrough from CharCodeAt slow case"); |
12865 } | 12870 } |
12866 | 12871 |
12867 | 12872 |
12868 // ------------------------------------------------------------------------- | 12873 // ------------------------------------------------------------------------- |
12869 // StringCharFromCodeGenerator | 12874 // StringCharFromCodeGenerator |
12870 | 12875 |
12871 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { | 12876 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { |
12872 // Fast case of Heap::LookupSingleCharacterStringFromCode. | 12877 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
12873 ASSERT(kSmiTag == 0); | 12878 STATIC_ASSERT(kSmiTag == 0); |
12874 ASSERT(kSmiShiftSize == 0); | 12879 STATIC_ASSERT(kSmiShiftSize == 0); |
12875 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); | 12880 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
12876 __ test(code_, | 12881 __ test(code_, |
12877 Immediate(kSmiTagMask | | 12882 Immediate(kSmiTagMask | |
12878 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); | 12883 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
12879 __ j(not_zero, &slow_case_, not_taken); | 12884 __ j(not_zero, &slow_case_, not_taken); |
12880 | 12885 |
12881 __ Set(result_, Immediate(Factory::single_character_string_cache())); | 12886 __ Set(result_, Immediate(Factory::single_character_string_cache())); |
12882 ASSERT(kSmiTag == 0); | 12887 STATIC_ASSERT(kSmiTag == 0); |
12883 ASSERT(kSmiTagSize == 1); | 12888 STATIC_ASSERT(kSmiTagSize == 1); |
12884 ASSERT(kSmiShiftSize == 0); | 12889 STATIC_ASSERT(kSmiShiftSize == 0); |
12885 // At this point code register contains smi tagged ascii char code. | 12890 // At this point code register contains smi tagged ascii char code. |
12886 __ mov(result_, FieldOperand(result_, | 12891 __ mov(result_, FieldOperand(result_, |
12887 code_, times_half_pointer_size, | 12892 code_, times_half_pointer_size, |
12888 FixedArray::kHeaderSize)); | 12893 FixedArray::kHeaderSize)); |
12889 __ cmp(result_, Factory::undefined_value()); | 12894 __ cmp(result_, Factory::undefined_value()); |
12890 __ j(equal, &slow_case_, not_taken); | 12895 __ j(equal, &slow_case_, not_taken); |
12891 __ bind(&exit_); | 12896 __ bind(&exit_); |
12892 } | 12897 } |
12893 | 12898 |
12894 | 12899 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12946 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); | 12951 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); |
12947 __ j(above_equal, &string_add_runtime); | 12952 __ j(above_equal, &string_add_runtime); |
12948 } | 12953 } |
12949 | 12954 |
12950 // Both arguments are strings. | 12955 // Both arguments are strings. |
12951 // eax: first string | 12956 // eax: first string |
12952 // edx: second string | 12957 // edx: second string |
12953 // Check if either of the strings are empty. In that case return the other. | 12958 // Check if either of the strings are empty. In that case return the other. |
12954 Label second_not_zero_length, both_not_zero_length; | 12959 Label second_not_zero_length, both_not_zero_length; |
12955 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); | 12960 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); |
12956 ASSERT(kSmiTag == 0); | 12961 STATIC_ASSERT(kSmiTag == 0); |
12957 __ test(ecx, Operand(ecx)); | 12962 __ test(ecx, Operand(ecx)); |
12958 __ j(not_zero, &second_not_zero_length); | 12963 __ j(not_zero, &second_not_zero_length); |
12959 // Second string is empty, result is first string which is already in eax. | 12964 // Second string is empty, result is first string which is already in eax. |
12960 __ IncrementCounter(&Counters::string_add_native, 1); | 12965 __ IncrementCounter(&Counters::string_add_native, 1); |
12961 __ ret(2 * kPointerSize); | 12966 __ ret(2 * kPointerSize); |
12962 __ bind(&second_not_zero_length); | 12967 __ bind(&second_not_zero_length); |
12963 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | 12968 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |
12964 ASSERT(kSmiTag == 0); | 12969 STATIC_ASSERT(kSmiTag == 0); |
12965 __ test(ebx, Operand(ebx)); | 12970 __ test(ebx, Operand(ebx)); |
12966 __ j(not_zero, &both_not_zero_length); | 12971 __ j(not_zero, &both_not_zero_length); |
12967 // First string is empty, result is second string which is in edx. | 12972 // First string is empty, result is second string which is in edx. |
12968 __ mov(eax, edx); | 12973 __ mov(eax, edx); |
12969 __ IncrementCounter(&Counters::string_add_native, 1); | 12974 __ IncrementCounter(&Counters::string_add_native, 1); |
12970 __ ret(2 * kPointerSize); | 12975 __ ret(2 * kPointerSize); |
12971 | 12976 |
12972 // Both strings are non-empty. | 12977 // Both strings are non-empty. |
12973 // eax: first string | 12978 // eax: first string |
12974 // ebx: length of first string as a smi | 12979 // ebx: length of first string as a smi |
12975 // ecx: length of second string as a smi | 12980 // ecx: length of second string as a smi |
12976 // edx: second string | 12981 // edx: second string |
12977 // Look at the length of the result of adding the two strings. | 12982 // Look at the length of the result of adding the two strings. |
12978 Label string_add_flat_result, longer_than_two; | 12983 Label string_add_flat_result, longer_than_two; |
12979 __ bind(&both_not_zero_length); | 12984 __ bind(&both_not_zero_length); |
12980 __ add(ebx, Operand(ecx)); | 12985 __ add(ebx, Operand(ecx)); |
12981 ASSERT(Smi::kMaxValue == String::kMaxLength); | 12986 STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); |
12982 // Handle exceptionally long strings in the runtime system. | 12987 // Handle exceptionally long strings in the runtime system. |
12983 __ j(overflow, &string_add_runtime); | 12988 __ j(overflow, &string_add_runtime); |
12984 // Use the runtime system when adding two one character strings, as it | 12989 // Use the runtime system when adding two one character strings, as it |
12985 // contains optimizations for this specific case using the symbol table. | 12990 // contains optimizations for this specific case using the symbol table. |
12986 __ cmp(Operand(ebx), Immediate(Smi::FromInt(2))); | 12991 __ cmp(Operand(ebx), Immediate(Smi::FromInt(2))); |
12987 __ j(not_equal, &longer_than_two); | 12992 __ j(not_equal, &longer_than_two); |
12988 | 12993 |
12989 // Check that both strings are non-external ascii strings. | 12994 // Check that both strings are non-external ascii strings. |
12990 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, | 12995 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, |
12991 &string_add_runtime); | 12996 &string_add_runtime); |
(...skipping 20 matching lines...) Expand all Loading... |
13012 __ j(below, &string_add_flat_result); | 13017 __ j(below, &string_add_flat_result); |
13013 | 13018 |
13014 // If result is not supposed to be flat allocate a cons string object. If both | 13019 // If result is not supposed to be flat allocate a cons string object. If both |
13015 // strings are ascii the result is an ascii cons string. | 13020 // strings are ascii the result is an ascii cons string. |
13016 Label non_ascii, allocated, ascii_data; | 13021 Label non_ascii, allocated, ascii_data; |
13017 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); | 13022 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); |
13018 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); | 13023 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); |
13019 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | 13024 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
13020 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); | 13025 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); |
13021 __ and_(ecx, Operand(edi)); | 13026 __ and_(ecx, Operand(edi)); |
13022 ASSERT(kStringEncodingMask == kAsciiStringTag); | 13027 STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); |
13023 __ test(ecx, Immediate(kAsciiStringTag)); | 13028 __ test(ecx, Immediate(kAsciiStringTag)); |
13024 __ j(zero, &non_ascii); | 13029 __ j(zero, &non_ascii); |
13025 __ bind(&ascii_data); | 13030 __ bind(&ascii_data); |
13026 // Allocate an acsii cons string. | 13031 // Allocate an acsii cons string. |
13027 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); | 13032 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); |
13028 __ bind(&allocated); | 13033 __ bind(&allocated); |
13029 // Fill the fields of the cons string. | 13034 // Fill the fields of the cons string. |
13030 if (FLAG_debug_code) __ AbortIfNotSmi(ebx); | 13035 if (FLAG_debug_code) __ AbortIfNotSmi(ebx); |
13031 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); | 13036 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); |
13032 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), | 13037 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), |
13033 Immediate(String::kEmptyHashField)); | 13038 Immediate(String::kEmptyHashField)); |
13034 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | 13039 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); |
13035 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | 13040 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); |
13036 __ mov(eax, ecx); | 13041 __ mov(eax, ecx); |
13037 __ IncrementCounter(&Counters::string_add_native, 1); | 13042 __ IncrementCounter(&Counters::string_add_native, 1); |
13038 __ ret(2 * kPointerSize); | 13043 __ ret(2 * kPointerSize); |
13039 __ bind(&non_ascii); | 13044 __ bind(&non_ascii); |
13040 // At least one of the strings is two-byte. Check whether it happens | 13045 // At least one of the strings is two-byte. Check whether it happens |
13041 // to contain only ascii characters. | 13046 // to contain only ascii characters. |
13042 // ecx: first instance type AND second instance type. | 13047 // ecx: first instance type AND second instance type. |
13043 // edi: second instance type. | 13048 // edi: second instance type. |
13044 __ test(ecx, Immediate(kAsciiDataHintMask)); | 13049 __ test(ecx, Immediate(kAsciiDataHintMask)); |
13045 __ j(not_zero, &ascii_data); | 13050 __ j(not_zero, &ascii_data); |
13046 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 13051 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
13047 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 13052 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
13048 __ xor_(edi, Operand(ecx)); | 13053 __ xor_(edi, Operand(ecx)); |
13049 ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); | 13054 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); |
13050 __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); | 13055 __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); |
13051 __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); | 13056 __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); |
13052 __ j(equal, &ascii_data); | 13057 __ j(equal, &ascii_data); |
13053 // Allocate a two byte cons string. | 13058 // Allocate a two byte cons string. |
13054 __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); | 13059 __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); |
13055 __ jmp(&allocated); | 13060 __ jmp(&allocated); |
13056 | 13061 |
13057 // Handle creating a flat result. First check that both strings are not | 13062 // Handle creating a flat result. First check that both strings are not |
13058 // external strings. | 13063 // external strings. |
13059 // eax: first string | 13064 // eax: first string |
13060 // ebx: length of resulting flat string as a smi | 13065 // ebx: length of resulting flat string as a smi |
13061 // edx: second string | 13066 // edx: second string |
13062 __ bind(&string_add_flat_result); | 13067 __ bind(&string_add_flat_result); |
13063 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 13068 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
13064 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 13069 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
13065 __ and_(ecx, kStringRepresentationMask); | 13070 __ and_(ecx, kStringRepresentationMask); |
13066 __ cmp(ecx, kExternalStringTag); | 13071 __ cmp(ecx, kExternalStringTag); |
13067 __ j(equal, &string_add_runtime); | 13072 __ j(equal, &string_add_runtime); |
13068 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 13073 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
13069 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 13074 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
13070 __ and_(ecx, kStringRepresentationMask); | 13075 __ and_(ecx, kStringRepresentationMask); |
13071 __ cmp(ecx, kExternalStringTag); | 13076 __ cmp(ecx, kExternalStringTag); |
13072 __ j(equal, &string_add_runtime); | 13077 __ j(equal, &string_add_runtime); |
13073 // Now check if both strings are ascii strings. | 13078 // Now check if both strings are ascii strings. |
13074 // eax: first string | 13079 // eax: first string |
13075 // ebx: length of resulting flat string as a smi | 13080 // ebx: length of resulting flat string as a smi |
13076 // edx: second string | 13081 // edx: second string |
13077 Label non_ascii_string_add_flat_result; | 13082 Label non_ascii_string_add_flat_result; |
13078 ASSERT(kStringEncodingMask == kAsciiStringTag); | 13083 STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); |
13079 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 13084 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
13080 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); | 13085 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); |
13081 __ j(zero, &non_ascii_string_add_flat_result); | 13086 __ j(zero, &non_ascii_string_add_flat_result); |
13082 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 13087 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
13083 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); | 13088 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); |
13084 __ j(zero, &string_add_runtime); | 13089 __ j(zero, &string_add_runtime); |
13085 | 13090 |
13086 __ bind(&make_flat_ascii_string); | 13091 __ bind(&make_flat_ascii_string); |
13087 // Both strings are ascii strings. As they are short they are both flat. | 13092 // Both strings are ascii strings. As they are short they are both flat. |
13088 // ebx: length of resulting flat string as a smi | 13093 // ebx: length of resulting flat string as a smi |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13187 __ j(not_zero, &loop); | 13192 __ j(not_zero, &loop); |
13188 } | 13193 } |
13189 | 13194 |
13190 | 13195 |
13191 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, | 13196 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, |
13192 Register dest, | 13197 Register dest, |
13193 Register src, | 13198 Register src, |
13194 Register count, | 13199 Register count, |
13195 Register scratch, | 13200 Register scratch, |
13196 bool ascii) { | 13201 bool ascii) { |
13197 // Copy characters using rep movs of doublewords. Align destination on 4 byte | 13202 // Copy characters using rep movs of doublewords. |
13198 // boundary before starting rep movs. Copy remaining characters after running | 13203 // The destination is aligned on a 4 byte boundary because we are |
13199 // rep movs. | 13204 // copying to the beginning of a newly allocated string. |
13200 ASSERT(dest.is(edi)); // rep movs destination | 13205 ASSERT(dest.is(edi)); // rep movs destination |
13201 ASSERT(src.is(esi)); // rep movs source | 13206 ASSERT(src.is(esi)); // rep movs source |
13202 ASSERT(count.is(ecx)); // rep movs count | 13207 ASSERT(count.is(ecx)); // rep movs count |
13203 ASSERT(!scratch.is(dest)); | 13208 ASSERT(!scratch.is(dest)); |
13204 ASSERT(!scratch.is(src)); | 13209 ASSERT(!scratch.is(src)); |
13205 ASSERT(!scratch.is(count)); | 13210 ASSERT(!scratch.is(count)); |
13206 | 13211 |
13207 // Nothing to do for zero characters. | 13212 // Nothing to do for zero characters. |
13208 Label done; | 13213 Label done; |
13209 __ test(count, Operand(count)); | 13214 __ test(count, Operand(count)); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13310 Label found_in_symbol_table; | 13315 Label found_in_symbol_table; |
13311 Label next_probe[kProbes], next_probe_pop_mask[kProbes]; | 13316 Label next_probe[kProbes], next_probe_pop_mask[kProbes]; |
13312 for (int i = 0; i < kProbes; i++) { | 13317 for (int i = 0; i < kProbes; i++) { |
13313 // Calculate entry in symbol table. | 13318 // Calculate entry in symbol table. |
13314 __ mov(scratch, hash); | 13319 __ mov(scratch, hash); |
13315 if (i > 0) { | 13320 if (i > 0) { |
13316 __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i))); | 13321 __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i))); |
13317 } | 13322 } |
13318 __ and_(scratch, Operand(mask)); | 13323 __ and_(scratch, Operand(mask)); |
13319 | 13324 |
13320 // Load the entry from the symble table. | 13325 // Load the entry from the symbol table. |
13321 Register candidate = scratch; // Scratch register contains candidate. | 13326 Register candidate = scratch; // Scratch register contains candidate. |
13322 ASSERT_EQ(1, SymbolTable::kEntrySize); | 13327 STATIC_ASSERT(SymbolTable::kEntrySize == 1); |
13323 __ mov(candidate, | 13328 __ mov(candidate, |
13324 FieldOperand(symbol_table, | 13329 FieldOperand(symbol_table, |
13325 scratch, | 13330 scratch, |
13326 times_pointer_size, | 13331 times_pointer_size, |
13327 SymbolTable::kElementsStartOffset)); | 13332 SymbolTable::kElementsStartOffset)); |
13328 | 13333 |
13329 // If entry is undefined no string with this hash can be found. | 13334 // If entry is undefined no string with this hash can be found. |
13330 __ cmp(candidate, Factory::undefined_value()); | 13335 __ cmp(candidate, Factory::undefined_value()); |
13331 __ j(equal, not_found); | 13336 __ j(equal, not_found); |
13332 | 13337 |
(...skipping 22 matching lines...) Expand all Loading... |
13355 __ pop(mask); | 13360 __ pop(mask); |
13356 __ bind(&next_probe[i]); | 13361 __ bind(&next_probe[i]); |
13357 } | 13362 } |
13358 | 13363 |
13359 // No matching 2 character string found by probing. | 13364 // No matching 2 character string found by probing. |
13360 __ jmp(not_found); | 13365 __ jmp(not_found); |
13361 | 13366 |
13362 // Scratch register contains result when we fall through to here. | 13367 // Scratch register contains result when we fall through to here. |
13363 Register result = scratch; | 13368 Register result = scratch; |
13364 __ bind(&found_in_symbol_table); | 13369 __ bind(&found_in_symbol_table); |
13365 __ pop(mask); // Pop temporally saved mask from the stack. | 13370 __ pop(mask); // Pop saved mask from the stack. |
13366 if (!result.is(eax)) { | 13371 if (!result.is(eax)) { |
13367 __ mov(eax, result); | 13372 __ mov(eax, result); |
13368 } | 13373 } |
13369 } | 13374 } |
13370 | 13375 |
13371 | 13376 |
13372 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 13377 void StringHelper::GenerateHashInit(MacroAssembler* masm, |
13373 Register hash, | 13378 Register hash, |
13374 Register character, | 13379 Register character, |
13375 Register scratch) { | 13380 Register scratch) { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13430 Label runtime; | 13435 Label runtime; |
13431 | 13436 |
13432 // Stack frame on entry. | 13437 // Stack frame on entry. |
13433 // esp[0]: return address | 13438 // esp[0]: return address |
13434 // esp[4]: to | 13439 // esp[4]: to |
13435 // esp[8]: from | 13440 // esp[8]: from |
13436 // esp[12]: string | 13441 // esp[12]: string |
13437 | 13442 |
13438 // Make sure first argument is a string. | 13443 // Make sure first argument is a string. |
13439 __ mov(eax, Operand(esp, 3 * kPointerSize)); | 13444 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
13440 ASSERT_EQ(0, kSmiTag); | 13445 STATIC_ASSERT(kSmiTag == 0); |
13441 __ test(eax, Immediate(kSmiTagMask)); | 13446 __ test(eax, Immediate(kSmiTagMask)); |
13442 __ j(zero, &runtime); | 13447 __ j(zero, &runtime); |
13443 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); | 13448 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); |
13444 __ j(NegateCondition(is_string), &runtime); | 13449 __ j(NegateCondition(is_string), &runtime); |
13445 | 13450 |
13446 // eax: string | 13451 // eax: string |
13447 // ebx: instance type | 13452 // ebx: instance type |
| 13453 |
13448 // Calculate length of sub string using the smi values. | 13454 // Calculate length of sub string using the smi values. |
13449 Label result_longer_than_two; | 13455 Label result_longer_than_two; |
13450 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. | 13456 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. |
13451 __ test(ecx, Immediate(kSmiTagMask)); | 13457 __ test(ecx, Immediate(kSmiTagMask)); |
13452 __ j(not_zero, &runtime); | 13458 __ j(not_zero, &runtime); |
13453 __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. | 13459 __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. |
13454 __ test(edx, Immediate(kSmiTagMask)); | 13460 __ test(edx, Immediate(kSmiTagMask)); |
13455 __ j(not_zero, &runtime); | 13461 __ j(not_zero, &runtime); |
13456 __ sub(ecx, Operand(edx)); | 13462 __ sub(ecx, Operand(edx)); |
13457 __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); | 13463 __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13543 __ mov(edi, eax); | 13549 __ mov(edi, eax); |
13544 __ add(Operand(edi), | 13550 __ add(Operand(edi), |
13545 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 13551 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
13546 // Load string argument and locate character of sub string start. | 13552 // Load string argument and locate character of sub string start. |
13547 __ mov(esi, Operand(esp, 3 * kPointerSize)); | 13553 __ mov(esi, Operand(esp, 3 * kPointerSize)); |
13548 __ add(Operand(esi), | 13554 __ add(Operand(esi), |
13549 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 13555 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
13550 __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from | 13556 __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from |
13551 // As from is a smi it is 2 times the value which matches the size of a two | 13557 // As from is a smi it is 2 times the value which matches the size of a two |
13552 // byte character. | 13558 // byte character. |
13553 ASSERT_EQ(0, kSmiTag); | 13559 STATIC_ASSERT(kSmiTag == 0); |
13554 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 13560 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
13555 __ add(esi, Operand(ebx)); | 13561 __ add(esi, Operand(ebx)); |
13556 | 13562 |
13557 // eax: result string | 13563 // eax: result string |
13558 // ecx: result length | 13564 // ecx: result length |
13559 // edx: original value of esi | 13565 // edx: original value of esi |
13560 // edi: first character of result | 13566 // edi: first character of result |
13561 // esi: character of sub string start | 13567 // esi: character of sub string start |
13562 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); | 13568 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); |
13563 __ mov(esi, edx); // Restore esi. | 13569 __ mov(esi, edx); // Restore esi. |
13564 | 13570 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13630 __ add(Operand(index), Immediate(1)); | 13636 __ add(Operand(index), Immediate(1)); |
13631 __ j(not_zero, &loop); | 13637 __ j(not_zero, &loop); |
13632 } | 13638 } |
13633 | 13639 |
13634 // Compare lengths - strings up to min-length are equal. | 13640 // Compare lengths - strings up to min-length are equal. |
13635 __ bind(&compare_lengths); | 13641 __ bind(&compare_lengths); |
13636 __ test(length_delta, Operand(length_delta)); | 13642 __ test(length_delta, Operand(length_delta)); |
13637 __ j(not_zero, &result_not_equal); | 13643 __ j(not_zero, &result_not_equal); |
13638 | 13644 |
13639 // Result is EQUAL. | 13645 // Result is EQUAL. |
13640 ASSERT_EQ(0, EQUAL); | 13646 STATIC_ASSERT(EQUAL == 0); |
13641 ASSERT_EQ(0, kSmiTag); | 13647 STATIC_ASSERT(kSmiTag == 0); |
13642 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 13648 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
13643 __ ret(0); | 13649 __ ret(0); |
13644 | 13650 |
13645 __ bind(&result_not_equal); | 13651 __ bind(&result_not_equal); |
13646 __ j(greater, &result_greater); | 13652 __ j(greater, &result_greater); |
13647 | 13653 |
13648 // Result is LESS. | 13654 // Result is LESS. |
13649 __ Set(eax, Immediate(Smi::FromInt(LESS))); | 13655 __ Set(eax, Immediate(Smi::FromInt(LESS))); |
13650 __ ret(0); | 13656 __ ret(0); |
13651 | 13657 |
(...skipping 11 matching lines...) Expand all Loading... |
13663 // esp[0]: return address | 13669 // esp[0]: return address |
13664 // esp[4]: right string | 13670 // esp[4]: right string |
13665 // esp[8]: left string | 13671 // esp[8]: left string |
13666 | 13672 |
13667 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left | 13673 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left |
13668 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right | 13674 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right |
13669 | 13675 |
13670 Label not_same; | 13676 Label not_same; |
13671 __ cmp(edx, Operand(eax)); | 13677 __ cmp(edx, Operand(eax)); |
13672 __ j(not_equal, ¬_same); | 13678 __ j(not_equal, ¬_same); |
13673 ASSERT_EQ(0, EQUAL); | 13679 STATIC_ASSERT(EQUAL == 0); |
13674 ASSERT_EQ(0, kSmiTag); | 13680 STATIC_ASSERT(kSmiTag == 0); |
13675 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 13681 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
13676 __ IncrementCounter(&Counters::string_compare_native, 1); | 13682 __ IncrementCounter(&Counters::string_compare_native, 1); |
13677 __ ret(2 * kPointerSize); | 13683 __ ret(2 * kPointerSize); |
13678 | 13684 |
13679 __ bind(¬_same); | 13685 __ bind(¬_same); |
13680 | 13686 |
13681 // Check that both objects are sequential ascii strings. | 13687 // Check that both objects are sequential ascii strings. |
13682 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); | 13688 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); |
13683 | 13689 |
13684 // Compare flat ascii strings. | 13690 // Compare flat ascii strings. |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13897 masm.GetCode(&desc); | 13903 masm.GetCode(&desc); |
13898 // Call the function from C++. | 13904 // Call the function from C++. |
13899 return FUNCTION_CAST<MemCopyFunction>(buffer); | 13905 return FUNCTION_CAST<MemCopyFunction>(buffer); |
13900 } | 13906 } |
13901 | 13907 |
13902 #undef __ | 13908 #undef __ |
13903 | 13909 |
13904 } } // namespace v8::internal | 13910 } } // namespace v8::internal |
13905 | 13911 |
13906 #endif // V8_TARGET_ARCH_IA32 | 13912 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |