diff options
Diffstat (limited to 'Source/JavaScriptCore/jit')
-rw-r--r-- | Source/JavaScriptCore/jit/JIT.cpp | 6 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JIT.h | 52 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JITArithmetic.cpp | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JITInlineMethods.h | 60 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JITOpcodes.cpp | 31 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JITOpcodes32_64.cpp | 154 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JITPropertyAccess.cpp | 35 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp | 41 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JITStubs.cpp | 134 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JITStubs.h | 25 | ||||
-rw-r--r-- | Source/JavaScriptCore/jit/JSInterfaceJIT.h | 35 |
11 files changed, 405 insertions, 170 deletions
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp index 063ae8c..b983427 100644 --- a/Source/JavaScriptCore/jit/JIT.cpp +++ b/Source/JavaScriptCore/jit/JIT.cpp @@ -44,6 +44,7 @@ JSC::MacroAssemblerX86Common::SSE2CheckState JSC::MacroAssemblerX86Common::s_sse #include "RepatchBuffer.h" #include "ResultType.h" #include "SamplingTool.h" +#include "dfg/DFGNode.h" // for DFG_SUCCESS_STATS using namespace std; @@ -471,6 +472,11 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck) Jump registerFileCheck; if (m_codeBlock->codeType() == FunctionCode) { +#if DFG_SUCCESS_STATS + static SamplingCounter counter("orignalJIT"); + emitCount(counter); +#endif + // In the case of a fast linked call, we do not set this up in the caller. emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock); diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h index 61bd2ab..6b8c6dd 100644 --- a/Source/JavaScriptCore/jit/JIT.h +++ b/Source/JavaScriptCore/jit/JIT.h @@ -235,7 +235,7 @@ namespace JSC { static void patchGetByIdSelf(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress); static void patchPutByIdReplace(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct); - static void patchMethodCallProto(CodeBlock* codeblock, MethodCallLinkInfo&, JSFunction*, Structure*, JSObject*, ReturnAddressPtr); + static void patchMethodCallProto(JSGlobalData&, CodeBlock* codeblock, MethodCallLinkInfo&, JSFunction*, Structure*, JSObject*, ReturnAddressPtr); static void compilePatchGetArrayLength(JSGlobalData* globalData, CodeBlock* codeBlock, ReturnAddressPtr returnAddress) { @@ -311,7 +311,7 @@ namespace JSC { void emitStoreInt32(unsigned index, RegisterID payload, bool indexIsInt32 = false); void emitStoreInt32(unsigned index, TrustedImm32 payload, bool indexIsInt32 = false); void emitStoreCell(unsigned index, RegisterID payload, bool indexIsCell = false); - void emitStoreBool(unsigned index, RegisterID tag, bool indexIsBool = false); + void emitStoreBool(unsigned index, RegisterID payload, bool indexIsBool = false); void emitStoreDouble(unsigned index, FPRegisterID value); bool isLabeled(unsigned bytecodeOffset); @@ -473,6 +473,48 @@ namespace JSC { static const int patchOffsetMethodCheckProtoStruct = 52; static const int patchOffsetMethodCheckPutFunction = 84; #endif +#elif CPU(SH4) + // These architecture specific value are used to enable patching - see comment on op_put_by_id. + static const int patchOffsetGetByIdStructure = 6; + static const int patchOffsetPutByIdPropertyMapOffset = 24; + static const int patchOffsetPutByIdStructure = 6; + // These architecture specific value are used to enable patching - see comment on op_get_by_id. + static const int patchOffsetGetByIdBranchToSlowCase = 10; + static const int patchOffsetGetByIdPropertyMapOffset = 24; + static const int patchOffsetGetByIdPutResult = 32; + + // sequenceOpCall + static const int sequenceOpCallInstructionSpace = 12; + static const int sequenceOpCallConstantSpace = 2; + // sequenceMethodCheck + static const int sequenceMethodCheckInstructionSpace = 40; + static const int sequenceMethodCheckConstantSpace = 6; + // sequenceGetByIdHotPath + static const int sequenceGetByIdHotPathInstructionSpace = 36; + static const int sequenceGetByIdHotPathConstantSpace = 5; + // sequenceGetByIdSlowCase + static const int sequenceGetByIdSlowCaseInstructionSpace = 26; + static const int sequenceGetByIdSlowCaseConstantSpace = 2; + // sequencePutById + static const int sequencePutByIdInstructionSpace = 36; + static const int sequencePutByIdConstantSpace = 5; + + static const int patchOffsetGetByIdPropertyMapOffset1 = 20; + static const int patchOffsetGetByIdPropertyMapOffset2 = 26; + + static const int patchOffsetPutByIdPropertyMapOffset1 = 20; + static const int patchOffsetPutByIdPropertyMapOffset2 = 26; + +#if ENABLE(OPCODE_SAMPLING) + static const int patchOffsetGetByIdSlowCaseCall = 0; // FIMXE +#else + static const int patchOffsetGetByIdSlowCaseCall = 22; +#endif + static const int patchOffsetOpCallCompareToJump = 4; + + static const int patchOffsetMethodCheckProtoObj = 12; + static const int patchOffsetMethodCheckProtoStruct = 20; + static const int patchOffsetMethodCheckPutFunction = 32; #else #error "JSVALUE32_64 not supported on this platform." #endif @@ -665,14 +707,16 @@ namespace JSC { #if (defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL) #define BEGIN_UNINTERRUPTED_SEQUENCE(name) do { beginUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace); } while (false) -#define END_UNINTERRUPTED_SEQUENCE(name) do { endUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace); } while (false) +#define END_UNINTERRUPTED_SEQUENCE_FOR_PUT(name, dst) do { endUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace, dst); } while (false) +#define END_UNINTERRUPTED_SEQUENCE(name) END_UNINTERRUPTED_SEQUENCE_FOR_PUT(name, 0) void beginUninterruptedSequence(int, int); - void endUninterruptedSequence(int, int); + void endUninterruptedSequence(int, int, int); #else #define BEGIN_UNINTERRUPTED_SEQUENCE(name) do { beginUninterruptedSequence(); } while (false) #define END_UNINTERRUPTED_SEQUENCE(name) do { endUninterruptedSequence(); } while (false) +#define END_UNINTERRUPTED_SEQUENCE_FOR_PUT(name, dst) do { endUninterruptedSequence(); } while (false) #endif void emit_op_add(Instruction*); diff --git a/Source/JavaScriptCore/jit/JITArithmetic.cpp b/Source/JavaScriptCore/jit/JITArithmetic.cpp index edf2290..734cc1d 100644 --- a/Source/JavaScriptCore/jit/JITArithmetic.cpp +++ b/Source/JavaScriptCore/jit/JITArithmetic.cpp @@ -966,7 +966,7 @@ void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned, unsigned op1, unsign void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned result, unsigned op1, unsigned op2, OperandTypes types, bool op1HasImmediateIntFastCase, bool op2HasImmediateIntFastCase) { // We assume that subtracting TagTypeNumber is equivalent to adding DoubleEncodeOffset. - COMPILE_ASSERT(((JSImmediate::TagTypeNumber + JSImmediate::DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0); + COMPILE_ASSERT(((TagTypeNumber + DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0); Jump notImm1; Jump notImm2; diff --git a/Source/JavaScriptCore/jit/JITInlineMethods.h b/Source/JavaScriptCore/jit/JITInlineMethods.h index 16c2335..dabfdd2 100644 --- a/Source/JavaScriptCore/jit/JITInlineMethods.h +++ b/Source/JavaScriptCore/jit/JITInlineMethods.h @@ -123,6 +123,13 @@ ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace ensureSpace(insnSpace, constSpace); +#elif CPU(SH4) +#ifndef NDEBUG + insnSpace += sizeof(SH4Word); + constSpace += sizeof(uint64_t); +#endif + + m_assembler.ensureSpace(insnSpace + m_assembler.maxInstructionSize + 2, constSpace + 8); #endif #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL @@ -133,8 +140,9 @@ ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace #endif } -ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace) +ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace, int dst) { + UNUSED_PARAM(dst); #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL /* There are several cases when the uninterrupted sequence is larger than * maximum required offset for pathing the same sequence. Eg.: if in a @@ -143,6 +151,15 @@ ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace) * calculation of length of uninterrupted sequence. So, the insnSpace and * constSpace should be upper limit instead of hard limit. */ +#if CPU(SH4) + if ((dst > 15) || (dst < -16)) { + insnSpace += 8; + constSpace += 2; + } + + if (((dst >= -16) && (dst < 0)) || ((dst > 7) && (dst <= 15))) + insnSpace += 8; +#endif ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) <= insnSpace); ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin <= constSpace); #endif @@ -167,6 +184,22 @@ ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) { loadPtr(address, linkRegister); } +#elif CPU(SH4) + +ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) +{ + m_assembler.stspr(reg); +} + +ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) +{ + m_assembler.ldspr(reg); +} + +ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) +{ + loadPtrLinkReg(address); +} #elif CPU(MIPS) @@ -217,6 +250,8 @@ ALWAYS_INLINE void JIT::restoreArgumentReferenceForTrampoline() addPtr(TrustedImm32(sizeof(void*)), stackPointerRegister, firstArgumentRegister); #elif CPU(ARM) move(stackPointerRegister, firstArgumentRegister); +#elif CPU(SH4) + move(stackPointerRegister, firstArgumentRegister); #endif // In the trampoline on x86-64, the first argument register is not overwritten. } @@ -453,11 +488,11 @@ inline void JIT::emitStoreCell(unsigned index, RegisterID payload, bool indexIsC store32(TrustedImm32(JSValue::CellTag), tagFor(index, callFrameRegister)); } -inline void JIT::emitStoreBool(unsigned index, RegisterID tag, bool indexIsBool) +inline void JIT::emitStoreBool(unsigned index, RegisterID payload, bool indexIsBool) { + store32(payload, payloadFor(index, callFrameRegister)); if (!indexIsBool) - store32(TrustedImm32(0), payloadFor(index, callFrameRegister)); - store32(tag, tagFor(index, callFrameRegister)); + store32(TrustedImm32(JSValue::BooleanTag), tagFor(index, callFrameRegister)); } inline void JIT::emitStoreDouble(unsigned index, FPRegisterID value) @@ -674,7 +709,7 @@ ALWAYS_INLINE JIT::Jump JIT::emitJumpIfJSCell(RegisterID reg) #if USE(JSVALUE64) return branchTestPtr(Zero, reg, tagMaskRegister); #else - return branchTest32(Zero, reg, TrustedImm32(JSImmediate::TagMask)); + return branchTest32(Zero, reg, TrustedImm32(TagMask)); #endif } @@ -695,7 +730,7 @@ ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotJSCell(RegisterID reg) #if USE(JSVALUE64) return branchTestPtr(NonZero, reg, tagMaskRegister); #else - return branchTest32(NonZero, reg, TrustedImm32(JSImmediate::TagMask)); + return branchTest32(NonZero, reg, TrustedImm32(TagMask)); #endif } @@ -736,7 +771,7 @@ ALWAYS_INLINE JIT::Jump JIT::emitJumpIfImmediateInteger(RegisterID reg) #if USE(JSVALUE64) return branchPtr(AboveOrEqual, reg, tagTypeNumberRegister); #else - return branchTest32(NonZero, reg, TrustedImm32(JSImmediate::TagTypeNumber)); + return branchTest32(NonZero, reg, TrustedImm32(TagTypeNumber)); #endif } @@ -745,7 +780,7 @@ ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateInteger(RegisterID reg) #if USE(JSVALUE64) return branchPtr(Below, reg, tagTypeNumberRegister); #else - return branchTest32(Zero, reg, TrustedImm32(JSImmediate::TagTypeNumber)); + return branchTest32(Zero, reg, TrustedImm32(TagTypeNumber)); #endif } @@ -774,12 +809,12 @@ ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateNumber(RegisterID reg) #if USE(JSVALUE32_64) ALWAYS_INLINE void JIT::emitFastArithDeTagImmediate(RegisterID reg) { - subPtr(TrustedImm32(JSImmediate::TagTypeNumber), reg); + subPtr(TrustedImm32(TagTypeNumber), reg); } ALWAYS_INLINE JIT::Jump JIT::emitFastArithDeTagImmediateJumpIfZero(RegisterID reg) { - return branchSubPtr(Zero, TrustedImm32(JSImmediate::TagTypeNumber), reg); + return branchSubPtr(Zero, TrustedImm32(TagTypeNumber), reg); } #endif @@ -790,7 +825,7 @@ ALWAYS_INLINE void JIT::emitFastArithReTagImmediate(RegisterID src, RegisterID d #else if (src != dest) move(src, dest); - addPtr(TrustedImm32(JSImmediate::TagTypeNumber), dest); + addPtr(TrustedImm32(TagTypeNumber), dest); #endif } @@ -810,8 +845,7 @@ ALWAYS_INLINE void JIT::emitFastArithIntToImmNoCheck(RegisterID src, RegisterID ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg) { - lshift32(TrustedImm32(JSImmediate::ExtendedPayloadShift), reg); - or32(TrustedImm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool)), reg); + or32(TrustedImm32(static_cast<int32_t>(ValueFalse)), reg); } #endif // USE(JSVALUE32_64) diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp index daceea6..53bc1df 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp @@ -57,7 +57,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable // Checks out okay! - get the length from the Ustring. load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT0); - Jump string_failureCases3 = branch32(Above, regT0, TrustedImm32(JSImmediate::maxImmediateInt)); + Jump string_failureCases3 = branch32(LessThan, regT0, TrustedImm32(0)); // regT0 contains a 64 bit value (is positive, is zero extended) so we don't need sign extend here. emitFastArithIntToImmNoCheck(regT0, regT0); @@ -695,9 +695,14 @@ void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<Slo void JIT::emit_op_not(Instruction* currentInstruction) { emitGetVirtualRegister(currentInstruction[2].u.operand, regT0); - xorPtr(TrustedImm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool)), regT0); - addSlowCase(branchTestPtr(NonZero, regT0, TrustedImm32(static_cast<int32_t>(~JSImmediate::ExtendedPayloadBitBoolValue)))); - xorPtr(TrustedImm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool | JSImmediate::ExtendedPayloadBitBoolValue)), regT0); + + // Invert against JSValue(false); if the value was tagged as a boolean, then all bits will be + // clear other than the low bit (which will be 0 or 1 for false or true inputs respectively). + // Then invert against JSValue(true), which will add the tag back in, and flip the low bit. + xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), regT0); + addSlowCase(branchTestPtr(NonZero, regT0, TrustedImm32(static_cast<int32_t>(~1)))); + xorPtr(TrustedImm32(static_cast<int32_t>(ValueTrue)), regT0); + emitPutVirtualRegister(currentInstruction[1].u.operand); } @@ -731,7 +736,7 @@ void JIT::emit_op_jeq_null(Instruction* currentInstruction) // Now handle the immediate cases - undefined & null isImmediate.link(this); - andPtr(TrustedImm32(~JSImmediate::ExtendedTagBitUndefined), regT0); + andPtr(TrustedImm32(~TagBitUndefined), regT0); addJump(branchPtr(Equal, regT0, TrustedImmPtr(JSValue::encode(jsNull()))), target); wasNotImmediate.link(this); @@ -752,7 +757,7 @@ void JIT::emit_op_jneq_null(Instruction* currentInstruction) // Now handle the immediate cases - undefined & null isImmediate.link(this); - andPtr(TrustedImm32(~JSImmediate::ExtendedTagBitUndefined), regT0); + andPtr(TrustedImm32(~TagBitUndefined), regT0); addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(jsNull()))), target); wasNotImmediate.link(this); @@ -909,8 +914,8 @@ void JIT::emit_op_get_pnames(Instruction* currentInstruction) isNotObject.link(this); move(regT0, regT1); - and32(TrustedImm32(~JSImmediate::ExtendedTagBitUndefined), regT1); - addJump(branch32(Equal, regT1, TrustedImm32(JSImmediate::FullTagTypeNull)), breakTarget); + and32(TrustedImm32(~TagBitUndefined), regT1); + addJump(branch32(Equal, regT1, TrustedImm32(ValueNull)), breakTarget); JITStubCall toObjectStubCall(this, cti_to_object); toObjectStubCall.addArgument(regT0); @@ -1163,8 +1168,8 @@ void JIT::emit_op_eq_null(Instruction* currentInstruction) isImmediate.link(this); - andPtr(TrustedImm32(~JSImmediate::ExtendedTagBitUndefined), regT0); - setPtr(Equal, regT0, TrustedImm32(JSImmediate::FullTagTypeNull), regT0); + andPtr(TrustedImm32(~TagBitUndefined), regT0); + setPtr(Equal, regT0, TrustedImm32(ValueNull), regT0); wasNotImmediate.link(this); @@ -1188,8 +1193,8 @@ void JIT::emit_op_neq_null(Instruction* currentInstruction) isImmediate.link(this); - andPtr(TrustedImm32(~JSImmediate::ExtendedTagBitUndefined), regT0); - setPtr(NotEqual, regT0, TrustedImm32(JSImmediate::FullTagTypeNull), regT0); + andPtr(TrustedImm32(~TagBitUndefined), regT0); + setPtr(NotEqual, regT0, TrustedImm32(ValueNull), regT0); wasNotImmediate.link(this); @@ -1374,7 +1379,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { linkSlowCase(iter); - xorPtr(TrustedImm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool)), regT0); + xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), regT0); JITStubCall stubCall(this, cti_op_not); stubCall.addArgument(regT0); stubCall.call(currentInstruction[1].u.operand); diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp index bc0b2cb..edce21c 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -245,7 +245,26 @@ JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isCon call(Address(regT2, executableOffsetToFunction)); restoreReturnAddressBeforeReturn(regT3); +#elif CPU(SH4) + // Load caller frame's scope chain into this callframe so that whatever we call can + // get to its global data. + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2); + emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2); + emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); + + preserveReturnAddressAfterCall(regT3); // Callee preserved + emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); + + // Calling convention: f(r0 == regT4, r1 == regT5, ...); + // Host function signature: f(ExecState*); + move(callFrameRegister, regT4); + + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT5); + move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. + loadPtr(Address(regT5, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + call(Address(regT2, executableOffsetToFunction), regT0); + restoreReturnAddressBeforeReturn(regT3); #elif CPU(MIPS) // Load caller frame's scope chain into this callframe so that whatever we call can // get to its global data. @@ -394,7 +413,28 @@ JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executa addPtr(TrustedImm32(16), stackPointerRegister); restoreReturnAddressBeforeReturn(regT3); +#elif CPU(SH4) + // Load caller frame's scope chain into this callframe so that whatever we call can + // get to its global data. + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2); + emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2); + emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); + preserveReturnAddressAfterCall(regT3); // Callee preserved + emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); + + // Calling convention: f(r0 == regT4, r1 == regT5, ...); + // Host function signature: f(ExecState*); + move(callFrameRegister, regT4); + + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT5); + move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. + loadPtr(Address(regT5, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + + // call the function + nativeCall = call(); + + restoreReturnAddressBeforeReturn(regT3); #elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL) #error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform." #else @@ -553,7 +593,7 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) // Optimistically load the result true, and start looping. // Initially, regT1 still contains proto and regT2 still contains value. // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain. - move(TrustedImm32(JSValue::TrueTag), regT0); + move(TrustedImm32(1), regT0); Label loop(this); // Load the prototype of the cell in regT2. If this is equal to regT1 - WIN! @@ -564,7 +604,7 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) branchTest32(NonZero, regT2).linkTo(loop, this); // We get here either by dropping out of the loop, or if value was not an Object. Result is false. - move(TrustedImm32(JSValue::FalseTag), regT0); + move(TrustedImm32(0), regT0); // isInstance jumps right down to here, to skip setting the result to false (it has already set true). isInstance.link(this); @@ -829,9 +869,9 @@ void JIT::emit_op_not(Instruction* currentInstruction) emitLoadTag(src, regT0); - xor32(TrustedImm32(JSValue::FalseTag), regT0); - addSlowCase(branchTest32(NonZero, regT0, TrustedImm32(~1))); - xor32(TrustedImm32(JSValue::TrueTag), regT0); + emitLoad(src, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::BooleanTag))); + xor32(TrustedImm32(1), regT0); emitStoreBool(dst, regT0, (dst == src)); } @@ -855,25 +895,9 @@ void JIT::emit_op_jfalse(Instruction* currentInstruction) emitLoad(cond, regT1, regT0); - Jump isTrue = branch32(Equal, regT1, TrustedImm32(JSValue::TrueTag)); - addJump(branch32(Equal, regT1, TrustedImm32(JSValue::FalseTag)), target); - - Jump isNotInteger = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)); - Jump isTrue2 = branch32(NotEqual, regT0, TrustedImm32(0)); - addJump(jump(), target); - - if (supportsFloatingPoint()) { - isNotInteger.link(this); - - addSlowCase(branch32(Above, regT1, TrustedImm32(JSValue::LowestTag))); - - emitLoadDouble(cond, fpRegT0); - addJump(branchDoubleZeroOrNaN(fpRegT0, fpRegT1), target); - } else - addSlowCase(isNotInteger); - - isTrue.link(this); - isTrue2.link(this); + ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1)); + addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag))); + addJump(branchTest32(Zero, regT0), target); } void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -882,6 +906,18 @@ void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEnt unsigned target = currentInstruction[2].u.operand; linkSlowCase(iter); + + if (supportsFloatingPoint()) { + // regT1 contains the tag from the hot path. + Jump notNumber = branch32(Above, regT1, Imm32(JSValue::LowestTag)); + + emitLoadDouble(cond, fpRegT0); + emitJumpSlowToHot(branchDoubleZeroOrNaN(fpRegT0, fpRegT1), target); + emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jfalse)); + + notNumber.link(this); + } + JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(cond); stubCall.call(); @@ -895,25 +931,9 @@ void JIT::emit_op_jtrue(Instruction* currentInstruction) emitLoad(cond, regT1, regT0); - Jump isFalse = branch32(Equal, regT1, TrustedImm32(JSValue::FalseTag)); - addJump(branch32(Equal, regT1, TrustedImm32(JSValue::TrueTag)), target); - - Jump isNotInteger = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)); - Jump isFalse2 = branch32(Equal, regT0, TrustedImm32(0)); - addJump(jump(), target); - - if (supportsFloatingPoint()) { - isNotInteger.link(this); - - addSlowCase(branch32(Above, regT1, TrustedImm32(JSValue::LowestTag))); - - emitLoadDouble(cond, fpRegT0); - addJump(branchDoubleNonZero(fpRegT0, fpRegT1), target); - } else - addSlowCase(isNotInteger); - - isFalse.link(this); - isFalse2.link(this); + ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1)); + addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag))); + addJump(branchTest32(NonZero, regT0), target); } void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -922,6 +942,18 @@ void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntr unsigned target = currentInstruction[2].u.operand; linkSlowCase(iter); + + if (supportsFloatingPoint()) { + // regT1 contains the tag from the hot path. + Jump notNumber = branch32(Above, regT1, Imm32(JSValue::LowestTag)); + + emitLoadDouble(cond, fpRegT0); + emitJumpSlowToHot(branchDoubleNonZero(fpRegT0, fpRegT1), target); + emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jtrue)); + + notNumber.link(this); + } + JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(cond); stubCall.call(); @@ -946,8 +978,9 @@ void JIT::emit_op_jeq_null(Instruction* currentInstruction) // Now handle the immediate cases - undefined & null isImmediate.link(this); - ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && !(JSValue::NullTag + 1)); - addJump(branch32(AboveOrEqual, regT1, TrustedImm32(JSValue::UndefinedTag)), target); + ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1)); + or32(TrustedImm32(1), regT1); + addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), target); wasNotImmediate.link(this); } @@ -970,8 +1003,9 @@ void JIT::emit_op_jneq_null(Instruction* currentInstruction) // Now handle the immediate cases - undefined & null isImmediate.link(this); - ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && !(JSValue::NullTag + 1)); - addJump(branch32(Below, regT1, TrustedImm32(JSValue::UndefinedTag)), target); + ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1)); + or32(TrustedImm32(1), regT1); + addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::NullTag)), target); wasNotImmediate.link(this); } @@ -1012,8 +1046,7 @@ void JIT::emit_op_eq(Instruction* currentInstruction) addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag))); addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag))); - set8Compare32(Equal, regT0, regT2, regT0); - or32(TrustedImm32(JSValue::FalseTag), regT0); + set32Compare32(Equal, regT0, regT2, regT0); emitStoreBool(dst, regT0); } @@ -1049,7 +1082,6 @@ void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>: stubCallEq.call(regT0); storeResult.link(this); - or32(TrustedImm32(JSValue::FalseTag), regT0); emitStoreBool(dst, regT0); } @@ -1064,8 +1096,7 @@ void JIT::emit_op_neq(Instruction* currentInstruction) addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag))); addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag))); - set8Compare32(NotEqual, regT0, regT2, regT0); - or32(TrustedImm32(JSValue::FalseTag), regT0); + set32Compare32(NotEqual, regT0, regT2, regT0); emitStoreBool(dst, regT0); } @@ -1100,7 +1131,6 @@ void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry> storeResult.link(this); xor32(TrustedImm32(0x1), regT0); - or32(TrustedImm32(JSValue::FalseTag), regT0); emitStoreBool(dst, regT0); } @@ -1121,11 +1151,9 @@ void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqTy addSlowCase(branch32(AboveOrEqual, regT2, TrustedImm32(JSValue::CellTag))); if (type == OpStrictEq) - set8Compare32(Equal, regT0, regT1, regT0); + set32Compare32(Equal, regT0, regT1, regT0); else - set8Compare32(NotEqual, regT0, regT1, regT0); - - or32(TrustedImm32(JSValue::FalseTag), regT0); + set32Compare32(NotEqual, regT0, regT1, regT0); emitStoreBool(dst, regT0); } @@ -1185,14 +1213,12 @@ void JIT::emit_op_eq_null(Instruction* currentInstruction) isImmediate.link(this); - set8Compare32(Equal, regT1, TrustedImm32(JSValue::NullTag), regT2); - set8Compare32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag), regT1); + set32Compare32(Equal, regT1, TrustedImm32(JSValue::NullTag), regT2); + set32Compare32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag), regT1); or32(regT2, regT1); wasNotImmediate.link(this); - or32(TrustedImm32(JSValue::FalseTag), regT1); - emitStoreBool(dst, regT1); } @@ -1211,14 +1237,12 @@ void JIT::emit_op_neq_null(Instruction* currentInstruction) isImmediate.link(this); - set8Compare32(NotEqual, regT1, TrustedImm32(JSValue::NullTag), regT2); - set8Compare32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag), regT1); + set32Compare32(NotEqual, regT1, TrustedImm32(JSValue::NullTag), regT2); + set32Compare32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag), regT1); and32(regT2, regT1); wasNotImmediate.link(this); - or32(TrustedImm32(JSValue::FalseTag), regT1); - emitStoreBool(dst, regT1); } diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp index 68f8dda..a1f1fe6 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -581,7 +581,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure // ecx = baseObject->m_structure if (!direct) { - for (RefPtr<Structure>* it = chain->head(); *it; ++it) + for (WriteBarrier<Structure>* it = chain->head(); *it; ++it) testPrototype((*it)->storedPrototype(), failureCases); } @@ -606,11 +606,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure restoreReturnAddressBeforeReturn(regT3); } - // Assumes m_refCount can be decremented easily, refcount decrement is safe as - // codeblock should ensure oldStructure->m_refCount > 0 - sub32(TrustedImm32(1), AbsoluteAddress(oldStructure->addressOfCount())); - add32(TrustedImm32(1), AbsoluteAddress(newStructure->addressOfCount())); - storePtr(TrustedImmPtr(newStructure), Address(regT0, JSCell::structureOffset())); + storePtrWithWriteBarrier(TrustedImmPtr(newStructure), regT0, Address(regT0, JSCell::structureOffset())); // write the value compilePutDirectOffset(regT0, regT1, newStructure, cachedOffset); @@ -652,17 +648,15 @@ void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, St repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset), offset); } -void JIT::patchMethodCallProto(CodeBlock* codeBlock, MethodCallLinkInfo& methodCallLinkInfo, JSFunction* callee, Structure* structure, JSObject* proto, ReturnAddressPtr returnAddress) +void JIT::patchMethodCallProto(JSGlobalData& globalData, CodeBlock* codeBlock, MethodCallLinkInfo& methodCallLinkInfo, JSFunction* callee, Structure* structure, JSObject* proto, ReturnAddressPtr returnAddress) { RepatchBuffer repatchBuffer(codeBlock); ASSERT(!methodCallLinkInfo.cachedStructure); - methodCallLinkInfo.cachedStructure = structure; - structure->ref(); + methodCallLinkInfo.cachedStructure.set(globalData, codeBlock->ownerExecutable(), structure); Structure* prototypeStructure = proto->structure(); - methodCallLinkInfo.cachedPrototypeStructure = prototypeStructure; - prototypeStructure->ref(); + methodCallLinkInfo.cachedPrototypeStructure.set(globalData, codeBlock->ownerExecutable(), prototypeStructure); repatchBuffer.repatch(methodCallLinkInfo.structureLabel, structure); repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoObj), proto); @@ -697,7 +691,7 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) // Checks out okay! - get the length from the storage loadPtr(Address(regT0, JSArray::storageOffset()), regT3); load32(Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2); - Jump failureCases2 = branch32(Above, regT2, TrustedImm32(JSImmediate::maxImmediateInt)); + Jump failureCases2 = branch32(LessThan, regT2, TrustedImm32(0)); emitFastArithIntToImmNoCheck(regT2, regT0); Jump success = jump(); @@ -735,7 +729,7 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str Jump failureCases1 = checkStructure(regT0, structure); // Check the prototype object's Structure had not changed. - Structure* const * prototypeStructureAddress = protoObject->addressOfStructure(); + const void* prototypeStructureAddress = protoObject->addressOfStructure(); #if CPU(X86_64) move(TrustedImmPtr(prototypeStructure), regT3); Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3); @@ -839,8 +833,7 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); - structure->ref(); - polymorphicStructures->list[currentIndex].set(entryLabel, structure); + polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), entryLabel, structure); // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); @@ -858,7 +851,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi Jump failureCases1 = checkStructure(regT0, structure); // Check the prototype object's Structure had not changed. - Structure* const * prototypeStructureAddress = protoObject->addressOfStructure(); + const void* prototypeStructureAddress = protoObject->addressOfStructure(); #if CPU(X86_64) move(TrustedImmPtr(prototypeStructure), regT3); Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3); @@ -907,10 +900,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult)); CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); - - structure->ref(); - prototypeStructure->ref(); - prototypeStructures->list[currentIndex].set(entryLabel, structure, prototypeStructure); + prototypeStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), entryLabel, structure, prototypeStructure); // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); @@ -928,7 +918,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi bucketsOfFail.append(baseObjectCheck); Structure* currStructure = structure; - RefPtr<Structure>* it = chain->head(); + WriteBarrier<Structure>* it = chain->head(); JSObject* protoObject = 0; for (unsigned i = 0; i < count; ++i, ++it) { protoObject = asObject(currStructure->prototypeForLookup(callFrame)); @@ -978,7 +968,6 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); // Track the stub we have created so that it will be deleted later. - structure->ref(); prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), entryLabel, structure, chain); // Finally patch the jump to slow case back in the hot path to jump here instead. @@ -997,7 +986,7 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str bucketsOfFail.append(checkStructure(regT0, structure)); Structure* currStructure = structure; - RefPtr<Structure>* it = chain->head(); + WriteBarrier<Structure>* it = chain->head(); JSObject* protoObject = 0; for (unsigned i = 0; i < count; ++i, ++it) { protoObject = asObject(currStructure->prototypeForLookup(callFrame)); diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp index 2a47e5c..d0c3688 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp @@ -475,7 +475,7 @@ void JIT::compileGetByIdSlowCase(int dst, int base, Identifier* ident, Vector<Sl stubCall.addArgument(TrustedImmPtr(ident)); Call call = stubCall.call(dst); - END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdSlowCase); + END_UNINTERRUPTED_SEQUENCE_FOR_PUT(sequenceGetByIdSlowCase, dst); ASSERT_JIT_OFFSET(differenceBetween(coldPathBegin, call), patchOffsetGetByIdSlowCaseCall); @@ -597,7 +597,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure if (!direct) { // Verify that nothing in the prototype chain has a setter for this property. - for (RefPtr<Structure>* it = chain->head(); *it; ++it) + for (WriteBarrier<Structure>* it = chain->head(); *it; ++it) testPrototype((*it)->storedPrototype(), failureCases); } @@ -619,12 +619,10 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure restoreReturnAddressBeforeReturn(regT3); } + + storePtrWithWriteBarrier(TrustedImmPtr(newStructure), regT0, Address(regT0, JSCell::structureOffset())); - sub32(TrustedImm32(1), AbsoluteAddress(oldStructure->addressOfCount())); - add32(TrustedImm32(1), AbsoluteAddress(newStructure->addressOfCount())); - storePtr(TrustedImmPtr(newStructure), Address(regT0, JSCell::structureOffset())); - -#if CPU(MIPS) +#if CPU(MIPS) || CPU(SH4) // For MIPS, we don't add sizeof(void*) to the stack offset. load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT3); load32(Address(stackPointerRegister, OBJECT_OFFSETOF(JITStackFrame, args[2]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT2); @@ -674,17 +672,14 @@ void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, St repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag } -void JIT::patchMethodCallProto(CodeBlock* codeBlock, MethodCallLinkInfo& methodCallLinkInfo, JSFunction* callee, Structure* structure, JSObject* proto, ReturnAddressPtr returnAddress) +void JIT::patchMethodCallProto(JSGlobalData& globalData, CodeBlock* codeBlock, MethodCallLinkInfo& methodCallLinkInfo, JSFunction* callee, Structure* structure, JSObject* proto, ReturnAddressPtr returnAddress) { RepatchBuffer repatchBuffer(codeBlock); ASSERT(!methodCallLinkInfo.cachedStructure); - methodCallLinkInfo.cachedStructure = structure; - structure->ref(); - + methodCallLinkInfo.cachedStructure.set(globalData, codeBlock->ownerExecutable(), structure); Structure* prototypeStructure = proto->structure(); - methodCallLinkInfo.cachedPrototypeStructure = prototypeStructure; - prototypeStructure->ref(); + methodCallLinkInfo.cachedPrototypeStructure.set(globalData, codeBlock->ownerExecutable(), prototypeStructure); repatchBuffer.repatch(methodCallLinkInfo.structureLabel, structure); repatchBuffer.repatch(methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoObj), proto); @@ -762,7 +757,7 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str Jump failureCases1 = checkStructure(regT0, structure); // Check the prototype object's Structure had not changed. - Structure* const * prototypeStructureAddress = protoObject->addressOfStructure(); + const void* prototypeStructureAddress = protoObject->addressOfStructure(); #if CPU(X86_64) move(TrustedImmPtr(prototypeStructure), regT3); Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3); @@ -867,9 +862,8 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult)); CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); - - structure->ref(); - polymorphicStructures->list[currentIndex].set(entryLabel, structure); + + polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), entryLabel, structure); // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); @@ -889,7 +883,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi Jump failureCases1 = checkStructure(regT0, structure); // Check the prototype object's Structure had not changed. - Structure* const * prototypeStructureAddress = protoObject->addressOfStructure(); + const void* prototypeStructureAddress = protoObject->addressOfStructure(); #if CPU(X86_64) move(TrustedImmPtr(prototypeStructure), regT3); Jump failureCases2 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3); @@ -935,10 +929,8 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult)); CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); - - structure->ref(); - prototypeStructure->ref(); - prototypeStructures->list[currentIndex].set(entryLabel, structure, prototypeStructure); + + prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), entryLabel, structure, prototypeStructure); // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); @@ -957,7 +949,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi bucketsOfFail.append(checkStructure(regT0, structure)); Structure* currStructure = structure; - RefPtr<Structure>* it = chain->head(); + WriteBarrier<Structure>* it = chain->head(); JSObject* protoObject = 0; for (unsigned i = 0; i < count; ++i, ++it) { protoObject = asObject(currStructure->prototypeForLookup(callFrame)); @@ -1006,7 +998,6 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); // Track the stub we have created so that it will be deleted later. - structure->ref(); prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), entryLabel, structure, chain); // Finally patch the jump to slow case back in the hot path to jump here instead. @@ -1026,7 +1017,7 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str bucketsOfFail.append(checkStructure(regT0, structure)); Structure* currStructure = structure; - RefPtr<Structure>* it = chain->head(); + WriteBarrier<Structure>* it = chain->head(); JSObject* protoObject = 0; for (unsigned i = 0; i < count; ++i, ++it) { protoObject = asObject(currStructure->prototypeForLookup(callFrame)); diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index e52c7c8..953bd11 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -40,7 +40,7 @@ #include "Debugger.h" #include "ExceptionHelpers.h" #include "GetterSetter.h" -#include "Global.h" +#include "Strong.h" #include "JIT.h" #include "JSActivation.h" #include "JSArray.h" @@ -67,7 +67,7 @@ using namespace std; namespace JSC { -#if OS(DARWIN) || OS(WINDOWS) +#if OS(DARWIN) || (OS(WINDOWS) && CPU(X86)) #define SYMBOL_STRING(name) "_" #name #else #define SYMBOL_STRING(name) #name @@ -81,7 +81,7 @@ namespace JSC { #if (OS(LINUX) || OS(FREEBSD)) && CPU(X86_64) #define SYMBOL_STRING_RELOCATION(name) #name "@plt" -#elif OS(DARWIN) +#elif OS(DARWIN) || (CPU(X86_64) && COMPILER(MINGW) && !GCC_VERSION_AT_LEAST(4, 5, 0)) #define SYMBOL_STRING_RELOCATION(name) "_" #name #elif CPU(X86) && COMPILER(MINGW) #define SYMBOL_STRING_RELOCATION(name) "@" #name "@4" @@ -314,7 +314,79 @@ extern "C" { #define ENABLE_PROFILER_REFERENCE_OFFSET 96 #define GLOBAL_DATA_OFFSET 100 #define STACK_LENGTH 104 +#elif CPU(SH4) +#define SYMBOL_STRING(name) #name +/* code (r4), RegisterFile* (r5), CallFrame* (r6), JSValue* exception (r7), Profiler**(sp), JSGlobalData (sp)*/ +asm volatile ( +".text\n" +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" +SYMBOL_STRING(ctiTrampoline) ":" "\n" + "mov.l r7, @-r15" "\n" + "mov.l r6, @-r15" "\n" + "mov.l r5, @-r15" "\n" + "mov.l r8, @-r15" "\n" + "mov #127, r8" "\n" + "mov.l r14, @-r15" "\n" + "sts.l pr, @-r15" "\n" + "mov.l r13, @-r15" "\n" + "mov.l r11, @-r15" "\n" + "mov.l r10, @-r15" "\n" + "add #-60, r15" "\n" + "mov r6, r14" "\n" + "jsr @r4" "\n" + "nop" "\n" + "add #60, r15" "\n" + "mov.l @r15+,r10" "\n" + "mov.l @r15+,r11" "\n" + "mov.l @r15+,r13" "\n" + "lds.l @r15+,pr" "\n" + "mov.l @r15+,r14" "\n" + "mov.l @r15+,r8" "\n" + "add #12, r15" "\n" + "rts" "\n" + "nop" "\n" +); + +asm volatile ( +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" +SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" + "mov.l .L2"SYMBOL_STRING(cti_vm_throw)",r0" "\n" + "mov r15, r4" "\n" + "mov.l @(r0,r12),r11" "\n" + "jsr @r11" "\n" + "nop" "\n" + "add #60, r15" "\n" + "mov.l @r15+,r10" "\n" + "mov.l @r15+,r11" "\n" + "mov.l @r15+,r13" "\n" + "lds.l @r15+,pr" "\n" + "mov.l @r15+,r14" "\n" + "mov.l @r15+,r8" "\n" + "add #12, r15" "\n" + "rts" "\n" + "nop" "\n" + ".align 2" "\n" + ".L2"SYMBOL_STRING(cti_vm_throw)":.long " SYMBOL_STRING(cti_vm_throw)"@GOT \n" +); + +asm volatile ( +".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" + "add #60, r15" "\n" + "mov.l @r15+,r10" "\n" + "mov.l @r15+,r11" "\n" + "mov.l @r15+,r13" "\n" + "lds.l @r15+,pr" "\n" + "mov.l @r15+,r14" "\n" + "mov.l @r15+,r8" "\n" + "add #12, r15" "\n" + "rts" "\n" + "nop" "\n" +); #else #error "JIT not supported on this platform." #endif @@ -771,12 +843,12 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co normalizePrototypeChain(callFrame, baseCell); StructureChain* prototypeChain = structure->prototypeChain(callFrame); - stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); + stubInfo->initPutByIdTransition(callFrame->globalData(), codeBlock->ownerExecutable(), structure->previousID(), structure, prototypeChain); JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); return; } - stubInfo->initPutByIdReplace(structure); + stubInfo->initPutByIdReplace(callFrame->globalData(), codeBlock->ownerExecutable(), structure); JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct); } @@ -824,7 +896,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co if (slot.slotBase() == baseValue) { // set this up, so derefStructures can do it's job. - stubInfo->initGetByIdSelf(structure); + stubInfo->initGetByIdSelf(callFrame->globalData(), codeBlock->ownerExecutable(), structure); if (slot.cachedPropertyType() != PropertySlot::Value) ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail)); else @@ -847,10 +919,10 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co // should not be treated as a dictionary. if (slotBaseObject->structure()->isDictionary()) { slotBaseObject->flattenDictionaryObject(callFrame->globalData()); - offset = slotBaseObject->structure()->get(propertyName); + offset = slotBaseObject->structure()->get(callFrame->globalData(), propertyName); } - stubInfo->initGetByIdProto(structure, slotBaseObject->structure()); + stubInfo->initGetByIdProto(callFrame->globalData(), codeBlock->ownerExecutable(), structure, slotBaseObject->structure()); ASSERT(!structure->isDictionary()); ASSERT(!slotBaseObject->structure()->isDictionary()); @@ -866,7 +938,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co } StructureChain* prototypeChain = structure->prototypeChain(callFrame); - stubInfo->initGetByIdChain(structure, prototypeChain); + stubInfo->initGetByIdChain(callFrame->globalData(), codeBlock->ownerExecutable(), structure, prototypeChain); JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); } @@ -1156,6 +1228,29 @@ MSVC() MSVC_END( END) */ +#elif CPU(SH4) +#define DEFINE_STUB_FUNCTION(rtype, op) \ + extern "C" { \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ + }; \ + asm volatile( \ + ".align 2" "\n" \ + ".globl " SYMBOL_STRING(cti_##op) "\n" \ + SYMBOL_STRING(cti_##op) ":" "\n" \ + "sts pr, r11" "\n" \ + "mov.l r11, @(0x38, r15)" "\n" \ + "mov.l .L2"SYMBOL_STRING(JITStubThunked_##op)",r0" "\n" \ + "mov.l @(r0,r12),r11" "\n" \ + "jsr @r11" "\n" \ + "nop" "\n" \ + "mov.l @(0x38, r15), r11 " "\n" \ + "lds r11, pr " "\n" \ + "rts" "\n" \ + "nop" "\n" \ + ".align 2" "\n" \ + ".L2"SYMBOL_STRING(JITStubThunked_##op)":.long " SYMBOL_STRING(JITStubThunked_##op)"@GOT \n" \ + ); \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) #else #define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION) #endif @@ -1465,7 +1560,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) // Check to see if the function is on the object's prototype. Patch up the code to optimize. if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { - JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS); + JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS); return JSValue::encode(result); } @@ -1476,7 +1571,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) // for now. For now it performs a check on a special object on the global object only used for this // purpose. The object is in no way exposed, and as such the check will always pass. if (slot.slotBase() == baseValue) { - JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject->methodCallDummy(), STUB_RETURN_ADDRESS); + JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject->methodCallDummy(), STUB_RETURN_ADDRESS); return JSValue::encode(result); } } @@ -1535,7 +1630,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) if (stubInfo->accessType == access_get_by_id_self) { ASSERT(!stubInfo->stubRoutine); - polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure); + polymorphicStructureList = new PolymorphicAccessStructureList(callFrame->globalData(), codeBlock->ownerExecutable(), CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure.get()); stubInfo->initGetByIdSelfList(polymorphicStructureList, 1); } else { polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList; @@ -1560,12 +1655,12 @@ static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(JSG switch (stubInfo->accessType) { case access_get_by_id_proto: - prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure); + prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure.get(), stubInfo->u.getByIdProto.prototypeStructure.get()); stubInfo->stubRoutine = CodeLocationLabel(); stubInfo->initGetByIdProtoList(prototypeStructureList, 2); break; case access_get_by_id_chain: - prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain); + prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure.get(), stubInfo->u.getByIdChain.chain.get()); stubInfo->stubRoutine = CodeLocationLabel(); stubInfo->initGetByIdProtoList(prototypeStructureList, 2); break; @@ -1649,7 +1744,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) // should not be treated as a dictionary. if (slotBaseObject->structure()->isDictionary()) { slotBaseObject->flattenDictionaryObject(callFrame->globalData()); - offset = slotBaseObject->structure()->get(propertyName); + offset = slotBaseObject->structure()->get(callFrame->globalData(), propertyName); } int listIndex; @@ -2658,10 +2753,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global) JSValue result = slot.getValue(callFrame, ident); if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { GlobalResolveInfo& globalResolveInfo = codeBlock->globalResolveInfo(globalResolveInfoIndex); - if (globalResolveInfo.structure) - globalResolveInfo.structure->deref(); - globalObject->structure()->ref(); - globalResolveInfo.structure = globalObject->structure(); + globalResolveInfo.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure()); globalResolveInfo.offset = slot.cachedOffset(); return JSValue::encode(result); } @@ -3495,7 +3587,7 @@ MacroAssemblerCodePtr JITThunks::ctiStub(JSGlobalData* globalData, ThunkGenerato NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function) { - std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Global<NativeExecutable>(Global<NativeExecutable>::EmptyValue)); + std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Strong<NativeExecutable>()); if (entry.second) entry.first->second.set(*globalData, NativeExecutable::create(*globalData, JIT::compileCTINativeCall(globalData, m_executablePool, function), function, ctiNativeConstruct(), callHostFunctionAsConstructor)); return entry.first->second.get(); @@ -3503,7 +3595,7 @@ NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFu NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator) { - std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Global<NativeExecutable>(Global<NativeExecutable>::EmptyValue)); + std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Strong<NativeExecutable>()); if (entry.second) { MacroAssemblerCodePtr code = globalData->canUseJIT() ? generator(globalData, m_executablePool.get()) : MacroAssemblerCodePtr(); entry.first->second.set(*globalData, NativeExecutable::create(*globalData, code, function, ctiNativeConstruct(), callHostFunctionAsConstructor)); diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h index af6e13f..7c67f6e 100644 --- a/Source/JavaScriptCore/jit/JITStubs.h +++ b/Source/JavaScriptCore/jit/JITStubs.h @@ -229,6 +229,27 @@ namespace JSC { ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; } }; +#elif CPU(SH4) + struct JITStackFrame { + JITStubArg padding; // Unused + JITStubArg args[6]; + + ReturnAddressPtr thunkReturnAddress; + void* savedR10; + void* savedR11; + void* savedR13; + void* savedRPR; + void* savedR14; + void* savedTimeoutReg; + + RegisterFile* registerFile; + CallFrame* callFrame; + JSValue* exception; + Profiler** enabledProfilerReference; + JSGlobalData* globalData; + + ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; } + }; #else #error "JITStackFrame not defined for this platform." #endif @@ -254,7 +275,7 @@ namespace JSC { extern "C" void ctiOpThrowNotCaught(); extern "C" EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*); - template <typename T> class Global; + template <typename T> class Strong; class JITThunks { public: @@ -283,7 +304,7 @@ namespace JSC { private: typedef HashMap<ThunkGenerator, MacroAssemblerCodePtr> CTIStubMap; CTIStubMap m_ctiStubMap; - typedef HashMap<NativeFunction, Global<NativeExecutable> > HostFunctionStubMap; + typedef HashMap<NativeFunction, Strong<NativeExecutable> > HostFunctionStubMap; OwnPtr<HostFunctionStubMap> m_hostFunctionStubMap; RefPtr<ExecutablePool> m_executablePool; diff --git a/Source/JavaScriptCore/jit/JSInterfaceJIT.h b/Source/JavaScriptCore/jit/JSInterfaceJIT.h index 5d3f239..e1d9353 100644 --- a/Source/JavaScriptCore/jit/JSInterfaceJIT.h +++ b/Source/JavaScriptCore/jit/JSInterfaceJIT.h @@ -28,7 +28,6 @@ #include "JITCode.h" #include "JITStubs.h" -#include "JSImmediate.h" #include "JSValue.h" #include "MacroAssembler.h" #include "RegisterFile.h" @@ -154,21 +153,51 @@ namespace JSC { static const FPRegisterID fpRegT1 = MIPSRegisters::f6; static const FPRegisterID fpRegT2 = MIPSRegisters::f8; static const FPRegisterID fpRegT3 = MIPSRegisters::f10; +#elif CPU(SH4) + static const RegisterID timeoutCheckRegister = SH4Registers::r8; + static const RegisterID callFrameRegister = SH4Registers::fp; + + static const RegisterID regT0 = SH4Registers::r0; + static const RegisterID regT1 = SH4Registers::r1; + static const RegisterID regT2 = SH4Registers::r2; + static const RegisterID regT3 = SH4Registers::r10; + static const RegisterID regT4 = SH4Registers::r4; + static const RegisterID regT5 = SH4Registers::r5; + static const RegisterID regT6 = SH4Registers::r6; + static const RegisterID regT7 = SH4Registers::r7; + static const RegisterID firstArgumentRegister =regT4; + + static const RegisterID returnValueRegister = SH4Registers::r0; + static const RegisterID cachedResultRegister = SH4Registers::r0; + + static const FPRegisterID fpRegT0 = SH4Registers::fr0; + static const FPRegisterID fpRegT1 = SH4Registers::fr2; + static const FPRegisterID fpRegT2 = SH4Registers::fr4; + static const FPRegisterID fpRegT3 = SH4Registers::fr6; + static const FPRegisterID fpRegT4 = SH4Registers::fr8; + static const FPRegisterID fpRegT5 = SH4Registers::fr10; + static const FPRegisterID fpRegT6 = SH4Registers::fr12; + static const FPRegisterID fpRegT7 = SH4Registers::fr14; #else #error "JIT not supported on this platform." #endif #if USE(JSVALUE32_64) // Can't just propogate JSValue::Int32Tag as visual studio doesn't like it - static const unsigned Int32Tag = 0xfffffffd; + static const unsigned Int32Tag = 0xffffffff; COMPILE_ASSERT(Int32Tag == JSValue::Int32Tag, Int32Tag_out_of_sync); #else - static const unsigned Int32Tag = JSImmediate::TagTypeNumber >> 32; + static const unsigned Int32Tag = TagTypeNumber >> 32; #endif inline Jump emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload); inline Jump emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst); inline Jump emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch); + inline void storePtrWithWriteBarrier(TrustedImmPtr ptr, RegisterID /* owner */, Address dest) + { + storePtr(ptr, dest); + } + #if USE(JSVALUE32_64) inline Jump emitJumpIfNotJSCell(unsigned virtualRegisterIndex); inline Address tagFor(int index, RegisterID base = callFrameRegister); |