2010-04-28 Oliver Hunt <oliver@apple.com>
Reviewed by Gavin Barraclough.
Add fast paths for Math.pow and Math.sqrt
https://bugs.webkit.org/show_bug.cgi?id=38294
Add specialized thunks for Math.pow and Math.sqrt.
This requires adding a sqrtDouble function to the MacroAssembler
and sqrtsd to the x86 assembler.
Math.pow is slightly more complicated, in that we have
to implement exponentiation ourselves rather than relying
on hardware support. The inline exponentiation is restricted
to positive integer exponents on a numeric base. Exponentiation
is finally performed through the "Exponentiation by Squaring"
algorithm.
* assembler/AbstractMacroAssembler.h:
(JSC::AbstractMacroAssembler::ImmPtr::ImmPtr):
* assembler/MacroAssemblerARM.h:
(JSC::MacroAssemblerARM::supportsFloatingPointSqrt):
(JSC::MacroAssemblerARM::loadDouble):
(JSC::MacroAssemblerARM::sqrtDouble):
* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::supportsFloatingPointSqrt):
(JSC::MacroAssemblerARMv7::sqrtDouble):
* assembler/MacroAssemblerX86.h:
(JSC::MacroAssemblerX86::loadDouble):
(JSC::MacroAssemblerX86::supportsFloatingPointSqrt):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::sqrtDouble):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::loadDouble):
(JSC::MacroAssemblerX86_64::supportsFloatingPointSqrt):
* assembler/X86Assembler.h:
(JSC::X86Assembler::):
(JSC::X86Assembler::movsd_mr):
(JSC::X86Assembler::sqrtsd_rr):
(JSC::X86Assembler::X86InstructionFormatter::twoByteOp):
(JSC::X86Assembler::X86InstructionFormatter::memoryModRM):
* create_hash_table:
* jit/JIT.h:
* jit/JITInlineMethods.h:
* jit/JITOpcodes.cpp:
* jit/JITStubs.h:
(JSC::JITThunks::ctiNativeCallThunk):
* jit/JSInterfaceJIT.h:
(JSC::JSInterfaceJIT::emitLoadDouble):
(JSC::JSInterfaceJIT::emitJumpIfImmediateNumber):
(JSC::JSInterfaceJIT::emitJumpIfNotImmediateNumber):
(JSC::JSInterfaceJIT::emitLoadInt32):
* jit/SpecializedThunkJIT.h:
(JSC::SpecializedThunkJIT::loadDoubleArgument):
(JSC::SpecializedThunkJIT::loadInt32Argument):
(JSC::SpecializedThunkJIT::returnJSValue):
(JSC::SpecializedThunkJIT::returnDouble):
(JSC::SpecializedThunkJIT::finalize):
* jit/ThunkGenerators.cpp:
(JSC::sqrtThunkGenerator):
(JSC::powThunkGenerator):
* jit/ThunkGenerators.h:
* runtime/Executable.h:
(JSC::NativeExecutable::NativeExecutable):
* runtime/JSFunction.cpp:
(JSC::JSFunction::JSFunction):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@58469 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/jit/JSInterfaceJIT.h b/JavaScriptCore/jit/JSInterfaceJIT.h
index 74fc0e4..caf1ac5 100644
--- a/JavaScriptCore/jit/JSInterfaceJIT.h
+++ b/JavaScriptCore/jit/JSInterfaceJIT.h
@@ -68,6 +68,7 @@
static const FPRegisterID fpRegT0 = X86Registers::xmm0;
static const FPRegisterID fpRegT1 = X86Registers::xmm1;
static const FPRegisterID fpRegT2 = X86Registers::xmm2;
+ static const FPRegisterID fpRegT3 = X86Registers::xmm3;
#elif CPU(X86)
static const RegisterID returnValueRegister = X86Registers::eax;
static const RegisterID cachedResultRegister = X86Registers::eax;
@@ -86,6 +87,7 @@
static const FPRegisterID fpRegT0 = X86Registers::xmm0;
static const FPRegisterID fpRegT1 = X86Registers::xmm1;
static const FPRegisterID fpRegT2 = X86Registers::xmm2;
+ static const FPRegisterID fpRegT3 = X86Registers::xmm3;
#elif CPU(ARM_THUMB2)
static const RegisterID returnValueRegister = ARMRegisters::r0;
static const RegisterID cachedResultRegister = ARMRegisters::r0;
@@ -102,6 +104,7 @@
static const FPRegisterID fpRegT0 = ARMRegisters::d0;
static const FPRegisterID fpRegT1 = ARMRegisters::d1;
static const FPRegisterID fpRegT2 = ARMRegisters::d2;
+ static const FPRegisterID fpRegT3 = ARMRegisters::d3;
#elif CPU(ARM_TRADITIONAL)
static const RegisterID returnValueRegister = ARMRegisters::r0;
static const RegisterID cachedResultRegister = ARMRegisters::r0;
@@ -126,6 +129,7 @@
static const FPRegisterID fpRegT0 = ARMRegisters::d0;
static const FPRegisterID fpRegT1 = ARMRegisters::d1;
static const FPRegisterID fpRegT2 = ARMRegisters::d2;
+ static const FPRegisterID fpRegT3 = ARMRegisters::d3;
#elif CPU(MIPS)
static const RegisterID returnValueRegister = MIPSRegisters::v0;
static const RegisterID cachedResultRegister = MIPSRegisters::v0;
@@ -148,21 +152,29 @@
static const FPRegisterID fpRegT0 = MIPSRegisters::f4;
static const FPRegisterID fpRegT1 = MIPSRegisters::f6;
static const FPRegisterID fpRegT2 = MIPSRegisters::f8;
+ static const FPRegisterID fpRegT2 = MIPSRegisters::f10;
#else
#error "JIT not supported on this platform."
#endif
inline Jump emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload);
inline Jump emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst);
+ inline Jump emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch);
#if USE(JSVALUE32_64)
inline Jump emitJumpIfNotJSCell(unsigned virtualRegisterIndex);
inline Address tagFor(unsigned index, RegisterID base = callFrameRegister);
#endif
+
+#if USE(JSVALUE32) || USE(JSVALUE64)
+ Jump emitJumpIfImmediateNumber(RegisterID reg);
+ Jump emitJumpIfNotImmediateNumber(RegisterID reg);
+#endif
+
inline Address payloadFor(unsigned index, RegisterID base = callFrameRegister);
inline Address addressFor(unsigned index, RegisterID base = callFrameRegister);
};
-
+
#if USE(JSVALUE32_64)
inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload)
{
@@ -190,9 +202,31 @@
{
return Address(base, (index * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload));
}
+
+ inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
+ {
+ loadPtr(tagFor(virtualRegisterIndex), scratch);
+ Jump isDouble = branch32(Below, scratch, Imm32(JSValue::LowestTag));
+ Jump notInt = branch32(NotEqual, scratch, Imm32(JSValue::Int32Tag));
+ loadPtr(payloadFor(virtualRegisterIndex), scratch);
+ convertInt32ToDouble(scratch, dst);
+ Jump done = jump();
+ isDouble.link(this);
+ loadDouble(addressFor(virtualRegisterIndex), dst);
+ done.link(this);
+ return notInt;
+ }
#endif
#if USE(JSVALUE64)
+ ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg)
+ {
+ return branchTestPtr(NonZero, reg, tagTypeNumberRegister);
+ }
+ ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg)
+ {
+ return branchTestPtr(Zero, reg, tagTypeNumberRegister);
+ }
inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID dst)
{
loadPtr(addressFor(virtualRegisterIndex), dst);
@@ -206,6 +240,21 @@
zeroExtend32ToPtr(dst, dst);
return result;
}
+
+ inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
+ {
+ loadPtr(addressFor(virtualRegisterIndex), scratch);
+ Jump notNumber = emitJumpIfNotImmediateNumber(scratch);
+ Jump notInt = branchPtr(Below, scratch, tagTypeNumberRegister);
+ convertInt32ToDouble(scratch, dst);
+ Jump done = jump();
+ notInt.link(this);
+ addPtr(tagTypeNumberRegister, scratch);
+ movePtrToDouble(scratch, dst);
+ done.link(this);
+ return notNumber;
+ }
+
#endif
#if USE(JSVALUE32)
@@ -221,7 +270,13 @@
Jump result = branchTest32(Zero, dst, Imm32(JSImmediate::TagTypeNumber));
rshift32(Imm32(JSImmediate::IntegerPayloadShift), dst);
return result;
- }
+ }
+
+ inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned, FPRegisterID, RegisterID)
+ {
+ ASSERT_NOT_REACHED();
+ return jump();
+ }
#endif
#if !USE(JSVALUE32_64)