OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
6 | 6 |
7 #include "src/codegen.h" | 7 #include "src/codegen.h" |
8 #include "src/ic/ic.h" | 8 #include "src/ic/ic.h" |
9 #include "src/ic/ic-compiler.h" | 9 #include "src/ic/ic-compiler.h" |
10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
11 | 11 |
12 namespace v8 { | 12 namespace v8 { |
13 namespace internal { | 13 namespace internal { |
14 | 14 |
15 | 15 |
16 #define __ ACCESS_MASM(masm) | 16 #define __ ACCESS_MASM(masm) |
17 | 17 |
18 // Helper function used from LoadIC GenerateNormal. | |
19 // | |
20 // elements: Property dictionary. It is not clobbered if a jump to the miss | |
21 // label is done. | |
22 // name: Property name. It is not clobbered if a jump to the miss label is | |
23 // done | |
24 // result: Register for the result. It is only updated if a jump to the miss | |
25 // label is not done. | |
26 // The scratch registers need to be different from elements, name and result. | |
27 // The generated code assumes that the receiver has slow properties, | |
28 // is not a global object and does not have interceptors. | |
29 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss, | |
30 Register elements, Register name, | |
31 Register result, Register scratch1, | |
32 Register scratch2) { | |
33 DCHECK(!AreAliased(elements, name, scratch1, scratch2)); | |
34 DCHECK(!AreAliased(result, scratch1, scratch2)); | |
35 | |
36 Label done; | |
37 | |
38 // Probe the dictionary. | |
39 NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements, | |
40 name, scratch1, scratch2); | |
41 | |
42 // If probing finds an entry check that the value is a normal property. | |
43 __ Bind(&done); | |
44 | |
45 static const int kElementsStartOffset = | |
46 NameDictionary::kHeaderSize + | |
47 NameDictionary::kElementsStartIndex * kPointerSize; | |
48 static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | |
49 __ Ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset)); | |
50 __ Tst(scratch1, Smi::FromInt(PropertyDetails::TypeField::kMask)); | |
51 __ B(ne, miss); | |
52 | |
53 // Get the value at the masked, scaled index and return. | |
54 __ Ldr(result, | |
55 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize)); | |
56 } | |
57 | |
58 | |
59 // Helper function used from StoreIC::GenerateNormal. | |
60 // | |
61 // elements: Property dictionary. It is not clobbered if a jump to the miss | |
62 // label is done. | |
63 // name: Property name. It is not clobbered if a jump to the miss label is | |
64 // done | |
65 // value: The value to store (never clobbered). | |
66 // | |
67 // The generated code assumes that the receiver has slow properties, | |
68 // is not a global object and does not have interceptors. | |
69 static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss, | |
70 Register elements, Register name, | |
71 Register value, Register scratch1, | |
72 Register scratch2) { | |
73 DCHECK(!AreAliased(elements, name, value, scratch1, scratch2)); | |
74 | |
75 Label done; | |
76 | |
77 // Probe the dictionary. | |
78 NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements, | |
79 name, scratch1, scratch2); | |
80 | |
81 // If probing finds an entry in the dictionary check that the value | |
82 // is a normal property that is not read only. | |
83 __ Bind(&done); | |
84 | |
85 static const int kElementsStartOffset = | |
86 NameDictionary::kHeaderSize + | |
87 NameDictionary::kElementsStartIndex * kPointerSize; | |
88 static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | |
89 static const int kTypeAndReadOnlyMask = | |
90 PropertyDetails::TypeField::kMask | | |
91 PropertyDetails::AttributesField::encode(READ_ONLY); | |
92 __ Ldrsw(scratch1, UntagSmiFieldMemOperand(scratch2, kDetailsOffset)); | |
93 __ Tst(scratch1, kTypeAndReadOnlyMask); | |
94 __ B(ne, miss); | |
95 | |
96 // Store the value at the masked, scaled index and return. | |
97 static const int kValueOffset = kElementsStartOffset + kPointerSize; | |
98 __ Add(scratch2, scratch2, kValueOffset - kHeapObjectTag); | |
99 __ Str(value, MemOperand(scratch2)); | |
100 | |
101 // Update the write barrier. Make sure not to clobber the value. | |
102 __ Mov(scratch1, value); | |
103 __ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved, | |
104 kDontSaveFPRegs); | |
105 } | |
106 | |
107 void LoadIC::GenerateNormal(MacroAssembler* masm) { | |
108 Register dictionary = x0; | |
109 DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister())); | |
110 DCHECK(!dictionary.is(LoadDescriptor::NameRegister())); | |
111 Label slow; | |
112 | |
113 __ Ldr(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(), | |
114 JSObject::kPropertiesOffset)); | |
115 GenerateDictionaryLoad(masm, &slow, dictionary, | |
116 LoadDescriptor::NameRegister(), x0, x3, x4); | |
117 __ Ret(); | |
118 | |
119 // Dictionary load failed, go slow (but don't miss). | |
120 __ Bind(&slow); | |
121 GenerateRuntimeGetProperty(masm); | |
122 } | |
123 | |
124 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | |
125 // The return address is in lr. | |
126 __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); | |
127 | |
128 // Do tail-call to runtime routine. | |
129 __ TailCallRuntime(Runtime::kGetProperty); | |
130 } | |
131 | |
132 static void StoreIC_PushArgs(MacroAssembler* masm) { | 18 static void StoreIC_PushArgs(MacroAssembler* masm) { |
133 __ Push(StoreWithVectorDescriptor::ValueRegister(), | 19 __ Push(StoreWithVectorDescriptor::ValueRegister(), |
134 StoreWithVectorDescriptor::SlotRegister(), | 20 StoreWithVectorDescriptor::SlotRegister(), |
135 StoreWithVectorDescriptor::VectorRegister(), | 21 StoreWithVectorDescriptor::VectorRegister(), |
136 StoreWithVectorDescriptor::ReceiverRegister(), | 22 StoreWithVectorDescriptor::ReceiverRegister(), |
137 StoreWithVectorDescriptor::NameRegister()); | 23 StoreWithVectorDescriptor::NameRegister()); |
138 } | 24 } |
139 | 25 |
140 | 26 |
141 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { | 27 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { |
142 ASM_LOCATION("KeyedStoreIC::GenerateMiss"); | 28 ASM_LOCATION("KeyedStoreIC::GenerateMiss"); |
143 StoreIC_PushArgs(masm); | 29 StoreIC_PushArgs(masm); |
144 __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); | 30 __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); |
145 } | 31 } |
146 | 32 |
147 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { | 33 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { |
148 ASM_LOCATION("KeyedStoreIC::GenerateSlow"); | 34 ASM_LOCATION("KeyedStoreIC::GenerateSlow"); |
149 StoreIC_PushArgs(masm); | 35 StoreIC_PushArgs(masm); |
150 | 36 |
151 // The slow case calls into the runtime to complete the store without causing | 37 // The slow case calls into the runtime to complete the store without causing |
152 // an IC miss that would otherwise cause a transition to the generic stub. | 38 // an IC miss that would otherwise cause a transition to the generic stub. |
153 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); | 39 __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow); |
154 } | 40 } |
155 | 41 |
156 void StoreIC::GenerateMiss(MacroAssembler* masm) { | |
157 StoreIC_PushArgs(masm); | |
158 | |
159 // Tail call to the entry. | |
160 __ TailCallRuntime(Runtime::kStoreIC_Miss); | |
161 } | |
162 | |
163 | |
164 void StoreIC::GenerateNormal(MacroAssembler* masm) { | |
165 Label miss; | |
166 Register value = StoreDescriptor::ValueRegister(); | |
167 Register receiver = StoreDescriptor::ReceiverRegister(); | |
168 Register name = StoreDescriptor::NameRegister(); | |
169 Register dictionary = x5; | |
170 DCHECK(!AreAliased(value, receiver, name, | |
171 StoreWithVectorDescriptor::SlotRegister(), | |
172 StoreWithVectorDescriptor::VectorRegister(), x5, x6, x7)); | |
173 | |
174 __ Ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | |
175 | |
176 GenerateDictionaryStore(masm, &miss, dictionary, name, value, x6, x7); | |
177 Counters* counters = masm->isolate()->counters(); | |
178 __ IncrementCounter(counters->ic_store_normal_hit(), 1, x6, x7); | |
179 __ Ret(); | |
180 | |
181 // Cache miss: Jump to runtime. | |
182 __ Bind(&miss); | |
183 __ IncrementCounter(counters->ic_store_normal_miss(), 1, x6, x7); | |
184 GenerateMiss(masm); | |
185 } | |
186 | |
187 | |
188 Condition CompareIC::ComputeCondition(Token::Value op) { | 42 Condition CompareIC::ComputeCondition(Token::Value op) { |
189 switch (op) { | 43 switch (op) { |
190 case Token::EQ_STRICT: | 44 case Token::EQ_STRICT: |
191 case Token::EQ: | 45 case Token::EQ: |
192 return eq; | 46 return eq; |
193 case Token::LT: | 47 case Token::LT: |
194 return lt; | 48 return lt; |
195 case Token::GT: | 49 case Token::GT: |
196 return gt; | 50 return gt; |
197 case Token::LTE: | 51 case Token::LTE: |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 } else { | 123 } else { |
270 DCHECK(to_patch->Mask(TestBranchMask) == TBNZ); | 124 DCHECK(to_patch->Mask(TestBranchMask) == TBNZ); |
271 // This is JumpIfSmi(smi_reg, branch_imm). | 125 // This is JumpIfSmi(smi_reg, branch_imm). |
272 patcher.tbz(smi_reg, 0, branch_imm); | 126 patcher.tbz(smi_reg, 0, branch_imm); |
273 } | 127 } |
274 } | 128 } |
275 } // namespace internal | 129 } // namespace internal |
276 } // namespace v8 | 130 } // namespace v8 |
277 | 131 |
278 #endif // V8_TARGET_ARCH_ARM64 | 132 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |