| 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 |