| 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 671 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 682 | 682 |
| 683 // See call site for description. | 683 // See call site for description. |
| 684 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 684 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
| 685 Register left, | 685 Register left, |
| 686 Register right, | 686 Register right, |
| 687 Register left_type, | 687 Register left_type, |
| 688 Register right_type, | 688 Register right_type, |
| 689 Register scratch) { | 689 Register scratch) { |
| 690 ASSERT(!AreAliased(left, right, left_type, right_type, scratch)); | 690 ASSERT(!AreAliased(left, right, left_type, right_type, scratch)); |
| 691 | 691 |
| 692 if (masm->emit_debug_code()) { |
| 693 // We assume that the arguments are not identical. |
| 694 __ Cmp(left, right); |
| 695 __ Assert(ne, "Expected non-identical objects."); |
| 696 } |
| 697 |
| 692 // If either operand is a JS object or an oddball value, then they are not | 698 // If either operand is a JS object or an oddball value, then they are not |
| 693 // equal since their pointers are different. | 699 // equal since their pointers are different. |
| 694 // There is no test for undetectability in strict equality. | 700 // There is no test for undetectability in strict equality. |
| 695 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); | 701 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); |
| 696 Label right_non_object; | 702 Label right_non_object; |
| 697 | 703 |
| 698 __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE); | 704 __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE); |
| 699 __ B(lt, &right_non_object); | 705 __ B(lt, &right_non_object); |
| 700 | 706 |
| 701 // Return non-zero - x0 already contains a non-zero pointer. | 707 // Return non-zero - x0 already contains a non-zero pointer. |
| 702 ASSERT(left.is(x0) || right.is(x0)); | 708 ASSERT(left.is(x0) || right.is(x0)); |
| 703 Label return_not_equal; | 709 Label return_not_equal; |
| 704 __ Bind(&return_not_equal); | 710 __ Bind(&return_not_equal); |
| 705 __ Ret(); | 711 __ Ret(); |
| 706 | 712 |
| 707 __ Bind(&right_non_object); | 713 __ Bind(&right_non_object); |
| 708 | 714 |
| 709 // Check for oddballs: true, false, null, undefined. | 715 // Check for oddballs: true, false, null, undefined. |
| 710 __ Cmp(right_type, ODDBALL_TYPE); | 716 __ Cmp(right_type, ODDBALL_TYPE); |
| 711 | 717 |
| 712 // If right is not ODDBALL, test left. Otherwise, set eq condition. | 718 // If right is not ODDBALL, test left. Otherwise, set eq condition. |
| 713 __ Ccmp(left_type, ODDBALL_TYPE, ZFlag, ne); | 719 __ Ccmp(left_type, ODDBALL_TYPE, ZFlag, ne); |
| 714 | 720 |
| 715 // If right or left is not ODDBALL, test left >= FIRST_SPEC_OBJECT_TYPE. | 721 // If right or left is not ODDBALL, test left >= FIRST_SPEC_OBJECT_TYPE. |
| 716 // Otherwise, right or left is ODDBALL, so set a ge condition. | 722 // Otherwise, right or left is ODDBALL, so set a ge condition. |
| 717 __ Ccmp(left_type, FIRST_SPEC_OBJECT_TYPE, NVFlag, ne); | 723 __ Ccmp(left_type, FIRST_SPEC_OBJECT_TYPE, NVFlag, ne); |
| 718 | 724 |
| 719 __ B(ge, &return_not_equal); | 725 __ B(ge, &return_not_equal); |
| 720 | 726 |
| 721 // Check for internalized-internalized comparison. Ensure that no non-strings | 727 // Internalized strings are unique, so they can only be equal if they are the |
| 722 // have the internalized bit set. | 728 // same object. We have already tested that case, so if left and right are |
| 723 STATIC_ASSERT(LAST_TYPE < (kNotStringTag + kIsInternalizedMask)); | 729 // both internalized strings, they cannot be equal. |
| 724 STATIC_ASSERT(kInternalizedTag != 0); | 730 __ And(scratch, right_type, kIsNotStringMask | kIsInternalizedMask); |
| 725 __ And(scratch, right_type, left_type); | 731 __ Cmp(scratch, kInternalizedTag | kStringTag); |
| 726 __ Tbnz(scratch, MaskToBit(kIsInternalizedMask), &return_not_equal); | 732 __ And(scratch, left_type, kIsNotStringMask | kIsInternalizedMask); |
| 733 __ Ccmp(scratch, kInternalizedTag | kStringTag, NoFlag, eq); |
| 734 __ B(eq, &return_not_equal); |
| 727 } | 735 } |
| 728 | 736 |
| 729 | 737 |
| 730 // See call site for description. | 738 // See call site for description. |
| 731 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 739 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
| 732 Register left, | 740 Register left, |
| 733 Register right, | 741 Register right, |
| 734 FPRegister left_d, | 742 FPRegister left_d, |
| 735 FPRegister right_d, | 743 FPRegister right_d, |
| 736 Register scratch, | 744 Register scratch, |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 807 Register right, | 815 Register right, |
| 808 Register left_map, | 816 Register left_map, |
| 809 Register right_map, | 817 Register right_map, |
| 810 Register left_type, | 818 Register left_type, |
| 811 Register right_type, | 819 Register right_type, |
| 812 Label* possible_strings, | 820 Label* possible_strings, |
| 813 Label* not_both_strings) { | 821 Label* not_both_strings) { |
| 814 ASSERT(!AreAliased(left, right, left_map, right_map, left_type, right_type)); | 822 ASSERT(!AreAliased(left, right, left_map, right_map, left_type, right_type)); |
| 815 Register result = x0; | 823 Register result = x0; |
| 816 | 824 |
| 817 // Ensure that no non-strings have the internalized bit set. | |
| 818 Label object_test; | 825 Label object_test; |
| 819 STATIC_ASSERT(kStringTag == 0); | 826 STATIC_ASSERT(kStringTag == 0); |
| 820 STATIC_ASSERT(kInternalizedTag != 0); | 827 STATIC_ASSERT(kInternalizedTag != 0); |
| 821 // TODO(all): reexamine this branch sequence for optimisation wrt branch | 828 // TODO(all): reexamine this branch sequence for optimisation wrt branch |
| 822 // prediction. | 829 // prediction. |
| 823 __ Tbnz(right_type, MaskToBit(kIsNotStringMask), &object_test); | 830 __ Tbnz(right_type, MaskToBit(kIsNotStringMask), &object_test); |
| 824 __ Tbz(right_type, MaskToBit(kIsInternalizedMask), possible_strings); | 831 __ Tbz(right_type, MaskToBit(kIsInternalizedMask), possible_strings); |
| 825 __ Tbnz(left_type, MaskToBit(kIsNotStringMask), not_both_strings); | 832 __ Tbnz(left_type, MaskToBit(kIsNotStringMask), not_both_strings); |
| 826 __ Tbz(left_type, MaskToBit(kIsInternalizedMask), possible_strings); | 833 __ Tbz(left_type, MaskToBit(kIsInternalizedMask), possible_strings); |
| 827 | 834 |
| (...skipping 919 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1747 } | 1754 } |
| 1748 | 1755 |
| 1749 __ Bind(¬_smis); | 1756 __ Bind(¬_smis); |
| 1750 } | 1757 } |
| 1751 | 1758 |
| 1752 | 1759 |
| 1753 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 1760 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
| 1754 ASM_LOCATION("BinaryOpStub::GenerateSmiStub"); | 1761 ASM_LOCATION("BinaryOpStub::GenerateSmiStub"); |
| 1755 Label right_arg_changed, call_runtime; | 1762 Label right_arg_changed, call_runtime; |
| 1756 | 1763 |
| 1757 if ((op_ == Token::MOD) && has_fixed_right_arg_) { | 1764 if ((op_ == Token::MOD) && encoded_right_arg_.has_value) { |
| 1758 // It is guaranteed that the value will fit into a Smi, because if it | 1765 // It is guaranteed that the value will fit into a Smi, because if it |
| 1759 // didn't, we wouldn't be here, see BinaryOp_Patch. | 1766 // didn't, we wouldn't be here, see BinaryOp_Patch. |
| 1760 __ CompareAndBranch(x0, Operand(Smi::FromInt(fixed_right_arg_value())), ne, | 1767 __ CompareAndBranch(x0, Operand(Smi::FromInt(fixed_right_arg_value())), ne, |
| 1761 &right_arg_changed); | 1768 &right_arg_changed); |
| 1762 } | 1769 } |
| 1763 | 1770 |
| 1764 #ifdef DEBUG | 1771 #ifdef DEBUG |
| 1765 Register saved_left = x18; | 1772 Register saved_left = x18; |
| 1766 Register saved_right = x19; | 1773 Register saved_right = x19; |
| 1767 if (masm->emit_debug_code()) { | 1774 if (masm->emit_debug_code()) { |
| (...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2493 | 2500 |
| 2494 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { | 2501 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { |
| 2495 // It is important that the following stubs are generated in this order | 2502 // It is important that the following stubs are generated in this order |
| 2496 // because pregenerated stubs can only call other pregenerated stubs. | 2503 // because pregenerated stubs can only call other pregenerated stubs. |
| 2497 // RecordWriteStub uses StoreBufferOverflowStub, which in turn uses | 2504 // RecordWriteStub uses StoreBufferOverflowStub, which in turn uses |
| 2498 // CEntryStub. | 2505 // CEntryStub. |
| 2499 CEntryStub::GenerateAheadOfTime(isolate); | 2506 CEntryStub::GenerateAheadOfTime(isolate); |
| 2500 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 2507 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 2501 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 2508 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
| 2502 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); | 2509 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 2503 | 2510 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
| 2504 if (FLAG_optimize_constructed_arrays) { | |
| 2505 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | |
| 2506 } | |
| 2507 } | 2511 } |
| 2508 | 2512 |
| 2509 | 2513 |
| 2510 void CodeStub::GenerateFPStubs(Isolate* isolate) { | 2514 void CodeStub::GenerateFPStubs(Isolate* isolate) { |
| 2511 // Floating-point code doesn't get special handling in A64, so there's | 2515 // Floating-point code doesn't get special handling in A64, so there's |
| 2512 // nothing to do here. | 2516 // nothing to do here. |
| 2513 USE(isolate); | 2517 USE(isolate); |
| 2514 } | 2518 } |
| 2515 | 2519 |
| 2516 | 2520 |
| (...skipping 1935 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4452 | 4456 |
| 4453 __ Bind(&done); | 4457 __ Bind(&done); |
| 4454 __ Ret(); | 4458 __ Ret(); |
| 4455 | 4459 |
| 4456 __ Bind(&slow); | 4460 __ Bind(&slow); |
| 4457 __ Push(length_smi, index_smi, input); | 4461 __ Push(length_smi, index_smi, input); |
| 4458 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); | 4462 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); |
| 4459 } | 4463 } |
| 4460 | 4464 |
| 4461 | 4465 |
| 4462 // TODO(mcapewel): This code has been ported as part of the merge process, but | |
| 4463 // is currently untested. | |
| 4464 // TODO(jbramley): Don't use static registers here, but take them as arguments. | |
| 4465 static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) { | |
| 4466 ASM_UNIMPLEMENTED_BREAK("Untested: GenerateRecordCallTargetNoArray"); | |
| 4467 // Cache the called function in a global property cell. Cache states are | |
| 4468 // uninitialized, monomorphic (indicated by a JSFunction), and megamorphic. | |
| 4469 // x1 : the function to call | |
| 4470 // x2 : cache cell for the call target | |
| 4471 Label done; | |
| 4472 | |
| 4473 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()), | |
| 4474 masm->isolate()->heap()->undefined_value()); | |
| 4475 ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()), | |
| 4476 masm->isolate()->heap()->the_hole_value()); | |
| 4477 | |
| 4478 // Load the cache state. | |
| 4479 __ Ldr(x3, FieldMemOperand(x2, Cell::kValueOffset)); | |
| 4480 | |
| 4481 // A monomorphic cache hit or an already megamorphic state: invoke the | |
| 4482 // function without changing the state. | |
| 4483 __ Cmp(x3, x1); | |
| 4484 __ B(eq, &done); | |
| 4485 __ JumpIfRoot(x3, Heap::kUndefinedValueRootIndex, &done); | |
| 4486 | |
| 4487 // A monomorphic miss (i.e, here the cache is not uninitialized) goes | |
| 4488 // megamorphic. MegamorphicSentinal is an immortal immovable object | |
| 4489 // (undefined) so no write-barrier is needed. | |
| 4490 Label skip_undef_store; | |
| 4491 __ JumpIfRoot(x3, Heap::kTheHoleValueRootIndex, &skip_undef_store); | |
| 4492 __ LoadRoot(ip0, Heap::kUndefinedValueRootIndex); | |
| 4493 __ Str(ip0, FieldMemOperand(x2, Cell::kValueOffset)); | |
| 4494 __ B(&done); | |
| 4495 __ Bind(&skip_undef_store); | |
| 4496 | |
| 4497 // An uninitialized cache is patched with the function. | |
| 4498 __ Str(x1, FieldMemOperand(x2, Cell::kValueOffset)); | |
| 4499 // No need for a write barrier here - cells are rescanned. | |
| 4500 | |
| 4501 __ Bind(&done); | |
| 4502 } | |
| 4503 | |
| 4504 | |
| 4505 // TODO(jbramley): Don't use static registers here, but take them as arguments. | 4466 // TODO(jbramley): Don't use static registers here, but take them as arguments. |
| 4506 static void GenerateRecordCallTarget(MacroAssembler* masm) { | 4467 static void GenerateRecordCallTarget(MacroAssembler* masm) { |
| 4507 // Cache the called function in a global property cell. Cache states are | 4468 // Cache the called function in a global property cell. Cache states are |
| 4508 // uninitialized, monomorphic (indicated by a JSFunction), and megamorphic. | 4469 // uninitialized, monomorphic (indicated by a JSFunction), and megamorphic. |
| 4509 // x1 : the function to call | 4470 // x1 : the function to call |
| 4510 // x2 : cache cell for the call target | 4471 // x2 : cache cell for the call target |
| 4511 ASSERT(FLAG_optimize_constructed_arrays); | |
| 4512 Label initialize, done, miss, megamorphic, not_array_function; | 4472 Label initialize, done, miss, megamorphic, not_array_function; |
| 4513 | 4473 |
| 4514 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()), | 4474 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()), |
| 4515 masm->isolate()->heap()->undefined_value()); | 4475 masm->isolate()->heap()->undefined_value()); |
| 4516 ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()), | 4476 ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()), |
| 4517 masm->isolate()->heap()->the_hole_value()); | 4477 masm->isolate()->heap()->the_hole_value()); |
| 4518 | 4478 |
| 4519 // Load the cache state. | 4479 // Load the cache state. |
| 4520 __ Ldr(x3, FieldMemOperand(x2, Cell::kValueOffset)); | 4480 __ Ldr(x3, FieldMemOperand(x2, Cell::kValueOffset)); |
| 4521 | 4481 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4606 __ Bind(&call); | 4566 __ Bind(&call); |
| 4607 } | 4567 } |
| 4608 | 4568 |
| 4609 // Check that the function is really a JavaScript function. | 4569 // Check that the function is really a JavaScript function. |
| 4610 // x1 function pushed function (to be verified) | 4570 // x1 function pushed function (to be verified) |
| 4611 __ JumpIfSmi(function, &non_function); | 4571 __ JumpIfSmi(function, &non_function); |
| 4612 // Get the map of the function object. | 4572 // Get the map of the function object. |
| 4613 __ JumpIfNotObjectType(function, x10, x10, JS_FUNCTION_TYPE, &slow); | 4573 __ JumpIfNotObjectType(function, x10, x10, JS_FUNCTION_TYPE, &slow); |
| 4614 | 4574 |
| 4615 if (RecordCallTarget()) { | 4575 if (RecordCallTarget()) { |
| 4616 if (FLAG_optimize_constructed_arrays) { | 4576 GenerateRecordCallTarget(masm); |
| 4617 GenerateRecordCallTarget(masm); | |
| 4618 } else { | |
| 4619 GenerateRecordCallTargetNoArray(masm); | |
| 4620 } | |
| 4621 } | 4577 } |
| 4622 | 4578 |
| 4623 // Fast-case: Invoke the function now. | 4579 // Fast-case: Invoke the function now. |
| 4624 // x1 function pushed function | 4580 // x1 function pushed function |
| 4625 ParameterCount actual(argc_); | 4581 ParameterCount actual(argc_); |
| 4626 | 4582 |
| 4627 if (ReceiverMightBeImplicit()) { | 4583 if (ReceiverMightBeImplicit()) { |
| 4628 Label call_as_function; | 4584 Label call_as_function; |
| 4629 __ JumpIfRoot(x4, Heap::kTheHoleValueRootIndex, &call_as_function); | 4585 __ JumpIfRoot(x4, Heap::kTheHoleValueRootIndex, &call_as_function); |
| 4630 __ InvokeFunction(function, | 4586 __ InvokeFunction(function, |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4688 Label slow, non_function_call; | 4644 Label slow, non_function_call; |
| 4689 | 4645 |
| 4690 // Check that the function is not a smi. | 4646 // Check that the function is not a smi. |
| 4691 __ JumpIfSmi(function, &non_function_call); | 4647 __ JumpIfSmi(function, &non_function_call); |
| 4692 // Check that the function is a JSFunction. | 4648 // Check that the function is a JSFunction. |
| 4693 Register object_type = x10; | 4649 Register object_type = x10; |
| 4694 __ JumpIfNotObjectType(function, object_type, object_type, JS_FUNCTION_TYPE, | 4650 __ JumpIfNotObjectType(function, object_type, object_type, JS_FUNCTION_TYPE, |
| 4695 &slow); | 4651 &slow); |
| 4696 | 4652 |
| 4697 if (RecordCallTarget()) { | 4653 if (RecordCallTarget()) { |
| 4698 if (FLAG_optimize_constructed_arrays) { | 4654 GenerateRecordCallTarget(masm); |
| 4699 GenerateRecordCallTarget(masm); | |
| 4700 } else { | |
| 4701 GenerateRecordCallTargetNoArray(masm); | |
| 4702 } | |
| 4703 } | 4655 } |
| 4704 | 4656 |
| 4705 // Jump to the function-specific construct stub. | 4657 // Jump to the function-specific construct stub. |
| 4706 Register jump_reg = FLAG_optimize_constructed_arrays ? x3 : x2; | 4658 Register jump_reg = x3; |
| 4707 Register shared_func_info = jump_reg; | 4659 Register shared_func_info = jump_reg; |
| 4708 Register cons_stub = jump_reg; | 4660 Register cons_stub = jump_reg; |
| 4709 Register cons_stub_code = jump_reg; | 4661 Register cons_stub_code = jump_reg; |
| 4710 __ Ldr(shared_func_info, | 4662 __ Ldr(shared_func_info, |
| 4711 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset)); | 4663 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset)); |
| 4712 __ Ldr(cons_stub, | 4664 __ Ldr(cons_stub, |
| 4713 FieldMemOperand(shared_func_info, | 4665 FieldMemOperand(shared_func_info, |
| 4714 SharedFunctionInfo::kConstructStubOffset)); | 4666 SharedFunctionInfo::kConstructStubOffset)); |
| 4715 __ Add(cons_stub_code, cons_stub, Code::kHeaderSize - kHeapObjectTag); | 4667 __ Add(cons_stub_code, cons_stub, Code::kHeaderSize - kHeapObjectTag); |
| 4716 __ Br(cons_stub_code); | 4668 __ Br(cons_stub_code); |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4957 | 4909 |
| 4958 // Check that both operands are internalized strings. | 4910 // Check that both operands are internalized strings. |
| 4959 Register rhs_map = x10; | 4911 Register rhs_map = x10; |
| 4960 Register lhs_map = x11; | 4912 Register lhs_map = x11; |
| 4961 Register rhs_type = x10; | 4913 Register rhs_type = x10; |
| 4962 Register lhs_type = x11; | 4914 Register lhs_type = x11; |
| 4963 __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset)); | 4915 __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset)); |
| 4964 __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset)); | 4916 __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset)); |
| 4965 __ Ldrb(lhs_type, FieldMemOperand(lhs_map, Map::kInstanceTypeOffset)); | 4917 __ Ldrb(lhs_type, FieldMemOperand(lhs_map, Map::kInstanceTypeOffset)); |
| 4966 __ Ldrb(rhs_type, FieldMemOperand(rhs_map, Map::kInstanceTypeOffset)); | 4918 __ Ldrb(rhs_type, FieldMemOperand(rhs_map, Map::kInstanceTypeOffset)); |
| 4967 __ And(x10, lhs_type, rhs_type); | 4919 |
| 4968 __ Tbz(x10, MaskToBit(kIsInternalizedMask), &miss); | 4920 __ And(x12, rhs_type, kIsNotStringMask | kIsInternalizedMask); |
| 4969 STATIC_ASSERT(kInternalizedTag != 0); | 4921 __ And(x13, lhs_type, kIsNotStringMask | kIsInternalizedMask); |
| 4922 __ Cmp(x12, kInternalizedTag | kStringTag); |
| 4923 __ Ccmp(x13, kInternalizedTag | kStringTag, NoFlag, eq); |
| 4924 __ B(ne, &miss); |
| 4970 | 4925 |
| 4971 // Internalized strings are compared by identity. | 4926 // Internalized strings are compared by identity. |
| 4972 STATIC_ASSERT(EQUAL == 0); | 4927 STATIC_ASSERT(EQUAL == 0); |
| 4973 __ Cmp(lhs, rhs); | 4928 __ Cmp(lhs, rhs); |
| 4974 __ Cset(result, ne); | 4929 __ Cset(result, ne); |
| 4975 __ Ret(); | 4930 __ Ret(); |
| 4976 | 4931 |
| 4977 __ Bind(&miss); | 4932 __ Bind(&miss); |
| 4978 GenerateMiss(masm); | 4933 GenerateMiss(masm); |
| 4979 } | 4934 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 4997 | 4952 |
| 4998 // Check that both operands are unique names. This leaves the instance | 4953 // Check that both operands are unique names. This leaves the instance |
| 4999 // types loaded in tmp1 and tmp2. | 4954 // types loaded in tmp1 and tmp2. |
| 5000 __ Ldr(x10, FieldMemOperand(lhs, HeapObject::kMapOffset)); | 4955 __ Ldr(x10, FieldMemOperand(lhs, HeapObject::kMapOffset)); |
| 5001 __ Ldr(x11, FieldMemOperand(rhs, HeapObject::kMapOffset)); | 4956 __ Ldr(x11, FieldMemOperand(rhs, HeapObject::kMapOffset)); |
| 5002 __ Ldrb(lhs_instance_type, FieldMemOperand(x10, Map::kInstanceTypeOffset)); | 4957 __ Ldrb(lhs_instance_type, FieldMemOperand(x10, Map::kInstanceTypeOffset)); |
| 5003 __ Ldrb(rhs_instance_type, FieldMemOperand(x11, Map::kInstanceTypeOffset)); | 4958 __ Ldrb(rhs_instance_type, FieldMemOperand(x11, Map::kInstanceTypeOffset)); |
| 5004 | 4959 |
| 5005 // To avoid a miss, each instance type should be either SYMBOL_TYPE or it | 4960 // To avoid a miss, each instance type should be either SYMBOL_TYPE or it |
| 5006 // should have kInternalizedTag set. | 4961 // should have kInternalizedTag set. |
| 5007 STATIC_ASSERT(kInternalizedTag != 0); | 4962 __ JumpIfNotUniqueName(lhs_instance_type, &miss); |
| 5008 __ Tst(lhs_instance_type, kIsInternalizedMask); | 4963 __ JumpIfNotUniqueName(rhs_instance_type, &miss); |
| 5009 __ Ccmp(lhs_instance_type, SYMBOL_TYPE, ZFlag, eq); | |
| 5010 __ B(ne, &miss); | |
| 5011 | |
| 5012 __ Tst(rhs_instance_type, kIsInternalizedMask); | |
| 5013 __ Ccmp(rhs_instance_type, SYMBOL_TYPE, ZFlag, eq); | |
| 5014 __ B(ne, &miss); | |
| 5015 | 4964 |
| 5016 // Unique names are compared by identity. | 4965 // Unique names are compared by identity. |
| 5017 STATIC_ASSERT(EQUAL == 0); | 4966 STATIC_ASSERT(EQUAL == 0); |
| 5018 __ Cmp(lhs, rhs); | 4967 __ Cmp(lhs, rhs); |
| 5019 __ Cset(result, ne); | 4968 __ Cset(result, ne); |
| 5020 __ Ret(); | 4969 __ Ret(); |
| 5021 | 4970 |
| 5022 __ Bind(&miss); | 4971 __ Bind(&miss); |
| 5023 GenerateMiss(masm); | 4972 GenerateMiss(masm); |
| 5024 } | 4973 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5056 Label not_equal; | 5005 Label not_equal; |
| 5057 __ Cmp(lhs, rhs); | 5006 __ Cmp(lhs, rhs); |
| 5058 __ B(ne, ¬_equal); | 5007 __ B(ne, ¬_equal); |
| 5059 __ Mov(result, EQUAL); | 5008 __ Mov(result, EQUAL); |
| 5060 __ Ret(); | 5009 __ Ret(); |
| 5061 | 5010 |
| 5062 __ Bind(¬_equal); | 5011 __ Bind(¬_equal); |
| 5063 // Handle not identical strings | 5012 // Handle not identical strings |
| 5064 | 5013 |
| 5065 // Check that both strings are internalized strings. If they are, we're done | 5014 // Check that both strings are internalized strings. If they are, we're done |
| 5066 // because we already know they are not identical. | 5015 // because we already know they are not identical. We know they are both |
| 5016 // strings. |
| 5067 if (equality) { | 5017 if (equality) { |
| 5068 ASSERT(GetCondition() == eq); | 5018 ASSERT(GetCondition() == eq); |
| 5069 STATIC_ASSERT(kInternalizedTag != 0); | 5019 STATIC_ASSERT(kInternalizedTag != 0); |
| 5070 Label not_internalized_strings; | 5020 Label not_internalized_strings; |
| 5071 __ And(x12, lhs_type, rhs_type); | 5021 __ And(x12, lhs_type, rhs_type); |
| 5072 __ Tbz(x12, MaskToBit(kIsInternalizedMask), ¬_internalized_strings); | 5022 __ Tbz(x12, MaskToBit(kIsInternalizedMask), ¬_internalized_strings); |
| 5073 // Result is in rhs (x0), and not EQUAL, as rhs is not a smi. | 5023 // Result is in rhs (x0), and not EQUAL, as rhs is not a smi. |
| 5074 __ Ret(); | 5024 __ Ret(); |
| 5075 __ Bind(¬_internalized_strings); | 5025 __ Bind(¬_internalized_strings); |
| 5076 } | 5026 } |
| (...skipping 1814 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6891 __ Cmp(entity_name, Operand(name)); | 6841 __ Cmp(entity_name, Operand(name)); |
| 6892 __ B(eq, miss); | 6842 __ B(eq, miss); |
| 6893 | 6843 |
| 6894 Label good; | 6844 Label good; |
| 6895 __ JumpIfRoot(entity_name, Heap::kTheHoleValueRootIndex, &good); | 6845 __ JumpIfRoot(entity_name, Heap::kTheHoleValueRootIndex, &good); |
| 6896 | 6846 |
| 6897 // Check if the entry name is not a unique name. | 6847 // Check if the entry name is not a unique name. |
| 6898 __ Ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); | 6848 __ Ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); |
| 6899 __ Ldrb(entity_name, | 6849 __ Ldrb(entity_name, |
| 6900 FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); | 6850 FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); |
| 6901 __ TestAndBranchIfAnySet(entity_name, kIsInternalizedMask, &good); | 6851 __ JumpIfNotUniqueName(entity_name, miss); |
| 6902 __ CompareAndBranch(entity_name, SYMBOL_TYPE, ne, miss); | |
| 6903 | |
| 6904 __ Bind(&good); | 6852 __ Bind(&good); |
| 6905 } | 6853 } |
| 6906 | 6854 |
| 6907 CPURegList spill_list(CPURegister::kRegister, kXRegSize, 0, 6); | 6855 CPURegList spill_list(CPURegister::kRegister, kXRegSize, 0, 6); |
| 6908 spill_list.Combine(lr); | 6856 spill_list.Combine(lr); |
| 6909 spill_list.Remove(scratch0); // Scratch registers don't need to be preserved. | 6857 spill_list.Remove(scratch0); // Scratch registers don't need to be preserved. |
| 6910 | 6858 |
| 6911 __ PushCPURegList(spill_list); | 6859 __ PushCPURegList(spill_list); |
| 6912 | 6860 |
| 6913 __ Ldr(x0, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 6861 __ Ldr(x0, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6978 // Having undefined at this place means the name is not contained. | 6926 // Having undefined at this place means the name is not contained. |
| 6979 __ Cmp(entry_key, undefined); | 6927 __ Cmp(entry_key, undefined); |
| 6980 __ B(eq, ¬_in_dictionary); | 6928 __ B(eq, ¬_in_dictionary); |
| 6981 | 6929 |
| 6982 // Stop if found the property. | 6930 // Stop if found the property. |
| 6983 __ Cmp(entry_key, key); | 6931 __ Cmp(entry_key, key); |
| 6984 __ B(eq, &in_dictionary); | 6932 __ B(eq, &in_dictionary); |
| 6985 | 6933 |
| 6986 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { | 6934 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
| 6987 // Check if the entry name is not a unique name. | 6935 // Check if the entry name is not a unique name. |
| 6988 Label cont; | |
| 6989 __ Ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset)); | 6936 __ Ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset)); |
| 6990 __ Ldrb(entry_key, FieldMemOperand(entry_key, Map::kInstanceTypeOffset)); | 6937 __ Ldrb(entry_key, FieldMemOperand(entry_key, Map::kInstanceTypeOffset)); |
| 6991 STATIC_ASSERT(kIsInternalizedMask != 0); | 6938 __ JumpIfNotUniqueName(entry_key, &maybe_in_dictionary); |
| 6992 __ Tbnz(entry_key, MaskToBit(kIsInternalizedMask), &cont); | |
| 6993 __ CompareAndBranch(entry_key, SYMBOL_TYPE, ne, &maybe_in_dictionary); | |
| 6994 __ Bind(&cont); | |
| 6995 } | 6939 } |
| 6996 } | 6940 } |
| 6997 | 6941 |
| 6998 __ Bind(&maybe_in_dictionary); | 6942 __ Bind(&maybe_in_dictionary); |
| 6999 // If we are doing negative lookup then probing failure should be | 6943 // If we are doing negative lookup then probing failure should be |
| 7000 // treated as a lookup success. For positive lookup, probing failure | 6944 // treated as a lookup success. For positive lookup, probing failure |
| 7001 // should be treated as lookup failure. | 6945 // should be treated as lookup failure. |
| 7002 if (mode_ == POSITIVE_LOOKUP) { | 6946 if (mode_ == POSITIVE_LOOKUP) { |
| 7003 __ Mov(result, 0); | 6947 __ Mov(result, 0); |
| 7004 __ Ret(); | 6948 __ Ret(); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7172 Label okay_here; | 7116 Label okay_here; |
| 7173 Handle<Map> cell_map(masm->isolate()->heap()->global_property_cell_map()); | 7117 Handle<Map> cell_map(masm->isolate()->heap()->global_property_cell_map()); |
| 7174 __ CompareAndBranch(type_info_cell, Operand(undefined_sentinel), | 7118 __ CompareAndBranch(type_info_cell, Operand(undefined_sentinel), |
| 7175 eq, &okay_here); | 7119 eq, &okay_here); |
| 7176 __ Ldr(x10, FieldMemOperand(type_info_cell, Cell::kMapOffset)); | 7120 __ Ldr(x10, FieldMemOperand(type_info_cell, Cell::kMapOffset)); |
| 7177 __ Cmp(x10, Operand(cell_map)); | 7121 __ Cmp(x10, Operand(cell_map)); |
| 7178 __ Assert(eq, "Expected property cell in type_info_cell"); | 7122 __ Assert(eq, "Expected property cell in type_info_cell"); |
| 7179 __ Bind(&okay_here); | 7123 __ Bind(&okay_here); |
| 7180 } | 7124 } |
| 7181 | 7125 |
| 7182 if (FLAG_optimize_constructed_arrays) { | 7126 Register kind = x3; |
| 7183 Register kind = x3; | 7127 Label no_info, switch_ready; |
| 7184 Label no_info, switch_ready; | 7128 // Get the elements kind and case on that. |
| 7185 // Get the elements kind and case on that. | 7129 __ CompareAndBranch(type_info_cell, Operand(undefined_sentinel), |
| 7186 __ CompareAndBranch(type_info_cell, Operand(undefined_sentinel), | 7130 eq, &no_info); |
| 7187 eq, &no_info); | 7131 __ Ldr(kind, FieldMemOperand(type_info_cell, PropertyCell::kValueOffset)); |
| 7188 __ Ldr(kind, FieldMemOperand(type_info_cell, PropertyCell::kValueOffset)); | 7132 __ JumpIfNotSmi(kind, &no_info); |
| 7189 __ JumpIfNotSmi(kind, &no_info); | 7133 __ SmiUntag(kind); |
| 7190 __ SmiUntag(kind); | 7134 __ B(&switch_ready); |
| 7191 __ B(&switch_ready); | |
| 7192 | 7135 |
| 7193 __ Bind(&no_info); | 7136 __ Bind(&no_info); |
| 7194 __ Mov(kind, GetInitialFastElementsKind()); | 7137 __ Mov(kind, GetInitialFastElementsKind()); |
| 7195 __ Bind(&switch_ready); | 7138 __ Bind(&switch_ready); |
| 7196 | 7139 |
| 7197 if (argument_count_ == ANY) { | 7140 if (argument_count_ == ANY) { |
| 7198 Label zero_case, n_case; | 7141 Label zero_case, n_case; |
| 7199 __ Cbz(argc, &zero_case); | 7142 __ Cbz(argc, &zero_case); |
| 7200 __ Cmp(argc, 1); | 7143 __ Cmp(argc, 1); |
| 7201 __ B(ne, &n_case); | 7144 __ B(ne, &n_case); |
| 7202 | 7145 |
| 7203 // One argument. | 7146 // One argument. |
| 7204 CreateArrayDispatchOneArgument(masm); | 7147 CreateArrayDispatchOneArgument(masm); |
| 7205 | 7148 |
| 7206 __ Bind(&zero_case); | 7149 __ Bind(&zero_case); |
| 7207 // No arguments. | 7150 // No arguments. |
| 7208 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); | 7151 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); |
| 7209 | 7152 |
| 7210 __ Bind(&n_case); | 7153 __ Bind(&n_case); |
| 7211 // N arguments. | 7154 // N arguments. |
| 7212 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); | 7155 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); |
| 7213 | 7156 |
| 7214 } else if (argument_count_ == NONE) { | 7157 } else if (argument_count_ == NONE) { |
| 7215 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); | 7158 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); |
| 7216 } else if (argument_count_ == ONE) { | 7159 } else if (argument_count_ == ONE) { |
| 7217 CreateArrayDispatchOneArgument(masm); | 7160 CreateArrayDispatchOneArgument(masm); |
| 7218 } else if (argument_count_ == MORE_THAN_ONE) { | 7161 } else if (argument_count_ == MORE_THAN_ONE) { |
| 7219 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); | 7162 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); |
| 7220 } else { | |
| 7221 UNREACHABLE(); | |
| 7222 } | |
| 7223 } else { | 7163 } else { |
| 7224 Label generic_constructor; | 7164 UNREACHABLE(); |
| 7225 // Run the native code for the Array function called as a constructor. | |
| 7226 ArrayNativeCode(masm, &generic_constructor); | |
| 7227 | |
| 7228 // Jump to the generic construct code in case the specialized code cannot | |
| 7229 // handle the construction. | |
| 7230 __ Bind(&generic_constructor); | |
| 7231 Handle<Code> generic_construct_stub = | |
| 7232 masm->isolate()->builtins()->JSConstructStubGeneric(); | |
| 7233 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); | |
| 7234 } | 7165 } |
| 7235 } | 7166 } |
| 7236 | 7167 |
| 7237 | 7168 |
| 7238 void InternalArrayConstructorStub::GenerateCase( | 7169 void InternalArrayConstructorStub::GenerateCase( |
| 7239 MacroAssembler* masm, ElementsKind kind) { | 7170 MacroAssembler* masm, ElementsKind kind) { |
| 7240 Label zero_case, n_case; | 7171 Label zero_case, n_case; |
| 7241 Register argc = x0; | 7172 Register argc = x0; |
| 7242 | 7173 |
| 7243 __ Cbz(argc, &zero_case); | 7174 __ Cbz(argc, &zero_case); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7293 __ Ldr(x10, FieldMemOperand(constructor, | 7224 __ Ldr(x10, FieldMemOperand(constructor, |
| 7294 JSFunction::kPrototypeOrInitialMapOffset)); | 7225 JSFunction::kPrototypeOrInitialMapOffset)); |
| 7295 // Will both indicate a NULL and a Smi. | 7226 // Will both indicate a NULL and a Smi. |
| 7296 __ JumpIfSmi(x10, &unexpected_map); | 7227 __ JumpIfSmi(x10, &unexpected_map); |
| 7297 __ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok); | 7228 __ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok); |
| 7298 __ Bind(&unexpected_map); | 7229 __ Bind(&unexpected_map); |
| 7299 __ Abort("Unexpected initial map for Array function"); | 7230 __ Abort("Unexpected initial map for Array function"); |
| 7300 __ Bind(&map_ok); | 7231 __ Bind(&map_ok); |
| 7301 } | 7232 } |
| 7302 | 7233 |
| 7303 if (FLAG_optimize_constructed_arrays) { | 7234 Register kind = w3; |
| 7304 Register kind = w3; | 7235 // Figure out the right elements kind |
| 7305 // Figure out the right elements kind | 7236 __ Ldr(x10, FieldMemOperand(constructor, |
| 7306 __ Ldr(x10, FieldMemOperand(constructor, | 7237 JSFunction::kPrototypeOrInitialMapOffset)); |
| 7307 JSFunction::kPrototypeOrInitialMapOffset)); | |
| 7308 | 7238 |
| 7309 // TODO(jbramley): Add a helper function to read elements kind from an | 7239 // TODO(jbramley): Add a helper function to read elements kind from an |
| 7310 // existing map. | 7240 // existing map. |
| 7311 // Load the map's "bit field 2" into result. | 7241 // Load the map's "bit field 2" into result. |
| 7312 __ Ldr(kind, FieldMemOperand(x10, Map::kBitField2Offset)); | 7242 __ Ldr(kind, FieldMemOperand(x10, Map::kBitField2Offset)); |
| 7313 // Retrieve elements_kind from bit field 2. | 7243 // Retrieve elements_kind from bit field 2. |
| 7314 __ Ubfx(kind, kind, Map::kElementsKindShift, Map::kElementsKindBitCount); | 7244 __ Ubfx(kind, kind, Map::kElementsKindShift, Map::kElementsKindBitCount); |
| 7315 | 7245 |
| 7316 if (FLAG_debug_code) { | 7246 if (FLAG_debug_code) { |
| 7317 Label done; | 7247 Label done; |
| 7318 __ Cmp(x3, FAST_ELEMENTS); | 7248 __ Cmp(x3, FAST_ELEMENTS); |
| 7319 __ Ccmp(x3, FAST_HOLEY_ELEMENTS, ZFlag, ne); | 7249 __ Ccmp(x3, FAST_HOLEY_ELEMENTS, ZFlag, ne); |
| 7320 __ Assert(eq, | 7250 __ Assert(eq, |
| 7321 "Invalid ElementsKind for InternalArray or InternalPackedArray"); | 7251 "Invalid ElementsKind for InternalArray or InternalPackedArray"); |
| 7322 } | 7252 } |
| 7323 | 7253 |
| 7324 Label fast_elements_case; | 7254 Label fast_elements_case; |
| 7325 __ CompareAndBranch(kind, FAST_ELEMENTS, eq, &fast_elements_case); | 7255 __ CompareAndBranch(kind, FAST_ELEMENTS, eq, &fast_elements_case); |
| 7326 GenerateCase(masm, FAST_HOLEY_ELEMENTS); | 7256 GenerateCase(masm, FAST_HOLEY_ELEMENTS); |
| 7327 | 7257 |
| 7328 __ Bind(&fast_elements_case); | 7258 __ Bind(&fast_elements_case); |
| 7329 GenerateCase(masm, FAST_ELEMENTS); | 7259 GenerateCase(masm, FAST_ELEMENTS); |
| 7330 } else { | |
| 7331 Label generic_constructor; | |
| 7332 // Run the native code for the Array function called as constructor. | |
| 7333 ArrayNativeCode(masm, &generic_constructor); | |
| 7334 | |
| 7335 // Jump to the generic construct code in case the specialized code cannot | |
| 7336 // handle the construction. | |
| 7337 __ Bind(&generic_constructor); | |
| 7338 Handle<Code> generic_construct_stub = | |
| 7339 masm->isolate()->builtins()->JSConstructStubGeneric(); | |
| 7340 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); | |
| 7341 } | |
| 7342 } | 7260 } |
| 7343 | 7261 |
| 7344 | 7262 |
| 7345 #undef __ | 7263 #undef __ |
| 7346 | 7264 |
| 7347 } } // namespace v8::internal | 7265 } } // namespace v8::internal |
| 7348 | 7266 |
| 7349 #endif // V8_TARGET_ARCH_A64 | 7267 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |