OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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_PPC | 5 #if V8_TARGET_ARCH_S390 |
6 | 6 |
| 7 #include "src/code-stubs.h" |
7 #include "src/base/bits.h" | 8 #include "src/base/bits.h" |
8 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
9 #include "src/code-stubs.h" | |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
11 #include "src/ic/handler-compiler.h" | 11 #include "src/ic/handler-compiler.h" |
12 #include "src/ic/ic.h" | 12 #include "src/ic/ic.h" |
13 #include "src/ic/stub-cache.h" | 13 #include "src/ic/stub-cache.h" |
14 #include "src/isolate.h" | 14 #include "src/isolate.h" |
15 #include "src/ppc/code-stubs-ppc.h" | |
16 #include "src/regexp/jsregexp.h" | 15 #include "src/regexp/jsregexp.h" |
17 #include "src/regexp/regexp-macro-assembler.h" | 16 #include "src/regexp/regexp-macro-assembler.h" |
18 #include "src/runtime/runtime.h" | 17 #include "src/runtime/runtime.h" |
| 18 #include "src/s390/code-stubs-s390.h" |
19 | 19 |
20 namespace v8 { | 20 namespace v8 { |
21 namespace internal { | 21 namespace internal { |
22 | 22 |
23 | |
24 static void InitializeArrayConstructorDescriptor( | 23 static void InitializeArrayConstructorDescriptor( |
25 Isolate* isolate, CodeStubDescriptor* descriptor, | 24 Isolate* isolate, CodeStubDescriptor* descriptor, |
26 int constant_stack_parameter_count) { | 25 int constant_stack_parameter_count) { |
27 Address deopt_handler = | 26 Address deopt_handler = |
28 Runtime::FunctionForId(Runtime::kArrayConstructor)->entry; | 27 Runtime::FunctionForId(Runtime::kArrayConstructor)->entry; |
29 | 28 |
30 if (constant_stack_parameter_count == 0) { | 29 if (constant_stack_parameter_count == 0) { |
31 descriptor->Initialize(deopt_handler, constant_stack_parameter_count, | 30 descriptor->Initialize(deopt_handler, constant_stack_parameter_count, |
32 JS_FUNCTION_STUB_MODE); | 31 JS_FUNCTION_STUB_MODE); |
33 } else { | 32 } else { |
34 descriptor->Initialize(r3, deopt_handler, constant_stack_parameter_count, | 33 descriptor->Initialize(r2, deopt_handler, constant_stack_parameter_count, |
35 JS_FUNCTION_STUB_MODE); | 34 JS_FUNCTION_STUB_MODE); |
36 } | 35 } |
37 } | 36 } |
38 | 37 |
39 | |
40 static void InitializeInternalArrayConstructorDescriptor( | 38 static void InitializeInternalArrayConstructorDescriptor( |
41 Isolate* isolate, CodeStubDescriptor* descriptor, | 39 Isolate* isolate, CodeStubDescriptor* descriptor, |
42 int constant_stack_parameter_count) { | 40 int constant_stack_parameter_count) { |
43 Address deopt_handler = | 41 Address deopt_handler = |
44 Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry; | 42 Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry; |
45 | 43 |
46 if (constant_stack_parameter_count == 0) { | 44 if (constant_stack_parameter_count == 0) { |
47 descriptor->Initialize(deopt_handler, constant_stack_parameter_count, | 45 descriptor->Initialize(deopt_handler, constant_stack_parameter_count, |
48 JS_FUNCTION_STUB_MODE); | 46 JS_FUNCTION_STUB_MODE); |
49 } else { | 47 } else { |
50 descriptor->Initialize(r3, deopt_handler, constant_stack_parameter_count, | 48 descriptor->Initialize(r2, deopt_handler, constant_stack_parameter_count, |
51 JS_FUNCTION_STUB_MODE); | 49 JS_FUNCTION_STUB_MODE); |
52 } | 50 } |
53 } | 51 } |
54 | 52 |
55 | |
56 void ArrayNoArgumentConstructorStub::InitializeDescriptor( | 53 void ArrayNoArgumentConstructorStub::InitializeDescriptor( |
57 CodeStubDescriptor* descriptor) { | 54 CodeStubDescriptor* descriptor) { |
58 InitializeArrayConstructorDescriptor(isolate(), descriptor, 0); | 55 InitializeArrayConstructorDescriptor(isolate(), descriptor, 0); |
59 } | 56 } |
60 | 57 |
61 | |
62 void ArraySingleArgumentConstructorStub::InitializeDescriptor( | 58 void ArraySingleArgumentConstructorStub::InitializeDescriptor( |
63 CodeStubDescriptor* descriptor) { | 59 CodeStubDescriptor* descriptor) { |
64 InitializeArrayConstructorDescriptor(isolate(), descriptor, 1); | 60 InitializeArrayConstructorDescriptor(isolate(), descriptor, 1); |
65 } | 61 } |
66 | 62 |
67 | |
68 void ArrayNArgumentsConstructorStub::InitializeDescriptor( | 63 void ArrayNArgumentsConstructorStub::InitializeDescriptor( |
69 CodeStubDescriptor* descriptor) { | 64 CodeStubDescriptor* descriptor) { |
70 InitializeArrayConstructorDescriptor(isolate(), descriptor, -1); | 65 InitializeArrayConstructorDescriptor(isolate(), descriptor, -1); |
71 } | 66 } |
72 | 67 |
73 | |
74 void InternalArrayNoArgumentConstructorStub::InitializeDescriptor( | 68 void InternalArrayNoArgumentConstructorStub::InitializeDescriptor( |
75 CodeStubDescriptor* descriptor) { | 69 CodeStubDescriptor* descriptor) { |
76 InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 0); | 70 InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 0); |
77 } | 71 } |
78 | 72 |
79 | |
80 void InternalArraySingleArgumentConstructorStub::InitializeDescriptor( | 73 void InternalArraySingleArgumentConstructorStub::InitializeDescriptor( |
81 CodeStubDescriptor* descriptor) { | 74 CodeStubDescriptor* descriptor) { |
82 InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 1); | 75 InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 1); |
83 } | 76 } |
84 | 77 |
85 | |
86 void InternalArrayNArgumentsConstructorStub::InitializeDescriptor( | 78 void InternalArrayNArgumentsConstructorStub::InitializeDescriptor( |
87 CodeStubDescriptor* descriptor) { | 79 CodeStubDescriptor* descriptor) { |
88 InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, -1); | 80 InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, -1); |
89 } | 81 } |
90 | 82 |
91 | |
92 #define __ ACCESS_MASM(masm) | 83 #define __ ACCESS_MASM(masm) |
93 | 84 |
94 static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, | 85 static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, |
95 Condition cond); | 86 Condition cond); |
96 static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs, | 87 static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs, |
97 Register rhs, Label* lhs_not_nan, | 88 Register rhs, Label* lhs_not_nan, |
98 Label* slow, bool strict); | 89 Label* slow, bool strict); |
99 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, Register lhs, | 90 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, Register lhs, |
100 Register rhs); | 91 Register rhs); |
101 | 92 |
102 | |
103 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm, | 93 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm, |
104 ExternalReference miss) { | 94 ExternalReference miss) { |
105 // Update the static counter each time a new code stub is generated. | 95 // Update the static counter each time a new code stub is generated. |
106 isolate()->counters()->code_stubs()->Increment(); | 96 isolate()->counters()->code_stubs()->Increment(); |
107 | 97 |
108 CallInterfaceDescriptor descriptor = GetCallInterfaceDescriptor(); | 98 CallInterfaceDescriptor descriptor = GetCallInterfaceDescriptor(); |
109 int param_count = descriptor.GetRegisterParameterCount(); | 99 int param_count = descriptor.GetRegisterParameterCount(); |
110 { | 100 { |
111 // Call the runtime system in a fresh internal frame. | 101 // Call the runtime system in a fresh internal frame. |
112 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 102 FrameScope scope(masm, StackFrame::INTERNAL); |
113 DCHECK(param_count == 0 || | 103 DCHECK(param_count == 0 || |
114 r3.is(descriptor.GetRegisterParameter(param_count - 1))); | 104 r2.is(descriptor.GetRegisterParameter(param_count - 1))); |
115 // Push arguments | 105 // Push arguments |
116 for (int i = 0; i < param_count; ++i) { | 106 for (int i = 0; i < param_count; ++i) { |
117 __ push(descriptor.GetRegisterParameter(i)); | 107 __ push(descriptor.GetRegisterParameter(i)); |
118 } | 108 } |
119 __ CallExternalReference(miss, param_count); | 109 __ CallExternalReference(miss, param_count); |
120 } | 110 } |
121 | 111 |
122 __ Ret(); | 112 __ Ret(); |
123 } | 113 } |
124 | 114 |
125 | |
126 void DoubleToIStub::Generate(MacroAssembler* masm) { | 115 void DoubleToIStub::Generate(MacroAssembler* masm) { |
127 Label out_of_range, only_low, negate, done, fastpath_done; | 116 Label out_of_range, only_low, negate, done, fastpath_done; |
128 Register input_reg = source(); | 117 Register input_reg = source(); |
129 Register result_reg = destination(); | 118 Register result_reg = destination(); |
130 DCHECK(is_truncating()); | 119 DCHECK(is_truncating()); |
131 | 120 |
132 int double_offset = offset(); | 121 int double_offset = offset(); |
133 | 122 |
134 // Immediate values for this stub fit in instructions, so it's safe to use ip. | 123 // Immediate values for this stub fit in instructions, so it's safe to use ip. |
135 Register scratch = GetRegisterThatIsNotOneOf(input_reg, result_reg); | 124 Register scratch = GetRegisterThatIsNotOneOf(input_reg, result_reg); |
136 Register scratch_low = | 125 Register scratch_low = |
137 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch); | 126 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch); |
138 Register scratch_high = | 127 Register scratch_high = |
139 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch_low); | 128 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch_low); |
140 DoubleRegister double_scratch = kScratchDoubleReg; | 129 DoubleRegister double_scratch = kScratchDoubleReg; |
141 | 130 |
142 __ push(scratch); | 131 __ push(scratch); |
143 // Account for saved regs if input is sp. | 132 // Account for saved regs if input is sp. |
144 if (input_reg.is(sp)) double_offset += kPointerSize; | 133 if (input_reg.is(sp)) double_offset += kPointerSize; |
145 | 134 |
146 if (!skip_fastpath()) { | 135 if (!skip_fastpath()) { |
147 // Load double input. | 136 // Load double input. |
148 __ lfd(double_scratch, MemOperand(input_reg, double_offset)); | 137 __ LoadDouble(double_scratch, MemOperand(input_reg, double_offset)); |
149 | 138 |
150 // Do fast-path convert from double to int. | 139 // Do fast-path convert from double to int. |
151 __ ConvertDoubleToInt64(double_scratch, | 140 __ ConvertDoubleToInt64(double_scratch, |
152 #if !V8_TARGET_ARCH_PPC64 | 141 #if !V8_TARGET_ARCH_S390X |
153 scratch, | 142 scratch, |
154 #endif | 143 #endif |
155 result_reg, d0); | 144 result_reg, d0); |
156 | 145 |
157 // Test for overflow | 146 // Test for overflow |
158 #if V8_TARGET_ARCH_PPC64 | 147 #if V8_TARGET_ARCH_S390X |
159 __ TestIfInt32(result_reg, r0); | 148 __ TestIfInt32(result_reg, r0); |
160 #else | 149 #else |
161 __ TestIfInt32(scratch, result_reg, r0); | 150 __ TestIfInt32(scratch, result_reg, r0); |
162 #endif | 151 #endif |
163 __ beq(&fastpath_done); | 152 __ beq(&fastpath_done, Label::kNear); |
164 } | 153 } |
165 | 154 |
166 __ Push(scratch_high, scratch_low); | 155 __ Push(scratch_high, scratch_low); |
167 // Account for saved regs if input is sp. | 156 // Account for saved regs if input is sp. |
168 if (input_reg.is(sp)) double_offset += 2 * kPointerSize; | 157 if (input_reg.is(sp)) double_offset += 2 * kPointerSize; |
169 | 158 |
170 __ lwz(scratch_high, | 159 __ LoadlW(scratch_high, |
171 MemOperand(input_reg, double_offset + Register::kExponentOffset)); | 160 MemOperand(input_reg, double_offset + Register::kExponentOffset)); |
172 __ lwz(scratch_low, | 161 __ LoadlW(scratch_low, |
173 MemOperand(input_reg, double_offset + Register::kMantissaOffset)); | 162 MemOperand(input_reg, double_offset + Register::kMantissaOffset)); |
174 | 163 |
175 __ ExtractBitMask(scratch, scratch_high, HeapNumber::kExponentMask); | 164 __ ExtractBitMask(scratch, scratch_high, HeapNumber::kExponentMask); |
176 // Load scratch with exponent - 1. This is faster than loading | 165 // Load scratch with exponent - 1. This is faster than loading |
177 // with exponent because Bias + 1 = 1024 which is a *PPC* immediate value. | 166 // with exponent because Bias + 1 = 1024 which is a *S390* immediate value. |
178 STATIC_ASSERT(HeapNumber::kExponentBias + 1 == 1024); | 167 STATIC_ASSERT(HeapNumber::kExponentBias + 1 == 1024); |
179 __ subi(scratch, scratch, Operand(HeapNumber::kExponentBias + 1)); | 168 __ SubP(scratch, Operand(HeapNumber::kExponentBias + 1)); |
180 // If exponent is greater than or equal to 84, the 32 less significant | 169 // If exponent is greater than or equal to 84, the 32 less significant |
181 // bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits), | 170 // bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits), |
182 // the result is 0. | 171 // the result is 0. |
183 // Compare exponent with 84 (compare exponent - 1 with 83). | 172 // Compare exponent with 84 (compare exponent - 1 with 83). |
184 __ cmpi(scratch, Operand(83)); | 173 __ CmpP(scratch, Operand(83)); |
185 __ bge(&out_of_range); | 174 __ bge(&out_of_range, Label::kNear); |
186 | 175 |
187 // If we reach this code, 31 <= exponent <= 83. | 176 // If we reach this code, 31 <= exponent <= 83. |
188 // So, we don't have to handle cases where 0 <= exponent <= 20 for | 177 // So, we don't have to handle cases where 0 <= exponent <= 20 for |
189 // which we would need to shift right the high part of the mantissa. | 178 // which we would need to shift right the high part of the mantissa. |
190 // Scratch contains exponent - 1. | 179 // Scratch contains exponent - 1. |
191 // Load scratch with 52 - exponent (load with 51 - (exponent - 1)). | 180 // Load scratch with 52 - exponent (load with 51 - (exponent - 1)). |
192 __ subfic(scratch, scratch, Operand(51)); | 181 __ Load(r0, Operand(51)); |
193 __ cmpi(scratch, Operand::Zero()); | 182 __ SubP(scratch, r0, scratch); |
194 __ ble(&only_low); | 183 __ CmpP(scratch, Operand::Zero()); |
| 184 __ ble(&only_low, Label::kNear); |
195 // 21 <= exponent <= 51, shift scratch_low and scratch_high | 185 // 21 <= exponent <= 51, shift scratch_low and scratch_high |
196 // to generate the result. | 186 // to generate the result. |
197 __ srw(scratch_low, scratch_low, scratch); | 187 __ ShiftRight(scratch_low, scratch_low, scratch); |
198 // Scratch contains: 52 - exponent. | 188 // Scratch contains: 52 - exponent. |
199 // We needs: exponent - 20. | 189 // We needs: exponent - 20. |
200 // So we use: 32 - scratch = 32 - 52 + exponent = exponent - 20. | 190 // So we use: 32 - scratch = 32 - 52 + exponent = exponent - 20. |
201 __ subfic(scratch, scratch, Operand(32)); | 191 __ Load(r0, Operand(32)); |
| 192 __ SubP(scratch, r0, scratch); |
202 __ ExtractBitMask(result_reg, scratch_high, HeapNumber::kMantissaMask); | 193 __ ExtractBitMask(result_reg, scratch_high, HeapNumber::kMantissaMask); |
203 // Set the implicit 1 before the mantissa part in scratch_high. | 194 // Set the implicit 1 before the mantissa part in scratch_high. |
204 STATIC_ASSERT(HeapNumber::kMantissaBitsInTopWord >= 16); | 195 STATIC_ASSERT(HeapNumber::kMantissaBitsInTopWord >= 16); |
205 __ oris(result_reg, result_reg, | 196 __ Load(r0, Operand(1 << ((HeapNumber::kMantissaBitsInTopWord)-16))); |
206 Operand(1 << ((HeapNumber::kMantissaBitsInTopWord) - 16))); | 197 __ ShiftLeftP(r0, r0, Operand(16)); |
207 __ slw(r0, result_reg, scratch); | 198 __ OrP(result_reg, result_reg, r0); |
208 __ orx(result_reg, scratch_low, r0); | 199 __ ShiftLeft(r0, result_reg, scratch); |
209 __ b(&negate); | 200 __ OrP(result_reg, scratch_low, r0); |
| 201 __ b(&negate, Label::kNear); |
210 | 202 |
211 __ bind(&out_of_range); | 203 __ bind(&out_of_range); |
212 __ mov(result_reg, Operand::Zero()); | 204 __ mov(result_reg, Operand::Zero()); |
213 __ b(&done); | 205 __ b(&done, Label::kNear); |
214 | 206 |
215 __ bind(&only_low); | 207 __ bind(&only_low); |
216 // 52 <= exponent <= 83, shift only scratch_low. | 208 // 52 <= exponent <= 83, shift only scratch_low. |
217 // On entry, scratch contains: 52 - exponent. | 209 // On entry, scratch contains: 52 - exponent. |
218 __ neg(scratch, scratch); | 210 __ LoadComplementRR(scratch, scratch); |
219 __ slw(result_reg, scratch_low, scratch); | 211 __ ShiftLeft(result_reg, scratch_low, scratch); |
220 | 212 |
221 __ bind(&negate); | 213 __ bind(&negate); |
222 // If input was positive, scratch_high ASR 31 equals 0 and | 214 // If input was positive, scratch_high ASR 31 equals 0 and |
223 // scratch_high LSR 31 equals zero. | 215 // scratch_high LSR 31 equals zero. |
224 // New result = (result eor 0) + 0 = result. | 216 // New result = (result eor 0) + 0 = result. |
225 // If the input was negative, we have to negate the result. | 217 // If the input was negative, we have to negate the result. |
226 // Input_high ASR 31 equals 0xffffffff and scratch_high LSR 31 equals 1. | 218 // Input_high ASR 31 equals 0xffffffff and scratch_high LSR 31 equals 1. |
227 // New result = (result eor 0xffffffff) + 1 = 0 - result. | 219 // New result = (result eor 0xffffffff) + 1 = 0 - result. |
228 __ srawi(r0, scratch_high, 31); | 220 __ ShiftRightArith(r0, scratch_high, Operand(31)); |
229 #if V8_TARGET_ARCH_PPC64 | 221 #if V8_TARGET_ARCH_S390X |
230 __ srdi(r0, r0, Operand(32)); | 222 __ lgfr(r0, r0); |
| 223 __ ShiftRightP(r0, r0, Operand(32)); |
231 #endif | 224 #endif |
232 __ xor_(result_reg, result_reg, r0); | 225 __ XorP(result_reg, r0); |
233 __ srwi(r0, scratch_high, Operand(31)); | 226 __ ShiftRight(r0, scratch_high, Operand(31)); |
234 __ add(result_reg, result_reg, r0); | 227 __ AddP(result_reg, r0); |
235 | 228 |
236 __ bind(&done); | 229 __ bind(&done); |
237 __ Pop(scratch_high, scratch_low); | 230 __ Pop(scratch_high, scratch_low); |
238 | 231 |
239 __ bind(&fastpath_done); | 232 __ bind(&fastpath_done); |
240 __ pop(scratch); | 233 __ pop(scratch); |
241 | 234 |
242 __ Ret(); | 235 __ Ret(); |
243 } | 236 } |
244 | 237 |
245 | |
246 // Handle the case where the lhs and rhs are the same object. | 238 // Handle the case where the lhs and rhs are the same object. |
247 // Equality is almost reflexive (everything but NaN), so this is a test | 239 // Equality is almost reflexive (everything but NaN), so this is a test |
248 // for "identity and not NaN". | 240 // for "identity and not NaN". |
249 static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, | 241 static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, |
250 Condition cond) { | 242 Condition cond) { |
251 Label not_identical; | 243 Label not_identical; |
252 Label heap_number, return_equal; | 244 Label heap_number, return_equal; |
253 __ cmp(r3, r4); | 245 __ CmpP(r2, r3); |
254 __ bne(¬_identical); | 246 __ bne(¬_identical); |
255 | 247 |
256 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), | 248 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), |
257 // so we do the second best thing - test it ourselves. | 249 // so we do the second best thing - test it ourselves. |
258 // They are both equal and they are not both Smis so both of them are not | 250 // They are both equal and they are not both Smis so both of them are not |
259 // Smis. If it's not a heap number, then return equal. | 251 // Smis. If it's not a heap number, then return equal. |
260 if (cond == lt || cond == gt) { | 252 if (cond == lt || cond == gt) { |
261 // Call runtime on identical JSObjects. | 253 // Call runtime on identical JSObjects. |
262 __ CompareObjectType(r3, r7, r7, FIRST_JS_RECEIVER_TYPE); | 254 __ CompareObjectType(r2, r6, r6, FIRST_JS_RECEIVER_TYPE); |
263 __ bge(slow); | 255 __ bge(slow); |
264 // Call runtime on identical symbols since we need to throw a TypeError. | 256 // Call runtime on identical symbols since we need to throw a TypeError. |
265 __ cmpi(r7, Operand(SYMBOL_TYPE)); | 257 __ CmpP(r6, Operand(SYMBOL_TYPE)); |
266 __ beq(slow); | 258 __ beq(slow); |
267 // Call runtime on identical SIMD values since we must throw a TypeError. | 259 // Call runtime on identical SIMD values since we must throw a TypeError. |
268 __ cmpi(r7, Operand(SIMD128_VALUE_TYPE)); | 260 __ CmpP(r6, Operand(SIMD128_VALUE_TYPE)); |
269 __ beq(slow); | 261 __ beq(slow); |
270 } else { | 262 } else { |
271 __ CompareObjectType(r3, r7, r7, HEAP_NUMBER_TYPE); | 263 __ CompareObjectType(r2, r6, r6, HEAP_NUMBER_TYPE); |
272 __ beq(&heap_number); | 264 __ beq(&heap_number); |
273 // Comparing JS objects with <=, >= is complicated. | 265 // Comparing JS objects with <=, >= is complicated. |
274 if (cond != eq) { | 266 if (cond != eq) { |
275 __ cmpi(r7, Operand(FIRST_JS_RECEIVER_TYPE)); | 267 __ CmpP(r6, Operand(FIRST_JS_RECEIVER_TYPE)); |
276 __ bge(slow); | 268 __ bge(slow); |
277 // Call runtime on identical symbols since we need to throw a TypeError. | 269 // Call runtime on identical symbols since we need to throw a TypeError. |
278 __ cmpi(r7, Operand(SYMBOL_TYPE)); | 270 __ CmpP(r6, Operand(SYMBOL_TYPE)); |
279 __ beq(slow); | 271 __ beq(slow); |
280 // Call runtime on identical SIMD values since we must throw a TypeError. | 272 // Call runtime on identical SIMD values since we must throw a TypeError. |
281 __ cmpi(r7, Operand(SIMD128_VALUE_TYPE)); | 273 __ CmpP(r6, Operand(SIMD128_VALUE_TYPE)); |
282 __ beq(slow); | 274 __ beq(slow); |
283 // Normally here we fall through to return_equal, but undefined is | 275 // Normally here we fall through to return_equal, but undefined is |
284 // special: (undefined == undefined) == true, but | 276 // special: (undefined == undefined) == true, but |
285 // (undefined <= undefined) == false! See ECMAScript 11.8.5. | 277 // (undefined <= undefined) == false! See ECMAScript 11.8.5. |
286 if (cond == le || cond == ge) { | 278 if (cond == le || cond == ge) { |
287 __ cmpi(r7, Operand(ODDBALL_TYPE)); | 279 __ CmpP(r6, Operand(ODDBALL_TYPE)); |
288 __ bne(&return_equal); | 280 __ bne(&return_equal); |
289 __ LoadRoot(r5, Heap::kUndefinedValueRootIndex); | 281 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex); |
290 __ cmp(r3, r5); | |
291 __ bne(&return_equal); | 282 __ bne(&return_equal); |
292 if (cond == le) { | 283 if (cond == le) { |
293 // undefined <= undefined should fail. | 284 // undefined <= undefined should fail. |
294 __ li(r3, Operand(GREATER)); | 285 __ LoadImmP(r2, Operand(GREATER)); |
295 } else { | 286 } else { |
296 // undefined >= undefined should fail. | 287 // undefined >= undefined should fail. |
297 __ li(r3, Operand(LESS)); | 288 __ LoadImmP(r2, Operand(LESS)); |
298 } | 289 } |
299 __ Ret(); | 290 __ Ret(); |
300 } | 291 } |
301 } | 292 } |
302 } | 293 } |
303 | 294 |
304 __ bind(&return_equal); | 295 __ bind(&return_equal); |
305 if (cond == lt) { | 296 if (cond == lt) { |
306 __ li(r3, Operand(GREATER)); // Things aren't less than themselves. | 297 __ LoadImmP(r2, Operand(GREATER)); // Things aren't less than themselves. |
307 } else if (cond == gt) { | 298 } else if (cond == gt) { |
308 __ li(r3, Operand(LESS)); // Things aren't greater than themselves. | 299 __ LoadImmP(r2, Operand(LESS)); // Things aren't greater than themselves. |
309 } else { | 300 } else { |
310 __ li(r3, Operand(EQUAL)); // Things are <=, >=, ==, === themselves. | 301 __ LoadImmP(r2, Operand(EQUAL)); // Things are <=, >=, ==, === themselves |
311 } | 302 } |
312 __ Ret(); | 303 __ Ret(); |
313 | 304 |
314 // For less and greater we don't have to check for NaN since the result of | 305 // For less and greater we don't have to check for NaN since the result of |
315 // x < x is false regardless. For the others here is some code to check | 306 // x < x is false regardless. For the others here is some code to check |
316 // for NaN. | 307 // for NaN. |
317 if (cond != lt && cond != gt) { | 308 if (cond != lt && cond != gt) { |
318 __ bind(&heap_number); | 309 __ bind(&heap_number); |
319 // It is a heap number, so return non-equal if it's NaN and equal if it's | 310 // It is a heap number, so return non-equal if it's NaN and equal if it's |
320 // not NaN. | 311 // not NaN. |
321 | 312 |
322 // The representation of NaN values has all exponent bits (52..62) set, | 313 // The representation of NaN values has all exponent bits (52..62) set, |
323 // and not all mantissa bits (0..51) clear. | 314 // and not all mantissa bits (0..51) clear. |
324 // Read top bits of double representation (second word of value). | 315 // Read top bits of double representation (second word of value). |
325 __ lwz(r5, FieldMemOperand(r3, HeapNumber::kExponentOffset)); | 316 __ LoadlW(r4, FieldMemOperand(r2, HeapNumber::kExponentOffset)); |
326 // Test that exponent bits are all set. | 317 // Test that exponent bits are all set. |
327 STATIC_ASSERT(HeapNumber::kExponentMask == 0x7ff00000u); | 318 STATIC_ASSERT(HeapNumber::kExponentMask == 0x7ff00000u); |
328 __ ExtractBitMask(r6, r5, HeapNumber::kExponentMask); | 319 __ ExtractBitMask(r5, r4, HeapNumber::kExponentMask); |
329 __ cmpli(r6, Operand(0x7ff)); | 320 __ CmpLogicalP(r5, Operand(0x7ff)); |
330 __ bne(&return_equal); | 321 __ bne(&return_equal); |
331 | 322 |
332 // Shift out flag and all exponent bits, retaining only mantissa. | 323 // Shift out flag and all exponent bits, retaining only mantissa. |
333 __ slwi(r5, r5, Operand(HeapNumber::kNonMantissaBitsInTopWord)); | 324 __ sll(r4, Operand(HeapNumber::kNonMantissaBitsInTopWord)); |
334 // Or with all low-bits of mantissa. | 325 // Or with all low-bits of mantissa. |
335 __ lwz(r6, FieldMemOperand(r3, HeapNumber::kMantissaOffset)); | 326 __ LoadlW(r5, FieldMemOperand(r2, HeapNumber::kMantissaOffset)); |
336 __ orx(r3, r6, r5); | 327 __ OrP(r2, r5, r4); |
337 __ cmpi(r3, Operand::Zero()); | 328 __ CmpP(r2, Operand::Zero()); |
338 // For equal we already have the right value in r3: Return zero (equal) | 329 // For equal we already have the right value in r2: Return zero (equal) |
339 // if all bits in mantissa are zero (it's an Infinity) and non-zero if | 330 // if all bits in mantissa are zero (it's an Infinity) and non-zero if |
340 // not (it's a NaN). For <= and >= we need to load r0 with the failing | 331 // not (it's a NaN). For <= and >= we need to load r0 with the failing |
341 // value if it's a NaN. | 332 // value if it's a NaN. |
342 if (cond != eq) { | 333 if (cond != eq) { |
343 if (CpuFeatures::IsSupported(ISELECT)) { | 334 Label not_equal; |
344 __ li(r4, Operand((cond == le) ? GREATER : LESS)); | 335 __ bne(¬_equal, Label::kNear); |
345 __ isel(eq, r3, r3, r4); | 336 // All-zero means Infinity means equal. |
| 337 __ Ret(); |
| 338 __ bind(¬_equal); |
| 339 if (cond == le) { |
| 340 __ LoadImmP(r2, Operand(GREATER)); // NaN <= NaN should fail. |
346 } else { | 341 } else { |
347 // All-zero means Infinity means equal. | 342 __ LoadImmP(r2, Operand(LESS)); // NaN >= NaN should fail. |
348 __ Ret(eq); | |
349 if (cond == le) { | |
350 __ li(r3, Operand(GREATER)); // NaN <= NaN should fail. | |
351 } else { | |
352 __ li(r3, Operand(LESS)); // NaN >= NaN should fail. | |
353 } | |
354 } | 343 } |
355 } | 344 } |
356 __ Ret(); | 345 __ Ret(); |
357 } | 346 } |
358 // No fall through here. | 347 // No fall through here. |
359 | 348 |
360 __ bind(¬_identical); | 349 __ bind(¬_identical); |
361 } | 350 } |
362 | 351 |
363 | |
364 // See comment at call site. | 352 // See comment at call site. |
365 static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs, | 353 static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs, |
366 Register rhs, Label* lhs_not_nan, | 354 Register rhs, Label* lhs_not_nan, |
367 Label* slow, bool strict) { | 355 Label* slow, bool strict) { |
368 DCHECK((lhs.is(r3) && rhs.is(r4)) || (lhs.is(r4) && rhs.is(r3))); | 356 DCHECK((lhs.is(r2) && rhs.is(r3)) || (lhs.is(r3) && rhs.is(r2))); |
369 | 357 |
370 Label rhs_is_smi; | 358 Label rhs_is_smi; |
371 __ JumpIfSmi(rhs, &rhs_is_smi); | 359 __ JumpIfSmi(rhs, &rhs_is_smi); |
372 | 360 |
373 // Lhs is a Smi. Check whether the rhs is a heap number. | 361 // Lhs is a Smi. Check whether the rhs is a heap number. |
374 __ CompareObjectType(rhs, r6, r7, HEAP_NUMBER_TYPE); | 362 __ CompareObjectType(rhs, r5, r6, HEAP_NUMBER_TYPE); |
375 if (strict) { | 363 if (strict) { |
376 // If rhs is not a number and lhs is a Smi then strict equality cannot | 364 // If rhs is not a number and lhs is a Smi then strict equality cannot |
377 // succeed. Return non-equal | 365 // succeed. Return non-equal |
378 // If rhs is r3 then there is already a non zero value in it. | 366 // If rhs is r2 then there is already a non zero value in it. |
379 if (!rhs.is(r3)) { | 367 Label skip; |
380 Label skip; | 368 __ beq(&skip, Label::kNear); |
381 __ beq(&skip); | 369 if (!rhs.is(r2)) { |
382 __ mov(r3, Operand(NOT_EQUAL)); | 370 __ mov(r2, Operand(NOT_EQUAL)); |
383 __ Ret(); | |
384 __ bind(&skip); | |
385 } else { | |
386 __ Ret(ne); | |
387 } | 371 } |
| 372 __ Ret(); |
| 373 __ bind(&skip); |
388 } else { | 374 } else { |
389 // Smi compared non-strictly with a non-Smi non-heap-number. Call | 375 // Smi compared non-strictly with a non-Smi non-heap-number. Call |
390 // the runtime. | 376 // the runtime. |
391 __ bne(slow); | 377 __ bne(slow); |
392 } | 378 } |
393 | 379 |
394 // Lhs is a smi, rhs is a number. | 380 // Lhs is a smi, rhs is a number. |
395 // Convert lhs to a double in d7. | 381 // Convert lhs to a double in d7. |
396 __ SmiToDouble(d7, lhs); | 382 __ SmiToDouble(d7, lhs); |
397 // Load the double from rhs, tagged HeapNumber r3, to d6. | 383 // Load the double from rhs, tagged HeapNumber r2, to d6. |
398 __ lfd(d6, FieldMemOperand(rhs, HeapNumber::kValueOffset)); | 384 __ LoadDouble(d6, FieldMemOperand(rhs, HeapNumber::kValueOffset)); |
399 | 385 |
400 // We now have both loaded as doubles but we can skip the lhs nan check | 386 // We now have both loaded as doubles but we can skip the lhs nan check |
401 // since it's a smi. | 387 // since it's a smi. |
402 __ b(lhs_not_nan); | 388 __ b(lhs_not_nan); |
403 | 389 |
404 __ bind(&rhs_is_smi); | 390 __ bind(&rhs_is_smi); |
405 // Rhs is a smi. Check whether the non-smi lhs is a heap number. | 391 // Rhs is a smi. Check whether the non-smi lhs is a heap number. |
406 __ CompareObjectType(lhs, r7, r7, HEAP_NUMBER_TYPE); | 392 __ CompareObjectType(lhs, r6, r6, HEAP_NUMBER_TYPE); |
407 if (strict) { | 393 if (strict) { |
408 // If lhs is not a number and rhs is a smi then strict equality cannot | 394 // If lhs is not a number and rhs is a smi then strict equality cannot |
409 // succeed. Return non-equal. | 395 // succeed. Return non-equal. |
410 // If lhs is r3 then there is already a non zero value in it. | 396 // If lhs is r2 then there is already a non zero value in it. |
411 if (!lhs.is(r3)) { | 397 Label skip; |
412 Label skip; | 398 __ beq(&skip, Label::kNear); |
413 __ beq(&skip); | 399 if (!lhs.is(r2)) { |
414 __ mov(r3, Operand(NOT_EQUAL)); | 400 __ mov(r2, Operand(NOT_EQUAL)); |
415 __ Ret(); | |
416 __ bind(&skip); | |
417 } else { | |
418 __ Ret(ne); | |
419 } | 401 } |
| 402 __ Ret(); |
| 403 __ bind(&skip); |
420 } else { | 404 } else { |
421 // Smi compared non-strictly with a non-smi non-heap-number. Call | 405 // Smi compared non-strictly with a non-smi non-heap-number. Call |
422 // the runtime. | 406 // the runtime. |
423 __ bne(slow); | 407 __ bne(slow); |
424 } | 408 } |
425 | 409 |
426 // Rhs is a smi, lhs is a heap number. | 410 // Rhs is a smi, lhs is a heap number. |
427 // Load the double from lhs, tagged HeapNumber r4, to d7. | 411 // Load the double from lhs, tagged HeapNumber r3, to d7. |
428 __ lfd(d7, FieldMemOperand(lhs, HeapNumber::kValueOffset)); | 412 __ LoadDouble(d7, FieldMemOperand(lhs, HeapNumber::kValueOffset)); |
429 // Convert rhs to a double in d6. | 413 // Convert rhs to a double in d6. |
430 __ SmiToDouble(d6, rhs); | 414 __ SmiToDouble(d6, rhs); |
431 // Fall through to both_loaded_as_doubles. | 415 // Fall through to both_loaded_as_doubles. |
432 } | 416 } |
433 | 417 |
434 | |
435 // See comment at call site. | 418 // See comment at call site. |
436 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, Register lhs, | 419 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, Register lhs, |
437 Register rhs) { | 420 Register rhs) { |
438 DCHECK((lhs.is(r3) && rhs.is(r4)) || (lhs.is(r4) && rhs.is(r3))); | 421 DCHECK((lhs.is(r2) && rhs.is(r3)) || (lhs.is(r3) && rhs.is(r2))); |
439 | 422 |
440 // If either operand is a JS object or an oddball value, then they are | 423 // If either operand is a JS object or an oddball value, then they are |
441 // not equal since their pointers are different. | 424 // not equal since their pointers are different. |
442 // There is no test for undetectability in strict equality. | 425 // There is no test for undetectability in strict equality. |
443 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | 426 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
444 Label first_non_object; | 427 Label first_non_object; |
445 // Get the type of the first operand into r5 and compare it with | 428 // Get the type of the first operand into r4 and compare it with |
446 // FIRST_JS_RECEIVER_TYPE. | 429 // FIRST_JS_RECEIVER_TYPE. |
447 __ CompareObjectType(rhs, r5, r5, FIRST_JS_RECEIVER_TYPE); | 430 __ CompareObjectType(rhs, r4, r4, FIRST_JS_RECEIVER_TYPE); |
448 __ blt(&first_non_object); | 431 __ blt(&first_non_object, Label::kNear); |
449 | 432 |
450 // Return non-zero (r3 is not zero) | 433 // Return non-zero (r2 is not zero) |
451 Label return_not_equal; | 434 Label return_not_equal; |
452 __ bind(&return_not_equal); | 435 __ bind(&return_not_equal); |
453 __ Ret(); | 436 __ Ret(); |
454 | 437 |
455 __ bind(&first_non_object); | 438 __ bind(&first_non_object); |
456 // Check for oddballs: true, false, null, undefined. | 439 // Check for oddballs: true, false, null, undefined. |
457 __ cmpi(r5, Operand(ODDBALL_TYPE)); | 440 __ CmpP(r4, Operand(ODDBALL_TYPE)); |
458 __ beq(&return_not_equal); | 441 __ beq(&return_not_equal); |
459 | 442 |
460 __ CompareObjectType(lhs, r6, r6, FIRST_JS_RECEIVER_TYPE); | 443 __ CompareObjectType(lhs, r5, r5, FIRST_JS_RECEIVER_TYPE); |
461 __ bge(&return_not_equal); | 444 __ bge(&return_not_equal); |
462 | 445 |
463 // Check for oddballs: true, false, null, undefined. | 446 // Check for oddballs: true, false, null, undefined. |
464 __ cmpi(r6, Operand(ODDBALL_TYPE)); | 447 __ CmpP(r5, Operand(ODDBALL_TYPE)); |
465 __ beq(&return_not_equal); | 448 __ beq(&return_not_equal); |
466 | 449 |
467 // Now that we have the types we might as well check for | 450 // Now that we have the types we might as well check for |
468 // internalized-internalized. | 451 // internalized-internalized. |
469 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); | 452 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
470 __ orx(r5, r5, r6); | 453 __ OrP(r4, r4, r5); |
471 __ andi(r0, r5, Operand(kIsNotStringMask | kIsNotInternalizedMask)); | 454 __ AndP(r0, r4, Operand(kIsNotStringMask | kIsNotInternalizedMask)); |
472 __ beq(&return_not_equal, cr0); | 455 __ beq(&return_not_equal); |
473 } | 456 } |
474 | 457 |
475 | |
476 // See comment at call site. | 458 // See comment at call site. |
477 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, Register lhs, | 459 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, Register lhs, |
478 Register rhs, | 460 Register rhs, |
479 Label* both_loaded_as_doubles, | 461 Label* both_loaded_as_doubles, |
480 Label* not_heap_numbers, Label* slow) { | 462 Label* not_heap_numbers, Label* slow) { |
481 DCHECK((lhs.is(r3) && rhs.is(r4)) || (lhs.is(r4) && rhs.is(r3))); | 463 DCHECK((lhs.is(r2) && rhs.is(r3)) || (lhs.is(r3) && rhs.is(r2))); |
482 | 464 |
483 __ CompareObjectType(rhs, r6, r5, HEAP_NUMBER_TYPE); | 465 __ CompareObjectType(rhs, r5, r4, HEAP_NUMBER_TYPE); |
484 __ bne(not_heap_numbers); | 466 __ bne(not_heap_numbers); |
485 __ LoadP(r5, FieldMemOperand(lhs, HeapObject::kMapOffset)); | 467 __ LoadP(r4, FieldMemOperand(lhs, HeapObject::kMapOffset)); |
486 __ cmp(r5, r6); | 468 __ CmpP(r4, r5); |
487 __ bne(slow); // First was a heap number, second wasn't. Go slow case. | 469 __ bne(slow); // First was a heap number, second wasn't. Go slow case. |
488 | 470 |
489 // Both are heap numbers. Load them up then jump to the code we have | 471 // Both are heap numbers. Load them up then jump to the code we have |
490 // for that. | 472 // for that. |
491 __ lfd(d6, FieldMemOperand(rhs, HeapNumber::kValueOffset)); | 473 __ LoadDouble(d6, FieldMemOperand(rhs, HeapNumber::kValueOffset)); |
492 __ lfd(d7, FieldMemOperand(lhs, HeapNumber::kValueOffset)); | 474 __ LoadDouble(d7, FieldMemOperand(lhs, HeapNumber::kValueOffset)); |
493 | 475 |
494 __ b(both_loaded_as_doubles); | 476 __ b(both_loaded_as_doubles); |
495 } | 477 } |
496 | 478 |
497 | |
498 // Fast negative check for internalized-to-internalized equality. | 479 // Fast negative check for internalized-to-internalized equality. |
499 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, | 480 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, |
500 Register lhs, Register rhs, | 481 Register lhs, Register rhs, |
501 Label* possible_strings, | 482 Label* possible_strings, |
502 Label* runtime_call) { | 483 Label* runtime_call) { |
503 DCHECK((lhs.is(r3) && rhs.is(r4)) || (lhs.is(r4) && rhs.is(r3))); | 484 DCHECK((lhs.is(r2) && rhs.is(r3)) || (lhs.is(r3) && rhs.is(r2))); |
504 | 485 |
505 // r5 is object type of rhs. | 486 // r4 is object type of rhs. |
506 Label object_test, return_unequal, undetectable; | 487 Label object_test, return_unequal, undetectable; |
507 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); | 488 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
508 __ andi(r0, r5, Operand(kIsNotStringMask)); | 489 __ mov(r0, Operand(kIsNotStringMask)); |
509 __ bne(&object_test, cr0); | 490 __ AndP(r0, r4); |
510 __ andi(r0, r5, Operand(kIsNotInternalizedMask)); | 491 __ bne(&object_test, Label::kNear); |
511 __ bne(possible_strings, cr0); | 492 __ mov(r0, Operand(kIsNotInternalizedMask)); |
512 __ CompareObjectType(lhs, r6, r6, FIRST_NONSTRING_TYPE); | 493 __ AndP(r0, r4); |
| 494 __ bne(possible_strings); |
| 495 __ CompareObjectType(lhs, r5, r5, FIRST_NONSTRING_TYPE); |
513 __ bge(runtime_call); | 496 __ bge(runtime_call); |
514 __ andi(r0, r6, Operand(kIsNotInternalizedMask)); | 497 __ mov(r0, Operand(kIsNotInternalizedMask)); |
515 __ bne(possible_strings, cr0); | 498 __ AndP(r0, r5); |
| 499 __ bne(possible_strings); |
516 | 500 |
517 // Both are internalized. We already checked they weren't the same pointer so | 501 // Both are internalized. We already checked they weren't the same pointer so |
518 // they are not equal. Return non-equal by returning the non-zero object | 502 // they are not equal. Return non-equal by returning the non-zero object |
519 // pointer in r3. | 503 // pointer in r2. |
520 __ Ret(); | 504 __ Ret(); |
521 | 505 |
522 __ bind(&object_test); | 506 __ bind(&object_test); |
523 __ LoadP(r5, FieldMemOperand(lhs, HeapObject::kMapOffset)); | 507 __ LoadP(r4, FieldMemOperand(lhs, HeapObject::kMapOffset)); |
524 __ LoadP(r6, FieldMemOperand(rhs, HeapObject::kMapOffset)); | 508 __ LoadP(r5, FieldMemOperand(rhs, HeapObject::kMapOffset)); |
525 __ lbz(r7, FieldMemOperand(r5, Map::kBitFieldOffset)); | 509 __ LoadlB(r6, FieldMemOperand(r4, Map::kBitFieldOffset)); |
526 __ lbz(r8, FieldMemOperand(r6, Map::kBitFieldOffset)); | 510 __ LoadlB(r7, FieldMemOperand(r5, Map::kBitFieldOffset)); |
527 __ andi(r0, r7, Operand(1 << Map::kIsUndetectable)); | 511 __ AndP(r0, r6, Operand(1 << Map::kIsUndetectable)); |
528 __ bne(&undetectable, cr0); | 512 __ bne(&undetectable); |
529 __ andi(r0, r8, Operand(1 << Map::kIsUndetectable)); | 513 __ AndP(r0, r7, Operand(1 << Map::kIsUndetectable)); |
530 __ bne(&return_unequal, cr0); | 514 __ bne(&return_unequal); |
531 | 515 |
| 516 __ CompareInstanceType(r4, r4, FIRST_JS_RECEIVER_TYPE); |
| 517 __ blt(runtime_call); |
532 __ CompareInstanceType(r5, r5, FIRST_JS_RECEIVER_TYPE); | 518 __ CompareInstanceType(r5, r5, FIRST_JS_RECEIVER_TYPE); |
533 __ blt(runtime_call); | 519 __ blt(runtime_call); |
534 __ CompareInstanceType(r6, r6, FIRST_JS_RECEIVER_TYPE); | |
535 __ blt(runtime_call); | |
536 | 520 |
537 __ bind(&return_unequal); | 521 __ bind(&return_unequal); |
538 // Return non-equal by returning the non-zero object pointer in r3. | 522 // Return non-equal by returning the non-zero object pointer in r2. |
539 __ Ret(); | 523 __ Ret(); |
540 | 524 |
541 __ bind(&undetectable); | 525 __ bind(&undetectable); |
542 __ andi(r0, r8, Operand(1 << Map::kIsUndetectable)); | 526 __ AndP(r0, r7, Operand(1 << Map::kIsUndetectable)); |
543 __ beq(&return_unequal, cr0); | 527 __ beq(&return_unequal); |
544 __ li(r3, Operand(EQUAL)); | 528 __ LoadImmP(r2, Operand(EQUAL)); |
545 __ Ret(); | 529 __ Ret(); |
546 } | 530 } |
547 | 531 |
548 | |
549 static void CompareICStub_CheckInputType(MacroAssembler* masm, Register input, | 532 static void CompareICStub_CheckInputType(MacroAssembler* masm, Register input, |
550 Register scratch, | 533 Register scratch, |
551 CompareICState::State expected, | 534 CompareICState::State expected, |
552 Label* fail) { | 535 Label* fail) { |
553 Label ok; | 536 Label ok; |
554 if (expected == CompareICState::SMI) { | 537 if (expected == CompareICState::SMI) { |
555 __ JumpIfNotSmi(input, fail); | 538 __ JumpIfNotSmi(input, fail); |
556 } else if (expected == CompareICState::NUMBER) { | 539 } else if (expected == CompareICState::NUMBER) { |
557 __ JumpIfSmi(input, &ok); | 540 __ JumpIfSmi(input, &ok); |
558 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail, | 541 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail, |
559 DONT_DO_SMI_CHECK); | 542 DONT_DO_SMI_CHECK); |
560 } | 543 } |
561 // We could be strict about internalized/non-internalized here, but as long as | 544 // We could be strict about internalized/non-internalized here, but as long as |
562 // hydrogen doesn't care, the stub doesn't have to care either. | 545 // hydrogen doesn't care, the stub doesn't have to care either. |
563 __ bind(&ok); | 546 __ bind(&ok); |
564 } | 547 } |
565 | 548 |
566 | 549 // On entry r3 and r4 are the values to be compared. |
567 // On entry r4 and r5 are the values to be compared. | 550 // On exit r2 is 0, positive or negative to indicate the result of |
568 // On exit r3 is 0, positive or negative to indicate the result of | |
569 // the comparison. | 551 // the comparison. |
570 void CompareICStub::GenerateGeneric(MacroAssembler* masm) { | 552 void CompareICStub::GenerateGeneric(MacroAssembler* masm) { |
571 Register lhs = r4; | 553 Register lhs = r3; |
572 Register rhs = r3; | 554 Register rhs = r2; |
573 Condition cc = GetCondition(); | 555 Condition cc = GetCondition(); |
574 | 556 |
575 Label miss; | 557 Label miss; |
576 CompareICStub_CheckInputType(masm, lhs, r5, left(), &miss); | 558 CompareICStub_CheckInputType(masm, lhs, r4, left(), &miss); |
577 CompareICStub_CheckInputType(masm, rhs, r6, right(), &miss); | 559 CompareICStub_CheckInputType(masm, rhs, r5, right(), &miss); |
578 | 560 |
579 Label slow; // Call builtin. | 561 Label slow; // Call builtin. |
580 Label not_smis, both_loaded_as_doubles, lhs_not_nan; | 562 Label not_smis, both_loaded_as_doubles, lhs_not_nan; |
581 | 563 |
582 Label not_two_smis, smi_done; | 564 Label not_two_smis, smi_done; |
583 __ orx(r5, r4, r3); | 565 __ OrP(r4, r3, r2); |
584 __ JumpIfNotSmi(r5, ¬_two_smis); | 566 __ JumpIfNotSmi(r4, ¬_two_smis); |
585 __ SmiUntag(r4); | |
586 __ SmiUntag(r3); | 567 __ SmiUntag(r3); |
587 __ sub(r3, r4, r3); | 568 __ SmiUntag(r2); |
| 569 __ SubP(r2, r3, r2); |
588 __ Ret(); | 570 __ Ret(); |
589 __ bind(¬_two_smis); | 571 __ bind(¬_two_smis); |
590 | 572 |
591 // NOTICE! This code is only reached after a smi-fast-case check, so | 573 // NOTICE! This code is only reached after a smi-fast-case check, so |
592 // it is certain that at least one operand isn't a smi. | 574 // it is certain that at least one operand isn't a smi. |
593 | 575 |
594 // Handle the case where the objects are identical. Either returns the answer | 576 // Handle the case where the objects are identical. Either returns the answer |
595 // or goes to slow. Only falls through if the objects were not identical. | 577 // or goes to slow. Only falls through if the objects were not identical. |
596 EmitIdenticalObjectComparison(masm, &slow, cc); | 578 EmitIdenticalObjectComparison(masm, &slow, cc); |
597 | 579 |
598 // If either is a Smi (we know that not both are), then they can only | 580 // If either is a Smi (we know that not both are), then they can only |
599 // be strictly equal if the other is a HeapNumber. | 581 // be strictly equal if the other is a HeapNumber. |
600 STATIC_ASSERT(kSmiTag == 0); | 582 STATIC_ASSERT(kSmiTag == 0); |
601 DCHECK_EQ(static_cast<Smi*>(0), Smi::FromInt(0)); | 583 DCHECK_EQ(static_cast<Smi*>(0), Smi::FromInt(0)); |
602 __ and_(r5, lhs, rhs); | 584 __ AndP(r4, lhs, rhs); |
603 __ JumpIfNotSmi(r5, ¬_smis); | 585 __ JumpIfNotSmi(r4, ¬_smis); |
604 // One operand is a smi. EmitSmiNonsmiComparison generates code that can: | 586 // One operand is a smi. EmitSmiNonsmiComparison generates code that can: |
605 // 1) Return the answer. | 587 // 1) Return the answer. |
606 // 2) Go to slow. | 588 // 2) Go to slow. |
607 // 3) Fall through to both_loaded_as_doubles. | 589 // 3) Fall through to both_loaded_as_doubles. |
608 // 4) Jump to lhs_not_nan. | 590 // 4) Jump to lhs_not_nan. |
609 // In cases 3 and 4 we have found out we were dealing with a number-number | 591 // In cases 3 and 4 we have found out we were dealing with a number-number |
610 // comparison. The double values of the numbers have been loaded | 592 // comparison. The double values of the numbers have been loaded |
611 // into d7 and d6. | 593 // into d7 and d6. |
612 EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict()); | 594 EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict()); |
613 | 595 |
614 __ bind(&both_loaded_as_doubles); | 596 __ bind(&both_loaded_as_doubles); |
615 // The arguments have been converted to doubles and stored in d6 and d7 | 597 // The arguments have been converted to doubles and stored in d6 and d7 |
616 __ bind(&lhs_not_nan); | 598 __ bind(&lhs_not_nan); |
617 Label no_nan; | 599 Label no_nan; |
618 __ fcmpu(d7, d6); | 600 __ cdbr(d7, d6); |
619 | 601 |
620 Label nan, equal, less_than; | 602 Label nan, equal, less_than; |
621 __ bunordered(&nan); | 603 __ bunordered(&nan); |
622 if (CpuFeatures::IsSupported(ISELECT)) { | 604 __ beq(&equal, Label::kNear); |
623 DCHECK(EQUAL == 0); | 605 __ blt(&less_than, Label::kNear); |
624 __ li(r4, Operand(GREATER)); | 606 __ LoadImmP(r2, Operand(GREATER)); |
625 __ li(r5, Operand(LESS)); | 607 __ Ret(); |
626 __ isel(eq, r3, r0, r4); | 608 __ bind(&equal); |
627 __ isel(lt, r3, r5, r3); | 609 __ LoadImmP(r2, Operand(EQUAL)); |
628 __ Ret(); | 610 __ Ret(); |
629 } else { | 611 __ bind(&less_than); |
630 __ beq(&equal); | 612 __ LoadImmP(r2, Operand(LESS)); |
631 __ blt(&less_than); | 613 __ Ret(); |
632 __ li(r3, Operand(GREATER)); | |
633 __ Ret(); | |
634 __ bind(&equal); | |
635 __ li(r3, Operand(EQUAL)); | |
636 __ Ret(); | |
637 __ bind(&less_than); | |
638 __ li(r3, Operand(LESS)); | |
639 __ Ret(); | |
640 } | |
641 | 614 |
642 __ bind(&nan); | 615 __ bind(&nan); |
643 // If one of the sides was a NaN then the v flag is set. Load r3 with | 616 // If one of the sides was a NaN then the v flag is set. Load r2 with |
644 // whatever it takes to make the comparison fail, since comparisons with NaN | 617 // whatever it takes to make the comparison fail, since comparisons with NaN |
645 // always fail. | 618 // always fail. |
646 if (cc == lt || cc == le) { | 619 if (cc == lt || cc == le) { |
647 __ li(r3, Operand(GREATER)); | 620 __ LoadImmP(r2, Operand(GREATER)); |
648 } else { | 621 } else { |
649 __ li(r3, Operand(LESS)); | 622 __ LoadImmP(r2, Operand(LESS)); |
650 } | 623 } |
651 __ Ret(); | 624 __ Ret(); |
652 | 625 |
653 __ bind(¬_smis); | 626 __ bind(¬_smis); |
654 // At this point we know we are dealing with two different objects, | 627 // At this point we know we are dealing with two different objects, |
655 // and neither of them is a Smi. The objects are in rhs_ and lhs_. | 628 // and neither of them is a Smi. The objects are in rhs_ and lhs_. |
656 if (strict()) { | 629 if (strict()) { |
657 // This returns non-equal for some object types, or falls through if it | 630 // This returns non-equal for some object types, or falls through if it |
658 // was not lucky. | 631 // was not lucky. |
659 EmitStrictTwoHeapObjectCompare(masm, lhs, rhs); | 632 EmitStrictTwoHeapObjectCompare(masm, lhs, rhs); |
660 } | 633 } |
661 | 634 |
662 Label check_for_internalized_strings; | 635 Label check_for_internalized_strings; |
663 Label flat_string_check; | 636 Label flat_string_check; |
664 // Check for heap-number-heap-number comparison. Can jump to slow case, | 637 // Check for heap-number-heap-number comparison. Can jump to slow case, |
665 // or load both doubles into r3, r4, r5, r6 and jump to the code that handles | 638 // or load both doubles into r2, r3, r4, r5 and jump to the code that handles |
666 // that case. If the inputs are not doubles then jumps to | 639 // that case. If the inputs are not doubles then jumps to |
667 // check_for_internalized_strings. | 640 // check_for_internalized_strings. |
668 // In this case r5 will contain the type of rhs_. Never falls through. | 641 // In this case r4 will contain the type of rhs_. Never falls through. |
669 EmitCheckForTwoHeapNumbers(masm, lhs, rhs, &both_loaded_as_doubles, | 642 EmitCheckForTwoHeapNumbers(masm, lhs, rhs, &both_loaded_as_doubles, |
670 &check_for_internalized_strings, | 643 &check_for_internalized_strings, |
671 &flat_string_check); | 644 &flat_string_check); |
672 | 645 |
673 __ bind(&check_for_internalized_strings); | 646 __ bind(&check_for_internalized_strings); |
674 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of | 647 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of |
675 // internalized strings. | 648 // internalized strings. |
676 if (cc == eq && !strict()) { | 649 if (cc == eq && !strict()) { |
677 // Returns an answer for two internalized strings or two detectable objects. | 650 // Returns an answer for two internalized strings or two detectable objects. |
678 // Otherwise jumps to string case or not both strings case. | 651 // Otherwise jumps to string case or not both strings case. |
679 // Assumes that r5 is the type of rhs_ on entry. | 652 // Assumes that r4 is the type of rhs_ on entry. |
680 EmitCheckForInternalizedStringsOrObjects(masm, lhs, rhs, &flat_string_check, | 653 EmitCheckForInternalizedStringsOrObjects(masm, lhs, rhs, &flat_string_check, |
681 &slow); | 654 &slow); |
682 } | 655 } |
683 | 656 |
684 // Check for both being sequential one-byte strings, | 657 // Check for both being sequential one-byte strings, |
685 // and inline if that is the case. | 658 // and inline if that is the case. |
686 __ bind(&flat_string_check); | 659 __ bind(&flat_string_check); |
687 | 660 |
688 __ JumpIfNonSmisNotBothSequentialOneByteStrings(lhs, rhs, r5, r6, &slow); | 661 __ JumpIfNonSmisNotBothSequentialOneByteStrings(lhs, rhs, r4, r5, &slow); |
689 | 662 |
690 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r5, | 663 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r4, |
691 r6); | 664 r5); |
692 if (cc == eq) { | 665 if (cc == eq) { |
693 StringHelper::GenerateFlatOneByteStringEquals(masm, lhs, rhs, r5, r6); | 666 StringHelper::GenerateFlatOneByteStringEquals(masm, lhs, rhs, r4, r5); |
694 } else { | 667 } else { |
695 StringHelper::GenerateCompareFlatOneByteStrings(masm, lhs, rhs, r5, r6, r7); | 668 StringHelper::GenerateCompareFlatOneByteStrings(masm, lhs, rhs, r4, r5, r6); |
696 } | 669 } |
697 // Never falls through to here. | 670 // Never falls through to here. |
698 | 671 |
699 __ bind(&slow); | 672 __ bind(&slow); |
700 | 673 |
701 __ Push(lhs, rhs); | 674 __ Push(lhs, rhs); |
702 // Figure out which native to call and setup the arguments. | 675 // Figure out which native to call and setup the arguments. |
703 if (cc == eq) { | 676 if (cc == eq) { |
704 __ TailCallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals); | 677 __ TailCallRuntime(strict() ? Runtime::kStrictEquals : Runtime::kEquals); |
705 } else { | 678 } else { |
706 int ncr; // NaN compare result | 679 int ncr; // NaN compare result |
707 if (cc == lt || cc == le) { | 680 if (cc == lt || cc == le) { |
708 ncr = GREATER; | 681 ncr = GREATER; |
709 } else { | 682 } else { |
710 DCHECK(cc == gt || cc == ge); // remaining cases | 683 DCHECK(cc == gt || cc == ge); // remaining cases |
711 ncr = LESS; | 684 ncr = LESS; |
712 } | 685 } |
713 __ LoadSmiLiteral(r3, Smi::FromInt(ncr)); | 686 __ LoadSmiLiteral(r2, Smi::FromInt(ncr)); |
714 __ push(r3); | 687 __ push(r2); |
715 | 688 |
716 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 689 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
717 // tagged as a small integer. | 690 // tagged as a small integer. |
718 __ TailCallRuntime(Runtime::kCompare); | 691 __ TailCallRuntime(Runtime::kCompare); |
719 } | 692 } |
720 | 693 |
721 __ bind(&miss); | 694 __ bind(&miss); |
722 GenerateMiss(masm); | 695 GenerateMiss(masm); |
723 } | 696 } |
724 | 697 |
725 | |
726 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 698 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
727 // We don't allow a GC during a store buffer overflow so there is no need to | 699 // We don't allow a GC during a store buffer overflow so there is no need to |
728 // store the registers in any particular way, but we do have to store and | 700 // store the registers in any particular way, but we do have to store and |
729 // restore them. | 701 // restore them. |
730 __ mflr(r0); | 702 __ MultiPush(kJSCallerSaved | r14.bit()); |
731 __ MultiPush(kJSCallerSaved | r0.bit()); | |
732 if (save_doubles()) { | 703 if (save_doubles()) { |
733 __ MultiPushDoubles(kCallerSavedDoubles); | 704 __ MultiPushDoubles(kCallerSavedDoubles); |
734 } | 705 } |
735 const int argument_count = 1; | 706 const int argument_count = 1; |
736 const int fp_argument_count = 0; | 707 const int fp_argument_count = 0; |
737 const Register scratch = r4; | 708 const Register scratch = r3; |
738 | 709 |
739 AllowExternalCallThatCantCauseGC scope(masm); | 710 AllowExternalCallThatCantCauseGC scope(masm); |
740 __ PrepareCallCFunction(argument_count, fp_argument_count, scratch); | 711 __ PrepareCallCFunction(argument_count, fp_argument_count, scratch); |
741 __ mov(r3, Operand(ExternalReference::isolate_address(isolate()))); | 712 __ mov(r2, Operand(ExternalReference::isolate_address(isolate()))); |
742 __ CallCFunction(ExternalReference::store_buffer_overflow_function(isolate()), | 713 __ CallCFunction(ExternalReference::store_buffer_overflow_function(isolate()), |
743 argument_count); | 714 argument_count); |
744 if (save_doubles()) { | 715 if (save_doubles()) { |
745 __ MultiPopDoubles(kCallerSavedDoubles); | 716 __ MultiPopDoubles(kCallerSavedDoubles); |
746 } | 717 } |
747 __ MultiPop(kJSCallerSaved | r0.bit()); | 718 __ MultiPop(kJSCallerSaved | r14.bit()); |
748 __ mtlr(r0); | |
749 __ Ret(); | 719 __ Ret(); |
750 } | 720 } |
751 | 721 |
752 | |
753 void StoreRegistersStateStub::Generate(MacroAssembler* masm) { | 722 void StoreRegistersStateStub::Generate(MacroAssembler* masm) { |
754 __ PushSafepointRegisters(); | 723 __ PushSafepointRegisters(); |
755 __ blr(); | 724 __ b(r14); |
756 } | 725 } |
757 | 726 |
758 | |
759 void RestoreRegistersStateStub::Generate(MacroAssembler* masm) { | 727 void RestoreRegistersStateStub::Generate(MacroAssembler* masm) { |
760 __ PopSafepointRegisters(); | 728 __ PopSafepointRegisters(); |
761 __ blr(); | 729 __ b(r14); |
762 } | 730 } |
763 | 731 |
764 | |
765 void MathPowStub::Generate(MacroAssembler* masm) { | 732 void MathPowStub::Generate(MacroAssembler* masm) { |
766 const Register base = r4; | 733 const Register base = r3; |
767 const Register exponent = MathPowTaggedDescriptor::exponent(); | 734 const Register exponent = MathPowTaggedDescriptor::exponent(); |
768 DCHECK(exponent.is(r5)); | 735 DCHECK(exponent.is(r4)); |
769 const Register heapnumbermap = r8; | 736 const Register heapnumbermap = r7; |
770 const Register heapnumber = r3; | 737 const Register heapnumber = r2; |
771 const DoubleRegister double_base = d1; | 738 const DoubleRegister double_base = d1; |
772 const DoubleRegister double_exponent = d2; | 739 const DoubleRegister double_exponent = d2; |
773 const DoubleRegister double_result = d3; | 740 const DoubleRegister double_result = d3; |
774 const DoubleRegister double_scratch = d0; | 741 const DoubleRegister double_scratch = d0; |
775 const Register scratch = r11; | 742 const Register scratch = r1; |
776 const Register scratch2 = r10; | 743 const Register scratch2 = r9; |
777 | 744 |
778 Label call_runtime, done, int_exponent; | 745 Label call_runtime, done, int_exponent; |
779 if (exponent_type() == ON_STACK) { | 746 if (exponent_type() == ON_STACK) { |
780 Label base_is_smi, unpack_exponent; | 747 Label base_is_smi, unpack_exponent; |
781 // The exponent and base are supplied as arguments on the stack. | 748 // The exponent and base are supplied as arguments on the stack. |
782 // This can only happen if the stub is called from non-optimized code. | 749 // This can only happen if the stub is called from non-optimized code. |
783 // Load input parameters from stack to double registers. | 750 // Load input parameters from stack to double registers. |
784 __ LoadP(base, MemOperand(sp, 1 * kPointerSize)); | 751 __ LoadP(base, MemOperand(sp, 1 * kPointerSize)); |
785 __ LoadP(exponent, MemOperand(sp, 0 * kPointerSize)); | 752 __ LoadP(exponent, MemOperand(sp, 0 * kPointerSize)); |
786 | 753 |
787 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex); | 754 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex); |
788 | 755 |
789 __ UntagAndJumpIfSmi(scratch, base, &base_is_smi); | 756 __ UntagAndJumpIfSmi(scratch, base, &base_is_smi); |
790 __ LoadP(scratch, FieldMemOperand(base, JSObject::kMapOffset)); | 757 __ LoadP(scratch, FieldMemOperand(base, JSObject::kMapOffset)); |
791 __ cmp(scratch, heapnumbermap); | 758 __ CmpP(scratch, heapnumbermap); |
792 __ bne(&call_runtime); | 759 __ bne(&call_runtime); |
793 | 760 |
794 __ lfd(double_base, FieldMemOperand(base, HeapNumber::kValueOffset)); | 761 __ LoadDouble(double_base, FieldMemOperand(base, HeapNumber::kValueOffset)); |
795 __ b(&unpack_exponent); | 762 __ b(&unpack_exponent, Label::kNear); |
796 | 763 |
797 __ bind(&base_is_smi); | 764 __ bind(&base_is_smi); |
798 __ ConvertIntToDouble(scratch, double_base); | 765 __ ConvertIntToDouble(scratch, double_base); |
799 __ bind(&unpack_exponent); | 766 __ bind(&unpack_exponent); |
800 | 767 |
801 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent); | 768 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent); |
802 __ LoadP(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); | 769 __ LoadP(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); |
803 __ cmp(scratch, heapnumbermap); | 770 __ CmpP(scratch, heapnumbermap); |
804 __ bne(&call_runtime); | 771 __ bne(&call_runtime); |
805 | 772 |
806 __ lfd(double_exponent, | 773 __ LoadDouble(double_exponent, |
807 FieldMemOperand(exponent, HeapNumber::kValueOffset)); | 774 FieldMemOperand(exponent, HeapNumber::kValueOffset)); |
808 } else if (exponent_type() == TAGGED) { | 775 } else if (exponent_type() == TAGGED) { |
809 // Base is already in double_base. | 776 // Base is already in double_base. |
810 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent); | 777 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent); |
811 | 778 |
812 __ lfd(double_exponent, | 779 __ LoadDouble(double_exponent, |
813 FieldMemOperand(exponent, HeapNumber::kValueOffset)); | 780 FieldMemOperand(exponent, HeapNumber::kValueOffset)); |
814 } | 781 } |
815 | 782 |
816 if (exponent_type() != INTEGER) { | 783 if (exponent_type() != INTEGER) { |
817 // Detect integer exponents stored as double. | 784 // Detect integer exponents stored as double. |
818 __ TryDoubleToInt32Exact(scratch, double_exponent, scratch2, | 785 __ TryDoubleToInt32Exact(scratch, double_exponent, scratch2, |
819 double_scratch); | 786 double_scratch); |
820 __ beq(&int_exponent); | 787 __ beq(&int_exponent, Label::kNear); |
821 | 788 |
822 if (exponent_type() == ON_STACK) { | 789 if (exponent_type() == ON_STACK) { |
823 // Detect square root case. Crankshaft detects constant +/-0.5 at | 790 // Detect square root case. Crankshaft detects constant +/-0.5 at |
824 // compile time and uses DoMathPowHalf instead. We then skip this check | 791 // compile time and uses DoMathPowHalf instead. We then skip this check |
825 // for non-constant cases of +/-0.5 as these hardly occur. | 792 // for non-constant cases of +/-0.5 as these hardly occur. |
826 Label not_plus_half, not_minus_inf1, not_minus_inf2; | 793 Label not_plus_half, not_minus_inf1, not_minus_inf2; |
827 | 794 |
828 // Test for 0.5. | 795 // Test for 0.5. |
829 __ LoadDoubleLiteral(double_scratch, 0.5, scratch); | 796 __ LoadDoubleLiteral(double_scratch, 0.5, scratch); |
830 __ fcmpu(double_exponent, double_scratch); | 797 __ cdbr(double_exponent, double_scratch); |
831 __ bne(¬_plus_half); | 798 __ bne(¬_plus_half, Label::kNear); |
832 | 799 |
833 // Calculates square root of base. Check for the special case of | 800 // Calculates square root of base. Check for the special case of |
834 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). | 801 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). |
835 __ LoadDoubleLiteral(double_scratch, -V8_INFINITY, scratch); | 802 __ LoadDoubleLiteral(double_scratch, -V8_INFINITY, scratch); |
836 __ fcmpu(double_base, double_scratch); | 803 __ cdbr(double_base, double_scratch); |
837 __ bne(¬_minus_inf1); | 804 __ bne(¬_minus_inf1, Label::kNear); |
838 __ fneg(double_result, double_scratch); | 805 __ lcdbr(double_result, double_scratch); |
839 __ b(&done); | 806 __ b(&done); |
840 __ bind(¬_minus_inf1); | 807 __ bind(¬_minus_inf1); |
841 | 808 |
842 // Add +0 to convert -0 to +0. | 809 // Add +0 to convert -0 to +0. |
843 __ fadd(double_scratch, double_base, kDoubleRegZero); | 810 __ ldr(double_scratch, double_base); |
844 __ fsqrt(double_result, double_scratch); | 811 __ lzdr(kDoubleRegZero); |
| 812 __ adbr(double_scratch, kDoubleRegZero); |
| 813 __ sqdbr(double_result, double_scratch); |
845 __ b(&done); | 814 __ b(&done); |
846 | 815 |
847 __ bind(¬_plus_half); | 816 __ bind(¬_plus_half); |
848 __ LoadDoubleLiteral(double_scratch, -0.5, scratch); | 817 __ LoadDoubleLiteral(double_scratch, -0.5, scratch); |
849 __ fcmpu(double_exponent, double_scratch); | 818 __ cdbr(double_exponent, double_scratch); |
850 __ bne(&call_runtime); | 819 __ bne(&call_runtime); |
851 | 820 |
852 // Calculates square root of base. Check for the special case of | 821 // Calculates square root of base. Check for the special case of |
853 // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). | 822 // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). |
854 __ LoadDoubleLiteral(double_scratch, -V8_INFINITY, scratch); | 823 __ LoadDoubleLiteral(double_scratch, -V8_INFINITY, scratch); |
855 __ fcmpu(double_base, double_scratch); | 824 __ cdbr(double_base, double_scratch); |
856 __ bne(¬_minus_inf2); | 825 __ bne(¬_minus_inf2, Label::kNear); |
857 __ fmr(double_result, kDoubleRegZero); | 826 __ ldr(double_result, kDoubleRegZero); |
858 __ b(&done); | 827 __ b(&done); |
859 __ bind(¬_minus_inf2); | 828 __ bind(¬_minus_inf2); |
860 | 829 |
861 // Add +0 to convert -0 to +0. | 830 // Add +0 to convert -0 to +0. |
862 __ fadd(double_scratch, double_base, kDoubleRegZero); | 831 __ ldr(double_scratch, double_base); |
| 832 __ lzdr(kDoubleRegZero); |
| 833 __ adbr(double_scratch, kDoubleRegZero); |
863 __ LoadDoubleLiteral(double_result, 1.0, scratch); | 834 __ LoadDoubleLiteral(double_result, 1.0, scratch); |
864 __ fsqrt(double_scratch, double_scratch); | 835 __ sqdbr(double_scratch, double_scratch); |
865 __ fdiv(double_result, double_result, double_scratch); | 836 __ ddbr(double_result, double_scratch); |
866 __ b(&done); | 837 __ b(&done); |
867 } | 838 } |
868 | 839 |
869 __ mflr(r0); | 840 __ push(r14); |
870 __ push(r0); | |
871 { | 841 { |
872 AllowExternalCallThatCantCauseGC scope(masm); | 842 AllowExternalCallThatCantCauseGC scope(masm); |
873 __ PrepareCallCFunction(0, 2, scratch); | 843 __ PrepareCallCFunction(0, 2, scratch); |
874 __ MovToFloatParameters(double_base, double_exponent); | 844 __ MovToFloatParameters(double_base, double_exponent); |
875 __ CallCFunction( | 845 __ CallCFunction( |
876 ExternalReference::power_double_double_function(isolate()), 0, 2); | 846 ExternalReference::power_double_double_function(isolate()), 0, 2); |
877 } | 847 } |
878 __ pop(r0); | 848 __ pop(r14); |
879 __ mtlr(r0); | |
880 __ MovFromFloatResult(double_result); | 849 __ MovFromFloatResult(double_result); |
881 __ b(&done); | 850 __ b(&done); |
882 } | 851 } |
883 | 852 |
884 // Calculate power with integer exponent. | 853 // Calculate power with integer exponent. |
885 __ bind(&int_exponent); | 854 __ bind(&int_exponent); |
886 | 855 |
887 // Get two copies of exponent in the registers scratch and exponent. | 856 // Get two copies of exponent in the registers scratch and exponent. |
888 if (exponent_type() == INTEGER) { | 857 if (exponent_type() == INTEGER) { |
889 __ mr(scratch, exponent); | 858 __ LoadRR(scratch, exponent); |
890 } else { | 859 } else { |
891 // Exponent has previously been stored into scratch as untagged integer. | 860 // Exponent has previously been stored into scratch as untagged integer. |
892 __ mr(exponent, scratch); | 861 __ LoadRR(exponent, scratch); |
893 } | 862 } |
894 __ fmr(double_scratch, double_base); // Back up base. | 863 __ ldr(double_scratch, double_base); // Back up base. |
895 __ li(scratch2, Operand(1)); | 864 __ LoadImmP(scratch2, Operand(1)); |
896 __ ConvertIntToDouble(scratch2, double_result); | 865 __ ConvertIntToDouble(scratch2, double_result); |
897 | 866 |
898 // Get absolute value of exponent. | 867 // Get absolute value of exponent. |
899 __ cmpi(scratch, Operand::Zero()); | 868 Label positive_exponent; |
900 if (CpuFeatures::IsSupported(ISELECT)) { | 869 __ CmpP(scratch, Operand::Zero()); |
901 __ neg(scratch2, scratch); | 870 __ bge(&positive_exponent, Label::kNear); |
902 __ isel(lt, scratch, scratch2, scratch); | 871 __ LoadComplementRR(scratch, scratch); |
903 } else { | 872 __ bind(&positive_exponent); |
904 Label positive_exponent; | |
905 __ bge(&positive_exponent); | |
906 __ neg(scratch, scratch); | |
907 __ bind(&positive_exponent); | |
908 } | |
909 | 873 |
910 Label while_true, no_carry, loop_end; | 874 Label while_true, no_carry, loop_end; |
911 __ bind(&while_true); | 875 __ bind(&while_true); |
912 __ andi(scratch2, scratch, Operand(1)); | 876 __ mov(scratch2, Operand(1)); |
913 __ beq(&no_carry, cr0); | 877 __ AndP(scratch2, scratch); |
914 __ fmul(double_result, double_result, double_scratch); | 878 __ beq(&no_carry, Label::kNear); |
| 879 __ mdbr(double_result, double_scratch); |
915 __ bind(&no_carry); | 880 __ bind(&no_carry); |
916 __ ShiftRightArithImm(scratch, scratch, 1, SetRC); | 881 __ ShiftRightArithP(scratch, scratch, Operand(1)); |
917 __ beq(&loop_end, cr0); | 882 __ beq(&loop_end, Label::kNear); |
918 __ fmul(double_scratch, double_scratch, double_scratch); | 883 __ mdbr(double_scratch, double_scratch); |
919 __ b(&while_true); | 884 __ b(&while_true); |
920 __ bind(&loop_end); | 885 __ bind(&loop_end); |
921 | 886 |
922 __ cmpi(exponent, Operand::Zero()); | 887 __ CmpP(exponent, Operand::Zero()); |
923 __ bge(&done); | 888 __ bge(&done); |
924 | 889 |
925 __ li(scratch2, Operand(1)); | 890 // get 1/double_result: |
926 __ ConvertIntToDouble(scratch2, double_scratch); | 891 __ ldr(double_scratch, double_result); |
927 __ fdiv(double_result, double_scratch, double_result); | 892 __ LoadImmP(scratch2, Operand(1)); |
| 893 __ ConvertIntToDouble(scratch2, double_result); |
| 894 __ ddbr(double_result, double_scratch); |
| 895 |
928 // Test whether result is zero. Bail out to check for subnormal result. | 896 // Test whether result is zero. Bail out to check for subnormal result. |
929 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. | 897 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. |
930 __ fcmpu(double_result, kDoubleRegZero); | 898 __ lzdr(kDoubleRegZero); |
931 __ bne(&done); | 899 __ cdbr(double_result, kDoubleRegZero); |
| 900 __ bne(&done, Label::kNear); |
932 // double_exponent may not containe the exponent value if the input was a | 901 // double_exponent may not containe the exponent value if the input was a |
933 // smi. We set it with exponent value before bailing out. | 902 // smi. We set it with exponent value before bailing out. |
934 __ ConvertIntToDouble(exponent, double_exponent); | 903 __ ConvertIntToDouble(exponent, double_exponent); |
935 | 904 |
936 // Returning or bailing out. | 905 // Returning or bailing out. |
937 if (exponent_type() == ON_STACK) { | 906 if (exponent_type() == ON_STACK) { |
938 // The arguments are still on the stack. | 907 // The arguments are still on the stack. |
939 __ bind(&call_runtime); | 908 __ bind(&call_runtime); |
940 __ TailCallRuntime(Runtime::kMathPowRT); | 909 __ TailCallRuntime(Runtime::kMathPowRT); |
941 | 910 |
942 // The stub is called from non-optimized code, which expects the result | 911 // The stub is called from non-optimized code, which expects the result |
943 // as heap number in exponent. | 912 // as heap number in exponent. |
944 __ bind(&done); | 913 __ bind(&done); |
945 __ AllocateHeapNumber(heapnumber, scratch, scratch2, heapnumbermap, | 914 __ AllocateHeapNumber(heapnumber, scratch, scratch2, heapnumbermap, |
946 &call_runtime); | 915 &call_runtime); |
947 __ stfd(double_result, | 916 __ StoreDouble(double_result, |
948 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); | 917 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); |
949 DCHECK(heapnumber.is(r3)); | 918 DCHECK(heapnumber.is(r2)); |
950 __ Ret(2); | 919 __ Ret(2); |
951 } else { | 920 } else { |
952 __ mflr(r0); | 921 __ push(r14); |
953 __ push(r0); | |
954 { | 922 { |
955 AllowExternalCallThatCantCauseGC scope(masm); | 923 AllowExternalCallThatCantCauseGC scope(masm); |
956 __ PrepareCallCFunction(0, 2, scratch); | 924 __ PrepareCallCFunction(0, 2, scratch); |
957 __ MovToFloatParameters(double_base, double_exponent); | 925 __ MovToFloatParameters(double_base, double_exponent); |
958 __ CallCFunction( | 926 __ CallCFunction( |
959 ExternalReference::power_double_double_function(isolate()), 0, 2); | 927 ExternalReference::power_double_double_function(isolate()), 0, 2); |
960 } | 928 } |
961 __ pop(r0); | 929 __ pop(r14); |
962 __ mtlr(r0); | |
963 __ MovFromFloatResult(double_result); | 930 __ MovFromFloatResult(double_result); |
964 | 931 |
965 __ bind(&done); | 932 __ bind(&done); |
966 __ Ret(); | 933 __ Ret(); |
967 } | 934 } |
968 } | 935 } |
969 | 936 |
970 | |
971 bool CEntryStub::NeedsImmovableCode() { return true; } | 937 bool CEntryStub::NeedsImmovableCode() { return true; } |
972 | 938 |
973 | |
974 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { | 939 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { |
975 CEntryStub::GenerateAheadOfTime(isolate); | 940 CEntryStub::GenerateAheadOfTime(isolate); |
976 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 941 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
977 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 942 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
978 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | 943 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
979 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); | 944 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); |
980 CreateWeakCellStub::GenerateAheadOfTime(isolate); | 945 CreateWeakCellStub::GenerateAheadOfTime(isolate); |
981 BinaryOpICStub::GenerateAheadOfTime(isolate); | 946 BinaryOpICStub::GenerateAheadOfTime(isolate); |
982 StoreRegistersStateStub::GenerateAheadOfTime(isolate); | 947 StoreRegistersStateStub::GenerateAheadOfTime(isolate); |
983 RestoreRegistersStateStub::GenerateAheadOfTime(isolate); | 948 RestoreRegistersStateStub::GenerateAheadOfTime(isolate); |
984 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); | 949 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); |
985 StoreFastElementStub::GenerateAheadOfTime(isolate); | 950 StoreFastElementStub::GenerateAheadOfTime(isolate); |
986 TypeofStub::GenerateAheadOfTime(isolate); | 951 TypeofStub::GenerateAheadOfTime(isolate); |
987 } | 952 } |
988 | 953 |
989 | |
990 void StoreRegistersStateStub::GenerateAheadOfTime(Isolate* isolate) { | 954 void StoreRegistersStateStub::GenerateAheadOfTime(Isolate* isolate) { |
991 StoreRegistersStateStub stub(isolate); | 955 StoreRegistersStateStub stub(isolate); |
992 stub.GetCode(); | 956 stub.GetCode(); |
993 } | 957 } |
994 | 958 |
995 | |
996 void RestoreRegistersStateStub::GenerateAheadOfTime(Isolate* isolate) { | 959 void RestoreRegistersStateStub::GenerateAheadOfTime(Isolate* isolate) { |
997 RestoreRegistersStateStub stub(isolate); | 960 RestoreRegistersStateStub stub(isolate); |
998 stub.GetCode(); | 961 stub.GetCode(); |
999 } | 962 } |
1000 | 963 |
1001 | |
1002 void CodeStub::GenerateFPStubs(Isolate* isolate) { | 964 void CodeStub::GenerateFPStubs(Isolate* isolate) { |
1003 // Generate if not already in cache. | |
1004 SaveFPRegsMode mode = kSaveFPRegs; | 965 SaveFPRegsMode mode = kSaveFPRegs; |
1005 CEntryStub(isolate, 1, mode).GetCode(); | 966 CEntryStub(isolate, 1, mode).GetCode(); |
1006 StoreBufferOverflowStub(isolate, mode).GetCode(); | 967 StoreBufferOverflowStub(isolate, mode).GetCode(); |
1007 isolate->set_fp_stubs_generated(true); | 968 isolate->set_fp_stubs_generated(true); |
1008 } | 969 } |
1009 | 970 |
1010 | |
1011 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { | 971 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { |
1012 CEntryStub stub(isolate, 1, kDontSaveFPRegs); | 972 CEntryStub stub(isolate, 1, kDontSaveFPRegs); |
1013 stub.GetCode(); | 973 stub.GetCode(); |
1014 } | 974 } |
1015 | 975 |
1016 | |
1017 void CEntryStub::Generate(MacroAssembler* masm) { | 976 void CEntryStub::Generate(MacroAssembler* masm) { |
1018 // Called from JavaScript; parameters are on stack as if calling JS function. | 977 // Called from JavaScript; parameters are on stack as if calling JS function. |
1019 // r3: number of arguments including receiver | 978 // r2: number of arguments including receiver |
1020 // r4: pointer to builtin function | 979 // r3: pointer to builtin function |
1021 // fp: frame pointer (restored after C call) | 980 // fp: frame pointer (restored after C call) |
1022 // sp: stack pointer (restored as callee's sp after C call) | 981 // sp: stack pointer (restored as callee's sp after C call) |
1023 // cp: current context (C callee-saved) | 982 // cp: current context (C callee-saved) |
1024 // | 983 // |
1025 // If argv_in_register(): | 984 // If argv_in_register(): |
1026 // r5: pointer to the first argument | 985 // r4: pointer to the first argument |
1027 ProfileEntryHookStub::MaybeCallEntryHook(masm); | 986 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
1028 | 987 |
1029 __ mr(r15, r4); | 988 __ LoadRR(r7, r3); |
1030 | 989 |
1031 if (argv_in_register()) { | 990 if (argv_in_register()) { |
1032 // Move argv into the correct register. | 991 // Move argv into the correct register. |
1033 __ mr(r4, r5); | 992 __ LoadRR(r3, r4); |
1034 } else { | 993 } else { |
1035 // Compute the argv pointer. | 994 // Compute the argv pointer. |
1036 __ ShiftLeftImm(r4, r3, Operand(kPointerSizeLog2)); | 995 __ ShiftLeftP(r3, r2, Operand(kPointerSizeLog2)); |
1037 __ add(r4, r4, sp); | 996 __ lay(r3, MemOperand(r3, sp, -kPointerSize)); |
1038 __ subi(r4, r4, Operand(kPointerSize)); | |
1039 } | 997 } |
1040 | 998 |
1041 // Enter the exit frame that transitions from JavaScript to C++. | 999 // Enter the exit frame that transitions from JavaScript to C++. |
1042 FrameScope scope(masm, StackFrame::MANUAL); | 1000 FrameScope scope(masm, StackFrame::MANUAL); |
1043 | 1001 |
1044 // Need at least one extra slot for return address location. | 1002 // Need at least one extra slot for return address location. |
1045 int arg_stack_space = 1; | 1003 int arg_stack_space = 1; |
1046 | 1004 |
1047 // Pass buffer for return value on stack if necessary | 1005 // Pass buffer for return value on stack if necessary |
1048 bool needs_return_buffer = | 1006 bool needs_return_buffer = |
1049 result_size() > 2 || | 1007 result_size() > 2 || |
1050 (result_size() == 2 && !ABI_RETURNS_OBJECT_PAIRS_IN_REGS); | 1008 (result_size() == 2 && !ABI_RETURNS_OBJECTPAIR_IN_REGS); |
1051 if (needs_return_buffer) { | 1009 if (needs_return_buffer) { |
1052 arg_stack_space += result_size(); | 1010 arg_stack_space += result_size(); |
1053 } | 1011 } |
1054 | 1012 |
| 1013 #if V8_TARGET_ARCH_S390X |
| 1014 // 64-bit linux pass Argument object by reference not value |
| 1015 arg_stack_space += 2; |
| 1016 #endif |
| 1017 |
1055 __ EnterExitFrame(save_doubles(), arg_stack_space); | 1018 __ EnterExitFrame(save_doubles(), arg_stack_space); |
1056 | 1019 |
1057 // Store a copy of argc in callee-saved registers for later. | 1020 // Store a copy of argc, argv in callee-saved registers for later. |
1058 __ mr(r14, r3); | 1021 __ LoadRR(r6, r2); |
1059 | 1022 __ LoadRR(r8, r3); |
1060 // r3, r14: number of arguments including receiver (C callee-saved) | 1023 // r2, r6: number of arguments including receiver (C callee-saved) |
1061 // r4: pointer to the first argument | 1024 // r3, r8: pointer to the first argument |
1062 // r15: pointer to builtin function (C callee-saved) | 1025 // r7: pointer to builtin function (C callee-saved) |
1063 | 1026 |
1064 // Result returned in registers or stack, depending on result size and ABI. | 1027 // Result returned in registers or stack, depending on result size and ABI. |
1065 | 1028 |
1066 Register isolate_reg = r5; | 1029 Register isolate_reg = r4; |
1067 if (needs_return_buffer) { | 1030 if (needs_return_buffer) { |
1068 // The return value is a non-scalar value. | 1031 // The return value is 16-byte non-scalar value. |
1069 // Use frame storage reserved by calling function to pass return | 1032 // Use frame storage reserved by calling function to pass return |
1070 // buffer as implicit first argument. | 1033 // buffer as implicit first argument in R2. Shfit original parameters |
1071 __ mr(r5, r4); | 1034 // by one register each. |
1072 __ mr(r4, r3); | 1035 __ LoadRR(r4, r3); |
1073 __ addi(r3, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize)); | 1036 __ LoadRR(r3, r2); |
1074 isolate_reg = r6; | 1037 __ la(r2, MemOperand(sp, (kStackFrameExtraParamSlot + 1) * kPointerSize)); |
| 1038 isolate_reg = r5; |
1075 } | 1039 } |
1076 | |
1077 // Call C built-in. | 1040 // Call C built-in. |
1078 __ mov(isolate_reg, Operand(ExternalReference::isolate_address(isolate()))); | 1041 __ mov(isolate_reg, Operand(ExternalReference::isolate_address(isolate()))); |
1079 | 1042 |
1080 Register target = r15; | 1043 Register target = r7; |
1081 if (ABI_USES_FUNCTION_DESCRIPTORS) { | |
1082 // AIX/PPC64BE Linux use a function descriptor. | |
1083 __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(r15, kPointerSize)); | |
1084 __ LoadP(ip, MemOperand(r15, 0)); // Instruction address | |
1085 target = ip; | |
1086 } else if (ABI_CALL_VIA_IP) { | |
1087 __ Move(ip, r15); | |
1088 target = ip; | |
1089 } | |
1090 | 1044 |
1091 // To let the GC traverse the return address of the exit frames, we need to | 1045 // To let the GC traverse the return address of the exit frames, we need to |
1092 // know where the return address is. The CEntryStub is unmovable, so | 1046 // know where the return address is. The CEntryStub is unmovable, so |
1093 // we can store the address on the stack to be able to find it again and | 1047 // we can store the address on the stack to be able to find it again and |
1094 // we never have to restore it, because it will not change. | 1048 // we never have to restore it, because it will not change. |
1095 Label after_call; | 1049 { |
1096 __ mov_label_addr(r0, &after_call); | 1050 Label return_label; |
1097 __ StoreP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize)); | 1051 __ larl(r14, &return_label); // Generate the return addr of call later. |
1098 __ Call(target); | 1052 __ StoreP(r14, MemOperand(sp, kStackFrameRASlot * kPointerSize)); |
1099 __ bind(&after_call); | 1053 |
| 1054 // zLinux ABI requires caller's frame to have sufficient space for callee |
| 1055 // preserved regsiter save area. |
| 1056 // __ lay(sp, MemOperand(sp, -kCalleeRegisterSaveAreaSize)); |
| 1057 __ positions_recorder()->WriteRecordedPositions(); |
| 1058 __ b(target); |
| 1059 __ bind(&return_label); |
| 1060 // __ la(sp, MemOperand(sp, +kCalleeRegisterSaveAreaSize)); |
| 1061 } |
1100 | 1062 |
1101 // If return value is on the stack, pop it to registers. | 1063 // If return value is on the stack, pop it to registers. |
1102 if (needs_return_buffer) { | 1064 if (needs_return_buffer) { |
1103 if (result_size() > 2) __ LoadP(r5, MemOperand(r3, 2 * kPointerSize)); | 1065 if (result_size() > 2) __ LoadP(r4, MemOperand(r2, 2 * kPointerSize)); |
1104 __ LoadP(r4, MemOperand(r3, kPointerSize)); | 1066 __ LoadP(r3, MemOperand(r2, kPointerSize)); |
1105 __ LoadP(r3, MemOperand(r3)); | 1067 __ LoadP(r2, MemOperand(r2)); |
1106 } | 1068 } |
1107 | 1069 |
1108 // Check result for exception sentinel. | 1070 // Check result for exception sentinel. |
1109 Label exception_returned; | 1071 Label exception_returned; |
1110 __ CompareRoot(r3, Heap::kExceptionRootIndex); | 1072 __ CompareRoot(r2, Heap::kExceptionRootIndex); |
1111 __ beq(&exception_returned); | 1073 __ beq(&exception_returned, Label::kNear); |
1112 | 1074 |
1113 // Check that there is no pending exception, otherwise we | 1075 // Check that there is no pending exception, otherwise we |
1114 // should have returned the exception sentinel. | 1076 // should have returned the exception sentinel. |
1115 if (FLAG_debug_code) { | 1077 if (FLAG_debug_code) { |
1116 Label okay; | 1078 Label okay; |
1117 ExternalReference pending_exception_address( | 1079 ExternalReference pending_exception_address( |
1118 Isolate::kPendingExceptionAddress, isolate()); | 1080 Isolate::kPendingExceptionAddress, isolate()); |
1119 | 1081 __ mov(r4, Operand(pending_exception_address)); |
1120 __ mov(r6, Operand(pending_exception_address)); | 1082 __ LoadP(r4, MemOperand(r4)); |
1121 __ LoadP(r6, MemOperand(r6)); | 1083 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); |
1122 __ CompareRoot(r6, Heap::kTheHoleValueRootIndex); | |
1123 // Cannot use check here as it attempts to generate call into runtime. | 1084 // Cannot use check here as it attempts to generate call into runtime. |
1124 __ beq(&okay); | 1085 __ beq(&okay, Label::kNear); |
1125 __ stop("Unexpected pending exception"); | 1086 __ stop("Unexpected pending exception"); |
1126 __ bind(&okay); | 1087 __ bind(&okay); |
1127 } | 1088 } |
1128 | 1089 |
1129 // Exit C frame and return. | 1090 // Exit C frame and return. |
1130 // r3:r4: result | 1091 // r2:r3: result |
1131 // sp: stack pointer | 1092 // sp: stack pointer |
1132 // fp: frame pointer | 1093 // fp: frame pointer |
1133 Register argc; | 1094 Register argc; |
1134 if (argv_in_register()) { | 1095 if (argv_in_register()) { |
1135 // We don't want to pop arguments so set argc to no_reg. | 1096 // We don't want to pop arguments so set argc to no_reg. |
1136 argc = no_reg; | 1097 argc = no_reg; |
1137 } else { | 1098 } else { |
1138 // r14: still holds argc (callee-saved). | 1099 // r6: still holds argc (callee-saved). |
1139 argc = r14; | 1100 argc = r6; |
1140 } | 1101 } |
1141 __ LeaveExitFrame(save_doubles(), argc, true); | 1102 __ LeaveExitFrame(save_doubles(), argc, true); |
1142 __ blr(); | 1103 __ b(r14); |
1143 | 1104 |
1144 // Handling of exception. | 1105 // Handling of exception. |
1145 __ bind(&exception_returned); | 1106 __ bind(&exception_returned); |
1146 | 1107 |
1147 ExternalReference pending_handler_context_address( | 1108 ExternalReference pending_handler_context_address( |
1148 Isolate::kPendingHandlerContextAddress, isolate()); | 1109 Isolate::kPendingHandlerContextAddress, isolate()); |
1149 ExternalReference pending_handler_code_address( | 1110 ExternalReference pending_handler_code_address( |
1150 Isolate::kPendingHandlerCodeAddress, isolate()); | 1111 Isolate::kPendingHandlerCodeAddress, isolate()); |
1151 ExternalReference pending_handler_offset_address( | 1112 ExternalReference pending_handler_offset_address( |
1152 Isolate::kPendingHandlerOffsetAddress, isolate()); | 1113 Isolate::kPendingHandlerOffsetAddress, isolate()); |
1153 ExternalReference pending_handler_fp_address( | 1114 ExternalReference pending_handler_fp_address( |
1154 Isolate::kPendingHandlerFPAddress, isolate()); | 1115 Isolate::kPendingHandlerFPAddress, isolate()); |
1155 ExternalReference pending_handler_sp_address( | 1116 ExternalReference pending_handler_sp_address( |
1156 Isolate::kPendingHandlerSPAddress, isolate()); | 1117 Isolate::kPendingHandlerSPAddress, isolate()); |
1157 | 1118 |
1158 // Ask the runtime for help to determine the handler. This will set r3 to | 1119 // Ask the runtime for help to determine the handler. This will set r3 to |
1159 // contain the current pending exception, don't clobber it. | 1120 // contain the current pending exception, don't clobber it. |
1160 ExternalReference find_handler(Runtime::kUnwindAndFindExceptionHandler, | 1121 ExternalReference find_handler(Runtime::kUnwindAndFindExceptionHandler, |
1161 isolate()); | 1122 isolate()); |
1162 { | 1123 { |
1163 FrameScope scope(masm, StackFrame::MANUAL); | 1124 FrameScope scope(masm, StackFrame::MANUAL); |
1164 __ PrepareCallCFunction(3, 0, r3); | 1125 __ PrepareCallCFunction(3, 0, r2); |
1165 __ li(r3, Operand::Zero()); | 1126 __ LoadImmP(r2, Operand::Zero()); |
1166 __ li(r4, Operand::Zero()); | 1127 __ LoadImmP(r3, Operand::Zero()); |
1167 __ mov(r5, Operand(ExternalReference::isolate_address(isolate()))); | 1128 __ mov(r4, Operand(ExternalReference::isolate_address(isolate()))); |
1168 __ CallCFunction(find_handler, 3); | 1129 __ CallCFunction(find_handler, 3); |
1169 } | 1130 } |
1170 | 1131 |
1171 // Retrieve the handler context, SP and FP. | 1132 // Retrieve the handler context, SP and FP. |
1172 __ mov(cp, Operand(pending_handler_context_address)); | 1133 __ mov(cp, Operand(pending_handler_context_address)); |
1173 __ LoadP(cp, MemOperand(cp)); | 1134 __ LoadP(cp, MemOperand(cp)); |
1174 __ mov(sp, Operand(pending_handler_sp_address)); | 1135 __ mov(sp, Operand(pending_handler_sp_address)); |
1175 __ LoadP(sp, MemOperand(sp)); | 1136 __ LoadP(sp, MemOperand(sp)); |
1176 __ mov(fp, Operand(pending_handler_fp_address)); | 1137 __ mov(fp, Operand(pending_handler_fp_address)); |
1177 __ LoadP(fp, MemOperand(fp)); | 1138 __ LoadP(fp, MemOperand(fp)); |
1178 | 1139 |
1179 // If the handler is a JS frame, restore the context to the frame. Note that | 1140 // If the handler is a JS frame, restore the context to the frame. Note that |
1180 // the context will be set to (cp == 0) for non-JS frames. | 1141 // the context will be set to (cp == 0) for non-JS frames. |
1181 Label skip; | 1142 Label skip; |
1182 __ cmpi(cp, Operand::Zero()); | 1143 __ CmpP(cp, Operand::Zero()); |
1183 __ beq(&skip); | 1144 __ beq(&skip, Label::kNear); |
1184 __ StoreP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1145 __ StoreP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
1185 __ bind(&skip); | 1146 __ bind(&skip); |
1186 | 1147 |
1187 // Compute the handler entry address and jump to it. | 1148 // Compute the handler entry address and jump to it. |
1188 ConstantPoolUnavailableScope constant_pool_unavailable(masm); | 1149 __ mov(r3, Operand(pending_handler_code_address)); |
1189 __ mov(r4, Operand(pending_handler_code_address)); | 1150 __ LoadP(r3, MemOperand(r3)); |
| 1151 __ mov(r4, Operand(pending_handler_offset_address)); |
1190 __ LoadP(r4, MemOperand(r4)); | 1152 __ LoadP(r4, MemOperand(r4)); |
1191 __ mov(r5, Operand(pending_handler_offset_address)); | 1153 __ AddP(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start |
1192 __ LoadP(r5, MemOperand(r5)); | 1154 __ AddP(ip, r3, r4); |
1193 __ addi(r4, r4, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start | |
1194 if (FLAG_enable_embedded_constant_pool) { | |
1195 __ LoadConstantPoolPointerRegisterFromCodeTargetAddress(r4); | |
1196 } | |
1197 __ add(ip, r4, r5); | |
1198 __ Jump(ip); | 1155 __ Jump(ip); |
1199 } | 1156 } |
1200 | 1157 |
1201 | |
1202 void JSEntryStub::Generate(MacroAssembler* masm) { | 1158 void JSEntryStub::Generate(MacroAssembler* masm) { |
1203 // r3: code entry | 1159 // r2: code entry |
1204 // r4: function | 1160 // r3: function |
1205 // r5: receiver | 1161 // r4: receiver |
1206 // r6: argc | 1162 // r5: argc |
1207 // [sp+0]: argv | 1163 // r6: argv |
1208 | 1164 |
1209 Label invoke, handler_entry, exit; | 1165 Label invoke, handler_entry, exit; |
1210 | 1166 |
1211 // Called from C | |
1212 __ function_descriptor(); | |
1213 | |
1214 ProfileEntryHookStub::MaybeCallEntryHook(masm); | 1167 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
1215 | 1168 |
1216 // PPC LINUX ABI: | 1169 // saving floating point registers |
1217 // preserve LR in pre-reserved slot in caller's frame | 1170 #if V8_HOST_ARCH_S390X |
1218 __ mflr(r0); | 1171 // 64bit ABI requires f8 to f15 be saved |
1219 __ StoreP(r0, MemOperand(sp, kStackFrameLRSlot * kPointerSize)); | 1172 __ lay(sp, MemOperand(sp, -8 * kDoubleSize)); |
| 1173 __ std(d8, MemOperand(sp)); |
| 1174 __ std(d9, MemOperand(sp, 1 * kDoubleSize)); |
| 1175 __ std(d10, MemOperand(sp, 2 * kDoubleSize)); |
| 1176 __ std(d11, MemOperand(sp, 3 * kDoubleSize)); |
| 1177 __ std(d12, MemOperand(sp, 4 * kDoubleSize)); |
| 1178 __ std(d13, MemOperand(sp, 5 * kDoubleSize)); |
| 1179 __ std(d14, MemOperand(sp, 6 * kDoubleSize)); |
| 1180 __ std(d15, MemOperand(sp, 7 * kDoubleSize)); |
| 1181 #else |
| 1182 // 31bit ABI requires you to store f4 and f6: |
| 1183 // http://refspecs.linuxbase.org/ELF/zSeries/lzsabi0_s390.html#AEN417 |
| 1184 __ lay(sp, MemOperand(sp, -2 * kDoubleSize)); |
| 1185 __ std(d4, MemOperand(sp)); |
| 1186 __ std(d6, MemOperand(sp, kDoubleSize)); |
| 1187 #endif |
1220 | 1188 |
1221 // Save callee saved registers on the stack. | 1189 // zLinux ABI |
1222 __ MultiPush(kCalleeSaved); | 1190 // Incoming parameters: |
| 1191 // r2: code entry |
| 1192 // r3: function |
| 1193 // r4: receiver |
| 1194 // r5: argc |
| 1195 // r6: argv |
| 1196 // Requires us to save the callee-preserved registers r6-r13 |
| 1197 // General convention is to also save r14 (return addr) and |
| 1198 // sp/r15 as well in a single STM/STMG |
| 1199 __ lay(sp, MemOperand(sp, -10 * kPointerSize)); |
| 1200 __ StoreMultipleP(r6, sp, MemOperand(sp, 0)); |
1223 | 1201 |
1224 // Save callee-saved double registers. | |
1225 __ MultiPushDoubles(kCalleeSavedDoubles); | |
1226 // Set up the reserved register for 0.0. | 1202 // Set up the reserved register for 0.0. |
1227 __ LoadDoubleLiteral(kDoubleRegZero, 0.0, r0); | 1203 // __ LoadDoubleLiteral(kDoubleRegZero, 0.0, r0); |
1228 | 1204 |
1229 // Push a frame with special values setup to mark it as an entry frame. | 1205 // Push a frame with special values setup to mark it as an entry frame. |
1230 // r3: code entry | 1206 // Bad FP (-1) |
1231 // r4: function | 1207 // SMI Marker |
1232 // r5: receiver | 1208 // SMI Marker |
1233 // r6: argc | 1209 // kCEntryFPAddress |
1234 // r7: argv | 1210 // Frame type |
1235 __ li(r0, Operand(-1)); // Push a bad frame pointer to fail if it is used. | 1211 __ lay(sp, MemOperand(sp, -5 * kPointerSize)); |
1236 __ push(r0); | 1212 // Push a bad frame pointer to fail if it is used. |
1237 if (FLAG_enable_embedded_constant_pool) { | 1213 __ LoadImmP(r10, Operand(-1)); |
1238 __ li(kConstantPoolRegister, Operand::Zero()); | 1214 |
1239 __ push(kConstantPoolRegister); | |
1240 } | |
1241 int marker = type(); | 1215 int marker = type(); |
1242 __ LoadSmiLiteral(r0, Smi::FromInt(marker)); | 1216 __ LoadSmiLiteral(r9, Smi::FromInt(marker)); |
1243 __ push(r0); | 1217 __ LoadSmiLiteral(r8, Smi::FromInt(marker)); |
1244 __ push(r0); | |
1245 // Save copies of the top frame descriptor on the stack. | 1218 // Save copies of the top frame descriptor on the stack. |
1246 __ mov(r8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); | 1219 __ mov(r7, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); |
1247 __ LoadP(r0, MemOperand(r8)); | 1220 __ LoadP(r7, MemOperand(r7)); |
1248 __ push(r0); | 1221 __ StoreMultipleP(r7, r10, MemOperand(sp, kPointerSize)); |
1249 | |
1250 // Set up frame pointer for the frame to be pushed. | 1222 // Set up frame pointer for the frame to be pushed. |
1251 __ addi(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); | 1223 // Need to add kPointerSize, because sp has one extra |
| 1224 // frame already for the frame type being pushed later. |
| 1225 __ lay(fp, |
| 1226 MemOperand(sp, -EntryFrameConstants::kCallerFPOffset + kPointerSize)); |
1252 | 1227 |
1253 // If this is the outermost JS call, set js_entry_sp value. | 1228 // If this is the outermost JS call, set js_entry_sp value. |
1254 Label non_outermost_js; | 1229 Label non_outermost_js; |
1255 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate()); | 1230 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate()); |
1256 __ mov(r8, Operand(ExternalReference(js_entry_sp))); | 1231 __ mov(r7, Operand(ExternalReference(js_entry_sp))); |
1257 __ LoadP(r9, MemOperand(r8)); | 1232 __ LoadAndTestP(r8, MemOperand(r7)); |
1258 __ cmpi(r9, Operand::Zero()); | 1233 __ bne(&non_outermost_js, Label::kNear); |
1259 __ bne(&non_outermost_js); | 1234 __ StoreP(fp, MemOperand(r7)); |
1260 __ StoreP(fp, MemOperand(r8)); | |
1261 __ LoadSmiLiteral(ip, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); | 1235 __ LoadSmiLiteral(ip, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); |
1262 Label cont; | 1236 Label cont; |
1263 __ b(&cont); | 1237 __ b(&cont, Label::kNear); |
1264 __ bind(&non_outermost_js); | 1238 __ bind(&non_outermost_js); |
1265 __ LoadSmiLiteral(ip, Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)); | 1239 __ LoadSmiLiteral(ip, Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)); |
| 1240 |
1266 __ bind(&cont); | 1241 __ bind(&cont); |
1267 __ push(ip); // frame-type | 1242 __ StoreP(ip, MemOperand(sp)); // frame-type |
1268 | 1243 |
1269 // Jump to a faked try block that does the invoke, with a faked catch | 1244 // Jump to a faked try block that does the invoke, with a faked catch |
1270 // block that sets the pending exception. | 1245 // block that sets the pending exception. |
1271 __ b(&invoke); | 1246 __ b(&invoke, Label::kNear); |
1272 | 1247 |
1273 __ bind(&handler_entry); | 1248 __ bind(&handler_entry); |
1274 handler_offset_ = handler_entry.pos(); | 1249 handler_offset_ = handler_entry.pos(); |
1275 // Caught exception: Store result (exception) in the pending exception | 1250 // Caught exception: Store result (exception) in the pending exception |
1276 // field in the JSEnv and return a failure sentinel. Coming in here the | 1251 // field in the JSEnv and return a failure sentinel. Coming in here the |
1277 // fp will be invalid because the PushStackHandler below sets it to 0 to | 1252 // fp will be invalid because the PushStackHandler below sets it to 0 to |
1278 // signal the existence of the JSEntry frame. | 1253 // signal the existence of the JSEntry frame. |
1279 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | 1254 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, |
1280 isolate()))); | 1255 isolate()))); |
1281 | 1256 |
1282 __ StoreP(r3, MemOperand(ip)); | 1257 __ StoreP(r2, MemOperand(ip)); |
1283 __ LoadRoot(r3, Heap::kExceptionRootIndex); | 1258 __ LoadRoot(r2, Heap::kExceptionRootIndex); |
1284 __ b(&exit); | 1259 __ b(&exit, Label::kNear); |
1285 | 1260 |
1286 // Invoke: Link this frame into the handler chain. | 1261 // Invoke: Link this frame into the handler chain. |
1287 __ bind(&invoke); | 1262 __ bind(&invoke); |
1288 // Must preserve r3-r7. | 1263 // Must preserve r2-r6. |
1289 __ PushStackHandler(); | 1264 __ PushStackHandler(); |
1290 // If an exception not caught by another handler occurs, this handler | 1265 // If an exception not caught by another handler occurs, this handler |
1291 // returns control to the code after the b(&invoke) above, which | 1266 // returns control to the code after the b(&invoke) above, which |
1292 // restores all kCalleeSaved registers (including cp and fp) to their | 1267 // restores all kCalleeSaved registers (including cp and fp) to their |
1293 // saved values before returning a failure to C. | 1268 // saved values before returning a failure to C. |
1294 | 1269 |
1295 // Clear any pending exceptions. | 1270 // Clear any pending exceptions. |
1296 __ mov(r8, Operand(isolate()->factory()->the_hole_value())); | |
1297 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | 1271 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, |
1298 isolate()))); | 1272 isolate()))); |
1299 __ StoreP(r8, MemOperand(ip)); | 1273 __ mov(r7, Operand(isolate()->factory()->the_hole_value())); |
| 1274 __ StoreP(r7, MemOperand(ip)); |
1300 | 1275 |
1301 // Invoke the function by calling through JS entry trampoline builtin. | 1276 // Invoke the function by calling through JS entry trampoline builtin. |
1302 // Notice that we cannot store a reference to the trampoline code directly in | 1277 // Notice that we cannot store a reference to the trampoline code directly in |
1303 // this stub, because runtime stubs are not traversed when doing GC. | 1278 // this stub, because runtime stubs are not traversed when doing GC. |
1304 | 1279 |
1305 // Expected registers by Builtins::JSEntryTrampoline | 1280 // Expected registers by Builtins::JSEntryTrampoline |
1306 // r3: code entry | 1281 // r2: code entry |
1307 // r4: function | 1282 // r3: function |
1308 // r5: receiver | 1283 // r4: receiver |
1309 // r6: argc | 1284 // r5: argc |
1310 // r7: argv | 1285 // r6: argv |
1311 if (type() == StackFrame::ENTRY_CONSTRUCT) { | 1286 if (type() == StackFrame::ENTRY_CONSTRUCT) { |
1312 ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline, | 1287 ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline, |
1313 isolate()); | 1288 isolate()); |
1314 __ mov(ip, Operand(construct_entry)); | 1289 __ mov(ip, Operand(construct_entry)); |
1315 } else { | 1290 } else { |
1316 ExternalReference entry(Builtins::kJSEntryTrampoline, isolate()); | 1291 ExternalReference entry(Builtins::kJSEntryTrampoline, isolate()); |
1317 __ mov(ip, Operand(entry)); | 1292 __ mov(ip, Operand(entry)); |
1318 } | 1293 } |
1319 __ LoadP(ip, MemOperand(ip)); // deref address | 1294 __ LoadP(ip, MemOperand(ip)); // deref address |
1320 | 1295 |
1321 // Branch and link to JSEntryTrampoline. | 1296 // Branch and link to JSEntryTrampoline. |
1322 // the address points to the start of the code object, skip the header | 1297 // the address points to the start of the code object, skip the header |
1323 __ addi(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); | 1298 __ AddP(ip, Operand(Code::kHeaderSize - kHeapObjectTag)); |
1324 __ mtctr(ip); | 1299 Label return_addr; |
1325 __ bctrl(); // make the call | 1300 // __ basr(r14, ip); |
| 1301 __ larl(r14, &return_addr); |
| 1302 __ b(ip); |
| 1303 __ bind(&return_addr); |
1326 | 1304 |
1327 // Unlink this frame from the handler chain. | 1305 // Unlink this frame from the handler chain. |
1328 __ PopStackHandler(); | 1306 __ PopStackHandler(); |
1329 | 1307 |
1330 __ bind(&exit); // r3 holds result | 1308 __ bind(&exit); // r2 holds result |
1331 // Check if the current stack frame is marked as the outermost JS frame. | 1309 // Check if the current stack frame is marked as the outermost JS frame. |
1332 Label non_outermost_js_2; | 1310 Label non_outermost_js_2; |
1333 __ pop(r8); | 1311 __ pop(r7); |
1334 __ CmpSmiLiteral(r8, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME), r0); | 1312 __ CmpSmiLiteral(r7, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME), r0); |
1335 __ bne(&non_outermost_js_2); | 1313 __ bne(&non_outermost_js_2, Label::kNear); |
1336 __ mov(r9, Operand::Zero()); | 1314 __ mov(r8, Operand::Zero()); |
1337 __ mov(r8, Operand(ExternalReference(js_entry_sp))); | 1315 __ mov(r7, Operand(ExternalReference(js_entry_sp))); |
1338 __ StoreP(r9, MemOperand(r8)); | 1316 __ StoreP(r8, MemOperand(r7)); |
1339 __ bind(&non_outermost_js_2); | 1317 __ bind(&non_outermost_js_2); |
1340 | 1318 |
1341 // Restore the top frame descriptors from the stack. | 1319 // Restore the top frame descriptors from the stack. |
1342 __ pop(r6); | 1320 __ pop(r5); |
1343 __ mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); | 1321 __ mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); |
1344 __ StoreP(r6, MemOperand(ip)); | 1322 __ StoreP(r5, MemOperand(ip)); |
1345 | 1323 |
1346 // Reset the stack to the callee saved registers. | 1324 // Reset the stack to the callee saved registers. |
1347 __ addi(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); | 1325 __ lay(sp, MemOperand(sp, -EntryFrameConstants::kCallerFPOffset)); |
1348 | 1326 |
1349 // Restore callee-saved double registers. | 1327 // Reload callee-saved preserved regs, return address reg (r14) and sp |
1350 __ MultiPopDoubles(kCalleeSavedDoubles); | 1328 __ LoadMultipleP(r6, sp, MemOperand(sp, 0)); |
| 1329 __ la(sp, MemOperand(sp, 10 * kPointerSize)); |
1351 | 1330 |
1352 // Restore callee-saved registers. | 1331 // saving floating point registers |
1353 __ MultiPop(kCalleeSaved); | 1332 #if V8_HOST_ARCH_S390X |
| 1333 // 64bit ABI requires f8 to f15 be saved |
| 1334 __ ld(d8, MemOperand(sp)); |
| 1335 __ ld(d9, MemOperand(sp, 1 * kDoubleSize)); |
| 1336 __ ld(d10, MemOperand(sp, 2 * kDoubleSize)); |
| 1337 __ ld(d11, MemOperand(sp, 3 * kDoubleSize)); |
| 1338 __ ld(d12, MemOperand(sp, 4 * kDoubleSize)); |
| 1339 __ ld(d13, MemOperand(sp, 5 * kDoubleSize)); |
| 1340 __ ld(d14, MemOperand(sp, 6 * kDoubleSize)); |
| 1341 __ ld(d15, MemOperand(sp, 7 * kDoubleSize)); |
| 1342 __ la(sp, MemOperand(sp, 8 * kDoubleSize)); |
| 1343 #else |
| 1344 // 31bit ABI requires you to store f4 and f6: |
| 1345 // http://refspecs.linuxbase.org/ELF/zSeries/lzsabi0_s390.html#AEN417 |
| 1346 __ ld(d4, MemOperand(sp)); |
| 1347 __ ld(d6, MemOperand(sp, kDoubleSize)); |
| 1348 __ la(sp, MemOperand(sp, 2 * kDoubleSize)); |
| 1349 #endif |
1354 | 1350 |
1355 // Return | 1351 __ b(r14); |
1356 __ LoadP(r0, MemOperand(sp, kStackFrameLRSlot * kPointerSize)); | |
1357 __ mtlr(r0); | |
1358 __ blr(); | |
1359 } | 1352 } |
1360 | 1353 |
1361 | |
1362 void InstanceOfStub::Generate(MacroAssembler* masm) { | 1354 void InstanceOfStub::Generate(MacroAssembler* masm) { |
1363 Register const object = r4; // Object (lhs). | 1355 Register const object = r3; // Object (lhs). |
1364 Register const function = r3; // Function (rhs). | 1356 Register const function = r2; // Function (rhs). |
1365 Register const object_map = r5; // Map of {object}. | 1357 Register const object_map = r4; // Map of {object}. |
1366 Register const function_map = r6; // Map of {function}. | 1358 Register const function_map = r5; // Map of {function}. |
1367 Register const function_prototype = r7; // Prototype of {function}. | 1359 Register const function_prototype = r6; // Prototype of {function}. |
1368 Register const scratch = r8; | 1360 Register const scratch = r7; |
1369 | 1361 |
1370 DCHECK(object.is(InstanceOfDescriptor::LeftRegister())); | 1362 DCHECK(object.is(InstanceOfDescriptor::LeftRegister())); |
1371 DCHECK(function.is(InstanceOfDescriptor::RightRegister())); | 1363 DCHECK(function.is(InstanceOfDescriptor::RightRegister())); |
1372 | 1364 |
1373 // Check if {object} is a smi. | 1365 // Check if {object} is a smi. |
1374 Label object_is_smi; | 1366 Label object_is_smi; |
1375 __ JumpIfSmi(object, &object_is_smi); | 1367 __ JumpIfSmi(object, &object_is_smi); |
1376 | 1368 |
1377 // Lookup the {function} and the {object} map in the global instanceof cache. | 1369 // Lookup the {function} and the {object} map in the global instanceof cache. |
1378 // Note: This is safe because we clear the global instanceof cache whenever | 1370 // Note: This is safe because we clear the global instanceof cache whenever |
1379 // we change the prototype of any object. | 1371 // we change the prototype of any object. |
1380 Label fast_case, slow_case; | 1372 Label fast_case, slow_case; |
1381 __ LoadP(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); | 1373 __ LoadP(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); |
1382 __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex); | 1374 __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex); |
1383 __ bne(&fast_case); | 1375 __ bne(&fast_case); |
1384 __ CompareRoot(object_map, Heap::kInstanceofCacheMapRootIndex); | 1376 __ CompareRoot(object_map, Heap::kInstanceofCacheMapRootIndex); |
1385 __ bne(&fast_case); | 1377 __ bne(&fast_case); |
1386 __ LoadRoot(r3, Heap::kInstanceofCacheAnswerRootIndex); | 1378 __ LoadRoot(r2, Heap::kInstanceofCacheAnswerRootIndex); |
1387 __ Ret(); | 1379 __ Ret(); |
1388 | 1380 |
1389 // If {object} is a smi we can safely return false if {function} is a JS | 1381 // If {object} is a smi we can safely return false if {function} is a JS |
1390 // function, otherwise we have to miss to the runtime and throw an exception. | 1382 // function, otherwise we have to miss to the runtime and throw an exception. |
1391 __ bind(&object_is_smi); | 1383 __ bind(&object_is_smi); |
1392 __ JumpIfSmi(function, &slow_case); | 1384 __ JumpIfSmi(function, &slow_case); |
1393 __ CompareObjectType(function, function_map, scratch, JS_FUNCTION_TYPE); | 1385 __ CompareObjectType(function, function_map, scratch, JS_FUNCTION_TYPE); |
1394 __ bne(&slow_case); | 1386 __ bne(&slow_case); |
1395 __ LoadRoot(r3, Heap::kFalseValueRootIndex); | 1387 __ LoadRoot(r2, Heap::kFalseValueRootIndex); |
1396 __ Ret(); | 1388 __ Ret(); |
1397 | 1389 |
1398 // Fast-case: The {function} must be a valid JSFunction. | 1390 // Fast-case: The {function} must be a valid JSFunction. |
1399 __ bind(&fast_case); | 1391 __ bind(&fast_case); |
1400 __ JumpIfSmi(function, &slow_case); | 1392 __ JumpIfSmi(function, &slow_case); |
1401 __ CompareObjectType(function, function_map, scratch, JS_FUNCTION_TYPE); | 1393 __ CompareObjectType(function, function_map, scratch, JS_FUNCTION_TYPE); |
1402 __ bne(&slow_case); | 1394 __ bne(&slow_case); |
1403 | 1395 |
1404 // Ensure that {function} has an instance prototype. | 1396 // Ensure that {function} has an instance prototype. |
1405 __ lbz(scratch, FieldMemOperand(function_map, Map::kBitFieldOffset)); | 1397 __ LoadlB(scratch, FieldMemOperand(function_map, Map::kBitFieldOffset)); |
1406 __ TestBit(scratch, Map::kHasNonInstancePrototype, r0); | 1398 __ TestBit(scratch, Map::kHasNonInstancePrototype, r0); |
1407 __ bne(&slow_case, cr0); | 1399 __ bne(&slow_case); |
1408 | 1400 |
1409 // Get the "prototype" (or initial map) of the {function}. | 1401 // Get the "prototype" (or initial map) of the {function}. |
1410 __ LoadP(function_prototype, | 1402 __ LoadP(function_prototype, |
1411 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 1403 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
1412 __ AssertNotSmi(function_prototype); | 1404 __ AssertNotSmi(function_prototype); |
1413 | 1405 |
1414 // Resolve the prototype if the {function} has an initial map. Afterwards the | 1406 // Resolve the prototype if the {function} has an initial map. Afterwards the |
1415 // {function_prototype} will be either the JSReceiver prototype object or the | 1407 // {function_prototype} will be either the JSReceiver prototype object or the |
1416 // hole value, which means that no instances of the {function} were created so | 1408 // hole value, which means that no instances of the {function} were created so |
1417 // far and hence we should return false. | 1409 // far and hence we should return false. |
1418 Label function_prototype_valid; | 1410 Label function_prototype_valid; |
1419 __ CompareObjectType(function_prototype, scratch, scratch, MAP_TYPE); | 1411 __ CompareObjectType(function_prototype, scratch, scratch, MAP_TYPE); |
1420 __ bne(&function_prototype_valid); | 1412 __ bne(&function_prototype_valid); |
1421 __ LoadP(function_prototype, | 1413 __ LoadP(function_prototype, |
1422 FieldMemOperand(function_prototype, Map::kPrototypeOffset)); | 1414 FieldMemOperand(function_prototype, Map::kPrototypeOffset)); |
1423 __ bind(&function_prototype_valid); | 1415 __ bind(&function_prototype_valid); |
1424 __ AssertNotSmi(function_prototype); | 1416 __ AssertNotSmi(function_prototype); |
1425 | 1417 |
1426 // Update the global instanceof cache with the current {object} map and | 1418 // Update the global instanceof cache with the current {object} map and |
1427 // {function}. The cached answer will be set when it is known below. | 1419 // {function}. The cached answer will be set when it is known below. |
1428 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); | 1420 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); |
1429 __ StoreRoot(object_map, Heap::kInstanceofCacheMapRootIndex); | 1421 __ StoreRoot(object_map, Heap::kInstanceofCacheMapRootIndex); |
1430 | 1422 |
1431 // Loop through the prototype chain looking for the {function} prototype. | 1423 // Loop through the prototype chain looking for the {function} prototype. |
1432 // Assume true, and change to false if not found. | 1424 // Assume true, and change to false if not found. |
1433 Register const object_instance_type = function_map; | 1425 Register const object_instance_type = function_map; |
1434 Register const map_bit_field = function_map; | 1426 Register const map_bit_field = function_map; |
1435 Register const null = scratch; | 1427 Register const null = scratch; |
1436 Register const result = r3; | 1428 Register const result = r2; |
1437 | 1429 |
1438 Label done, loop, fast_runtime_fallback; | 1430 Label done, loop, fast_runtime_fallback; |
1439 __ LoadRoot(result, Heap::kTrueValueRootIndex); | 1431 __ LoadRoot(result, Heap::kTrueValueRootIndex); |
1440 __ LoadRoot(null, Heap::kNullValueRootIndex); | 1432 __ LoadRoot(null, Heap::kNullValueRootIndex); |
1441 __ bind(&loop); | 1433 __ bind(&loop); |
1442 | 1434 |
1443 // Check if the object needs to be access checked. | 1435 // Check if the object needs to be access checked. |
1444 __ lbz(map_bit_field, FieldMemOperand(object_map, Map::kBitFieldOffset)); | 1436 __ LoadlB(map_bit_field, FieldMemOperand(object_map, Map::kBitFieldOffset)); |
1445 __ TestBit(map_bit_field, Map::kIsAccessCheckNeeded, r0); | 1437 __ TestBit(map_bit_field, Map::kIsAccessCheckNeeded, r0); |
1446 __ bne(&fast_runtime_fallback, cr0); | 1438 __ bne(&fast_runtime_fallback); |
1447 // Check if the current object is a Proxy. | 1439 // Check if the current object is a Proxy. |
1448 __ CompareInstanceType(object_map, object_instance_type, JS_PROXY_TYPE); | 1440 __ CompareInstanceType(object_map, object_instance_type, JS_PROXY_TYPE); |
1449 __ beq(&fast_runtime_fallback); | 1441 __ beq(&fast_runtime_fallback); |
1450 | 1442 |
1451 __ LoadP(object, FieldMemOperand(object_map, Map::kPrototypeOffset)); | 1443 __ LoadP(object, FieldMemOperand(object_map, Map::kPrototypeOffset)); |
1452 __ cmp(object, function_prototype); | 1444 __ CmpP(object, function_prototype); |
1453 __ beq(&done); | 1445 __ beq(&done); |
1454 __ cmp(object, null); | 1446 __ CmpP(object, null); |
1455 __ LoadP(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); | 1447 __ LoadP(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); |
1456 __ bne(&loop); | 1448 __ bne(&loop); |
1457 __ LoadRoot(result, Heap::kFalseValueRootIndex); | 1449 __ LoadRoot(result, Heap::kFalseValueRootIndex); |
1458 __ bind(&done); | 1450 __ bind(&done); |
1459 __ StoreRoot(result, Heap::kInstanceofCacheAnswerRootIndex); | 1451 __ StoreRoot(result, Heap::kInstanceofCacheAnswerRootIndex); |
1460 __ Ret(); | 1452 __ Ret(); |
1461 | 1453 |
1462 // Found Proxy or access check needed: Call the runtime | 1454 // Found Proxy or access check needed: Call the runtime |
1463 __ bind(&fast_runtime_fallback); | 1455 __ bind(&fast_runtime_fallback); |
1464 __ Push(object, function_prototype); | 1456 __ Push(object, function_prototype); |
1465 // Invalidate the instanceof cache. | 1457 // Invalidate the instanceof cache. |
1466 __ LoadSmiLiteral(scratch, Smi::FromInt(0)); | 1458 __ LoadSmiLiteral(scratch, Smi::FromInt(0)); |
1467 __ StoreRoot(scratch, Heap::kInstanceofCacheFunctionRootIndex); | 1459 __ StoreRoot(scratch, Heap::kInstanceofCacheFunctionRootIndex); |
1468 __ TailCallRuntime(Runtime::kHasInPrototypeChain); | 1460 __ TailCallRuntime(Runtime::kHasInPrototypeChain); |
1469 | 1461 |
1470 // Slow-case: Call the %InstanceOf runtime function. | 1462 // Slow-case: Call the %InstanceOf runtime function. |
1471 __ bind(&slow_case); | 1463 __ bind(&slow_case); |
1472 __ Push(object, function); | 1464 __ Push(object, function); |
1473 __ TailCallRuntime(Runtime::kInstanceOf); | 1465 __ TailCallRuntime(Runtime::kInstanceOf); |
1474 } | 1466 } |
1475 | 1467 |
1476 | |
1477 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { | 1468 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { |
1478 Label miss; | 1469 Label miss; |
1479 Register receiver = LoadDescriptor::ReceiverRegister(); | 1470 Register receiver = LoadDescriptor::ReceiverRegister(); |
1480 // Ensure that the vector and slot registers won't be clobbered before | 1471 // Ensure that the vector and slot registers won't be clobbered before |
1481 // calling the miss handler. | 1472 // calling the miss handler. |
1482 DCHECK(!AreAliased(r7, r8, LoadWithVectorDescriptor::VectorRegister(), | 1473 DCHECK(!AreAliased(r6, r7, LoadWithVectorDescriptor::VectorRegister(), |
1483 LoadWithVectorDescriptor::SlotRegister())); | 1474 LoadWithVectorDescriptor::SlotRegister())); |
1484 | 1475 |
1485 NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, r7, | 1476 NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, r6, |
1486 r8, &miss); | 1477 r7, &miss); |
1487 __ bind(&miss); | 1478 __ bind(&miss); |
1488 PropertyAccessCompiler::TailCallBuiltin( | 1479 PropertyAccessCompiler::TailCallBuiltin( |
1489 masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC)); | 1480 masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC)); |
1490 } | 1481 } |
1491 | 1482 |
1492 | |
1493 void LoadIndexedStringStub::Generate(MacroAssembler* masm) { | 1483 void LoadIndexedStringStub::Generate(MacroAssembler* masm) { |
1494 // Return address is in lr. | 1484 // Return address is in lr. |
1495 Label miss; | 1485 Label miss; |
1496 | 1486 |
1497 Register receiver = LoadDescriptor::ReceiverRegister(); | 1487 Register receiver = LoadDescriptor::ReceiverRegister(); |
1498 Register index = LoadDescriptor::NameRegister(); | 1488 Register index = LoadDescriptor::NameRegister(); |
1499 Register scratch = r8; | 1489 Register scratch = r7; |
1500 Register result = r3; | 1490 Register result = r2; |
1501 DCHECK(!scratch.is(receiver) && !scratch.is(index)); | 1491 DCHECK(!scratch.is(receiver) && !scratch.is(index)); |
1502 DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()) && | 1492 DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()) && |
1503 result.is(LoadWithVectorDescriptor::SlotRegister())); | 1493 result.is(LoadWithVectorDescriptor::SlotRegister())); |
1504 | 1494 |
1505 // StringCharAtGenerator doesn't use the result register until it's passed | 1495 // StringCharAtGenerator doesn't use the result register until it's passed |
1506 // the different miss possibilities. If it did, we would have a conflict | 1496 // the different miss possibilities. If it did, we would have a conflict |
1507 // when FLAG_vector_ics is true. | 1497 // when FLAG_vector_ics is true. |
1508 StringCharAtGenerator char_at_generator(receiver, index, scratch, result, | 1498 StringCharAtGenerator char_at_generator(receiver, index, scratch, result, |
1509 &miss, // When not a string. | 1499 &miss, // When not a string. |
1510 &miss, // When not a number. | 1500 &miss, // When not a number. |
1511 &miss, // When index out of range. | 1501 &miss, // When index out of range. |
1512 STRING_INDEX_IS_ARRAY_INDEX, | 1502 STRING_INDEX_IS_ARRAY_INDEX, |
1513 RECEIVER_IS_STRING); | 1503 RECEIVER_IS_STRING); |
1514 char_at_generator.GenerateFast(masm); | 1504 char_at_generator.GenerateFast(masm); |
1515 __ Ret(); | 1505 __ Ret(); |
1516 | 1506 |
1517 StubRuntimeCallHelper call_helper; | 1507 StubRuntimeCallHelper call_helper; |
1518 char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper); | 1508 char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper); |
1519 | 1509 |
1520 __ bind(&miss); | 1510 __ bind(&miss); |
1521 PropertyAccessCompiler::TailCallBuiltin( | 1511 PropertyAccessCompiler::TailCallBuiltin( |
1522 masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC)); | 1512 masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC)); |
1523 } | 1513 } |
1524 | 1514 |
1525 | |
1526 void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) { | 1515 void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) { |
1527 // Return address is in lr. | 1516 // Return address is in lr. |
1528 Label slow; | 1517 Label slow; |
1529 | 1518 |
1530 Register receiver = LoadDescriptor::ReceiverRegister(); | 1519 Register receiver = LoadDescriptor::ReceiverRegister(); |
1531 Register key = LoadDescriptor::NameRegister(); | 1520 Register key = LoadDescriptor::NameRegister(); |
1532 | 1521 |
1533 // Check that the key is an array index, that is Uint32. | 1522 // Check that the key is an array index, that is Uint32. |
1534 __ TestIfPositiveSmi(key, r0); | 1523 __ TestIfPositiveSmi(key, r0); |
1535 __ bne(&slow, cr0); | 1524 __ bne(&slow); |
1536 | 1525 |
1537 // Everything is fine, call runtime. | 1526 // Everything is fine, call runtime. |
1538 __ Push(receiver, key); // Receiver, key. | 1527 __ Push(receiver, key); // Receiver, key. |
1539 | 1528 |
1540 // Perform tail call to the entry. | 1529 // Perform tail call to the entry. |
1541 __ TailCallRuntime(Runtime::kLoadElementWithInterceptor); | 1530 __ TailCallRuntime(Runtime::kLoadElementWithInterceptor); |
1542 | 1531 |
1543 __ bind(&slow); | 1532 __ bind(&slow); |
1544 PropertyAccessCompiler::TailCallBuiltin( | 1533 PropertyAccessCompiler::TailCallBuiltin( |
1545 masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC)); | 1534 masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC)); |
1546 } | 1535 } |
1547 | 1536 |
1548 | |
1549 void RegExpExecStub::Generate(MacroAssembler* masm) { | 1537 void RegExpExecStub::Generate(MacroAssembler* masm) { |
1550 // Just jump directly to runtime if native RegExp is not selected at compile | 1538 // Just jump directly to runtime if native RegExp is not selected at compile |
1551 // time or if regexp entry in generated code is turned off runtime switch or | 1539 // time or if regexp entry in generated code is turned off runtime switch or |
1552 // at compilation. | 1540 // at compilation. |
1553 #ifdef V8_INTERPRETED_REGEXP | 1541 #ifdef V8_INTERPRETED_REGEXP |
1554 __ TailCallRuntime(Runtime::kRegExpExec); | 1542 __ TailCallRuntime(Runtime::kRegExpExec); |
1555 #else // V8_INTERPRETED_REGEXP | 1543 #else // V8_INTERPRETED_REGEXP |
1556 | 1544 |
1557 // Stack frame on entry. | 1545 // Stack frame on entry. |
1558 // sp[0]: last_match_info (expected JSArray) | 1546 // sp[0]: last_match_info (expected JSArray) |
1559 // sp[4]: previous index | 1547 // sp[4]: previous index |
1560 // sp[8]: subject string | 1548 // sp[8]: subject string |
1561 // sp[12]: JSRegExp object | 1549 // sp[12]: JSRegExp object |
1562 | 1550 |
1563 const int kLastMatchInfoOffset = 0 * kPointerSize; | 1551 const int kLastMatchInfoOffset = 0 * kPointerSize; |
1564 const int kPreviousIndexOffset = 1 * kPointerSize; | 1552 const int kPreviousIndexOffset = 1 * kPointerSize; |
1565 const int kSubjectOffset = 2 * kPointerSize; | 1553 const int kSubjectOffset = 2 * kPointerSize; |
1566 const int kJSRegExpOffset = 3 * kPointerSize; | 1554 const int kJSRegExpOffset = 3 * kPointerSize; |
1567 | 1555 |
1568 Label runtime, br_over, encoding_type_UC16; | 1556 Label runtime, br_over, encoding_type_UC16; |
1569 | 1557 |
1570 // Allocation of registers for this function. These are in callee save | 1558 // Allocation of registers for this function. These are in callee save |
1571 // registers and will be preserved by the call to the native RegExp code, as | 1559 // registers and will be preserved by the call to the native RegExp code, as |
1572 // this code is called using the normal C calling convention. When calling | 1560 // this code is called using the normal C calling convention. When calling |
1573 // directly from generated code the native RegExp code will not do a GC and | 1561 // directly from generated code the native RegExp code will not do a GC and |
1574 // therefore the content of these registers are safe to use after the call. | 1562 // therefore the content of these registers are safe to use after the call. |
1575 Register subject = r14; | 1563 Register subject = r6; |
1576 Register regexp_data = r15; | 1564 Register regexp_data = r7; |
1577 Register last_match_info_elements = r16; | 1565 Register last_match_info_elements = r8; |
1578 Register code = r17; | 1566 Register code = r9; |
| 1567 |
| 1568 __ CleanseP(r14); |
1579 | 1569 |
1580 // Ensure register assigments are consistent with callee save masks | 1570 // Ensure register assigments are consistent with callee save masks |
1581 DCHECK(subject.bit() & kCalleeSaved); | 1571 DCHECK(subject.bit() & kCalleeSaved); |
1582 DCHECK(regexp_data.bit() & kCalleeSaved); | 1572 DCHECK(regexp_data.bit() & kCalleeSaved); |
1583 DCHECK(last_match_info_elements.bit() & kCalleeSaved); | 1573 DCHECK(last_match_info_elements.bit() & kCalleeSaved); |
1584 DCHECK(code.bit() & kCalleeSaved); | 1574 DCHECK(code.bit() & kCalleeSaved); |
1585 | 1575 |
1586 // Ensure that a RegExp stack is allocated. | 1576 // Ensure that a RegExp stack is allocated. |
1587 ExternalReference address_of_regexp_stack_memory_address = | 1577 ExternalReference address_of_regexp_stack_memory_address = |
1588 ExternalReference::address_of_regexp_stack_memory_address(isolate()); | 1578 ExternalReference::address_of_regexp_stack_memory_address(isolate()); |
1589 ExternalReference address_of_regexp_stack_memory_size = | 1579 ExternalReference address_of_regexp_stack_memory_size = |
1590 ExternalReference::address_of_regexp_stack_memory_size(isolate()); | 1580 ExternalReference::address_of_regexp_stack_memory_size(isolate()); |
1591 __ mov(r3, Operand(address_of_regexp_stack_memory_size)); | 1581 __ mov(r2, Operand(address_of_regexp_stack_memory_size)); |
1592 __ LoadP(r3, MemOperand(r3, 0)); | 1582 __ LoadAndTestP(r2, MemOperand(r2)); |
1593 __ cmpi(r3, Operand::Zero()); | |
1594 __ beq(&runtime); | 1583 __ beq(&runtime); |
1595 | 1584 |
1596 // Check that the first argument is a JSRegExp object. | 1585 // Check that the first argument is a JSRegExp object. |
1597 __ LoadP(r3, MemOperand(sp, kJSRegExpOffset)); | 1586 __ LoadP(r2, MemOperand(sp, kJSRegExpOffset)); |
1598 __ JumpIfSmi(r3, &runtime); | 1587 __ JumpIfSmi(r2, &runtime); |
1599 __ CompareObjectType(r3, r4, r4, JS_REGEXP_TYPE); | 1588 __ CompareObjectType(r2, r3, r3, JS_REGEXP_TYPE); |
1600 __ bne(&runtime); | 1589 __ bne(&runtime); |
1601 | 1590 |
1602 // Check that the RegExp has been compiled (data contains a fixed array). | 1591 // Check that the RegExp has been compiled (data contains a fixed array). |
1603 __ LoadP(regexp_data, FieldMemOperand(r3, JSRegExp::kDataOffset)); | 1592 __ LoadP(regexp_data, FieldMemOperand(r2, JSRegExp::kDataOffset)); |
1604 if (FLAG_debug_code) { | 1593 if (FLAG_debug_code) { |
1605 __ TestIfSmi(regexp_data, r0); | 1594 __ TestIfSmi(regexp_data); |
1606 __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected, cr0); | 1595 __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected, cr0); |
1607 __ CompareObjectType(regexp_data, r3, r3, FIXED_ARRAY_TYPE); | 1596 __ CompareObjectType(regexp_data, r2, r2, FIXED_ARRAY_TYPE); |
1608 __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected); | 1597 __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected); |
1609 } | 1598 } |
1610 | 1599 |
1611 // regexp_data: RegExp data (FixedArray) | 1600 // regexp_data: RegExp data (FixedArray) |
1612 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | 1601 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
1613 __ LoadP(r3, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); | 1602 __ LoadP(r2, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); |
1614 // DCHECK(Smi::FromInt(JSRegExp::IRREGEXP) < (char *)0xffffu); | 1603 // DCHECK(Smi::FromInt(JSRegExp::IRREGEXP) < (char *)0xffffu); |
1615 __ CmpSmiLiteral(r3, Smi::FromInt(JSRegExp::IRREGEXP), r0); | 1604 __ CmpSmiLiteral(r2, Smi::FromInt(JSRegExp::IRREGEXP), r0); |
1616 __ bne(&runtime); | 1605 __ bne(&runtime); |
1617 | 1606 |
1618 // regexp_data: RegExp data (FixedArray) | 1607 // regexp_data: RegExp data (FixedArray) |
1619 // Check that the number of captures fit in the static offsets vector buffer. | 1608 // Check that the number of captures fit in the static offsets vector buffer. |
1620 __ LoadP(r5, | 1609 __ LoadP(r4, |
1621 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | 1610 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); |
1622 // Check (number_of_captures + 1) * 2 <= offsets vector size | 1611 // Check (number_of_captures + 1) * 2 <= offsets vector size |
1623 // Or number_of_captures * 2 <= offsets vector size - 2 | 1612 // Or number_of_captures * 2 <= offsets vector size - 2 |
1624 // SmiToShortArrayOffset accomplishes the multiplication by 2 and | 1613 // SmiToShortArrayOffset accomplishes the multiplication by 2 and |
1625 // SmiUntag (which is a nop for 32-bit). | 1614 // SmiUntag (which is a nop for 32-bit). |
1626 __ SmiToShortArrayOffset(r5, r5); | 1615 __ SmiToShortArrayOffset(r4, r4); |
1627 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); | 1616 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); |
1628 __ cmpli(r5, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize - 2)); | 1617 __ CmpLogicalP(r4, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize - 2)); |
1629 __ bgt(&runtime); | 1618 __ bgt(&runtime); |
1630 | 1619 |
1631 // Reset offset for possibly sliced string. | 1620 // Reset offset for possibly sliced string. |
1632 __ li(r11, Operand::Zero()); | 1621 __ LoadImmP(ip, Operand::Zero()); |
1633 __ LoadP(subject, MemOperand(sp, kSubjectOffset)); | 1622 __ LoadP(subject, MemOperand(sp, kSubjectOffset)); |
1634 __ JumpIfSmi(subject, &runtime); | 1623 __ JumpIfSmi(subject, &runtime); |
1635 __ mr(r6, subject); // Make a copy of the original subject string. | 1624 __ LoadRR(r5, subject); // Make a copy of the original subject string. |
1636 __ LoadP(r3, FieldMemOperand(subject, HeapObject::kMapOffset)); | 1625 __ LoadP(r2, FieldMemOperand(subject, HeapObject::kMapOffset)); |
1637 __ lbz(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); | 1626 __ LoadlB(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
1638 // subject: subject string | 1627 // subject: subject string |
1639 // r6: subject string | 1628 // r5: subject string |
1640 // r3: subject string instance type | 1629 // r2: subject string instance type |
1641 // regexp_data: RegExp data (FixedArray) | 1630 // regexp_data: RegExp data (FixedArray) |
1642 // Handle subject string according to its encoding and representation: | 1631 // Handle subject string according to its encoding and representation: |
1643 // (1) Sequential string? If yes, go to (5). | 1632 // (1) Sequential string? If yes, go to (5). |
1644 // (2) Anything but sequential or cons? If yes, go to (6). | 1633 // (2) Anything but sequential or cons? If yes, go to (6). |
1645 // (3) Cons string. If the string is flat, replace subject with first string. | 1634 // (3) Cons string. If the string is flat, replace subject with first string. |
1646 // Otherwise bailout. | 1635 // Otherwise bailout. |
1647 // (4) Is subject external? If yes, go to (7). | 1636 // (4) Is subject external? If yes, go to (7). |
1648 // (5) Sequential string. Load regexp code according to encoding. | 1637 // (5) Sequential string. Load regexp code according to encoding. |
1649 // (E) Carry on. | 1638 // (E) Carry on. |
1650 /// [...] | 1639 /// [...] |
1651 | 1640 |
1652 // Deferred code at the end of the stub: | 1641 // Deferred code at the end of the stub: |
1653 // (6) Not a long external string? If yes, go to (8). | 1642 // (6) Not a long external string? If yes, go to (8). |
1654 // (7) External string. Make it, offset-wise, look like a sequential string. | 1643 // (7) External string. Make it, offset-wise, look like a sequential string. |
1655 // Go to (5). | 1644 // Go to (5). |
1656 // (8) Short external string or not a string? If yes, bail out to runtime. | 1645 // (8) Short external string or not a string? If yes, bail out to runtime. |
1657 // (9) Sliced string. Replace subject with parent. Go to (4). | 1646 // (9) Sliced string. Replace subject with parent. Go to (4). |
1658 | 1647 |
1659 Label seq_string /* 5 */, external_string /* 7 */, check_underlying /* 4 */, | 1648 Label seq_string /* 5 */, external_string /* 7 */, check_underlying /* 4 */, |
1660 not_seq_nor_cons /* 6 */, not_long_external /* 8 */; | 1649 not_seq_nor_cons /* 6 */, not_long_external /* 8 */; |
1661 | 1650 |
1662 // (1) Sequential string? If yes, go to (5). | 1651 // (1) Sequential string? If yes, go to (5). |
1663 STATIC_ASSERT((kIsNotStringMask | kStringRepresentationMask | | 1652 STATIC_ASSERT((kIsNotStringMask | kStringRepresentationMask | |
1664 kShortExternalStringMask) == 0x93); | 1653 kShortExternalStringMask) == 0x93); |
1665 __ andi(r4, r3, Operand(kIsNotStringMask | kStringRepresentationMask | | 1654 __ mov(r3, Operand(kIsNotStringMask | kStringRepresentationMask | |
1666 kShortExternalStringMask)); | 1655 kShortExternalStringMask)); |
| 1656 __ AndP(r3, r2); |
1667 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); | 1657 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); |
1668 __ beq(&seq_string, cr0); // Go to (5). | 1658 __ beq(&seq_string); // Go to (5). |
1669 | 1659 |
1670 // (2) Anything but sequential or cons? If yes, go to (6). | 1660 // (2) Anything but sequential or cons? If yes, go to (6). |
1671 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | 1661 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
1672 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | 1662 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |
1673 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); | 1663 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); |
1674 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); | 1664 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); |
1675 STATIC_ASSERT(kExternalStringTag < 0xffffu); | 1665 STATIC_ASSERT(kExternalStringTag < 0xffffu); |
1676 __ cmpi(r4, Operand(kExternalStringTag)); | 1666 __ CmpP(r3, Operand(kExternalStringTag)); |
1677 __ bge(¬_seq_nor_cons); // Go to (6). | 1667 __ bge(¬_seq_nor_cons); // Go to (6). |
1678 | 1668 |
1679 // (3) Cons string. Check that it's flat. | 1669 // (3) Cons string. Check that it's flat. |
1680 // Replace subject with first string and reload instance type. | 1670 // Replace subject with first string and reload instance type. |
1681 __ LoadP(r3, FieldMemOperand(subject, ConsString::kSecondOffset)); | 1671 __ LoadP(r2, FieldMemOperand(subject, ConsString::kSecondOffset)); |
1682 __ CompareRoot(r3, Heap::kempty_stringRootIndex); | 1672 __ CompareRoot(r2, Heap::kempty_stringRootIndex); |
1683 __ bne(&runtime); | 1673 __ bne(&runtime); |
1684 __ LoadP(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); | 1674 __ LoadP(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); |
1685 | 1675 |
1686 // (4) Is subject external? If yes, go to (7). | 1676 // (4) Is subject external? If yes, go to (7). |
1687 __ bind(&check_underlying); | 1677 __ bind(&check_underlying); |
1688 __ LoadP(r3, FieldMemOperand(subject, HeapObject::kMapOffset)); | 1678 __ LoadP(r2, FieldMemOperand(subject, HeapObject::kMapOffset)); |
1689 __ lbz(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); | 1679 __ LoadlB(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
1690 STATIC_ASSERT(kSeqStringTag == 0); | 1680 STATIC_ASSERT(kSeqStringTag == 0); |
1691 STATIC_ASSERT(kStringRepresentationMask == 3); | 1681 STATIC_ASSERT(kStringRepresentationMask == 3); |
1692 __ andi(r0, r3, Operand(kStringRepresentationMask)); | 1682 __ tmll(r2, Operand(kStringRepresentationMask)); |
1693 // The underlying external string is never a short external string. | 1683 // The underlying external string is never a short external string. |
1694 STATIC_ASSERT(ExternalString::kMaxShortLength < ConsString::kMinLength); | 1684 STATIC_ASSERT(ExternalString::kMaxShortLength < ConsString::kMinLength); |
1695 STATIC_ASSERT(ExternalString::kMaxShortLength < SlicedString::kMinLength); | 1685 STATIC_ASSERT(ExternalString::kMaxShortLength < SlicedString::kMinLength); |
1696 __ bne(&external_string, cr0); // Go to (7). | 1686 __ bne(&external_string); // Go to (7). |
1697 | 1687 |
1698 // (5) Sequential string. Load regexp code according to encoding. | 1688 // (5) Sequential string. Load regexp code according to encoding. |
1699 __ bind(&seq_string); | 1689 __ bind(&seq_string); |
1700 // subject: sequential subject string (or look-alike, external string) | 1690 // subject: sequential subject string (or look-alike, external string) |
1701 // r6: original subject string | 1691 // r5: original subject string |
1702 // Load previous index and check range before r6 is overwritten. We have to | 1692 // Load previous index and check range before r5 is overwritten. We have to |
1703 // use r6 instead of subject here because subject might have been only made | 1693 // use r5 instead of subject here because subject might have been only made |
1704 // to look like a sequential string when it actually is an external string. | 1694 // to look like a sequential string when it actually is an external string. |
1705 __ LoadP(r4, MemOperand(sp, kPreviousIndexOffset)); | 1695 __ LoadP(r3, MemOperand(sp, kPreviousIndexOffset)); |
1706 __ JumpIfNotSmi(r4, &runtime); | 1696 __ JumpIfNotSmi(r3, &runtime); |
1707 __ LoadP(r6, FieldMemOperand(r6, String::kLengthOffset)); | 1697 __ LoadP(r5, FieldMemOperand(r5, String::kLengthOffset)); |
1708 __ cmpl(r6, r4); | 1698 __ CmpLogicalP(r5, r3); |
1709 __ ble(&runtime); | 1699 __ ble(&runtime); |
1710 __ SmiUntag(r4); | 1700 __ SmiUntag(r3); |
1711 | 1701 |
1712 STATIC_ASSERT(4 == kOneByteStringTag); | 1702 STATIC_ASSERT(4 == kOneByteStringTag); |
1713 STATIC_ASSERT(kTwoByteStringTag == 0); | 1703 STATIC_ASSERT(kTwoByteStringTag == 0); |
1714 STATIC_ASSERT(kStringEncodingMask == 4); | 1704 STATIC_ASSERT(kStringEncodingMask == 4); |
1715 __ ExtractBitMask(r6, r3, kStringEncodingMask, SetRC); | 1705 __ ExtractBitMask(r5, r2, kStringEncodingMask, SetRC); |
1716 __ beq(&encoding_type_UC16, cr0); | 1706 __ beq(&encoding_type_UC16, Label::kNear); |
1717 __ LoadP(code, | 1707 __ LoadP(code, |
1718 FieldMemOperand(regexp_data, JSRegExp::kDataOneByteCodeOffset)); | 1708 FieldMemOperand(regexp_data, JSRegExp::kDataOneByteCodeOffset)); |
1719 __ b(&br_over); | 1709 __ b(&br_over, Label::kNear); |
1720 __ bind(&encoding_type_UC16); | 1710 __ bind(&encoding_type_UC16); |
1721 __ LoadP(code, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset)); | 1711 __ LoadP(code, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset)); |
1722 __ bind(&br_over); | 1712 __ bind(&br_over); |
1723 | 1713 |
1724 // (E) Carry on. String handling is done. | 1714 // (E) Carry on. String handling is done. |
1725 // code: irregexp code | 1715 // code: irregexp code |
1726 // Check that the irregexp code has been generated for the actual string | 1716 // Check that the irregexp code has been generated for the actual string |
1727 // encoding. If it has, the field contains a code object otherwise it contains | 1717 // encoding. If it has, the field contains a code object otherwise it contains |
1728 // a smi (code flushing support). | 1718 // a smi (code flushing support). |
1729 __ JumpIfSmi(code, &runtime); | 1719 __ JumpIfSmi(code, &runtime); |
1730 | 1720 |
1731 // r4: previous index | 1721 // r3: previous index |
1732 // r6: encoding of subject string (1 if one_byte, 0 if two_byte); | 1722 // r5: encoding of subject string (1 if one_byte, 0 if two_byte); |
1733 // code: Address of generated regexp code | 1723 // code: Address of generated regexp code |
1734 // subject: Subject string | 1724 // subject: Subject string |
1735 // regexp_data: RegExp data (FixedArray) | 1725 // regexp_data: RegExp data (FixedArray) |
1736 // All checks done. Now push arguments for native regexp code. | 1726 // All checks done. Now push arguments for native regexp code. |
1737 __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1, r3, r5); | 1727 __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1, r2, r4); |
1738 | 1728 |
1739 // Isolates: note we add an additional parameter here (isolate pointer). | 1729 // Isolates: note we add an additional parameter here (isolate pointer). |
1740 const int kRegExpExecuteArguments = 10; | 1730 const int kRegExpExecuteArguments = 10; |
1741 const int kParameterRegisters = 8; | 1731 const int kParameterRegisters = 5; |
1742 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); | 1732 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); |
1743 | 1733 |
1744 // Stack pointer now points to cell where return address is to be written. | 1734 // Stack pointer now points to cell where return address is to be written. |
1745 // Arguments are before that on the stack or in registers. | 1735 // Arguments are before that on the stack or in registers. |
1746 | 1736 |
1747 // Argument 10 (in stack parameter area): Pass current isolate address. | 1737 // Argument 10 (in stack parameter area): Pass current isolate address. |
1748 __ mov(r3, Operand(ExternalReference::isolate_address(isolate()))); | 1738 __ mov(r2, Operand(ExternalReference::isolate_address(isolate()))); |
1749 __ StoreP(r3, MemOperand(sp, (kStackFrameExtraParamSlot + 1) * kPointerSize)); | 1739 __ StoreP(r2, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize + |
| 1740 4 * kPointerSize)); |
1750 | 1741 |
1751 // Argument 9 is a dummy that reserves the space used for | 1742 // Argument 9 is a dummy that reserves the space used for |
1752 // the return address added by the ExitFrame in native calls. | 1743 // the return address added by the ExitFrame in native calls. |
| 1744 __ mov(r2, Operand::Zero()); |
| 1745 __ StoreP(r2, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize + |
| 1746 3 * kPointerSize)); |
1753 | 1747 |
1754 // Argument 8 (r10): Indicate that this is a direct call from JavaScript. | 1748 // Argument 8: Indicate that this is a direct call from JavaScript. |
1755 __ li(r10, Operand(1)); | 1749 __ mov(r2, Operand(1)); |
| 1750 __ StoreP(r2, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize + |
| 1751 2 * kPointerSize)); |
1756 | 1752 |
1757 // Argument 7 (r9): Start (high end) of backtracking stack memory area. | 1753 // Argument 7: Start (high end) of backtracking stack memory area. |
1758 __ mov(r3, Operand(address_of_regexp_stack_memory_address)); | 1754 __ mov(r2, Operand(address_of_regexp_stack_memory_address)); |
1759 __ LoadP(r3, MemOperand(r3, 0)); | 1755 __ LoadP(r2, MemOperand(r2, 0)); |
1760 __ mov(r5, Operand(address_of_regexp_stack_memory_size)); | 1756 __ mov(r1, Operand(address_of_regexp_stack_memory_size)); |
1761 __ LoadP(r5, MemOperand(r5, 0)); | 1757 __ LoadP(r1, MemOperand(r1, 0)); |
1762 __ add(r9, r3, r5); | 1758 __ AddP(r2, r1); |
| 1759 __ StoreP(r2, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize + |
| 1760 1 * kPointerSize)); |
1763 | 1761 |
1764 // Argument 6 (r8): Set the number of capture registers to zero to force | 1762 // Argument 6: Set the number of capture registers to zero to force |
1765 // global egexps to behave as non-global. This does not affect non-global | 1763 // global egexps to behave as non-global. This does not affect non-global |
1766 // regexps. | 1764 // regexps. |
1767 __ li(r8, Operand::Zero()); | 1765 __ mov(r2, Operand::Zero()); |
| 1766 __ StoreP(r2, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize + |
| 1767 0 * kPointerSize)); |
1768 | 1768 |
1769 // Argument 5 (r7): static offsets vector buffer. | 1769 // Argument 1 (r2): Subject string. |
| 1770 // Load the length from the original subject string from the previous stack |
| 1771 // frame. Therefore we have to use fp, which points exactly to 15 pointer |
| 1772 // sizes below the previous sp. (Because creating a new stack frame pushes |
| 1773 // the previous fp onto the stack and moves up sp by 2 * kPointerSize and |
| 1774 // 13 registers saved on the stack previously) |
| 1775 __ LoadP(r2, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); |
| 1776 |
| 1777 // Argument 2 (r3): Previous index. |
| 1778 // Already there |
| 1779 __ AddP(r1, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag)); |
| 1780 |
| 1781 // Argument 5 (r6): static offsets vector buffer. |
1770 __ mov( | 1782 __ mov( |
1771 r7, | 1783 r6, |
1772 Operand(ExternalReference::address_of_static_offsets_vector(isolate()))); | 1784 Operand(ExternalReference::address_of_static_offsets_vector(isolate()))); |
1773 | 1785 |
1774 // For arguments 4 (r6) and 3 (r5) get string length, calculate start of data | 1786 // For arguments 4 (r5) and 3 (r4) get string length, calculate start of data |
1775 // and calculate the shift of the index (0 for one-byte and 1 for two-byte). | 1787 // and calculate the shift of the index (0 for one-byte and 1 for two byte). |
1776 __ addi(r18, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag)); | 1788 __ XorP(r5, Operand(1)); |
1777 __ xori(r6, r6, Operand(1)); | |
1778 // Load the length from the original subject string from the previous stack | |
1779 // frame. Therefore we have to use fp, which points exactly to two pointer | |
1780 // sizes below the previous sp. (Because creating a new stack frame pushes | |
1781 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) | |
1782 __ LoadP(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); | |
1783 // If slice offset is not 0, load the length from the original sliced string. | 1789 // If slice offset is not 0, load the length from the original sliced string. |
1784 // Argument 4, r6: End of string data | 1790 // Argument 3, r4: Start of string data |
1785 // Argument 3, r5: Start of string data | |
1786 // Prepare start and end index of the input. | 1791 // Prepare start and end index of the input. |
1787 __ ShiftLeft_(r11, r11, r6); | 1792 __ ShiftLeftP(ip, ip, r5); |
1788 __ add(r11, r18, r11); | 1793 __ AddP(ip, r1, ip); |
1789 __ ShiftLeft_(r5, r4, r6); | 1794 __ ShiftLeftP(r4, r3, r5); |
1790 __ add(r5, r11, r5); | 1795 __ AddP(r4, ip, r4); |
1791 | 1796 |
1792 __ LoadP(r18, FieldMemOperand(subject, String::kLengthOffset)); | 1797 // Argument 4, r5: End of string data |
1793 __ SmiUntag(r18); | 1798 __ LoadP(r1, FieldMemOperand(r2, String::kLengthOffset)); |
1794 __ ShiftLeft_(r6, r18, r6); | 1799 __ SmiUntag(r1); |
1795 __ add(r6, r11, r6); | 1800 __ ShiftLeftP(r0, r1, r5); |
1796 | 1801 __ AddP(r5, ip, r0); |
1797 // Argument 2 (r4): Previous index. | |
1798 // Already there | |
1799 | |
1800 // Argument 1 (r3): Subject string. | |
1801 __ mr(r3, subject); | |
1802 | 1802 |
1803 // Locate the code entry and call it. | 1803 // Locate the code entry and call it. |
1804 __ addi(code, code, Operand(Code::kHeaderSize - kHeapObjectTag)); | 1804 __ AddP(code, Operand(Code::kHeaderSize - kHeapObjectTag)); |
1805 | 1805 |
1806 DirectCEntryStub stub(isolate()); | 1806 DirectCEntryStub stub(isolate()); |
1807 stub.GenerateCall(masm, code); | 1807 stub.GenerateCall(masm, code); |
1808 | 1808 |
1809 __ LeaveExitFrame(false, no_reg, true); | 1809 __ LeaveExitFrame(false, no_reg, true); |
1810 | 1810 |
1811 // r3: result (int32) | 1811 // r2: result (int32) |
1812 // subject: subject string (callee saved) | 1812 // subject: subject string -- needed to reload |
| 1813 __ LoadP(subject, MemOperand(sp, kSubjectOffset)); |
| 1814 |
1813 // regexp_data: RegExp data (callee saved) | 1815 // regexp_data: RegExp data (callee saved) |
1814 // last_match_info_elements: Last match info elements (callee saved) | 1816 // last_match_info_elements: Last match info elements (callee saved) |
1815 // Check the result. | 1817 // Check the result. |
1816 Label success; | 1818 Label success; |
1817 __ cmpwi(r3, Operand(1)); | 1819 __ Cmp32(r2, Operand(1)); |
1818 // We expect exactly one result since we force the called regexp to behave | 1820 // We expect exactly one result since we force the called regexp to behave |
1819 // as non-global. | 1821 // as non-global. |
1820 __ beq(&success); | 1822 __ beq(&success); |
1821 Label failure; | 1823 Label failure; |
1822 __ cmpwi(r3, Operand(NativeRegExpMacroAssembler::FAILURE)); | 1824 __ Cmp32(r2, Operand(NativeRegExpMacroAssembler::FAILURE)); |
1823 __ beq(&failure); | 1825 __ beq(&failure); |
1824 __ cmpwi(r3, Operand(NativeRegExpMacroAssembler::EXCEPTION)); | 1826 __ Cmp32(r2, Operand(NativeRegExpMacroAssembler::EXCEPTION)); |
1825 // If not exception it can only be retry. Handle that in the runtime system. | 1827 // If not exception it can only be retry. Handle that in the runtime system. |
1826 __ bne(&runtime); | 1828 __ bne(&runtime); |
1827 // Result must now be exception. If there is no pending exception already a | 1829 // Result must now be exception. If there is no pending exception already a |
1828 // stack overflow (on the backtrack stack) was detected in RegExp code but | 1830 // stack overflow (on the backtrack stack) was detected in RegExp code but |
1829 // haven't created the exception yet. Handle that in the runtime system. | 1831 // haven't created the exception yet. Handle that in the runtime system. |
1830 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | 1832 // TODO(592): Rerunning the RegExp to get the stack overflow exception. |
1831 __ mov(r4, Operand(isolate()->factory()->the_hole_value())); | 1833 __ mov(r3, Operand(isolate()->factory()->the_hole_value())); |
1832 __ mov(r5, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | 1834 __ mov(r4, Operand(ExternalReference(Isolate::kPendingExceptionAddress, |
1833 isolate()))); | 1835 isolate()))); |
1834 __ LoadP(r3, MemOperand(r5, 0)); | 1836 __ LoadP(r2, MemOperand(r4, 0)); |
1835 __ cmp(r3, r4); | 1837 __ CmpP(r2, r3); |
1836 __ beq(&runtime); | 1838 __ beq(&runtime); |
1837 | 1839 |
1838 // For exception, throw the exception again. | 1840 // For exception, throw the exception again. |
1839 __ TailCallRuntime(Runtime::kRegExpExecReThrow); | 1841 __ TailCallRuntime(Runtime::kRegExpExecReThrow); |
1840 | 1842 |
1841 __ bind(&failure); | 1843 __ bind(&failure); |
1842 // For failure and exception return null. | 1844 // For failure and exception return null. |
1843 __ mov(r3, Operand(isolate()->factory()->null_value())); | 1845 __ mov(r2, Operand(isolate()->factory()->null_value())); |
1844 __ addi(sp, sp, Operand(4 * kPointerSize)); | 1846 __ la(sp, MemOperand(sp, (4 * kPointerSize))); |
1845 __ Ret(); | 1847 __ Ret(); |
1846 | 1848 |
1847 // Process the result from the native regexp code. | 1849 // Process the result from the native regexp code. |
1848 __ bind(&success); | 1850 __ bind(&success); |
1849 __ LoadP(r4, | 1851 __ LoadP(r3, |
1850 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | 1852 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); |
1851 // Calculate number of capture registers (number_of_captures + 1) * 2. | 1853 // Calculate number of capture registers (number_of_captures + 1) * 2. |
1852 // SmiToShortArrayOffset accomplishes the multiplication by 2 and | 1854 // SmiToShortArrayOffset accomplishes the multiplication by 2 and |
1853 // SmiUntag (which is a nop for 32-bit). | 1855 // SmiUntag (which is a nop for 32-bit). |
1854 __ SmiToShortArrayOffset(r4, r4); | 1856 __ SmiToShortArrayOffset(r3, r3); |
1855 __ addi(r4, r4, Operand(2)); | 1857 __ AddP(r3, Operand(2)); |
1856 | 1858 |
1857 __ LoadP(r3, MemOperand(sp, kLastMatchInfoOffset)); | 1859 __ LoadP(r2, MemOperand(sp, kLastMatchInfoOffset)); |
1858 __ JumpIfSmi(r3, &runtime); | 1860 __ JumpIfSmi(r2, &runtime); |
1859 __ CompareObjectType(r3, r5, r5, JS_ARRAY_TYPE); | 1861 __ CompareObjectType(r2, r4, r4, JS_ARRAY_TYPE); |
1860 __ bne(&runtime); | 1862 __ bne(&runtime); |
1861 // Check that the JSArray is in fast case. | 1863 // Check that the JSArray is in fast case. |
1862 __ LoadP(last_match_info_elements, | 1864 __ LoadP(last_match_info_elements, |
1863 FieldMemOperand(r3, JSArray::kElementsOffset)); | 1865 FieldMemOperand(r2, JSArray::kElementsOffset)); |
1864 __ LoadP(r3, | 1866 __ LoadP(r2, |
1865 FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); | 1867 FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); |
1866 __ CompareRoot(r3, Heap::kFixedArrayMapRootIndex); | 1868 __ CompareRoot(r2, Heap::kFixedArrayMapRootIndex); |
1867 __ bne(&runtime); | 1869 __ bne(&runtime); |
1868 // Check that the last match info has space for the capture registers and the | 1870 // Check that the last match info has space for the capture registers and the |
1869 // additional information. | 1871 // additional information. |
1870 __ LoadP( | 1872 __ LoadP( |
1871 r3, FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); | 1873 r2, FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); |
1872 __ addi(r5, r4, Operand(RegExpImpl::kLastMatchOverhead)); | 1874 __ AddP(r4, r3, Operand(RegExpImpl::kLastMatchOverhead)); |
1873 __ SmiUntag(r0, r3); | 1875 __ SmiUntag(r0, r2); |
1874 __ cmp(r5, r0); | 1876 __ CmpP(r4, r0); |
1875 __ bgt(&runtime); | 1877 __ bgt(&runtime); |
1876 | 1878 |
1877 // r4: number of capture registers | 1879 // r3: number of capture registers |
1878 // subject: subject string | 1880 // subject: subject string |
1879 // Store the capture count. | 1881 // Store the capture count. |
1880 __ SmiTag(r5, r4); | 1882 __ SmiTag(r4, r3); |
1881 __ StoreP(r5, FieldMemOperand(last_match_info_elements, | 1883 __ StoreP(r4, FieldMemOperand(last_match_info_elements, |
1882 RegExpImpl::kLastCaptureCountOffset), | 1884 RegExpImpl::kLastCaptureCountOffset)); |
1883 r0); | |
1884 // Store last subject and last input. | 1885 // Store last subject and last input. |
1885 __ StoreP(subject, FieldMemOperand(last_match_info_elements, | 1886 __ StoreP(subject, FieldMemOperand(last_match_info_elements, |
1886 RegExpImpl::kLastSubjectOffset), | 1887 RegExpImpl::kLastSubjectOffset)); |
1887 r0); | 1888 __ LoadRR(r4, subject); |
1888 __ mr(r5, subject); | |
1889 __ RecordWriteField(last_match_info_elements, RegExpImpl::kLastSubjectOffset, | 1889 __ RecordWriteField(last_match_info_elements, RegExpImpl::kLastSubjectOffset, |
1890 subject, r10, kLRHasNotBeenSaved, kDontSaveFPRegs); | 1890 subject, r9, kLRHasNotBeenSaved, kDontSaveFPRegs); |
1891 __ mr(subject, r5); | 1891 __ LoadRR(subject, r4); |
1892 __ StoreP(subject, FieldMemOperand(last_match_info_elements, | 1892 __ StoreP(subject, FieldMemOperand(last_match_info_elements, |
1893 RegExpImpl::kLastInputOffset), | 1893 RegExpImpl::kLastInputOffset)); |
1894 r0); | |
1895 __ RecordWriteField(last_match_info_elements, RegExpImpl::kLastInputOffset, | 1894 __ RecordWriteField(last_match_info_elements, RegExpImpl::kLastInputOffset, |
1896 subject, r10, kLRHasNotBeenSaved, kDontSaveFPRegs); | 1895 subject, r9, kLRHasNotBeenSaved, kDontSaveFPRegs); |
1897 | 1896 |
1898 // Get the static offsets vector filled by the native regexp code. | 1897 // Get the static offsets vector filled by the native regexp code. |
1899 ExternalReference address_of_static_offsets_vector = | 1898 ExternalReference address_of_static_offsets_vector = |
1900 ExternalReference::address_of_static_offsets_vector(isolate()); | 1899 ExternalReference::address_of_static_offsets_vector(isolate()); |
1901 __ mov(r5, Operand(address_of_static_offsets_vector)); | 1900 __ mov(r4, Operand(address_of_static_offsets_vector)); |
1902 | 1901 |
1903 // r4: number of capture registers | 1902 // r3: number of capture registers |
1904 // r5: offsets vector | 1903 // r4: offsets vector |
1905 Label next_capture; | 1904 Label next_capture; |
1906 // Capture register counter starts from number of capture registers and | 1905 // Capture register counter starts from number of capture registers and |
1907 // counts down until wraping after zero. | 1906 // counts down until wraping after zero. |
1908 __ addi( | 1907 __ AddP( |
1909 r3, last_match_info_elements, | 1908 r2, last_match_info_elements, |
1910 Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag - kPointerSize)); | 1909 Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag - kPointerSize)); |
1911 __ addi(r5, r5, Operand(-kIntSize)); // bias down for lwzu | 1910 __ AddP(r4, Operand(-kIntSize)); // bias down for lwzu |
1912 __ mtctr(r4); | |
1913 __ bind(&next_capture); | 1911 __ bind(&next_capture); |
1914 // Read the value from the static offsets vector buffer. | 1912 // Read the value from the static offsets vector buffer. |
1915 __ lwzu(r6, MemOperand(r5, kIntSize)); | 1913 __ ly(r5, MemOperand(r4, kIntSize)); |
| 1914 __ lay(r4, MemOperand(r4, kIntSize)); |
1916 // Store the smi value in the last match info. | 1915 // Store the smi value in the last match info. |
1917 __ SmiTag(r6); | 1916 __ SmiTag(r5); |
1918 __ StorePU(r6, MemOperand(r3, kPointerSize)); | 1917 __ StoreP(r5, MemOperand(r2, kPointerSize)); |
1919 __ bdnz(&next_capture); | 1918 __ lay(r2, MemOperand(r2, kPointerSize)); |
| 1919 __ BranchOnCount(r3, &next_capture); |
1920 | 1920 |
1921 // Return last match info. | 1921 // Return last match info. |
1922 __ LoadP(r3, MemOperand(sp, kLastMatchInfoOffset)); | 1922 __ LoadP(r2, MemOperand(sp, kLastMatchInfoOffset)); |
1923 __ addi(sp, sp, Operand(4 * kPointerSize)); | 1923 __ la(sp, MemOperand(sp, (4 * kPointerSize))); |
1924 __ Ret(); | 1924 __ Ret(); |
1925 | 1925 |
1926 // Do the runtime call to execute the regexp. | 1926 // Do the runtime call to execute the regexp. |
1927 __ bind(&runtime); | 1927 __ bind(&runtime); |
1928 __ TailCallRuntime(Runtime::kRegExpExec); | 1928 __ TailCallRuntime(Runtime::kRegExpExec); |
1929 | 1929 |
1930 // Deferred code for string handling. | 1930 // Deferred code for string handling. |
1931 // (6) Not a long external string? If yes, go to (8). | 1931 // (6) Not a long external string? If yes, go to (8). |
1932 __ bind(¬_seq_nor_cons); | 1932 __ bind(¬_seq_nor_cons); |
1933 // Compare flags are still set. | 1933 // Compare flags are still set. |
1934 __ bgt(¬_long_external); // Go to (8). | 1934 __ bgt(¬_long_external); // Go to (8). |
1935 | 1935 |
1936 // (7) External string. Make it, offset-wise, look like a sequential string. | 1936 // (7) External string. Make it, offset-wise, look like a sequential string. |
1937 __ bind(&external_string); | 1937 __ bind(&external_string); |
1938 __ LoadP(r3, FieldMemOperand(subject, HeapObject::kMapOffset)); | 1938 __ LoadP(r2, FieldMemOperand(subject, HeapObject::kMapOffset)); |
1939 __ lbz(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); | 1939 __ LoadlB(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
1940 if (FLAG_debug_code) { | 1940 if (FLAG_debug_code) { |
1941 // Assert that we do not have a cons or slice (indirect strings) here. | 1941 // Assert that we do not have a cons or slice (indirect strings) here. |
1942 // Sequential strings have already been ruled out. | 1942 // Sequential strings have already been ruled out. |
1943 STATIC_ASSERT(kIsIndirectStringMask == 1); | 1943 STATIC_ASSERT(kIsIndirectStringMask == 1); |
1944 __ andi(r0, r3, Operand(kIsIndirectStringMask)); | 1944 __ tmll(r2, Operand(kIsIndirectStringMask)); |
1945 __ Assert(eq, kExternalStringExpectedButNotFound, cr0); | 1945 __ Assert(eq, kExternalStringExpectedButNotFound, cr0); |
1946 } | 1946 } |
1947 __ LoadP(subject, | 1947 __ LoadP(subject, |
1948 FieldMemOperand(subject, ExternalString::kResourceDataOffset)); | 1948 FieldMemOperand(subject, ExternalString::kResourceDataOffset)); |
1949 // Move the pointer so that offset-wise, it looks like a sequential string. | 1949 // Move the pointer so that offset-wise, it looks like a sequential string. |
1950 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 1950 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
1951 __ subi(subject, subject, | 1951 __ SubP(subject, subject, |
1952 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 1952 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
1953 __ b(&seq_string); // Go to (5). | 1953 __ b(&seq_string); // Go to (5). |
1954 | 1954 |
1955 // (8) Short external string or not a string? If yes, bail out to runtime. | 1955 // (8) Short external string or not a string? If yes, bail out to runtime. |
1956 __ bind(¬_long_external); | 1956 __ bind(¬_long_external); |
1957 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag != 0); | 1957 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag != 0); |
1958 __ andi(r0, r4, Operand(kIsNotStringMask | kShortExternalStringMask)); | 1958 __ mov(r0, Operand(kIsNotStringMask | kShortExternalStringMask)); |
1959 __ bne(&runtime, cr0); | 1959 __ AndP(r0, r3); |
| 1960 __ bne(&runtime); |
1960 | 1961 |
1961 // (9) Sliced string. Replace subject with parent. Go to (4). | 1962 // (9) Sliced string. Replace subject with parent. Go to (4). |
1962 // Load offset into r11 and replace subject string with parent. | 1963 // Load offset into ip and replace subject string with parent. |
1963 __ LoadP(r11, FieldMemOperand(subject, SlicedString::kOffsetOffset)); | 1964 __ LoadP(ip, FieldMemOperand(subject, SlicedString::kOffsetOffset)); |
1964 __ SmiUntag(r11); | 1965 __ SmiUntag(ip); |
1965 __ LoadP(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); | 1966 __ LoadP(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); |
1966 __ b(&check_underlying); // Go to (4). | 1967 __ b(&check_underlying); // Go to (4). |
1967 #endif // V8_INTERPRETED_REGEXP | 1968 #endif // V8_INTERPRETED_REGEXP |
1968 } | 1969 } |
1969 | 1970 |
1970 | |
1971 static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) { | 1971 static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) { |
1972 // r3 : number of arguments to the construct function | 1972 // r2 : number of arguments to the construct function |
1973 // r4 : the function to call | 1973 // r3 : the function to call |
1974 // r5 : feedback vector | 1974 // r4 : feedback vector |
1975 // r6 : slot in feedback vector (Smi) | 1975 // r5 : slot in feedback vector (Smi) |
1976 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 1976 FrameScope scope(masm, StackFrame::INTERNAL); |
1977 | 1977 |
1978 // Number-of-arguments register must be smi-tagged to call out. | 1978 // Number-of-arguments register must be smi-tagged to call out. |
1979 __ SmiTag(r3); | 1979 __ SmiTag(r2); |
1980 __ Push(r6, r5, r4, r3); | 1980 __ Push(r5, r4, r3, r2); |
1981 | 1981 |
1982 __ CallStub(stub); | 1982 __ CallStub(stub); |
1983 | 1983 |
1984 __ Pop(r6, r5, r4, r3); | 1984 __ Pop(r5, r4, r3, r2); |
1985 __ SmiUntag(r3); | 1985 __ SmiUntag(r2); |
1986 } | 1986 } |
1987 | 1987 |
1988 | |
1989 static void GenerateRecordCallTarget(MacroAssembler* masm) { | 1988 static void GenerateRecordCallTarget(MacroAssembler* masm) { |
1990 // Cache the called function in a feedback vector slot. Cache states | 1989 // Cache the called function in a feedback vector slot. Cache states |
1991 // are uninitialized, monomorphic (indicated by a JSFunction), and | 1990 // are uninitialized, monomorphic (indicated by a JSFunction), and |
1992 // megamorphic. | 1991 // megamorphic. |
1993 // r3 : number of arguments to the construct function | 1992 // r2 : number of arguments to the construct function |
1994 // r4 : the function to call | 1993 // r3 : the function to call |
1995 // r5 : feedback vector | 1994 // r4 : feedback vector |
1996 // r6 : slot in feedback vector (Smi) | 1995 // r5 : slot in feedback vector (Smi) |
1997 Label initialize, done, miss, megamorphic, not_array_function; | 1996 Label initialize, done, miss, megamorphic, not_array_function; |
1998 | 1997 |
1999 DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()), | 1998 DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()), |
2000 masm->isolate()->heap()->megamorphic_symbol()); | 1999 masm->isolate()->heap()->megamorphic_symbol()); |
2001 DCHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(masm->isolate()), | 2000 DCHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(masm->isolate()), |
2002 masm->isolate()->heap()->uninitialized_symbol()); | 2001 masm->isolate()->heap()->uninitialized_symbol()); |
2003 | 2002 |
2004 // Load the cache state into r8. | 2003 // Load the cache state into r7. |
2005 __ SmiToPtrArrayOffset(r8, r6); | 2004 __ SmiToPtrArrayOffset(r7, r5); |
2006 __ add(r8, r5, r8); | 2005 __ AddP(r7, r4, r7); |
2007 __ LoadP(r8, FieldMemOperand(r8, FixedArray::kHeaderSize)); | 2006 __ LoadP(r7, FieldMemOperand(r7, FixedArray::kHeaderSize)); |
2008 | 2007 |
2009 // A monomorphic cache hit or an already megamorphic state: invoke the | 2008 // A monomorphic cache hit or an already megamorphic state: invoke the |
2010 // function without changing the state. | 2009 // function without changing the state. |
2011 // We don't know if r8 is a WeakCell or a Symbol, but it's harmless to read at | 2010 // We don't know if r7 is a WeakCell or a Symbol, but it's harmless to read at |
2012 // this position in a symbol (see static asserts in type-feedback-vector.h). | 2011 // this position in a symbol (see static asserts in type-feedback-vector.h). |
2013 Label check_allocation_site; | 2012 Label check_allocation_site; |
2014 Register feedback_map = r9; | 2013 Register feedback_map = r8; |
2015 Register weak_value = r10; | 2014 Register weak_value = r9; |
2016 __ LoadP(weak_value, FieldMemOperand(r8, WeakCell::kValueOffset)); | 2015 __ LoadP(weak_value, FieldMemOperand(r7, WeakCell::kValueOffset)); |
2017 __ cmp(r4, weak_value); | 2016 __ CmpP(r3, weak_value); |
2018 __ beq(&done); | 2017 __ beq(&done); |
2019 __ CompareRoot(r8, Heap::kmegamorphic_symbolRootIndex); | 2018 __ CompareRoot(r7, Heap::kmegamorphic_symbolRootIndex); |
2020 __ beq(&done); | 2019 __ beq(&done); |
2021 __ LoadP(feedback_map, FieldMemOperand(r8, HeapObject::kMapOffset)); | 2020 __ LoadP(feedback_map, FieldMemOperand(r7, HeapObject::kMapOffset)); |
2022 __ CompareRoot(feedback_map, Heap::kWeakCellMapRootIndex); | 2021 __ CompareRoot(feedback_map, Heap::kWeakCellMapRootIndex); |
2023 __ bne(&check_allocation_site); | 2022 __ bne(&check_allocation_site); |
2024 | 2023 |
2025 // If the weak cell is cleared, we have a new chance to become monomorphic. | 2024 // If the weak cell is cleared, we have a new chance to become monomorphic. |
2026 __ JumpIfSmi(weak_value, &initialize); | 2025 __ JumpIfSmi(weak_value, &initialize); |
2027 __ b(&megamorphic); | 2026 __ b(&megamorphic); |
2028 | 2027 |
2029 __ bind(&check_allocation_site); | 2028 __ bind(&check_allocation_site); |
2030 // If we came here, we need to see if we are the array function. | 2029 // If we came here, we need to see if we are the array function. |
2031 // If we didn't have a matching function, and we didn't find the megamorph | 2030 // If we didn't have a matching function, and we didn't find the megamorph |
2032 // sentinel, then we have in the slot either some other function or an | 2031 // sentinel, then we have in the slot either some other function or an |
2033 // AllocationSite. | 2032 // AllocationSite. |
2034 __ CompareRoot(feedback_map, Heap::kAllocationSiteMapRootIndex); | 2033 __ CompareRoot(feedback_map, Heap::kAllocationSiteMapRootIndex); |
2035 __ bne(&miss); | 2034 __ bne(&miss); |
2036 | 2035 |
2037 // Make sure the function is the Array() function | 2036 // Make sure the function is the Array() function |
2038 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r8); | 2037 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r7); |
2039 __ cmp(r4, r8); | 2038 __ CmpP(r3, r7); |
2040 __ bne(&megamorphic); | 2039 __ bne(&megamorphic); |
2041 __ b(&done); | 2040 __ b(&done); |
2042 | 2041 |
2043 __ bind(&miss); | 2042 __ bind(&miss); |
2044 | 2043 |
2045 // A monomorphic miss (i.e, here the cache is not uninitialized) goes | 2044 // A monomorphic miss (i.e, here the cache is not uninitialized) goes |
2046 // megamorphic. | 2045 // megamorphic. |
2047 __ CompareRoot(r8, Heap::kuninitialized_symbolRootIndex); | 2046 __ CompareRoot(r7, Heap::kuninitialized_symbolRootIndex); |
2048 __ beq(&initialize); | 2047 __ beq(&initialize); |
2049 // MegamorphicSentinel is an immortal immovable object (undefined) so no | 2048 // MegamorphicSentinel is an immortal immovable object (undefined) so no |
2050 // write-barrier is needed. | 2049 // write-barrier is needed. |
2051 __ bind(&megamorphic); | 2050 __ bind(&megamorphic); |
2052 __ SmiToPtrArrayOffset(r8, r6); | 2051 __ SmiToPtrArrayOffset(r7, r5); |
2053 __ add(r8, r5, r8); | 2052 __ AddP(r7, r4, r7); |
2054 __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex); | 2053 __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex); |
2055 __ StoreP(ip, FieldMemOperand(r8, FixedArray::kHeaderSize), r0); | 2054 __ StoreP(ip, FieldMemOperand(r7, FixedArray::kHeaderSize), r0); |
2056 __ jmp(&done); | 2055 __ jmp(&done); |
2057 | 2056 |
2058 // An uninitialized cache is patched with the function | 2057 // An uninitialized cache is patched with the function |
2059 __ bind(&initialize); | 2058 __ bind(&initialize); |
2060 | 2059 |
2061 // Make sure the function is the Array() function. | 2060 // Make sure the function is the Array() function. |
2062 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r8); | 2061 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r7); |
2063 __ cmp(r4, r8); | 2062 __ CmpP(r3, r7); |
2064 __ bne(¬_array_function); | 2063 __ bne(¬_array_function); |
2065 | 2064 |
2066 // The target function is the Array constructor, | 2065 // The target function is the Array constructor, |
2067 // Create an AllocationSite if we don't already have it, store it in the | 2066 // Create an AllocationSite if we don't already have it, store it in the |
2068 // slot. | 2067 // slot. |
2069 CreateAllocationSiteStub create_stub(masm->isolate()); | 2068 CreateAllocationSiteStub create_stub(masm->isolate()); |
2070 CallStubInRecordCallTarget(masm, &create_stub); | 2069 CallStubInRecordCallTarget(masm, &create_stub); |
2071 __ b(&done); | 2070 __ b(&done); |
2072 | 2071 |
2073 __ bind(¬_array_function); | 2072 __ bind(¬_array_function); |
2074 | 2073 |
2075 CreateWeakCellStub weak_cell_stub(masm->isolate()); | 2074 CreateWeakCellStub weak_cell_stub(masm->isolate()); |
2076 CallStubInRecordCallTarget(masm, &weak_cell_stub); | 2075 CallStubInRecordCallTarget(masm, &weak_cell_stub); |
2077 __ bind(&done); | 2076 __ bind(&done); |
2078 } | 2077 } |
2079 | 2078 |
2080 | |
2081 void CallConstructStub::Generate(MacroAssembler* masm) { | 2079 void CallConstructStub::Generate(MacroAssembler* masm) { |
2082 // r3 : number of arguments | 2080 // r2 : number of arguments |
2083 // r4 : the function to call | 2081 // r3 : the function to call |
2084 // r5 : feedback vector | 2082 // r4 : feedback vector |
2085 // r6 : slot in feedback vector (Smi, for RecordCallTarget) | 2083 // r5 : slot in feedback vector (Smi, for RecordCallTarget) |
2086 | 2084 |
2087 Label non_function; | 2085 Label non_function; |
2088 // Check that the function is not a smi. | 2086 // Check that the function is not a smi. |
2089 __ JumpIfSmi(r4, &non_function); | 2087 __ JumpIfSmi(r3, &non_function); |
2090 // Check that the function is a JSFunction. | 2088 // Check that the function is a JSFunction. |
2091 __ CompareObjectType(r4, r8, r8, JS_FUNCTION_TYPE); | 2089 __ CompareObjectType(r3, r7, r7, JS_FUNCTION_TYPE); |
2092 __ bne(&non_function); | 2090 __ bne(&non_function); |
2093 | 2091 |
2094 GenerateRecordCallTarget(masm); | 2092 GenerateRecordCallTarget(masm); |
2095 | 2093 |
2096 __ SmiToPtrArrayOffset(r8, r6); | 2094 __ SmiToPtrArrayOffset(r7, r5); |
2097 __ add(r8, r5, r8); | 2095 __ AddP(r7, r4, r7); |
2098 // Put the AllocationSite from the feedback vector into r5, or undefined. | 2096 // Put the AllocationSite from the feedback vector into r4, or undefined. |
2099 __ LoadP(r5, FieldMemOperand(r8, FixedArray::kHeaderSize)); | 2097 __ LoadP(r4, FieldMemOperand(r7, FixedArray::kHeaderSize)); |
2100 __ LoadP(r8, FieldMemOperand(r5, AllocationSite::kMapOffset)); | 2098 __ LoadP(r7, FieldMemOperand(r4, AllocationSite::kMapOffset)); |
2101 __ CompareRoot(r8, Heap::kAllocationSiteMapRootIndex); | 2099 __ CompareRoot(r7, Heap::kAllocationSiteMapRootIndex); |
2102 if (CpuFeatures::IsSupported(ISELECT)) { | 2100 Label feedback_register_initialized; |
2103 __ LoadRoot(r8, Heap::kUndefinedValueRootIndex); | 2101 __ beq(&feedback_register_initialized); |
2104 __ isel(eq, r5, r5, r8); | 2102 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); |
2105 } else { | 2103 __ bind(&feedback_register_initialized); |
2106 Label feedback_register_initialized; | |
2107 __ beq(&feedback_register_initialized); | |
2108 __ LoadRoot(r5, Heap::kUndefinedValueRootIndex); | |
2109 __ bind(&feedback_register_initialized); | |
2110 } | |
2111 | 2104 |
2112 __ AssertUndefinedOrAllocationSite(r5, r8); | 2105 __ AssertUndefinedOrAllocationSite(r4, r7); |
2113 | 2106 |
2114 // Pass function as new target. | 2107 // Pass function as new target. |
2115 __ mr(r6, r4); | 2108 __ LoadRR(r5, r3); |
2116 | 2109 |
2117 // Tail call to the function-specific construct stub (still in the caller | 2110 // Tail call to the function-specific construct stub (still in the caller |
2118 // context at this point). | 2111 // context at this point). |
2119 __ LoadP(r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); | 2112 __ LoadP(r6, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset)); |
2120 __ LoadP(r7, FieldMemOperand(r7, SharedFunctionInfo::kConstructStubOffset)); | 2113 __ LoadP(r6, FieldMemOperand(r6, SharedFunctionInfo::kConstructStubOffset)); |
2121 __ addi(ip, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); | 2114 __ AddP(ip, r6, Operand(Code::kHeaderSize - kHeapObjectTag)); |
2122 __ JumpToJSEntry(ip); | 2115 __ JumpToJSEntry(ip); |
2123 | 2116 |
2124 __ bind(&non_function); | 2117 __ bind(&non_function); |
2125 __ mr(r6, r4); | 2118 __ LoadRR(r5, r3); |
2126 __ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 2119 __ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
2127 } | 2120 } |
2128 | 2121 |
2129 | |
2130 void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) { | 2122 void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) { |
2131 // r4 - function | 2123 // r3 - function |
2132 // r6 - slot id | 2124 // r5 - slot id |
2133 // r5 - vector | 2125 // r4 - vector |
2134 // r7 - allocation site (loaded from vector[slot]) | 2126 // r6 - allocation site (loaded from vector[slot]) |
2135 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r8); | 2127 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r7); |
2136 __ cmp(r4, r8); | 2128 __ CmpP(r3, r7); |
2137 __ bne(miss); | 2129 __ bne(miss); |
2138 | 2130 |
2139 __ mov(r3, Operand(arg_count())); | 2131 __ mov(r2, Operand(arg_count())); |
2140 | 2132 |
2141 // Increment the call count for monomorphic function calls. | 2133 // Increment the call count for monomorphic function calls. |
2142 const int count_offset = FixedArray::kHeaderSize + kPointerSize; | 2134 const int count_offset = FixedArray::kHeaderSize + kPointerSize; |
2143 __ SmiToPtrArrayOffset(r8, r6); | 2135 __ SmiToPtrArrayOffset(r7, r5); |
2144 __ add(r5, r5, r8); | 2136 __ AddP(r4, r4, r7); |
2145 __ LoadP(r6, FieldMemOperand(r5, count_offset)); | 2137 __ LoadP(r5, FieldMemOperand(r4, count_offset)); |
2146 __ AddSmiLiteral(r6, r6, Smi::FromInt(CallICNexus::kCallCountIncrement), r0); | 2138 __ AddSmiLiteral(r5, r5, Smi::FromInt(CallICNexus::kCallCountIncrement), r0); |
2147 __ StoreP(r6, FieldMemOperand(r5, count_offset), r0); | 2139 __ StoreP(r5, FieldMemOperand(r4, count_offset), r0); |
2148 | 2140 |
2149 __ mr(r5, r7); | 2141 __ LoadRR(r4, r6); |
2150 __ mr(r6, r4); | 2142 __ LoadRR(r5, r3); |
2151 ArrayConstructorStub stub(masm->isolate(), arg_count()); | 2143 ArrayConstructorStub stub(masm->isolate(), arg_count()); |
2152 __ TailCallStub(&stub); | 2144 __ TailCallStub(&stub); |
2153 } | 2145 } |
2154 | 2146 |
2155 | |
2156 void CallICStub::Generate(MacroAssembler* masm) { | 2147 void CallICStub::Generate(MacroAssembler* masm) { |
2157 // r4 - function | 2148 // r3 - function |
2158 // r6 - slot id (Smi) | 2149 // r5 - slot id (Smi) |
2159 // r5 - vector | 2150 // r4 - vector |
2160 Label extra_checks_or_miss, call, call_function; | 2151 Label extra_checks_or_miss, call, call_function; |
2161 int argc = arg_count(); | 2152 int argc = arg_count(); |
2162 ParameterCount actual(argc); | 2153 ParameterCount actual(argc); |
2163 | 2154 |
2164 // The checks. First, does r4 match the recorded monomorphic target? | 2155 // The checks. First, does r3 match the recorded monomorphic target? |
2165 __ SmiToPtrArrayOffset(r9, r6); | 2156 __ SmiToPtrArrayOffset(r8, r5); |
2166 __ add(r9, r5, r9); | 2157 __ AddP(r8, r4, r8); |
2167 __ LoadP(r7, FieldMemOperand(r9, FixedArray::kHeaderSize)); | 2158 __ LoadP(r6, FieldMemOperand(r8, FixedArray::kHeaderSize)); |
2168 | 2159 |
2169 // We don't know that we have a weak cell. We might have a private symbol | 2160 // We don't know that we have a weak cell. We might have a private symbol |
2170 // or an AllocationSite, but the memory is safe to examine. | 2161 // or an AllocationSite, but the memory is safe to examine. |
2171 // AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to | 2162 // AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to |
2172 // FixedArray. | 2163 // FixedArray. |
2173 // WeakCell::kValueOffset - contains a JSFunction or Smi(0) | 2164 // WeakCell::kValueOffset - contains a JSFunction or Smi(0) |
2174 // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not | 2165 // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not |
2175 // computed, meaning that it can't appear to be a pointer. If the low bit is | 2166 // computed, meaning that it can't appear to be a pointer. If the low bit is |
2176 // 0, then hash is computed, but the 0 bit prevents the field from appearing | 2167 // 0, then hash is computed, but the 0 bit prevents the field from appearing |
2177 // to be a pointer. | 2168 // to be a pointer. |
2178 STATIC_ASSERT(WeakCell::kSize >= kPointerSize); | 2169 STATIC_ASSERT(WeakCell::kSize >= kPointerSize); |
2179 STATIC_ASSERT(AllocationSite::kTransitionInfoOffset == | 2170 STATIC_ASSERT(AllocationSite::kTransitionInfoOffset == |
2180 WeakCell::kValueOffset && | 2171 WeakCell::kValueOffset && |
2181 WeakCell::kValueOffset == Symbol::kHashFieldSlot); | 2172 WeakCell::kValueOffset == Symbol::kHashFieldSlot); |
2182 | 2173 |
2183 __ LoadP(r8, FieldMemOperand(r7, WeakCell::kValueOffset)); | 2174 __ LoadP(r7, FieldMemOperand(r6, WeakCell::kValueOffset)); |
2184 __ cmp(r4, r8); | 2175 __ CmpP(r3, r7); |
2185 __ bne(&extra_checks_or_miss); | 2176 __ bne(&extra_checks_or_miss, Label::kNear); |
2186 | 2177 |
2187 // The compare above could have been a SMI/SMI comparison. Guard against this | 2178 // The compare above could have been a SMI/SMI comparison. Guard against this |
2188 // convincing us that we have a monomorphic JSFunction. | 2179 // convincing us that we have a monomorphic JSFunction. |
2189 __ JumpIfSmi(r4, &extra_checks_or_miss); | 2180 __ JumpIfSmi(r3, &extra_checks_or_miss); |
2190 | 2181 |
2191 // Increment the call count for monomorphic function calls. | 2182 // Increment the call count for monomorphic function calls. |
2192 const int count_offset = FixedArray::kHeaderSize + kPointerSize; | 2183 const int count_offset = FixedArray::kHeaderSize + kPointerSize; |
2193 __ LoadP(r6, FieldMemOperand(r9, count_offset)); | 2184 __ LoadP(r5, FieldMemOperand(r8, count_offset)); |
2194 __ AddSmiLiteral(r6, r6, Smi::FromInt(CallICNexus::kCallCountIncrement), r0); | 2185 __ AddSmiLiteral(r5, r5, Smi::FromInt(CallICNexus::kCallCountIncrement), r0); |
2195 __ StoreP(r6, FieldMemOperand(r9, count_offset), r0); | 2186 __ StoreP(r5, FieldMemOperand(r8, count_offset), r0); |
2196 | 2187 |
2197 __ bind(&call_function); | 2188 __ bind(&call_function); |
2198 __ mov(r3, Operand(argc)); | 2189 __ mov(r2, Operand(argc)); |
2199 __ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(), | 2190 __ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(), |
2200 tail_call_mode()), | 2191 tail_call_mode()), |
2201 RelocInfo::CODE_TARGET); | 2192 RelocInfo::CODE_TARGET); |
2202 | 2193 |
2203 __ bind(&extra_checks_or_miss); | 2194 __ bind(&extra_checks_or_miss); |
2204 Label uninitialized, miss, not_allocation_site; | 2195 Label uninitialized, miss, not_allocation_site; |
2205 | 2196 |
2206 __ CompareRoot(r7, Heap::kmegamorphic_symbolRootIndex); | 2197 __ CompareRoot(r6, Heap::kmegamorphic_symbolRootIndex); |
2207 __ beq(&call); | 2198 __ beq(&call); |
2208 | 2199 |
2209 // Verify that r7 contains an AllocationSite | 2200 // Verify that r6 contains an AllocationSite |
2210 __ LoadP(r8, FieldMemOperand(r7, HeapObject::kMapOffset)); | 2201 __ LoadP(r7, FieldMemOperand(r6, HeapObject::kMapOffset)); |
2211 __ CompareRoot(r8, Heap::kAllocationSiteMapRootIndex); | 2202 __ CompareRoot(r7, Heap::kAllocationSiteMapRootIndex); |
2212 __ bne(¬_allocation_site); | 2203 __ bne(¬_allocation_site); |
2213 | 2204 |
2214 // We have an allocation site. | 2205 // We have an allocation site. |
2215 HandleArrayCase(masm, &miss); | 2206 HandleArrayCase(masm, &miss); |
2216 | 2207 |
2217 __ bind(¬_allocation_site); | 2208 __ bind(¬_allocation_site); |
2218 | 2209 |
2219 // The following cases attempt to handle MISS cases without going to the | 2210 // The following cases attempt to handle MISS cases without going to the |
2220 // runtime. | 2211 // runtime. |
2221 if (FLAG_trace_ic) { | 2212 if (FLAG_trace_ic) { |
2222 __ b(&miss); | 2213 __ b(&miss); |
2223 } | 2214 } |
2224 | 2215 |
2225 __ CompareRoot(r7, Heap::kuninitialized_symbolRootIndex); | 2216 __ CompareRoot(r6, Heap::kuninitialized_symbolRootIndex); |
2226 __ beq(&uninitialized); | 2217 __ beq(&uninitialized); |
2227 | 2218 |
2228 // We are going megamorphic. If the feedback is a JSFunction, it is fine | 2219 // We are going megamorphic. If the feedback is a JSFunction, it is fine |
2229 // to handle it here. More complex cases are dealt with in the runtime. | 2220 // to handle it here. More complex cases are dealt with in the runtime. |
2230 __ AssertNotSmi(r7); | 2221 __ AssertNotSmi(r6); |
2231 __ CompareObjectType(r7, r8, r8, JS_FUNCTION_TYPE); | 2222 __ CompareObjectType(r6, r7, r7, JS_FUNCTION_TYPE); |
2232 __ bne(&miss); | 2223 __ bne(&miss); |
2233 __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex); | 2224 __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex); |
2234 __ StoreP(ip, FieldMemOperand(r9, FixedArray::kHeaderSize), r0); | 2225 __ StoreP(ip, FieldMemOperand(r8, FixedArray::kHeaderSize), r0); |
2235 | 2226 |
2236 __ bind(&call); | 2227 __ bind(&call); |
2237 __ mov(r3, Operand(argc)); | 2228 __ mov(r2, Operand(argc)); |
2238 __ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()), | 2229 __ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()), |
2239 RelocInfo::CODE_TARGET); | 2230 RelocInfo::CODE_TARGET); |
2240 | 2231 |
2241 __ bind(&uninitialized); | 2232 __ bind(&uninitialized); |
2242 | 2233 |
2243 // We are going monomorphic, provided we actually have a JSFunction. | 2234 // We are going monomorphic, provided we actually have a JSFunction. |
2244 __ JumpIfSmi(r4, &miss); | 2235 __ JumpIfSmi(r3, &miss); |
2245 | 2236 |
2246 // Goto miss case if we do not have a function. | 2237 // Goto miss case if we do not have a function. |
2247 __ CompareObjectType(r4, r7, r7, JS_FUNCTION_TYPE); | 2238 __ CompareObjectType(r3, r6, r6, JS_FUNCTION_TYPE); |
2248 __ bne(&miss); | 2239 __ bne(&miss); |
2249 | 2240 |
2250 // Make sure the function is not the Array() function, which requires special | 2241 // Make sure the function is not the Array() function, which requires special |
2251 // behavior on MISS. | 2242 // behavior on MISS. |
2252 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r7); | 2243 __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r6); |
2253 __ cmp(r4, r7); | 2244 __ CmpP(r3, r6); |
2254 __ beq(&miss); | 2245 __ beq(&miss); |
2255 | 2246 |
2256 // Make sure the function belongs to the same native context. | 2247 // Make sure the function belongs to the same native context. |
2257 __ LoadP(r7, FieldMemOperand(r4, JSFunction::kContextOffset)); | 2248 __ LoadP(r6, FieldMemOperand(r3, JSFunction::kContextOffset)); |
2258 __ LoadP(r7, ContextMemOperand(r7, Context::NATIVE_CONTEXT_INDEX)); | 2249 __ LoadP(r6, ContextMemOperand(r6, Context::NATIVE_CONTEXT_INDEX)); |
2259 __ LoadP(ip, NativeContextMemOperand()); | 2250 __ LoadP(ip, NativeContextMemOperand()); |
2260 __ cmp(r7, ip); | 2251 __ CmpP(r6, ip); |
2261 __ bne(&miss); | 2252 __ bne(&miss); |
2262 | 2253 |
2263 // Initialize the call counter. | 2254 // Initialize the call counter. |
2264 __ LoadSmiLiteral(r8, Smi::FromInt(CallICNexus::kCallCountIncrement)); | 2255 __ LoadSmiLiteral(r7, Smi::FromInt(CallICNexus::kCallCountIncrement)); |
2265 __ StoreP(r8, FieldMemOperand(r9, count_offset), r0); | 2256 __ StoreP(r7, FieldMemOperand(r8, count_offset), r0); |
2266 | 2257 |
2267 // Store the function. Use a stub since we need a frame for allocation. | 2258 // Store the function. Use a stub since we need a frame for allocation. |
2268 // r5 - vector | 2259 // r4 - vector |
2269 // r6 - slot | 2260 // r5 - slot |
2270 // r4 - function | 2261 // r3 - function |
2271 { | 2262 { |
2272 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 2263 FrameScope scope(masm, StackFrame::INTERNAL); |
2273 CreateWeakCellStub create_stub(masm->isolate()); | 2264 CreateWeakCellStub create_stub(masm->isolate()); |
2274 __ Push(r4); | 2265 __ Push(r3); |
2275 __ CallStub(&create_stub); | 2266 __ CallStub(&create_stub); |
2276 __ Pop(r4); | 2267 __ Pop(r3); |
2277 } | 2268 } |
2278 | 2269 |
2279 __ b(&call_function); | 2270 __ b(&call_function); |
2280 | 2271 |
2281 // We are here because tracing is on or we encountered a MISS case we can't | 2272 // We are here because tracing is on or we encountered a MISS case we can't |
2282 // handle here. | 2273 // handle here. |
2283 __ bind(&miss); | 2274 __ bind(&miss); |
2284 GenerateMiss(masm); | 2275 GenerateMiss(masm); |
2285 | 2276 |
2286 __ b(&call); | 2277 __ b(&call); |
2287 } | 2278 } |
2288 | 2279 |
2289 | |
2290 void CallICStub::GenerateMiss(MacroAssembler* masm) { | 2280 void CallICStub::GenerateMiss(MacroAssembler* masm) { |
2291 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 2281 FrameScope scope(masm, StackFrame::INTERNAL); |
2292 | 2282 |
2293 // Push the function and feedback info. | 2283 // Push the function and feedback info. |
2294 __ Push(r4, r5, r6); | 2284 __ Push(r3, r4, r5); |
2295 | 2285 |
2296 // Call the entry. | 2286 // Call the entry. |
2297 __ CallRuntime(Runtime::kCallIC_Miss); | 2287 __ CallRuntime(Runtime::kCallIC_Miss); |
2298 | 2288 |
2299 // Move result to r4 and exit the internal frame. | 2289 // Move result to r3 and exit the internal frame. |
2300 __ mr(r4, r3); | 2290 __ LoadRR(r3, r2); |
2301 } | 2291 } |
2302 | 2292 |
2303 | |
2304 // StringCharCodeAtGenerator | 2293 // StringCharCodeAtGenerator |
2305 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 2294 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
2306 // If the receiver is a smi trigger the non-string case. | 2295 // If the receiver is a smi trigger the non-string case. |
2307 if (check_mode_ == RECEIVER_IS_UNKNOWN) { | 2296 if (check_mode_ == RECEIVER_IS_UNKNOWN) { |
2308 __ JumpIfSmi(object_, receiver_not_string_); | 2297 __ JumpIfSmi(object_, receiver_not_string_); |
2309 | 2298 |
2310 // Fetch the instance type of the receiver into result register. | 2299 // Fetch the instance type of the receiver into result register. |
2311 __ LoadP(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 2300 __ LoadP(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
2312 __ lbz(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 2301 __ LoadlB(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
2313 // If the receiver is not a string trigger the non-string case. | 2302 // If the receiver is not a string trigger the non-string case. |
2314 __ andi(r0, result_, Operand(kIsNotStringMask)); | 2303 __ mov(r0, Operand(kIsNotStringMask)); |
2315 __ bne(receiver_not_string_, cr0); | 2304 __ AndP(r0, result_); |
| 2305 __ bne(receiver_not_string_); |
2316 } | 2306 } |
2317 | 2307 |
2318 // If the index is non-smi trigger the non-smi case. | 2308 // If the index is non-smi trigger the non-smi case. |
2319 __ JumpIfNotSmi(index_, &index_not_smi_); | 2309 __ JumpIfNotSmi(index_, &index_not_smi_); |
2320 __ bind(&got_smi_index_); | 2310 __ bind(&got_smi_index_); |
2321 | 2311 |
2322 // Check for index out of range. | 2312 // Check for index out of range. |
2323 __ LoadP(ip, FieldMemOperand(object_, String::kLengthOffset)); | 2313 __ LoadP(ip, FieldMemOperand(object_, String::kLengthOffset)); |
2324 __ cmpl(ip, index_); | 2314 __ CmpLogicalP(ip, index_); |
2325 __ ble(index_out_of_range_); | 2315 __ ble(index_out_of_range_); |
2326 | 2316 |
2327 __ SmiUntag(index_); | 2317 __ SmiUntag(index_); |
2328 | 2318 |
2329 StringCharLoadGenerator::Generate(masm, object_, index_, result_, | 2319 StringCharLoadGenerator::Generate(masm, object_, index_, result_, |
2330 &call_runtime_); | 2320 &call_runtime_); |
2331 | 2321 |
2332 __ SmiTag(result_); | 2322 __ SmiTag(result_); |
2333 __ bind(&exit_); | 2323 __ bind(&exit_); |
2334 } | 2324 } |
2335 | 2325 |
2336 | |
2337 void StringCharCodeAtGenerator::GenerateSlow( | 2326 void StringCharCodeAtGenerator::GenerateSlow( |
2338 MacroAssembler* masm, EmbedMode embed_mode, | 2327 MacroAssembler* masm, EmbedMode embed_mode, |
2339 const RuntimeCallHelper& call_helper) { | 2328 const RuntimeCallHelper& call_helper) { |
2340 __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase); | 2329 __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase); |
2341 | 2330 |
2342 // Index is not a smi. | 2331 // Index is not a smi. |
2343 __ bind(&index_not_smi_); | 2332 __ bind(&index_not_smi_); |
2344 // If index is a heap number, try converting it to an integer. | 2333 // If index is a heap number, try converting it to an integer. |
2345 __ CheckMap(index_, result_, Heap::kHeapNumberMapRootIndex, index_not_number_, | 2334 __ CheckMap(index_, result_, Heap::kHeapNumberMapRootIndex, index_not_number_, |
2346 DONT_DO_SMI_CHECK); | 2335 DONT_DO_SMI_CHECK); |
2347 call_helper.BeforeCall(masm); | 2336 call_helper.BeforeCall(masm); |
2348 if (embed_mode == PART_OF_IC_HANDLER) { | 2337 if (embed_mode == PART_OF_IC_HANDLER) { |
2349 __ Push(LoadWithVectorDescriptor::VectorRegister(), | 2338 __ Push(LoadWithVectorDescriptor::VectorRegister(), |
2350 LoadWithVectorDescriptor::SlotRegister(), object_, index_); | 2339 LoadWithVectorDescriptor::SlotRegister(), object_, index_); |
2351 } else { | 2340 } else { |
2352 // index_ is consumed by runtime conversion function. | 2341 // index_ is consumed by runtime conversion function. |
2353 __ Push(object_, index_); | 2342 __ Push(object_, index_); |
2354 } | 2343 } |
2355 if (index_flags_ == STRING_INDEX_IS_NUMBER) { | 2344 if (index_flags_ == STRING_INDEX_IS_NUMBER) { |
2356 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero); | 2345 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero); |
2357 } else { | 2346 } else { |
2358 DCHECK(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); | 2347 DCHECK(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); |
2359 // NumberToSmi discards numbers that are not exact integers. | 2348 // NumberToSmi discards numbers that are not exact integers. |
2360 __ CallRuntime(Runtime::kNumberToSmi); | 2349 __ CallRuntime(Runtime::kNumberToSmi); |
2361 } | 2350 } |
2362 // Save the conversion result before the pop instructions below | 2351 // Save the conversion result before the pop instructions below |
2363 // have a chance to overwrite it. | 2352 // have a chance to overwrite it. |
2364 __ Move(index_, r3); | 2353 __ Move(index_, r2); |
2365 if (embed_mode == PART_OF_IC_HANDLER) { | 2354 if (embed_mode == PART_OF_IC_HANDLER) { |
2366 __ Pop(LoadWithVectorDescriptor::VectorRegister(), | 2355 __ Pop(LoadWithVectorDescriptor::VectorRegister(), |
2367 LoadWithVectorDescriptor::SlotRegister(), object_); | 2356 LoadWithVectorDescriptor::SlotRegister(), object_); |
2368 } else { | 2357 } else { |
2369 __ pop(object_); | 2358 __ pop(object_); |
2370 } | 2359 } |
2371 // Reload the instance type. | 2360 // Reload the instance type. |
2372 __ LoadP(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 2361 __ LoadP(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
2373 __ lbz(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 2362 __ LoadlB(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
2374 call_helper.AfterCall(masm); | 2363 call_helper.AfterCall(masm); |
2375 // If index is still not a smi, it must be out of range. | 2364 // If index is still not a smi, it must be out of range. |
2376 __ JumpIfNotSmi(index_, index_out_of_range_); | 2365 __ JumpIfNotSmi(index_, index_out_of_range_); |
2377 // Otherwise, return to the fast path. | 2366 // Otherwise, return to the fast path. |
2378 __ b(&got_smi_index_); | 2367 __ b(&got_smi_index_); |
2379 | 2368 |
2380 // Call runtime. We get here when the receiver is a string and the | 2369 // Call runtime. We get here when the receiver is a string and the |
2381 // index is a number, but the code of getting the actual character | 2370 // index is a number, but the code of getting the actual character |
2382 // is too complex (e.g., when the string needs to be flattened). | 2371 // is too complex (e.g., when the string needs to be flattened). |
2383 __ bind(&call_runtime_); | 2372 __ bind(&call_runtime_); |
2384 call_helper.BeforeCall(masm); | 2373 call_helper.BeforeCall(masm); |
2385 __ SmiTag(index_); | 2374 __ SmiTag(index_); |
2386 __ Push(object_, index_); | 2375 __ Push(object_, index_); |
2387 __ CallRuntime(Runtime::kStringCharCodeAtRT); | 2376 __ CallRuntime(Runtime::kStringCharCodeAtRT); |
2388 __ Move(result_, r3); | 2377 __ Move(result_, r2); |
2389 call_helper.AfterCall(masm); | 2378 call_helper.AfterCall(masm); |
2390 __ b(&exit_); | 2379 __ b(&exit_); |
2391 | 2380 |
2392 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); | 2381 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); |
2393 } | 2382 } |
2394 | 2383 |
2395 | |
2396 // ------------------------------------------------------------------------- | 2384 // ------------------------------------------------------------------------- |
2397 // StringCharFromCodeGenerator | 2385 // StringCharFromCodeGenerator |
2398 | 2386 |
2399 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { | 2387 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { |
2400 // Fast case of Heap::LookupSingleCharacterStringFromCode. | 2388 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
2401 DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCodeU + 1)); | 2389 DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCodeU + 1)); |
2402 __ LoadSmiLiteral(r0, Smi::FromInt(~String::kMaxOneByteCharCodeU)); | 2390 __ LoadSmiLiteral(r0, Smi::FromInt(~String::kMaxOneByteCharCodeU)); |
2403 __ ori(r0, r0, Operand(kSmiTagMask)); | 2391 __ OrP(r0, r0, Operand(kSmiTagMask)); |
2404 __ and_(r0, code_, r0, SetRC); | 2392 __ AndP(r0, code_, r0); |
2405 __ bne(&slow_case_, cr0); | 2393 __ bne(&slow_case_); |
2406 | 2394 |
2407 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); | 2395 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); |
2408 // At this point code register contains smi tagged one-byte char code. | 2396 // At this point code register contains smi tagged one-byte char code. |
2409 __ mr(r0, code_); | 2397 __ LoadRR(r0, code_); |
2410 __ SmiToPtrArrayOffset(code_, code_); | 2398 __ SmiToPtrArrayOffset(code_, code_); |
2411 __ add(result_, result_, code_); | 2399 __ AddP(result_, code_); |
2412 __ mr(code_, r0); | 2400 __ LoadRR(code_, r0); |
2413 __ LoadP(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); | 2401 __ LoadP(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); |
2414 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex); | 2402 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex); |
2415 __ beq(&slow_case_); | 2403 __ beq(&slow_case_); |
2416 __ bind(&exit_); | 2404 __ bind(&exit_); |
2417 } | 2405 } |
2418 | 2406 |
2419 | |
2420 void StringCharFromCodeGenerator::GenerateSlow( | 2407 void StringCharFromCodeGenerator::GenerateSlow( |
2421 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { | 2408 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
2422 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); | 2409 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); |
2423 | 2410 |
2424 __ bind(&slow_case_); | 2411 __ bind(&slow_case_); |
2425 call_helper.BeforeCall(masm); | 2412 call_helper.BeforeCall(masm); |
2426 __ push(code_); | 2413 __ push(code_); |
2427 __ CallRuntime(Runtime::kStringCharFromCode); | 2414 __ CallRuntime(Runtime::kStringCharFromCode); |
2428 __ Move(result_, r3); | 2415 __ Move(result_, r2); |
2429 call_helper.AfterCall(masm); | 2416 call_helper.AfterCall(masm); |
2430 __ b(&exit_); | 2417 __ b(&exit_); |
2431 | 2418 |
2432 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); | 2419 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
2433 } | 2420 } |
2434 | 2421 |
2435 | 2422 enum CopyCharactersFlags { COPY_ASCII = 1, DEST_ALWAYS_ALIGNED = 2 }; |
2436 enum CopyCharactersFlags { COPY_ONE_BYTE = 1, DEST_ALWAYS_ALIGNED = 2 }; | |
2437 | |
2438 | 2423 |
2439 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, Register dest, | 2424 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, Register dest, |
2440 Register src, Register count, | 2425 Register src, Register count, |
2441 Register scratch, | 2426 Register scratch, |
2442 String::Encoding encoding) { | 2427 String::Encoding encoding) { |
2443 if (FLAG_debug_code) { | 2428 if (FLAG_debug_code) { |
2444 // Check that destination is word aligned. | 2429 // Check that destination is word aligned. |
2445 __ andi(r0, dest, Operand(kPointerAlignmentMask)); | 2430 __ mov(r0, Operand(kPointerAlignmentMask)); |
| 2431 __ AndP(r0, dest); |
2446 __ Check(eq, kDestinationOfCopyNotAligned, cr0); | 2432 __ Check(eq, kDestinationOfCopyNotAligned, cr0); |
2447 } | 2433 } |
2448 | 2434 |
2449 // Nothing to do for zero characters. | 2435 // Nothing to do for zero characters. |
2450 Label done; | 2436 Label done; |
2451 if (encoding == String::TWO_BYTE_ENCODING) { | 2437 if (encoding == String::TWO_BYTE_ENCODING) { |
2452 // double the length | 2438 // double the length |
2453 __ add(count, count, count, LeaveOE, SetRC); | 2439 __ AddP(count, count, count); |
2454 __ beq(&done, cr0); | 2440 __ beq(&done, Label::kNear); |
2455 } else { | 2441 } else { |
2456 __ cmpi(count, Operand::Zero()); | 2442 __ CmpP(count, Operand::Zero()); |
2457 __ beq(&done); | 2443 __ beq(&done, Label::kNear); |
2458 } | 2444 } |
2459 | 2445 |
2460 // Copy count bytes from src to dst. | 2446 // Copy count bytes from src to dst. |
2461 Label byte_loop; | 2447 Label byte_loop; |
2462 __ mtctr(count); | 2448 // TODO(joransiu): Convert into MVC loop |
2463 __ bind(&byte_loop); | 2449 __ bind(&byte_loop); |
2464 __ lbz(scratch, MemOperand(src)); | 2450 __ LoadlB(scratch, MemOperand(src)); |
2465 __ addi(src, src, Operand(1)); | 2451 __ la(src, MemOperand(src, 1)); |
2466 __ stb(scratch, MemOperand(dest)); | 2452 __ stc(scratch, MemOperand(dest)); |
2467 __ addi(dest, dest, Operand(1)); | 2453 __ la(dest, MemOperand(dest, 1)); |
2468 __ bdnz(&byte_loop); | 2454 __ BranchOnCount(count, &byte_loop); |
2469 | 2455 |
2470 __ bind(&done); | 2456 __ bind(&done); |
2471 } | 2457 } |
2472 | 2458 |
2473 | |
2474 void SubStringStub::Generate(MacroAssembler* masm) { | 2459 void SubStringStub::Generate(MacroAssembler* masm) { |
2475 Label runtime; | 2460 Label runtime; |
2476 | 2461 |
2477 // Stack frame on entry. | 2462 // Stack frame on entry. |
2478 // lr: return address | 2463 // lr: return address |
2479 // sp[0]: to | 2464 // sp[0]: to |
2480 // sp[4]: from | 2465 // sp[4]: from |
2481 // sp[8]: string | 2466 // sp[8]: string |
2482 | 2467 |
2483 // This stub is called from the native-call %_SubString(...), so | 2468 // This stub is called from the native-call %_SubString(...), so |
2484 // nothing can be assumed about the arguments. It is tested that: | 2469 // nothing can be assumed about the arguments. It is tested that: |
2485 // "string" is a sequential string, | 2470 // "string" is a sequential string, |
2486 // both "from" and "to" are smis, and | 2471 // both "from" and "to" are smis, and |
2487 // 0 <= from <= to <= string.length. | 2472 // 0 <= from <= to <= string.length. |
2488 // If any of these assumptions fail, we call the runtime system. | 2473 // If any of these assumptions fail, we call the runtime system. |
2489 | 2474 |
2490 const int kToOffset = 0 * kPointerSize; | 2475 const int kToOffset = 0 * kPointerSize; |
2491 const int kFromOffset = 1 * kPointerSize; | 2476 const int kFromOffset = 1 * kPointerSize; |
2492 const int kStringOffset = 2 * kPointerSize; | 2477 const int kStringOffset = 2 * kPointerSize; |
2493 | 2478 |
2494 __ LoadP(r5, MemOperand(sp, kToOffset)); | 2479 __ LoadP(r4, MemOperand(sp, kToOffset)); |
2495 __ LoadP(r6, MemOperand(sp, kFromOffset)); | 2480 __ LoadP(r5, MemOperand(sp, kFromOffset)); |
2496 | 2481 |
2497 // If either to or from had the smi tag bit set, then fail to generic runtime | 2482 // If either to or from had the smi tag bit set, then fail to generic runtime |
| 2483 __ JumpIfNotSmi(r4, &runtime); |
2498 __ JumpIfNotSmi(r5, &runtime); | 2484 __ JumpIfNotSmi(r5, &runtime); |
2499 __ JumpIfNotSmi(r6, &runtime); | 2485 __ SmiUntag(r4); |
2500 __ SmiUntag(r5); | 2486 __ SmiUntag(r5); |
2501 __ SmiUntag(r6, SetRC); | 2487 // Both r4 and r5 are untagged integers. |
2502 // Both r5 and r6 are untagged integers. | |
2503 | 2488 |
2504 // We want to bailout to runtime here if From is negative. | 2489 // We want to bailout to runtime here if From is negative. |
2505 __ blt(&runtime, cr0); // From < 0. | 2490 __ blt(&runtime); // From < 0. |
2506 | 2491 |
2507 __ cmpl(r6, r5); | 2492 __ CmpLogicalP(r5, r4); |
2508 __ bgt(&runtime); // Fail if from > to. | 2493 __ bgt(&runtime); // Fail if from > to. |
2509 __ sub(r5, r5, r6); | 2494 __ SubP(r4, r4, r5); |
2510 | 2495 |
2511 // Make sure first argument is a string. | 2496 // Make sure first argument is a string. |
2512 __ LoadP(r3, MemOperand(sp, kStringOffset)); | 2497 __ LoadP(r2, MemOperand(sp, kStringOffset)); |
2513 __ JumpIfSmi(r3, &runtime); | 2498 __ JumpIfSmi(r2, &runtime); |
2514 Condition is_string = masm->IsObjectStringType(r3, r4); | 2499 Condition is_string = masm->IsObjectStringType(r2, r3); |
2515 __ b(NegateCondition(is_string), &runtime, cr0); | 2500 __ b(NegateCondition(is_string), &runtime); |
2516 | 2501 |
2517 Label single_char; | 2502 Label single_char; |
2518 __ cmpi(r5, Operand(1)); | 2503 __ CmpP(r4, Operand(1)); |
2519 __ b(eq, &single_char); | 2504 __ b(eq, &single_char); |
2520 | 2505 |
2521 // Short-cut for the case of trivial substring. | 2506 // Short-cut for the case of trivial substring. |
2522 Label return_r3; | 2507 Label return_r2; |
2523 // r3: original string | 2508 // r2: original string |
2524 // r5: result string length | 2509 // r4: result string length |
2525 __ LoadP(r7, FieldMemOperand(r3, String::kLengthOffset)); | 2510 __ LoadP(r6, FieldMemOperand(r2, String::kLengthOffset)); |
2526 __ SmiUntag(r0, r7); | 2511 __ SmiUntag(r0, r6); |
2527 __ cmpl(r5, r0); | 2512 __ CmpLogicalP(r4, r0); |
2528 // Return original string. | 2513 // Return original string. |
2529 __ beq(&return_r3); | 2514 __ beq(&return_r2); |
2530 // Longer than original string's length or negative: unsafe arguments. | 2515 // Longer than original string's length or negative: unsafe arguments. |
2531 __ bgt(&runtime); | 2516 __ bgt(&runtime); |
2532 // Shorter than original string's length: an actual substring. | 2517 // Shorter than original string's length: an actual substring. |
2533 | 2518 |
2534 // Deal with different string types: update the index if necessary | 2519 // Deal with different string types: update the index if necessary |
2535 // and put the underlying string into r8. | 2520 // and put the underlying string into r7. |
2536 // r3: original string | 2521 // r2: original string |
2537 // r4: instance type | 2522 // r3: instance type |
2538 // r5: length | 2523 // r4: length |
2539 // r6: from index (untagged) | 2524 // r5: from index (untagged) |
2540 Label underlying_unpacked, sliced_string, seq_or_external_string; | 2525 Label underlying_unpacked, sliced_string, seq_or_external_string; |
2541 // If the string is not indirect, it can only be sequential or external. | 2526 // If the string is not indirect, it can only be sequential or external. |
2542 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); | 2527 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); |
2543 STATIC_ASSERT(kIsIndirectStringMask != 0); | 2528 STATIC_ASSERT(kIsIndirectStringMask != 0); |
2544 __ andi(r0, r4, Operand(kIsIndirectStringMask)); | 2529 __ mov(r0, Operand(kIsIndirectStringMask)); |
2545 __ beq(&seq_or_external_string, cr0); | 2530 __ AndP(r0, r3); |
| 2531 __ beq(&seq_or_external_string); |
2546 | 2532 |
2547 __ andi(r0, r4, Operand(kSlicedNotConsMask)); | 2533 __ mov(r0, Operand(kSlicedNotConsMask)); |
2548 __ bne(&sliced_string, cr0); | 2534 __ AndP(r0, r3); |
| 2535 __ bne(&sliced_string); |
2549 // Cons string. Check whether it is flat, then fetch first part. | 2536 // Cons string. Check whether it is flat, then fetch first part. |
2550 __ LoadP(r8, FieldMemOperand(r3, ConsString::kSecondOffset)); | 2537 __ LoadP(r7, FieldMemOperand(r2, ConsString::kSecondOffset)); |
2551 __ CompareRoot(r8, Heap::kempty_stringRootIndex); | 2538 __ CompareRoot(r7, Heap::kempty_stringRootIndex); |
2552 __ bne(&runtime); | 2539 __ bne(&runtime); |
2553 __ LoadP(r8, FieldMemOperand(r3, ConsString::kFirstOffset)); | 2540 __ LoadP(r7, FieldMemOperand(r2, ConsString::kFirstOffset)); |
2554 // Update instance type. | 2541 // Update instance type. |
2555 __ LoadP(r4, FieldMemOperand(r8, HeapObject::kMapOffset)); | 2542 __ LoadP(r3, FieldMemOperand(r7, HeapObject::kMapOffset)); |
2556 __ lbz(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 2543 __ LoadlB(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); |
2557 __ b(&underlying_unpacked); | 2544 __ b(&underlying_unpacked); |
2558 | 2545 |
2559 __ bind(&sliced_string); | 2546 __ bind(&sliced_string); |
2560 // Sliced string. Fetch parent and correct start index by offset. | 2547 // Sliced string. Fetch parent and correct start index by offset. |
2561 __ LoadP(r8, FieldMemOperand(r3, SlicedString::kParentOffset)); | 2548 __ LoadP(r7, FieldMemOperand(r2, SlicedString::kParentOffset)); |
2562 __ LoadP(r7, FieldMemOperand(r3, SlicedString::kOffsetOffset)); | 2549 __ LoadP(r6, FieldMemOperand(r2, SlicedString::kOffsetOffset)); |
2563 __ SmiUntag(r4, r7); | 2550 __ SmiUntag(r3, r6); |
2564 __ add(r6, r6, r4); // Add offset to index. | 2551 __ AddP(r5, r3); // Add offset to index. |
2565 // Update instance type. | 2552 // Update instance type. |
2566 __ LoadP(r4, FieldMemOperand(r8, HeapObject::kMapOffset)); | 2553 __ LoadP(r3, FieldMemOperand(r7, HeapObject::kMapOffset)); |
2567 __ lbz(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 2554 __ LoadlB(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); |
2568 __ b(&underlying_unpacked); | 2555 __ b(&underlying_unpacked); |
2569 | 2556 |
2570 __ bind(&seq_or_external_string); | 2557 __ bind(&seq_or_external_string); |
2571 // Sequential or external string. Just move string to the expected register. | 2558 // Sequential or external string. Just move string to the expected register. |
2572 __ mr(r8, r3); | 2559 __ LoadRR(r7, r2); |
2573 | 2560 |
2574 __ bind(&underlying_unpacked); | 2561 __ bind(&underlying_unpacked); |
2575 | 2562 |
2576 if (FLAG_string_slices) { | 2563 if (FLAG_string_slices) { |
2577 Label copy_routine; | 2564 Label copy_routine; |
2578 // r8: underlying subject string | 2565 // r7: underlying subject string |
2579 // r4: instance type of underlying subject string | 2566 // r3: instance type of underlying subject string |
2580 // r5: length | 2567 // r4: length |
2581 // r6: adjusted start index (untagged) | 2568 // r5: adjusted start index (untagged) |
2582 __ cmpi(r5, Operand(SlicedString::kMinLength)); | 2569 __ CmpP(r4, Operand(SlicedString::kMinLength)); |
2583 // Short slice. Copy instead of slicing. | 2570 // Short slice. Copy instead of slicing. |
2584 __ blt(©_routine); | 2571 __ blt(©_routine); |
2585 // Allocate new sliced string. At this point we do not reload the instance | 2572 // Allocate new sliced string. At this point we do not reload the instance |
2586 // type including the string encoding because we simply rely on the info | 2573 // type including the string encoding because we simply rely on the info |
2587 // provided by the original string. It does not matter if the original | 2574 // provided by the original string. It does not matter if the original |
2588 // string's encoding is wrong because we always have to recheck encoding of | 2575 // string's encoding is wrong because we always have to recheck encoding of |
2589 // the newly created string's parent anyways due to externalized strings. | 2576 // the newly created string's parent anyways due to externalized strings. |
2590 Label two_byte_slice, set_slice_header; | 2577 Label two_byte_slice, set_slice_header; |
2591 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | 2578 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); |
2592 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 2579 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
2593 __ andi(r0, r4, Operand(kStringEncodingMask)); | 2580 __ mov(r0, Operand(kStringEncodingMask)); |
2594 __ beq(&two_byte_slice, cr0); | 2581 __ AndP(r0, r3); |
2595 __ AllocateOneByteSlicedString(r3, r5, r9, r10, &runtime); | 2582 __ beq(&two_byte_slice); |
| 2583 __ AllocateOneByteSlicedString(r2, r4, r8, r9, &runtime); |
2596 __ b(&set_slice_header); | 2584 __ b(&set_slice_header); |
2597 __ bind(&two_byte_slice); | 2585 __ bind(&two_byte_slice); |
2598 __ AllocateTwoByteSlicedString(r3, r5, r9, r10, &runtime); | 2586 __ AllocateTwoByteSlicedString(r2, r4, r8, r9, &runtime); |
2599 __ bind(&set_slice_header); | 2587 __ bind(&set_slice_header); |
2600 __ SmiTag(r6); | 2588 __ SmiTag(r5); |
2601 __ StoreP(r8, FieldMemOperand(r3, SlicedString::kParentOffset), r0); | 2589 __ StoreP(r7, FieldMemOperand(r2, SlicedString::kParentOffset)); |
2602 __ StoreP(r6, FieldMemOperand(r3, SlicedString::kOffsetOffset), r0); | 2590 __ StoreP(r5, FieldMemOperand(r2, SlicedString::kOffsetOffset)); |
2603 __ b(&return_r3); | 2591 __ b(&return_r2); |
2604 | 2592 |
2605 __ bind(©_routine); | 2593 __ bind(©_routine); |
2606 } | 2594 } |
2607 | 2595 |
2608 // r8: underlying subject string | 2596 // r7: underlying subject string |
2609 // r4: instance type of underlying subject string | 2597 // r3: instance type of underlying subject string |
2610 // r5: length | 2598 // r4: length |
2611 // r6: adjusted start index (untagged) | 2599 // r5: adjusted start index (untagged) |
2612 Label two_byte_sequential, sequential_string, allocate_result; | 2600 Label two_byte_sequential, sequential_string, allocate_result; |
2613 STATIC_ASSERT(kExternalStringTag != 0); | 2601 STATIC_ASSERT(kExternalStringTag != 0); |
2614 STATIC_ASSERT(kSeqStringTag == 0); | 2602 STATIC_ASSERT(kSeqStringTag == 0); |
2615 __ andi(r0, r4, Operand(kExternalStringTag)); | 2603 __ mov(r0, Operand(kExternalStringTag)); |
2616 __ beq(&sequential_string, cr0); | 2604 __ AndP(r0, r3); |
| 2605 __ beq(&sequential_string); |
2617 | 2606 |
2618 // Handle external string. | 2607 // Handle external string. |
2619 // Rule out short external strings. | 2608 // Rule out short external strings. |
2620 STATIC_ASSERT(kShortExternalStringTag != 0); | 2609 STATIC_ASSERT(kShortExternalStringTag != 0); |
2621 __ andi(r0, r4, Operand(kShortExternalStringTag)); | 2610 __ mov(r0, Operand(kShortExternalStringTag)); |
2622 __ bne(&runtime, cr0); | 2611 __ AndP(r0, r3); |
2623 __ LoadP(r8, FieldMemOperand(r8, ExternalString::kResourceDataOffset)); | 2612 __ bne(&runtime); |
2624 // r8 already points to the first character of underlying string. | 2613 __ LoadP(r7, FieldMemOperand(r7, ExternalString::kResourceDataOffset)); |
| 2614 // r7 already points to the first character of underlying string. |
2625 __ b(&allocate_result); | 2615 __ b(&allocate_result); |
2626 | 2616 |
2627 __ bind(&sequential_string); | 2617 __ bind(&sequential_string); |
2628 // Locate first character of underlying subject string. | 2618 // Locate first character of underlying subject string. |
2629 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 2619 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
2630 __ addi(r8, r8, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 2620 __ AddP(r7, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
2631 | 2621 |
2632 __ bind(&allocate_result); | 2622 __ bind(&allocate_result); |
2633 // Sequential acii string. Allocate the result. | 2623 // Sequential acii string. Allocate the result. |
2634 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | 2624 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); |
2635 __ andi(r0, r4, Operand(kStringEncodingMask)); | 2625 __ mov(r0, Operand(kStringEncodingMask)); |
2636 __ beq(&two_byte_sequential, cr0); | 2626 __ AndP(r0, r3); |
| 2627 __ beq(&two_byte_sequential); |
2637 | 2628 |
2638 // Allocate and copy the resulting one-byte string. | 2629 // Allocate and copy the resulting one-byte string. |
2639 __ AllocateOneByteString(r3, r5, r7, r9, r10, &runtime); | 2630 __ AllocateOneByteString(r2, r4, r6, r8, r9, &runtime); |
2640 | 2631 |
2641 // Locate first character of substring to copy. | 2632 // Locate first character of substring to copy. |
2642 __ add(r8, r8, r6); | 2633 __ AddP(r7, r5); |
2643 // Locate first character of result. | 2634 // Locate first character of result. |
2644 __ addi(r4, r3, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 2635 __ AddP(r3, r2, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
2645 | 2636 |
2646 // r3: result string | 2637 // r2: result string |
2647 // r4: first character of result string | 2638 // r3: first character of result string |
2648 // r5: result string length | 2639 // r4: result string length |
2649 // r8: first character of substring to copy | 2640 // r7: first character of substring to copy |
2650 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 2641 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
2651 StringHelper::GenerateCopyCharacters(masm, r4, r8, r5, r6, | 2642 StringHelper::GenerateCopyCharacters(masm, r3, r7, r4, r5, |
2652 String::ONE_BYTE_ENCODING); | 2643 String::ONE_BYTE_ENCODING); |
2653 __ b(&return_r3); | 2644 __ b(&return_r2); |
2654 | 2645 |
2655 // Allocate and copy the resulting two-byte string. | 2646 // Allocate and copy the resulting two-byte string. |
2656 __ bind(&two_byte_sequential); | 2647 __ bind(&two_byte_sequential); |
2657 __ AllocateTwoByteString(r3, r5, r7, r9, r10, &runtime); | 2648 __ AllocateTwoByteString(r2, r4, r6, r8, r9, &runtime); |
2658 | 2649 |
2659 // Locate first character of substring to copy. | 2650 // Locate first character of substring to copy. |
2660 __ ShiftLeftImm(r4, r6, Operand(1)); | 2651 __ ShiftLeftP(r3, r5, Operand(1)); |
2661 __ add(r8, r8, r4); | 2652 __ AddP(r7, r3); |
2662 // Locate first character of result. | 2653 // Locate first character of result. |
2663 __ addi(r4, r3, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 2654 __ AddP(r3, r2, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
2664 | 2655 |
2665 // r3: result string. | 2656 // r2: result string. |
2666 // r4: first character of result. | 2657 // r3: first character of result. |
2667 // r5: result length. | 2658 // r4: result length. |
2668 // r8: first character of substring to copy. | 2659 // r7: first character of substring to copy. |
2669 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 2660 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
2670 StringHelper::GenerateCopyCharacters(masm, r4, r8, r5, r6, | 2661 StringHelper::GenerateCopyCharacters(masm, r3, r7, r4, r5, |
2671 String::TWO_BYTE_ENCODING); | 2662 String::TWO_BYTE_ENCODING); |
2672 | 2663 |
2673 __ bind(&return_r3); | 2664 __ bind(&return_r2); |
2674 Counters* counters = isolate()->counters(); | 2665 Counters* counters = isolate()->counters(); |
2675 __ IncrementCounter(counters->sub_string_native(), 1, r6, r7); | 2666 __ IncrementCounter(counters->sub_string_native(), 1, r5, r6); |
2676 __ Drop(3); | 2667 __ Drop(3); |
2677 __ Ret(); | 2668 __ Ret(); |
2678 | 2669 |
2679 // Just jump to runtime to create the sub string. | 2670 // Just jump to runtime to create the sub string. |
2680 __ bind(&runtime); | 2671 __ bind(&runtime); |
2681 __ TailCallRuntime(Runtime::kSubString); | 2672 __ TailCallRuntime(Runtime::kSubString); |
2682 | 2673 |
2683 __ bind(&single_char); | 2674 __ bind(&single_char); |
2684 // r3: original string | 2675 // r2: original string |
2685 // r4: instance type | 2676 // r3: instance type |
2686 // r5: length | 2677 // r4: length |
2687 // r6: from index (untagged) | 2678 // r5: from index (untagged) |
2688 __ SmiTag(r6, r6); | 2679 __ SmiTag(r5, r5); |
2689 StringCharAtGenerator generator(r3, r6, r5, r3, &runtime, &runtime, &runtime, | 2680 StringCharAtGenerator generator(r2, r5, r4, r2, &runtime, &runtime, &runtime, |
2690 STRING_INDEX_IS_NUMBER, RECEIVER_IS_STRING); | 2681 STRING_INDEX_IS_NUMBER, RECEIVER_IS_STRING); |
2691 generator.GenerateFast(masm); | 2682 generator.GenerateFast(masm); |
2692 __ Drop(3); | 2683 __ Drop(3); |
2693 __ Ret(); | 2684 __ Ret(); |
2694 generator.SkipSlow(masm, &runtime); | 2685 generator.SkipSlow(masm, &runtime); |
2695 } | 2686 } |
2696 | 2687 |
2697 | |
2698 void ToNumberStub::Generate(MacroAssembler* masm) { | 2688 void ToNumberStub::Generate(MacroAssembler* masm) { |
2699 // The ToNumber stub takes one argument in r3. | 2689 // The ToNumber stub takes one argument in r2. |
2700 Label not_smi; | 2690 Label not_smi; |
2701 __ JumpIfNotSmi(r3, ¬_smi); | 2691 __ JumpIfNotSmi(r2, ¬_smi); |
2702 __ blr(); | 2692 __ b(r14); |
2703 __ bind(¬_smi); | 2693 __ bind(¬_smi); |
2704 | 2694 |
2705 __ CompareObjectType(r3, r4, r4, HEAP_NUMBER_TYPE); | 2695 __ CompareObjectType(r2, r3, r3, HEAP_NUMBER_TYPE); |
2706 // r3: receiver | 2696 // r2: receiver |
2707 // r4: receiver instance type | 2697 // r3: receiver instance type |
2708 __ Ret(eq); | 2698 Label not_heap_number; |
| 2699 __ bne(¬_heap_number); |
| 2700 __ Ret(); |
| 2701 __ bind(¬_heap_number); |
2709 | 2702 |
2710 Label not_string, slow_string; | 2703 Label not_string, slow_string; |
2711 __ cmpli(r4, Operand(FIRST_NONSTRING_TYPE)); | 2704 __ CmpLogicalP(r3, Operand(FIRST_NONSTRING_TYPE)); |
2712 __ bge(¬_string); | 2705 __ bge(¬_string, Label::kNear); |
2713 // Check if string has a cached array index. | 2706 // Check if string has a cached array index. |
2714 __ lwz(r5, FieldMemOperand(r3, String::kHashFieldOffset)); | 2707 __ LoadlW(r4, FieldMemOperand(r2, String::kHashFieldOffset)); |
2715 __ And(r0, r5, Operand(String::kContainsCachedArrayIndexMask), SetRC); | 2708 __ AndP(r0, r4, Operand(String::kContainsCachedArrayIndexMask)); |
2716 __ bne(&slow_string, cr0); | 2709 __ bne(&slow_string, Label::kNear); |
2717 __ IndexFromHash(r5, r3); | 2710 __ IndexFromHash(r4, r2); |
2718 __ blr(); | 2711 __ b(r14); |
2719 __ bind(&slow_string); | 2712 __ bind(&slow_string); |
2720 __ push(r3); // Push argument. | 2713 __ push(r2); // Push argument. |
2721 __ TailCallRuntime(Runtime::kStringToNumber); | 2714 __ TailCallRuntime(Runtime::kStringToNumber); |
2722 __ bind(¬_string); | 2715 __ bind(¬_string); |
2723 | 2716 |
2724 Label not_oddball; | 2717 Label not_oddball; |
2725 __ cmpi(r4, Operand(ODDBALL_TYPE)); | 2718 __ CmpP(r3, Operand(ODDBALL_TYPE)); |
2726 __ bne(¬_oddball); | 2719 __ bne(¬_oddball, Label::kNear); |
2727 __ LoadP(r3, FieldMemOperand(r3, Oddball::kToNumberOffset)); | 2720 __ LoadP(r2, FieldMemOperand(r2, Oddball::kToNumberOffset)); |
2728 __ blr(); | 2721 __ b(r14); |
2729 __ bind(¬_oddball); | 2722 __ bind(¬_oddball); |
2730 | 2723 |
2731 __ push(r3); // Push argument. | 2724 __ push(r2); // Push argument. |
2732 __ TailCallRuntime(Runtime::kToNumber); | 2725 __ TailCallRuntime(Runtime::kToNumber); |
2733 } | 2726 } |
2734 | 2727 |
2735 | |
2736 void ToLengthStub::Generate(MacroAssembler* masm) { | 2728 void ToLengthStub::Generate(MacroAssembler* masm) { |
2737 // The ToLength stub takes one argument in r3. | 2729 // The ToLength stub takes one argument in r2. |
2738 Label not_smi; | 2730 Label not_smi; |
2739 __ JumpIfNotSmi(r3, ¬_smi); | 2731 __ JumpIfNotSmi(r2, ¬_smi); |
2740 STATIC_ASSERT(kSmiTag == 0); | 2732 STATIC_ASSERT(kSmiTag == 0); |
2741 __ cmpi(r3, Operand::Zero()); | 2733 __ CmpP(r2, Operand::Zero()); |
2742 if (CpuFeatures::IsSupported(ISELECT)) { | 2734 Label positive; |
2743 __ isel(lt, r3, r0, r3); | 2735 __ bgt(&positive); |
2744 } else { | 2736 __ LoadImmP(r2, Operand::Zero()); |
2745 Label positive; | 2737 __ bind(&positive); |
2746 __ bgt(&positive); | |
2747 __ li(r3, Operand::Zero()); | |
2748 __ bind(&positive); | |
2749 } | |
2750 __ Ret(); | 2738 __ Ret(); |
2751 __ bind(¬_smi); | 2739 __ bind(¬_smi); |
2752 | 2740 |
2753 __ push(r3); // Push argument. | 2741 __ push(r2); // Push argument. |
2754 __ TailCallRuntime(Runtime::kToLength); | 2742 __ TailCallRuntime(Runtime::kToLength); |
2755 } | 2743 } |
2756 | 2744 |
| 2745 void ToStringStub::Generate(MacroAssembler* masm) { |
| 2746 // The ToString stub takes one argument in r2. |
| 2747 Label done; |
| 2748 Label is_number; |
| 2749 __ JumpIfSmi(r2, &is_number); |
2757 | 2750 |
2758 void ToStringStub::Generate(MacroAssembler* masm) { | 2751 __ CompareObjectType(r2, r3, r3, FIRST_NONSTRING_TYPE); |
2759 // The ToString stub takes one argument in r3. | 2752 // r2: receiver |
2760 Label is_number; | 2753 // r3: receiver instance type |
2761 __ JumpIfSmi(r3, &is_number); | 2754 __ blt(&done); |
2762 | |
2763 __ CompareObjectType(r3, r4, r4, FIRST_NONSTRING_TYPE); | |
2764 // r3: receiver | |
2765 // r4: receiver instance type | |
2766 __ Ret(lt); | |
2767 | 2755 |
2768 Label not_heap_number; | 2756 Label not_heap_number; |
2769 __ cmpi(r4, Operand(HEAP_NUMBER_TYPE)); | 2757 __ CmpP(r3, Operand(HEAP_NUMBER_TYPE)); |
2770 __ bne(¬_heap_number); | 2758 __ bne(¬_heap_number); |
2771 __ bind(&is_number); | 2759 __ bind(&is_number); |
2772 NumberToStringStub stub(isolate()); | 2760 NumberToStringStub stub(isolate()); |
2773 __ TailCallStub(&stub); | 2761 __ TailCallStub(&stub); |
2774 __ bind(¬_heap_number); | 2762 __ bind(¬_heap_number); |
2775 | 2763 |
2776 Label not_oddball; | 2764 Label not_oddball; |
2777 __ cmpi(r4, Operand(ODDBALL_TYPE)); | 2765 __ CmpP(r3, Operand(ODDBALL_TYPE)); |
2778 __ bne(¬_oddball); | 2766 __ bne(¬_oddball); |
2779 __ LoadP(r3, FieldMemOperand(r3, Oddball::kToStringOffset)); | 2767 __ LoadP(r2, FieldMemOperand(r2, Oddball::kToStringOffset)); |
2780 __ Ret(); | 2768 __ Ret(); |
2781 __ bind(¬_oddball); | 2769 __ bind(¬_oddball); |
2782 | 2770 |
2783 __ push(r3); // Push argument. | 2771 __ push(r2); // Push argument. |
2784 __ TailCallRuntime(Runtime::kToString); | 2772 __ TailCallRuntime(Runtime::kToString); |
| 2773 |
| 2774 __ bind(&done); |
| 2775 __ Ret(); |
2785 } | 2776 } |
2786 | 2777 |
2787 | |
2788 void ToNameStub::Generate(MacroAssembler* masm) { | 2778 void ToNameStub::Generate(MacroAssembler* masm) { |
2789 // The ToName stub takes one argument in r3. | 2779 // The ToName stub takes one argument in r2. |
2790 Label is_number; | 2780 Label is_number; |
2791 __ JumpIfSmi(r3, &is_number); | 2781 __ JumpIfSmi(r2, &is_number); |
2792 | 2782 |
2793 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); | 2783 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); |
2794 __ CompareObjectType(r3, r4, r4, LAST_NAME_TYPE); | 2784 __ CompareObjectType(r2, r3, r3, LAST_NAME_TYPE); |
2795 // r3: receiver | 2785 // r2: receiver |
2796 // r4: receiver instance type | 2786 // r3: receiver instance type |
2797 __ Ret(le); | 2787 __ Ret(le); |
2798 | 2788 |
2799 Label not_heap_number; | 2789 Label not_heap_number; |
2800 __ cmpi(r4, Operand(HEAP_NUMBER_TYPE)); | 2790 __ CmpP(r3, Operand(HEAP_NUMBER_TYPE)); |
2801 __ bne(¬_heap_number); | 2791 __ bne(¬_heap_number); |
2802 __ bind(&is_number); | 2792 __ bind(&is_number); |
2803 NumberToStringStub stub(isolate()); | 2793 NumberToStringStub stub(isolate()); |
2804 __ TailCallStub(&stub); | 2794 __ TailCallStub(&stub); |
2805 __ bind(¬_heap_number); | 2795 __ bind(¬_heap_number); |
2806 | 2796 |
2807 Label not_oddball; | 2797 Label not_oddball; |
2808 __ cmpi(r4, Operand(ODDBALL_TYPE)); | 2798 __ CmpP(r3, Operand(ODDBALL_TYPE)); |
2809 __ bne(¬_oddball); | 2799 __ bne(¬_oddball); |
2810 __ LoadP(r3, FieldMemOperand(r3, Oddball::kToStringOffset)); | 2800 __ LoadP(r2, FieldMemOperand(r2, Oddball::kToStringOffset)); |
2811 __ Ret(); | 2801 __ Ret(); |
2812 __ bind(¬_oddball); | 2802 __ bind(¬_oddball); |
2813 | 2803 |
2814 __ push(r3); // Push argument. | 2804 __ push(r2); // Push argument. |
2815 __ TailCallRuntime(Runtime::kToName); | 2805 __ TailCallRuntime(Runtime::kToName); |
2816 } | 2806 } |
2817 | 2807 |
2818 | |
2819 void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm, | 2808 void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm, |
2820 Register left, | 2809 Register left, |
2821 Register right, | 2810 Register right, |
2822 Register scratch1, | 2811 Register scratch1, |
2823 Register scratch2) { | 2812 Register scratch2) { |
2824 Register length = scratch1; | 2813 Register length = scratch1; |
2825 | 2814 |
2826 // Compare lengths. | 2815 // Compare lengths. |
2827 Label strings_not_equal, check_zero_length; | 2816 Label strings_not_equal, check_zero_length; |
2828 __ LoadP(length, FieldMemOperand(left, String::kLengthOffset)); | 2817 __ LoadP(length, FieldMemOperand(left, String::kLengthOffset)); |
2829 __ LoadP(scratch2, FieldMemOperand(right, String::kLengthOffset)); | 2818 __ LoadP(scratch2, FieldMemOperand(right, String::kLengthOffset)); |
2830 __ cmp(length, scratch2); | 2819 __ CmpP(length, scratch2); |
2831 __ beq(&check_zero_length); | 2820 __ beq(&check_zero_length); |
2832 __ bind(&strings_not_equal); | 2821 __ bind(&strings_not_equal); |
2833 __ LoadSmiLiteral(r3, Smi::FromInt(NOT_EQUAL)); | 2822 __ LoadSmiLiteral(r2, Smi::FromInt(NOT_EQUAL)); |
2834 __ Ret(); | 2823 __ Ret(); |
2835 | 2824 |
2836 // Check if the length is zero. | 2825 // Check if the length is zero. |
2837 Label compare_chars; | 2826 Label compare_chars; |
2838 __ bind(&check_zero_length); | 2827 __ bind(&check_zero_length); |
2839 STATIC_ASSERT(kSmiTag == 0); | 2828 STATIC_ASSERT(kSmiTag == 0); |
2840 __ cmpi(length, Operand::Zero()); | 2829 __ CmpP(length, Operand::Zero()); |
2841 __ bne(&compare_chars); | 2830 __ bne(&compare_chars); |
2842 __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL)); | 2831 __ LoadSmiLiteral(r2, Smi::FromInt(EQUAL)); |
2843 __ Ret(); | 2832 __ Ret(); |
2844 | 2833 |
2845 // Compare characters. | 2834 // Compare characters. |
2846 __ bind(&compare_chars); | 2835 __ bind(&compare_chars); |
2847 GenerateOneByteCharsCompareLoop(masm, left, right, length, scratch2, | 2836 GenerateOneByteCharsCompareLoop(masm, left, right, length, scratch2, |
2848 &strings_not_equal); | 2837 &strings_not_equal); |
2849 | 2838 |
2850 // Characters are equal. | 2839 // Characters are equal. |
2851 __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL)); | 2840 __ LoadSmiLiteral(r2, Smi::FromInt(EQUAL)); |
2852 __ Ret(); | 2841 __ Ret(); |
2853 } | 2842 } |
2854 | 2843 |
2855 | |
2856 void StringHelper::GenerateCompareFlatOneByteStrings( | 2844 void StringHelper::GenerateCompareFlatOneByteStrings( |
2857 MacroAssembler* masm, Register left, Register right, Register scratch1, | 2845 MacroAssembler* masm, Register left, Register right, Register scratch1, |
2858 Register scratch2, Register scratch3) { | 2846 Register scratch2, Register scratch3) { |
2859 Label result_not_equal, compare_lengths; | 2847 Label skip, result_not_equal, compare_lengths; |
2860 // Find minimum length and length difference. | 2848 // Find minimum length and length difference. |
2861 __ LoadP(scratch1, FieldMemOperand(left, String::kLengthOffset)); | 2849 __ LoadP(scratch1, FieldMemOperand(left, String::kLengthOffset)); |
2862 __ LoadP(scratch2, FieldMemOperand(right, String::kLengthOffset)); | 2850 __ LoadP(scratch2, FieldMemOperand(right, String::kLengthOffset)); |
2863 __ sub(scratch3, scratch1, scratch2, LeaveOE, SetRC); | 2851 __ SubP(scratch3, scratch1, scratch2 /*, LeaveOE, SetRC*/); |
| 2852 // Removing RC looks okay here. |
2864 Register length_delta = scratch3; | 2853 Register length_delta = scratch3; |
2865 if (CpuFeatures::IsSupported(ISELECT)) { | 2854 __ ble(&skip, Label::kNear); |
2866 __ isel(gt, scratch1, scratch2, scratch1, cr0); | 2855 __ LoadRR(scratch1, scratch2); |
2867 } else { | 2856 __ bind(&skip); |
2868 Label skip; | |
2869 __ ble(&skip, cr0); | |
2870 __ mr(scratch1, scratch2); | |
2871 __ bind(&skip); | |
2872 } | |
2873 Register min_length = scratch1; | 2857 Register min_length = scratch1; |
2874 STATIC_ASSERT(kSmiTag == 0); | 2858 STATIC_ASSERT(kSmiTag == 0); |
2875 __ cmpi(min_length, Operand::Zero()); | 2859 __ CmpP(min_length, Operand::Zero()); |
2876 __ beq(&compare_lengths); | 2860 __ beq(&compare_lengths); |
2877 | 2861 |
2878 // Compare loop. | 2862 // Compare loop. |
2879 GenerateOneByteCharsCompareLoop(masm, left, right, min_length, scratch2, | 2863 GenerateOneByteCharsCompareLoop(masm, left, right, min_length, scratch2, |
2880 &result_not_equal); | 2864 &result_not_equal); |
2881 | 2865 |
2882 // Compare lengths - strings up to min-length are equal. | 2866 // Compare lengths - strings up to min-length are equal. |
2883 __ bind(&compare_lengths); | 2867 __ bind(&compare_lengths); |
2884 DCHECK(Smi::FromInt(EQUAL) == static_cast<Smi*>(0)); | 2868 DCHECK(Smi::FromInt(EQUAL) == static_cast<Smi*>(0)); |
2885 // Use length_delta as result if it's zero. | 2869 // Use length_delta as result if it's zero. |
2886 __ mr(r3, length_delta); | 2870 __ LoadRR(r2, length_delta); |
2887 __ cmpi(r3, Operand::Zero()); | 2871 __ CmpP(length_delta, Operand::Zero()); |
2888 __ bind(&result_not_equal); | 2872 __ bind(&result_not_equal); |
2889 // Conditionally update the result based either on length_delta or | 2873 // Conditionally update the result based either on length_delta or |
2890 // the last comparion performed in the loop above. | 2874 // the last comparion performed in the loop above. |
2891 if (CpuFeatures::IsSupported(ISELECT)) { | 2875 Label less_equal, equal; |
2892 __ LoadSmiLiteral(r4, Smi::FromInt(GREATER)); | 2876 __ ble(&less_equal); |
2893 __ LoadSmiLiteral(r5, Smi::FromInt(LESS)); | 2877 __ LoadSmiLiteral(r2, Smi::FromInt(GREATER)); |
2894 __ isel(eq, r3, r0, r4); | 2878 __ Ret(); |
2895 __ isel(lt, r3, r5, r3); | 2879 __ bind(&less_equal); |
2896 __ Ret(); | 2880 __ beq(&equal); |
2897 } else { | 2881 __ LoadSmiLiteral(r2, Smi::FromInt(LESS)); |
2898 Label less_equal, equal; | 2882 __ bind(&equal); |
2899 __ ble(&less_equal); | 2883 __ Ret(); |
2900 __ LoadSmiLiteral(r3, Smi::FromInt(GREATER)); | |
2901 __ Ret(); | |
2902 __ bind(&less_equal); | |
2903 __ beq(&equal); | |
2904 __ LoadSmiLiteral(r3, Smi::FromInt(LESS)); | |
2905 __ bind(&equal); | |
2906 __ Ret(); | |
2907 } | |
2908 } | 2884 } |
2909 | 2885 |
2910 | |
2911 void StringHelper::GenerateOneByteCharsCompareLoop( | 2886 void StringHelper::GenerateOneByteCharsCompareLoop( |
2912 MacroAssembler* masm, Register left, Register right, Register length, | 2887 MacroAssembler* masm, Register left, Register right, Register length, |
2913 Register scratch1, Label* chars_not_equal) { | 2888 Register scratch1, Label* chars_not_equal) { |
2914 // Change index to run from -length to -1 by adding length to string | 2889 // Change index to run from -length to -1 by adding length to string |
2915 // start. This means that loop ends when index reaches zero, which | 2890 // start. This means that loop ends when index reaches zero, which |
2916 // doesn't need an additional compare. | 2891 // doesn't need an additional compare. |
2917 __ SmiUntag(length); | 2892 __ SmiUntag(length); |
2918 __ addi(scratch1, length, | 2893 __ AddP(scratch1, length, |
2919 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 2894 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
2920 __ add(left, left, scratch1); | 2895 __ AddP(left, scratch1); |
2921 __ add(right, right, scratch1); | 2896 __ AddP(right, scratch1); |
2922 __ subfic(length, length, Operand::Zero()); | 2897 __ LoadComplementRR(length, length); |
2923 Register index = length; // index = -length; | 2898 Register index = length; // index = -length; |
2924 | 2899 |
2925 // Compare loop. | 2900 // Compare loop. |
2926 Label loop; | 2901 Label loop; |
2927 __ bind(&loop); | 2902 __ bind(&loop); |
2928 __ lbzx(scratch1, MemOperand(left, index)); | 2903 __ LoadlB(scratch1, MemOperand(left, index)); |
2929 __ lbzx(r0, MemOperand(right, index)); | 2904 __ LoadlB(r0, MemOperand(right, index)); |
2930 __ cmp(scratch1, r0); | 2905 __ CmpP(scratch1, r0); |
2931 __ bne(chars_not_equal); | 2906 __ bne(chars_not_equal); |
2932 __ addi(index, index, Operand(1)); | 2907 __ AddP(index, Operand(1)); |
2933 __ cmpi(index, Operand::Zero()); | 2908 __ CmpP(index, Operand::Zero()); |
2934 __ bne(&loop); | 2909 __ bne(&loop); |
2935 } | 2910 } |
2936 | 2911 |
2937 | |
2938 void StringCompareStub::Generate(MacroAssembler* masm) { | 2912 void StringCompareStub::Generate(MacroAssembler* masm) { |
2939 // ----------- S t a t e ------------- | 2913 // ----------- S t a t e ------------- |
2940 // -- r4 : left | 2914 // -- r3 : left |
2941 // -- r3 : right | 2915 // -- r2 : right |
2942 // -- lr : return address | 2916 // -- r14 : return address |
2943 // ----------------------------------- | 2917 // ----------------------------------- |
2944 __ AssertString(r4); | |
2945 __ AssertString(r3); | 2918 __ AssertString(r3); |
| 2919 __ AssertString(r2); |
2946 | 2920 |
2947 Label not_same; | 2921 Label not_same; |
2948 __ cmp(r3, r4); | 2922 __ CmpP(r2, r3); |
2949 __ bne(¬_same); | 2923 __ bne(¬_same); |
2950 __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL)); | 2924 __ LoadSmiLiteral(r2, Smi::FromInt(EQUAL)); |
2951 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r4, | 2925 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r3, |
2952 r5); | 2926 r4); |
2953 __ Ret(); | 2927 __ Ret(); |
2954 | 2928 |
2955 __ bind(¬_same); | 2929 __ bind(¬_same); |
2956 | 2930 |
2957 // Check that both objects are sequential one-byte strings. | 2931 // Check that both objects are sequential one-byte strings. |
2958 Label runtime; | 2932 Label runtime; |
2959 __ JumpIfNotBothSequentialOneByteStrings(r4, r3, r5, r6, &runtime); | 2933 __ JumpIfNotBothSequentialOneByteStrings(r3, r2, r4, r5, &runtime); |
2960 | 2934 |
2961 // Compare flat one-byte strings natively. | 2935 // Compare flat one-byte strings natively. |
2962 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r5, | 2936 __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r4, |
2963 r6); | 2937 r5); |
2964 StringHelper::GenerateCompareFlatOneByteStrings(masm, r4, r3, r5, r6, r7); | 2938 StringHelper::GenerateCompareFlatOneByteStrings(masm, r3, r2, r4, r5, r6); |
2965 | 2939 |
2966 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 2940 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
2967 // tagged as a small integer. | 2941 // tagged as a small integer. |
2968 __ bind(&runtime); | 2942 __ bind(&runtime); |
2969 __ Push(r4, r3); | 2943 __ Push(r3, r2); |
2970 __ TailCallRuntime(Runtime::kStringCompare); | 2944 __ TailCallRuntime(Runtime::kStringCompare); |
2971 } | 2945 } |
2972 | 2946 |
2973 | |
2974 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { | 2947 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { |
2975 // ----------- S t a t e ------------- | 2948 // ----------- S t a t e ------------- |
2976 // -- r4 : left | 2949 // -- r3 : left |
2977 // -- r3 : right | 2950 // -- r2 : right |
2978 // -- lr : return address | 2951 // r3: second string |
2979 // ----------------------------------- | 2952 // ----------------------------------- |
2980 | 2953 |
2981 // Load r5 with the allocation site. We stick an undefined dummy value here | 2954 // Load r4 with the allocation site. We stick an undefined dummy value here |
2982 // and replace it with the real allocation site later when we instantiate this | 2955 // and replace it with the real allocation site later when we instantiate this |
2983 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate(). | 2956 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate(). |
2984 __ Move(r5, handle(isolate()->heap()->undefined_value())); | 2957 __ Move(r4, handle(isolate()->heap()->undefined_value())); |
2985 | 2958 |
2986 // Make sure that we actually patched the allocation site. | 2959 // Make sure that we actually patched the allocation site. |
2987 if (FLAG_debug_code) { | 2960 if (FLAG_debug_code) { |
2988 __ TestIfSmi(r5, r0); | 2961 __ TestIfSmi(r4); |
2989 __ Assert(ne, kExpectedAllocationSite, cr0); | 2962 __ Assert(ne, kExpectedAllocationSite, cr0); |
2990 __ push(r5); | 2963 __ push(r4); |
2991 __ LoadP(r5, FieldMemOperand(r5, HeapObject::kMapOffset)); | 2964 __ LoadP(r4, FieldMemOperand(r4, HeapObject::kMapOffset)); |
2992 __ LoadRoot(ip, Heap::kAllocationSiteMapRootIndex); | 2965 __ CompareRoot(r4, Heap::kAllocationSiteMapRootIndex); |
2993 __ cmp(r5, ip); | 2966 __ pop(r4); |
2994 __ pop(r5); | |
2995 __ Assert(eq, kExpectedAllocationSite); | 2967 __ Assert(eq, kExpectedAllocationSite); |
2996 } | 2968 } |
2997 | 2969 |
2998 // Tail call into the stub that handles binary operations with allocation | 2970 // Tail call into the stub that handles binary operations with allocation |
2999 // sites. | 2971 // sites. |
3000 BinaryOpWithAllocationSiteStub stub(isolate(), state()); | 2972 BinaryOpWithAllocationSiteStub stub(isolate(), state()); |
3001 __ TailCallStub(&stub); | 2973 __ TailCallStub(&stub); |
3002 } | 2974 } |
3003 | 2975 |
3004 | |
3005 void CompareICStub::GenerateBooleans(MacroAssembler* masm) { | 2976 void CompareICStub::GenerateBooleans(MacroAssembler* masm) { |
3006 DCHECK_EQ(CompareICState::BOOLEAN, state()); | 2977 DCHECK_EQ(CompareICState::BOOLEAN, state()); |
3007 Label miss; | 2978 Label miss; |
3008 | 2979 |
3009 __ CheckMap(r4, r5, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK); | 2980 __ CheckMap(r3, r4, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK); |
3010 __ CheckMap(r3, r6, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK); | 2981 __ CheckMap(r2, r5, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK); |
3011 if (!Token::IsEqualityOp(op())) { | 2982 if (!Token::IsEqualityOp(op())) { |
3012 __ LoadP(r4, FieldMemOperand(r4, Oddball::kToNumberOffset)); | |
3013 __ AssertSmi(r4); | |
3014 __ LoadP(r3, FieldMemOperand(r3, Oddball::kToNumberOffset)); | 2983 __ LoadP(r3, FieldMemOperand(r3, Oddball::kToNumberOffset)); |
3015 __ AssertSmi(r3); | 2984 __ AssertSmi(r3); |
| 2985 __ LoadP(r2, FieldMemOperand(r2, Oddball::kToNumberOffset)); |
| 2986 __ AssertSmi(r2); |
3016 } | 2987 } |
3017 __ sub(r3, r4, r3); | 2988 __ SubP(r2, r3, r2); |
3018 __ Ret(); | 2989 __ Ret(); |
3019 | 2990 |
3020 __ bind(&miss); | 2991 __ bind(&miss); |
3021 GenerateMiss(masm); | 2992 GenerateMiss(masm); |
3022 } | 2993 } |
3023 | 2994 |
3024 | |
3025 void CompareICStub::GenerateSmis(MacroAssembler* masm) { | 2995 void CompareICStub::GenerateSmis(MacroAssembler* masm) { |
3026 DCHECK(state() == CompareICState::SMI); | 2996 DCHECK(state() == CompareICState::SMI); |
3027 Label miss; | 2997 Label miss; |
3028 __ orx(r5, r4, r3); | 2998 __ OrP(r4, r3, r2); |
3029 __ JumpIfNotSmi(r5, &miss); | 2999 __ JumpIfNotSmi(r4, &miss); |
3030 | 3000 |
3031 if (GetCondition() == eq) { | 3001 if (GetCondition() == eq) { |
3032 // For equality we do not care about the sign of the result. | 3002 // For equality we do not care about the sign of the result. |
3033 // __ sub(r3, r3, r4, SetCC); | 3003 // __ sub(r2, r2, r3, SetCC); |
3034 __ sub(r3, r3, r4); | 3004 __ SubP(r2, r2, r3); |
3035 } else { | 3005 } else { |
3036 // Untag before subtracting to avoid handling overflow. | 3006 // Untag before subtracting to avoid handling overflow. |
3037 __ SmiUntag(r4); | |
3038 __ SmiUntag(r3); | 3007 __ SmiUntag(r3); |
3039 __ sub(r3, r4, r3); | 3008 __ SmiUntag(r2); |
| 3009 __ SubP(r2, r3, r2); |
3040 } | 3010 } |
3041 __ Ret(); | 3011 __ Ret(); |
3042 | 3012 |
3043 __ bind(&miss); | 3013 __ bind(&miss); |
3044 GenerateMiss(masm); | 3014 GenerateMiss(masm); |
3045 } | 3015 } |
3046 | 3016 |
3047 | |
3048 void CompareICStub::GenerateNumbers(MacroAssembler* masm) { | 3017 void CompareICStub::GenerateNumbers(MacroAssembler* masm) { |
3049 DCHECK(state() == CompareICState::NUMBER); | 3018 DCHECK(state() == CompareICState::NUMBER); |
3050 | 3019 |
3051 Label generic_stub; | 3020 Label generic_stub; |
3052 Label unordered, maybe_undefined1, maybe_undefined2; | 3021 Label unordered, maybe_undefined1, maybe_undefined2; |
3053 Label miss; | 3022 Label miss; |
3054 Label equal, less_than; | 3023 Label equal, less_than; |
3055 | 3024 |
3056 if (left() == CompareICState::SMI) { | 3025 if (left() == CompareICState::SMI) { |
3057 __ JumpIfNotSmi(r4, &miss); | 3026 __ JumpIfNotSmi(r3, &miss); |
3058 } | 3027 } |
3059 if (right() == CompareICState::SMI) { | 3028 if (right() == CompareICState::SMI) { |
3060 __ JumpIfNotSmi(r3, &miss); | 3029 __ JumpIfNotSmi(r2, &miss); |
3061 } | 3030 } |
3062 | 3031 |
3063 // Inlining the double comparison and falling back to the general compare | 3032 // Inlining the double comparison and falling back to the general compare |
3064 // stub if NaN is involved. | 3033 // stub if NaN is involved. |
3065 // Load left and right operand. | 3034 // Load left and right operand. |
3066 Label done, left, left_smi, right_smi; | 3035 Label done, left, left_smi, right_smi; |
3067 __ JumpIfSmi(r3, &right_smi); | 3036 __ JumpIfSmi(r2, &right_smi); |
3068 __ CheckMap(r3, r5, Heap::kHeapNumberMapRootIndex, &maybe_undefined1, | 3037 __ CheckMap(r2, r4, Heap::kHeapNumberMapRootIndex, &maybe_undefined1, |
3069 DONT_DO_SMI_CHECK); | 3038 DONT_DO_SMI_CHECK); |
3070 __ lfd(d1, FieldMemOperand(r3, HeapNumber::kValueOffset)); | 3039 __ LoadDouble(d1, FieldMemOperand(r2, HeapNumber::kValueOffset)); |
3071 __ b(&left); | 3040 __ b(&left); |
3072 __ bind(&right_smi); | 3041 __ bind(&right_smi); |
3073 __ SmiToDouble(d1, r3); | 3042 __ SmiToDouble(d1, r2); |
3074 | 3043 |
3075 __ bind(&left); | 3044 __ bind(&left); |
3076 __ JumpIfSmi(r4, &left_smi); | 3045 __ JumpIfSmi(r3, &left_smi); |
3077 __ CheckMap(r4, r5, Heap::kHeapNumberMapRootIndex, &maybe_undefined2, | 3046 __ CheckMap(r3, r4, Heap::kHeapNumberMapRootIndex, &maybe_undefined2, |
3078 DONT_DO_SMI_CHECK); | 3047 DONT_DO_SMI_CHECK); |
3079 __ lfd(d0, FieldMemOperand(r4, HeapNumber::kValueOffset)); | 3048 __ LoadDouble(d0, FieldMemOperand(r3, HeapNumber::kValueOffset)); |
3080 __ b(&done); | 3049 __ b(&done); |
3081 __ bind(&left_smi); | 3050 __ bind(&left_smi); |
3082 __ SmiToDouble(d0, r4); | 3051 __ SmiToDouble(d0, r3); |
3083 | 3052 |
3084 __ bind(&done); | 3053 __ bind(&done); |
3085 | 3054 |
3086 // Compare operands | 3055 // Compare operands |
3087 __ fcmpu(d0, d1); | 3056 __ cdbr(d0, d1); |
3088 | 3057 |
3089 // Don't base result on status bits when a NaN is involved. | 3058 // Don't base result on status bits when a NaN is involved. |
3090 __ bunordered(&unordered); | 3059 __ bunordered(&unordered); |
3091 | 3060 |
3092 // Return a result of -1, 0, or 1, based on status bits. | 3061 // Return a result of -1, 0, or 1, based on status bits. |
3093 if (CpuFeatures::IsSupported(ISELECT)) { | 3062 __ beq(&equal); |
3094 DCHECK(EQUAL == 0); | 3063 __ blt(&less_than); |
3095 __ li(r4, Operand(GREATER)); | 3064 // assume greater than |
3096 __ li(r5, Operand(LESS)); | 3065 __ LoadImmP(r2, Operand(GREATER)); |
3097 __ isel(eq, r3, r0, r4); | 3066 __ Ret(); |
3098 __ isel(lt, r3, r5, r3); | 3067 __ bind(&equal); |
3099 __ Ret(); | 3068 __ LoadImmP(r2, Operand(EQUAL)); |
3100 } else { | 3069 __ Ret(); |
3101 __ beq(&equal); | 3070 __ bind(&less_than); |
3102 __ blt(&less_than); | 3071 __ LoadImmP(r2, Operand(LESS)); |
3103 // assume greater than | 3072 __ Ret(); |
3104 __ li(r3, Operand(GREATER)); | |
3105 __ Ret(); | |
3106 __ bind(&equal); | |
3107 __ li(r3, Operand(EQUAL)); | |
3108 __ Ret(); | |
3109 __ bind(&less_than); | |
3110 __ li(r3, Operand(LESS)); | |
3111 __ Ret(); | |
3112 } | |
3113 | 3073 |
3114 __ bind(&unordered); | 3074 __ bind(&unordered); |
3115 __ bind(&generic_stub); | 3075 __ bind(&generic_stub); |
3116 CompareICStub stub(isolate(), op(), CompareICState::GENERIC, | 3076 CompareICStub stub(isolate(), op(), CompareICState::GENERIC, |
3117 CompareICState::GENERIC, CompareICState::GENERIC); | 3077 CompareICState::GENERIC, CompareICState::GENERIC); |
3118 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 3078 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
3119 | 3079 |
3120 __ bind(&maybe_undefined1); | 3080 __ bind(&maybe_undefined1); |
3121 if (Token::IsOrderedRelationalCompareOp(op())) { | 3081 if (Token::IsOrderedRelationalCompareOp(op())) { |
3122 __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); | 3082 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex); |
3123 __ bne(&miss); | 3083 __ bne(&miss); |
3124 __ JumpIfSmi(r4, &unordered); | 3084 __ JumpIfSmi(r3, &unordered); |
3125 __ CompareObjectType(r4, r5, r5, HEAP_NUMBER_TYPE); | 3085 __ CompareObjectType(r3, r4, r4, HEAP_NUMBER_TYPE); |
3126 __ bne(&maybe_undefined2); | 3086 __ bne(&maybe_undefined2); |
3127 __ b(&unordered); | 3087 __ b(&unordered); |
3128 } | 3088 } |
3129 | 3089 |
3130 __ bind(&maybe_undefined2); | 3090 __ bind(&maybe_undefined2); |
3131 if (Token::IsOrderedRelationalCompareOp(op())) { | 3091 if (Token::IsOrderedRelationalCompareOp(op())) { |
3132 __ CompareRoot(r4, Heap::kUndefinedValueRootIndex); | 3092 __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); |
3133 __ beq(&unordered); | 3093 __ beq(&unordered); |
3134 } | 3094 } |
3135 | 3095 |
3136 __ bind(&miss); | 3096 __ bind(&miss); |
3137 GenerateMiss(masm); | 3097 GenerateMiss(masm); |
3138 } | 3098 } |
3139 | 3099 |
3140 | |
3141 void CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) { | 3100 void CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) { |
3142 DCHECK(state() == CompareICState::INTERNALIZED_STRING); | 3101 DCHECK(state() == CompareICState::INTERNALIZED_STRING); |
3143 Label miss, not_equal; | 3102 Label miss, not_equal; |
3144 | 3103 |
3145 // Registers containing left and right operands respectively. | 3104 // Registers containing left and right operands respectively. |
3146 Register left = r4; | 3105 Register left = r3; |
3147 Register right = r3; | 3106 Register right = r2; |
3148 Register tmp1 = r5; | 3107 Register tmp1 = r4; |
3149 Register tmp2 = r6; | 3108 Register tmp2 = r5; |
3150 | 3109 |
3151 // Check that both operands are heap objects. | 3110 // Check that both operands are heap objects. |
3152 __ JumpIfEitherSmi(left, right, &miss); | 3111 __ JumpIfEitherSmi(left, right, &miss); |
3153 | 3112 |
3154 // Check that both operands are symbols. | 3113 // Check that both operands are symbols. |
3155 __ LoadP(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 3114 __ LoadP(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
3156 __ LoadP(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 3115 __ LoadP(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
3157 __ lbz(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 3116 __ LoadlB(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
3158 __ lbz(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 3117 __ LoadlB(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
3159 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); | 3118 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
3160 __ orx(tmp1, tmp1, tmp2); | 3119 __ OrP(tmp1, tmp1, tmp2); |
3161 __ andi(r0, tmp1, Operand(kIsNotStringMask | kIsNotInternalizedMask)); | 3120 __ AndP(r0, tmp1, Operand(kIsNotStringMask | kIsNotInternalizedMask)); |
3162 __ bne(&miss, cr0); | 3121 __ bne(&miss); |
3163 | 3122 |
3164 // Internalized strings are compared by identity. | 3123 // Internalized strings are compared by identity. |
3165 __ cmp(left, right); | 3124 __ CmpP(left, right); |
3166 __ bne(¬_equal); | 3125 __ bne(¬_equal); |
3167 // Make sure r3 is non-zero. At this point input operands are | 3126 // Make sure r2 is non-zero. At this point input operands are |
3168 // guaranteed to be non-zero. | 3127 // guaranteed to be non-zero. |
3169 DCHECK(right.is(r3)); | 3128 DCHECK(right.is(r2)); |
3170 STATIC_ASSERT(EQUAL == 0); | 3129 STATIC_ASSERT(EQUAL == 0); |
3171 STATIC_ASSERT(kSmiTag == 0); | 3130 STATIC_ASSERT(kSmiTag == 0); |
3172 __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL)); | 3131 __ LoadSmiLiteral(r2, Smi::FromInt(EQUAL)); |
3173 __ bind(¬_equal); | 3132 __ bind(¬_equal); |
3174 __ Ret(); | 3133 __ Ret(); |
3175 | 3134 |
3176 __ bind(&miss); | 3135 __ bind(&miss); |
3177 GenerateMiss(masm); | 3136 GenerateMiss(masm); |
3178 } | 3137 } |
3179 | 3138 |
3180 | |
3181 void CompareICStub::GenerateUniqueNames(MacroAssembler* masm) { | 3139 void CompareICStub::GenerateUniqueNames(MacroAssembler* masm) { |
3182 DCHECK(state() == CompareICState::UNIQUE_NAME); | 3140 DCHECK(state() == CompareICState::UNIQUE_NAME); |
3183 DCHECK(GetCondition() == eq); | 3141 DCHECK(GetCondition() == eq); |
3184 Label miss; | 3142 Label miss; |
3185 | 3143 |
3186 // Registers containing left and right operands respectively. | 3144 // Registers containing left and right operands respectively. |
3187 Register left = r4; | 3145 Register left = r3; |
3188 Register right = r3; | 3146 Register right = r2; |
3189 Register tmp1 = r5; | 3147 Register tmp1 = r4; |
3190 Register tmp2 = r6; | 3148 Register tmp2 = r5; |
3191 | 3149 |
3192 // Check that both operands are heap objects. | 3150 // Check that both operands are heap objects. |
3193 __ JumpIfEitherSmi(left, right, &miss); | 3151 __ JumpIfEitherSmi(left, right, &miss); |
3194 | 3152 |
3195 // Check that both operands are unique names. This leaves the instance | 3153 // Check that both operands are unique names. This leaves the instance |
3196 // types loaded in tmp1 and tmp2. | 3154 // types loaded in tmp1 and tmp2. |
3197 __ LoadP(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 3155 __ LoadP(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
3198 __ LoadP(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 3156 __ LoadP(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
3199 __ lbz(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 3157 __ LoadlB(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
3200 __ lbz(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 3158 __ LoadlB(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
3201 | 3159 |
3202 __ JumpIfNotUniqueNameInstanceType(tmp1, &miss); | 3160 __ JumpIfNotUniqueNameInstanceType(tmp1, &miss); |
3203 __ JumpIfNotUniqueNameInstanceType(tmp2, &miss); | 3161 __ JumpIfNotUniqueNameInstanceType(tmp2, &miss); |
3204 | 3162 |
3205 // Unique names are compared by identity. | 3163 // Unique names are compared by identity. |
3206 __ cmp(left, right); | 3164 __ CmpP(left, right); |
3207 __ bne(&miss); | 3165 __ bne(&miss); |
3208 // Make sure r3 is non-zero. At this point input operands are | 3166 // Make sure r2 is non-zero. At this point input operands are |
3209 // guaranteed to be non-zero. | 3167 // guaranteed to be non-zero. |
3210 DCHECK(right.is(r3)); | 3168 DCHECK(right.is(r2)); |
3211 STATIC_ASSERT(EQUAL == 0); | 3169 STATIC_ASSERT(EQUAL == 0); |
3212 STATIC_ASSERT(kSmiTag == 0); | 3170 STATIC_ASSERT(kSmiTag == 0); |
3213 __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL)); | 3171 __ LoadSmiLiteral(r2, Smi::FromInt(EQUAL)); |
3214 __ Ret(); | 3172 __ Ret(); |
3215 | 3173 |
3216 __ bind(&miss); | 3174 __ bind(&miss); |
3217 GenerateMiss(masm); | 3175 GenerateMiss(masm); |
3218 } | 3176 } |
3219 | 3177 |
3220 | |
3221 void CompareICStub::GenerateStrings(MacroAssembler* masm) { | 3178 void CompareICStub::GenerateStrings(MacroAssembler* masm) { |
3222 DCHECK(state() == CompareICState::STRING); | 3179 DCHECK(state() == CompareICState::STRING); |
3223 Label miss, not_identical, is_symbol; | 3180 Label miss, not_identical, is_symbol; |
3224 | 3181 |
3225 bool equality = Token::IsEqualityOp(op()); | 3182 bool equality = Token::IsEqualityOp(op()); |
3226 | 3183 |
3227 // Registers containing left and right operands respectively. | 3184 // Registers containing left and right operands respectively. |
3228 Register left = r4; | 3185 Register left = r3; |
3229 Register right = r3; | 3186 Register right = r2; |
3230 Register tmp1 = r5; | 3187 Register tmp1 = r4; |
3231 Register tmp2 = r6; | 3188 Register tmp2 = r5; |
3232 Register tmp3 = r7; | 3189 Register tmp3 = r6; |
3233 Register tmp4 = r8; | 3190 Register tmp4 = r7; |
3234 | 3191 |
3235 // Check that both operands are heap objects. | 3192 // Check that both operands are heap objects. |
3236 __ JumpIfEitherSmi(left, right, &miss); | 3193 __ JumpIfEitherSmi(left, right, &miss); |
3237 | 3194 |
3238 // Check that both operands are strings. This leaves the instance | 3195 // Check that both operands are strings. This leaves the instance |
3239 // types loaded in tmp1 and tmp2. | 3196 // types loaded in tmp1 and tmp2. |
3240 __ LoadP(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 3197 __ LoadP(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
3241 __ LoadP(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 3198 __ LoadP(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
3242 __ lbz(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 3199 __ LoadlB(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
3243 __ lbz(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 3200 __ LoadlB(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
3244 STATIC_ASSERT(kNotStringTag != 0); | 3201 STATIC_ASSERT(kNotStringTag != 0); |
3245 __ orx(tmp3, tmp1, tmp2); | 3202 __ OrP(tmp3, tmp1, tmp2); |
3246 __ andi(r0, tmp3, Operand(kIsNotStringMask)); | 3203 __ AndP(r0, tmp3, Operand(kIsNotStringMask)); |
3247 __ bne(&miss, cr0); | 3204 __ bne(&miss); |
3248 | 3205 |
3249 // Fast check for identical strings. | 3206 // Fast check for identical strings. |
3250 __ cmp(left, right); | 3207 __ CmpP(left, right); |
3251 STATIC_ASSERT(EQUAL == 0); | 3208 STATIC_ASSERT(EQUAL == 0); |
3252 STATIC_ASSERT(kSmiTag == 0); | 3209 STATIC_ASSERT(kSmiTag == 0); |
3253 __ bne(¬_identical); | 3210 __ bne(¬_identical); |
3254 __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL)); | 3211 __ LoadSmiLiteral(r2, Smi::FromInt(EQUAL)); |
3255 __ Ret(); | 3212 __ Ret(); |
3256 __ bind(¬_identical); | 3213 __ bind(¬_identical); |
3257 | 3214 |
3258 // Handle not identical strings. | 3215 // Handle not identical strings. |
3259 | 3216 |
3260 // Check that both strings are internalized strings. If they are, we're done | 3217 // Check that both strings are internalized strings. If they are, we're done |
3261 // because we already know they are not identical. We know they are both | 3218 // because we already know they are not identical. We know they are both |
3262 // strings. | 3219 // strings. |
3263 if (equality) { | 3220 if (equality) { |
3264 DCHECK(GetCondition() == eq); | 3221 DCHECK(GetCondition() == eq); |
3265 STATIC_ASSERT(kInternalizedTag == 0); | 3222 STATIC_ASSERT(kInternalizedTag == 0); |
3266 __ orx(tmp3, tmp1, tmp2); | 3223 __ OrP(tmp3, tmp1, tmp2); |
3267 __ andi(r0, tmp3, Operand(kIsNotInternalizedMask)); | 3224 __ AndP(r0, tmp3, Operand(kIsNotInternalizedMask)); |
3268 // Make sure r3 is non-zero. At this point input operands are | 3225 __ bne(&is_symbol); |
| 3226 // Make sure r2 is non-zero. At this point input operands are |
3269 // guaranteed to be non-zero. | 3227 // guaranteed to be non-zero. |
3270 DCHECK(right.is(r3)); | 3228 DCHECK(right.is(r2)); |
3271 __ Ret(eq, cr0); | 3229 __ Ret(); |
| 3230 __ bind(&is_symbol); |
3272 } | 3231 } |
3273 | 3232 |
3274 // Check that both strings are sequential one-byte. | 3233 // Check that both strings are sequential one-byte. |
3275 Label runtime; | 3234 Label runtime; |
3276 __ JumpIfBothInstanceTypesAreNotSequentialOneByte(tmp1, tmp2, tmp3, tmp4, | 3235 __ JumpIfBothInstanceTypesAreNotSequentialOneByte(tmp1, tmp2, tmp3, tmp4, |
3277 &runtime); | 3236 &runtime); |
3278 | 3237 |
3279 // Compare flat one-byte strings. Returns when done. | 3238 // Compare flat one-byte strings. Returns when done. |
3280 if (equality) { | 3239 if (equality) { |
3281 StringHelper::GenerateFlatOneByteStringEquals(masm, left, right, tmp1, | 3240 StringHelper::GenerateFlatOneByteStringEquals(masm, left, right, tmp1, |
3282 tmp2); | 3241 tmp2); |
3283 } else { | 3242 } else { |
3284 StringHelper::GenerateCompareFlatOneByteStrings(masm, left, right, tmp1, | 3243 StringHelper::GenerateCompareFlatOneByteStrings(masm, left, right, tmp1, |
3285 tmp2, tmp3); | 3244 tmp2, tmp3); |
3286 } | 3245 } |
3287 | 3246 |
3288 // Handle more complex cases in runtime. | 3247 // Handle more complex cases in runtime. |
3289 __ bind(&runtime); | 3248 __ bind(&runtime); |
3290 __ Push(left, right); | 3249 __ Push(left, right); |
3291 if (equality) { | 3250 if (equality) { |
3292 __ TailCallRuntime(Runtime::kStringEquals); | 3251 __ TailCallRuntime(Runtime::kStringEquals); |
3293 } else { | 3252 } else { |
3294 __ TailCallRuntime(Runtime::kStringCompare); | 3253 __ TailCallRuntime(Runtime::kStringCompare); |
3295 } | 3254 } |
3296 | 3255 |
3297 __ bind(&miss); | 3256 __ bind(&miss); |
3298 GenerateMiss(masm); | 3257 GenerateMiss(masm); |
3299 } | 3258 } |
3300 | 3259 |
3301 | |
3302 void CompareICStub::GenerateReceivers(MacroAssembler* masm) { | 3260 void CompareICStub::GenerateReceivers(MacroAssembler* masm) { |
3303 DCHECK_EQ(CompareICState::RECEIVER, state()); | 3261 DCHECK_EQ(CompareICState::RECEIVER, state()); |
3304 Label miss; | 3262 Label miss; |
3305 __ and_(r5, r4, r3); | 3263 __ AndP(r4, r3, r2); |
3306 __ JumpIfSmi(r5, &miss); | 3264 __ JumpIfSmi(r4, &miss); |
3307 | 3265 |
3308 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | 3266 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
3309 __ CompareObjectType(r3, r5, r5, FIRST_JS_RECEIVER_TYPE); | 3267 __ CompareObjectType(r2, r4, r4, FIRST_JS_RECEIVER_TYPE); |
3310 __ blt(&miss); | 3268 __ blt(&miss); |
3311 __ CompareObjectType(r4, r5, r5, FIRST_JS_RECEIVER_TYPE); | 3269 __ CompareObjectType(r3, r4, r4, FIRST_JS_RECEIVER_TYPE); |
3312 __ blt(&miss); | 3270 __ blt(&miss); |
3313 | 3271 |
3314 DCHECK(GetCondition() == eq); | 3272 DCHECK(GetCondition() == eq); |
3315 __ sub(r3, r3, r4); | 3273 __ SubP(r2, r2, r3); |
3316 __ Ret(); | 3274 __ Ret(); |
3317 | 3275 |
3318 __ bind(&miss); | 3276 __ bind(&miss); |
3319 GenerateMiss(masm); | 3277 GenerateMiss(masm); |
3320 } | 3278 } |
3321 | 3279 |
3322 | |
3323 void CompareICStub::GenerateKnownReceivers(MacroAssembler* masm) { | 3280 void CompareICStub::GenerateKnownReceivers(MacroAssembler* masm) { |
3324 Label miss; | 3281 Label miss; |
3325 Handle<WeakCell> cell = Map::WeakCellForMap(known_map_); | 3282 Handle<WeakCell> cell = Map::WeakCellForMap(known_map_); |
3326 __ and_(r5, r4, r3); | 3283 __ AndP(r4, r3, r2); |
3327 __ JumpIfSmi(r5, &miss); | 3284 __ JumpIfSmi(r4, &miss); |
3328 __ GetWeakValue(r7, cell); | 3285 __ GetWeakValue(r6, cell); |
| 3286 __ LoadP(r4, FieldMemOperand(r2, HeapObject::kMapOffset)); |
3329 __ LoadP(r5, FieldMemOperand(r3, HeapObject::kMapOffset)); | 3287 __ LoadP(r5, FieldMemOperand(r3, HeapObject::kMapOffset)); |
3330 __ LoadP(r6, FieldMemOperand(r4, HeapObject::kMapOffset)); | 3288 __ CmpP(r4, r6); |
3331 __ cmp(r5, r7); | |
3332 __ bne(&miss); | 3289 __ bne(&miss); |
3333 __ cmp(r6, r7); | 3290 __ CmpP(r5, r6); |
3334 __ bne(&miss); | 3291 __ bne(&miss); |
3335 | 3292 |
3336 if (Token::IsEqualityOp(op())) { | 3293 if (Token::IsEqualityOp(op())) { |
3337 __ sub(r3, r3, r4); | 3294 __ SubP(r2, r2, r3); |
3338 __ Ret(); | 3295 __ Ret(); |
3339 } else { | 3296 } else { |
3340 if (op() == Token::LT || op() == Token::LTE) { | 3297 if (op() == Token::LT || op() == Token::LTE) { |
3341 __ LoadSmiLiteral(r5, Smi::FromInt(GREATER)); | 3298 __ LoadSmiLiteral(r4, Smi::FromInt(GREATER)); |
3342 } else { | 3299 } else { |
3343 __ LoadSmiLiteral(r5, Smi::FromInt(LESS)); | 3300 __ LoadSmiLiteral(r4, Smi::FromInt(LESS)); |
3344 } | 3301 } |
3345 __ Push(r4, r3, r5); | 3302 __ Push(r3, r2, r4); |
3346 __ TailCallRuntime(Runtime::kCompare); | 3303 __ TailCallRuntime(Runtime::kCompare); |
3347 } | 3304 } |
3348 | 3305 |
3349 __ bind(&miss); | 3306 __ bind(&miss); |
3350 GenerateMiss(masm); | 3307 GenerateMiss(masm); |
3351 } | 3308 } |
3352 | 3309 |
3353 | |
3354 void CompareICStub::GenerateMiss(MacroAssembler* masm) { | 3310 void CompareICStub::GenerateMiss(MacroAssembler* masm) { |
3355 { | 3311 { |
3356 // Call the runtime system in a fresh internal frame. | 3312 // Call the runtime system in a fresh internal frame. |
3357 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 3313 FrameScope scope(masm, StackFrame::INTERNAL); |
3358 __ Push(r4, r3); | 3314 __ Push(r3, r2); |
3359 __ Push(r4, r3); | 3315 __ Push(r3, r2); |
3360 __ LoadSmiLiteral(r0, Smi::FromInt(op())); | 3316 __ LoadSmiLiteral(r0, Smi::FromInt(op())); |
3361 __ push(r0); | 3317 __ push(r0); |
3362 __ CallRuntime(Runtime::kCompareIC_Miss); | 3318 __ CallRuntime(Runtime::kCompareIC_Miss); |
3363 // Compute the entry point of the rewritten stub. | 3319 // Compute the entry point of the rewritten stub. |
3364 __ addi(r5, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); | 3320 __ AddP(r4, r2, Operand(Code::kHeaderSize - kHeapObjectTag)); |
3365 // Restore registers. | 3321 // Restore registers. |
3366 __ Pop(r4, r3); | 3322 __ Pop(r3, r2); |
3367 } | 3323 } |
3368 | 3324 |
3369 __ JumpToJSEntry(r5); | 3325 __ JumpToJSEntry(r4); |
3370 } | 3326 } |
3371 | 3327 |
3372 | |
3373 // This stub is paired with DirectCEntryStub::GenerateCall | 3328 // This stub is paired with DirectCEntryStub::GenerateCall |
3374 void DirectCEntryStub::Generate(MacroAssembler* masm) { | 3329 void DirectCEntryStub::Generate(MacroAssembler* masm) { |
3375 // Place the return address on the stack, making the call | 3330 __ CleanseP(r14); |
3376 // GC safe. The RegExp backend also relies on this. | 3331 |
3377 __ mflr(r0); | 3332 // Statement positions are expected to be recorded when the target |
3378 __ StoreP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize)); | 3333 // address is loaded. |
3379 __ Call(ip); // Call the C++ function. | 3334 __ positions_recorder()->WriteRecordedPositions(); |
3380 __ LoadP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize)); | 3335 |
3381 __ mtlr(r0); | 3336 __ b(ip); // Callee will return to R14 directly |
3382 __ blr(); | |
3383 } | 3337 } |
3384 | 3338 |
| 3339 void DirectCEntryStub::GenerateCall(MacroAssembler* masm, Register target) { |
| 3340 #if ABI_USES_FUNCTION_DESCRIPTORS && !defined(USE_SIMULATOR) |
| 3341 // Native AIX/S390X Linux use a function descriptor. |
| 3342 __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(target, kPointerSize)); |
| 3343 __ LoadP(target, MemOperand(target, 0)); // Instruction address |
| 3344 #else |
| 3345 // ip needs to be set for DirectCEentryStub::Generate, and also |
| 3346 // for ABI_CALL_VIA_IP. |
| 3347 __ Move(ip, target); |
| 3348 #endif |
3385 | 3349 |
3386 void DirectCEntryStub::GenerateCall(MacroAssembler* masm, Register target) { | 3350 __ call(GetCode(), RelocInfo::CODE_TARGET); // Call the stub. |
3387 if (ABI_USES_FUNCTION_DESCRIPTORS) { | |
3388 // AIX/PPC64BE Linux use a function descriptor. | |
3389 __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(target, kPointerSize)); | |
3390 __ LoadP(ip, MemOperand(target, 0)); // Instruction address | |
3391 } else { | |
3392 // ip needs to be set for DirectCEentryStub::Generate, and also | |
3393 // for ABI_CALL_VIA_IP. | |
3394 __ Move(ip, target); | |
3395 } | |
3396 | |
3397 intptr_t code = reinterpret_cast<intptr_t>(GetCode().location()); | |
3398 __ mov(r0, Operand(code, RelocInfo::CODE_TARGET)); | |
3399 __ Call(r0); // Call the stub. | |
3400 } | 3351 } |
3401 | 3352 |
3402 | |
3403 void NameDictionaryLookupStub::GenerateNegativeLookup( | 3353 void NameDictionaryLookupStub::GenerateNegativeLookup( |
3404 MacroAssembler* masm, Label* miss, Label* done, Register receiver, | 3354 MacroAssembler* masm, Label* miss, Label* done, Register receiver, |
3405 Register properties, Handle<Name> name, Register scratch0) { | 3355 Register properties, Handle<Name> name, Register scratch0) { |
3406 DCHECK(name->IsUniqueName()); | 3356 DCHECK(name->IsUniqueName()); |
3407 // If names of slots in range from 1 to kProbes - 1 for the hash value are | 3357 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
3408 // not equal to the name and kProbes-th slot is not used (its name is the | 3358 // not equal to the name and kProbes-th slot is not used (its name is the |
3409 // undefined value), it guarantees the hash table doesn't contain the | 3359 // undefined value), it guarantees the hash table doesn't contain the |
3410 // property. It's true even if some slots represent deleted properties | 3360 // property. It's true even if some slots represent deleted properties |
3411 // (their names are the hole value). | 3361 // (their names are the hole value). |
3412 for (int i = 0; i < kInlinedProbes; i++) { | 3362 for (int i = 0; i < kInlinedProbes; i++) { |
3413 // scratch0 points to properties hash. | 3363 // scratch0 points to properties hash. |
3414 // Compute the masked index: (hash + i + i * i) & mask. | 3364 // Compute the masked index: (hash + i + i * i) & mask. |
3415 Register index = scratch0; | 3365 Register index = scratch0; |
3416 // Capacity is smi 2^n. | 3366 // Capacity is smi 2^n. |
3417 __ LoadP(index, FieldMemOperand(properties, kCapacityOffset)); | 3367 __ LoadP(index, FieldMemOperand(properties, kCapacityOffset)); |
3418 __ subi(index, index, Operand(1)); | 3368 __ SubP(index, Operand(1)); |
3419 __ LoadSmiLiteral( | 3369 __ LoadSmiLiteral( |
3420 ip, Smi::FromInt(name->Hash() + NameDictionary::GetProbeOffset(i))); | 3370 ip, Smi::FromInt(name->Hash() + NameDictionary::GetProbeOffset(i))); |
3421 __ and_(index, index, ip); | 3371 __ AndP(index, ip); |
3422 | 3372 |
3423 // Scale the index by multiplying by the entry size. | 3373 // Scale the index by multiplying by the entry size. |
3424 STATIC_ASSERT(NameDictionary::kEntrySize == 3); | 3374 STATIC_ASSERT(NameDictionary::kEntrySize == 3); |
3425 __ ShiftLeftImm(ip, index, Operand(1)); | 3375 __ ShiftLeftP(ip, index, Operand(1)); |
3426 __ add(index, index, ip); // index *= 3. | 3376 __ AddP(index, ip); // index *= 3. |
3427 | 3377 |
3428 Register entity_name = scratch0; | 3378 Register entity_name = scratch0; |
3429 // Having undefined at this place means the name is not contained. | 3379 // Having undefined at this place means the name is not contained. |
3430 Register tmp = properties; | 3380 Register tmp = properties; |
3431 __ SmiToPtrArrayOffset(ip, index); | 3381 __ SmiToPtrArrayOffset(ip, index); |
3432 __ add(tmp, properties, ip); | 3382 __ AddP(tmp, properties, ip); |
3433 __ LoadP(entity_name, FieldMemOperand(tmp, kElementsStartOffset)); | 3383 __ LoadP(entity_name, FieldMemOperand(tmp, kElementsStartOffset)); |
3434 | 3384 |
3435 DCHECK(!tmp.is(entity_name)); | 3385 DCHECK(!tmp.is(entity_name)); |
3436 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex); | 3386 __ CompareRoot(entity_name, Heap::kUndefinedValueRootIndex); |
3437 __ cmp(entity_name, tmp); | |
3438 __ beq(done); | 3387 __ beq(done); |
3439 | 3388 |
3440 // Load the hole ready for use below: | |
3441 __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex); | |
3442 | |
3443 // Stop if found the property. | 3389 // Stop if found the property. |
3444 __ Cmpi(entity_name, Operand(Handle<Name>(name)), r0); | 3390 __ CmpP(entity_name, Operand(Handle<Name>(name))); |
3445 __ beq(miss); | 3391 __ beq(miss); |
3446 | 3392 |
3447 Label good; | 3393 Label good; |
3448 __ cmp(entity_name, tmp); | 3394 __ CompareRoot(entity_name, Heap::kTheHoleValueRootIndex); |
3449 __ beq(&good); | 3395 __ beq(&good); |
3450 | 3396 |
3451 // Check if the entry name is not a unique name. | 3397 // Check if the entry name is not a unique name. |
3452 __ LoadP(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); | 3398 __ LoadP(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); |
3453 __ lbz(entity_name, FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); | 3399 __ LoadlB(entity_name, |
| 3400 FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); |
3454 __ JumpIfNotUniqueNameInstanceType(entity_name, miss); | 3401 __ JumpIfNotUniqueNameInstanceType(entity_name, miss); |
3455 __ bind(&good); | 3402 __ bind(&good); |
3456 | 3403 |
3457 // Restore the properties. | 3404 // Restore the properties. |
3458 __ LoadP(properties, | 3405 __ LoadP(properties, |
3459 FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 3406 FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
3460 } | 3407 } |
3461 | 3408 |
3462 const int spill_mask = (r0.bit() | r9.bit() | r8.bit() | r7.bit() | r6.bit() | | 3409 const int spill_mask = (r0.bit() | r8.bit() | r7.bit() | r6.bit() | r5.bit() | |
3463 r5.bit() | r4.bit() | r3.bit()); | 3410 r4.bit() | r3.bit() | r2.bit()); |
3464 | 3411 |
3465 __ mflr(r0); | 3412 __ LoadRR(r0, r14); |
3466 __ MultiPush(spill_mask); | 3413 __ MultiPush(spill_mask); |
3467 | 3414 |
3468 __ LoadP(r3, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 3415 __ LoadP(r2, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
3469 __ mov(r4, Operand(Handle<Name>(name))); | 3416 __ mov(r3, Operand(Handle<Name>(name))); |
3470 NameDictionaryLookupStub stub(masm->isolate(), NEGATIVE_LOOKUP); | 3417 NameDictionaryLookupStub stub(masm->isolate(), NEGATIVE_LOOKUP); |
3471 __ CallStub(&stub); | 3418 __ CallStub(&stub); |
3472 __ cmpi(r3, Operand::Zero()); | 3419 __ CmpP(r2, Operand::Zero()); |
3473 | 3420 |
3474 __ MultiPop(spill_mask); // MultiPop does not touch condition flags | 3421 __ MultiPop(spill_mask); // MultiPop does not touch condition flags |
3475 __ mtlr(r0); | 3422 __ LoadRR(r14, r0); |
3476 | 3423 |
3477 __ beq(done); | 3424 __ beq(done); |
3478 __ bne(miss); | 3425 __ bne(miss); |
3479 } | 3426 } |
3480 | 3427 |
3481 | |
3482 // Probe the name dictionary in the |elements| register. Jump to the | 3428 // Probe the name dictionary in the |elements| register. Jump to the |
3483 // |done| label if a property with the given name is found. Jump to | 3429 // |done| label if a property with the given name is found. Jump to |
3484 // the |miss| label otherwise. | 3430 // the |miss| label otherwise. |
3485 // If lookup was successful |scratch2| will be equal to elements + 4 * index. | 3431 // If lookup was successful |scratch2| will be equal to elements + 4 * index. |
3486 void NameDictionaryLookupStub::GeneratePositiveLookup( | 3432 void NameDictionaryLookupStub::GeneratePositiveLookup( |
3487 MacroAssembler* masm, Label* miss, Label* done, Register elements, | 3433 MacroAssembler* masm, Label* miss, Label* done, Register elements, |
3488 Register name, Register scratch1, Register scratch2) { | 3434 Register name, Register scratch1, Register scratch2) { |
3489 DCHECK(!elements.is(scratch1)); | 3435 DCHECK(!elements.is(scratch1)); |
3490 DCHECK(!elements.is(scratch2)); | 3436 DCHECK(!elements.is(scratch2)); |
3491 DCHECK(!name.is(scratch1)); | 3437 DCHECK(!name.is(scratch1)); |
3492 DCHECK(!name.is(scratch2)); | 3438 DCHECK(!name.is(scratch2)); |
3493 | 3439 |
3494 __ AssertName(name); | 3440 __ AssertName(name); |
3495 | 3441 |
3496 // Compute the capacity mask. | 3442 // Compute the capacity mask. |
3497 __ LoadP(scratch1, FieldMemOperand(elements, kCapacityOffset)); | 3443 __ LoadP(scratch1, FieldMemOperand(elements, kCapacityOffset)); |
3498 __ SmiUntag(scratch1); // convert smi to int | 3444 __ SmiUntag(scratch1); // convert smi to int |
3499 __ subi(scratch1, scratch1, Operand(1)); | 3445 __ SubP(scratch1, Operand(1)); |
3500 | 3446 |
3501 // Generate an unrolled loop that performs a few probes before | 3447 // Generate an unrolled loop that performs a few probes before |
3502 // giving up. Measurements done on Gmail indicate that 2 probes | 3448 // giving up. Measurements done on Gmail indicate that 2 probes |
3503 // cover ~93% of loads from dictionaries. | 3449 // cover ~93% of loads from dictionaries. |
3504 for (int i = 0; i < kInlinedProbes; i++) { | 3450 for (int i = 0; i < kInlinedProbes; i++) { |
3505 // Compute the masked index: (hash + i + i * i) & mask. | 3451 // Compute the masked index: (hash + i + i * i) & mask. |
3506 __ lwz(scratch2, FieldMemOperand(name, Name::kHashFieldOffset)); | 3452 __ LoadlW(scratch2, FieldMemOperand(name, String::kHashFieldOffset)); |
3507 if (i > 0) { | 3453 if (i > 0) { |
3508 // Add the probe offset (i + i * i) left shifted to avoid right shifting | 3454 // Add the probe offset (i + i * i) left shifted to avoid right shifting |
3509 // the hash in a separate instruction. The value hash + i + i * i is right | 3455 // the hash in a separate instruction. The value hash + i + i * i is right |
3510 // shifted in the following and instruction. | 3456 // shifted in the following and instruction. |
3511 DCHECK(NameDictionary::GetProbeOffset(i) < | 3457 DCHECK(NameDictionary::GetProbeOffset(i) < |
3512 1 << (32 - Name::kHashFieldOffset)); | 3458 1 << (32 - Name::kHashFieldOffset)); |
3513 __ addi(scratch2, scratch2, | 3459 __ AddP(scratch2, |
3514 Operand(NameDictionary::GetProbeOffset(i) << Name::kHashShift)); | 3460 Operand(NameDictionary::GetProbeOffset(i) << Name::kHashShift)); |
3515 } | 3461 } |
3516 __ srwi(scratch2, scratch2, Operand(Name::kHashShift)); | 3462 __ srl(scratch2, Operand(String::kHashShift)); |
3517 __ and_(scratch2, scratch1, scratch2); | 3463 __ AndP(scratch2, scratch1); |
3518 | 3464 |
3519 // Scale the index by multiplying by the entry size. | 3465 // Scale the index by multiplying by the entry size. |
3520 STATIC_ASSERT(NameDictionary::kEntrySize == 3); | 3466 STATIC_ASSERT(NameDictionary::kEntrySize == 3); |
3521 // scratch2 = scratch2 * 3. | 3467 // scratch2 = scratch2 * 3. |
3522 __ ShiftLeftImm(ip, scratch2, Operand(1)); | 3468 __ ShiftLeftP(ip, scratch2, Operand(1)); |
3523 __ add(scratch2, scratch2, ip); | 3469 __ AddP(scratch2, ip); |
3524 | 3470 |
3525 // Check if the key is identical to the name. | 3471 // Check if the key is identical to the name. |
3526 __ ShiftLeftImm(ip, scratch2, Operand(kPointerSizeLog2)); | 3472 __ ShiftLeftP(ip, scratch2, Operand(kPointerSizeLog2)); |
3527 __ add(scratch2, elements, ip); | 3473 __ AddP(scratch2, elements, ip); |
3528 __ LoadP(ip, FieldMemOperand(scratch2, kElementsStartOffset)); | 3474 __ LoadP(ip, FieldMemOperand(scratch2, kElementsStartOffset)); |
3529 __ cmp(name, ip); | 3475 __ CmpP(name, ip); |
3530 __ beq(done); | 3476 __ beq(done); |
3531 } | 3477 } |
3532 | 3478 |
3533 const int spill_mask = (r0.bit() | r9.bit() | r8.bit() | r7.bit() | r6.bit() | | 3479 const int spill_mask = (r0.bit() | r8.bit() | r7.bit() | r6.bit() | r5.bit() | |
3534 r5.bit() | r4.bit() | r3.bit()) & | 3480 r4.bit() | r3.bit() | r2.bit()) & |
3535 ~(scratch1.bit() | scratch2.bit()); | 3481 ~(scratch1.bit() | scratch2.bit()); |
3536 | 3482 |
3537 __ mflr(r0); | 3483 __ LoadRR(r0, r14); |
3538 __ MultiPush(spill_mask); | 3484 __ MultiPush(spill_mask); |
3539 if (name.is(r3)) { | 3485 if (name.is(r2)) { |
3540 DCHECK(!elements.is(r4)); | 3486 DCHECK(!elements.is(r3)); |
3541 __ mr(r4, name); | 3487 __ LoadRR(r3, name); |
3542 __ mr(r3, elements); | 3488 __ LoadRR(r2, elements); |
3543 } else { | 3489 } else { |
3544 __ mr(r3, elements); | 3490 __ LoadRR(r2, elements); |
3545 __ mr(r4, name); | 3491 __ LoadRR(r3, name); |
3546 } | 3492 } |
3547 NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP); | 3493 NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP); |
3548 __ CallStub(&stub); | 3494 __ CallStub(&stub); |
3549 __ cmpi(r3, Operand::Zero()); | 3495 __ LoadRR(r1, r2); |
3550 __ mr(scratch2, r5); | 3496 __ LoadRR(scratch2, r4); |
3551 __ MultiPop(spill_mask); | 3497 __ MultiPop(spill_mask); |
3552 __ mtlr(r0); | 3498 __ LoadRR(r14, r0); |
3553 | 3499 |
| 3500 __ CmpP(r1, Operand::Zero()); |
3554 __ bne(done); | 3501 __ bne(done); |
3555 __ beq(miss); | 3502 __ beq(miss); |
3556 } | 3503 } |
3557 | 3504 |
3558 | |
3559 void NameDictionaryLookupStub::Generate(MacroAssembler* masm) { | 3505 void NameDictionaryLookupStub::Generate(MacroAssembler* masm) { |
3560 // This stub overrides SometimesSetsUpAFrame() to return false. That means | 3506 // This stub overrides SometimesSetsUpAFrame() to return false. That means |
3561 // we cannot call anything that could cause a GC from this stub. | 3507 // we cannot call anything that could cause a GC from this stub. |
3562 // Registers: | 3508 // Registers: |
3563 // result: NameDictionary to probe | 3509 // result: NameDictionary to probe |
3564 // r4: key | 3510 // r3: key |
3565 // dictionary: NameDictionary to probe. | 3511 // dictionary: NameDictionary to probe. |
3566 // index: will hold an index of entry if lookup is successful. | 3512 // index: will hold an index of entry if lookup is successful. |
3567 // might alias with result_. | 3513 // might alias with result_. |
3568 // Returns: | 3514 // Returns: |
3569 // result_ is zero if lookup failed, non zero otherwise. | 3515 // result_ is zero if lookup failed, non zero otherwise. |
3570 | 3516 |
3571 Register result = r3; | 3517 Register result = r2; |
3572 Register dictionary = r3; | 3518 Register dictionary = r2; |
3573 Register key = r4; | 3519 Register key = r3; |
3574 Register index = r5; | 3520 Register index = r4; |
3575 Register mask = r6; | 3521 Register mask = r5; |
3576 Register hash = r7; | 3522 Register hash = r6; |
3577 Register undefined = r8; | 3523 Register undefined = r7; |
3578 Register entry_key = r9; | 3524 Register entry_key = r8; |
3579 Register scratch = r9; | 3525 Register scratch = r8; |
3580 | 3526 |
3581 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; | 3527 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; |
3582 | 3528 |
3583 __ LoadP(mask, FieldMemOperand(dictionary, kCapacityOffset)); | 3529 __ LoadP(mask, FieldMemOperand(dictionary, kCapacityOffset)); |
3584 __ SmiUntag(mask); | 3530 __ SmiUntag(mask); |
3585 __ subi(mask, mask, Operand(1)); | 3531 __ SubP(mask, Operand(1)); |
3586 | 3532 |
3587 __ lwz(hash, FieldMemOperand(key, Name::kHashFieldOffset)); | 3533 __ LoadlW(hash, FieldMemOperand(key, String::kHashFieldOffset)); |
3588 | 3534 |
3589 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); | 3535 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); |
3590 | 3536 |
3591 for (int i = kInlinedProbes; i < kTotalProbes; i++) { | 3537 for (int i = kInlinedProbes; i < kTotalProbes; i++) { |
3592 // Compute the masked index: (hash + i + i * i) & mask. | 3538 // Compute the masked index: (hash + i + i * i) & mask. |
3593 // Capacity is smi 2^n. | 3539 // Capacity is smi 2^n. |
3594 if (i > 0) { | 3540 if (i > 0) { |
3595 // Add the probe offset (i + i * i) left shifted to avoid right shifting | 3541 // Add the probe offset (i + i * i) left shifted to avoid right shifting |
3596 // the hash in a separate instruction. The value hash + i + i * i is right | 3542 // the hash in a separate instruction. The value hash + i + i * i is right |
3597 // shifted in the following and instruction. | 3543 // shifted in the following and instruction. |
3598 DCHECK(NameDictionary::GetProbeOffset(i) < | 3544 DCHECK(NameDictionary::GetProbeOffset(i) < |
3599 1 << (32 - Name::kHashFieldOffset)); | 3545 1 << (32 - Name::kHashFieldOffset)); |
3600 __ addi(index, hash, | 3546 __ AddP(index, hash, |
3601 Operand(NameDictionary::GetProbeOffset(i) << Name::kHashShift)); | 3547 Operand(NameDictionary::GetProbeOffset(i) << Name::kHashShift)); |
3602 } else { | 3548 } else { |
3603 __ mr(index, hash); | 3549 __ LoadRR(index, hash); |
3604 } | 3550 } |
3605 __ srwi(r0, index, Operand(Name::kHashShift)); | 3551 __ ShiftRight(r0, index, Operand(String::kHashShift)); |
3606 __ and_(index, mask, r0); | 3552 __ AndP(index, r0, mask); |
3607 | 3553 |
3608 // Scale the index by multiplying by the entry size. | 3554 // Scale the index by multiplying by the entry size. |
3609 STATIC_ASSERT(NameDictionary::kEntrySize == 3); | 3555 STATIC_ASSERT(NameDictionary::kEntrySize == 3); |
3610 __ ShiftLeftImm(scratch, index, Operand(1)); | 3556 __ ShiftLeftP(scratch, index, Operand(1)); |
3611 __ add(index, index, scratch); // index *= 3. | 3557 __ AddP(index, scratch); // index *= 3. |
3612 | 3558 |
3613 __ ShiftLeftImm(scratch, index, Operand(kPointerSizeLog2)); | 3559 __ ShiftLeftP(scratch, index, Operand(kPointerSizeLog2)); |
3614 __ add(index, dictionary, scratch); | 3560 __ AddP(index, dictionary, scratch); |
3615 __ LoadP(entry_key, FieldMemOperand(index, kElementsStartOffset)); | 3561 __ LoadP(entry_key, FieldMemOperand(index, kElementsStartOffset)); |
3616 | 3562 |
3617 // Having undefined at this place means the name is not contained. | 3563 // Having undefined at this place means the name is not contained. |
3618 __ cmp(entry_key, undefined); | 3564 __ CmpP(entry_key, undefined); |
3619 __ beq(¬_in_dictionary); | 3565 __ beq(¬_in_dictionary); |
3620 | 3566 |
3621 // Stop if found the property. | 3567 // Stop if found the property. |
3622 __ cmp(entry_key, key); | 3568 __ CmpP(entry_key, key); |
3623 __ beq(&in_dictionary); | 3569 __ beq(&in_dictionary); |
3624 | 3570 |
3625 if (i != kTotalProbes - 1 && mode() == NEGATIVE_LOOKUP) { | 3571 if (i != kTotalProbes - 1 && mode() == NEGATIVE_LOOKUP) { |
3626 // Check if the entry name is not a unique name. | 3572 // Check if the entry name is not a unique name. |
3627 __ LoadP(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset)); | 3573 __ LoadP(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset)); |
3628 __ lbz(entry_key, FieldMemOperand(entry_key, Map::kInstanceTypeOffset)); | 3574 __ LoadlB(entry_key, |
| 3575 FieldMemOperand(entry_key, Map::kInstanceTypeOffset)); |
3629 __ JumpIfNotUniqueNameInstanceType(entry_key, &maybe_in_dictionary); | 3576 __ JumpIfNotUniqueNameInstanceType(entry_key, &maybe_in_dictionary); |
3630 } | 3577 } |
3631 } | 3578 } |
3632 | 3579 |
3633 __ bind(&maybe_in_dictionary); | 3580 __ bind(&maybe_in_dictionary); |
3634 // If we are doing negative lookup then probing failure should be | 3581 // If we are doing negative lookup then probing failure should be |
3635 // treated as a lookup success. For positive lookup probing failure | 3582 // treated as a lookup success. For positive lookup probing failure |
3636 // should be treated as lookup failure. | 3583 // should be treated as lookup failure. |
3637 if (mode() == POSITIVE_LOOKUP) { | 3584 if (mode() == POSITIVE_LOOKUP) { |
3638 __ li(result, Operand::Zero()); | 3585 __ LoadImmP(result, Operand::Zero()); |
3639 __ Ret(); | 3586 __ Ret(); |
3640 } | 3587 } |
3641 | 3588 |
3642 __ bind(&in_dictionary); | 3589 __ bind(&in_dictionary); |
3643 __ li(result, Operand(1)); | 3590 __ LoadImmP(result, Operand(1)); |
3644 __ Ret(); | 3591 __ Ret(); |
3645 | 3592 |
3646 __ bind(¬_in_dictionary); | 3593 __ bind(¬_in_dictionary); |
3647 __ li(result, Operand::Zero()); | 3594 __ LoadImmP(result, Operand::Zero()); |
3648 __ Ret(); | 3595 __ Ret(); |
3649 } | 3596 } |
3650 | 3597 |
3651 | |
3652 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( | 3598 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( |
3653 Isolate* isolate) { | 3599 Isolate* isolate) { |
3654 StoreBufferOverflowStub stub1(isolate, kDontSaveFPRegs); | 3600 StoreBufferOverflowStub stub1(isolate, kDontSaveFPRegs); |
3655 stub1.GetCode(); | 3601 stub1.GetCode(); |
3656 // Hydrogen code stubs need stub2 at snapshot time. | 3602 // Hydrogen code stubs need stub2 at snapshot time. |
3657 StoreBufferOverflowStub stub2(isolate, kSaveFPRegs); | 3603 StoreBufferOverflowStub stub2(isolate, kSaveFPRegs); |
3658 stub2.GetCode(); | 3604 stub2.GetCode(); |
3659 } | 3605 } |
3660 | 3606 |
3661 | |
3662 // Takes the input in 3 registers: address_ value_ and object_. A pointer to | 3607 // Takes the input in 3 registers: address_ value_ and object_. A pointer to |
3663 // the value has just been written into the object, now this stub makes sure | 3608 // the value has just been written into the object, now this stub makes sure |
3664 // we keep the GC informed. The word in the object where the value has been | 3609 // we keep the GC informed. The word in the object where the value has been |
3665 // written is in the address register. | 3610 // written is in the address register. |
3666 void RecordWriteStub::Generate(MacroAssembler* masm) { | 3611 void RecordWriteStub::Generate(MacroAssembler* masm) { |
3667 Label skip_to_incremental_noncompacting; | 3612 Label skip_to_incremental_noncompacting; |
3668 Label skip_to_incremental_compacting; | 3613 Label skip_to_incremental_compacting; |
3669 | 3614 |
3670 // The first two branch instructions are generated with labels so as to | 3615 // The first two branch instructions are generated with labels so as to |
3671 // get the offset fixed up correctly by the bind(Label*) call. We patch | 3616 // get the offset fixed up correctly by the bind(Label*) call. We patch |
3672 // it back and forth between branch condition True and False | 3617 // it back and forth between branch condition True and False |
3673 // when we start and stop incremental heap marking. | 3618 // when we start and stop incremental heap marking. |
3674 // See RecordWriteStub::Patch for details. | 3619 // See RecordWriteStub::Patch for details. |
3675 | 3620 |
3676 // Clear the bit, branch on True for NOP action initially | 3621 // Clear the bit, branch on True for NOP action initially |
3677 __ crclr(Assembler::encode_crbit(cr2, CR_LT)); | 3622 __ b(CC_NOP, &skip_to_incremental_noncompacting); |
3678 __ blt(&skip_to_incremental_noncompacting, cr2); | 3623 __ b(CC_NOP, &skip_to_incremental_compacting); |
3679 __ blt(&skip_to_incremental_compacting, cr2); | |
3680 | 3624 |
3681 if (remembered_set_action() == EMIT_REMEMBERED_SET) { | 3625 if (remembered_set_action() == EMIT_REMEMBERED_SET) { |
3682 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), | 3626 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), |
3683 MacroAssembler::kReturnAtEnd); | 3627 MacroAssembler::kReturnAtEnd); |
3684 } | 3628 } |
3685 __ Ret(); | 3629 __ Ret(); |
3686 | 3630 |
3687 __ bind(&skip_to_incremental_noncompacting); | 3631 __ bind(&skip_to_incremental_noncompacting); |
3688 GenerateIncremental(masm, INCREMENTAL); | 3632 GenerateIncremental(masm, INCREMENTAL); |
3689 | 3633 |
3690 __ bind(&skip_to_incremental_compacting); | 3634 __ bind(&skip_to_incremental_compacting); |
3691 GenerateIncremental(masm, INCREMENTAL_COMPACTION); | 3635 GenerateIncremental(masm, INCREMENTAL_COMPACTION); |
3692 | 3636 |
3693 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY. | 3637 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY. |
3694 // Will be checked in IncrementalMarking::ActivateGeneratedStub. | 3638 // Will be checked in IncrementalMarking::ActivateGeneratedStub. |
3695 // patching not required on PPC as the initial path is effectively NOP | 3639 // patching not required on S390 as the initial path is effectively NOP |
3696 } | 3640 } |
3697 | 3641 |
3698 | |
3699 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { | 3642 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { |
3700 regs_.Save(masm); | 3643 regs_.Save(masm); |
3701 | 3644 |
3702 if (remembered_set_action() == EMIT_REMEMBERED_SET) { | 3645 if (remembered_set_action() == EMIT_REMEMBERED_SET) { |
3703 Label dont_need_remembered_set; | 3646 Label dont_need_remembered_set; |
3704 | 3647 |
3705 __ LoadP(regs_.scratch0(), MemOperand(regs_.address(), 0)); | 3648 __ LoadP(regs_.scratch0(), MemOperand(regs_.address(), 0)); |
3706 __ JumpIfNotInNewSpace(regs_.scratch0(), // Value. | 3649 __ JumpIfNotInNewSpace(regs_.scratch0(), // Value. |
3707 regs_.scratch0(), &dont_need_remembered_set); | 3650 regs_.scratch0(), &dont_need_remembered_set); |
3708 | 3651 |
(...skipping 12 matching lines...) Expand all Loading... |
3721 __ bind(&dont_need_remembered_set); | 3664 __ bind(&dont_need_remembered_set); |
3722 } | 3665 } |
3723 | 3666 |
3724 CheckNeedsToInformIncrementalMarker( | 3667 CheckNeedsToInformIncrementalMarker( |
3725 masm, kReturnOnNoNeedToInformIncrementalMarker, mode); | 3668 masm, kReturnOnNoNeedToInformIncrementalMarker, mode); |
3726 InformIncrementalMarker(masm); | 3669 InformIncrementalMarker(masm); |
3727 regs_.Restore(masm); | 3670 regs_.Restore(masm); |
3728 __ Ret(); | 3671 __ Ret(); |
3729 } | 3672 } |
3730 | 3673 |
3731 | |
3732 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) { | 3674 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) { |
3733 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode()); | 3675 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode()); |
3734 int argument_count = 3; | 3676 int argument_count = 3; |
3735 __ PrepareCallCFunction(argument_count, regs_.scratch0()); | 3677 __ PrepareCallCFunction(argument_count, regs_.scratch0()); |
3736 Register address = | 3678 Register address = |
3737 r3.is(regs_.address()) ? regs_.scratch0() : regs_.address(); | 3679 r2.is(regs_.address()) ? regs_.scratch0() : regs_.address(); |
3738 DCHECK(!address.is(regs_.object())); | 3680 DCHECK(!address.is(regs_.object())); |
3739 DCHECK(!address.is(r3)); | 3681 DCHECK(!address.is(r2)); |
3740 __ mr(address, regs_.address()); | 3682 __ LoadRR(address, regs_.address()); |
3741 __ mr(r3, regs_.object()); | 3683 __ LoadRR(r2, regs_.object()); |
3742 __ mr(r4, address); | 3684 __ LoadRR(r3, address); |
3743 __ mov(r5, Operand(ExternalReference::isolate_address(isolate()))); | 3685 __ mov(r4, Operand(ExternalReference::isolate_address(isolate()))); |
3744 | 3686 |
3745 AllowExternalCallThatCantCauseGC scope(masm); | 3687 AllowExternalCallThatCantCauseGC scope(masm); |
3746 __ CallCFunction( | 3688 __ CallCFunction( |
3747 ExternalReference::incremental_marking_record_write_function(isolate()), | 3689 ExternalReference::incremental_marking_record_write_function(isolate()), |
3748 argument_count); | 3690 argument_count); |
3749 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode()); | 3691 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode()); |
3750 } | 3692 } |
3751 | 3693 |
3752 | |
3753 void RecordWriteStub::CheckNeedsToInformIncrementalMarker( | 3694 void RecordWriteStub::CheckNeedsToInformIncrementalMarker( |
3754 MacroAssembler* masm, OnNoNeedToInformIncrementalMarker on_no_need, | 3695 MacroAssembler* masm, OnNoNeedToInformIncrementalMarker on_no_need, |
3755 Mode mode) { | 3696 Mode mode) { |
3756 Label on_black; | 3697 Label on_black; |
3757 Label need_incremental; | 3698 Label need_incremental; |
3758 Label need_incremental_pop_scratch; | 3699 Label need_incremental_pop_scratch; |
3759 | 3700 |
3760 DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0); | 3701 DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0); |
3761 __ lis(r0, Operand((~Page::kPageAlignmentMask >> 16))); | 3702 __ AndP(regs_.scratch0(), regs_.object(), Operand(~Page::kPageAlignmentMask)); |
3762 __ and_(regs_.scratch0(), regs_.object(), r0); | |
3763 __ LoadP( | 3703 __ LoadP( |
3764 regs_.scratch1(), | 3704 regs_.scratch1(), |
3765 MemOperand(regs_.scratch0(), MemoryChunk::kWriteBarrierCounterOffset)); | 3705 MemOperand(regs_.scratch0(), MemoryChunk::kWriteBarrierCounterOffset)); |
3766 __ subi(regs_.scratch1(), regs_.scratch1(), Operand(1)); | 3706 __ SubP(regs_.scratch1(), regs_.scratch1(), Operand(1)); |
3767 __ StoreP( | 3707 __ StoreP( |
3768 regs_.scratch1(), | 3708 regs_.scratch1(), |
3769 MemOperand(regs_.scratch0(), MemoryChunk::kWriteBarrierCounterOffset)); | 3709 MemOperand(regs_.scratch0(), MemoryChunk::kWriteBarrierCounterOffset)); |
3770 __ cmpi(regs_.scratch1(), Operand::Zero()); // PPC, we could do better here | 3710 __ CmpP(regs_.scratch1(), Operand::Zero()); // S390, we could do better here |
3771 __ blt(&need_incremental); | 3711 __ blt(&need_incremental); |
3772 | 3712 |
3773 // Let's look at the color of the object: If it is not black we don't have | 3713 // Let's look at the color of the object: If it is not black we don't have |
3774 // to inform the incremental marker. | 3714 // to inform the incremental marker. |
3775 __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black); | 3715 __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black); |
3776 | 3716 |
3777 regs_.Restore(masm); | 3717 regs_.Restore(masm); |
3778 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { | 3718 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { |
3779 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), | 3719 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), |
3780 MacroAssembler::kReturnAtEnd); | 3720 MacroAssembler::kReturnAtEnd); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3822 } | 3762 } |
3823 | 3763 |
3824 __ bind(&need_incremental_pop_scratch); | 3764 __ bind(&need_incremental_pop_scratch); |
3825 __ Pop(regs_.object(), regs_.address()); | 3765 __ Pop(regs_.object(), regs_.address()); |
3826 | 3766 |
3827 __ bind(&need_incremental); | 3767 __ bind(&need_incremental); |
3828 | 3768 |
3829 // Fall through when we need to inform the incremental marker. | 3769 // Fall through when we need to inform the incremental marker. |
3830 } | 3770 } |
3831 | 3771 |
3832 | |
3833 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { | 3772 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { |
3834 CEntryStub ces(isolate(), 1, kSaveFPRegs); | 3773 CEntryStub ces(isolate(), 1, kSaveFPRegs); |
3835 __ Call(ces.GetCode(), RelocInfo::CODE_TARGET); | 3774 __ Call(ces.GetCode(), RelocInfo::CODE_TARGET); |
3836 int parameter_count_offset = | 3775 int parameter_count_offset = |
3837 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; | 3776 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; |
3838 __ LoadP(r4, MemOperand(fp, parameter_count_offset)); | 3777 __ LoadP(r3, MemOperand(fp, parameter_count_offset)); |
3839 if (function_mode() == JS_FUNCTION_STUB_MODE) { | 3778 if (function_mode() == JS_FUNCTION_STUB_MODE) { |
3840 __ addi(r4, r4, Operand(1)); | 3779 __ AddP(r3, Operand(1)); |
3841 } | 3780 } |
3842 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); | 3781 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); |
3843 __ slwi(r4, r4, Operand(kPointerSizeLog2)); | 3782 __ ShiftLeftP(r3, r3, Operand(kPointerSizeLog2)); |
3844 __ add(sp, sp, r4); | 3783 __ la(sp, MemOperand(r3, sp)); |
3845 __ Ret(); | 3784 __ Ret(); |
3846 } | 3785 } |
3847 | 3786 |
3848 | |
3849 void LoadICTrampolineStub::Generate(MacroAssembler* masm) { | 3787 void LoadICTrampolineStub::Generate(MacroAssembler* masm) { |
3850 __ EmitLoadTypeFeedbackVector(LoadWithVectorDescriptor::VectorRegister()); | 3788 __ EmitLoadTypeFeedbackVector(LoadWithVectorDescriptor::VectorRegister()); |
3851 LoadICStub stub(isolate(), state()); | 3789 LoadICStub stub(isolate(), state()); |
3852 stub.GenerateForTrampoline(masm); | 3790 stub.GenerateForTrampoline(masm); |
3853 } | 3791 } |
3854 | 3792 |
3855 | |
3856 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { | 3793 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { |
3857 __ EmitLoadTypeFeedbackVector(LoadWithVectorDescriptor::VectorRegister()); | 3794 __ EmitLoadTypeFeedbackVector(LoadWithVectorDescriptor::VectorRegister()); |
3858 KeyedLoadICStub stub(isolate(), state()); | 3795 KeyedLoadICStub stub(isolate(), state()); |
3859 stub.GenerateForTrampoline(masm); | 3796 stub.GenerateForTrampoline(masm); |
3860 } | 3797 } |
3861 | 3798 |
3862 | |
3863 void CallICTrampolineStub::Generate(MacroAssembler* masm) { | 3799 void CallICTrampolineStub::Generate(MacroAssembler* masm) { |
3864 __ EmitLoadTypeFeedbackVector(r5); | 3800 __ EmitLoadTypeFeedbackVector(r4); |
3865 CallICStub stub(isolate(), state()); | 3801 CallICStub stub(isolate(), state()); |
3866 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 3802 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
3867 } | 3803 } |
3868 | 3804 |
3869 | |
3870 void LoadICStub::Generate(MacroAssembler* masm) { GenerateImpl(masm, false); } | 3805 void LoadICStub::Generate(MacroAssembler* masm) { GenerateImpl(masm, false); } |
3871 | 3806 |
3872 | |
3873 void LoadICStub::GenerateForTrampoline(MacroAssembler* masm) { | 3807 void LoadICStub::GenerateForTrampoline(MacroAssembler* masm) { |
3874 GenerateImpl(masm, true); | 3808 GenerateImpl(masm, true); |
3875 } | 3809 } |
3876 | 3810 |
3877 | |
3878 static void HandleArrayCases(MacroAssembler* masm, Register feedback, | 3811 static void HandleArrayCases(MacroAssembler* masm, Register feedback, |
3879 Register receiver_map, Register scratch1, | 3812 Register receiver_map, Register scratch1, |
3880 Register scratch2, bool is_polymorphic, | 3813 Register scratch2, bool is_polymorphic, |
3881 Label* miss) { | 3814 Label* miss) { |
3882 // feedback initially contains the feedback array | 3815 // feedback initially contains the feedback array |
3883 Label next_loop, prepare_next; | 3816 Label next_loop, prepare_next; |
3884 Label start_polymorphic; | 3817 Label start_polymorphic; |
3885 | 3818 |
3886 Register cached_map = scratch1; | 3819 Register cached_map = scratch1; |
3887 | 3820 |
3888 __ LoadP(cached_map, | 3821 __ LoadP(cached_map, |
3889 FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0))); | 3822 FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0))); |
3890 __ LoadP(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset)); | 3823 __ LoadP(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset)); |
3891 __ cmp(receiver_map, cached_map); | 3824 __ CmpP(receiver_map, cached_map); |
3892 __ bne(&start_polymorphic); | 3825 __ bne(&start_polymorphic, Label::kNear); |
3893 // found, now call handler. | 3826 // found, now call handler. |
3894 Register handler = feedback; | 3827 Register handler = feedback; |
3895 __ LoadP(handler, | 3828 __ LoadP(handler, |
3896 FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1))); | 3829 FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1))); |
3897 __ addi(ip, handler, Operand(Code::kHeaderSize - kHeapObjectTag)); | 3830 __ AddP(ip, handler, Operand(Code::kHeaderSize - kHeapObjectTag)); |
3898 __ Jump(ip); | 3831 __ Jump(ip); |
3899 | 3832 |
3900 | |
3901 Register length = scratch2; | 3833 Register length = scratch2; |
3902 __ bind(&start_polymorphic); | 3834 __ bind(&start_polymorphic); |
3903 __ LoadP(length, FieldMemOperand(feedback, FixedArray::kLengthOffset)); | 3835 __ LoadP(length, FieldMemOperand(feedback, FixedArray::kLengthOffset)); |
3904 if (!is_polymorphic) { | 3836 if (!is_polymorphic) { |
3905 // If the IC could be monomorphic we have to make sure we don't go past the | 3837 // If the IC could be monomorphic we have to make sure we don't go past the |
3906 // end of the feedback array. | 3838 // end of the feedback array. |
3907 __ CmpSmiLiteral(length, Smi::FromInt(2), r0); | 3839 __ CmpSmiLiteral(length, Smi::FromInt(2), r0); |
3908 __ beq(miss); | 3840 __ beq(miss); |
3909 } | 3841 } |
3910 | 3842 |
3911 Register too_far = length; | 3843 Register too_far = length; |
3912 Register pointer_reg = feedback; | 3844 Register pointer_reg = feedback; |
3913 | 3845 |
3914 // +-----+------+------+-----+-----+ ... ----+ | 3846 // +-----+------+------+-----+-----+ ... ----+ |
3915 // | map | len | wm0 | h0 | wm1 | hN | | 3847 // | map | len | wm0 | h0 | wm1 | hN | |
3916 // +-----+------+------+-----+-----+ ... ----+ | 3848 // +-----+------+------+-----+-----+ ... ----+ |
3917 // 0 1 2 len-1 | 3849 // 0 1 2 len-1 |
3918 // ^ ^ | 3850 // ^ ^ |
3919 // | | | 3851 // | | |
3920 // pointer_reg too_far | 3852 // pointer_reg too_far |
3921 // aka feedback scratch2 | 3853 // aka feedback scratch2 |
3922 // also need receiver_map | 3854 // also need receiver_map |
3923 // use cached_map (scratch1) to look in the weak map values. | 3855 // use cached_map (scratch1) to look in the weak map values. |
3924 __ SmiToPtrArrayOffset(r0, length); | 3856 __ SmiToPtrArrayOffset(r0, length); |
3925 __ add(too_far, feedback, r0); | 3857 __ AddP(too_far, feedback, r0); |
3926 __ addi(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 3858 __ AddP(too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
3927 __ addi(pointer_reg, feedback, | 3859 __ AddP(pointer_reg, feedback, |
3928 Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag)); | 3860 Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag)); |
3929 | 3861 |
3930 __ bind(&next_loop); | 3862 __ bind(&next_loop); |
3931 __ LoadP(cached_map, MemOperand(pointer_reg)); | 3863 __ LoadP(cached_map, MemOperand(pointer_reg)); |
3932 __ LoadP(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset)); | 3864 __ LoadP(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset)); |
3933 __ cmp(receiver_map, cached_map); | 3865 __ CmpP(receiver_map, cached_map); |
3934 __ bne(&prepare_next); | 3866 __ bne(&prepare_next, Label::kNear); |
3935 __ LoadP(handler, MemOperand(pointer_reg, kPointerSize)); | 3867 __ LoadP(handler, MemOperand(pointer_reg, kPointerSize)); |
3936 __ addi(ip, handler, Operand(Code::kHeaderSize - kHeapObjectTag)); | 3868 __ AddP(ip, handler, Operand(Code::kHeaderSize - kHeapObjectTag)); |
3937 __ Jump(ip); | 3869 __ Jump(ip); |
3938 | 3870 |
3939 __ bind(&prepare_next); | 3871 __ bind(&prepare_next); |
3940 __ addi(pointer_reg, pointer_reg, Operand(kPointerSize * 2)); | 3872 __ AddP(pointer_reg, Operand(kPointerSize * 2)); |
3941 __ cmp(pointer_reg, too_far); | 3873 __ CmpP(pointer_reg, too_far); |
3942 __ blt(&next_loop); | 3874 __ blt(&next_loop, Label::kNear); |
3943 | 3875 |
3944 // We exhausted our array of map handler pairs. | 3876 // We exhausted our array of map handler pairs. |
3945 __ b(miss); | 3877 __ b(miss); |
3946 } | 3878 } |
3947 | 3879 |
3948 | |
3949 static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver, | 3880 static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver, |
3950 Register receiver_map, Register feedback, | 3881 Register receiver_map, Register feedback, |
3951 Register vector, Register slot, | 3882 Register vector, Register slot, |
3952 Register scratch, Label* compare_map, | 3883 Register scratch, Label* compare_map, |
3953 Label* load_smi_map, Label* try_array) { | 3884 Label* load_smi_map, Label* try_array) { |
3954 __ JumpIfSmi(receiver, load_smi_map); | 3885 __ JumpIfSmi(receiver, load_smi_map); |
3955 __ LoadP(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 3886 __ LoadP(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
3956 __ bind(compare_map); | 3887 __ bind(compare_map); |
3957 Register cached_map = scratch; | 3888 Register cached_map = scratch; |
3958 // Move the weak map into the weak_cell register. | 3889 // Move the weak map into the weak_cell register. |
3959 __ LoadP(cached_map, FieldMemOperand(feedback, WeakCell::kValueOffset)); | 3890 __ LoadP(cached_map, FieldMemOperand(feedback, WeakCell::kValueOffset)); |
3960 __ cmp(cached_map, receiver_map); | 3891 __ CmpP(cached_map, receiver_map); |
3961 __ bne(try_array); | 3892 __ bne(try_array); |
3962 Register handler = feedback; | 3893 Register handler = feedback; |
3963 __ SmiToPtrArrayOffset(r0, slot); | 3894 __ SmiToPtrArrayOffset(r1, slot); |
3964 __ add(handler, vector, r0); | |
3965 __ LoadP(handler, | 3895 __ LoadP(handler, |
3966 FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize)); | 3896 FieldMemOperand(r1, vector, FixedArray::kHeaderSize + kPointerSize)); |
3967 __ addi(ip, handler, Operand(Code::kHeaderSize - kHeapObjectTag)); | 3897 __ AddP(ip, handler, Operand(Code::kHeaderSize - kHeapObjectTag)); |
3968 __ Jump(ip); | 3898 __ Jump(ip); |
3969 } | 3899 } |
3970 | 3900 |
| 3901 void LoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { |
| 3902 Register receiver = LoadWithVectorDescriptor::ReceiverRegister(); // r3 |
| 3903 Register name = LoadWithVectorDescriptor::NameRegister(); // r4 |
| 3904 Register vector = LoadWithVectorDescriptor::VectorRegister(); // r5 |
| 3905 Register slot = LoadWithVectorDescriptor::SlotRegister(); // r2 |
| 3906 Register feedback = r6; |
| 3907 Register receiver_map = r7; |
| 3908 Register scratch1 = r8; |
3971 | 3909 |
3972 void LoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { | 3910 __ SmiToPtrArrayOffset(r1, slot); |
3973 Register receiver = LoadWithVectorDescriptor::ReceiverRegister(); // r4 | 3911 __ LoadP(feedback, FieldMemOperand(r1, vector, FixedArray::kHeaderSize)); |
3974 Register name = LoadWithVectorDescriptor::NameRegister(); // r5 | |
3975 Register vector = LoadWithVectorDescriptor::VectorRegister(); // r6 | |
3976 Register slot = LoadWithVectorDescriptor::SlotRegister(); // r3 | |
3977 Register feedback = r7; | |
3978 Register receiver_map = r8; | |
3979 Register scratch1 = r9; | |
3980 | |
3981 __ SmiToPtrArrayOffset(r0, slot); | |
3982 __ add(feedback, vector, r0); | |
3983 __ LoadP(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize)); | |
3984 | 3912 |
3985 // Try to quickly handle the monomorphic case without knowing for sure | 3913 // Try to quickly handle the monomorphic case without knowing for sure |
3986 // if we have a weak cell in feedback. We do know it's safe to look | 3914 // if we have a weak cell in feedback. We do know it's safe to look |
3987 // at WeakCell::kValueOffset. | 3915 // at WeakCell::kValueOffset. |
3988 Label try_array, load_smi_map, compare_map; | 3916 Label try_array, load_smi_map, compare_map; |
3989 Label not_array, miss; | 3917 Label not_array, miss; |
3990 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector, slot, | 3918 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector, slot, |
3991 scratch1, &compare_map, &load_smi_map, &try_array); | 3919 scratch1, &compare_map, &load_smi_map, &try_array); |
3992 | 3920 |
3993 // Is it a fixed array? | 3921 // Is it a fixed array? |
3994 __ bind(&try_array); | 3922 __ bind(&try_array); |
3995 __ LoadP(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset)); | 3923 __ LoadP(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset)); |
3996 __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex); | 3924 __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex); |
3997 __ bne(¬_array); | 3925 __ bne(¬_array, Label::kNear); |
3998 HandleArrayCases(masm, feedback, receiver_map, scratch1, r10, true, &miss); | 3926 HandleArrayCases(masm, feedback, receiver_map, scratch1, r9, true, &miss); |
3999 | 3927 |
4000 __ bind(¬_array); | 3928 __ bind(¬_array); |
4001 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); | 3929 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); |
4002 __ bne(&miss); | 3930 __ bne(&miss); |
4003 Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags( | 3931 Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags( |
4004 Code::ComputeHandlerFlags(Code::LOAD_IC)); | 3932 Code::ComputeHandlerFlags(Code::LOAD_IC)); |
4005 masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags, | 3933 masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags, |
4006 receiver, name, feedback, | 3934 receiver, name, feedback, |
4007 receiver_map, scratch1, r10); | 3935 receiver_map, scratch1, r9); |
4008 | 3936 |
4009 __ bind(&miss); | 3937 __ bind(&miss); |
4010 LoadIC::GenerateMiss(masm); | 3938 LoadIC::GenerateMiss(masm); |
4011 | 3939 |
4012 __ bind(&load_smi_map); | 3940 __ bind(&load_smi_map); |
4013 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex); | 3941 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex); |
4014 __ b(&compare_map); | 3942 __ b(&compare_map); |
4015 } | 3943 } |
4016 | 3944 |
4017 | |
4018 void KeyedLoadICStub::Generate(MacroAssembler* masm) { | 3945 void KeyedLoadICStub::Generate(MacroAssembler* masm) { |
4019 GenerateImpl(masm, false); | 3946 GenerateImpl(masm, false); |
4020 } | 3947 } |
4021 | 3948 |
4022 | |
4023 void KeyedLoadICStub::GenerateForTrampoline(MacroAssembler* masm) { | 3949 void KeyedLoadICStub::GenerateForTrampoline(MacroAssembler* masm) { |
4024 GenerateImpl(masm, true); | 3950 GenerateImpl(masm, true); |
4025 } | 3951 } |
4026 | 3952 |
| 3953 void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { |
| 3954 Register receiver = LoadWithVectorDescriptor::ReceiverRegister(); // r3 |
| 3955 Register key = LoadWithVectorDescriptor::NameRegister(); // r4 |
| 3956 Register vector = LoadWithVectorDescriptor::VectorRegister(); // r5 |
| 3957 Register slot = LoadWithVectorDescriptor::SlotRegister(); // r2 |
| 3958 Register feedback = r6; |
| 3959 Register receiver_map = r7; |
| 3960 Register scratch1 = r8; |
4027 | 3961 |
4028 void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { | 3962 __ SmiToPtrArrayOffset(r1, slot); |
4029 Register receiver = LoadWithVectorDescriptor::ReceiverRegister(); // r4 | 3963 __ LoadP(feedback, FieldMemOperand(r1, vector, FixedArray::kHeaderSize)); |
4030 Register key = LoadWithVectorDescriptor::NameRegister(); // r5 | |
4031 Register vector = LoadWithVectorDescriptor::VectorRegister(); // r6 | |
4032 Register slot = LoadWithVectorDescriptor::SlotRegister(); // r3 | |
4033 Register feedback = r7; | |
4034 Register receiver_map = r8; | |
4035 Register scratch1 = r9; | |
4036 | |
4037 __ SmiToPtrArrayOffset(r0, slot); | |
4038 __ add(feedback, vector, r0); | |
4039 __ LoadP(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize)); | |
4040 | 3964 |
4041 // Try to quickly handle the monomorphic case without knowing for sure | 3965 // Try to quickly handle the monomorphic case without knowing for sure |
4042 // if we have a weak cell in feedback. We do know it's safe to look | 3966 // if we have a weak cell in feedback. We do know it's safe to look |
4043 // at WeakCell::kValueOffset. | 3967 // at WeakCell::kValueOffset. |
4044 Label try_array, load_smi_map, compare_map; | 3968 Label try_array, load_smi_map, compare_map; |
4045 Label not_array, miss; | 3969 Label not_array, miss; |
4046 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector, slot, | 3970 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector, slot, |
4047 scratch1, &compare_map, &load_smi_map, &try_array); | 3971 scratch1, &compare_map, &load_smi_map, &try_array); |
4048 | 3972 |
4049 __ bind(&try_array); | 3973 __ bind(&try_array); |
4050 // Is it a fixed array? | 3974 // Is it a fixed array? |
4051 __ LoadP(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset)); | 3975 __ LoadP(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset)); |
4052 __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex); | 3976 __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex); |
4053 __ bne(¬_array); | 3977 __ bne(¬_array); |
4054 | 3978 |
4055 // We have a polymorphic element handler. | 3979 // We have a polymorphic element handler. |
4056 Label polymorphic, try_poly_name; | 3980 Label polymorphic, try_poly_name; |
4057 __ bind(&polymorphic); | 3981 __ bind(&polymorphic); |
4058 HandleArrayCases(masm, feedback, receiver_map, scratch1, r10, true, &miss); | 3982 HandleArrayCases(masm, feedback, receiver_map, scratch1, r9, true, &miss); |
4059 | 3983 |
4060 __ bind(¬_array); | 3984 __ bind(¬_array); |
4061 // Is it generic? | 3985 // Is it generic? |
4062 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); | 3986 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); |
4063 __ bne(&try_poly_name); | 3987 __ bne(&try_poly_name); |
4064 Handle<Code> megamorphic_stub = | 3988 Handle<Code> megamorphic_stub = |
4065 KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); | 3989 KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); |
4066 __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET); | 3990 __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET); |
4067 | 3991 |
4068 __ bind(&try_poly_name); | 3992 __ bind(&try_poly_name); |
4069 // We might have a name in feedback, and a fixed array in the next slot. | 3993 // We might have a name in feedback, and a fixed array in the next slot. |
4070 __ cmp(key, feedback); | 3994 __ CmpP(key, feedback); |
4071 __ bne(&miss); | 3995 __ bne(&miss); |
4072 // If the name comparison succeeded, we know we have a fixed array with | 3996 // If the name comparison succeeded, we know we have a fixed array with |
4073 // at least one map/handler pair. | 3997 // at least one map/handler pair. |
4074 __ SmiToPtrArrayOffset(r0, slot); | 3998 __ SmiToPtrArrayOffset(r1, slot); |
4075 __ add(feedback, vector, r0); | |
4076 __ LoadP(feedback, | 3999 __ LoadP(feedback, |
4077 FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize)); | 4000 FieldMemOperand(r1, vector, FixedArray::kHeaderSize + kPointerSize)); |
4078 HandleArrayCases(masm, feedback, receiver_map, scratch1, r10, false, &miss); | 4001 HandleArrayCases(masm, feedback, receiver_map, scratch1, r9, false, &miss); |
4079 | 4002 |
4080 __ bind(&miss); | 4003 __ bind(&miss); |
4081 KeyedLoadIC::GenerateMiss(masm); | 4004 KeyedLoadIC::GenerateMiss(masm); |
4082 | 4005 |
4083 __ bind(&load_smi_map); | 4006 __ bind(&load_smi_map); |
4084 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex); | 4007 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex); |
4085 __ b(&compare_map); | 4008 __ b(&compare_map); |
4086 } | 4009 } |
4087 | 4010 |
4088 | |
4089 void VectorStoreICTrampolineStub::Generate(MacroAssembler* masm) { | 4011 void VectorStoreICTrampolineStub::Generate(MacroAssembler* masm) { |
4090 __ EmitLoadTypeFeedbackVector(VectorStoreICDescriptor::VectorRegister()); | 4012 __ EmitLoadTypeFeedbackVector(VectorStoreICDescriptor::VectorRegister()); |
4091 VectorStoreICStub stub(isolate(), state()); | 4013 VectorStoreICStub stub(isolate(), state()); |
4092 stub.GenerateForTrampoline(masm); | 4014 stub.GenerateForTrampoline(masm); |
4093 } | 4015 } |
4094 | 4016 |
4095 | |
4096 void VectorKeyedStoreICTrampolineStub::Generate(MacroAssembler* masm) { | 4017 void VectorKeyedStoreICTrampolineStub::Generate(MacroAssembler* masm) { |
4097 __ EmitLoadTypeFeedbackVector(VectorStoreICDescriptor::VectorRegister()); | 4018 __ EmitLoadTypeFeedbackVector(VectorStoreICDescriptor::VectorRegister()); |
4098 VectorKeyedStoreICStub stub(isolate(), state()); | 4019 VectorKeyedStoreICStub stub(isolate(), state()); |
4099 stub.GenerateForTrampoline(masm); | 4020 stub.GenerateForTrampoline(masm); |
4100 } | 4021 } |
4101 | 4022 |
4102 | |
4103 void VectorStoreICStub::Generate(MacroAssembler* masm) { | 4023 void VectorStoreICStub::Generate(MacroAssembler* masm) { |
4104 GenerateImpl(masm, false); | 4024 GenerateImpl(masm, false); |
4105 } | 4025 } |
4106 | 4026 |
4107 | |
4108 void VectorStoreICStub::GenerateForTrampoline(MacroAssembler* masm) { | 4027 void VectorStoreICStub::GenerateForTrampoline(MacroAssembler* masm) { |
4109 GenerateImpl(masm, true); | 4028 GenerateImpl(masm, true); |
4110 } | 4029 } |
4111 | 4030 |
4112 | |
4113 void VectorStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { | 4031 void VectorStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { |
4114 Register receiver = VectorStoreICDescriptor::ReceiverRegister(); // r4 | 4032 Register receiver = VectorStoreICDescriptor::ReceiverRegister(); // r3 |
4115 Register key = VectorStoreICDescriptor::NameRegister(); // r5 | 4033 Register key = VectorStoreICDescriptor::NameRegister(); // r4 |
4116 Register vector = VectorStoreICDescriptor::VectorRegister(); // r6 | 4034 Register vector = VectorStoreICDescriptor::VectorRegister(); // r5 |
4117 Register slot = VectorStoreICDescriptor::SlotRegister(); // r7 | 4035 Register slot = VectorStoreICDescriptor::SlotRegister(); // r6 |
4118 DCHECK(VectorStoreICDescriptor::ValueRegister().is(r3)); // r3 | 4036 DCHECK(VectorStoreICDescriptor::ValueRegister().is(r2)); // r2 |
4119 Register feedback = r8; | 4037 Register feedback = r7; |
4120 Register receiver_map = r9; | 4038 Register receiver_map = r8; |
4121 Register scratch1 = r10; | 4039 Register scratch1 = r9; |
4122 | 4040 |
4123 __ SmiToPtrArrayOffset(r0, slot); | 4041 __ SmiToPtrArrayOffset(r0, slot); |
4124 __ add(feedback, vector, r0); | 4042 __ AddP(feedback, vector, r0); |
4125 __ LoadP(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize)); | 4043 __ LoadP(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize)); |
4126 | 4044 |
4127 // Try to quickly handle the monomorphic case without knowing for sure | 4045 // Try to quickly handle the monomorphic case without knowing for sure |
4128 // if we have a weak cell in feedback. We do know it's safe to look | 4046 // if we have a weak cell in feedback. We do know it's safe to look |
4129 // at WeakCell::kValueOffset. | 4047 // at WeakCell::kValueOffset. |
4130 Label try_array, load_smi_map, compare_map; | 4048 Label try_array, load_smi_map, compare_map; |
4131 Label not_array, miss; | 4049 Label not_array, miss; |
4132 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector, slot, | 4050 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector, slot, |
4133 scratch1, &compare_map, &load_smi_map, &try_array); | 4051 scratch1, &compare_map, &load_smi_map, &try_array); |
4134 | 4052 |
4135 // Is it a fixed array? | 4053 // Is it a fixed array? |
4136 __ bind(&try_array); | 4054 __ bind(&try_array); |
4137 __ LoadP(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset)); | 4055 __ LoadP(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset)); |
4138 __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex); | 4056 __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex); |
4139 __ bne(¬_array); | 4057 __ bne(¬_array); |
4140 | 4058 |
4141 Register scratch2 = r11; | 4059 Register scratch2 = ip; |
4142 HandleArrayCases(masm, feedback, receiver_map, scratch1, scratch2, true, | 4060 HandleArrayCases(masm, feedback, receiver_map, scratch1, scratch2, true, |
4143 &miss); | 4061 &miss); |
4144 | 4062 |
4145 __ bind(¬_array); | 4063 __ bind(¬_array); |
4146 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); | 4064 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); |
4147 __ bne(&miss); | 4065 __ bne(&miss); |
4148 Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags( | 4066 Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags( |
4149 Code::ComputeHandlerFlags(Code::STORE_IC)); | 4067 Code::ComputeHandlerFlags(Code::STORE_IC)); |
4150 masm->isolate()->stub_cache()->GenerateProbe( | 4068 masm->isolate()->stub_cache()->GenerateProbe( |
4151 masm, Code::STORE_IC, code_flags, receiver, key, feedback, receiver_map, | 4069 masm, Code::STORE_IC, code_flags, receiver, key, feedback, receiver_map, |
4152 scratch1, scratch2); | 4070 scratch1, scratch2); |
4153 | 4071 |
4154 __ bind(&miss); | 4072 __ bind(&miss); |
4155 StoreIC::GenerateMiss(masm); | 4073 StoreIC::GenerateMiss(masm); |
4156 | 4074 |
4157 __ bind(&load_smi_map); | 4075 __ bind(&load_smi_map); |
4158 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex); | 4076 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex); |
4159 __ b(&compare_map); | 4077 __ b(&compare_map); |
4160 } | 4078 } |
4161 | 4079 |
4162 | |
4163 void VectorKeyedStoreICStub::Generate(MacroAssembler* masm) { | 4080 void VectorKeyedStoreICStub::Generate(MacroAssembler* masm) { |
4164 GenerateImpl(masm, false); | 4081 GenerateImpl(masm, false); |
4165 } | 4082 } |
4166 | 4083 |
4167 | |
4168 void VectorKeyedStoreICStub::GenerateForTrampoline(MacroAssembler* masm) { | 4084 void VectorKeyedStoreICStub::GenerateForTrampoline(MacroAssembler* masm) { |
4169 GenerateImpl(masm, true); | 4085 GenerateImpl(masm, true); |
4170 } | 4086 } |
4171 | 4087 |
4172 | |
4173 static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register feedback, | 4088 static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register feedback, |
4174 Register receiver_map, Register scratch1, | 4089 Register receiver_map, Register scratch1, |
4175 Register scratch2, Label* miss) { | 4090 Register scratch2, Label* miss) { |
4176 // feedback initially contains the feedback array | 4091 // feedback initially contains the feedback array |
4177 Label next_loop, prepare_next; | 4092 Label next_loop, prepare_next; |
4178 Label start_polymorphic; | 4093 Label start_polymorphic; |
4179 Label transition_call; | 4094 Label transition_call; |
4180 | 4095 |
4181 Register cached_map = scratch1; | 4096 Register cached_map = scratch1; |
4182 Register too_far = scratch2; | 4097 Register too_far = scratch2; |
4183 Register pointer_reg = feedback; | 4098 Register pointer_reg = feedback; |
4184 __ LoadP(too_far, FieldMemOperand(feedback, FixedArray::kLengthOffset)); | 4099 __ LoadP(too_far, FieldMemOperand(feedback, FixedArray::kLengthOffset)); |
4185 | 4100 |
4186 // +-----+------+------+-----+-----+-----+ ... ----+ | 4101 // +-----+------+------+-----+-----+-----+ ... ----+ |
4187 // | map | len | wm0 | wt0 | h0 | wm1 | hN | | 4102 // | map | len | wm0 | wt0 | h0 | wm1 | hN | |
4188 // +-----+------+------+-----+-----+ ----+ ... ----+ | 4103 // +-----+------+------+-----+-----+ ----+ ... ----+ |
4189 // 0 1 2 len-1 | 4104 // 0 1 2 len-1 |
4190 // ^ ^ | 4105 // ^ ^ |
4191 // | | | 4106 // | | |
4192 // pointer_reg too_far | 4107 // pointer_reg too_far |
4193 // aka feedback scratch2 | 4108 // aka feedback scratch2 |
4194 // also need receiver_map | 4109 // also need receiver_map |
4195 // use cached_map (scratch1) to look in the weak map values. | 4110 // use cached_map (scratch1) to look in the weak map values. |
4196 __ SmiToPtrArrayOffset(r0, too_far); | 4111 __ SmiToPtrArrayOffset(r0, too_far); |
4197 __ add(too_far, feedback, r0); | 4112 __ AddP(too_far, feedback, r0); |
4198 __ addi(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 4113 __ AddP(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
4199 __ addi(pointer_reg, feedback, | 4114 __ AddP(pointer_reg, feedback, |
4200 Operand(FixedArray::OffsetOfElementAt(0) - kHeapObjectTag)); | 4115 Operand(FixedArray::OffsetOfElementAt(0) - kHeapObjectTag)); |
4201 | 4116 |
4202 __ bind(&next_loop); | 4117 __ bind(&next_loop); |
4203 __ LoadP(cached_map, MemOperand(pointer_reg)); | 4118 __ LoadP(cached_map, MemOperand(pointer_reg)); |
4204 __ LoadP(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset)); | 4119 __ LoadP(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset)); |
4205 __ cmp(receiver_map, cached_map); | 4120 __ CmpP(receiver_map, cached_map); |
4206 __ bne(&prepare_next); | 4121 __ bne(&prepare_next); |
4207 // Is it a transitioning store? | 4122 // Is it a transitioning store? |
4208 __ LoadP(too_far, MemOperand(pointer_reg, kPointerSize)); | 4123 __ LoadP(too_far, MemOperand(pointer_reg, kPointerSize)); |
4209 __ CompareRoot(too_far, Heap::kUndefinedValueRootIndex); | 4124 __ CompareRoot(too_far, Heap::kUndefinedValueRootIndex); |
4210 __ bne(&transition_call); | 4125 __ bne(&transition_call); |
4211 __ LoadP(pointer_reg, MemOperand(pointer_reg, kPointerSize * 2)); | 4126 __ LoadP(pointer_reg, MemOperand(pointer_reg, kPointerSize * 2)); |
4212 __ addi(ip, pointer_reg, Operand(Code::kHeaderSize - kHeapObjectTag)); | 4127 __ AddP(ip, pointer_reg, Operand(Code::kHeaderSize - kHeapObjectTag)); |
4213 __ Jump(ip); | 4128 __ Jump(ip); |
4214 | 4129 |
4215 __ bind(&transition_call); | 4130 __ bind(&transition_call); |
4216 __ LoadP(too_far, FieldMemOperand(too_far, WeakCell::kValueOffset)); | 4131 __ LoadP(too_far, FieldMemOperand(too_far, WeakCell::kValueOffset)); |
4217 __ JumpIfSmi(too_far, miss); | 4132 __ JumpIfSmi(too_far, miss); |
4218 | 4133 |
4219 __ LoadP(receiver_map, MemOperand(pointer_reg, kPointerSize * 2)); | 4134 __ LoadP(receiver_map, MemOperand(pointer_reg, kPointerSize * 2)); |
4220 | 4135 |
4221 // Load the map into the correct register. | 4136 // Load the map into the correct register. |
4222 DCHECK(feedback.is(VectorStoreTransitionDescriptor::MapRegister())); | 4137 DCHECK(feedback.is(VectorStoreTransitionDescriptor::MapRegister())); |
4223 __ mr(feedback, too_far); | 4138 __ LoadRR(feedback, too_far); |
4224 | 4139 |
4225 __ addi(ip, receiver_map, Operand(Code::kHeaderSize - kHeapObjectTag)); | 4140 __ AddP(ip, receiver_map, Operand(Code::kHeaderSize - kHeapObjectTag)); |
4226 __ Jump(ip); | 4141 __ Jump(ip); |
4227 | 4142 |
4228 __ bind(&prepare_next); | 4143 __ bind(&prepare_next); |
4229 __ addi(pointer_reg, pointer_reg, Operand(kPointerSize * 3)); | 4144 __ AddP(pointer_reg, pointer_reg, Operand(kPointerSize * 3)); |
4230 __ cmpl(pointer_reg, too_far); | 4145 __ CmpLogicalP(pointer_reg, too_far); |
4231 __ blt(&next_loop); | 4146 __ blt(&next_loop); |
4232 | 4147 |
4233 // We exhausted our array of map handler pairs. | 4148 // We exhausted our array of map handler pairs. |
4234 __ b(miss); | 4149 __ b(miss); |
4235 } | 4150 } |
4236 | 4151 |
4237 | |
4238 void VectorKeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { | 4152 void VectorKeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { |
4239 Register receiver = VectorStoreICDescriptor::ReceiverRegister(); // r4 | 4153 Register receiver = VectorStoreICDescriptor::ReceiverRegister(); // r3 |
4240 Register key = VectorStoreICDescriptor::NameRegister(); // r5 | 4154 Register key = VectorStoreICDescriptor::NameRegister(); // r4 |
4241 Register vector = VectorStoreICDescriptor::VectorRegister(); // r6 | 4155 Register vector = VectorStoreICDescriptor::VectorRegister(); // r5 |
4242 Register slot = VectorStoreICDescriptor::SlotRegister(); // r7 | 4156 Register slot = VectorStoreICDescriptor::SlotRegister(); // r6 |
4243 DCHECK(VectorStoreICDescriptor::ValueRegister().is(r3)); // r3 | 4157 DCHECK(VectorStoreICDescriptor::ValueRegister().is(r2)); // r2 |
4244 Register feedback = r8; | 4158 Register feedback = r7; |
4245 Register receiver_map = r9; | 4159 Register receiver_map = r8; |
4246 Register scratch1 = r10; | 4160 Register scratch1 = r9; |
4247 | 4161 |
4248 __ SmiToPtrArrayOffset(r0, slot); | 4162 __ SmiToPtrArrayOffset(r0, slot); |
4249 __ add(feedback, vector, r0); | 4163 __ AddP(feedback, vector, r0); |
4250 __ LoadP(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize)); | 4164 __ LoadP(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize)); |
4251 | 4165 |
4252 // Try to quickly handle the monomorphic case without knowing for sure | 4166 // Try to quickly handle the monomorphic case without knowing for sure |
4253 // if we have a weak cell in feedback. We do know it's safe to look | 4167 // if we have a weak cell in feedback. We do know it's safe to look |
4254 // at WeakCell::kValueOffset. | 4168 // at WeakCell::kValueOffset. |
4255 Label try_array, load_smi_map, compare_map; | 4169 Label try_array, load_smi_map, compare_map; |
4256 Label not_array, miss; | 4170 Label not_array, miss; |
4257 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector, slot, | 4171 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector, slot, |
4258 scratch1, &compare_map, &load_smi_map, &try_array); | 4172 scratch1, &compare_map, &load_smi_map, &try_array); |
4259 | 4173 |
4260 __ bind(&try_array); | 4174 __ bind(&try_array); |
4261 // Is it a fixed array? | 4175 // Is it a fixed array? |
4262 __ LoadP(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset)); | 4176 __ LoadP(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset)); |
4263 __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex); | 4177 __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex); |
4264 __ bne(¬_array); | 4178 __ bne(¬_array); |
4265 | 4179 |
4266 // We have a polymorphic element handler. | 4180 // We have a polymorphic element handler. |
4267 Label polymorphic, try_poly_name; | 4181 Label polymorphic, try_poly_name; |
4268 __ bind(&polymorphic); | 4182 __ bind(&polymorphic); |
4269 | 4183 |
4270 Register scratch2 = r11; | 4184 Register scratch2 = ip; |
4271 | 4185 |
4272 HandlePolymorphicStoreCase(masm, feedback, receiver_map, scratch1, scratch2, | 4186 HandlePolymorphicStoreCase(masm, feedback, receiver_map, scratch1, scratch2, |
4273 &miss); | 4187 &miss); |
4274 | 4188 |
4275 __ bind(¬_array); | 4189 __ bind(¬_array); |
4276 // Is it generic? | 4190 // Is it generic? |
4277 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); | 4191 __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); |
4278 __ bne(&try_poly_name); | 4192 __ bne(&try_poly_name); |
4279 Handle<Code> megamorphic_stub = | 4193 Handle<Code> megamorphic_stub = |
4280 KeyedStoreIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); | 4194 KeyedStoreIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); |
4281 __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET); | 4195 __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET); |
4282 | 4196 |
4283 __ bind(&try_poly_name); | 4197 __ bind(&try_poly_name); |
4284 // We might have a name in feedback, and a fixed array in the next slot. | 4198 // We might have a name in feedback, and a fixed array in the next slot. |
4285 __ cmp(key, feedback); | 4199 __ CmpP(key, feedback); |
4286 __ bne(&miss); | 4200 __ bne(&miss); |
4287 // If the name comparison succeeded, we know we have a fixed array with | 4201 // If the name comparison succeeded, we know we have a fixed array with |
4288 // at least one map/handler pair. | 4202 // at least one map/handler pair. |
4289 __ SmiToPtrArrayOffset(r0, slot); | 4203 __ SmiToPtrArrayOffset(r0, slot); |
4290 __ add(feedback, vector, r0); | 4204 __ AddP(feedback, vector, r0); |
4291 __ LoadP(feedback, | 4205 __ LoadP(feedback, |
4292 FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize)); | 4206 FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize)); |
4293 HandleArrayCases(masm, feedback, receiver_map, scratch1, scratch2, false, | 4207 HandleArrayCases(masm, feedback, receiver_map, scratch1, scratch2, false, |
4294 &miss); | 4208 &miss); |
4295 | 4209 |
4296 __ bind(&miss); | 4210 __ bind(&miss); |
4297 KeyedStoreIC::GenerateMiss(masm); | 4211 KeyedStoreIC::GenerateMiss(masm); |
4298 | 4212 |
4299 __ bind(&load_smi_map); | 4213 __ bind(&load_smi_map); |
4300 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex); | 4214 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex); |
4301 __ b(&compare_map); | 4215 __ b(&compare_map); |
4302 } | 4216 } |
4303 | 4217 |
4304 | |
4305 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { | 4218 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { |
4306 if (masm->isolate()->function_entry_hook() != NULL) { | 4219 if (masm->isolate()->function_entry_hook() != NULL) { |
4307 PredictableCodeSizeScope predictable(masm, | 4220 PredictableCodeSizeScope predictable(masm, |
4308 #if V8_TARGET_ARCH_PPC64 | 4221 #if V8_TARGET_ARCH_S390X |
4309 14 * Assembler::kInstrSize); | 4222 40); |
| 4223 #elif V8_HOST_ARCH_S390 |
| 4224 36); |
4310 #else | 4225 #else |
4311 11 * Assembler::kInstrSize); | 4226 32); |
4312 #endif | 4227 #endif |
4313 ProfileEntryHookStub stub(masm->isolate()); | 4228 ProfileEntryHookStub stub(masm->isolate()); |
4314 __ mflr(r0); | 4229 __ CleanseP(r14); |
4315 __ Push(r0, ip); | 4230 __ Push(r14, ip); |
4316 __ CallStub(&stub); | 4231 __ CallStub(&stub); // BRASL |
4317 __ Pop(r0, ip); | 4232 __ Pop(r14, ip); |
4318 __ mtlr(r0); | |
4319 } | 4233 } |
4320 } | 4234 } |
4321 | 4235 |
4322 | |
4323 void ProfileEntryHookStub::Generate(MacroAssembler* masm) { | 4236 void ProfileEntryHookStub::Generate(MacroAssembler* masm) { |
4324 // The entry hook is a "push lr, ip" instruction, followed by a call. | 4237 // The entry hook is a "push lr" instruction (LAY+ST/STG), followed by a call. |
| 4238 #if V8_TARGET_ARCH_S390X |
4325 const int32_t kReturnAddressDistanceFromFunctionStart = | 4239 const int32_t kReturnAddressDistanceFromFunctionStart = |
4326 Assembler::kCallTargetAddressOffset + 3 * Assembler::kInstrSize; | 4240 Assembler::kCallTargetAddressOffset + 18; // LAY + STG * 2 |
| 4241 #elif V8_HOST_ARCH_S390 |
| 4242 const int32_t kReturnAddressDistanceFromFunctionStart = |
| 4243 Assembler::kCallTargetAddressOffset + 18; // NILH + LAY + ST * 2 |
| 4244 #else |
| 4245 const int32_t kReturnAddressDistanceFromFunctionStart = |
| 4246 Assembler::kCallTargetAddressOffset + 14; // LAY + ST * 2 |
| 4247 #endif |
4327 | 4248 |
4328 // This should contain all kJSCallerSaved registers. | 4249 // This should contain all kJSCallerSaved registers. |
4329 const RegList kSavedRegs = kJSCallerSaved | // Caller saved registers. | 4250 const RegList kSavedRegs = kJSCallerSaved | // Caller saved registers. |
4330 r15.bit(); // Saved stack pointer. | 4251 r7.bit(); // Saved stack pointer. |
4331 | 4252 |
4332 // We also save lr, so the count here is one higher than the mask indicates. | 4253 // We also save r14+ip, so count here is one higher than the mask indicates. |
4333 const int32_t kNumSavedRegs = kNumJSCallerSaved + 2; | 4254 const int32_t kNumSavedRegs = kNumJSCallerSaved + 3; |
4334 | 4255 |
4335 // Save all caller-save registers as this may be called from anywhere. | 4256 // Save all caller-save registers as this may be called from anywhere. |
4336 __ mflr(ip); | 4257 __ CleanseP(r14); |
| 4258 __ LoadRR(ip, r14); |
4337 __ MultiPush(kSavedRegs | ip.bit()); | 4259 __ MultiPush(kSavedRegs | ip.bit()); |
4338 | 4260 |
4339 // Compute the function's address for the first argument. | 4261 // Compute the function's address for the first argument. |
4340 __ subi(r3, ip, Operand(kReturnAddressDistanceFromFunctionStart)); | 4262 |
| 4263 __ SubP(r2, ip, Operand(kReturnAddressDistanceFromFunctionStart)); |
4341 | 4264 |
4342 // The caller's return address is two slots above the saved temporaries. | 4265 // The caller's return address is two slots above the saved temporaries. |
4343 // Grab that for the second argument to the hook. | 4266 // Grab that for the second argument to the hook. |
4344 __ addi(r4, sp, Operand((kNumSavedRegs + 1) * kPointerSize)); | 4267 __ lay(r3, MemOperand(sp, kNumSavedRegs * kPointerSize)); |
4345 | 4268 |
4346 // Align the stack if necessary. | 4269 // Align the stack if necessary. |
4347 int frame_alignment = masm->ActivationFrameAlignment(); | 4270 int frame_alignment = masm->ActivationFrameAlignment(); |
4348 if (frame_alignment > kPointerSize) { | 4271 if (frame_alignment > kPointerSize) { |
4349 __ mr(r15, sp); | 4272 __ LoadRR(r7, sp); |
4350 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); | 4273 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); |
4351 __ ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment))); | 4274 __ ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment))); |
4352 } | 4275 } |
4353 | 4276 |
4354 #if !defined(USE_SIMULATOR) | 4277 #if !defined(USE_SIMULATOR) |
4355 uintptr_t entry_hook = | 4278 uintptr_t entry_hook = |
4356 reinterpret_cast<uintptr_t>(isolate()->function_entry_hook()); | 4279 reinterpret_cast<uintptr_t>(isolate()->function_entry_hook()); |
4357 #else | 4280 __ mov(ip, Operand(entry_hook)); |
| 4281 |
| 4282 #if ABI_USES_FUNCTION_DESCRIPTORS |
| 4283 // Function descriptor |
| 4284 __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(ip, kPointerSize)); |
| 4285 __ LoadP(ip, MemOperand(ip, 0)); |
| 4286 // ip already set. |
| 4287 #endif |
| 4288 #endif |
| 4289 |
| 4290 // zLinux ABI requires caller's frame to have sufficient space for callee |
| 4291 // preserved regsiter save area. |
| 4292 __ LoadImmP(r0, Operand::Zero()); |
| 4293 __ StoreP(r0, MemOperand(sp, -kCalleeRegisterSaveAreaSize - |
| 4294 kNumRequiredStackFrameSlots * kPointerSize)); |
| 4295 __ lay(sp, MemOperand(sp, -kCalleeRegisterSaveAreaSize - |
| 4296 kNumRequiredStackFrameSlots * kPointerSize)); |
| 4297 #if defined(USE_SIMULATOR) |
4358 // Under the simulator we need to indirect the entry hook through a | 4298 // Under the simulator we need to indirect the entry hook through a |
4359 // trampoline function at a known address. | 4299 // trampoline function at a known address. |
| 4300 // It additionally takes an isolate as a third parameter |
| 4301 __ mov(r4, Operand(ExternalReference::isolate_address(isolate()))); |
| 4302 |
4360 ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline)); | 4303 ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline)); |
4361 ExternalReference entry_hook = ExternalReference( | 4304 __ mov(ip, Operand(ExternalReference( |
4362 &dispatcher, ExternalReference::BUILTIN_CALL, isolate()); | 4305 &dispatcher, ExternalReference::BUILTIN_CALL, isolate()))); |
4363 | |
4364 // It additionally takes an isolate as a third parameter | |
4365 __ mov(r5, Operand(ExternalReference::isolate_address(isolate()))); | |
4366 #endif | 4306 #endif |
4367 | |
4368 __ mov(ip, Operand(entry_hook)); | |
4369 | |
4370 if (ABI_USES_FUNCTION_DESCRIPTORS) { | |
4371 __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(ip, kPointerSize)); | |
4372 __ LoadP(ip, MemOperand(ip, 0)); | |
4373 } | |
4374 // ip set above, so nothing more to do for ABI_CALL_VIA_IP. | |
4375 | |
4376 // PPC LINUX ABI: | |
4377 __ li(r0, Operand::Zero()); | |
4378 __ StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize)); | |
4379 | |
4380 __ Call(ip); | 4307 __ Call(ip); |
4381 | 4308 |
4382 __ addi(sp, sp, Operand(kNumRequiredStackFrameSlots * kPointerSize)); | 4309 // zLinux ABI requires caller's frame to have sufficient space for callee |
| 4310 // preserved regsiter save area. |
| 4311 __ la(sp, MemOperand(sp, kCalleeRegisterSaveAreaSize + |
| 4312 kNumRequiredStackFrameSlots * kPointerSize)); |
4383 | 4313 |
4384 // Restore the stack pointer if needed. | 4314 // Restore the stack pointer if needed. |
4385 if (frame_alignment > kPointerSize) { | 4315 if (frame_alignment > kPointerSize) { |
4386 __ mr(sp, r15); | 4316 __ LoadRR(sp, r7); |
4387 } | 4317 } |
4388 | 4318 |
4389 // Also pop lr to get Ret(0). | 4319 // Also pop lr to get Ret(0). |
4390 __ MultiPop(kSavedRegs | ip.bit()); | 4320 __ MultiPop(kSavedRegs | ip.bit()); |
4391 __ mtlr(ip); | 4321 __ LoadRR(r14, ip); |
4392 __ Ret(); | 4322 __ Ret(); |
4393 } | 4323 } |
4394 | 4324 |
4395 | |
4396 template <class T> | 4325 template <class T> |
4397 static void CreateArrayDispatch(MacroAssembler* masm, | 4326 static void CreateArrayDispatch(MacroAssembler* masm, |
4398 AllocationSiteOverrideMode mode) { | 4327 AllocationSiteOverrideMode mode) { |
4399 if (mode == DISABLE_ALLOCATION_SITES) { | 4328 if (mode == DISABLE_ALLOCATION_SITES) { |
4400 T stub(masm->isolate(), GetInitialFastElementsKind(), mode); | 4329 T stub(masm->isolate(), GetInitialFastElementsKind(), mode); |
4401 __ TailCallStub(&stub); | 4330 __ TailCallStub(&stub); |
4402 } else if (mode == DONT_OVERRIDE) { | 4331 } else if (mode == DONT_OVERRIDE) { |
4403 int last_index = | 4332 int last_index = |
4404 GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); | 4333 GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); |
4405 for (int i = 0; i <= last_index; ++i) { | 4334 for (int i = 0; i <= last_index; ++i) { |
4406 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); | 4335 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); |
4407 __ Cmpi(r6, Operand(kind), r0); | 4336 __ CmpP(r5, Operand(kind)); |
4408 T stub(masm->isolate(), kind); | 4337 T stub(masm->isolate(), kind); |
4409 __ TailCallStub(&stub, eq); | 4338 __ TailCallStub(&stub, eq); |
4410 } | 4339 } |
4411 | 4340 |
4412 // If we reached this point there is a problem. | 4341 // If we reached this point there is a problem. |
4413 __ Abort(kUnexpectedElementsKindInArrayConstructor); | 4342 __ Abort(kUnexpectedElementsKindInArrayConstructor); |
4414 } else { | 4343 } else { |
4415 UNREACHABLE(); | 4344 UNREACHABLE(); |
4416 } | 4345 } |
4417 } | 4346 } |
4418 | 4347 |
4419 | |
4420 static void CreateArrayDispatchOneArgument(MacroAssembler* masm, | 4348 static void CreateArrayDispatchOneArgument(MacroAssembler* masm, |
4421 AllocationSiteOverrideMode mode) { | 4349 AllocationSiteOverrideMode mode) { |
4422 // r5 - allocation site (if mode != DISABLE_ALLOCATION_SITES) | 4350 // r4 - allocation site (if mode != DISABLE_ALLOCATION_SITES) |
4423 // r6 - kind (if mode != DISABLE_ALLOCATION_SITES) | 4351 // r5 - kind (if mode != DISABLE_ALLOCATION_SITES) |
4424 // r3 - number of arguments | 4352 // r2 - number of arguments |
4425 // r4 - constructor? | 4353 // r3 - constructor? |
4426 // sp[0] - last argument | 4354 // sp[0] - last argument |
4427 Label normal_sequence; | 4355 Label normal_sequence; |
4428 if (mode == DONT_OVERRIDE) { | 4356 if (mode == DONT_OVERRIDE) { |
4429 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); | 4357 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); |
4430 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); | 4358 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); |
4431 STATIC_ASSERT(FAST_ELEMENTS == 2); | 4359 STATIC_ASSERT(FAST_ELEMENTS == 2); |
4432 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); | 4360 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); |
4433 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS == 4); | 4361 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS == 4); |
4434 STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); | 4362 STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); |
4435 | 4363 |
4436 // is the low bit set? If so, we are holey and that is good. | 4364 // is the low bit set? If so, we are holey and that is good. |
4437 __ andi(r0, r6, Operand(1)); | 4365 __ AndP(r0, r5, Operand(1)); |
4438 __ bne(&normal_sequence, cr0); | 4366 __ bne(&normal_sequence); |
4439 } | 4367 } |
4440 | 4368 |
4441 // look at the first argument | 4369 // look at the first argument |
4442 __ LoadP(r8, MemOperand(sp, 0)); | 4370 __ LoadP(r7, MemOperand(sp, 0)); |
4443 __ cmpi(r8, Operand::Zero()); | 4371 __ CmpP(r7, Operand::Zero()); |
4444 __ beq(&normal_sequence); | 4372 __ beq(&normal_sequence); |
4445 | 4373 |
4446 if (mode == DISABLE_ALLOCATION_SITES) { | 4374 if (mode == DISABLE_ALLOCATION_SITES) { |
4447 ElementsKind initial = GetInitialFastElementsKind(); | 4375 ElementsKind initial = GetInitialFastElementsKind(); |
4448 ElementsKind holey_initial = GetHoleyElementsKind(initial); | 4376 ElementsKind holey_initial = GetHoleyElementsKind(initial); |
4449 | 4377 |
4450 ArraySingleArgumentConstructorStub stub_holey( | 4378 ArraySingleArgumentConstructorStub stub_holey( |
4451 masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES); | 4379 masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES); |
4452 __ TailCallStub(&stub_holey); | 4380 __ TailCallStub(&stub_holey); |
4453 | 4381 |
4454 __ bind(&normal_sequence); | 4382 __ bind(&normal_sequence); |
4455 ArraySingleArgumentConstructorStub stub(masm->isolate(), initial, | 4383 ArraySingleArgumentConstructorStub stub(masm->isolate(), initial, |
4456 DISABLE_ALLOCATION_SITES); | 4384 DISABLE_ALLOCATION_SITES); |
4457 __ TailCallStub(&stub); | 4385 __ TailCallStub(&stub); |
4458 } else if (mode == DONT_OVERRIDE) { | 4386 } else if (mode == DONT_OVERRIDE) { |
4459 // We are going to create a holey array, but our kind is non-holey. | 4387 // We are going to create a holey array, but our kind is non-holey. |
4460 // Fix kind and retry (only if we have an allocation site in the slot). | 4388 // Fix kind and retry (only if we have an allocation site in the slot). |
4461 __ addi(r6, r6, Operand(1)); | 4389 __ AddP(r5, r5, Operand(1)); |
4462 | |
4463 if (FLAG_debug_code) { | 4390 if (FLAG_debug_code) { |
4464 __ LoadP(r8, FieldMemOperand(r5, 0)); | 4391 __ LoadP(r7, FieldMemOperand(r4, 0)); |
4465 __ CompareRoot(r8, Heap::kAllocationSiteMapRootIndex); | 4392 __ CompareRoot(r7, Heap::kAllocationSiteMapRootIndex); |
4466 __ Assert(eq, kExpectedAllocationSite); | 4393 __ Assert(eq, kExpectedAllocationSite); |
4467 } | 4394 } |
4468 | 4395 |
4469 // Save the resulting elements kind in type info. We can't just store r6 | 4396 // Save the resulting elements kind in type info. We can't just store r5 |
4470 // in the AllocationSite::transition_info field because elements kind is | 4397 // in the AllocationSite::transition_info field because elements kind is |
4471 // restricted to a portion of the field...upper bits need to be left alone. | 4398 // restricted to a portion of the field...upper bits need to be left alone. |
4472 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); | 4399 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); |
4473 __ LoadP(r7, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset)); | 4400 __ LoadP(r6, FieldMemOperand(r4, AllocationSite::kTransitionInfoOffset)); |
4474 __ AddSmiLiteral(r7, r7, Smi::FromInt(kFastElementsKindPackedToHoley), r0); | 4401 __ AddSmiLiteral(r6, r6, Smi::FromInt(kFastElementsKindPackedToHoley), r0); |
4475 __ StoreP(r7, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset), | 4402 __ StoreP(r6, FieldMemOperand(r4, AllocationSite::kTransitionInfoOffset)); |
4476 r0); | |
4477 | 4403 |
4478 __ bind(&normal_sequence); | 4404 __ bind(&normal_sequence); |
4479 int last_index = | 4405 int last_index = |
4480 GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); | 4406 GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); |
4481 for (int i = 0; i <= last_index; ++i) { | 4407 for (int i = 0; i <= last_index; ++i) { |
4482 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); | 4408 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); |
4483 __ mov(r0, Operand(kind)); | 4409 __ CmpP(r5, Operand(kind)); |
4484 __ cmp(r6, r0); | |
4485 ArraySingleArgumentConstructorStub stub(masm->isolate(), kind); | 4410 ArraySingleArgumentConstructorStub stub(masm->isolate(), kind); |
4486 __ TailCallStub(&stub, eq); | 4411 __ TailCallStub(&stub, eq); |
4487 } | 4412 } |
4488 | 4413 |
4489 // If we reached this point there is a problem. | 4414 // If we reached this point there is a problem. |
4490 __ Abort(kUnexpectedElementsKindInArrayConstructor); | 4415 __ Abort(kUnexpectedElementsKindInArrayConstructor); |
4491 } else { | 4416 } else { |
4492 UNREACHABLE(); | 4417 UNREACHABLE(); |
4493 } | 4418 } |
4494 } | 4419 } |
4495 | 4420 |
4496 | |
4497 template <class T> | 4421 template <class T> |
4498 static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { | 4422 static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { |
4499 int to_index = | 4423 int to_index = |
4500 GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); | 4424 GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); |
4501 for (int i = 0; i <= to_index; ++i) { | 4425 for (int i = 0; i <= to_index; ++i) { |
4502 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); | 4426 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); |
4503 T stub(isolate, kind); | 4427 T stub(isolate, kind); |
4504 stub.GetCode(); | 4428 stub.GetCode(); |
4505 if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) { | 4429 if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) { |
4506 T stub1(isolate, kind, DISABLE_ALLOCATION_SITES); | 4430 T stub1(isolate, kind, DISABLE_ALLOCATION_SITES); |
4507 stub1.GetCode(); | 4431 stub1.GetCode(); |
4508 } | 4432 } |
4509 } | 4433 } |
4510 } | 4434 } |
4511 | 4435 |
4512 | |
4513 void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { | 4436 void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { |
4514 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>( | 4437 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>( |
4515 isolate); | 4438 isolate); |
4516 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>( | 4439 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>( |
4517 isolate); | 4440 isolate); |
4518 ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>( | 4441 ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>( |
4519 isolate); | 4442 isolate); |
4520 } | 4443 } |
4521 | 4444 |
4522 | |
4523 void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( | 4445 void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( |
4524 Isolate* isolate) { | 4446 Isolate* isolate) { |
4525 ElementsKind kinds[2] = {FAST_ELEMENTS, FAST_HOLEY_ELEMENTS}; | 4447 ElementsKind kinds[2] = {FAST_ELEMENTS, FAST_HOLEY_ELEMENTS}; |
4526 for (int i = 0; i < 2; i++) { | 4448 for (int i = 0; i < 2; i++) { |
4527 // For internal arrays we only need a few things | 4449 // For internal arrays we only need a few things |
4528 InternalArrayNoArgumentConstructorStub stubh1(isolate, kinds[i]); | 4450 InternalArrayNoArgumentConstructorStub stubh1(isolate, kinds[i]); |
4529 stubh1.GetCode(); | 4451 stubh1.GetCode(); |
4530 InternalArraySingleArgumentConstructorStub stubh2(isolate, kinds[i]); | 4452 InternalArraySingleArgumentConstructorStub stubh2(isolate, kinds[i]); |
4531 stubh2.GetCode(); | 4453 stubh2.GetCode(); |
4532 InternalArrayNArgumentsConstructorStub stubh3(isolate, kinds[i]); | 4454 InternalArrayNArgumentsConstructorStub stubh3(isolate, kinds[i]); |
4533 stubh3.GetCode(); | 4455 stubh3.GetCode(); |
4534 } | 4456 } |
4535 } | 4457 } |
4536 | 4458 |
4537 | |
4538 void ArrayConstructorStub::GenerateDispatchToArrayStub( | 4459 void ArrayConstructorStub::GenerateDispatchToArrayStub( |
4539 MacroAssembler* masm, AllocationSiteOverrideMode mode) { | 4460 MacroAssembler* masm, AllocationSiteOverrideMode mode) { |
4540 if (argument_count() == ANY) { | 4461 if (argument_count() == ANY) { |
4541 Label not_zero_case, not_one_case; | 4462 Label not_zero_case, not_one_case; |
4542 __ cmpi(r3, Operand::Zero()); | 4463 __ CmpP(r2, Operand::Zero()); |
4543 __ bne(¬_zero_case); | 4464 __ bne(¬_zero_case); |
4544 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode); | 4465 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode); |
4545 | 4466 |
4546 __ bind(¬_zero_case); | 4467 __ bind(¬_zero_case); |
4547 __ cmpi(r3, Operand(1)); | 4468 __ CmpP(r2, Operand(1)); |
4548 __ bgt(¬_one_case); | 4469 __ bgt(¬_one_case); |
4549 CreateArrayDispatchOneArgument(masm, mode); | 4470 CreateArrayDispatchOneArgument(masm, mode); |
4550 | 4471 |
4551 __ bind(¬_one_case); | 4472 __ bind(¬_one_case); |
4552 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode); | 4473 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode); |
4553 } else if (argument_count() == NONE) { | 4474 } else if (argument_count() == NONE) { |
4554 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode); | 4475 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode); |
4555 } else if (argument_count() == ONE) { | 4476 } else if (argument_count() == ONE) { |
4556 CreateArrayDispatchOneArgument(masm, mode); | 4477 CreateArrayDispatchOneArgument(masm, mode); |
4557 } else if (argument_count() == MORE_THAN_ONE) { | 4478 } else if (argument_count() == MORE_THAN_ONE) { |
4558 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode); | 4479 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode); |
4559 } else { | 4480 } else { |
4560 UNREACHABLE(); | 4481 UNREACHABLE(); |
4561 } | 4482 } |
4562 } | 4483 } |
4563 | 4484 |
4564 | |
4565 void ArrayConstructorStub::Generate(MacroAssembler* masm) { | 4485 void ArrayConstructorStub::Generate(MacroAssembler* masm) { |
4566 // ----------- S t a t e ------------- | 4486 // ----------- S t a t e ------------- |
4567 // -- r3 : argc (only if argument_count() == ANY) | 4487 // -- r2 : argc (only if argument_count() == ANY) |
4568 // -- r4 : constructor | 4488 // -- r3 : constructor |
4569 // -- r5 : AllocationSite or undefined | 4489 // -- r4 : AllocationSite or undefined |
4570 // -- r6 : new target | 4490 // -- r5 : new target |
4571 // -- sp[0] : return address | 4491 // -- sp[0] : return address |
4572 // -- sp[4] : last argument | 4492 // -- sp[4] : last argument |
4573 // ----------------------------------- | 4493 // ----------------------------------- |
4574 | 4494 |
4575 if (FLAG_debug_code) { | 4495 if (FLAG_debug_code) { |
4576 // The array construct code is only set for the global and natives | 4496 // The array construct code is only set for the global and natives |
4577 // builtin Array functions which always have maps. | 4497 // builtin Array functions which always have maps. |
4578 | 4498 |
4579 // Initial map for the builtin Array function should be a map. | 4499 // Initial map for the builtin Array function should be a map. |
4580 __ LoadP(r7, FieldMemOperand(r4, JSFunction::kPrototypeOrInitialMapOffset)); | 4500 __ LoadP(r6, FieldMemOperand(r3, JSFunction::kPrototypeOrInitialMapOffset)); |
4581 // Will both indicate a NULL and a Smi. | 4501 // Will both indicate a NULL and a Smi. |
4582 __ TestIfSmi(r7, r0); | 4502 __ TestIfSmi(r6); |
4583 __ Assert(ne, kUnexpectedInitialMapForArrayFunction, cr0); | 4503 __ Assert(ne, kUnexpectedInitialMapForArrayFunction, cr0); |
4584 __ CompareObjectType(r7, r7, r8, MAP_TYPE); | 4504 __ CompareObjectType(r6, r6, r7, MAP_TYPE); |
4585 __ Assert(eq, kUnexpectedInitialMapForArrayFunction); | 4505 __ Assert(eq, kUnexpectedInitialMapForArrayFunction); |
4586 | 4506 |
4587 // We should either have undefined in r5 or a valid AllocationSite | 4507 // We should either have undefined in r4 or a valid AllocationSite |
4588 __ AssertUndefinedOrAllocationSite(r5, r7); | 4508 __ AssertUndefinedOrAllocationSite(r4, r6); |
4589 } | 4509 } |
4590 | 4510 |
4591 // Enter the context of the Array function. | 4511 // Enter the context of the Array function. |
4592 __ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset)); | 4512 __ LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset)); |
4593 | 4513 |
4594 Label subclassing; | 4514 Label subclassing; |
4595 __ cmp(r6, r4); | 4515 __ CmpP(r5, r3); |
4596 __ bne(&subclassing); | 4516 __ bne(&subclassing, Label::kNear); |
4597 | 4517 |
4598 Label no_info; | 4518 Label no_info; |
4599 // Get the elements kind and case on that. | 4519 // Get the elements kind and case on that. |
4600 __ CompareRoot(r5, Heap::kUndefinedValueRootIndex); | 4520 __ CompareRoot(r4, Heap::kUndefinedValueRootIndex); |
4601 __ beq(&no_info); | 4521 __ beq(&no_info); |
4602 | 4522 |
4603 __ LoadP(r6, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset)); | 4523 __ LoadP(r5, FieldMemOperand(r4, AllocationSite::kTransitionInfoOffset)); |
4604 __ SmiUntag(r6); | 4524 __ SmiUntag(r5); |
4605 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); | 4525 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); |
4606 __ And(r6, r6, Operand(AllocationSite::ElementsKindBits::kMask)); | 4526 __ AndP(r5, Operand(AllocationSite::ElementsKindBits::kMask)); |
4607 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); | 4527 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); |
4608 | 4528 |
4609 __ bind(&no_info); | 4529 __ bind(&no_info); |
4610 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); | 4530 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); |
4611 | 4531 |
4612 __ bind(&subclassing); | 4532 __ bind(&subclassing); |
4613 switch (argument_count()) { | 4533 switch (argument_count()) { |
4614 case ANY: | 4534 case ANY: |
4615 case MORE_THAN_ONE: | 4535 case MORE_THAN_ONE: |
4616 __ ShiftLeftImm(r0, r3, Operand(kPointerSizeLog2)); | 4536 __ ShiftLeftP(r1, r2, Operand(kPointerSizeLog2)); |
4617 __ StorePX(r4, MemOperand(sp, r0)); | 4537 __ StoreP(r3, MemOperand(sp, r1)); |
4618 __ addi(r3, r3, Operand(3)); | 4538 __ AddP(r2, r2, Operand(3)); |
4619 break; | 4539 break; |
4620 case NONE: | 4540 case NONE: |
4621 __ StoreP(r4, MemOperand(sp, 0 * kPointerSize)); | 4541 __ StoreP(r3, MemOperand(sp, 0 * kPointerSize)); |
4622 __ li(r3, Operand(3)); | 4542 __ LoadImmP(r2, Operand(3)); |
4623 break; | 4543 break; |
4624 case ONE: | 4544 case ONE: |
4625 __ StoreP(r4, MemOperand(sp, 1 * kPointerSize)); | 4545 __ StoreP(r3, MemOperand(sp, 1 * kPointerSize)); |
4626 __ li(r3, Operand(4)); | 4546 __ LoadImmP(r2, Operand(4)); |
4627 break; | 4547 break; |
4628 } | 4548 } |
4629 | 4549 |
4630 __ Push(r6, r5); | 4550 __ Push(r5, r4); |
4631 __ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate())); | 4551 __ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate())); |
4632 } | 4552 } |
4633 | 4553 |
4634 | |
4635 void InternalArrayConstructorStub::GenerateCase(MacroAssembler* masm, | 4554 void InternalArrayConstructorStub::GenerateCase(MacroAssembler* masm, |
4636 ElementsKind kind) { | 4555 ElementsKind kind) { |
4637 __ cmpli(r3, Operand(1)); | 4556 __ CmpLogicalP(r2, Operand(1)); |
4638 | 4557 |
4639 InternalArrayNoArgumentConstructorStub stub0(isolate(), kind); | 4558 InternalArrayNoArgumentConstructorStub stub0(isolate(), kind); |
4640 __ TailCallStub(&stub0, lt); | 4559 __ TailCallStub(&stub0, lt); |
4641 | 4560 |
4642 InternalArrayNArgumentsConstructorStub stubN(isolate(), kind); | 4561 InternalArrayNArgumentsConstructorStub stubN(isolate(), kind); |
4643 __ TailCallStub(&stubN, gt); | 4562 __ TailCallStub(&stubN, gt); |
4644 | 4563 |
4645 if (IsFastPackedElementsKind(kind)) { | 4564 if (IsFastPackedElementsKind(kind)) { |
4646 // We might need to create a holey array | 4565 // We might need to create a holey array |
4647 // look at the first argument | 4566 // look at the first argument |
4648 __ LoadP(r6, MemOperand(sp, 0)); | 4567 __ LoadP(r5, MemOperand(sp, 0)); |
4649 __ cmpi(r6, Operand::Zero()); | 4568 __ CmpP(r5, Operand::Zero()); |
4650 | 4569 |
4651 InternalArraySingleArgumentConstructorStub stub1_holey( | 4570 InternalArraySingleArgumentConstructorStub stub1_holey( |
4652 isolate(), GetHoleyElementsKind(kind)); | 4571 isolate(), GetHoleyElementsKind(kind)); |
4653 __ TailCallStub(&stub1_holey, ne); | 4572 __ TailCallStub(&stub1_holey, ne); |
4654 } | 4573 } |
4655 | 4574 |
4656 InternalArraySingleArgumentConstructorStub stub1(isolate(), kind); | 4575 InternalArraySingleArgumentConstructorStub stub1(isolate(), kind); |
4657 __ TailCallStub(&stub1); | 4576 __ TailCallStub(&stub1); |
4658 } | 4577 } |
4659 | 4578 |
4660 | |
4661 void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { | 4579 void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { |
4662 // ----------- S t a t e ------------- | 4580 // ----------- S t a t e ------------- |
4663 // -- r3 : argc | 4581 // -- r2 : argc |
4664 // -- r4 : constructor | 4582 // -- r3 : constructor |
4665 // -- sp[0] : return address | 4583 // -- sp[0] : return address |
4666 // -- sp[4] : last argument | 4584 // -- sp[4] : last argument |
4667 // ----------------------------------- | 4585 // ----------------------------------- |
4668 | 4586 |
4669 if (FLAG_debug_code) { | 4587 if (FLAG_debug_code) { |
4670 // The array construct code is only set for the global and natives | 4588 // The array construct code is only set for the global and natives |
4671 // builtin Array functions which always have maps. | 4589 // builtin Array functions which always have maps. |
4672 | 4590 |
4673 // Initial map for the builtin Array function should be a map. | 4591 // Initial map for the builtin Array function should be a map. |
4674 __ LoadP(r6, FieldMemOperand(r4, JSFunction::kPrototypeOrInitialMapOffset)); | 4592 __ LoadP(r5, FieldMemOperand(r3, JSFunction::kPrototypeOrInitialMapOffset)); |
4675 // Will both indicate a NULL and a Smi. | 4593 // Will both indicate a NULL and a Smi. |
4676 __ TestIfSmi(r6, r0); | 4594 __ TestIfSmi(r5); |
4677 __ Assert(ne, kUnexpectedInitialMapForArrayFunction, cr0); | 4595 __ Assert(ne, kUnexpectedInitialMapForArrayFunction, cr0); |
4678 __ CompareObjectType(r6, r6, r7, MAP_TYPE); | 4596 __ CompareObjectType(r5, r5, r6, MAP_TYPE); |
4679 __ Assert(eq, kUnexpectedInitialMapForArrayFunction); | 4597 __ Assert(eq, kUnexpectedInitialMapForArrayFunction); |
4680 } | 4598 } |
4681 | 4599 |
4682 // Figure out the right elements kind | 4600 // Figure out the right elements kind |
4683 __ LoadP(r6, FieldMemOperand(r4, JSFunction::kPrototypeOrInitialMapOffset)); | 4601 __ LoadP(r5, FieldMemOperand(r3, JSFunction::kPrototypeOrInitialMapOffset)); |
4684 // Load the map's "bit field 2" into |result|. | 4602 // Load the map's "bit field 2" into |result|. |
4685 __ lbz(r6, FieldMemOperand(r6, Map::kBitField2Offset)); | 4603 __ LoadlB(r5, FieldMemOperand(r5, Map::kBitField2Offset)); |
4686 // Retrieve elements_kind from bit field 2. | 4604 // Retrieve elements_kind from bit field 2. |
4687 __ DecodeField<Map::ElementsKindBits>(r6); | 4605 __ DecodeField<Map::ElementsKindBits>(r5); |
4688 | 4606 |
4689 if (FLAG_debug_code) { | 4607 if (FLAG_debug_code) { |
4690 Label done; | 4608 Label done; |
4691 __ cmpi(r6, Operand(FAST_ELEMENTS)); | 4609 __ CmpP(r5, Operand(FAST_ELEMENTS)); |
4692 __ beq(&done); | 4610 __ beq(&done); |
4693 __ cmpi(r6, Operand(FAST_HOLEY_ELEMENTS)); | 4611 __ CmpP(r5, Operand(FAST_HOLEY_ELEMENTS)); |
4694 __ Assert(eq, kInvalidElementsKindForInternalArrayOrInternalPackedArray); | 4612 __ Assert(eq, kInvalidElementsKindForInternalArrayOrInternalPackedArray); |
4695 __ bind(&done); | 4613 __ bind(&done); |
4696 } | 4614 } |
4697 | 4615 |
4698 Label fast_elements_case; | 4616 Label fast_elements_case; |
4699 __ cmpi(r6, Operand(FAST_ELEMENTS)); | 4617 __ CmpP(r5, Operand(FAST_ELEMENTS)); |
4700 __ beq(&fast_elements_case); | 4618 __ beq(&fast_elements_case); |
4701 GenerateCase(masm, FAST_HOLEY_ELEMENTS); | 4619 GenerateCase(masm, FAST_HOLEY_ELEMENTS); |
4702 | 4620 |
4703 __ bind(&fast_elements_case); | 4621 __ bind(&fast_elements_case); |
4704 GenerateCase(masm, FAST_ELEMENTS); | 4622 GenerateCase(masm, FAST_ELEMENTS); |
4705 } | 4623 } |
4706 | 4624 |
4707 void FastNewObjectStub::Generate(MacroAssembler* masm) { | 4625 void FastNewObjectStub::Generate(MacroAssembler* masm) { |
4708 // ----------- S t a t e ------------- | 4626 // ----------- S t a t e ------------- |
4709 // -- r4 : target | 4627 // -- r3 : target |
4710 // -- r6 : new target | 4628 // -- r5 : new target |
4711 // -- cp : context | 4629 // -- cp : context |
4712 // -- lr : return address | 4630 // -- lr : return address |
4713 // ----------------------------------- | 4631 // ----------------------------------- |
4714 __ AssertFunction(r4); | 4632 __ AssertFunction(r3); |
4715 __ AssertReceiver(r6); | 4633 __ AssertReceiver(r5); |
4716 | 4634 |
4717 // Verify that the new target is a JSFunction. | 4635 // Verify that the new target is a JSFunction. |
4718 Label new_object; | 4636 Label new_object; |
4719 __ CompareObjectType(r6, r5, r5, JS_FUNCTION_TYPE); | 4637 __ CompareObjectType(r5, r4, r4, JS_FUNCTION_TYPE); |
4720 __ bne(&new_object); | 4638 __ bne(&new_object); |
4721 | 4639 |
4722 // Load the initial map and verify that it's in fact a map. | 4640 // Load the initial map and verify that it's in fact a map. |
4723 __ LoadP(r5, FieldMemOperand(r6, JSFunction::kPrototypeOrInitialMapOffset)); | 4641 __ LoadP(r4, FieldMemOperand(r5, JSFunction::kPrototypeOrInitialMapOffset)); |
4724 __ JumpIfSmi(r5, &new_object); | 4642 __ JumpIfSmi(r4, &new_object); |
4725 __ CompareObjectType(r5, r3, r3, MAP_TYPE); | 4643 __ CompareObjectType(r4, r2, r2, MAP_TYPE); |
4726 __ bne(&new_object); | 4644 __ bne(&new_object); |
4727 | 4645 |
4728 // Fall back to runtime if the target differs from the new target's | 4646 // Fall back to runtime if the target differs from the new target's |
4729 // initial map constructor. | 4647 // initial map constructor. |
4730 __ LoadP(r3, FieldMemOperand(r5, Map::kConstructorOrBackPointerOffset)); | 4648 __ LoadP(r2, FieldMemOperand(r4, Map::kConstructorOrBackPointerOffset)); |
4731 __ cmp(r3, r4); | 4649 __ CmpP(r2, r3); |
4732 __ bne(&new_object); | 4650 __ bne(&new_object); |
4733 | 4651 |
4734 // Allocate the JSObject on the heap. | 4652 // Allocate the JSObject on the heap. |
4735 Label allocate, done_allocate; | 4653 Label allocate, done_allocate; |
4736 __ lbz(r7, FieldMemOperand(r5, Map::kInstanceSizeOffset)); | 4654 __ LoadlB(r6, FieldMemOperand(r4, Map::kInstanceSizeOffset)); |
4737 __ Allocate(r7, r3, r8, r9, &allocate, SIZE_IN_WORDS); | 4655 __ Allocate(r6, r2, r7, r8, &allocate, SIZE_IN_WORDS); |
4738 __ bind(&done_allocate); | 4656 __ bind(&done_allocate); |
4739 | 4657 |
4740 // Initialize the JSObject fields. | 4658 // Initialize the JSObject fields. |
4741 __ StoreP(r5, MemOperand(r3, JSObject::kMapOffset)); | 4659 __ StoreP(r4, MemOperand(r2, JSObject::kMapOffset)); |
4742 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex); | 4660 __ LoadRoot(r5, Heap::kEmptyFixedArrayRootIndex); |
4743 __ StoreP(r6, MemOperand(r3, JSObject::kPropertiesOffset)); | 4661 __ StoreP(r5, MemOperand(r2, JSObject::kPropertiesOffset)); |
4744 __ StoreP(r6, MemOperand(r3, JSObject::kElementsOffset)); | 4662 __ StoreP(r5, MemOperand(r2, JSObject::kElementsOffset)); |
4745 STATIC_ASSERT(JSObject::kHeaderSize == 3 * kPointerSize); | 4663 STATIC_ASSERT(JSObject::kHeaderSize == 3 * kPointerSize); |
4746 __ addi(r4, r3, Operand(JSObject::kHeaderSize)); | 4664 __ AddP(r3, r2, Operand(JSObject::kHeaderSize)); |
4747 | 4665 |
4748 // ----------- S t a t e ------------- | 4666 // ----------- S t a t e ------------- |
4749 // -- r3 : result (untagged) | 4667 // -- r2 : result (untagged) |
4750 // -- r4 : result fields (untagged) | 4668 // -- r3 : result fields (untagged) |
4751 // -- r8 : result end (untagged) | 4669 // -- r7 : result end (untagged) |
4752 // -- r5 : initial map | 4670 // -- r4 : initial map |
4753 // -- cp : context | 4671 // -- cp : context |
4754 // -- lr : return address | 4672 // -- lr : return address |
4755 // ----------------------------------- | 4673 // ----------------------------------- |
4756 | 4674 |
4757 // Perform in-object slack tracking if requested. | 4675 // Perform in-object slack tracking if requested. |
4758 Label slack_tracking; | 4676 Label slack_tracking; |
4759 STATIC_ASSERT(Map::kNoSlackTracking == 0); | 4677 STATIC_ASSERT(Map::kNoSlackTracking == 0); |
4760 __ LoadRoot(r9, Heap::kUndefinedValueRootIndex); | 4678 __ LoadRoot(r8, Heap::kUndefinedValueRootIndex); |
4761 __ lwz(r6, FieldMemOperand(r5, Map::kBitField3Offset)); | 4679 __ LoadlW(r5, FieldMemOperand(r4, Map::kBitField3Offset)); |
4762 __ DecodeField<Map::ConstructionCounter>(r10, r6, SetRC); | 4680 __ DecodeField<Map::ConstructionCounter>(r9, r5); |
4763 __ bne(&slack_tracking, cr0); | 4681 __ LoadAndTestP(r9, r9); |
| 4682 __ bne(&slack_tracking); |
4764 { | 4683 { |
4765 // Initialize all in-object fields with undefined. | 4684 // Initialize all in-object fields with undefined. |
4766 __ InitializeFieldsWithFiller(r4, r8, r9); | 4685 __ InitializeFieldsWithFiller(r3, r7, r8); |
4767 | 4686 |
4768 // Add the object tag to make the JSObject real. | 4687 // Add the object tag to make the JSObject real. |
4769 __ addi(r3, r3, Operand(kHeapObjectTag)); | 4688 __ AddP(r2, r2, Operand(kHeapObjectTag)); |
4770 __ Ret(); | 4689 __ Ret(); |
4771 } | 4690 } |
4772 __ bind(&slack_tracking); | 4691 __ bind(&slack_tracking); |
4773 { | 4692 { |
4774 // Decrease generous allocation count. | 4693 // Decrease generous allocation count. |
4775 STATIC_ASSERT(Map::ConstructionCounter::kNext == 32); | 4694 STATIC_ASSERT(Map::ConstructionCounter::kNext == 32); |
4776 __ Add(r6, r6, -(1 << Map::ConstructionCounter::kShift), r0); | 4695 __ Add32(r5, r5, Operand(-(1 << Map::ConstructionCounter::kShift))); |
4777 __ stw(r6, FieldMemOperand(r5, Map::kBitField3Offset)); | 4696 __ StoreW(r5, FieldMemOperand(r4, Map::kBitField3Offset)); |
4778 | 4697 |
4779 // Initialize the in-object fields with undefined. | 4698 // Initialize the in-object fields with undefined. |
4780 __ lbz(r7, FieldMemOperand(r5, Map::kUnusedPropertyFieldsOffset)); | 4699 __ LoadlB(r6, FieldMemOperand(r4, Map::kUnusedPropertyFieldsOffset)); |
4781 __ ShiftLeftImm(r7, r7, Operand(kPointerSizeLog2)); | 4700 __ ShiftLeftP(r6, r6, Operand(kPointerSizeLog2)); |
4782 __ sub(r7, r8, r7); | 4701 __ SubP(r6, r7, r6); |
4783 __ InitializeFieldsWithFiller(r4, r7, r9); | 4702 __ InitializeFieldsWithFiller(r3, r6, r8); |
4784 | 4703 |
4785 // Initialize the remaining (reserved) fields with one pointer filler map. | 4704 // Initialize the remaining (reserved) fields with one pointer filler map. |
4786 __ LoadRoot(r9, Heap::kOnePointerFillerMapRootIndex); | 4705 __ LoadRoot(r8, Heap::kOnePointerFillerMapRootIndex); |
4787 __ InitializeFieldsWithFiller(r4, r8, r9); | 4706 __ InitializeFieldsWithFiller(r3, r7, r8); |
4788 | 4707 |
4789 // Add the object tag to make the JSObject real. | 4708 // Add the object tag to make the JSObject real. |
4790 __ addi(r3, r3, Operand(kHeapObjectTag)); | 4709 __ AddP(r2, r2, Operand(kHeapObjectTag)); |
4791 | 4710 |
4792 // Check if we can finalize the instance size. | 4711 // Check if we can finalize the instance size. |
4793 __ cmpi(r10, Operand(Map::kSlackTrackingCounterEnd)); | 4712 __ CmpP(r9, Operand(Map::kSlackTrackingCounterEnd)); |
4794 __ Ret(ne); | 4713 __ Ret(ne); |
4795 | 4714 |
4796 // Finalize the instance size. | 4715 // Finalize the instance size. |
4797 { | 4716 { |
4798 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 4717 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
4799 __ Push(r3, r5); | 4718 __ Push(r2, r4); |
4800 __ CallRuntime(Runtime::kFinalizeInstanceSize); | 4719 __ CallRuntime(Runtime::kFinalizeInstanceSize); |
4801 __ Pop(r3); | 4720 __ Pop(r2); |
4802 } | 4721 } |
4803 __ Ret(); | 4722 __ Ret(); |
4804 } | 4723 } |
4805 | 4724 |
4806 // Fall back to %AllocateInNewSpace. | 4725 // Fall back to %AllocateInNewSpace. |
4807 __ bind(&allocate); | 4726 __ bind(&allocate); |
4808 { | 4727 { |
4809 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 4728 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
4810 STATIC_ASSERT(kSmiTag == 0); | 4729 STATIC_ASSERT(kSmiTag == 0); |
4811 __ ShiftLeftImm(r7, r7, | 4730 __ ShiftLeftP(r6, r6, |
4812 Operand(kPointerSizeLog2 + kSmiTagSize + kSmiShiftSize)); | 4731 Operand(kPointerSizeLog2 + kSmiTagSize + kSmiShiftSize)); |
4813 __ Push(r5, r7); | 4732 __ Push(r4, r6); |
4814 __ CallRuntime(Runtime::kAllocateInNewSpace); | 4733 __ CallRuntime(Runtime::kAllocateInNewSpace); |
4815 __ Pop(r5); | 4734 __ Pop(r4); |
4816 } | 4735 } |
4817 __ subi(r3, r3, Operand(kHeapObjectTag)); | 4736 __ SubP(r2, r2, Operand(kHeapObjectTag)); |
4818 __ lbz(r8, FieldMemOperand(r5, Map::kInstanceSizeOffset)); | 4737 __ LoadlB(r7, FieldMemOperand(r4, Map::kInstanceSizeOffset)); |
4819 __ ShiftLeftImm(r8, r8, Operand(kPointerSizeLog2)); | 4738 __ ShiftLeftP(r7, r7, Operand(kPointerSizeLog2)); |
4820 __ add(r8, r3, r8); | 4739 __ AddP(r7, r2, r7); |
4821 __ b(&done_allocate); | 4740 __ b(&done_allocate); |
4822 | 4741 |
4823 // Fall back to %NewObject. | 4742 // Fall back to %NewObject. |
4824 __ bind(&new_object); | 4743 __ bind(&new_object); |
4825 __ Push(r4, r6); | 4744 __ Push(r3, r5); |
4826 __ TailCallRuntime(Runtime::kNewObject); | 4745 __ TailCallRuntime(Runtime::kNewObject); |
4827 } | 4746 } |
4828 | 4747 |
4829 void FastNewRestParameterStub::Generate(MacroAssembler* masm) { | 4748 void FastNewRestParameterStub::Generate(MacroAssembler* masm) { |
4830 // ----------- S t a t e ------------- | 4749 // ----------- S t a t e ------------- |
4831 // -- r4 : function | 4750 // -- r3 : function |
4832 // -- cp : context | 4751 // -- cp : context |
4833 // -- fp : frame pointer | 4752 // -- fp : frame pointer |
4834 // -- lr : return address | 4753 // -- lr : return address |
4835 // ----------------------------------- | 4754 // ----------------------------------- |
4836 __ AssertFunction(r4); | 4755 __ AssertFunction(r3); |
4837 | 4756 |
4838 // For Ignition we need to skip all possible handler/stub frames until | 4757 // For Ignition we need to skip all possible handler/stub frames until |
4839 // we reach the JavaScript frame for the function (similar to what the | 4758 // we reach the JavaScript frame for the function (similar to what the |
4840 // runtime fallback implementation does). So make r5 point to that | 4759 // runtime fallback implementation does). So make r4 point to that |
4841 // JavaScript frame. | 4760 // JavaScript frame. |
4842 { | 4761 { |
4843 Label loop, loop_entry; | 4762 Label loop, loop_entry; |
4844 __ mr(r5, fp); | 4763 __ LoadRR(r4, fp); |
4845 __ b(&loop_entry); | 4764 __ b(&loop_entry); |
4846 __ bind(&loop); | 4765 __ bind(&loop); |
4847 __ LoadP(r5, MemOperand(r5, StandardFrameConstants::kCallerFPOffset)); | 4766 __ LoadP(r4, MemOperand(r4, StandardFrameConstants::kCallerFPOffset)); |
4848 __ bind(&loop_entry); | 4767 __ bind(&loop_entry); |
4849 __ LoadP(ip, MemOperand(r5, StandardFrameConstants::kMarkerOffset)); | 4768 __ LoadP(ip, MemOperand(r4, StandardFrameConstants::kMarkerOffset)); |
4850 __ cmp(ip, r4); | 4769 __ CmpP(ip, r3); |
4851 __ bne(&loop); | 4770 __ bne(&loop); |
4852 } | 4771 } |
4853 | 4772 |
4854 // Check if we have rest parameters (only possible if we have an | 4773 // Check if we have rest parameters (only possible if we have an |
4855 // arguments adaptor frame below the function frame). | 4774 // arguments adaptor frame below the function frame). |
4856 Label no_rest_parameters; | 4775 Label no_rest_parameters; |
4857 __ LoadP(r5, MemOperand(r5, StandardFrameConstants::kCallerFPOffset)); | 4776 __ LoadP(r4, MemOperand(r4, StandardFrameConstants::kCallerFPOffset)); |
4858 __ LoadP(ip, MemOperand(r5, StandardFrameConstants::kContextOffset)); | 4777 __ LoadP(ip, MemOperand(r4, StandardFrameConstants::kContextOffset)); |
4859 __ CmpSmiLiteral(ip, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0); | 4778 __ CmpSmiLiteral(ip, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0); |
4860 __ bne(&no_rest_parameters); | 4779 __ bne(&no_rest_parameters); |
4861 | 4780 |
4862 // Check if the arguments adaptor frame contains more arguments than | 4781 // Check if the arguments adaptor frame contains more arguments than |
4863 // specified by the function's internal formal parameter count. | 4782 // specified by the function's internal formal parameter count. |
4864 Label rest_parameters; | 4783 Label rest_parameters; |
4865 __ LoadP(r3, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 4784 __ LoadP(r2, MemOperand(r4, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
4866 __ LoadP(r4, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); | 4785 __ LoadP(r3, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset)); |
4867 __ LoadWordArith( | 4786 __ LoadW( |
4868 r4, FieldMemOperand(r4, SharedFunctionInfo::kFormalParameterCountOffset)); | 4787 r3, FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset)); |
4869 #if V8_TARGET_ARCH_PPC64 | 4788 #if V8_TARGET_ARCH_S390X |
4870 __ SmiTag(r4); | 4789 __ SmiTag(r3); |
4871 #endif | 4790 #endif |
4872 __ sub(r3, r3, r4, LeaveOE, SetRC); | 4791 __ SubP(r2, r2, r3); |
4873 __ bgt(&rest_parameters, cr0); | 4792 __ bgt(&rest_parameters); |
4874 | 4793 |
4875 // Return an empty rest parameter array. | 4794 // Return an empty rest parameter array. |
4876 __ bind(&no_rest_parameters); | 4795 __ bind(&no_rest_parameters); |
4877 { | 4796 { |
4878 // ----------- S t a t e ------------- | 4797 // ----------- S t a t e ------------- |
4879 // -- cp : context | 4798 // -- cp : context |
4880 // -- lr : return address | 4799 // -- lr : return address |
4881 // ----------------------------------- | 4800 // ----------------------------------- |
4882 | 4801 |
4883 // Allocate an empty rest parameter array. | 4802 // Allocate an empty rest parameter array. |
4884 Label allocate, done_allocate; | 4803 Label allocate, done_allocate; |
4885 __ Allocate(JSArray::kSize, r3, r4, r5, &allocate, TAG_OBJECT); | 4804 __ Allocate(JSArray::kSize, r2, r3, r4, &allocate, TAG_OBJECT); |
4886 __ bind(&done_allocate); | 4805 __ bind(&done_allocate); |
4887 | 4806 |
4888 // Setup the rest parameter array in r0. | 4807 // Setup the rest parameter array in r0. |
4889 __ LoadNativeContextSlot(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, r4); | 4808 __ LoadNativeContextSlot(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, r3); |
4890 __ StoreP(r4, FieldMemOperand(r3, JSArray::kMapOffset), r0); | 4809 __ StoreP(r3, FieldMemOperand(r2, JSArray::kMapOffset), r0); |
4891 __ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex); | 4810 __ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex); |
4892 __ StoreP(r4, FieldMemOperand(r3, JSArray::kPropertiesOffset), r0); | 4811 __ StoreP(r3, FieldMemOperand(r2, JSArray::kPropertiesOffset), r0); |
4893 __ StoreP(r4, FieldMemOperand(r3, JSArray::kElementsOffset), r0); | 4812 __ StoreP(r3, FieldMemOperand(r2, JSArray::kElementsOffset), r0); |
4894 __ li(r4, Operand::Zero()); | 4813 __ LoadImmP(r3, Operand::Zero()); |
4895 __ StoreP(r4, FieldMemOperand(r3, JSArray::kLengthOffset), r0); | 4814 __ StoreP(r3, FieldMemOperand(r2, JSArray::kLengthOffset), r0); |
4896 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); | 4815 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); |
4897 __ Ret(); | 4816 __ Ret(); |
4898 | 4817 |
4899 // Fall back to %AllocateInNewSpace. | 4818 // Fall back to %AllocateInNewSpace. |
4900 __ bind(&allocate); | 4819 __ bind(&allocate); |
4901 { | 4820 { |
4902 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 4821 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
4903 __ Push(Smi::FromInt(JSArray::kSize)); | 4822 __ Push(Smi::FromInt(JSArray::kSize)); |
4904 __ CallRuntime(Runtime::kAllocateInNewSpace); | 4823 __ CallRuntime(Runtime::kAllocateInNewSpace); |
4905 } | 4824 } |
4906 __ b(&done_allocate); | 4825 __ b(&done_allocate); |
4907 } | 4826 } |
4908 | 4827 |
4909 __ bind(&rest_parameters); | 4828 __ bind(&rest_parameters); |
4910 { | 4829 { |
4911 // Compute the pointer to the first rest parameter (skippping the receiver). | 4830 // Compute the pointer to the first rest parameter (skippping the receiver). |
4912 __ SmiToPtrArrayOffset(r9, r3); | 4831 __ SmiToPtrArrayOffset(r8, r2); |
4913 __ add(r5, r5, r9); | 4832 __ AddP(r4, r4, r8); |
4914 __ addi(r5, r5, Operand(StandardFrameConstants::kCallerSPOffset)); | 4833 __ AddP(r4, r4, Operand(StandardFrameConstants::kCallerSPOffset)); |
4915 | 4834 |
4916 // ----------- S t a t e ------------- | 4835 // ----------- S t a t e ------------- |
4917 // -- cp : context | 4836 // -- cp : context |
4918 // -- r3 : number of rest parameters (tagged) | 4837 // -- r2 : number of rest parameters (tagged) |
4919 // -- r5 : pointer just past first rest parameters | 4838 // -- r4 : pointer just past first rest parameters |
4920 // -- r9 : size of rest parameters | 4839 // -- r8 : size of rest parameters |
4921 // -- lr : return address | 4840 // -- lr : return address |
4922 // ----------------------------------- | 4841 // ----------------------------------- |
4923 | 4842 |
4924 // Allocate space for the rest parameter array plus the backing store. | 4843 // Allocate space for the rest parameter array plus the backing store. |
4925 Label allocate, done_allocate; | 4844 Label allocate, done_allocate; |
4926 __ mov(r4, Operand(JSArray::kSize + FixedArray::kHeaderSize)); | 4845 __ mov(r3, Operand(JSArray::kSize + FixedArray::kHeaderSize)); |
4927 __ add(r4, r4, r9); | 4846 __ AddP(r3, r3, r8); |
4928 __ Allocate(r4, r6, r7, r8, &allocate, TAG_OBJECT); | 4847 __ Allocate(r3, r5, r6, r7, &allocate, TAG_OBJECT); |
4929 __ bind(&done_allocate); | 4848 __ bind(&done_allocate); |
4930 | 4849 |
4931 // Setup the elements array in r6. | 4850 // Setup the elements array in r5. |
4932 __ LoadRoot(r4, Heap::kFixedArrayMapRootIndex); | 4851 __ LoadRoot(r3, Heap::kFixedArrayMapRootIndex); |
4933 __ StoreP(r4, FieldMemOperand(r6, FixedArray::kMapOffset), r0); | 4852 __ StoreP(r3, FieldMemOperand(r5, FixedArray::kMapOffset), r0); |
4934 __ StoreP(r3, FieldMemOperand(r6, FixedArray::kLengthOffset), r0); | 4853 __ StoreP(r2, FieldMemOperand(r5, FixedArray::kLengthOffset), r0); |
4935 __ addi(r7, r6, | 4854 __ AddP(r6, r5, |
4936 Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize)); | 4855 Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize)); |
4937 { | 4856 { |
4938 Label loop; | 4857 Label loop; |
4939 __ SmiUntag(r0, r3); | 4858 __ SmiUntag(r1, r2); |
4940 __ mtctr(r0); | 4859 // __ mtctr(r0); |
4941 __ bind(&loop); | 4860 __ bind(&loop); |
4942 __ LoadPU(ip, MemOperand(r5, -kPointerSize)); | 4861 __ lay(r4, MemOperand(r4, -kPointerSize)); |
4943 __ StorePU(ip, MemOperand(r7, kPointerSize)); | 4862 __ LoadP(ip, MemOperand(r4)); |
4944 __ bdnz(&loop); | 4863 __ la(r6, MemOperand(r6, kPointerSize)); |
4945 __ addi(r7, r7, Operand(kPointerSize)); | 4864 __ StoreP(ip, MemOperand(r6)); |
| 4865 // __ bdnz(&loop); |
| 4866 __ BranchOnCount(r1, &loop); |
| 4867 __ AddP(r6, r6, Operand(kPointerSize)); |
4946 } | 4868 } |
4947 | 4869 |
4948 // Setup the rest parameter array in r7. | 4870 // Setup the rest parameter array in r6. |
4949 __ LoadNativeContextSlot(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, r4); | 4871 __ LoadNativeContextSlot(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, r3); |
4950 __ StoreP(r4, MemOperand(r7, JSArray::kMapOffset)); | 4872 __ StoreP(r3, MemOperand(r6, JSArray::kMapOffset)); |
4951 __ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex); | 4873 __ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex); |
4952 __ StoreP(r4, MemOperand(r7, JSArray::kPropertiesOffset)); | 4874 __ StoreP(r3, MemOperand(r6, JSArray::kPropertiesOffset)); |
4953 __ StoreP(r6, MemOperand(r7, JSArray::kElementsOffset)); | 4875 __ StoreP(r5, MemOperand(r6, JSArray::kElementsOffset)); |
4954 __ StoreP(r3, MemOperand(r7, JSArray::kLengthOffset)); | 4876 __ StoreP(r2, MemOperand(r6, JSArray::kLengthOffset)); |
4955 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); | 4877 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); |
4956 __ addi(r3, r7, Operand(kHeapObjectTag)); | 4878 __ AddP(r2, r6, Operand(kHeapObjectTag)); |
4957 __ Ret(); | 4879 __ Ret(); |
4958 | 4880 |
4959 // Fall back to %AllocateInNewSpace. | 4881 // Fall back to %AllocateInNewSpace. |
4960 __ bind(&allocate); | 4882 __ bind(&allocate); |
4961 { | 4883 { |
4962 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 4884 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
4963 __ SmiTag(r4); | 4885 __ SmiTag(r3); |
4964 __ Push(r3, r5, r4); | 4886 __ Push(r2, r4, r3); |
4965 __ CallRuntime(Runtime::kAllocateInNewSpace); | 4887 __ CallRuntime(Runtime::kAllocateInNewSpace); |
4966 __ mr(r6, r3); | 4888 __ LoadRR(r5, r2); |
4967 __ Pop(r3, r5); | 4889 __ Pop(r2, r4); |
4968 } | 4890 } |
4969 __ b(&done_allocate); | 4891 __ b(&done_allocate); |
4970 } | 4892 } |
4971 } | 4893 } |
4972 | 4894 |
4973 void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) { | 4895 void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) { |
4974 // ----------- S t a t e ------------- | 4896 // ----------- S t a t e ------------- |
4975 // -- r4 : function | 4897 // -- r3 : function |
4976 // -- cp : context | 4898 // -- cp : context |
4977 // -- fp : frame pointer | 4899 // -- fp : frame pointer |
4978 // -- lr : return address | 4900 // -- lr : return address |
4979 // ----------------------------------- | 4901 // ----------------------------------- |
4980 __ AssertFunction(r4); | 4902 __ AssertFunction(r3); |
4981 | 4903 |
4982 // TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub. | 4904 // TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub. |
4983 __ LoadP(r5, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); | 4905 __ LoadP(r4, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset)); |
4984 __ LoadWordArith( | 4906 __ LoadW( |
4985 r5, FieldMemOperand(r5, SharedFunctionInfo::kFormalParameterCountOffset)); | 4907 r4, FieldMemOperand(r4, SharedFunctionInfo::kFormalParameterCountOffset)); |
4986 #if V8_TARGET_ARCH_PPC64 | 4908 #if V8_TARGET_ARCH_S390X |
4987 __ SmiTag(r5); | 4909 __ SmiTag(r4); |
4988 #endif | 4910 #endif |
4989 __ SmiToPtrArrayOffset(r6, r5); | 4911 __ SmiToPtrArrayOffset(r5, r4); |
4990 __ add(r6, fp, r6); | 4912 __ AddP(r5, fp, r5); |
4991 __ addi(r6, r6, Operand(StandardFrameConstants::kCallerSPOffset)); | 4913 __ AddP(r5, r5, Operand(StandardFrameConstants::kCallerSPOffset)); |
4992 | 4914 |
4993 // r4 : function | 4915 // r3 : function |
4994 // r5 : number of parameters (tagged) | 4916 // r4 : number of parameters (tagged) |
4995 // r6 : parameters pointer | 4917 // r5 : parameters pointer |
4996 // Registers used over whole function: | 4918 // Registers used over whole function: |
4997 // r8 : arguments count (tagged) | 4919 // r7 : arguments count (tagged) |
4998 // r9 : mapped parameter count (tagged) | 4920 // r8 : mapped parameter count (tagged) |
4999 | 4921 |
5000 // Check if the calling frame is an arguments adaptor frame. | 4922 // Check if the calling frame is an arguments adaptor frame. |
5001 Label adaptor_frame, try_allocate, runtime; | 4923 Label adaptor_frame, try_allocate, runtime; |
5002 __ LoadP(r7, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 4924 __ LoadP(r6, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
5003 __ LoadP(r3, MemOperand(r7, StandardFrameConstants::kContextOffset)); | 4925 __ LoadP(r2, MemOperand(r6, StandardFrameConstants::kContextOffset)); |
5004 __ CmpSmiLiteral(r3, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0); | 4926 __ CmpSmiLiteral(r2, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0); |
5005 __ beq(&adaptor_frame); | 4927 __ beq(&adaptor_frame); |
5006 | 4928 |
5007 // No adaptor, parameter count = argument count. | 4929 // No adaptor, parameter count = argument count. |
5008 __ mr(r8, r5); | 4930 __ LoadRR(r7, r4); |
5009 __ mr(r9, r5); | 4931 __ LoadRR(r8, r4); |
5010 __ b(&try_allocate); | 4932 __ b(&try_allocate); |
5011 | 4933 |
5012 // We have an adaptor frame. Patch the parameters pointer. | 4934 // We have an adaptor frame. Patch the parameters pointer. |
5013 __ bind(&adaptor_frame); | 4935 __ bind(&adaptor_frame); |
5014 __ LoadP(r8, MemOperand(r7, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 4936 __ LoadP(r7, MemOperand(r6, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
5015 __ SmiToPtrArrayOffset(r6, r8); | 4937 __ SmiToPtrArrayOffset(r5, r7); |
5016 __ add(r6, r6, r7); | 4938 __ AddP(r5, r5, r6); |
5017 __ addi(r6, r6, Operand(StandardFrameConstants::kCallerSPOffset)); | 4939 __ AddP(r5, r5, Operand(StandardFrameConstants::kCallerSPOffset)); |
5018 | 4940 |
5019 // r8 = argument count (tagged) | 4941 // r7 = argument count (tagged) |
5020 // r9 = parameter count (tagged) | 4942 // r8 = parameter count (tagged) |
5021 // Compute the mapped parameter count = min(r5, r8) in r9. | 4943 // Compute the mapped parameter count = min(r4, r7) in r8. |
5022 __ cmp(r5, r8); | 4944 __ CmpP(r4, r7); |
5023 if (CpuFeatures::IsSupported(ISELECT)) { | 4945 Label skip; |
5024 __ isel(lt, r9, r5, r8); | 4946 __ LoadRR(r8, r4); |
5025 } else { | 4947 __ blt(&skip); |
5026 Label skip; | 4948 __ LoadRR(r8, r7); |
5027 __ mr(r9, r5); | 4949 __ bind(&skip); |
5028 __ blt(&skip); | |
5029 __ mr(r9, r8); | |
5030 __ bind(&skip); | |
5031 } | |
5032 | 4950 |
5033 __ bind(&try_allocate); | 4951 __ bind(&try_allocate); |
5034 | 4952 |
5035 // Compute the sizes of backing store, parameter map, and arguments object. | 4953 // Compute the sizes of backing store, parameter map, and arguments object. |
5036 // 1. Parameter map, has 2 extra words containing context and backing store. | 4954 // 1. Parameter map, has 2 extra words containing context and backing store. |
5037 const int kParameterMapHeaderSize = | 4955 const int kParameterMapHeaderSize = |
5038 FixedArray::kHeaderSize + 2 * kPointerSize; | 4956 FixedArray::kHeaderSize + 2 * kPointerSize; |
5039 // If there are no mapped parameters, we do not need the parameter_map. | 4957 // If there are no mapped parameters, we do not need the parameter_map. |
5040 __ CmpSmiLiteral(r9, Smi::FromInt(0), r0); | 4958 __ CmpSmiLiteral(r8, Smi::FromInt(0), r0); |
5041 if (CpuFeatures::IsSupported(ISELECT)) { | 4959 Label skip2, skip3; |
5042 __ SmiToPtrArrayOffset(r11, r9); | 4960 __ bne(&skip2); |
5043 __ addi(r11, r11, Operand(kParameterMapHeaderSize)); | 4961 __ LoadImmP(r1, Operand::Zero()); |
5044 __ isel(eq, r11, r0, r11); | 4962 __ b(&skip3); |
5045 } else { | 4963 __ bind(&skip2); |
5046 Label skip2, skip3; | 4964 __ SmiToPtrArrayOffset(r1, r8); |
5047 __ bne(&skip2); | 4965 __ AddP(r1, r1, Operand(kParameterMapHeaderSize)); |
5048 __ li(r11, Operand::Zero()); | 4966 __ bind(&skip3); |
5049 __ b(&skip3); | |
5050 __ bind(&skip2); | |
5051 __ SmiToPtrArrayOffset(r11, r9); | |
5052 __ addi(r11, r11, Operand(kParameterMapHeaderSize)); | |
5053 __ bind(&skip3); | |
5054 } | |
5055 | 4967 |
5056 // 2. Backing store. | 4968 // 2. Backing store. |
5057 __ SmiToPtrArrayOffset(r7, r8); | 4969 __ SmiToPtrArrayOffset(r6, r7); |
5058 __ add(r11, r11, r7); | 4970 __ AddP(r1, r1, r6); |
5059 __ addi(r11, r11, Operand(FixedArray::kHeaderSize)); | 4971 __ AddP(r1, r1, Operand(FixedArray::kHeaderSize)); |
5060 | 4972 |
5061 // 3. Arguments object. | 4973 // 3. Arguments object. |
5062 __ addi(r11, r11, Operand(JSSloppyArgumentsObject::kSize)); | 4974 __ AddP(r1, r1, Operand(JSSloppyArgumentsObject::kSize)); |
5063 | 4975 |
5064 // Do the allocation of all three objects in one go. | 4976 // Do the allocation of all three objects in one go. |
5065 __ Allocate(r11, r3, r11, r7, &runtime, TAG_OBJECT); | 4977 __ Allocate(r1, r2, r1, r6, &runtime, TAG_OBJECT); |
5066 | 4978 |
5067 // r3 = address of new object(s) (tagged) | 4979 // r2 = address of new object(s) (tagged) |
5068 // r5 = argument count (smi-tagged) | 4980 // r4 = argument count (smi-tagged) |
5069 // Get the arguments boilerplate from the current native context into r4. | 4981 // Get the arguments boilerplate from the current native context into r3. |
5070 const int kNormalOffset = | 4982 const int kNormalOffset = |
5071 Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX); | 4983 Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX); |
5072 const int kAliasedOffset = | 4984 const int kAliasedOffset = |
5073 Context::SlotOffset(Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX); | 4985 Context::SlotOffset(Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX); |
5074 | 4986 |
5075 __ LoadP(r7, NativeContextMemOperand()); | 4987 __ LoadP(r6, NativeContextMemOperand()); |
5076 __ cmpi(r9, Operand::Zero()); | 4988 __ CmpP(r8, Operand::Zero()); |
5077 if (CpuFeatures::IsSupported(ISELECT)) { | 4989 Label skip4, skip5; |
5078 __ LoadP(r11, MemOperand(r7, kNormalOffset)); | 4990 __ bne(&skip4); |
5079 __ LoadP(r7, MemOperand(r7, kAliasedOffset)); | 4991 __ LoadP(r6, MemOperand(r6, kNormalOffset)); |
5080 __ isel(eq, r7, r11, r7); | 4992 __ b(&skip5); |
5081 } else { | 4993 __ bind(&skip4); |
5082 Label skip4, skip5; | 4994 __ LoadP(r6, MemOperand(r6, kAliasedOffset)); |
5083 __ bne(&skip4); | 4995 __ bind(&skip5); |
5084 __ LoadP(r7, MemOperand(r7, kNormalOffset)); | |
5085 __ b(&skip5); | |
5086 __ bind(&skip4); | |
5087 __ LoadP(r7, MemOperand(r7, kAliasedOffset)); | |
5088 __ bind(&skip5); | |
5089 } | |
5090 | 4996 |
5091 // r3 = address of new object (tagged) | 4997 // r2 = address of new object (tagged) |
5092 // r5 = argument count (smi-tagged) | 4998 // r4 = argument count (smi-tagged) |
5093 // r7 = address of arguments map (tagged) | 4999 // r6 = address of arguments map (tagged) |
5094 // r9 = mapped parameter count (tagged) | 5000 // r8 = mapped parameter count (tagged) |
5095 __ StoreP(r7, FieldMemOperand(r3, JSObject::kMapOffset), r0); | 5001 __ StoreP(r6, FieldMemOperand(r2, JSObject::kMapOffset), r0); |
5096 __ LoadRoot(r11, Heap::kEmptyFixedArrayRootIndex); | 5002 __ LoadRoot(r1, Heap::kEmptyFixedArrayRootIndex); |
5097 __ StoreP(r11, FieldMemOperand(r3, JSObject::kPropertiesOffset), r0); | 5003 __ StoreP(r1, FieldMemOperand(r2, JSObject::kPropertiesOffset), r0); |
5098 __ StoreP(r11, FieldMemOperand(r3, JSObject::kElementsOffset), r0); | 5004 __ StoreP(r1, FieldMemOperand(r2, JSObject::kElementsOffset), r0); |
5099 | 5005 |
5100 // Set up the callee in-object property. | 5006 // Set up the callee in-object property. |
5101 __ AssertNotSmi(r4); | 5007 __ AssertNotSmi(r3); |
5102 __ StoreP(r4, FieldMemOperand(r3, JSSloppyArgumentsObject::kCalleeOffset), | 5008 __ StoreP(r3, FieldMemOperand(r2, JSSloppyArgumentsObject::kCalleeOffset), |
5103 r0); | 5009 r0); |
5104 | 5010 |
5105 // Use the length (smi tagged) and set that as an in-object property too. | 5011 // Use the length (smi tagged) and set that as an in-object property too. |
5106 __ AssertSmi(r8); | 5012 __ AssertSmi(r7); |
5107 __ StoreP(r8, FieldMemOperand(r3, JSSloppyArgumentsObject::kLengthOffset), | 5013 __ StoreP(r7, FieldMemOperand(r2, JSSloppyArgumentsObject::kLengthOffset), |
5108 r0); | 5014 r0); |
5109 | 5015 |
5110 // Set up the elements pointer in the allocated arguments object. | 5016 // Set up the elements pointer in the allocated arguments object. |
5111 // If we allocated a parameter map, r7 will point there, otherwise | 5017 // If we allocated a parameter map, r6 will point there, otherwise |
5112 // it will point to the backing store. | 5018 // it will point to the backing store. |
5113 __ addi(r7, r3, Operand(JSSloppyArgumentsObject::kSize)); | 5019 __ AddP(r6, r2, Operand(JSSloppyArgumentsObject::kSize)); |
5114 __ StoreP(r7, FieldMemOperand(r3, JSObject::kElementsOffset), r0); | 5020 __ StoreP(r6, FieldMemOperand(r2, JSObject::kElementsOffset), r0); |
5115 | 5021 |
5116 // r3 = address of new object (tagged) | 5022 // r2 = address of new object (tagged) |
5117 // r5 = argument count (tagged) | 5023 // r4 = argument count (tagged) |
5118 // r7 = address of parameter map or backing store (tagged) | 5024 // r6 = address of parameter map or backing store (tagged) |
5119 // r9 = mapped parameter count (tagged) | 5025 // r8 = mapped parameter count (tagged) |
5120 // Initialize parameter map. If there are no mapped arguments, we're done. | 5026 // Initialize parameter map. If there are no mapped arguments, we're done. |
5121 Label skip_parameter_map; | 5027 Label skip_parameter_map; |
5122 __ CmpSmiLiteral(r9, Smi::FromInt(0), r0); | 5028 __ CmpSmiLiteral(r8, Smi::FromInt(0), r0); |
5123 if (CpuFeatures::IsSupported(ISELECT)) { | 5029 Label skip6; |
5124 __ isel(eq, r4, r7, r4); | 5030 __ bne(&skip6); |
5125 __ beq(&skip_parameter_map); | 5031 // Move backing store address to r3, because it is |
5126 } else { | 5032 // expected there when filling in the unmapped arguments. |
5127 Label skip6; | 5033 __ LoadRR(r3, r6); |
5128 __ bne(&skip6); | 5034 __ b(&skip_parameter_map); |
5129 // Move backing store address to r4, because it is | 5035 __ bind(&skip6); |
5130 // expected there when filling in the unmapped arguments. | |
5131 __ mr(r4, r7); | |
5132 __ b(&skip_parameter_map); | |
5133 __ bind(&skip6); | |
5134 } | |
5135 | 5036 |
5136 __ LoadRoot(r8, Heap::kSloppyArgumentsElementsMapRootIndex); | 5037 __ LoadRoot(r7, Heap::kSloppyArgumentsElementsMapRootIndex); |
5137 __ StoreP(r8, FieldMemOperand(r7, FixedArray::kMapOffset), r0); | 5038 __ StoreP(r7, FieldMemOperand(r6, FixedArray::kMapOffset), r0); |
5138 __ AddSmiLiteral(r8, r9, Smi::FromInt(2), r0); | 5039 __ AddSmiLiteral(r7, r8, Smi::FromInt(2), r0); |
5139 __ StoreP(r8, FieldMemOperand(r7, FixedArray::kLengthOffset), r0); | 5040 __ StoreP(r7, FieldMemOperand(r6, FixedArray::kLengthOffset), r0); |
5140 __ StoreP(cp, FieldMemOperand(r7, FixedArray::kHeaderSize + 0 * kPointerSize), | 5041 __ StoreP(cp, FieldMemOperand(r6, FixedArray::kHeaderSize + 0 * kPointerSize), |
5141 r0); | 5042 r0); |
5142 __ SmiToPtrArrayOffset(r8, r9); | 5043 __ SmiToPtrArrayOffset(r7, r8); |
5143 __ add(r8, r8, r7); | 5044 __ AddP(r7, r7, r6); |
5144 __ addi(r8, r8, Operand(kParameterMapHeaderSize)); | 5045 __ AddP(r7, r7, Operand(kParameterMapHeaderSize)); |
5145 __ StoreP(r8, FieldMemOperand(r7, FixedArray::kHeaderSize + 1 * kPointerSize), | 5046 __ StoreP(r7, FieldMemOperand(r6, FixedArray::kHeaderSize + 1 * kPointerSize), |
5146 r0); | 5047 r0); |
5147 | 5048 |
5148 // Copy the parameter slots and the holes in the arguments. | 5049 // Copy the parameter slots and the holes in the arguments. |
5149 // We need to fill in mapped_parameter_count slots. They index the context, | 5050 // We need to fill in mapped_parameter_count slots. They index the context, |
5150 // where parameters are stored in reverse order, at | 5051 // where parameters are stored in reverse order, at |
5151 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 | 5052 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 |
5152 // The mapped parameter thus need to get indices | 5053 // The mapped parameter thus need to get indices |
5153 // MIN_CONTEXT_SLOTS+parameter_count-1 .. | 5054 // MIN_CONTEXT_SLOTS+parameter_count-1 .. |
5154 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count | 5055 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count |
5155 // We loop from right to left. | 5056 // We loop from right to left. |
5156 Label parameters_loop; | 5057 Label parameters_loop; |
5157 __ mr(r8, r9); | 5058 __ LoadRR(r7, r8); |
5158 __ AddSmiLiteral(r11, r5, Smi::FromInt(Context::MIN_CONTEXT_SLOTS), r0); | 5059 __ AddSmiLiteral(r1, r4, Smi::FromInt(Context::MIN_CONTEXT_SLOTS), r0); |
5159 __ sub(r11, r11, r9); | 5060 __ SubP(r1, r1, r8); |
5160 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 5061 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
5161 __ SmiToPtrArrayOffset(r4, r8); | 5062 __ SmiToPtrArrayOffset(r3, r7); |
5162 __ add(r4, r4, r7); | 5063 __ AddP(r3, r3, r6); |
5163 __ addi(r4, r4, Operand(kParameterMapHeaderSize)); | 5064 __ AddP(r3, r3, Operand(kParameterMapHeaderSize)); |
5164 | 5065 |
5165 // r4 = address of backing store (tagged) | 5066 // r3 = address of backing store (tagged) |
5166 // r7 = address of parameter map (tagged) | 5067 // r6 = address of parameter map (tagged) |
5167 // r8 = temporary scratch (a.o., for address calculation) | 5068 // r7 = temporary scratch (a.o., for address calculation) |
5168 // r10 = temporary scratch (a.o., for address calculation) | 5069 // r9 = temporary scratch (a.o., for address calculation) |
5169 // ip = the hole value | 5070 // ip = the hole value |
5170 __ SmiUntag(r8); | 5071 __ SmiUntag(r7); |
5171 __ mtctr(r8); | 5072 __ push(r4); |
5172 __ ShiftLeftImm(r8, r8, Operand(kPointerSizeLog2)); | 5073 __ LoadRR(r4, r7); |
5173 __ add(r10, r4, r8); | 5074 __ ShiftLeftP(r7, r7, Operand(kPointerSizeLog2)); |
5174 __ add(r8, r7, r8); | 5075 __ AddP(r9, r3, r7); |
5175 __ addi(r10, r10, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 5076 __ AddP(r7, r6, r7); |
5176 __ addi(r8, r8, Operand(kParameterMapHeaderSize - kHeapObjectTag)); | 5077 __ AddP(r9, r9, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 5078 __ AddP(r7, r7, Operand(kParameterMapHeaderSize - kHeapObjectTag)); |
5177 | 5079 |
5178 __ bind(¶meters_loop); | 5080 __ bind(¶meters_loop); |
5179 __ StorePU(r11, MemOperand(r8, -kPointerSize)); | 5081 __ StoreP(r1, MemOperand(r7, -kPointerSize)); |
5180 __ StorePU(ip, MemOperand(r10, -kPointerSize)); | 5082 __ lay(r7, MemOperand(r7, -kPointerSize)); |
5181 __ AddSmiLiteral(r11, r11, Smi::FromInt(1), r0); | 5083 __ StoreP(ip, MemOperand(r9, -kPointerSize)); |
5182 __ bdnz(¶meters_loop); | 5084 __ lay(r9, MemOperand(r9, -kPointerSize)); |
| 5085 __ AddSmiLiteral(r1, r1, Smi::FromInt(1), r0); |
| 5086 __ BranchOnCount(r4, ¶meters_loop); |
| 5087 __ pop(r4); |
5183 | 5088 |
5184 // Restore r8 = argument count (tagged). | 5089 // Restore r7 = argument count (tagged). |
5185 __ LoadP(r8, FieldMemOperand(r3, JSSloppyArgumentsObject::kLengthOffset)); | 5090 __ LoadP(r7, FieldMemOperand(r2, JSSloppyArgumentsObject::kLengthOffset)); |
5186 | 5091 |
5187 __ bind(&skip_parameter_map); | 5092 __ bind(&skip_parameter_map); |
5188 // r3 = address of new object (tagged) | 5093 // r2 = address of new object (tagged) |
5189 // r4 = address of backing store (tagged) | 5094 // r3 = address of backing store (tagged) |
5190 // r8 = argument count (tagged) | 5095 // r7 = argument count (tagged) |
5191 // r9 = mapped parameter count (tagged) | 5096 // r8 = mapped parameter count (tagged) |
5192 // r11 = scratch | 5097 // r1 = scratch |
5193 // Copy arguments header and remaining slots (if there are any). | 5098 // Copy arguments header and remaining slots (if there are any). |
5194 __ LoadRoot(r11, Heap::kFixedArrayMapRootIndex); | 5099 __ LoadRoot(r1, Heap::kFixedArrayMapRootIndex); |
5195 __ StoreP(r11, FieldMemOperand(r4, FixedArray::kMapOffset), r0); | 5100 __ StoreP(r1, FieldMemOperand(r3, FixedArray::kMapOffset), r0); |
5196 __ StoreP(r8, FieldMemOperand(r4, FixedArray::kLengthOffset), r0); | 5101 __ StoreP(r7, FieldMemOperand(r3, FixedArray::kLengthOffset), r0); |
5197 __ sub(r11, r8, r9, LeaveOE, SetRC); | 5102 __ SubP(r1, r7, r8); |
5198 __ Ret(eq, cr0); | 5103 __ Ret(eq); |
5199 | 5104 |
5200 Label arguments_loop; | 5105 Label arguments_loop; |
5201 __ SmiUntag(r11); | 5106 __ SmiUntag(r1); |
5202 __ mtctr(r11); | 5107 __ LoadRR(r4, r1); |
5203 | 5108 |
5204 __ SmiToPtrArrayOffset(r0, r9); | 5109 __ SmiToPtrArrayOffset(r0, r8); |
5205 __ sub(r6, r6, r0); | 5110 __ SubP(r5, r5, r0); |
5206 __ add(r11, r4, r0); | 5111 __ AddP(r1, r3, r0); |
5207 __ addi(r11, r11, | 5112 __ AddP(r1, r1, |
5208 Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize)); | 5113 Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize)); |
5209 | 5114 |
5210 __ bind(&arguments_loop); | 5115 __ bind(&arguments_loop); |
5211 __ LoadPU(r7, MemOperand(r6, -kPointerSize)); | 5116 __ LoadP(r6, MemOperand(r5, -kPointerSize)); |
5212 __ StorePU(r7, MemOperand(r11, kPointerSize)); | 5117 __ lay(r5, MemOperand(r5, -kPointerSize)); |
5213 __ bdnz(&arguments_loop); | 5118 __ StoreP(r6, MemOperand(r1, kPointerSize)); |
| 5119 __ la(r1, MemOperand(r1, kPointerSize)); |
| 5120 __ BranchOnCount(r4, &arguments_loop); |
5214 | 5121 |
5215 // Return. | 5122 // Return. |
5216 __ Ret(); | 5123 __ Ret(); |
5217 | 5124 |
5218 // Do the runtime call to allocate the arguments object. | 5125 // Do the runtime call to allocate the arguments object. |
5219 // r8 = argument count (tagged) | 5126 // r7 = argument count (tagged) |
5220 __ bind(&runtime); | 5127 __ bind(&runtime); |
5221 __ Push(r4, r6, r8); | 5128 __ Push(r3, r5, r7); |
5222 __ TailCallRuntime(Runtime::kNewSloppyArguments); | 5129 __ TailCallRuntime(Runtime::kNewSloppyArguments); |
5223 } | 5130 } |
5224 | 5131 |
5225 void FastNewStrictArgumentsStub::Generate(MacroAssembler* masm) { | 5132 void FastNewStrictArgumentsStub::Generate(MacroAssembler* masm) { |
5226 // ----------- S t a t e ------------- | 5133 // ----------- S t a t e ------------- |
5227 // -- r4 : function | 5134 // -- r3 : function |
5228 // -- cp : context | 5135 // -- cp : context |
5229 // -- fp : frame pointer | 5136 // -- fp : frame pointer |
5230 // -- lr : return address | 5137 // -- lr : return address |
5231 // ----------------------------------- | 5138 // ----------------------------------- |
5232 __ AssertFunction(r4); | 5139 __ AssertFunction(r3); |
5233 | 5140 |
5234 // For Ignition we need to skip all possible handler/stub frames until | 5141 // For Ignition we need to skip all possible handler/stub frames until |
5235 // we reach the JavaScript frame for the function (similar to what the | 5142 // we reach the JavaScript frame for the function (similar to what the |
5236 // runtime fallback implementation does). So make r5 point to that | 5143 // runtime fallback implementation does). So make r4 point to that |
5237 // JavaScript frame. | 5144 // JavaScript frame. |
5238 { | 5145 { |
5239 Label loop, loop_entry; | 5146 Label loop, loop_entry; |
5240 __ mr(r5, fp); | 5147 __ LoadRR(r4, fp); |
5241 __ b(&loop_entry); | 5148 __ b(&loop_entry); |
5242 __ bind(&loop); | 5149 __ bind(&loop); |
5243 __ LoadP(r5, MemOperand(r5, StandardFrameConstants::kCallerFPOffset)); | 5150 __ LoadP(r4, MemOperand(r4, StandardFrameConstants::kCallerFPOffset)); |
5244 __ bind(&loop_entry); | 5151 __ bind(&loop_entry); |
5245 __ LoadP(ip, MemOperand(r5, StandardFrameConstants::kMarkerOffset)); | 5152 __ LoadP(ip, MemOperand(r4, StandardFrameConstants::kMarkerOffset)); |
5246 __ cmp(ip, r4); | 5153 __ CmpP(ip, r3); |
5247 __ bne(&loop); | 5154 __ bne(&loop); |
5248 } | 5155 } |
5249 | 5156 |
5250 // Check if we have an arguments adaptor frame below the function frame. | 5157 // Check if we have an arguments adaptor frame below the function frame. |
5251 Label arguments_adaptor, arguments_done; | 5158 Label arguments_adaptor, arguments_done; |
5252 __ LoadP(r6, MemOperand(r5, StandardFrameConstants::kCallerFPOffset)); | 5159 __ LoadP(r5, MemOperand(r4, StandardFrameConstants::kCallerFPOffset)); |
5253 __ LoadP(ip, MemOperand(r6, StandardFrameConstants::kContextOffset)); | 5160 __ LoadP(ip, MemOperand(r5, StandardFrameConstants::kContextOffset)); |
5254 __ CmpSmiLiteral(ip, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0); | 5161 __ CmpSmiLiteral(ip, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0); |
5255 __ beq(&arguments_adaptor); | 5162 __ beq(&arguments_adaptor); |
5256 { | 5163 { |
5257 __ LoadP(r4, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); | 5164 __ LoadP(r3, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset)); |
5258 __ LoadWordArith( | 5165 __ LoadW(r2, FieldMemOperand( |
5259 r3, | 5166 r3, SharedFunctionInfo::kFormalParameterCountOffset)); |
5260 FieldMemOperand(r4, SharedFunctionInfo::kFormalParameterCountOffset)); | 5167 #if V8_TARGET_ARCH_S390X |
5261 #if V8_TARGET_ARCH_PPC64 | 5168 __ SmiTag(r2); |
5262 __ SmiTag(r3); | |
5263 #endif | 5169 #endif |
5264 __ SmiToPtrArrayOffset(r9, r3); | 5170 __ SmiToPtrArrayOffset(r8, r2); |
5265 __ add(r5, r5, r9); | 5171 __ AddP(r4, r4, r8); |
5266 } | 5172 } |
5267 __ b(&arguments_done); | 5173 __ b(&arguments_done); |
5268 __ bind(&arguments_adaptor); | 5174 __ bind(&arguments_adaptor); |
5269 { | 5175 { |
5270 __ LoadP(r3, MemOperand(r6, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 5176 __ LoadP(r2, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
5271 __ SmiToPtrArrayOffset(r9, r3); | 5177 __ SmiToPtrArrayOffset(r8, r2); |
5272 __ add(r5, r6, r9); | 5178 __ AddP(r4, r5, r8); |
5273 } | 5179 } |
5274 __ bind(&arguments_done); | 5180 __ bind(&arguments_done); |
5275 __ addi(r5, r5, Operand(StandardFrameConstants::kCallerSPOffset)); | 5181 __ AddP(r4, r4, Operand(StandardFrameConstants::kCallerSPOffset)); |
5276 | 5182 |
5277 // ----------- S t a t e ------------- | 5183 // ----------- S t a t e ------------- |
5278 // -- cp : context | 5184 // -- cp : context |
5279 // -- r3 : number of rest parameters (tagged) | 5185 // -- r2 : number of rest parameters (tagged) |
5280 // -- r5 : pointer just past first rest parameters | 5186 // -- r4 : pointer just past first rest parameters |
5281 // -- r9 : size of rest parameters | 5187 // -- r8 : size of rest parameters |
5282 // -- lr : return address | 5188 // -- lr : return address |
5283 // ----------------------------------- | 5189 // ----------------------------------- |
5284 | 5190 |
5285 // Allocate space for the strict arguments object plus the backing store. | 5191 // Allocate space for the strict arguments object plus the backing store. |
5286 Label allocate, done_allocate; | 5192 Label allocate, done_allocate; |
5287 __ mov(r4, Operand(JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize)); | 5193 __ mov(r3, Operand(JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize)); |
5288 __ add(r4, r4, r9); | 5194 __ AddP(r3, r3, r8); |
5289 __ Allocate(r4, r6, r7, r8, &allocate, TAG_OBJECT); | 5195 __ Allocate(r3, r5, r6, r7, &allocate, TAG_OBJECT); |
5290 __ bind(&done_allocate); | 5196 __ bind(&done_allocate); |
5291 | 5197 |
5292 // Setup the elements array in r6. | 5198 // Setup the elements array in r5. |
5293 __ LoadRoot(r4, Heap::kFixedArrayMapRootIndex); | 5199 __ LoadRoot(r3, Heap::kFixedArrayMapRootIndex); |
5294 __ StoreP(r4, FieldMemOperand(r6, FixedArray::kMapOffset), r0); | 5200 __ StoreP(r3, FieldMemOperand(r5, FixedArray::kMapOffset), r0); |
5295 __ StoreP(r3, FieldMemOperand(r6, FixedArray::kLengthOffset), r0); | 5201 __ StoreP(r2, FieldMemOperand(r5, FixedArray::kLengthOffset), r0); |
5296 __ addi(r7, r6, | 5202 __ AddP(r6, r5, |
5297 Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize)); | 5203 Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize)); |
5298 { | 5204 { |
5299 Label loop, done_loop; | 5205 Label loop, done_loop; |
5300 __ SmiUntag(r0, r3, SetRC); | 5206 __ SmiUntag(r1, r2); |
5301 __ beq(&done_loop, cr0); | 5207 __ LoadAndTestP(r1, r1); |
5302 __ mtctr(r0); | 5208 __ beq(&done_loop); |
5303 __ bind(&loop); | 5209 __ bind(&loop); |
5304 __ LoadPU(ip, MemOperand(r5, -kPointerSize)); | 5210 __ lay(r4, MemOperand(r4, -kPointerSize)); |
5305 __ StorePU(ip, MemOperand(r7, kPointerSize)); | 5211 __ LoadP(ip, MemOperand(r4)); |
5306 __ bdnz(&loop); | 5212 __ la(r6, MemOperand(r6, kPointerSize)); |
| 5213 __ StoreP(ip, MemOperand(r6)); |
| 5214 __ BranchOnCount(r1, &loop); |
5307 __ bind(&done_loop); | 5215 __ bind(&done_loop); |
5308 __ addi(r7, r7, Operand(kPointerSize)); | 5216 __ AddP(r6, r6, Operand(kPointerSize)); |
5309 } | 5217 } |
5310 | 5218 |
5311 // Setup the rest parameter array in r7. | 5219 // Setup the rest parameter array in r6. |
5312 __ LoadNativeContextSlot(Context::STRICT_ARGUMENTS_MAP_INDEX, r4); | 5220 __ LoadNativeContextSlot(Context::STRICT_ARGUMENTS_MAP_INDEX, r3); |
5313 __ StoreP(r4, MemOperand(r7, JSStrictArgumentsObject::kMapOffset)); | 5221 __ StoreP(r3, MemOperand(r6, JSStrictArgumentsObject::kMapOffset)); |
5314 __ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex); | 5222 __ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex); |
5315 __ StoreP(r4, MemOperand(r7, JSStrictArgumentsObject::kPropertiesOffset)); | 5223 __ StoreP(r3, MemOperand(r6, JSStrictArgumentsObject::kPropertiesOffset)); |
5316 __ StoreP(r6, MemOperand(r7, JSStrictArgumentsObject::kElementsOffset)); | 5224 __ StoreP(r5, MemOperand(r6, JSStrictArgumentsObject::kElementsOffset)); |
5317 __ StoreP(r3, MemOperand(r7, JSStrictArgumentsObject::kLengthOffset)); | 5225 __ StoreP(r2, MemOperand(r6, JSStrictArgumentsObject::kLengthOffset)); |
5318 STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); | 5226 STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); |
5319 __ addi(r3, r7, Operand(kHeapObjectTag)); | 5227 __ AddP(r2, r6, Operand(kHeapObjectTag)); |
5320 __ Ret(); | 5228 __ Ret(); |
5321 | 5229 |
5322 // Fall back to %AllocateInNewSpace. | 5230 // Fall back to %AllocateInNewSpace. |
5323 __ bind(&allocate); | 5231 __ bind(&allocate); |
5324 { | 5232 { |
5325 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 5233 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
5326 __ SmiTag(r4); | 5234 __ SmiTag(r3); |
5327 __ Push(r3, r5, r4); | 5235 __ Push(r2, r4, r3); |
5328 __ CallRuntime(Runtime::kAllocateInNewSpace); | 5236 __ CallRuntime(Runtime::kAllocateInNewSpace); |
5329 __ mr(r6, r3); | 5237 __ LoadRR(r5, r2); |
5330 __ Pop(r3, r5); | 5238 __ Pop(r2, r4); |
5331 } | 5239 } |
5332 __ b(&done_allocate); | 5240 __ b(&done_allocate); |
5333 } | 5241 } |
5334 | 5242 |
5335 void LoadGlobalViaContextStub::Generate(MacroAssembler* masm) { | 5243 void LoadGlobalViaContextStub::Generate(MacroAssembler* masm) { |
5336 Register context = cp; | 5244 Register context = cp; |
5337 Register result = r3; | 5245 Register result = r2; |
5338 Register slot = r5; | 5246 Register slot = r4; |
5339 | 5247 |
5340 // Go up the context chain to the script context. | 5248 // Go up the context chain to the script context. |
5341 for (int i = 0; i < depth(); ++i) { | 5249 for (int i = 0; i < depth(); ++i) { |
5342 __ LoadP(result, ContextMemOperand(context, Context::PREVIOUS_INDEX)); | 5250 __ LoadP(result, ContextMemOperand(context, Context::PREVIOUS_INDEX)); |
5343 context = result; | 5251 context = result; |
5344 } | 5252 } |
5345 | 5253 |
5346 // Load the PropertyCell value at the specified slot. | 5254 // Load the PropertyCell value at the specified slot. |
5347 __ ShiftLeftImm(r0, slot, Operand(kPointerSizeLog2)); | 5255 __ ShiftLeftP(r0, slot, Operand(kPointerSizeLog2)); |
5348 __ add(result, context, r0); | 5256 __ AddP(result, context, r0); |
5349 __ LoadP(result, ContextMemOperand(result)); | 5257 __ LoadP(result, ContextMemOperand(result)); |
5350 __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset)); | 5258 __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset)); |
5351 | 5259 |
5352 // If the result is not the_hole, return. Otherwise, handle in the runtime. | 5260 // If the result is not the_hole, return. Otherwise, handle in the runtime. |
5353 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); | 5261 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
5354 __ Ret(ne); | 5262 Label runtime; |
| 5263 __ beq(&runtime); |
| 5264 __ Ret(); |
| 5265 __ bind(&runtime); |
5355 | 5266 |
5356 // Fallback to runtime. | 5267 // Fallback to runtime. |
5357 __ SmiTag(slot); | 5268 __ SmiTag(slot); |
5358 __ Push(slot); | 5269 __ Push(slot); |
5359 __ TailCallRuntime(Runtime::kLoadGlobalViaContext); | 5270 __ TailCallRuntime(Runtime::kLoadGlobalViaContext); |
5360 } | 5271 } |
5361 | 5272 |
| 5273 void StoreGlobalViaContextStub::Generate(MacroAssembler* masm) { |
| 5274 Register value = r2; |
| 5275 Register slot = r4; |
5362 | 5276 |
5363 void StoreGlobalViaContextStub::Generate(MacroAssembler* masm) { | 5277 Register cell = r3; |
5364 Register value = r3; | 5278 Register cell_details = r5; |
5365 Register slot = r5; | 5279 Register cell_value = r6; |
5366 | 5280 Register cell_value_map = r7; |
5367 Register cell = r4; | 5281 Register scratch = r8; |
5368 Register cell_details = r6; | |
5369 Register cell_value = r7; | |
5370 Register cell_value_map = r8; | |
5371 Register scratch = r9; | |
5372 | 5282 |
5373 Register context = cp; | 5283 Register context = cp; |
5374 Register context_temp = cell; | 5284 Register context_temp = cell; |
5375 | 5285 |
5376 Label fast_heapobject_case, fast_smi_case, slow_case; | 5286 Label fast_heapobject_case, fast_smi_case, slow_case; |
5377 | 5287 |
5378 if (FLAG_debug_code) { | 5288 if (FLAG_debug_code) { |
5379 __ CompareRoot(value, Heap::kTheHoleValueRootIndex); | 5289 __ CompareRoot(value, Heap::kTheHoleValueRootIndex); |
5380 __ Check(ne, kUnexpectedValue); | 5290 __ Check(ne, kUnexpectedValue); |
5381 } | 5291 } |
5382 | 5292 |
5383 // Go up the context chain to the script context. | 5293 // Go up the context chain to the script context. |
5384 for (int i = 0; i < depth(); i++) { | 5294 for (int i = 0; i < depth(); i++) { |
5385 __ LoadP(context_temp, ContextMemOperand(context, Context::PREVIOUS_INDEX)); | 5295 __ LoadP(context_temp, ContextMemOperand(context, Context::PREVIOUS_INDEX)); |
5386 context = context_temp; | 5296 context = context_temp; |
5387 } | 5297 } |
5388 | 5298 |
5389 // Load the PropertyCell at the specified slot. | 5299 // Load the PropertyCell at the specified slot. |
5390 __ ShiftLeftImm(r0, slot, Operand(kPointerSizeLog2)); | 5300 __ ShiftLeftP(r0, slot, Operand(kPointerSizeLog2)); |
5391 __ add(cell, context, r0); | 5301 __ AddP(cell, context, r0); |
5392 __ LoadP(cell, ContextMemOperand(cell)); | 5302 __ LoadP(cell, ContextMemOperand(cell)); |
5393 | 5303 |
5394 // Load PropertyDetails for the cell (actually only the cell_type and kind). | 5304 // Load PropertyDetails for the cell (actually only the cell_type and kind). |
5395 __ LoadP(cell_details, FieldMemOperand(cell, PropertyCell::kDetailsOffset)); | 5305 __ LoadP(cell_details, FieldMemOperand(cell, PropertyCell::kDetailsOffset)); |
5396 __ SmiUntag(cell_details); | 5306 __ SmiUntag(cell_details); |
5397 __ andi(cell_details, cell_details, | 5307 __ AndP(cell_details, cell_details, |
5398 Operand(PropertyDetails::PropertyCellTypeField::kMask | | 5308 Operand(PropertyDetails::PropertyCellTypeField::kMask | |
5399 PropertyDetails::KindField::kMask | | 5309 PropertyDetails::KindField::kMask | |
5400 PropertyDetails::kAttributesReadOnlyMask)); | 5310 PropertyDetails::kAttributesReadOnlyMask)); |
5401 | 5311 |
5402 // Check if PropertyCell holds mutable data. | 5312 // Check if PropertyCell holds mutable data. |
5403 Label not_mutable_data; | 5313 Label not_mutable_data; |
5404 __ cmpi(cell_details, Operand(PropertyDetails::PropertyCellTypeField::encode( | 5314 __ CmpP(cell_details, Operand(PropertyDetails::PropertyCellTypeField::encode( |
5405 PropertyCellType::kMutable) | | 5315 PropertyCellType::kMutable) | |
5406 PropertyDetails::KindField::encode(kData))); | 5316 PropertyDetails::KindField::encode(kData))); |
5407 __ bne(¬_mutable_data); | 5317 __ bne(¬_mutable_data); |
5408 __ JumpIfSmi(value, &fast_smi_case); | 5318 __ JumpIfSmi(value, &fast_smi_case); |
5409 | 5319 |
5410 __ bind(&fast_heapobject_case); | 5320 __ bind(&fast_heapobject_case); |
5411 __ StoreP(value, FieldMemOperand(cell, PropertyCell::kValueOffset), r0); | 5321 __ StoreP(value, FieldMemOperand(cell, PropertyCell::kValueOffset), r0); |
5412 // RecordWriteField clobbers the value register, so we copy it before the | 5322 // RecordWriteField clobbers the value register, so we copy it before the |
5413 // call. | 5323 // call. |
5414 __ mr(r6, value); | 5324 __ LoadRR(r5, value); |
5415 __ RecordWriteField(cell, PropertyCell::kValueOffset, r6, scratch, | 5325 __ RecordWriteField(cell, PropertyCell::kValueOffset, r5, scratch, |
5416 kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET, | 5326 kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET, |
5417 OMIT_SMI_CHECK); | 5327 OMIT_SMI_CHECK); |
5418 __ Ret(); | 5328 __ Ret(); |
5419 | 5329 |
5420 __ bind(¬_mutable_data); | 5330 __ bind(¬_mutable_data); |
5421 // Check if PropertyCell value matches the new value (relevant for Constant, | 5331 // Check if PropertyCell value matches the new value (relevant for Constant, |
5422 // ConstantType and Undefined cells). | 5332 // ConstantType and Undefined cells). |
5423 Label not_same_value; | 5333 Label not_same_value; |
5424 __ LoadP(cell_value, FieldMemOperand(cell, PropertyCell::kValueOffset)); | 5334 __ LoadP(cell_value, FieldMemOperand(cell, PropertyCell::kValueOffset)); |
5425 __ cmp(cell_value, value); | 5335 __ CmpP(cell_value, value); |
5426 __ bne(¬_same_value); | 5336 __ bne(¬_same_value); |
5427 | 5337 |
5428 // Make sure the PropertyCell is not marked READ_ONLY. | 5338 // Make sure the PropertyCell is not marked READ_ONLY. |
5429 __ andi(r0, cell_details, Operand(PropertyDetails::kAttributesReadOnlyMask)); | 5339 __ AndP(r0, cell_details, Operand(PropertyDetails::kAttributesReadOnlyMask)); |
5430 __ bne(&slow_case, cr0); | 5340 __ bne(&slow_case); |
5431 | 5341 |
5432 if (FLAG_debug_code) { | 5342 if (FLAG_debug_code) { |
5433 Label done; | 5343 Label done; |
5434 // This can only be true for Constant, ConstantType and Undefined cells, | 5344 // This can only be true for Constant, ConstantType and Undefined cells, |
5435 // because we never store the_hole via this stub. | 5345 // because we never store the_hole via this stub. |
5436 __ cmpi(cell_details, | 5346 __ CmpP(cell_details, |
5437 Operand(PropertyDetails::PropertyCellTypeField::encode( | 5347 Operand(PropertyDetails::PropertyCellTypeField::encode( |
5438 PropertyCellType::kConstant) | | 5348 PropertyCellType::kConstant) | |
5439 PropertyDetails::KindField::encode(kData))); | 5349 PropertyDetails::KindField::encode(kData))); |
5440 __ beq(&done); | 5350 __ beq(&done); |
5441 __ cmpi(cell_details, | 5351 __ CmpP(cell_details, |
5442 Operand(PropertyDetails::PropertyCellTypeField::encode( | 5352 Operand(PropertyDetails::PropertyCellTypeField::encode( |
5443 PropertyCellType::kConstantType) | | 5353 PropertyCellType::kConstantType) | |
5444 PropertyDetails::KindField::encode(kData))); | 5354 PropertyDetails::KindField::encode(kData))); |
5445 __ beq(&done); | 5355 __ beq(&done); |
5446 __ cmpi(cell_details, | 5356 __ CmpP(cell_details, |
5447 Operand(PropertyDetails::PropertyCellTypeField::encode( | 5357 Operand(PropertyDetails::PropertyCellTypeField::encode( |
5448 PropertyCellType::kUndefined) | | 5358 PropertyCellType::kUndefined) | |
5449 PropertyDetails::KindField::encode(kData))); | 5359 PropertyDetails::KindField::encode(kData))); |
5450 __ Check(eq, kUnexpectedValue); | 5360 __ Check(eq, kUnexpectedValue); |
5451 __ bind(&done); | 5361 __ bind(&done); |
5452 } | 5362 } |
5453 __ Ret(); | 5363 __ Ret(); |
5454 __ bind(¬_same_value); | 5364 __ bind(¬_same_value); |
5455 | 5365 |
5456 // Check if PropertyCell contains data with constant type (and is not | 5366 // Check if PropertyCell contains data with constant type (and is not |
5457 // READ_ONLY). | 5367 // READ_ONLY). |
5458 __ cmpi(cell_details, Operand(PropertyDetails::PropertyCellTypeField::encode( | 5368 __ CmpP(cell_details, Operand(PropertyDetails::PropertyCellTypeField::encode( |
5459 PropertyCellType::kConstantType) | | 5369 PropertyCellType::kConstantType) | |
5460 PropertyDetails::KindField::encode(kData))); | 5370 PropertyDetails::KindField::encode(kData))); |
5461 __ bne(&slow_case); | 5371 __ bne(&slow_case); |
5462 | 5372 |
5463 // Now either both old and new values must be smis or both must be heap | 5373 // Now either both old and new values must be smis or both must be heap |
5464 // objects with same map. | 5374 // objects with same map. |
5465 Label value_is_heap_object; | 5375 Label value_is_heap_object; |
5466 __ JumpIfNotSmi(value, &value_is_heap_object); | 5376 __ JumpIfNotSmi(value, &value_is_heap_object); |
5467 __ JumpIfNotSmi(cell_value, &slow_case); | 5377 __ JumpIfNotSmi(cell_value, &slow_case); |
5468 // Old and new values are smis, no need for a write barrier here. | 5378 // Old and new values are smis, no need for a write barrier here. |
5469 __ bind(&fast_smi_case); | 5379 __ bind(&fast_smi_case); |
5470 __ StoreP(value, FieldMemOperand(cell, PropertyCell::kValueOffset), r0); | 5380 __ StoreP(value, FieldMemOperand(cell, PropertyCell::kValueOffset), r0); |
5471 __ Ret(); | 5381 __ Ret(); |
5472 | 5382 |
5473 __ bind(&value_is_heap_object); | 5383 __ bind(&value_is_heap_object); |
5474 __ JumpIfSmi(cell_value, &slow_case); | 5384 __ JumpIfSmi(cell_value, &slow_case); |
5475 | 5385 |
5476 __ LoadP(cell_value_map, FieldMemOperand(cell_value, HeapObject::kMapOffset)); | 5386 __ LoadP(cell_value_map, FieldMemOperand(cell_value, HeapObject::kMapOffset)); |
5477 __ LoadP(scratch, FieldMemOperand(value, HeapObject::kMapOffset)); | 5387 __ LoadP(scratch, FieldMemOperand(value, HeapObject::kMapOffset)); |
5478 __ cmp(cell_value_map, scratch); | 5388 __ CmpP(cell_value_map, scratch); |
5479 __ beq(&fast_heapobject_case); | 5389 __ beq(&fast_heapobject_case); |
5480 | 5390 |
5481 // Fallback to runtime. | 5391 // Fallback to runtime. |
5482 __ bind(&slow_case); | 5392 __ bind(&slow_case); |
5483 __ SmiTag(slot); | 5393 __ SmiTag(slot); |
5484 __ Push(slot, value); | 5394 __ Push(slot, value); |
5485 __ TailCallRuntime(is_strict(language_mode()) | 5395 __ TailCallRuntime(is_strict(language_mode()) |
5486 ? Runtime::kStoreGlobalViaContext_Strict | 5396 ? Runtime::kStoreGlobalViaContext_Strict |
5487 : Runtime::kStoreGlobalViaContext_Sloppy); | 5397 : Runtime::kStoreGlobalViaContext_Sloppy); |
5488 } | 5398 } |
5489 | 5399 |
5490 | |
5491 static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { | 5400 static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { |
5492 return ref0.address() - ref1.address(); | 5401 return ref0.address() - ref1.address(); |
5493 } | 5402 } |
5494 | 5403 |
5495 | |
5496 // Calls an API function. Allocates HandleScope, extracts returned value | 5404 // Calls an API function. Allocates HandleScope, extracts returned value |
5497 // from handle and propagates exceptions. Restores context. stack_space | 5405 // from handle and propagates exceptions. Restores context. stack_space |
5498 // - space to be unwound on exit (includes the call JS arguments space and | 5406 // - space to be unwound on exit (includes the call JS arguments space and |
5499 // the additional space allocated for the fast call). | 5407 // the additional space allocated for the fast call). |
5500 static void CallApiFunctionAndReturn(MacroAssembler* masm, | 5408 static void CallApiFunctionAndReturn(MacroAssembler* masm, |
5501 Register function_address, | 5409 Register function_address, |
5502 ExternalReference thunk_ref, | 5410 ExternalReference thunk_ref, |
5503 int stack_space, | 5411 int stack_space, |
5504 MemOperand* stack_space_operand, | 5412 MemOperand* stack_space_operand, |
5505 MemOperand return_value_operand, | 5413 MemOperand return_value_operand, |
5506 MemOperand* context_restore_operand) { | 5414 MemOperand* context_restore_operand) { |
5507 Isolate* isolate = masm->isolate(); | 5415 Isolate* isolate = masm->isolate(); |
5508 ExternalReference next_address = | 5416 ExternalReference next_address = |
5509 ExternalReference::handle_scope_next_address(isolate); | 5417 ExternalReference::handle_scope_next_address(isolate); |
5510 const int kNextOffset = 0; | 5418 const int kNextOffset = 0; |
5511 const int kLimitOffset = AddressOffset( | 5419 const int kLimitOffset = AddressOffset( |
5512 ExternalReference::handle_scope_limit_address(isolate), next_address); | 5420 ExternalReference::handle_scope_limit_address(isolate), next_address); |
5513 const int kLevelOffset = AddressOffset( | 5421 const int kLevelOffset = AddressOffset( |
5514 ExternalReference::handle_scope_level_address(isolate), next_address); | 5422 ExternalReference::handle_scope_level_address(isolate), next_address); |
5515 | 5423 |
5516 // Additional parameter is the address of the actual callback. | 5424 // Additional parameter is the address of the actual callback. |
5517 DCHECK(function_address.is(r4) || function_address.is(r5)); | 5425 DCHECK(function_address.is(r3) || function_address.is(r4)); |
5518 Register scratch = r6; | 5426 Register scratch = r5; |
5519 | 5427 |
5520 __ mov(scratch, Operand(ExternalReference::is_profiling_address(isolate))); | 5428 __ mov(scratch, Operand(ExternalReference::is_profiling_address(isolate))); |
5521 __ lbz(scratch, MemOperand(scratch, 0)); | 5429 __ LoadlB(scratch, MemOperand(scratch, 0)); |
5522 __ cmpi(scratch, Operand::Zero()); | 5430 __ CmpP(scratch, Operand::Zero()); |
5523 | 5431 |
5524 if (CpuFeatures::IsSupported(ISELECT)) { | 5432 Label profiler_disabled; |
5525 __ mov(scratch, Operand(thunk_ref)); | 5433 Label end_profiler_check; |
5526 __ isel(eq, scratch, function_address, scratch); | 5434 __ beq(&profiler_disabled, Label::kNear); |
5527 } else { | 5435 __ mov(scratch, Operand(thunk_ref)); |
5528 Label profiler_disabled; | 5436 __ b(&end_profiler_check, Label::kNear); |
5529 Label end_profiler_check; | 5437 __ bind(&profiler_disabled); |
5530 __ beq(&profiler_disabled); | 5438 __ LoadRR(scratch, function_address); |
5531 __ mov(scratch, Operand(thunk_ref)); | 5439 __ bind(&end_profiler_check); |
5532 __ b(&end_profiler_check); | |
5533 __ bind(&profiler_disabled); | |
5534 __ mr(scratch, function_address); | |
5535 __ bind(&end_profiler_check); | |
5536 } | |
5537 | 5440 |
5538 // Allocate HandleScope in callee-save registers. | 5441 // Allocate HandleScope in callee-save registers. |
5539 // r17 - next_address | 5442 // r9 - next_address |
5540 // r14 - next_address->kNextOffset | 5443 // r6 - next_address->kNextOffset |
5541 // r15 - next_address->kLimitOffset | 5444 // r7 - next_address->kLimitOffset |
5542 // r16 - next_address->kLevelOffset | 5445 // r8 - next_address->kLevelOffset |
5543 __ mov(r17, Operand(next_address)); | 5446 __ mov(r9, Operand(next_address)); |
5544 __ LoadP(r14, MemOperand(r17, kNextOffset)); | 5447 __ LoadP(r6, MemOperand(r9, kNextOffset)); |
5545 __ LoadP(r15, MemOperand(r17, kLimitOffset)); | 5448 __ LoadP(r7, MemOperand(r9, kLimitOffset)); |
5546 __ lwz(r16, MemOperand(r17, kLevelOffset)); | 5449 __ LoadlW(r8, MemOperand(r9, kLevelOffset)); |
5547 __ addi(r16, r16, Operand(1)); | 5450 __ AddP(r8, Operand(1)); |
5548 __ stw(r16, MemOperand(r17, kLevelOffset)); | 5451 __ StoreW(r8, MemOperand(r9, kLevelOffset)); |
5549 | 5452 |
5550 if (FLAG_log_timer_events) { | 5453 if (FLAG_log_timer_events) { |
5551 FrameScope frame(masm, StackFrame::MANUAL); | 5454 FrameScope frame(masm, StackFrame::MANUAL); |
5552 __ PushSafepointRegisters(); | 5455 __ PushSafepointRegisters(); |
5553 __ PrepareCallCFunction(1, r3); | 5456 __ PrepareCallCFunction(1, r2); |
5554 __ mov(r3, Operand(ExternalReference::isolate_address(isolate))); | 5457 __ mov(r2, Operand(ExternalReference::isolate_address(isolate))); |
5555 __ CallCFunction(ExternalReference::log_enter_external_function(isolate), | 5458 __ CallCFunction(ExternalReference::log_enter_external_function(isolate), |
5556 1); | 5459 1); |
5557 __ PopSafepointRegisters(); | 5460 __ PopSafepointRegisters(); |
5558 } | 5461 } |
5559 | 5462 |
5560 // Native call returns to the DirectCEntry stub which redirects to the | 5463 // Native call returns to the DirectCEntry stub which redirects to the |
5561 // return address pushed on stack (could have moved after GC). | 5464 // return address pushed on stack (could have moved after GC). |
5562 // DirectCEntry stub itself is generated early and never moves. | 5465 // DirectCEntry stub itself is generated early and never moves. |
5563 DirectCEntryStub stub(isolate); | 5466 DirectCEntryStub stub(isolate); |
5564 stub.GenerateCall(masm, scratch); | 5467 stub.GenerateCall(masm, scratch); |
5565 | 5468 |
5566 if (FLAG_log_timer_events) { | 5469 if (FLAG_log_timer_events) { |
5567 FrameScope frame(masm, StackFrame::MANUAL); | 5470 FrameScope frame(masm, StackFrame::MANUAL); |
5568 __ PushSafepointRegisters(); | 5471 __ PushSafepointRegisters(); |
5569 __ PrepareCallCFunction(1, r3); | 5472 __ PrepareCallCFunction(1, r2); |
5570 __ mov(r3, Operand(ExternalReference::isolate_address(isolate))); | 5473 __ mov(r2, Operand(ExternalReference::isolate_address(isolate))); |
5571 __ CallCFunction(ExternalReference::log_leave_external_function(isolate), | 5474 __ CallCFunction(ExternalReference::log_leave_external_function(isolate), |
5572 1); | 5475 1); |
5573 __ PopSafepointRegisters(); | 5476 __ PopSafepointRegisters(); |
5574 } | 5477 } |
5575 | 5478 |
5576 Label promote_scheduled_exception; | 5479 Label promote_scheduled_exception; |
5577 Label delete_allocated_handles; | 5480 Label delete_allocated_handles; |
5578 Label leave_exit_frame; | 5481 Label leave_exit_frame; |
5579 Label return_value_loaded; | 5482 Label return_value_loaded; |
5580 | 5483 |
5581 // load value from ReturnValue | 5484 // load value from ReturnValue |
5582 __ LoadP(r3, return_value_operand); | 5485 __ LoadP(r2, return_value_operand); |
5583 __ bind(&return_value_loaded); | 5486 __ bind(&return_value_loaded); |
5584 // No more valid handles (the result handle was the last one). Restore | 5487 // No more valid handles (the result handle was the last one). Restore |
5585 // previous handle scope. | 5488 // previous handle scope. |
5586 __ StoreP(r14, MemOperand(r17, kNextOffset)); | 5489 __ StoreP(r6, MemOperand(r9, kNextOffset)); |
5587 if (__ emit_debug_code()) { | 5490 if (__ emit_debug_code()) { |
5588 __ lwz(r4, MemOperand(r17, kLevelOffset)); | 5491 __ LoadlW(r3, MemOperand(r9, kLevelOffset)); |
5589 __ cmp(r4, r16); | 5492 __ CmpP(r3, r8); |
5590 __ Check(eq, kUnexpectedLevelAfterReturnFromApiCall); | 5493 __ Check(eq, kUnexpectedLevelAfterReturnFromApiCall); |
5591 } | 5494 } |
5592 __ subi(r16, r16, Operand(1)); | 5495 __ SubP(r8, Operand(1)); |
5593 __ stw(r16, MemOperand(r17, kLevelOffset)); | 5496 __ StoreW(r8, MemOperand(r9, kLevelOffset)); |
5594 __ LoadP(r0, MemOperand(r17, kLimitOffset)); | 5497 __ CmpP(r7, MemOperand(r9, kLimitOffset)); |
5595 __ cmp(r15, r0); | 5498 __ bne(&delete_allocated_handles, Label::kNear); |
5596 __ bne(&delete_allocated_handles); | |
5597 | 5499 |
5598 // Leave the API exit frame. | 5500 // Leave the API exit frame. |
5599 __ bind(&leave_exit_frame); | 5501 __ bind(&leave_exit_frame); |
5600 bool restore_context = context_restore_operand != NULL; | 5502 bool restore_context = context_restore_operand != NULL; |
5601 if (restore_context) { | 5503 if (restore_context) { |
5602 __ LoadP(cp, *context_restore_operand); | 5504 __ LoadP(cp, *context_restore_operand); |
5603 } | 5505 } |
5604 // LeaveExitFrame expects unwind space to be in a register. | 5506 // LeaveExitFrame expects unwind space to be in a register. |
5605 if (stack_space_operand != NULL) { | 5507 if (stack_space_operand != NULL) { |
5606 __ lwz(r14, *stack_space_operand); | 5508 __ l(r6, *stack_space_operand); |
5607 } else { | 5509 } else { |
5608 __ mov(r14, Operand(stack_space)); | 5510 __ mov(r6, Operand(stack_space)); |
5609 } | 5511 } |
5610 __ LeaveExitFrame(false, r14, !restore_context, stack_space_operand != NULL); | 5512 __ LeaveExitFrame(false, r6, !restore_context, stack_space_operand != NULL); |
5611 | 5513 |
5612 // Check if the function scheduled an exception. | 5514 // Check if the function scheduled an exception. |
5613 __ LoadRoot(r14, Heap::kTheHoleValueRootIndex); | 5515 __ mov(r7, Operand(ExternalReference::scheduled_exception_address(isolate))); |
5614 __ mov(r15, Operand(ExternalReference::scheduled_exception_address(isolate))); | 5516 __ LoadP(r7, MemOperand(r7)); |
5615 __ LoadP(r15, MemOperand(r15)); | 5517 __ CompareRoot(r7, Heap::kTheHoleValueRootIndex); |
5616 __ cmp(r14, r15); | 5518 __ bne(&promote_scheduled_exception, Label::kNear); |
5617 __ bne(&promote_scheduled_exception); | |
5618 | 5519 |
5619 __ blr(); | 5520 __ b(r14); |
5620 | 5521 |
5621 // Re-throw by promoting a scheduled exception. | 5522 // Re-throw by promoting a scheduled exception. |
5622 __ bind(&promote_scheduled_exception); | 5523 __ bind(&promote_scheduled_exception); |
5623 __ TailCallRuntime(Runtime::kPromoteScheduledException); | 5524 __ TailCallRuntime(Runtime::kPromoteScheduledException); |
5624 | 5525 |
5625 // HandleScope limit has changed. Delete allocated extensions. | 5526 // HandleScope limit has changed. Delete allocated extensions. |
5626 __ bind(&delete_allocated_handles); | 5527 __ bind(&delete_allocated_handles); |
5627 __ StoreP(r15, MemOperand(r17, kLimitOffset)); | 5528 __ StoreP(r7, MemOperand(r9, kLimitOffset)); |
5628 __ mr(r14, r3); | 5529 __ LoadRR(r6, r2); |
5629 __ PrepareCallCFunction(1, r15); | 5530 __ PrepareCallCFunction(1, r7); |
5630 __ mov(r3, Operand(ExternalReference::isolate_address(isolate))); | 5531 __ mov(r2, Operand(ExternalReference::isolate_address(isolate))); |
5631 __ CallCFunction(ExternalReference::delete_handle_scope_extensions(isolate), | 5532 __ CallCFunction(ExternalReference::delete_handle_scope_extensions(isolate), |
5632 1); | 5533 1); |
5633 __ mr(r3, r14); | 5534 __ LoadRR(r2, r6); |
5634 __ b(&leave_exit_frame); | 5535 __ b(&leave_exit_frame, Label::kNear); |
5635 } | 5536 } |
5636 | 5537 |
5637 static void CallApiFunctionStubHelper(MacroAssembler* masm, | 5538 static void CallApiFunctionStubHelper(MacroAssembler* masm, |
5638 const ParameterCount& argc, | 5539 const ParameterCount& argc, |
5639 bool return_first_arg, | 5540 bool return_first_arg, |
5640 bool call_data_undefined, bool is_lazy) { | 5541 bool call_data_undefined, bool is_lazy) { |
5641 // ----------- S t a t e ------------- | 5542 // ----------- S t a t e ------------- |
5642 // -- r3 : callee | 5543 // -- r2 : callee |
5643 // -- r7 : call_data | 5544 // -- r6 : call_data |
5644 // -- r5 : holder | 5545 // -- r4 : holder |
5645 // -- r4 : api_function_address | 5546 // -- r3 : api_function_address |
5646 // -- r6 : number of arguments if argc is a register | 5547 // -- r5 : number of arguments if argc is a register |
5647 // -- cp : context | 5548 // -- cp : context |
5648 // -- | 5549 // -- |
5649 // -- sp[0] : last argument | 5550 // -- sp[0] : last argument |
5650 // -- ... | 5551 // -- ... |
5651 // -- sp[(argc - 1)* 4] : first argument | 5552 // -- sp[(argc - 1)* 4] : first argument |
5652 // -- sp[argc * 4] : receiver | 5553 // -- sp[argc * 4] : receiver |
5653 // ----------------------------------- | 5554 // ----------------------------------- |
5654 | 5555 |
5655 Register callee = r3; | 5556 Register callee = r2; |
5656 Register call_data = r7; | 5557 Register call_data = r6; |
5657 Register holder = r5; | 5558 Register holder = r4; |
5658 Register api_function_address = r4; | 5559 Register api_function_address = r3; |
5659 Register context = cp; | 5560 Register context = cp; |
5660 | 5561 |
5661 typedef FunctionCallbackArguments FCA; | 5562 typedef FunctionCallbackArguments FCA; |
5662 | 5563 |
5663 STATIC_ASSERT(FCA::kContextSaveIndex == 6); | 5564 STATIC_ASSERT(FCA::kContextSaveIndex == 6); |
5664 STATIC_ASSERT(FCA::kCalleeIndex == 5); | 5565 STATIC_ASSERT(FCA::kCalleeIndex == 5); |
5665 STATIC_ASSERT(FCA::kDataIndex == 4); | 5566 STATIC_ASSERT(FCA::kDataIndex == 4); |
5666 STATIC_ASSERT(FCA::kReturnValueOffset == 3); | 5567 STATIC_ASSERT(FCA::kReturnValueOffset == 3); |
5667 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); | 5568 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); |
5668 STATIC_ASSERT(FCA::kIsolateIndex == 1); | 5569 STATIC_ASSERT(FCA::kIsolateIndex == 1); |
5669 STATIC_ASSERT(FCA::kHolderIndex == 0); | 5570 STATIC_ASSERT(FCA::kHolderIndex == 0); |
5670 STATIC_ASSERT(FCA::kArgsLength == 7); | 5571 STATIC_ASSERT(FCA::kArgsLength == 7); |
5671 | 5572 |
5672 DCHECK(argc.is_immediate() || r3.is(argc.reg())); | 5573 DCHECK(argc.is_immediate() || r2.is(argc.reg())); |
5673 | 5574 |
5674 // context save | 5575 // context save |
5675 __ push(context); | 5576 __ push(context); |
5676 if (!is_lazy) { | 5577 if (!is_lazy) { |
5677 // load context from callee | 5578 // load context from callee |
5678 __ LoadP(context, FieldMemOperand(callee, JSFunction::kContextOffset)); | 5579 __ LoadP(context, FieldMemOperand(callee, JSFunction::kContextOffset)); |
5679 } | 5580 } |
5680 | 5581 |
5681 // callee | 5582 // callee |
5682 __ push(callee); | 5583 __ push(callee); |
5683 | 5584 |
5684 // call data | 5585 // call data |
5685 __ push(call_data); | 5586 __ push(call_data); |
5686 | 5587 |
5687 Register scratch = call_data; | 5588 Register scratch = call_data; |
5688 if (!call_data_undefined) { | 5589 if (!call_data_undefined) { |
5689 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); | 5590 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); |
5690 } | 5591 } |
5691 // return value | 5592 // return value |
5692 __ push(scratch); | 5593 __ push(scratch); |
5693 // return value default | 5594 // return value default |
5694 __ push(scratch); | 5595 __ push(scratch); |
5695 // isolate | 5596 // isolate |
5696 __ mov(scratch, Operand(ExternalReference::isolate_address(masm->isolate()))); | 5597 __ mov(scratch, Operand(ExternalReference::isolate_address(masm->isolate()))); |
5697 __ push(scratch); | 5598 __ push(scratch); |
5698 // holder | 5599 // holder |
5699 __ push(holder); | 5600 __ push(holder); |
5700 | 5601 |
5701 // Prepare arguments. | 5602 // Prepare arguments. |
5702 __ mr(scratch, sp); | 5603 __ LoadRR(scratch, sp); |
5703 | 5604 |
5704 // Allocate the v8::Arguments structure in the arguments' space since | 5605 // Allocate the v8::Arguments structure in the arguments' space since |
5705 // it's not controlled by GC. | 5606 // it's not controlled by GC. |
5706 // PPC LINUX ABI: | 5607 // S390 LINUX ABI: |
5707 // | 5608 // |
5708 // Create 5 extra slots on stack: | 5609 // Create 5 extra slots on stack: |
5709 // [0] space for DirectCEntryStub's LR save | 5610 // [0] space for DirectCEntryStub's LR save |
5710 // [1-4] FunctionCallbackInfo | 5611 // [1-4] FunctionCallbackInfo |
5711 const int kApiStackSpace = 5; | 5612 const int kApiStackSpace = 5; |
5712 const int kFunctionCallbackInfoOffset = | 5613 const int kFunctionCallbackInfoOffset = |
5713 (kStackFrameExtraParamSlot + 1) * kPointerSize; | 5614 (kStackFrameExtraParamSlot + 1) * kPointerSize; |
5714 | 5615 |
5715 FrameScope frame_scope(masm, StackFrame::MANUAL); | 5616 FrameScope frame_scope(masm, StackFrame::MANUAL); |
5716 __ EnterExitFrame(false, kApiStackSpace); | 5617 __ EnterExitFrame(false, kApiStackSpace); |
5717 | 5618 |
5718 DCHECK(!api_function_address.is(r3) && !scratch.is(r3)); | 5619 DCHECK(!api_function_address.is(r2) && !scratch.is(r2)); |
5719 // r3 = FunctionCallbackInfo& | 5620 // r2 = FunctionCallbackInfo& |
5720 // Arguments is after the return address. | 5621 // Arguments is after the return address. |
5721 __ addi(r3, sp, Operand(kFunctionCallbackInfoOffset)); | 5622 __ AddP(r2, sp, Operand(kFunctionCallbackInfoOffset)); |
5722 // FunctionCallbackInfo::implicit_args_ | 5623 // FunctionCallbackInfo::implicit_args_ |
5723 __ StoreP(scratch, MemOperand(r3, 0 * kPointerSize)); | 5624 __ StoreP(scratch, MemOperand(r2, 0 * kPointerSize)); |
5724 if (argc.is_immediate()) { | 5625 if (argc.is_immediate()) { |
5725 // FunctionCallbackInfo::values_ | 5626 // FunctionCallbackInfo::values_ |
5726 __ addi(ip, scratch, | 5627 __ AddP(ip, scratch, |
5727 Operand((FCA::kArgsLength - 1 + argc.immediate()) * kPointerSize)); | 5628 Operand((FCA::kArgsLength - 1 + argc.immediate()) * kPointerSize)); |
5728 __ StoreP(ip, MemOperand(r3, 1 * kPointerSize)); | 5629 __ StoreP(ip, MemOperand(r2, 1 * kPointerSize)); |
5729 // FunctionCallbackInfo::length_ = argc | 5630 // FunctionCallbackInfo::length_ = argc |
5730 __ li(ip, Operand(argc.immediate())); | 5631 __ LoadImmP(ip, Operand(argc.immediate())); |
5731 __ stw(ip, MemOperand(r3, 2 * kPointerSize)); | 5632 __ StoreW(ip, MemOperand(r2, 2 * kPointerSize)); |
5732 // FunctionCallbackInfo::is_construct_call_ = 0 | 5633 // FunctionCallbackInfo::is_construct_call_ = 0 |
5733 __ li(ip, Operand::Zero()); | 5634 __ LoadImmP(ip, Operand::Zero()); |
5734 __ stw(ip, MemOperand(r3, 2 * kPointerSize + kIntSize)); | 5635 __ StoreW(ip, MemOperand(r2, 2 * kPointerSize + kIntSize)); |
5735 } else { | 5636 } else { |
5736 __ ShiftLeftImm(ip, argc.reg(), Operand(kPointerSizeLog2)); | 5637 __ ShiftLeftP(ip, argc.reg(), Operand(kPointerSizeLog2)); |
5737 __ addi(ip, ip, Operand((FCA::kArgsLength - 1) * kPointerSize)); | 5638 __ AddP(ip, ip, Operand((FCA::kArgsLength - 1) * kPointerSize)); |
5738 // FunctionCallbackInfo::values_ | 5639 // FunctionCallbackInfo::values_ |
5739 __ add(r0, scratch, ip); | 5640 __ AddP(r0, scratch, ip); |
5740 __ StoreP(r0, MemOperand(r3, 1 * kPointerSize)); | 5641 __ StoreP(r0, MemOperand(r2, 1 * kPointerSize)); |
5741 // FunctionCallbackInfo::length_ = argc | 5642 // FunctionCallbackInfo::length_ = argc |
5742 __ stw(argc.reg(), MemOperand(r3, 2 * kPointerSize)); | 5643 __ StoreW(argc.reg(), MemOperand(r2, 2 * kPointerSize)); |
5743 // FunctionCallbackInfo::is_construct_call_ | 5644 // FunctionCallbackInfo::is_construct_call_ |
5744 __ stw(ip, MemOperand(r3, 2 * kPointerSize + kIntSize)); | 5645 __ StoreW(ip, MemOperand(r2, 2 * kPointerSize + kIntSize)); |
5745 } | 5646 } |
5746 | 5647 |
5747 ExternalReference thunk_ref = | 5648 ExternalReference thunk_ref = |
5748 ExternalReference::invoke_function_callback(masm->isolate()); | 5649 ExternalReference::invoke_function_callback(masm->isolate()); |
5749 | 5650 |
5750 AllowExternalCallThatCantCauseGC scope(masm); | 5651 AllowExternalCallThatCantCauseGC scope(masm); |
5751 MemOperand context_restore_operand( | 5652 MemOperand context_restore_operand( |
5752 fp, (2 + FCA::kContextSaveIndex) * kPointerSize); | 5653 fp, (2 + FCA::kContextSaveIndex) * kPointerSize); |
5753 // Stores return the first js argument | 5654 // Stores return the first js argument |
5754 int return_value_offset = 0; | 5655 int return_value_offset = 0; |
5755 if (return_first_arg) { | 5656 if (return_first_arg) { |
5756 return_value_offset = 2 + FCA::kArgsLength; | 5657 return_value_offset = 2 + FCA::kArgsLength; |
5757 } else { | 5658 } else { |
5758 return_value_offset = 2 + FCA::kReturnValueOffset; | 5659 return_value_offset = 2 + FCA::kReturnValueOffset; |
5759 } | 5660 } |
5760 MemOperand return_value_operand(fp, return_value_offset * kPointerSize); | 5661 MemOperand return_value_operand(fp, return_value_offset * kPointerSize); |
5761 int stack_space = 0; | 5662 int stack_space = 0; |
5762 MemOperand is_construct_call_operand = | 5663 MemOperand is_construct_call_operand = |
5763 MemOperand(sp, kFunctionCallbackInfoOffset + 2 * kPointerSize + kIntSize); | 5664 MemOperand(sp, kFunctionCallbackInfoOffset + 2 * kPointerSize + kIntSize); |
5764 MemOperand* stack_space_operand = &is_construct_call_operand; | 5665 MemOperand* stack_space_operand = &is_construct_call_operand; |
5765 if (argc.is_immediate()) { | 5666 if (argc.is_immediate()) { |
5766 stack_space = argc.immediate() + FCA::kArgsLength + 1; | 5667 stack_space = argc.immediate() + FCA::kArgsLength + 1; |
5767 stack_space_operand = NULL; | 5668 stack_space_operand = NULL; |
5768 } | 5669 } |
5769 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, stack_space, | 5670 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, stack_space, |
5770 stack_space_operand, return_value_operand, | 5671 stack_space_operand, return_value_operand, |
5771 &context_restore_operand); | 5672 &context_restore_operand); |
5772 } | 5673 } |
5773 | 5674 |
5774 | |
5775 void CallApiFunctionStub::Generate(MacroAssembler* masm) { | 5675 void CallApiFunctionStub::Generate(MacroAssembler* masm) { |
5776 bool call_data_undefined = this->call_data_undefined(); | 5676 bool call_data_undefined = this->call_data_undefined(); |
5777 CallApiFunctionStubHelper(masm, ParameterCount(r6), false, | 5677 CallApiFunctionStubHelper(masm, ParameterCount(r6), false, |
5778 call_data_undefined, false); | 5678 call_data_undefined, false); |
5779 } | 5679 } |
5780 | 5680 |
5781 | |
5782 void CallApiAccessorStub::Generate(MacroAssembler* masm) { | 5681 void CallApiAccessorStub::Generate(MacroAssembler* masm) { |
5783 bool is_store = this->is_store(); | 5682 bool is_store = this->is_store(); |
5784 int argc = this->argc(); | 5683 int argc = this->argc(); |
5785 bool call_data_undefined = this->call_data_undefined(); | 5684 bool call_data_undefined = this->call_data_undefined(); |
5786 bool is_lazy = this->is_lazy(); | 5685 bool is_lazy = this->is_lazy(); |
5787 CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store, | 5686 CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store, |
5788 call_data_undefined, is_lazy); | 5687 call_data_undefined, is_lazy); |
5789 } | 5688 } |
5790 | 5689 |
5791 | |
5792 void CallApiGetterStub::Generate(MacroAssembler* masm) { | 5690 void CallApiGetterStub::Generate(MacroAssembler* masm) { |
5793 // ----------- S t a t e ------------- | 5691 // ----------- S t a t e ------------- |
5794 // -- sp[0] : name | 5692 // -- sp[0] : name |
5795 // -- sp[4 .. (4 + kArgsLength*4)] : v8::PropertyCallbackInfo::args_ | 5693 // -- sp[4 .. (4 + kArgsLength*4)] : v8::PropertyCallbackInfo::args_ |
5796 // -- ... | 5694 // -- ... |
5797 // -- r5 : api_function_address | 5695 // -- r4 : api_function_address |
5798 // ----------------------------------- | 5696 // ----------------------------------- |
5799 | 5697 |
5800 Register api_function_address = ApiGetterDescriptor::function_address(); | 5698 Register api_function_address = ApiGetterDescriptor::function_address(); |
5801 int arg0Slot = 0; | 5699 int arg0Slot = 0; |
5802 int accessorInfoSlot = 0; | 5700 int accessorInfoSlot = 0; |
5803 int apiStackSpace = 0; | 5701 int apiStackSpace = 0; |
5804 DCHECK(api_function_address.is(r5)); | 5702 DCHECK(api_function_address.is(r4)); |
5805 | 5703 |
5806 // v8::PropertyCallbackInfo::args_ array and name handle. | 5704 // v8::PropertyCallbackInfo::args_ array and name handle. |
5807 const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1; | 5705 const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1; |
5808 | 5706 |
5809 // Load address of v8::PropertyAccessorInfo::args_ array and name handle. | 5707 // Load address of v8::PropertyAccessorInfo::args_ array and name handle. |
5810 __ mr(r3, sp); // r3 = Handle<Name> | 5708 __ LoadRR(r2, sp); // r2 = Handle<Name> |
5811 __ addi(r4, r3, Operand(1 * kPointerSize)); // r4 = v8::PCI::args_ | 5709 __ AddP(r3, r2, Operand(1 * kPointerSize)); // r3 = v8::PCI::args_ |
5812 | 5710 |
5813 // If ABI passes Handles (pointer-sized struct) in a register: | 5711 // If ABI passes Handles (pointer-sized struct) in a register: |
5814 // | 5712 // |
5815 // Create 2 extra slots on stack: | 5713 // Create 2 extra slots on stack: |
5816 // [0] space for DirectCEntryStub's LR save | 5714 // [0] space for DirectCEntryStub's LR save |
5817 // [1] AccessorInfo& | 5715 // [1] AccessorInfo& |
5818 // | 5716 // |
5819 // Otherwise: | 5717 // Otherwise: |
5820 // | 5718 // |
5821 // Create 3 extra slots on stack: | 5719 // Create 3 extra slots on stack: |
5822 // [0] space for DirectCEntryStub's LR save | 5720 // [0] space for DirectCEntryStub's LR save |
5823 // [1] copy of Handle (first arg) | 5721 // [1] copy of Handle (first arg) |
5824 // [2] AccessorInfo& | 5722 // [2] AccessorInfo& |
5825 if (ABI_PASSES_HANDLES_IN_REGS) { | 5723 if (ABI_PASSES_HANDLES_IN_REGS) { |
5826 accessorInfoSlot = kStackFrameExtraParamSlot + 1; | 5724 accessorInfoSlot = kStackFrameExtraParamSlot + 1; |
5827 apiStackSpace = 2; | 5725 apiStackSpace = 2; |
5828 } else { | 5726 } else { |
5829 arg0Slot = kStackFrameExtraParamSlot + 1; | 5727 arg0Slot = kStackFrameExtraParamSlot + 1; |
5830 accessorInfoSlot = arg0Slot + 1; | 5728 accessorInfoSlot = arg0Slot + 1; |
5831 apiStackSpace = 3; | 5729 apiStackSpace = 3; |
5832 } | 5730 } |
5833 | 5731 |
5834 FrameScope frame_scope(masm, StackFrame::MANUAL); | 5732 FrameScope frame_scope(masm, StackFrame::MANUAL); |
5835 __ EnterExitFrame(false, apiStackSpace); | 5733 __ EnterExitFrame(false, apiStackSpace); |
5836 | 5734 |
5837 if (!ABI_PASSES_HANDLES_IN_REGS) { | 5735 if (!ABI_PASSES_HANDLES_IN_REGS) { |
5838 // pass 1st arg by reference | 5736 // pass 1st arg by reference |
5839 __ StoreP(r3, MemOperand(sp, arg0Slot * kPointerSize)); | 5737 __ StoreP(r2, MemOperand(sp, arg0Slot * kPointerSize)); |
5840 __ addi(r3, sp, Operand(arg0Slot * kPointerSize)); | 5738 __ AddP(r2, sp, Operand(arg0Slot * kPointerSize)); |
5841 } | 5739 } |
5842 | 5740 |
5843 // Create v8::PropertyCallbackInfo object on the stack and initialize | 5741 // Create v8::PropertyCallbackInfo object on the stack and initialize |
5844 // it's args_ field. | 5742 // it's args_ field. |
5845 __ StoreP(r4, MemOperand(sp, accessorInfoSlot * kPointerSize)); | 5743 __ StoreP(r3, MemOperand(sp, accessorInfoSlot * kPointerSize)); |
5846 __ addi(r4, sp, Operand(accessorInfoSlot * kPointerSize)); | 5744 __ AddP(r3, sp, Operand(accessorInfoSlot * kPointerSize)); |
5847 // r4 = v8::PropertyCallbackInfo& | 5745 // r3 = v8::PropertyCallbackInfo& |
5848 | 5746 |
5849 ExternalReference thunk_ref = | 5747 ExternalReference thunk_ref = |
5850 ExternalReference::invoke_accessor_getter_callback(isolate()); | 5748 ExternalReference::invoke_accessor_getter_callback(isolate()); |
5851 | 5749 |
5852 // +3 is to skip prolog, return address and name handle. | 5750 // +3 is to skip prolog, return address and name handle. |
5853 MemOperand return_value_operand( | 5751 MemOperand return_value_operand( |
5854 fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize); | 5752 fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize); |
5855 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, | 5753 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, |
5856 kStackUnwindSpace, NULL, return_value_operand, NULL); | 5754 kStackUnwindSpace, NULL, return_value_operand, NULL); |
5857 } | 5755 } |
5858 | 5756 |
| 5757 #undef __ |
5859 | 5758 |
5860 #undef __ | |
5861 } // namespace internal | 5759 } // namespace internal |
5862 } // namespace v8 | 5760 } // namespace v8 |
5863 | 5761 |
5864 #endif // V8_TARGET_ARCH_PPC | 5762 #endif // V8_TARGET_ARCH_S390 |
OLD | NEW |