| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 561 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 __ Str(obj_length, FieldMemOperand(context, FixedArray::kLengthOffset)); | 572 __ Str(obj_length, FieldMemOperand(context, FixedArray::kLengthOffset)); |
| 573 | 573 |
| 574 // If this block context is nested in the native context we get a smi | 574 // If this block context is nested in the native context we get a smi |
| 575 // sentinel instead of a function. The block context should get the | 575 // sentinel instead of a function. The block context should get the |
| 576 // canonical empty function of the native context as its closure which we | 576 // canonical empty function of the native context as its closure which we |
| 577 // still have to look up. | 577 // still have to look up. |
| 578 Label after_sentinel; | 578 Label after_sentinel; |
| 579 __ JumpIfNotSmi(function, &after_sentinel); | 579 __ JumpIfNotSmi(function, &after_sentinel); |
| 580 if (FLAG_debug_code) { | 580 if (FLAG_debug_code) { |
| 581 __ Cmp(function, 0); | 581 __ Cmp(function, 0); |
| 582 __ Assert(eq, "Expected 0 as a Smi sentinel"); | 582 __ Assert(eq, kExpected0AsASmiSentinel); |
| 583 } | 583 } |
| 584 | 584 |
| 585 Register global_ctx = x14; | 585 Register global_ctx = x14; |
| 586 __ Ldr(global_ctx, FieldMemOperand(global_obj, | 586 __ Ldr(global_ctx, FieldMemOperand(global_obj, |
| 587 GlobalObject::kNativeContextOffset)); | 587 GlobalObject::kNativeContextOffset)); |
| 588 __ Ldr(function, ContextMemOperand(global_ctx, Context::CLOSURE_INDEX)); | 588 __ Ldr(function, ContextMemOperand(global_ctx, Context::CLOSURE_INDEX)); |
| 589 __ Bind(&after_sentinel); | 589 __ Bind(&after_sentinel); |
| 590 | 590 |
| 591 // Store the global object from the previous context, and set up the fixed | 591 // Store the global object from the previous context, and set up the fixed |
| 592 // slots. | 592 // slots. |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 688 if (cond == le) { | 688 if (cond == le) { |
| 689 __ Mov(result, GREATER); | 689 __ Mov(result, GREATER); |
| 690 } else { | 690 } else { |
| 691 __ Mov(result, LESS); | 691 __ Mov(result, LESS); |
| 692 } | 692 } |
| 693 __ Ret(); | 693 __ Ret(); |
| 694 } | 694 } |
| 695 | 695 |
| 696 // No fall through here. | 696 // No fall through here. |
| 697 if (FLAG_debug_code) { | 697 if (FLAG_debug_code) { |
| 698 __ Abort("We should never reach this code."); | 698 __ Unreachable(); |
| 699 } | 699 } |
| 700 | 700 |
| 701 __ Bind(¬_identical); | 701 __ Bind(¬_identical); |
| 702 } | 702 } |
| 703 | 703 |
| 704 | 704 |
| 705 // See call site for description. | 705 // See call site for description. |
| 706 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 706 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
| 707 Register left, | 707 Register left, |
| 708 Register right, | 708 Register right, |
| 709 Register left_type, | 709 Register left_type, |
| 710 Register right_type, | 710 Register right_type, |
| 711 Register scratch) { | 711 Register scratch) { |
| 712 ASSERT(!AreAliased(left, right, left_type, right_type, scratch)); | 712 ASSERT(!AreAliased(left, right, left_type, right_type, scratch)); |
| 713 | 713 |
| 714 if (masm->emit_debug_code()) { | 714 if (masm->emit_debug_code()) { |
| 715 // We assume that the arguments are not identical. | 715 // We assume that the arguments are not identical. |
| 716 __ Cmp(left, right); | 716 __ Cmp(left, right); |
| 717 __ Assert(ne, "Expected non-identical objects."); | 717 __ Assert(ne, kExpectedNonIdenticalObjects); |
| 718 } | 718 } |
| 719 | 719 |
| 720 // If either operand is a JS object or an oddball value, then they are not | 720 // If either operand is a JS object or an oddball value, then they are not |
| 721 // equal since their pointers are different. | 721 // equal since their pointers are different. |
| 722 // There is no test for undetectability in strict equality. | 722 // There is no test for undetectability in strict equality. |
| 723 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); | 723 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); |
| 724 Label right_non_object; | 724 Label right_non_object; |
| 725 | 725 |
| 726 __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE); | 726 __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE); |
| 727 __ B(lt, &right_non_object); | 727 __ B(lt, &right_non_object); |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1029 if (cond == eq) { | 1029 if (cond == eq) { |
| 1030 StringCompareStub::GenerateFlatAsciiStringEquals(masm, lhs, rhs, | 1030 StringCompareStub::GenerateFlatAsciiStringEquals(masm, lhs, rhs, |
| 1031 x10, x11, x12); | 1031 x10, x11, x12); |
| 1032 } else { | 1032 } else { |
| 1033 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, lhs, rhs, | 1033 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, lhs, rhs, |
| 1034 x10, x11, x12, x13); | 1034 x10, x11, x12, x13); |
| 1035 } | 1035 } |
| 1036 | 1036 |
| 1037 // Never fall through to here. | 1037 // Never fall through to here. |
| 1038 if (FLAG_debug_code) { | 1038 if (FLAG_debug_code) { |
| 1039 __ Abort("We should never reach this code."); | 1039 __ Unreachable(); |
| 1040 } | 1040 } |
| 1041 | 1041 |
| 1042 __ Bind(&slow); | 1042 __ Bind(&slow); |
| 1043 | 1043 |
| 1044 __ Push(lhs, rhs); | 1044 __ Push(lhs, rhs); |
| 1045 // Figure out which native to call and setup the arguments. | 1045 // Figure out which native to call and setup the arguments. |
| 1046 Builtins::JavaScript native; | 1046 Builtins::JavaScript native; |
| 1047 if (cond == eq) { | 1047 if (cond == eq) { |
| 1048 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | 1048 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
| 1049 } else { | 1049 } else { |
| (...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1579 | 1579 |
| 1580 // Code falls through if the result is not returned as either a smi or heap | 1580 // Code falls through if the result is not returned as either a smi or heap |
| 1581 // number. | 1581 // number. |
| 1582 __ Bind(&right_arg_changed); | 1582 __ Bind(&right_arg_changed); |
| 1583 GenerateTypeTransition(masm); | 1583 GenerateTypeTransition(masm); |
| 1584 | 1584 |
| 1585 __ Bind(&call_runtime); | 1585 __ Bind(&call_runtime); |
| 1586 #ifdef DEBUG | 1586 #ifdef DEBUG |
| 1587 if (masm->emit_debug_code()) { | 1587 if (masm->emit_debug_code()) { |
| 1588 __ Cmp(saved_left, x1); | 1588 __ Cmp(saved_left, x1); |
| 1589 __ Assert(eq, "lhs has been clobbered."); | 1589 __ Assert(eq, kLhsHasBeenClobbered); |
| 1590 __ Cmp(saved_right, x0); | 1590 __ Cmp(saved_right, x0); |
| 1591 __ Assert(eq, "lhs has been clobbered."); | 1591 __ Assert(eq, kRhsHasBeenClobbered); |
| 1592 } | 1592 } |
| 1593 #endif | 1593 #endif |
| 1594 { | 1594 { |
| 1595 FrameScope scope(masm, StackFrame::INTERNAL); | 1595 FrameScope scope(masm, StackFrame::INTERNAL); |
| 1596 GenerateRegisterArgsPush(masm); | 1596 GenerateRegisterArgsPush(masm); |
| 1597 GenerateCallRuntime(masm); | 1597 GenerateCallRuntime(masm); |
| 1598 } | 1598 } |
| 1599 __ Ret(); | 1599 __ Ret(); |
| 1600 } | 1600 } |
| 1601 | 1601 |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1769 ASSERT(!AreAliased(result, heap_number_map, scratch1, scratch2)); | 1769 ASSERT(!AreAliased(result, heap_number_map, scratch1, scratch2)); |
| 1770 | 1770 |
| 1771 if ((mode == OVERWRITE_LEFT) || (mode == OVERWRITE_RIGHT)) { | 1771 if ((mode == OVERWRITE_LEFT) || (mode == OVERWRITE_RIGHT)) { |
| 1772 Label skip_allocation, allocated; | 1772 Label skip_allocation, allocated; |
| 1773 Register overwritable_operand = (mode == OVERWRITE_LEFT) ? x1 : x0; | 1773 Register overwritable_operand = (mode == OVERWRITE_LEFT) ? x1 : x0; |
| 1774 if (masm->emit_debug_code()) { | 1774 if (masm->emit_debug_code()) { |
| 1775 // Check that the overwritable operand is a Smi or a HeapNumber. | 1775 // Check that the overwritable operand is a Smi or a HeapNumber. |
| 1776 Label ok; | 1776 Label ok; |
| 1777 __ JumpIfSmi(overwritable_operand, &ok); | 1777 __ JumpIfSmi(overwritable_operand, &ok); |
| 1778 __ JumpIfHeapNumber(overwritable_operand, &ok); | 1778 __ JumpIfHeapNumber(overwritable_operand, &ok); |
| 1779 __ Abort("The overwritable operand should be a HeapNumber"); | 1779 __ Abort(kExpectedSmiOrHeapNumber); |
| 1780 __ Bind(&ok); | 1780 __ Bind(&ok); |
| 1781 } | 1781 } |
| 1782 // If the overwritable operand is already a HeapNumber, we can skip | 1782 // If the overwritable operand is already a HeapNumber, we can skip |
| 1783 // allocation of a heap number. | 1783 // allocation of a heap number. |
| 1784 __ JumpIfNotSmi(overwritable_operand, &skip_allocation); | 1784 __ JumpIfNotSmi(overwritable_operand, &skip_allocation); |
| 1785 // Allocate a heap number for the result. | 1785 // Allocate a heap number for the result. |
| 1786 __ AllocateHeapNumber(result, gc_required, scratch1, scratch2, | 1786 __ AllocateHeapNumber(result, gc_required, scratch1, scratch2, |
| 1787 heap_number_map); | 1787 heap_number_map); |
| 1788 __ B(&allocated); | 1788 __ B(&allocated); |
| 1789 __ Bind(&skip_allocation); | 1789 __ Bind(&skip_allocation); |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2146 // A64 simulator does not currently simulate FPCR (where the rounding | 2146 // A64 simulator does not currently simulate FPCR (where the rounding |
| 2147 // mode is set), so test the operation with some debug code. | 2147 // mode is set), so test the operation with some debug code. |
| 2148 if (masm->emit_debug_code()) { | 2148 if (masm->emit_debug_code()) { |
| 2149 Register temp = masm->Tmp1(); | 2149 Register temp = masm->Tmp1(); |
| 2150 // d5 zero_double The value +0.0 as a double. | 2150 // d5 zero_double The value +0.0 as a double. |
| 2151 __ Fneg(scratch0_double, zero_double); | 2151 __ Fneg(scratch0_double, zero_double); |
| 2152 // Verify that we correctly generated +0.0 and -0.0. | 2152 // Verify that we correctly generated +0.0 and -0.0. |
| 2153 // bits(+0.0) = 0x0000000000000000 | 2153 // bits(+0.0) = 0x0000000000000000 |
| 2154 // bits(-0.0) = 0x8000000000000000 | 2154 // bits(-0.0) = 0x8000000000000000 |
| 2155 __ Fmov(temp, zero_double); | 2155 __ Fmov(temp, zero_double); |
| 2156 __ CheckRegisterIsClear(temp, "Could not generate +0.0."); | 2156 __ CheckRegisterIsClear(temp, kCouldNotGenerateZero); |
| 2157 __ Fmov(temp, scratch0_double); | 2157 __ Fmov(temp, scratch0_double); |
| 2158 __ Eor(temp, temp, kDSignMask); | 2158 __ Eor(temp, temp, kDSignMask); |
| 2159 __ CheckRegisterIsClear(temp, "Could not generate -0.0."); | 2159 __ CheckRegisterIsClear(temp, kCouldNotGenerateNegativeZero); |
| 2160 // Check that -0.0 + 0.0 == +0.0. | 2160 // Check that -0.0 + 0.0 == +0.0. |
| 2161 __ Fadd(scratch0_double, scratch0_double, zero_double); | 2161 __ Fadd(scratch0_double, scratch0_double, zero_double); |
| 2162 __ Fmov(temp, scratch0_double); | 2162 __ Fmov(temp, scratch0_double); |
| 2163 __ CheckRegisterIsClear(temp, "-0.0 + 0.0 did not produce +0.0."); | 2163 __ CheckRegisterIsClear(temp, kExpectedPositiveZero); |
| 2164 } | 2164 } |
| 2165 | 2165 |
| 2166 // If base is -INFINITY, make it +INFINITY. | 2166 // If base is -INFINITY, make it +INFINITY. |
| 2167 // * Calculate base - base: All infinities will become NaNs since both | 2167 // * Calculate base - base: All infinities will become NaNs since both |
| 2168 // -INFINITY+INFINITY and +INFINITY-INFINITY are NaN in A64. | 2168 // -INFINITY+INFINITY and +INFINITY-INFINITY are NaN in A64. |
| 2169 // * If the result is NaN, calculate abs(base). | 2169 // * If the result is NaN, calculate abs(base). |
| 2170 __ Fsub(scratch0_double, base_double, base_double); | 2170 __ Fsub(scratch0_double, base_double, base_double); |
| 2171 __ Fcmp(scratch0_double, 0.0); | 2171 __ Fcmp(scratch0_double, 0.0); |
| 2172 __ Fabs(scratch1_double, base_double); | 2172 __ Fabs(scratch1_double, base_double); |
| 2173 __ Fcsel(base_double, scratch1_double, base_double, vs); | 2173 __ Fcsel(base_double, scratch1_double, base_double, vs); |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2425 Label return_location; | 2425 Label return_location; |
| 2426 __ Adr(x12, &return_location); | 2426 __ Adr(x12, &return_location); |
| 2427 __ Poke(x12, 0); | 2427 __ Poke(x12, 0); |
| 2428 if (__ emit_debug_code()) { | 2428 if (__ emit_debug_code()) { |
| 2429 // Verify that the slot below fp[kSPOffset]-8 points to the return location | 2429 // Verify that the slot below fp[kSPOffset]-8 points to the return location |
| 2430 // (currently in x12). | 2430 // (currently in x12). |
| 2431 Register temp = masm->Tmp1(); | 2431 Register temp = masm->Tmp1(); |
| 2432 __ Ldr(temp, MemOperand(fp, ExitFrameConstants::kSPOffset)); | 2432 __ Ldr(temp, MemOperand(fp, ExitFrameConstants::kSPOffset)); |
| 2433 __ Ldr(temp, MemOperand(temp, -static_cast<int64_t>(kXRegSizeInBytes))); | 2433 __ Ldr(temp, MemOperand(temp, -static_cast<int64_t>(kXRegSizeInBytes))); |
| 2434 __ Cmp(temp, x12); | 2434 __ Cmp(temp, x12); |
| 2435 __ Check(eq, "fp[kSPOffset]-8 does not hold the return address."); | 2435 __ Check(eq, kReturnAddressNotFoundInFrame); |
| 2436 } | 2436 } |
| 2437 | 2437 |
| 2438 // Call the builtin. | 2438 // Call the builtin. |
| 2439 __ Blr(target); | 2439 __ Blr(target); |
| 2440 __ Bind(&return_location); | 2440 __ Bind(&return_location); |
| 2441 const Register& result = x0; | 2441 const Register& result = x0; |
| 2442 | 2442 |
| 2443 if (always_allocate) { | 2443 if (always_allocate) { |
| 2444 __ Mov(x10, Operand(scope_depth)); | 2444 __ Mov(x10, Operand(scope_depth)); |
| 2445 __ Ldr(x11, MemOperand(x10)); | 2445 __ Ldr(x11, MemOperand(x10)); |
| (...skipping 1304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3750 ASSERT(jssp.Is(__ StackPointer())); | 3750 ASSERT(jssp.Is(__ StackPointer())); |
| 3751 __ Peek(jsregexp_object, kJSRegExpOffset); | 3751 __ Peek(jsregexp_object, kJSRegExpOffset); |
| 3752 __ JumpIfSmi(jsregexp_object, &runtime); | 3752 __ JumpIfSmi(jsregexp_object, &runtime); |
| 3753 __ JumpIfNotObjectType(jsregexp_object, x10, x10, JS_REGEXP_TYPE, &runtime); | 3753 __ JumpIfNotObjectType(jsregexp_object, x10, x10, JS_REGEXP_TYPE, &runtime); |
| 3754 | 3754 |
| 3755 // Check that the RegExp has been compiled (data contains a fixed array). | 3755 // Check that the RegExp has been compiled (data contains a fixed array). |
| 3756 __ Ldr(regexp_data, FieldMemOperand(jsregexp_object, JSRegExp::kDataOffset)); | 3756 __ Ldr(regexp_data, FieldMemOperand(jsregexp_object, JSRegExp::kDataOffset)); |
| 3757 if (FLAG_debug_code) { | 3757 if (FLAG_debug_code) { |
| 3758 STATIC_ASSERT(kSmiTag == 0); | 3758 STATIC_ASSERT(kSmiTag == 0); |
| 3759 __ Tst(regexp_data, kSmiTagMask); | 3759 __ Tst(regexp_data, kSmiTagMask); |
| 3760 __ Check(ne, "Unexpected type for RegExp data, FixedArray expected"); | 3760 __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected); |
| 3761 __ CompareObjectType(regexp_data, x10, x10, FIXED_ARRAY_TYPE); | 3761 __ CompareObjectType(regexp_data, x10, x10, FIXED_ARRAY_TYPE); |
| 3762 __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); | 3762 __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected); |
| 3763 } | 3763 } |
| 3764 | 3764 |
| 3765 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | 3765 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
| 3766 __ Ldr(x10, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); | 3766 __ Ldr(x10, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); |
| 3767 __ Cmp(x10, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); | 3767 __ Cmp(x10, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); |
| 3768 __ B(ne, &runtime); | 3768 __ B(ne, &runtime); |
| 3769 | 3769 |
| 3770 // Check that the number of captures fit in the static offsets vector buffer. | 3770 // Check that the number of captures fit in the static offsets vector buffer. |
| 3771 // We have always at least one capture for the whole match, plus additional | 3771 // We have always at least one capture for the whole match, plus additional |
| 3772 // ones due to capturing parentheses. A capture takes 2 registers. | 3772 // ones due to capturing parentheses. A capture takes 2 registers. |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4152 __ B(ne, ¬_long_external); // Go to (8). | 4152 __ B(ne, ¬_long_external); // Go to (8). |
| 4153 | 4153 |
| 4154 // (7) External string. Make it, offset-wise, look like a sequential string. | 4154 // (7) External string. Make it, offset-wise, look like a sequential string. |
| 4155 __ Bind(&external_string); | 4155 __ Bind(&external_string); |
| 4156 if (masm->emit_debug_code()) { | 4156 if (masm->emit_debug_code()) { |
| 4157 // Assert that we do not have a cons or slice (indirect strings) here. | 4157 // Assert that we do not have a cons or slice (indirect strings) here. |
| 4158 // Sequential strings have already been ruled out. | 4158 // Sequential strings have already been ruled out. |
| 4159 __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset)); | 4159 __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset)); |
| 4160 __ Ldrb(x10, FieldMemOperand(x10, Map::kInstanceTypeOffset)); | 4160 __ Ldrb(x10, FieldMemOperand(x10, Map::kInstanceTypeOffset)); |
| 4161 __ Tst(x10, kIsIndirectStringMask); | 4161 __ Tst(x10, kIsIndirectStringMask); |
| 4162 __ Check(eq, "external string expected, but cons or sliced string found"); | 4162 __ Check(eq, kExternalStringExpectedButNotFound); |
| 4163 __ And(x10, x10, kStringRepresentationMask); | 4163 __ And(x10, x10, kStringRepresentationMask); |
| 4164 __ Cmp(x10, 0); | 4164 __ Cmp(x10, 0); |
| 4165 __ Check(ne, "external string expected, but sequential string found"); | 4165 __ Check(ne, kExternalStringExpectedButNotFound); |
| 4166 } | 4166 } |
| 4167 __ Ldr(subject, | 4167 __ Ldr(subject, |
| 4168 FieldMemOperand(subject, ExternalString::kResourceDataOffset)); | 4168 FieldMemOperand(subject, ExternalString::kResourceDataOffset)); |
| 4169 // Move the pointer so that offset-wise, it looks like a sequential string. | 4169 // Move the pointer so that offset-wise, it looks like a sequential string. |
| 4170 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 4170 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
| 4171 __ Sub(subject, subject, SeqTwoByteString::kHeaderSize - kHeapObjectTag); | 4171 __ Sub(subject, subject, SeqTwoByteString::kHeaderSize - kHeapObjectTag); |
| 4172 __ B(&seq_string); // Go to (5). | 4172 __ B(&seq_string); // Go to (5). |
| 4173 | 4173 |
| 4174 // (8) If this is a short external string or not a string, bail out to | 4174 // (8) If this is a short external string or not a string, bail out to |
| 4175 // runtime. | 4175 // runtime. |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4528 result_, | 4528 result_, |
| 4529 &call_runtime_); | 4529 &call_runtime_); |
| 4530 __ SmiTag(result_); | 4530 __ SmiTag(result_); |
| 4531 __ Bind(&exit_); | 4531 __ Bind(&exit_); |
| 4532 } | 4532 } |
| 4533 | 4533 |
| 4534 | 4534 |
| 4535 void StringCharCodeAtGenerator::GenerateSlow( | 4535 void StringCharCodeAtGenerator::GenerateSlow( |
| 4536 MacroAssembler* masm, | 4536 MacroAssembler* masm, |
| 4537 const RuntimeCallHelper& call_helper) { | 4537 const RuntimeCallHelper& call_helper) { |
| 4538 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); | 4538 __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase); |
| 4539 | 4539 |
| 4540 __ Bind(&index_not_smi_); | 4540 __ Bind(&index_not_smi_); |
| 4541 // If index is a heap number, try converting it to an integer. | 4541 // If index is a heap number, try converting it to an integer. |
| 4542 __ CheckMap(index_, | 4542 __ CheckMap(index_, |
| 4543 result_, | 4543 result_, |
| 4544 Heap::kHeapNumberMapRootIndex, | 4544 Heap::kHeapNumberMapRootIndex, |
| 4545 index_not_number_, | 4545 index_not_number_, |
| 4546 DONT_DO_SMI_CHECK); | 4546 DONT_DO_SMI_CHECK); |
| 4547 call_helper.BeforeCall(masm); | 4547 call_helper.BeforeCall(masm); |
| 4548 // Save object_ on the stack and pass index_ as argument for runtime call. | 4548 // Save object_ on the stack and pass index_ as argument for runtime call. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 4573 // is too complex (e.g., when the string needs to be flattened). | 4573 // is too complex (e.g., when the string needs to be flattened). |
| 4574 __ Bind(&call_runtime_); | 4574 __ Bind(&call_runtime_); |
| 4575 call_helper.BeforeCall(masm); | 4575 call_helper.BeforeCall(masm); |
| 4576 __ SmiTag(index_); | 4576 __ SmiTag(index_); |
| 4577 __ Push(object_, index_); | 4577 __ Push(object_, index_); |
| 4578 __ CallRuntime(Runtime::kStringCharCodeAt, 2); | 4578 __ CallRuntime(Runtime::kStringCharCodeAt, 2); |
| 4579 __ Mov(result_, x0); | 4579 __ Mov(result_, x0); |
| 4580 call_helper.AfterCall(masm); | 4580 call_helper.AfterCall(masm); |
| 4581 __ B(&exit_); | 4581 __ B(&exit_); |
| 4582 | 4582 |
| 4583 __ Abort("Unexpected fallthrough from CharCodeAt slow case"); | 4583 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); |
| 4584 } | 4584 } |
| 4585 | 4585 |
| 4586 | 4586 |
| 4587 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { | 4587 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { |
| 4588 __ JumpIfNotSmi(code_, &slow_case_); | 4588 __ JumpIfNotSmi(code_, &slow_case_); |
| 4589 __ Cmp(code_, Operand(Smi::FromInt(String::kMaxOneByteCharCode))); | 4589 __ Cmp(code_, Operand(Smi::FromInt(String::kMaxOneByteCharCode))); |
| 4590 __ B(hi, &slow_case_); | 4590 __ B(hi, &slow_case_); |
| 4591 | 4591 |
| 4592 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); | 4592 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); |
| 4593 // At this point code register contains smi tagged ASCII char code. | 4593 // At this point code register contains smi tagged ASCII char code. |
| 4594 STATIC_ASSERT(kSmiShift > kPointerSizeLog2); | 4594 STATIC_ASSERT(kSmiShift > kPointerSizeLog2); |
| 4595 __ Add(result_, result_, Operand(code_, LSR, kSmiShift - kPointerSizeLog2)); | 4595 __ Add(result_, result_, Operand(code_, LSR, kSmiShift - kPointerSizeLog2)); |
| 4596 __ Ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); | 4596 __ Ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); |
| 4597 __ JumpIfRoot(result_, Heap::kUndefinedValueRootIndex, &slow_case_); | 4597 __ JumpIfRoot(result_, Heap::kUndefinedValueRootIndex, &slow_case_); |
| 4598 __ Bind(&exit_); | 4598 __ Bind(&exit_); |
| 4599 } | 4599 } |
| 4600 | 4600 |
| 4601 | 4601 |
| 4602 void StringCharFromCodeGenerator::GenerateSlow( | 4602 void StringCharFromCodeGenerator::GenerateSlow( |
| 4603 MacroAssembler* masm, | 4603 MacroAssembler* masm, |
| 4604 const RuntimeCallHelper& call_helper) { | 4604 const RuntimeCallHelper& call_helper) { |
| 4605 __ Abort("Unexpected fallthrough to CharFromCode slow case"); | 4605 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); |
| 4606 | 4606 |
| 4607 __ Bind(&slow_case_); | 4607 __ Bind(&slow_case_); |
| 4608 call_helper.BeforeCall(masm); | 4608 call_helper.BeforeCall(masm); |
| 4609 __ Push(code_); | 4609 __ Push(code_); |
| 4610 __ CallRuntime(Runtime::kCharFromCode, 1); | 4610 __ CallRuntime(Runtime::kCharFromCode, 1); |
| 4611 __ Mov(result_, x0); | 4611 __ Mov(result_, x0); |
| 4612 call_helper.AfterCall(masm); | 4612 call_helper.AfterCall(masm); |
| 4613 __ B(&exit_); | 4613 __ B(&exit_); |
| 4614 | 4614 |
| 4615 __ Abort("Unexpected fallthrough from CharFromCode slow case"); | 4615 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
| 4616 } | 4616 } |
| 4617 | 4617 |
| 4618 | 4618 |
| 4619 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 4619 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |
| 4620 // Inputs are in x0 (lhs) and x1 (rhs). | 4620 // Inputs are in x0 (lhs) and x1 (rhs). |
| 4621 ASSERT(state_ == CompareIC::SMI); | 4621 ASSERT(state_ == CompareIC::SMI); |
| 4622 ASM_LOCATION("ICCompareStub[Smis]"); | 4622 ASM_LOCATION("ICCompareStub[Smis]"); |
| 4623 Label miss; | 4623 Label miss; |
| 4624 // Bail out (to 'miss') unless both x0 and x1 are smis. | 4624 // Bail out (to 'miss') unless both x0 and x1 are smis. |
| 4625 __ JumpIfEitherNotSmi(x0, x1, &miss); | 4625 __ JumpIfEitherNotSmi(x0, x1, &miss); |
| (...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5144 // If entry is undefined no string with this hash can be found. | 5144 // If entry is undefined no string with this hash can be found. |
| 5145 Label is_string; | 5145 Label is_string; |
| 5146 Register type = scratch; | 5146 Register type = scratch; |
| 5147 __ JumpIfNotObjectType(candidate, type, type, ODDBALL_TYPE, &is_string); | 5147 __ JumpIfNotObjectType(candidate, type, type, ODDBALL_TYPE, &is_string); |
| 5148 | 5148 |
| 5149 __ Cmp(undefined, candidate); | 5149 __ Cmp(undefined, candidate); |
| 5150 __ B(eq, not_found); | 5150 __ B(eq, not_found); |
| 5151 // Must be the hole (deleted entry). | 5151 // Must be the hole (deleted entry). |
| 5152 if (FLAG_debug_code) { | 5152 if (FLAG_debug_code) { |
| 5153 __ CompareRoot(candidate, Heap::kTheHoleValueRootIndex); | 5153 __ CompareRoot(candidate, Heap::kTheHoleValueRootIndex); |
| 5154 __ Assert(eq, "oddball in string table is not undefined or the hole"); | 5154 __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole); |
| 5155 } | 5155 } |
| 5156 __ B(&next_probe[i]); | 5156 __ B(&next_probe[i]); |
| 5157 | 5157 |
| 5158 __ Bind(&is_string); | 5158 __ Bind(&is_string); |
| 5159 | 5159 |
| 5160 // Check that the candidate is a non-external ASCII string. The instance | 5160 // Check that the candidate is a non-external ASCII string. The instance |
| 5161 // type is still in the type register from the CompareObjectType | 5161 // type is still in the type register from the CompareObjectType |
| 5162 // operation. | 5162 // operation. |
| 5163 __ JumpIfInstanceTypeIsNotSequentialAscii(type, type, &next_probe[i]); | 5163 __ JumpIfInstanceTypeIsNotSequentialAscii(type, type, &next_probe[i]); |
| 5164 | 5164 |
| (...skipping 1611 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6776 ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i); | 6776 ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i); |
| 6777 // TODO(jbramley): Is this the best way to handle this? Can we make the tail | 6777 // TODO(jbramley): Is this the best way to handle this? Can we make the tail |
| 6778 // calls conditional, rather than hopping over each one? | 6778 // calls conditional, rather than hopping over each one? |
| 6779 __ CompareAndBranch(kind, candidate_kind, ne, &next); | 6779 __ CompareAndBranch(kind, candidate_kind, ne, &next); |
| 6780 T stub(candidate_kind); | 6780 T stub(candidate_kind); |
| 6781 __ TailCallStub(&stub); | 6781 __ TailCallStub(&stub); |
| 6782 __ Bind(&next); | 6782 __ Bind(&next); |
| 6783 } | 6783 } |
| 6784 | 6784 |
| 6785 // If we reached this point there is a problem. | 6785 // If we reached this point there is a problem. |
| 6786 __ Abort("Unexpected ElementsKind in array constructor"); | 6786 __ Abort(kUnexpectedElementsKindInArrayConstructor); |
| 6787 } | 6787 } |
| 6788 | 6788 |
| 6789 | 6789 |
| 6790 // TODO(jbramley): If this needs to be a special case, make it a proper template | 6790 // TODO(jbramley): If this needs to be a special case, make it a proper template |
| 6791 // specialization, and not a separate function. | 6791 // specialization, and not a separate function. |
| 6792 static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { | 6792 static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { |
| 6793 // x0 - argc | 6793 // x0 - argc |
| 6794 // x1 - constructor? | 6794 // x1 - constructor? |
| 6795 // x2 - type info cell | 6795 // x2 - type info cell |
| 6796 // x3 - kind | 6796 // x3 - kind |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6839 ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i); | 6839 ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i); |
| 6840 // TODO(jbramley): Is this the best way to handle this? Can we make the tail | 6840 // TODO(jbramley): Is this the best way to handle this? Can we make the tail |
| 6841 // calls conditional, rather than hopping over each one? | 6841 // calls conditional, rather than hopping over each one? |
| 6842 __ CompareAndBranch(kind, candidate_kind, ne, &next); | 6842 __ CompareAndBranch(kind, candidate_kind, ne, &next); |
| 6843 ArraySingleArgumentConstructorStub stub(candidate_kind); | 6843 ArraySingleArgumentConstructorStub stub(candidate_kind); |
| 6844 __ TailCallStub(&stub); | 6844 __ TailCallStub(&stub); |
| 6845 __ Bind(&next); | 6845 __ Bind(&next); |
| 6846 } | 6846 } |
| 6847 | 6847 |
| 6848 // If we reached this point there is a problem. | 6848 // If we reached this point there is a problem. |
| 6849 __ Abort("Unexpected ElementsKind in array constructor"); | 6849 __ Abort(kUnexpectedElementsKindInArrayConstructor); |
| 6850 } | 6850 } |
| 6851 | 6851 |
| 6852 | 6852 |
| 6853 template<class T> | 6853 template<class T> |
| 6854 static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { | 6854 static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { |
| 6855 int to_index = GetSequenceIndexFromFastElementsKind( | 6855 int to_index = GetSequenceIndexFromFastElementsKind( |
| 6856 TERMINAL_FAST_ELEMENTS_KIND); | 6856 TERMINAL_FAST_ELEMENTS_KIND); |
| 6857 for (int i = 0; i <= to_index; ++i) { | 6857 for (int i = 0; i <= to_index; ++i) { |
| 6858 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); | 6858 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); |
| 6859 T stub(kind); | 6859 T stub(kind); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6908 // builtin Array functions which always have maps. | 6908 // builtin Array functions which always have maps. |
| 6909 | 6909 |
| 6910 Label unexpected_map, map_ok; | 6910 Label unexpected_map, map_ok; |
| 6911 // Initial map for the builtin Array function should be a map. | 6911 // Initial map for the builtin Array function should be a map. |
| 6912 __ Ldr(x10, FieldMemOperand(constructor, | 6912 __ Ldr(x10, FieldMemOperand(constructor, |
| 6913 JSFunction::kPrototypeOrInitialMapOffset)); | 6913 JSFunction::kPrototypeOrInitialMapOffset)); |
| 6914 // Will both indicate a NULL and a Smi. | 6914 // Will both indicate a NULL and a Smi. |
| 6915 __ JumpIfSmi(x10, &unexpected_map); | 6915 __ JumpIfSmi(x10, &unexpected_map); |
| 6916 __ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok); | 6916 __ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok); |
| 6917 __ Bind(&unexpected_map); | 6917 __ Bind(&unexpected_map); |
| 6918 __ Abort("Unexpected initial map for Array function"); | 6918 __ Abort(kUnexpectedInitialMapForArrayFunction); |
| 6919 __ Bind(&map_ok); | 6919 __ Bind(&map_ok); |
| 6920 | 6920 |
| 6921 // In type_info_cell, we expect either undefined or a valid Cell. | 6921 // In type_info_cell, we expect either undefined or a valid Cell. |
| 6922 Label okay_here; | 6922 Label okay_here; |
| 6923 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); | 6923 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); |
| 6924 __ JumpIfRoot(type_info_cell, Heap::kUndefinedValueRootIndex, &okay_here); | 6924 __ JumpIfRoot(type_info_cell, Heap::kUndefinedValueRootIndex, &okay_here); |
| 6925 __ Ldr(x10, FieldMemOperand(type_info_cell, Cell::kMapOffset)); | 6925 __ Ldr(x10, FieldMemOperand(type_info_cell, Cell::kMapOffset)); |
| 6926 __ Cmp(x10, Operand(cell_map)); | 6926 __ Cmp(x10, Operand(cell_map)); |
| 6927 __ Assert(eq, "Expected property cell in type_info_cell"); | 6927 __ Assert(eq, kExpectedPropertyCellInTypeInfoCell); |
| 6928 __ Bind(&okay_here); | 6928 __ Bind(&okay_here); |
| 6929 } | 6929 } |
| 6930 | 6930 |
| 6931 Register kind = x3; | 6931 Register kind = x3; |
| 6932 Label no_info, switch_ready; | 6932 Label no_info, switch_ready; |
| 6933 // Get the elements kind and case on that. | 6933 // Get the elements kind and case on that. |
| 6934 __ JumpIfRoot(type_info_cell, Heap::kUndefinedValueRootIndex, &no_info); | 6934 __ JumpIfRoot(type_info_cell, Heap::kUndefinedValueRootIndex, &no_info); |
| 6935 __ Ldr(kind, FieldMemOperand(type_info_cell, PropertyCell::kValueOffset)); | 6935 __ Ldr(kind, FieldMemOperand(type_info_cell, PropertyCell::kValueOffset)); |
| 6936 | 6936 |
| 6937 // The type cell may have undefined in its value. | 6937 // The type cell may have undefined in its value. |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7033 // builtin Array functions which always have maps. | 7033 // builtin Array functions which always have maps. |
| 7034 | 7034 |
| 7035 Label unexpected_map, map_ok; | 7035 Label unexpected_map, map_ok; |
| 7036 // Initial map for the builtin Array function should be a map. | 7036 // Initial map for the builtin Array function should be a map. |
| 7037 __ Ldr(x10, FieldMemOperand(constructor, | 7037 __ Ldr(x10, FieldMemOperand(constructor, |
| 7038 JSFunction::kPrototypeOrInitialMapOffset)); | 7038 JSFunction::kPrototypeOrInitialMapOffset)); |
| 7039 // Will both indicate a NULL and a Smi. | 7039 // Will both indicate a NULL and a Smi. |
| 7040 __ JumpIfSmi(x10, &unexpected_map); | 7040 __ JumpIfSmi(x10, &unexpected_map); |
| 7041 __ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok); | 7041 __ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok); |
| 7042 __ Bind(&unexpected_map); | 7042 __ Bind(&unexpected_map); |
| 7043 __ Abort("Unexpected initial map for Array function"); | 7043 __ Abort(kUnexpectedInitialMapForArrayFunction); |
| 7044 __ Bind(&map_ok); | 7044 __ Bind(&map_ok); |
| 7045 } | 7045 } |
| 7046 | 7046 |
| 7047 Register kind = w3; | 7047 Register kind = w3; |
| 7048 // Figure out the right elements kind | 7048 // Figure out the right elements kind |
| 7049 __ Ldr(x10, FieldMemOperand(constructor, | 7049 __ Ldr(x10, FieldMemOperand(constructor, |
| 7050 JSFunction::kPrototypeOrInitialMapOffset)); | 7050 JSFunction::kPrototypeOrInitialMapOffset)); |
| 7051 | 7051 |
| 7052 // TODO(jbramley): Add a helper function to read elements kind from an | 7052 // TODO(jbramley): Add a helper function to read elements kind from an |
| 7053 // existing map. | 7053 // existing map. |
| 7054 // Load the map's "bit field 2" into result. | 7054 // Load the map's "bit field 2" into result. |
| 7055 __ Ldr(kind, FieldMemOperand(x10, Map::kBitField2Offset)); | 7055 __ Ldr(kind, FieldMemOperand(x10, Map::kBitField2Offset)); |
| 7056 // Retrieve elements_kind from bit field 2. | 7056 // Retrieve elements_kind from bit field 2. |
| 7057 __ Ubfx(kind, kind, Map::kElementsKindShift, Map::kElementsKindBitCount); | 7057 __ Ubfx(kind, kind, Map::kElementsKindShift, Map::kElementsKindBitCount); |
| 7058 | 7058 |
| 7059 if (FLAG_debug_code) { | 7059 if (FLAG_debug_code) { |
| 7060 Label done; | 7060 Label done; |
| 7061 __ Cmp(x3, FAST_ELEMENTS); | 7061 __ Cmp(x3, FAST_ELEMENTS); |
| 7062 __ Ccmp(x3, FAST_HOLEY_ELEMENTS, ZFlag, ne); | 7062 __ Ccmp(x3, FAST_HOLEY_ELEMENTS, ZFlag, ne); |
| 7063 __ Assert(eq, | 7063 __ Assert(eq, kInvalidElementsKindForInternalArrayOrInternalPackedArray); |
| 7064 "Invalid ElementsKind for InternalArray or InternalPackedArray"); | |
| 7065 } | 7064 } |
| 7066 | 7065 |
| 7067 Label fast_elements_case; | 7066 Label fast_elements_case; |
| 7068 __ CompareAndBranch(kind, FAST_ELEMENTS, eq, &fast_elements_case); | 7067 __ CompareAndBranch(kind, FAST_ELEMENTS, eq, &fast_elements_case); |
| 7069 GenerateCase(masm, FAST_HOLEY_ELEMENTS); | 7068 GenerateCase(masm, FAST_HOLEY_ELEMENTS); |
| 7070 | 7069 |
| 7071 __ Bind(&fast_elements_case); | 7070 __ Bind(&fast_elements_case); |
| 7072 GenerateCase(masm, FAST_ELEMENTS); | 7071 GenerateCase(masm, FAST_ELEMENTS); |
| 7073 } | 7072 } |
| 7074 | 7073 |
| 7075 | 7074 |
| 7076 #undef __ | 7075 #undef __ |
| 7077 | 7076 |
| 7078 } } // namespace v8::internal | 7077 } } // namespace v8::internal |
| 7079 | 7078 |
| 7080 #endif // V8_TARGET_ARCH_A64 | 7079 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |