| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 1509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1520 case Token::BIT_XOR: | 1520 case Token::BIT_XOR: |
| 1521 case Token::SAR: | 1521 case Token::SAR: |
| 1522 case Token::SHL: | 1522 case Token::SHL: |
| 1523 case Token::SHR: | 1523 case Token::SHR: |
| 1524 GenerateRegisterArgsPush(masm); | 1524 GenerateRegisterArgsPush(masm); |
| 1525 break; | 1525 break; |
| 1526 default: | 1526 default: |
| 1527 UNREACHABLE(); | 1527 UNREACHABLE(); |
| 1528 } | 1528 } |
| 1529 | 1529 |
| 1530 if (op_ == Token::MOD && has_fixed_right_arg_) { | 1530 if (op_ == Token::MOD && encoded_right_arg_.has_value) { |
| 1531 // It is guaranteed that the value will fit into a Smi, because if it | 1531 // It is guaranteed that the value will fit into a Smi, because if it |
| 1532 // didn't, we wouldn't be here, see BinaryOp_Patch. | 1532 // didn't, we wouldn't be here, see BinaryOp_Patch. |
| 1533 __ cmp(eax, Immediate(Smi::FromInt(fixed_right_arg_value()))); | 1533 __ cmp(eax, Immediate(Smi::FromInt(fixed_right_arg_value()))); |
| 1534 __ j(not_equal, &right_arg_changed); | 1534 __ j(not_equal, &right_arg_changed); |
| 1535 } | 1535 } |
| 1536 | 1536 |
| 1537 if (result_type_ == BinaryOpIC::UNINITIALIZED || | 1537 if (result_type_ == BinaryOpIC::UNINITIALIZED || |
| 1538 result_type_ == BinaryOpIC::SMI) { | 1538 result_type_ == BinaryOpIC::SMI) { |
| 1539 BinaryOpStub_GenerateSmiCode( | 1539 BinaryOpStub_GenerateSmiCode( |
| 1540 masm, &call_runtime, NO_HEAPNUMBER_RESULTS, op_); | 1540 masm, &call_runtime, NO_HEAPNUMBER_RESULTS, op_); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1662 } | 1662 } |
| 1663 if (right_type_ == BinaryOpIC::SMI) { | 1663 if (right_type_ == BinaryOpIC::SMI) { |
| 1664 __ JumpIfNotSmi(eax, ¬_int32); | 1664 __ JumpIfNotSmi(eax, ¬_int32); |
| 1665 } | 1665 } |
| 1666 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); | 1666 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
| 1667 FloatingPointHelper::CheckSSE2OperandIsInt32( | 1667 FloatingPointHelper::CheckSSE2OperandIsInt32( |
| 1668 masm, ¬_int32, xmm0, ebx, ecx, xmm2); | 1668 masm, ¬_int32, xmm0, ebx, ecx, xmm2); |
| 1669 FloatingPointHelper::CheckSSE2OperandIsInt32( | 1669 FloatingPointHelper::CheckSSE2OperandIsInt32( |
| 1670 masm, ¬_int32, xmm1, edi, ecx, xmm2); | 1670 masm, ¬_int32, xmm1, edi, ecx, xmm2); |
| 1671 if (op_ == Token::MOD) { | 1671 if (op_ == Token::MOD) { |
| 1672 if (has_fixed_right_arg_) { | 1672 if (encoded_right_arg_.has_value) { |
| 1673 __ cmp(edi, Immediate(fixed_right_arg_value())); | 1673 __ cmp(edi, Immediate(fixed_right_arg_value())); |
| 1674 __ j(not_equal, &right_arg_changed); | 1674 __ j(not_equal, &right_arg_changed); |
| 1675 } | 1675 } |
| 1676 GenerateRegisterArgsPush(masm); | 1676 GenerateRegisterArgsPush(masm); |
| 1677 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); | 1677 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); |
| 1678 } else { | 1678 } else { |
| 1679 switch (op_) { | 1679 switch (op_) { |
| 1680 case Token::ADD: __ addsd(xmm0, xmm1); break; | 1680 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 1681 case Token::SUB: __ subsd(xmm0, xmm1); break; | 1681 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 1682 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 1682 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| (...skipping 2988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4671 void StackCheckStub::Generate(MacroAssembler* masm) { | 4671 void StackCheckStub::Generate(MacroAssembler* masm) { |
| 4672 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); | 4672 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); |
| 4673 } | 4673 } |
| 4674 | 4674 |
| 4675 | 4675 |
| 4676 void InterruptStub::Generate(MacroAssembler* masm) { | 4676 void InterruptStub::Generate(MacroAssembler* masm) { |
| 4677 __ TailCallRuntime(Runtime::kInterrupt, 0, 1); | 4677 __ TailCallRuntime(Runtime::kInterrupt, 0, 1); |
| 4678 } | 4678 } |
| 4679 | 4679 |
| 4680 | 4680 |
| 4681 static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) { | |
| 4682 // Cache the called function in a global property cell. Cache states | |
| 4683 // are uninitialized, monomorphic (indicated by a JSFunction), and | |
| 4684 // megamorphic. | |
| 4685 // ebx : cache cell for call target | |
| 4686 // edi : the function to call | |
| 4687 Isolate* isolate = masm->isolate(); | |
| 4688 Label initialize, done; | |
| 4689 | |
| 4690 // Load the cache state into ecx. | |
| 4691 __ mov(ecx, FieldOperand(ebx, PropertyCell::kValueOffset)); | |
| 4692 | |
| 4693 // A monomorphic cache hit or an already megamorphic state: invoke the | |
| 4694 // function without changing the state. | |
| 4695 __ cmp(ecx, edi); | |
| 4696 __ j(equal, &done, Label::kNear); | |
| 4697 __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); | |
| 4698 __ j(equal, &done, Label::kNear); | |
| 4699 | |
| 4700 // A monomorphic miss (i.e, here the cache is not uninitialized) goes | |
| 4701 // megamorphic. | |
| 4702 __ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate))); | |
| 4703 __ j(equal, &initialize, Label::kNear); | |
| 4704 // MegamorphicSentinel is an immortal immovable object (undefined) so no | |
| 4705 // write-barrier is needed. | |
| 4706 __ mov(FieldOperand(ebx, Cell::kValueOffset), | |
| 4707 Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); | |
| 4708 __ jmp(&done, Label::kNear); | |
| 4709 | |
| 4710 // An uninitialized cache is patched with the function. | |
| 4711 __ bind(&initialize); | |
| 4712 __ mov(FieldOperand(ebx, Cell::kValueOffset), edi); | |
| 4713 // No need for a write barrier here - cells are rescanned. | |
| 4714 | |
| 4715 __ bind(&done); | |
| 4716 } | |
| 4717 | |
| 4718 | |
| 4719 static void GenerateRecordCallTarget(MacroAssembler* masm) { | 4681 static void GenerateRecordCallTarget(MacroAssembler* masm) { |
| 4720 // Cache the called function in a global property cell. Cache states | 4682 // Cache the called function in a global property cell. Cache states |
| 4721 // are uninitialized, monomorphic (indicated by a JSFunction), and | 4683 // are uninitialized, monomorphic (indicated by a JSFunction), and |
| 4722 // megamorphic. | 4684 // megamorphic. |
| 4723 // ebx : cache cell for call target | 4685 // ebx : cache cell for call target |
| 4724 // edi : the function to call | 4686 // edi : the function to call |
| 4725 ASSERT(FLAG_optimize_constructed_arrays); | |
| 4726 Isolate* isolate = masm->isolate(); | 4687 Isolate* isolate = masm->isolate(); |
| 4727 Label initialize, done, miss, megamorphic, not_array_function; | 4688 Label initialize, done, miss, megamorphic, not_array_function; |
| 4728 | 4689 |
| 4729 // Load the cache state into ecx. | 4690 // Load the cache state into ecx. |
| 4730 __ mov(ecx, FieldOperand(ebx, Cell::kValueOffset)); | 4691 __ mov(ecx, FieldOperand(ebx, Cell::kValueOffset)); |
| 4731 | 4692 |
| 4732 // A monomorphic cache hit or an already megamorphic state: invoke the | 4693 // A monomorphic cache hit or an already megamorphic state: invoke the |
| 4733 // function without changing the state. | 4694 // function without changing the state. |
| 4734 __ cmp(ecx, edi); | 4695 __ cmp(ecx, edi); |
| 4735 __ j(equal, &done); | 4696 __ j(equal, &done); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4817 __ bind(&receiver_ok); | 4778 __ bind(&receiver_ok); |
| 4818 } | 4779 } |
| 4819 | 4780 |
| 4820 // Check that the function really is a JavaScript function. | 4781 // Check that the function really is a JavaScript function. |
| 4821 __ JumpIfSmi(edi, &non_function); | 4782 __ JumpIfSmi(edi, &non_function); |
| 4822 // Goto slow case if we do not have a function. | 4783 // Goto slow case if we do not have a function. |
| 4823 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 4784 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
| 4824 __ j(not_equal, &slow); | 4785 __ j(not_equal, &slow); |
| 4825 | 4786 |
| 4826 if (RecordCallTarget()) { | 4787 if (RecordCallTarget()) { |
| 4827 if (FLAG_optimize_constructed_arrays) { | 4788 GenerateRecordCallTarget(masm); |
| 4828 GenerateRecordCallTarget(masm); | |
| 4829 } else { | |
| 4830 GenerateRecordCallTargetNoArray(masm); | |
| 4831 } | |
| 4832 } | 4789 } |
| 4833 | 4790 |
| 4834 // Fast-case: Just invoke the function. | 4791 // Fast-case: Just invoke the function. |
| 4835 ParameterCount actual(argc_); | 4792 ParameterCount actual(argc_); |
| 4836 | 4793 |
| 4837 if (ReceiverMightBeImplicit()) { | 4794 if (ReceiverMightBeImplicit()) { |
| 4838 Label call_as_function; | 4795 Label call_as_function; |
| 4839 __ cmp(eax, isolate->factory()->the_hole_value()); | 4796 __ cmp(eax, isolate->factory()->the_hole_value()); |
| 4840 __ j(equal, &call_as_function); | 4797 __ j(equal, &call_as_function); |
| 4841 __ InvokeFunction(edi, | 4798 __ InvokeFunction(edi, |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4894 // edi : constructor function | 4851 // edi : constructor function |
| 4895 Label slow, non_function_call; | 4852 Label slow, non_function_call; |
| 4896 | 4853 |
| 4897 // Check that function is not a smi. | 4854 // Check that function is not a smi. |
| 4898 __ JumpIfSmi(edi, &non_function_call); | 4855 __ JumpIfSmi(edi, &non_function_call); |
| 4899 // Check that function is a JSFunction. | 4856 // Check that function is a JSFunction. |
| 4900 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 4857 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
| 4901 __ j(not_equal, &slow); | 4858 __ j(not_equal, &slow); |
| 4902 | 4859 |
| 4903 if (RecordCallTarget()) { | 4860 if (RecordCallTarget()) { |
| 4904 if (FLAG_optimize_constructed_arrays) { | 4861 GenerateRecordCallTarget(masm); |
| 4905 GenerateRecordCallTarget(masm); | |
| 4906 } else { | |
| 4907 GenerateRecordCallTargetNoArray(masm); | |
| 4908 } | |
| 4909 } | 4862 } |
| 4910 | 4863 |
| 4911 // Jump to the function-specific construct stub. | 4864 // Jump to the function-specific construct stub. |
| 4912 Register jmp_reg = FLAG_optimize_constructed_arrays ? ecx : ebx; | 4865 Register jmp_reg = ecx; |
| 4913 __ mov(jmp_reg, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 4866 __ mov(jmp_reg, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 4914 __ mov(jmp_reg, FieldOperand(jmp_reg, | 4867 __ mov(jmp_reg, FieldOperand(jmp_reg, |
| 4915 SharedFunctionInfo::kConstructStubOffset)); | 4868 SharedFunctionInfo::kConstructStubOffset)); |
| 4916 __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize)); | 4869 __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize)); |
| 4917 __ jmp(jmp_reg); | 4870 __ jmp(jmp_reg); |
| 4918 | 4871 |
| 4919 // edi: called object | 4872 // edi: called object |
| 4920 // eax: number of arguments | 4873 // eax: number of arguments |
| 4921 // ecx: object map | 4874 // ecx: object map |
| 4922 Label do_call; | 4875 Label do_call; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 4948 result_size_ == 1; | 4901 result_size_ == 1; |
| 4949 } | 4902 } |
| 4950 | 4903 |
| 4951 | 4904 |
| 4952 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { | 4905 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { |
| 4953 CEntryStub::GenerateAheadOfTime(isolate); | 4906 CEntryStub::GenerateAheadOfTime(isolate); |
| 4954 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 4907 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 4955 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 4908 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
| 4956 // It is important that the store buffer overflow stubs are generated first. | 4909 // It is important that the store buffer overflow stubs are generated first. |
| 4957 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); | 4910 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 4958 if (FLAG_optimize_constructed_arrays) { | 4911 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
| 4959 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | |
| 4960 } | |
| 4961 } | 4912 } |
| 4962 | 4913 |
| 4963 | 4914 |
| 4964 void CodeStub::GenerateFPStubs(Isolate* isolate) { | 4915 void CodeStub::GenerateFPStubs(Isolate* isolate) { |
| 4965 if (CpuFeatures::IsSupported(SSE2)) { | 4916 if (CpuFeatures::IsSupported(SSE2)) { |
| 4966 CEntryStub save_doubles(1, kSaveFPRegs); | 4917 CEntryStub save_doubles(1, kSaveFPRegs); |
| 4967 // Stubs might already be in the snapshot, detect that and don't regenerate, | 4918 // Stubs might already be in the snapshot, detect that and don't regenerate, |
| 4968 // which would lead to code stub initialization state being messed up. | 4919 // which would lead to code stub initialization state being messed up. |
| 4969 Code* save_doubles_code; | 4920 Code* save_doubles_code; |
| 4970 if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) { | 4921 if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5043 if (always_allocate_scope) { | 4994 if (always_allocate_scope) { |
| 5044 __ dec(Operand::StaticVariable(scope_depth)); | 4995 __ dec(Operand::StaticVariable(scope_depth)); |
| 5045 } | 4996 } |
| 5046 | 4997 |
| 5047 // Runtime functions should not return 'the hole'. Allowing it to escape may | 4998 // Runtime functions should not return 'the hole'. Allowing it to escape may |
| 5048 // lead to crashes in the IC code later. | 4999 // lead to crashes in the IC code later. |
| 5049 if (FLAG_debug_code) { | 5000 if (FLAG_debug_code) { |
| 5050 Label okay; | 5001 Label okay; |
| 5051 __ cmp(eax, masm->isolate()->factory()->the_hole_value()); | 5002 __ cmp(eax, masm->isolate()->factory()->the_hole_value()); |
| 5052 __ j(not_equal, &okay, Label::kNear); | 5003 __ j(not_equal, &okay, Label::kNear); |
| 5053 // TODO(wingo): Currently SuspendJSGeneratorObject returns the hole. Change | |
| 5054 // to return another sentinel like a harmony symbol. | |
| 5055 __ cmp(ebx, Immediate(ExternalReference( | |
| 5056 Runtime::kSuspendJSGeneratorObject, masm->isolate()))); | |
| 5057 __ j(equal, &okay, Label::kNear); | |
| 5058 __ int3(); | 5004 __ int3(); |
| 5059 __ bind(&okay); | 5005 __ bind(&okay); |
| 5060 } | 5006 } |
| 5061 | 5007 |
| 5062 // Check for failure result. | 5008 // Check for failure result. |
| 5063 Label failure_returned; | 5009 Label failure_returned; |
| 5064 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); | 5010 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); |
| 5065 __ lea(ecx, Operand(eax, 1)); | 5011 __ lea(ecx, Operand(eax, 1)); |
| 5066 // Lower 2 bits of ecx are 0 iff eax has failure tag. | 5012 // Lower 2 bits of ecx are 0 iff eax has failure tag. |
| 5067 __ test(ecx, Immediate(kFailureTagMask)); | 5013 __ test(ecx, Immediate(kFailureTagMask)); |
| (...skipping 1832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6900 STATIC_ASSERT(kSmiTag == 0); | 6846 STATIC_ASSERT(kSmiTag == 0); |
| 6901 __ and_(tmp1, right); | 6847 __ and_(tmp1, right); |
| 6902 __ JumpIfSmi(tmp1, &miss, Label::kNear); | 6848 __ JumpIfSmi(tmp1, &miss, Label::kNear); |
| 6903 | 6849 |
| 6904 // Check that both operands are internalized strings. | 6850 // Check that both operands are internalized strings. |
| 6905 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 6851 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 6906 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 6852 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 6907 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 6853 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 6908 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 6854 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 6909 STATIC_ASSERT(kInternalizedTag != 0); | 6855 STATIC_ASSERT(kInternalizedTag != 0); |
| 6910 __ and_(tmp1, tmp2); | 6856 __ and_(tmp1, Immediate(kIsNotStringMask | kIsInternalizedMask)); |
| 6911 __ test(tmp1, Immediate(kIsInternalizedMask)); | 6857 __ cmpb(tmp1, kInternalizedTag | kStringTag); |
| 6912 __ j(zero, &miss, Label::kNear); | 6858 __ j(not_equal, &miss, Label::kNear); |
| 6859 |
| 6860 __ and_(tmp2, Immediate(kIsNotStringMask | kIsInternalizedMask)); |
| 6861 __ cmpb(tmp2, kInternalizedTag | kStringTag); |
| 6862 __ j(not_equal, &miss, Label::kNear); |
| 6913 | 6863 |
| 6914 // Internalized strings are compared by identity. | 6864 // Internalized strings are compared by identity. |
| 6915 Label done; | 6865 Label done; |
| 6916 __ cmp(left, right); | 6866 __ cmp(left, right); |
| 6917 // Make sure eax is non-zero. At this point input operands are | 6867 // Make sure eax is non-zero. At this point input operands are |
| 6918 // guaranteed to be non-zero. | 6868 // guaranteed to be non-zero. |
| 6919 ASSERT(right.is(eax)); | 6869 ASSERT(right.is(eax)); |
| 6920 __ j(not_equal, &done, Label::kNear); | 6870 __ j(not_equal, &done, Label::kNear); |
| 6921 STATIC_ASSERT(EQUAL == 0); | 6871 STATIC_ASSERT(EQUAL == 0); |
| 6922 STATIC_ASSERT(kSmiTag == 0); | 6872 STATIC_ASSERT(kSmiTag == 0); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 6947 __ JumpIfSmi(tmp1, &miss, Label::kNear); | 6897 __ JumpIfSmi(tmp1, &miss, Label::kNear); |
| 6948 | 6898 |
| 6949 // Check that both operands are unique names. This leaves the instance | 6899 // Check that both operands are unique names. This leaves the instance |
| 6950 // types loaded in tmp1 and tmp2. | 6900 // types loaded in tmp1 and tmp2. |
| 6951 STATIC_ASSERT(kInternalizedTag != 0); | 6901 STATIC_ASSERT(kInternalizedTag != 0); |
| 6952 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 6902 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 6953 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 6903 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 6954 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 6904 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 6955 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 6905 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 6956 | 6906 |
| 6957 Label succeed1; | 6907 __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear); |
| 6958 __ test(tmp1, Immediate(kIsInternalizedMask)); | 6908 __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear); |
| 6959 __ j(not_zero, &succeed1); | |
| 6960 __ cmpb(tmp1, static_cast<uint8_t>(SYMBOL_TYPE)); | |
| 6961 __ j(not_equal, &miss); | |
| 6962 __ bind(&succeed1); | |
| 6963 | |
| 6964 Label succeed2; | |
| 6965 __ test(tmp2, Immediate(kIsInternalizedMask)); | |
| 6966 __ j(not_zero, &succeed2); | |
| 6967 __ cmpb(tmp2, static_cast<uint8_t>(SYMBOL_TYPE)); | |
| 6968 __ j(not_equal, &miss); | |
| 6969 __ bind(&succeed2); | |
| 6970 | 6909 |
| 6971 // Unique names are compared by identity. | 6910 // Unique names are compared by identity. |
| 6972 Label done; | 6911 Label done; |
| 6973 __ cmp(left, right); | 6912 __ cmp(left, right); |
| 6974 // Make sure eax is non-zero. At this point input operands are | 6913 // Make sure eax is non-zero. At this point input operands are |
| 6975 // guaranteed to be non-zero. | 6914 // guaranteed to be non-zero. |
| 6976 ASSERT(right.is(eax)); | 6915 ASSERT(right.is(eax)); |
| 6977 __ j(not_equal, &done, Label::kNear); | 6916 __ j(not_equal, &done, Label::kNear); |
| 6978 STATIC_ASSERT(EQUAL == 0); | 6917 STATIC_ASSERT(EQUAL == 0); |
| 6979 STATIC_ASSERT(kSmiTag == 0); | 6918 STATIC_ASSERT(kSmiTag == 0); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7024 STATIC_ASSERT(EQUAL == 0); | 6963 STATIC_ASSERT(EQUAL == 0); |
| 7025 STATIC_ASSERT(kSmiTag == 0); | 6964 STATIC_ASSERT(kSmiTag == 0); |
| 7026 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 6965 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 7027 __ ret(0); | 6966 __ ret(0); |
| 7028 | 6967 |
| 7029 // Handle not identical strings. | 6968 // Handle not identical strings. |
| 7030 __ bind(¬_same); | 6969 __ bind(¬_same); |
| 7031 | 6970 |
| 7032 // Check that both strings are internalized. If they are, we're done | 6971 // Check that both strings are internalized. If they are, we're done |
| 7033 // because we already know they are not identical. But in the case of | 6972 // because we already know they are not identical. But in the case of |
| 7034 // non-equality compare, we still need to determine the order. | 6973 // non-equality compare, we still need to determine the order. We |
| 6974 // also know they are both strings. |
| 7035 if (equality) { | 6975 if (equality) { |
| 7036 Label do_compare; | 6976 Label do_compare; |
| 7037 STATIC_ASSERT(kInternalizedTag != 0); | 6977 STATIC_ASSERT(kInternalizedTag != 0); |
| 7038 __ and_(tmp1, tmp2); | 6978 __ and_(tmp1, tmp2); |
| 7039 __ test(tmp1, Immediate(kIsInternalizedMask)); | 6979 __ test(tmp1, Immediate(kIsInternalizedMask)); |
| 7040 __ j(zero, &do_compare, Label::kNear); | 6980 __ j(zero, &do_compare, Label::kNear); |
| 7041 // Make sure eax is non-zero. At this point input operands are | 6981 // Make sure eax is non-zero. At this point input operands are |
| 7042 // guaranteed to be non-zero. | 6982 // guaranteed to be non-zero. |
| 7043 ASSERT(right.is(eax)); | 6983 ASSERT(right.is(eax)); |
| 7044 __ ret(0); | 6984 __ ret(0); |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7183 __ cmp(entity_name, Handle<Name>(name)); | 7123 __ cmp(entity_name, Handle<Name>(name)); |
| 7184 __ j(equal, miss); | 7124 __ j(equal, miss); |
| 7185 | 7125 |
| 7186 Label good; | 7126 Label good; |
| 7187 // Check for the hole and skip. | 7127 // Check for the hole and skip. |
| 7188 __ cmp(entity_name, masm->isolate()->factory()->the_hole_value()); | 7128 __ cmp(entity_name, masm->isolate()->factory()->the_hole_value()); |
| 7189 __ j(equal, &good, Label::kNear); | 7129 __ j(equal, &good, Label::kNear); |
| 7190 | 7130 |
| 7191 // Check if the entry name is not a unique name. | 7131 // Check if the entry name is not a unique name. |
| 7192 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); | 7132 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); |
| 7193 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), | 7133 __ JumpIfNotUniqueName(FieldOperand(entity_name, Map::kInstanceTypeOffset), |
| 7194 kIsInternalizedMask); | 7134 miss); |
| 7195 __ j(not_zero, &good); | |
| 7196 __ cmpb(FieldOperand(entity_name, Map::kInstanceTypeOffset), | |
| 7197 static_cast<uint8_t>(SYMBOL_TYPE)); | |
| 7198 __ j(not_equal, miss); | |
| 7199 __ bind(&good); | 7135 __ bind(&good); |
| 7200 } | 7136 } |
| 7201 | 7137 |
| 7202 NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP); | 7138 NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP); |
| 7203 __ push(Immediate(Handle<Object>(name))); | 7139 __ push(Immediate(Handle<Object>(name))); |
| 7204 __ push(Immediate(name->Hash())); | 7140 __ push(Immediate(name->Hash())); |
| 7205 __ CallStub(&stub); | 7141 __ CallStub(&stub); |
| 7206 __ test(r0, r0); | 7142 __ test(r0, r0); |
| 7207 __ j(not_zero, miss); | 7143 __ j(not_zero, miss); |
| 7208 __ jmp(done); | 7144 __ jmp(done); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7321 // Stop if found the property. | 7257 // Stop if found the property. |
| 7322 __ cmp(scratch, Operand(esp, 3 * kPointerSize)); | 7258 __ cmp(scratch, Operand(esp, 3 * kPointerSize)); |
| 7323 __ j(equal, &in_dictionary); | 7259 __ j(equal, &in_dictionary); |
| 7324 | 7260 |
| 7325 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { | 7261 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
| 7326 // If we hit a key that is not a unique name during negative | 7262 // If we hit a key that is not a unique name during negative |
| 7327 // lookup we have to bailout as this key might be equal to the | 7263 // lookup we have to bailout as this key might be equal to the |
| 7328 // key we are looking for. | 7264 // key we are looking for. |
| 7329 | 7265 |
| 7330 // Check if the entry name is not a unique name. | 7266 // Check if the entry name is not a unique name. |
| 7331 Label cont; | |
| 7332 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); | 7267 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
| 7333 __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset), | 7268 __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset), |
| 7334 kIsInternalizedMask); | 7269 &maybe_in_dictionary); |
| 7335 __ j(not_zero, &cont); | |
| 7336 __ cmpb(FieldOperand(scratch, Map::kInstanceTypeOffset), | |
| 7337 static_cast<uint8_t>(SYMBOL_TYPE)); | |
| 7338 __ j(not_equal, &maybe_in_dictionary); | |
| 7339 __ bind(&cont); | |
| 7340 } | 7270 } |
| 7341 } | 7271 } |
| 7342 | 7272 |
| 7343 __ bind(&maybe_in_dictionary); | 7273 __ bind(&maybe_in_dictionary); |
| 7344 // If we are doing negative lookup then probing failure should be | 7274 // If we are doing negative lookup then probing failure should be |
| 7345 // treated as a lookup success. For positive lookup probing failure | 7275 // treated as a lookup success. For positive lookup probing failure |
| 7346 // should be treated as lookup failure. | 7276 // should be treated as lookup failure. |
| 7347 if (mode_ == POSITIVE_LOOKUP) { | 7277 if (mode_ == POSITIVE_LOOKUP) { |
| 7348 __ mov(result_, Immediate(0)); | 7278 __ mov(result_, Immediate(0)); |
| 7349 __ Drop(1); | 7279 __ Drop(1); |
| (...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7938 // We should either have undefined in ebx or a valid cell | 7868 // We should either have undefined in ebx or a valid cell |
| 7939 Label okay_here; | 7869 Label okay_here; |
| 7940 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); | 7870 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); |
| 7941 __ cmp(ebx, Immediate(undefined_sentinel)); | 7871 __ cmp(ebx, Immediate(undefined_sentinel)); |
| 7942 __ j(equal, &okay_here); | 7872 __ j(equal, &okay_here); |
| 7943 __ cmp(FieldOperand(ebx, 0), Immediate(cell_map)); | 7873 __ cmp(FieldOperand(ebx, 0), Immediate(cell_map)); |
| 7944 __ Assert(equal, "Expected property cell in register ebx"); | 7874 __ Assert(equal, "Expected property cell in register ebx"); |
| 7945 __ bind(&okay_here); | 7875 __ bind(&okay_here); |
| 7946 } | 7876 } |
| 7947 | 7877 |
| 7948 if (FLAG_optimize_constructed_arrays) { | 7878 Label no_info, switch_ready; |
| 7949 Label no_info, switch_ready; | 7879 // Get the elements kind and case on that. |
| 7950 // Get the elements kind and case on that. | 7880 __ cmp(ebx, Immediate(undefined_sentinel)); |
| 7951 __ cmp(ebx, Immediate(undefined_sentinel)); | 7881 __ j(equal, &no_info); |
| 7952 __ j(equal, &no_info); | 7882 __ mov(edx, FieldOperand(ebx, Cell::kValueOffset)); |
| 7953 __ mov(edx, FieldOperand(ebx, Cell::kValueOffset)); | 7883 __ JumpIfNotSmi(edx, &no_info); |
| 7954 __ JumpIfNotSmi(edx, &no_info); | 7884 __ SmiUntag(edx); |
| 7955 __ SmiUntag(edx); | 7885 __ jmp(&switch_ready); |
| 7956 __ jmp(&switch_ready); | 7886 __ bind(&no_info); |
| 7957 __ bind(&no_info); | 7887 __ mov(edx, Immediate(GetInitialFastElementsKind())); |
| 7958 __ mov(edx, Immediate(GetInitialFastElementsKind())); | 7888 __ bind(&switch_ready); |
| 7959 __ bind(&switch_ready); | |
| 7960 | 7889 |
| 7961 if (argument_count_ == ANY) { | 7890 if (argument_count_ == ANY) { |
| 7962 Label not_zero_case, not_one_case; | 7891 Label not_zero_case, not_one_case; |
| 7963 __ test(eax, eax); | 7892 __ test(eax, eax); |
| 7964 __ j(not_zero, ¬_zero_case); | 7893 __ j(not_zero, ¬_zero_case); |
| 7965 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); | 7894 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); |
| 7966 | 7895 |
| 7967 __ bind(¬_zero_case); | 7896 __ bind(¬_zero_case); |
| 7968 __ cmp(eax, 1); | 7897 __ cmp(eax, 1); |
| 7969 __ j(greater, ¬_one_case); | 7898 __ j(greater, ¬_one_case); |
| 7970 CreateArrayDispatchOneArgument(masm); | 7899 CreateArrayDispatchOneArgument(masm); |
| 7971 | 7900 |
| 7972 __ bind(¬_one_case); | 7901 __ bind(¬_one_case); |
| 7973 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); | 7902 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); |
| 7974 } else if (argument_count_ == NONE) { | 7903 } else if (argument_count_ == NONE) { |
| 7975 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); | 7904 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); |
| 7976 } else if (argument_count_ == ONE) { | 7905 } else if (argument_count_ == ONE) { |
| 7977 CreateArrayDispatchOneArgument(masm); | 7906 CreateArrayDispatchOneArgument(masm); |
| 7978 } else if (argument_count_ == MORE_THAN_ONE) { | 7907 } else if (argument_count_ == MORE_THAN_ONE) { |
| 7979 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); | 7908 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); |
| 7980 } else { | |
| 7981 UNREACHABLE(); | |
| 7982 } | |
| 7983 } else { | 7909 } else { |
| 7984 Label generic_constructor; | 7910 UNREACHABLE(); |
| 7985 // Run the native code for the Array function called as constructor. | |
| 7986 ArrayNativeCode(masm, true, &generic_constructor); | |
| 7987 | |
| 7988 // Jump to the generic construct code in case the specialized code cannot | |
| 7989 // handle the construction. | |
| 7990 __ bind(&generic_constructor); | |
| 7991 Handle<Code> generic_construct_stub = | |
| 7992 masm->isolate()->builtins()->JSConstructStubGeneric(); | |
| 7993 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | |
| 7994 } | 7911 } |
| 7995 } | 7912 } |
| 7996 | 7913 |
| 7997 | 7914 |
| 7998 void InternalArrayConstructorStub::GenerateCase( | 7915 void InternalArrayConstructorStub::GenerateCase( |
| 7999 MacroAssembler* masm, ElementsKind kind) { | 7916 MacroAssembler* masm, ElementsKind kind) { |
| 8000 Label not_zero_case, not_one_case; | 7917 Label not_zero_case, not_one_case; |
| 8001 Label normal_sequence; | 7918 Label normal_sequence; |
| 8002 | 7919 |
| 8003 __ test(eax, eax); | 7920 __ test(eax, eax); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8046 | 7963 |
| 8047 // Initial map for the builtin Array function should be a map. | 7964 // Initial map for the builtin Array function should be a map. |
| 8048 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); | 7965 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
| 8049 // Will both indicate a NULL and a Smi. | 7966 // Will both indicate a NULL and a Smi. |
| 8050 __ test(ecx, Immediate(kSmiTagMask)); | 7967 __ test(ecx, Immediate(kSmiTagMask)); |
| 8051 __ Assert(not_zero, "Unexpected initial map for Array function"); | 7968 __ Assert(not_zero, "Unexpected initial map for Array function"); |
| 8052 __ CmpObjectType(ecx, MAP_TYPE, ecx); | 7969 __ CmpObjectType(ecx, MAP_TYPE, ecx); |
| 8053 __ Assert(equal, "Unexpected initial map for Array function"); | 7970 __ Assert(equal, "Unexpected initial map for Array function"); |
| 8054 } | 7971 } |
| 8055 | 7972 |
| 8056 if (FLAG_optimize_constructed_arrays) { | 7973 // Figure out the right elements kind |
| 8057 // Figure out the right elements kind | 7974 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
| 8058 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); | |
| 8059 | 7975 |
| 8060 // Load the map's "bit field 2" into |result|. We only need the first byte, | 7976 // Load the map's "bit field 2" into |result|. We only need the first byte, |
| 8061 // but the following masking takes care of that anyway. | 7977 // but the following masking takes care of that anyway. |
| 8062 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); | 7978 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); |
| 8063 // Retrieve elements_kind from bit field 2. | 7979 // Retrieve elements_kind from bit field 2. |
| 8064 __ and_(ecx, Map::kElementsKindMask); | 7980 __ and_(ecx, Map::kElementsKindMask); |
| 8065 __ shr(ecx, Map::kElementsKindShift); | 7981 __ shr(ecx, Map::kElementsKindShift); |
| 8066 | 7982 |
| 8067 if (FLAG_debug_code) { | 7983 if (FLAG_debug_code) { |
| 8068 Label done; | 7984 Label done; |
| 8069 __ cmp(ecx, Immediate(FAST_ELEMENTS)); | 7985 __ cmp(ecx, Immediate(FAST_ELEMENTS)); |
| 8070 __ j(equal, &done); | 7986 __ j(equal, &done); |
| 8071 __ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS)); | 7987 __ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS)); |
| 8072 __ Assert(equal, | 7988 __ Assert(equal, |
| 8073 "Invalid ElementsKind for InternalArray or InternalPackedArray"); | 7989 "Invalid ElementsKind for InternalArray or InternalPackedArray"); |
| 8074 __ bind(&done); | 7990 __ bind(&done); |
| 8075 } | 7991 } |
| 8076 | 7992 |
| 8077 Label fast_elements_case; | 7993 Label fast_elements_case; |
| 8078 __ cmp(ecx, Immediate(FAST_ELEMENTS)); | 7994 __ cmp(ecx, Immediate(FAST_ELEMENTS)); |
| 8079 __ j(equal, &fast_elements_case); | 7995 __ j(equal, &fast_elements_case); |
| 8080 GenerateCase(masm, FAST_HOLEY_ELEMENTS); | 7996 GenerateCase(masm, FAST_HOLEY_ELEMENTS); |
| 8081 | 7997 |
| 8082 __ bind(&fast_elements_case); | 7998 __ bind(&fast_elements_case); |
| 8083 GenerateCase(masm, FAST_ELEMENTS); | 7999 GenerateCase(masm, FAST_ELEMENTS); |
| 8084 } else { | |
| 8085 Label generic_constructor; | |
| 8086 // Run the native code for the Array function called as constructor. | |
| 8087 ArrayNativeCode(masm, true, &generic_constructor); | |
| 8088 | |
| 8089 // Jump to the generic construct code in case the specialized code cannot | |
| 8090 // handle the construction. | |
| 8091 __ bind(&generic_constructor); | |
| 8092 Handle<Code> generic_construct_stub = | |
| 8093 masm->isolate()->builtins()->JSConstructStubGeneric(); | |
| 8094 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | |
| 8095 } | |
| 8096 } | 8000 } |
| 8097 | 8001 |
| 8098 | 8002 |
| 8099 #undef __ | 8003 #undef __ |
| 8100 | 8004 |
| 8101 } } // namespace v8::internal | 8005 } } // namespace v8::internal |
| 8102 | 8006 |
| 8103 #endif // V8_TARGET_ARCH_IA32 | 8007 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |