OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_X64 | 5 #if V8_TARGET_ARCH_X64 |
6 | 6 |
7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 __ bind(&load_smi_rax); | 207 __ bind(&load_smi_rax); |
208 __ SmiToInteger32(kScratchRegister, rax); | 208 __ SmiToInteger32(kScratchRegister, rax); |
209 __ Cvtlsi2sd(xmm1, kScratchRegister); | 209 __ Cvtlsi2sd(xmm1, kScratchRegister); |
210 __ bind(&done); | 210 __ bind(&done); |
211 } | 211 } |
212 | 212 |
213 | 213 |
214 void MathPowStub::Generate(MacroAssembler* masm) { | 214 void MathPowStub::Generate(MacroAssembler* masm) { |
215 const Register exponent = MathPowTaggedDescriptor::exponent(); | 215 const Register exponent = MathPowTaggedDescriptor::exponent(); |
216 DCHECK(exponent.is(rdx)); | 216 DCHECK(exponent.is(rdx)); |
217 const Register base = rax; | |
218 const Register scratch = rcx; | 217 const Register scratch = rcx; |
219 const XMMRegister double_result = xmm3; | 218 const XMMRegister double_result = xmm3; |
220 const XMMRegister double_base = xmm2; | 219 const XMMRegister double_base = xmm2; |
221 const XMMRegister double_exponent = xmm1; | 220 const XMMRegister double_exponent = xmm1; |
222 const XMMRegister double_scratch = xmm4; | 221 const XMMRegister double_scratch = xmm4; |
223 | 222 |
224 Label call_runtime, done, exponent_not_smi, int_exponent; | 223 Label call_runtime, done, exponent_not_smi, int_exponent; |
225 | 224 |
226 // Save 1 in double_result - we need this several times later on. | 225 // Save 1 in double_result - we need this several times later on. |
227 __ movp(scratch, Immediate(1)); | 226 __ movp(scratch, Immediate(1)); |
228 __ Cvtlsi2sd(double_result, scratch); | 227 __ Cvtlsi2sd(double_result, scratch); |
229 | 228 |
230 if (exponent_type() == ON_STACK) { | 229 if (exponent_type() == TAGGED) { |
231 Label base_is_smi, unpack_exponent; | |
232 // The exponent and base are supplied as arguments on the stack. | |
233 // This can only happen if the stub is called from non-optimized code. | |
234 // Load input parameters from stack. | |
235 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); | |
236 __ movp(base, args.GetArgumentOperand(0)); | |
237 __ movp(exponent, args.GetArgumentOperand(1)); | |
238 __ JumpIfSmi(base, &base_is_smi, Label::kNear); | |
239 __ CompareRoot(FieldOperand(base, HeapObject::kMapOffset), | |
240 Heap::kHeapNumberMapRootIndex); | |
241 __ j(not_equal, &call_runtime); | |
242 | |
243 __ Movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset)); | |
244 __ jmp(&unpack_exponent, Label::kNear); | |
245 | |
246 __ bind(&base_is_smi); | |
247 __ SmiToInteger32(base, base); | |
248 __ Cvtlsi2sd(double_base, base); | |
249 __ bind(&unpack_exponent); | |
250 | |
251 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); | 230 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); |
252 __ SmiToInteger32(exponent, exponent); | 231 __ SmiToInteger32(exponent, exponent); |
253 __ jmp(&int_exponent); | 232 __ jmp(&int_exponent); |
254 | |
255 __ bind(&exponent_not_smi); | |
256 __ CompareRoot(FieldOperand(exponent, HeapObject::kMapOffset), | |
257 Heap::kHeapNumberMapRootIndex); | |
258 __ j(not_equal, &call_runtime); | |
259 __ Movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset)); | |
260 } else if (exponent_type() == TAGGED) { | |
261 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); | |
262 __ SmiToInteger32(exponent, exponent); | |
263 __ jmp(&int_exponent); | |
264 | 233 |
265 __ bind(&exponent_not_smi); | 234 __ bind(&exponent_not_smi); |
266 __ Movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset)); | 235 __ Movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset)); |
267 } | 236 } |
268 | 237 |
269 if (exponent_type() != INTEGER) { | 238 if (exponent_type() != INTEGER) { |
270 Label fast_power, try_arithmetic_simplification; | 239 Label fast_power, try_arithmetic_simplification; |
271 // Detect integer exponents stored as double. | 240 // Detect integer exponents stored as double. |
272 __ DoubleToI(exponent, double_exponent, double_scratch, | 241 __ DoubleToI(exponent, double_exponent, double_scratch, |
273 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification, | 242 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification, |
274 &try_arithmetic_simplification, | 243 &try_arithmetic_simplification, |
275 &try_arithmetic_simplification); | 244 &try_arithmetic_simplification); |
276 __ jmp(&int_exponent); | 245 __ jmp(&int_exponent); |
277 | 246 |
278 __ bind(&try_arithmetic_simplification); | 247 __ bind(&try_arithmetic_simplification); |
279 __ Cvttsd2si(exponent, double_exponent); | 248 __ Cvttsd2si(exponent, double_exponent); |
280 // Skip to runtime if possibly NaN (indicated by the indefinite integer). | 249 // Skip to runtime if possibly NaN (indicated by the indefinite integer). |
281 __ cmpl(exponent, Immediate(0x1)); | 250 __ cmpl(exponent, Immediate(0x1)); |
282 __ j(overflow, &call_runtime); | 251 __ j(overflow, &call_runtime); |
283 | 252 |
284 if (exponent_type() == ON_STACK) { | |
285 // Detect square root case. Crankshaft detects constant +/-0.5 at | |
286 // compile time and uses DoMathPowHalf instead. We then skip this check | |
287 // for non-constant cases of +/-0.5 as these hardly occur. | |
288 Label continue_sqrt, continue_rsqrt, not_plus_half; | |
289 // Test for 0.5. | |
290 // Load double_scratch with 0.5. | |
291 __ movq(scratch, V8_UINT64_C(0x3FE0000000000000)); | |
292 __ Movq(double_scratch, scratch); | |
293 // Already ruled out NaNs for exponent. | |
294 __ Ucomisd(double_scratch, double_exponent); | |
295 __ j(not_equal, ¬_plus_half, Label::kNear); | |
296 | |
297 // Calculates square root of base. Check for the special case of | |
298 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). | |
299 // According to IEEE-754, double-precision -Infinity has the highest | |
300 // 12 bits set and the lowest 52 bits cleared. | |
301 __ movq(scratch, V8_UINT64_C(0xFFF0000000000000)); | |
302 __ Movq(double_scratch, scratch); | |
303 __ Ucomisd(double_scratch, double_base); | |
304 // Comparing -Infinity with NaN results in "unordered", which sets the | |
305 // zero flag as if both were equal. However, it also sets the carry flag. | |
306 __ j(not_equal, &continue_sqrt, Label::kNear); | |
307 __ j(carry, &continue_sqrt, Label::kNear); | |
308 | |
309 // Set result to Infinity in the special case. | |
310 __ Xorpd(double_result, double_result); | |
311 __ Subsd(double_result, double_scratch); | |
312 __ jmp(&done); | |
313 | |
314 __ bind(&continue_sqrt); | |
315 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. | |
316 __ Xorpd(double_scratch, double_scratch); | |
317 __ Addsd(double_scratch, double_base); // Convert -0 to 0. | |
318 __ Sqrtsd(double_result, double_scratch); | |
319 __ jmp(&done); | |
320 | |
321 // Test for -0.5. | |
322 __ bind(¬_plus_half); | |
323 // Load double_scratch with -0.5 by substracting 1. | |
324 __ Subsd(double_scratch, double_result); | |
325 // Already ruled out NaNs for exponent. | |
326 __ Ucomisd(double_scratch, double_exponent); | |
327 __ j(not_equal, &fast_power, Label::kNear); | |
328 | |
329 // Calculates reciprocal of square root of base. Check for the special | |
330 // case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). | |
331 // According to IEEE-754, double-precision -Infinity has the highest | |
332 // 12 bits set and the lowest 52 bits cleared. | |
333 __ movq(scratch, V8_UINT64_C(0xFFF0000000000000)); | |
334 __ Movq(double_scratch, scratch); | |
335 __ Ucomisd(double_scratch, double_base); | |
336 // Comparing -Infinity with NaN results in "unordered", which sets the | |
337 // zero flag as if both were equal. However, it also sets the carry flag. | |
338 __ j(not_equal, &continue_rsqrt, Label::kNear); | |
339 __ j(carry, &continue_rsqrt, Label::kNear); | |
340 | |
341 // Set result to 0 in the special case. | |
342 __ Xorpd(double_result, double_result); | |
343 __ jmp(&done); | |
344 | |
345 __ bind(&continue_rsqrt); | |
346 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. | |
347 __ Xorpd(double_exponent, double_exponent); | |
348 __ Addsd(double_exponent, double_base); // Convert -0 to +0. | |
349 __ Sqrtsd(double_exponent, double_exponent); | |
350 __ Divsd(double_result, double_exponent); | |
351 __ jmp(&done); | |
352 } | |
353 | |
354 // Using FPU instructions to calculate power. | 253 // Using FPU instructions to calculate power. |
355 Label fast_power_failed; | 254 Label fast_power_failed; |
356 __ bind(&fast_power); | 255 __ bind(&fast_power); |
357 __ fnclex(); // Clear flags to catch exceptions later. | 256 __ fnclex(); // Clear flags to catch exceptions later. |
358 // Transfer (B)ase and (E)xponent onto the FPU register stack. | 257 // Transfer (B)ase and (E)xponent onto the FPU register stack. |
359 __ subp(rsp, Immediate(kDoubleSize)); | 258 __ subp(rsp, Immediate(kDoubleSize)); |
360 __ Movsd(Operand(rsp, 0), double_exponent); | 259 __ Movsd(Operand(rsp, 0), double_exponent); |
361 __ fld_d(Operand(rsp, 0)); // E | 260 __ fld_d(Operand(rsp, 0)); // E |
362 __ Movsd(Operand(rsp, 0), double_base); | 261 __ Movsd(Operand(rsp, 0), double_base); |
363 __ fld_d(Operand(rsp, 0)); // B, E | 262 __ fld_d(Operand(rsp, 0)); // B, E |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. | 331 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. |
433 __ Xorpd(double_scratch2, double_scratch2); | 332 __ Xorpd(double_scratch2, double_scratch2); |
434 __ Ucomisd(double_scratch2, double_result); | 333 __ Ucomisd(double_scratch2, double_result); |
435 // double_exponent aliased as double_scratch2 has already been overwritten | 334 // double_exponent aliased as double_scratch2 has already been overwritten |
436 // and may not have contained the exponent value in the first place when the | 335 // and may not have contained the exponent value in the first place when the |
437 // input was a smi. We reset it with exponent value before bailing out. | 336 // input was a smi. We reset it with exponent value before bailing out. |
438 __ j(not_equal, &done); | 337 __ j(not_equal, &done); |
439 __ Cvtlsi2sd(double_exponent, exponent); | 338 __ Cvtlsi2sd(double_exponent, exponent); |
440 | 339 |
441 // Returning or bailing out. | 340 // Returning or bailing out. |
442 if (exponent_type() == ON_STACK) { | 341 __ bind(&call_runtime); |
443 // The arguments are still on the stack. | 342 // Move base to the correct argument register. Exponent is already in xmm1. |
444 __ bind(&call_runtime); | 343 __ Movsd(xmm0, double_base); |
445 __ TailCallRuntime(Runtime::kMathPowRT); | 344 DCHECK(double_exponent.is(xmm1)); |
| 345 { |
| 346 AllowExternalCallThatCantCauseGC scope(masm); |
| 347 __ PrepareCallCFunction(2); |
| 348 __ CallCFunction(ExternalReference::power_double_double_function(isolate()), |
| 349 2); |
| 350 } |
| 351 // Return value is in xmm0. |
| 352 __ Movsd(double_result, xmm0); |
446 | 353 |
447 // The stub is called from non-optimized code, which expects the result | 354 __ bind(&done); |
448 // as heap number in rax. | 355 __ ret(0); |
449 __ bind(&done); | |
450 __ AllocateHeapNumber(rax, rcx, &call_runtime); | |
451 __ Movsd(FieldOperand(rax, HeapNumber::kValueOffset), double_result); | |
452 __ ret(2 * kPointerSize); | |
453 } else { | |
454 __ bind(&call_runtime); | |
455 // Move base to the correct argument register. Exponent is already in xmm1. | |
456 __ Movsd(xmm0, double_base); | |
457 DCHECK(double_exponent.is(xmm1)); | |
458 { | |
459 AllowExternalCallThatCantCauseGC scope(masm); | |
460 __ PrepareCallCFunction(2); | |
461 __ CallCFunction( | |
462 ExternalReference::power_double_double_function(isolate()), 2); | |
463 } | |
464 // Return value is in xmm0. | |
465 __ Movsd(double_result, xmm0); | |
466 | |
467 __ bind(&done); | |
468 __ ret(0); | |
469 } | |
470 } | 356 } |
471 | 357 |
472 | 358 |
473 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { | 359 void FunctionPrototypeStub::Generate(MacroAssembler* masm) { |
474 Label miss; | 360 Label miss; |
475 Register receiver = LoadDescriptor::ReceiverRegister(); | 361 Register receiver = LoadDescriptor::ReceiverRegister(); |
476 // Ensure that the vector and slot registers won't be clobbered before | 362 // Ensure that the vector and slot registers won't be clobbered before |
477 // calling the miss handler. | 363 // calling the miss handler. |
478 DCHECK(!AreAliased(r8, r9, LoadWithVectorDescriptor::VectorRegister(), | 364 DCHECK(!AreAliased(r8, r9, LoadWithVectorDescriptor::VectorRegister(), |
479 LoadDescriptor::SlotRegister())); | 365 LoadDescriptor::SlotRegister())); |
(...skipping 4850 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5330 kStackUnwindSpace, nullptr, return_value_operand, | 5216 kStackUnwindSpace, nullptr, return_value_operand, |
5331 NULL); | 5217 NULL); |
5332 } | 5218 } |
5333 | 5219 |
5334 #undef __ | 5220 #undef __ |
5335 | 5221 |
5336 } // namespace internal | 5222 } // namespace internal |
5337 } // namespace v8 | 5223 } // namespace v8 |
5338 | 5224 |
5339 #endif // V8_TARGET_ARCH_X64 | 5225 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |