diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-17 16:21:14 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-17 16:21:14 +0200 |
commit | 8995b83bcbfbb68245f779b64e5517627c6cc6ea (patch) | |
tree | 17985605dab9263cc2444bd4d45f189e142cca7c /Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp | |
parent | b9c9652036d5e9f1e29c574f40bc73a35c81ace6 (diff) | |
download | qtwebkit-8995b83bcbfbb68245f779b64e5517627c6cc6ea.tar.gz |
Imported WebKit commit cf4f8fc6f19b0629f51860cb2d4b25e139d07e00 (http://svn.webkit.org/repository/webkit/trunk@131592)
New snapshot that includes the build fixes for Mac OS X 10.6 and earlier as well
as the previously cherry-picked changes
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp | 560 |
1 files changed, 444 insertions, 116 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index d7cec27c1..0928dfa58 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -29,6 +29,7 @@ #if ENABLE(DFG_JIT) #include "Arguments.h" +#include "DFGCallArrayAllocatorSlowPathGenerator.h" #include "DFGSlowPathGenerator.h" namespace JSC { namespace DFG { @@ -72,7 +73,7 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat } // Since we statically know that we're filling an integer, and values - // in the RegisterFile are boxed, this must be DataFormatJSInteger. + // in the JSStack are boxed, this must be DataFormatJSInteger. // We will check this with a jitAssert below. info.fillJSValue(*m_stream, gpr, DataFormatJSInteger); unlock(gpr); @@ -1005,9 +1006,9 @@ void SpeculativeJIT::emitCall(Node& node) // arguments. int numPassedArgs = node.numChildren() - 1; - m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs + dummyThisArgument), callFramePayloadSlot(RegisterFile::ArgumentCount)); - m_jit.storePtr(GPRInfo::callFrameRegister, callFrameSlot(RegisterFile::CallerFrame)); - m_jit.storePtr(calleeGPR, callFrameSlot(RegisterFile::Callee)); + m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs + dummyThisArgument), callFramePayloadSlot(JSStack::ArgumentCount)); + m_jit.storePtr(GPRInfo::callFrameRegister, callFrameSlot(JSStack::CallerFrame)); + m_jit.storePtr(calleeGPR, callFrameSlot(JSStack::Callee)); for (int i = 0; i < numPassedArgs; i++) { Edge argEdge = m_jit.graph().m_varArgChildren[node.firstChild() + 1 + i]; @@ -1033,7 +1034,7 @@ void SpeculativeJIT::emitCall(Node& node) slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(JSValue::encode(JSValue()))); m_jit.loadPtr(MacroAssembler::Address(calleeGPR, OBJECT_OFFSETOF(JSFunction, m_scope)), resultGPR); - m_jit.storePtr(resultGPR, MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain)); + m_jit.storePtr(resultGPR, MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * JSStack::ScopeChain)); CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin; JITCompiler::Call fastCall = m_jit.nearCall(); @@ -2109,10 +2110,111 @@ void SpeculativeJIT::emitBranch(Node& node) } } +MacroAssembler::JumpList SpeculativeJIT::compileContiguousGetByVal(Node&, GPRReg, GPRReg propertyReg, GPRReg storageReg, GPRReg resultReg) +{ + MacroAssembler::JumpList slowCases; + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); + + m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr), resultReg); + slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultReg)); + + return slowCases; +} + +MacroAssembler::JumpList SpeculativeJIT::compileArrayStorageGetByVal(Node&, GPRReg, GPRReg propertyReg, GPRReg storageReg, GPRReg resultReg) +{ + MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())); + + m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), resultReg); + MacroAssembler::Jump hole = m_jit.branchTestPtr(MacroAssembler::Zero, resultReg); + + MacroAssembler::JumpList slowCases; + slowCases.append(outOfBounds); + slowCases.append(hole); + return slowCases; +} + +MacroAssembler::JumpList SpeculativeJIT::compileContiguousPutByVal(Node& node, GPRReg, GPRReg propertyReg, GPRReg storageReg, GPRReg valueReg, GPRReg tempReg) +{ + Array::Mode arrayMode = node.arrayMode(); + + MacroAssembler::JumpList slowCases; + + if (!mayStoreToTail(arrayMode)) { + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); + } else { + MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())); + + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength()))); + + if (isInBoundsAccess(arrayMode)) + speculationCheck(Uncountable, JSValueRegs(), NoNode, slowCases); + + m_jit.add32(TrustedImm32(1), propertyReg, tempReg); + m_jit.store32(tempReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())); + + inBounds.link(&m_jit); + } + + m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr)); + + if (isInBoundsAccess(arrayMode)) + return MacroAssembler::JumpList(); + return slowCases; +} + +MacroAssembler::JumpList SpeculativeJIT::compileArrayStoragePutByVal(Node& node, GPRReg, GPRReg propertyReg, GPRReg storageReg, GPRReg valueReg, GPRReg tempReg) +{ + Array::Mode arrayMode = node.arrayMode(); + + MacroAssembler::JumpList slowCases; + + MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())); + if (isInBoundsAccess(arrayMode)) + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); + else + slowCases.append(beyondArrayBounds); + + // Check if we're writing to a hole; if so increment m_numValuesInVector. + if (!mayStoreToHole(arrayMode)) { + // This is uncountable because if we take this exit, then the baseline JIT + // will immediately count the hole store. So there is no need for exit + // profiling. + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branchTestPtr(MacroAssembler::Zero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])))); + } else { + MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + if (isSlowPutAccess(arrayMode)) { + // This is sort of strange. If we wanted to optimize this code path, we would invert + // the above branch. But it's simply not worth it since this only happens if we're + // already having a bad time. + slowCases.append(m_jit.jump()); + } else { + m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, ArrayStorage::numValuesInVectorOffset())); + + // If we're writing to a hole we might be growing the array; + MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset())); + m_jit.add32(TrustedImm32(1), propertyReg, tempReg); + m_jit.store32(tempReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset())); + + lengthDoesNotNeedUpdate.link(&m_jit); + } + notHoleValue.link(&m_jit); + } + + // Store the value to the array. + m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + + return slowCases; +} + void SpeculativeJIT::compile(Node& node) { NodeType op = node.op(); - + switch (op) { case JSConstant: initConstantInfo(m_compileIndex); @@ -2202,7 +2304,7 @@ void SpeculativeJIT::compile(Node& node) // SetLocal doubles as a hint as to where a node will be stored and // as a speculation point. So before we speculate make sure that we // know where the child of this node needs to go in the virtual - // register file. + // stack. compileMovHint(node); // As far as OSR is concerned, we're on the bytecode index corresponding @@ -2231,7 +2333,7 @@ void SpeculativeJIT::compile(Node& node) // this SetLocal should not have executed. But for op_post_inc, it's just // fine, because this SetLocal's local (i.e. the LHS in a x = y++ // statement) would be dead anyway - so the fact that DFG would have - // already made the assignment, and baked it into the register file during + // already made the assignment, and baked it into the stack during // OSR exit, would not be visible to the old JIT in any way. m_codeOriginForOSR = nextNode->codeOrigin; @@ -2241,9 +2343,9 @@ void SpeculativeJIT::compile(Node& node) m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); // Indicate that it's no longer necessary to retrieve the value of - // this bytecode variable from registers or other locations in the register file, + // this bytecode variable from registers or other locations in the stack, // but that it is stored as a double. - recordSetLocal(node.local(), ValueSource(DoubleInRegisterFile)); + recordSetLocal(node.local(), ValueSource(DoubleInJSStack)); break; } @@ -2252,7 +2354,7 @@ void SpeculativeJIT::compile(Node& node) SpeculateIntegerOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); - recordSetLocal(node.local(), ValueSource(Int32InRegisterFile)); + recordSetLocal(node.local(), ValueSource(Int32InJSStack)); break; } if (isCellSpeculation(predictedType)) { @@ -2260,14 +2362,14 @@ void SpeculativeJIT::compile(Node& node) GPRReg cellGPR = cell.gpr(); m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local())); noResult(m_compileIndex); - recordSetLocal(node.local(), ValueSource(CellInRegisterFile)); + recordSetLocal(node.local(), ValueSource(CellInJSStack)); break; } if (isBooleanSpeculation(predictedType)) { SpeculateBooleanOperand boolean(this, node.child1()); m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); - recordSetLocal(node.local(), ValueSource(BooleanInRegisterFile)); + recordSetLocal(node.local(), ValueSource(BooleanInJSStack)); break; } } @@ -2276,7 +2378,7 @@ void SpeculativeJIT::compile(Node& node) m_jit.storePtr(value.gpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); - recordSetLocal(node.local(), ValueSource(ValueInRegisterFile)); + recordSetLocal(node.local(), ValueSource(ValueInJSStack)); // If we're storing an arguments object that has been optimized away, // our variable event stream for OSR exit now reflects the optimized @@ -2595,6 +2697,51 @@ void SpeculativeJIT::compile(Node& node) jsValueResult(result.gpr(), m_compileIndex); break; } + case IN_BOUNDS_CONTIGUOUS_MODES: { + SpeculateStrictInt32Operand property(this, node.child2()); + StorageOperand storage(this, node.child3()); + + GPRReg propertyReg = property.gpr(); + GPRReg storageReg = storage.gpr(); + + if (!m_compileOkay) + return; + + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); + + GPRTemporary result(this); + m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr), result.gpr()); + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr())); + jsValueResult(result.gpr(), m_compileIndex); + break; + } + case CONTIGUOUS_TO_TAIL_MODES: + case OUT_OF_BOUNDS_CONTIGUOUS_MODES: + case ALL_EFFECTFUL_CONTIGUOUS_MODES: { + SpeculateCellOperand base(this, node.child1()); + SpeculateStrictInt32Operand property(this, node.child2()); + StorageOperand storage(this, node.child3()); + + GPRReg baseReg = base.gpr(); + GPRReg propertyReg = property.gpr(); + GPRReg storageReg = storage.gpr(); + + if (!m_compileOkay) + return; + + GPRTemporary result(this); + GPRReg resultReg = result.gpr(); + + MacroAssembler::JumpList slowCases = + compileContiguousGetByVal(node, baseReg, propertyReg, storageReg, resultReg); + addSlowPathGenerator( + slowPathCall( + slowCases, this, operationGetByValArrayInt, + result.gpr(), baseReg, propertyReg)); + + jsValueResult(resultReg, m_compileIndex); + break; + } case IN_BOUNDS_ARRAY_STORAGE_MODES: { SpeculateStrictInt32Operand property(this, node.child2()); StorageOperand storage(this, node.child3()); @@ -2615,6 +2762,7 @@ void SpeculativeJIT::compile(Node& node) break; } case OUT_OF_BOUNDS_ARRAY_STORAGE_MODES: + case SLOW_PUT_ARRAY_STORAGE_MODES: case ALL_EFFECTFUL_ARRAY_STORAGE_MODES: { SpeculateCellOperand base(this, node.child1()); SpeculateStrictInt32Operand property(this, node.child2()); @@ -2627,21 +2775,17 @@ void SpeculativeJIT::compile(Node& node) if (!m_compileOkay) return; - MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())); - GPRTemporary result(this); - m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr()); - MacroAssembler::Jump hole = m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr()); - - MacroAssembler::JumpList slowCases; - slowCases.append(outOfBounds); - slowCases.append(hole); + GPRReg resultReg = result.gpr(); + + MacroAssembler::JumpList slowCases = + compileArrayStorageGetByVal(node, baseReg, propertyReg, storageReg, resultReg); addSlowPathGenerator( slowPathCall( slowCases, this, operationGetByValArrayInt, result.gpr(), baseReg, propertyReg)); - jsValueResult(result.gpr(), m_compileIndex); + jsValueResult(resultReg, m_compileIndex); break; } case Array::String: @@ -2735,8 +2879,8 @@ void SpeculativeJIT::compile(Node& node) GPRReg propertyReg = property.gpr(); switch (arrayMode) { - case ALL_ARRAY_STORAGE_MODES: - case ALL_EFFECTFUL_ARRAY_STORAGE_MODES: { + case ALL_CONTIGUOUS_MODES: + case ALL_EFFECTFUL_CONTIGUOUS_MODES: { JSValueOperand value(this, child3); GPRReg valueReg = value.gpr(); @@ -2756,59 +2900,76 @@ void SpeculativeJIT::compile(Node& node) // Store the value to the array. GPRReg propertyReg = property.gpr(); GPRReg valueReg = value.gpr(); - m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr)); noResult(m_compileIndex); break; } - MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())); - if (isInBoundsAccess(arrayMode)) - speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); - - // Check if we're writing to a hole; if so increment m_numValuesInVector. - MacroAssembler::Jump isHoleValue; - if (!mayStoreToHole(arrayMode)) { - // This is uncountable because if we take this exit, then the baseline JIT - // will immediately count the hole store. So there is no need for exit - // profiling. - speculationCheck( - Uncountable, JSValueRegs(), NoNode, - m_jit.branchTestPtr(MacroAssembler::Zero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])))); - } else { - MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - if (isSlowPutAccess(arrayMode)) { - // This is sort of strange. If we wanted to optimize this code path, we would invert - // the above branch. But it's simply not worth it since this only happens if we're - // already having a bad time. - isHoleValue = m_jit.jump(); - } else { - m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); - - // If we're writing to a hole we might be growing the array; - MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset())); - m_jit.add32(TrustedImm32(1), propertyReg); - m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset())); - m_jit.sub32(TrustedImm32(1), propertyReg); + GPRTemporary temporary; + GPRReg temporaryReg = temporaryRegisterForPutByVal(temporary, node); + + MacroAssembler::JumpList slowCases = + compileContiguousPutByVal( + node, baseReg, propertyReg, storageReg, valueReg, temporaryReg); + + base.use(); + property.use(); + value.use(); + storage.use(); + + if (!slowCases.empty()) { + addSlowPathGenerator( + slowPathCall( + slowCases, this, + m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, + NoResult, baseReg, propertyReg, valueReg)); + } + + noResult(m_compileIndex, UseChildrenCalledExplicitly); + break; + } + + case ALL_ARRAY_STORAGE_MODES: + case ALL_EFFECTFUL_ARRAY_STORAGE_MODES: { + JSValueOperand value(this, child3); + + GPRReg valueReg = value.gpr(); + + if (!m_compileOkay) + return; + + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratch.gpr()); + } + + StorageOperand storage(this, child4); + GPRReg storageReg = storage.gpr(); + + if (node.op() == PutByValAlias) { + // Store the value to the array. + GPRReg propertyReg = property.gpr(); + GPRReg valueReg = value.gpr(); + m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - lengthDoesNotNeedUpdate.link(&m_jit); - } - notHoleValue.link(&m_jit); + noResult(m_compileIndex); + break; } + GPRTemporary temporary; + GPRReg temporaryReg = temporaryRegisterForPutByVal(temporary, node); + + MacroAssembler::JumpList slowCases = + compileArrayStoragePutByVal( + node, baseReg, propertyReg, storageReg, valueReg, temporaryReg); + base.use(); property.use(); value.use(); storage.use(); - - // Store the value to the array. - m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - - if (!isInBoundsAccess(arrayMode)) { - MacroAssembler::JumpList slowCases; - slowCases.append(beyondArrayBounds); - if (isSlowPutAccess(arrayMode)) - slowCases.append(isHoleValue); + + if (!slowCases.empty()) { addSlowPathGenerator( slowPathCall( slowCases, this, @@ -2973,26 +3134,54 @@ void SpeculativeJIT::compile(Node& node) StorageOperand storage(this, node.child3()); GPRReg storageGPR = storage.gpr(); - m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR); + switch (node.arrayMode()) { + case Array::ArrayWithContiguous: + case Array::ArrayWithContiguousOutOfBounds: { + m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR); + MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); + m_jit.storePtr(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr)); + m_jit.add32(TrustedImm32(1), storageLengthGPR); + m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); + m_jit.orPtr(GPRInfo::tagTypeNumberRegister, storageLengthGPR); + + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationArrayPush, NoResult, storageLengthGPR, + valueGPR, baseGPR)); - // Refuse to handle bizarre lengths. - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe))); + jsValueResult(storageLengthGPR, m_compileIndex); + break; + } + + case Array::ArrayWithArrayStorage: + case Array::ArrayWithArrayStorageOutOfBounds: { + m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR); - MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset())); + // Refuse to handle bizarre lengths. + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe))); - m_jit.storePtr(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset())); - m_jit.add32(TrustedImm32(1), storageLengthGPR); - m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset())); - m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); - m_jit.orPtr(GPRInfo::tagTypeNumberRegister, storageLengthGPR); + m_jit.storePtr(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - addSlowPathGenerator( - slowPathCall( - slowPath, this, operationArrayPush, NoResult, storageLengthGPR, - valueGPR, baseGPR)); + m_jit.add32(TrustedImm32(1), storageLengthGPR); + m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset())); + m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); + m_jit.orPtr(GPRInfo::tagTypeNumberRegister, storageLengthGPR); + + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationArrayPush, NoResult, storageLengthGPR, + valueGPR, baseGPR)); - jsValueResult(storageLengthGPR, m_compileIndex); + jsValueResult(storageLengthGPR, m_compileIndex); + break; + } + + default: + CRASH(); + break; + } break; } @@ -3002,41 +3191,77 @@ void SpeculativeJIT::compile(Node& node) SpeculateCellOperand base(this, node.child1()); StorageOperand storage(this, node.child2()); GPRTemporary value(this); - GPRTemporary storageLength(this); GPRReg baseGPR = base.gpr(); GPRReg storageGPR = storage.gpr(); GPRReg valueGPR = value.gpr(); - GPRReg storageLengthGPR = storageLength.gpr(); - m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR); + switch (node.arrayMode()) { + case Array::ArrayWithContiguous: + case Array::ArrayWithContiguousOutOfBounds: { + m_jit.load32( + MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valueGPR); + MacroAssembler::Jump undefinedCase = + m_jit.branchTest32(MacroAssembler::Zero, valueGPR); + m_jit.sub32(TrustedImm32(1), valueGPR); + m_jit.store32( + valueGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); + m_jit.loadPtr( + MacroAssembler::BaseIndex(storageGPR, valueGPR, MacroAssembler::ScalePtr), + valueGPR); + MacroAssembler::Jump slowCase = m_jit.branchTestPtr(MacroAssembler::Zero, valueGPR); + + addSlowPathGenerator( + slowPathMove( + undefinedCase, this, + MacroAssembler::TrustedImmPtr(JSValue::encode(jsUndefined())), valueGPR)); + addSlowPathGenerator( + slowPathCall( + slowCase, this, operationArrayPopAndRecoverLength, valueGPR, baseGPR)); + + jsValueResult(valueGPR, m_compileIndex); + break; + } + + case Array::ArrayWithArrayStorage: + case Array::ArrayWithArrayStorageOutOfBounds: { + GPRTemporary storageLength(this); + GPRReg storageLengthGPR = storageLength.gpr(); + m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR); - JITCompiler::JumpList setUndefinedCases; - setUndefinedCases.append(m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR)); + JITCompiler::Jump undefinedCase = + m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR); - m_jit.sub32(TrustedImm32(1), storageLengthGPR); + m_jit.sub32(TrustedImm32(1), storageLengthGPR); - MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset())); + JITCompiler::JumpList slowCases; + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()))); - m_jit.loadPtr(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), valueGPR); + m_jit.loadPtr(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), valueGPR); + slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, valueGPR)); - m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset())); - - setUndefinedCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, valueGPR)); + m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset())); - m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - m_jit.sub32(MacroAssembler::TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); + m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + m_jit.sub32(MacroAssembler::TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); - addSlowPathGenerator( - slowPathMove( - setUndefinedCases, this, - MacroAssembler::TrustedImmPtr(JSValue::encode(jsUndefined())), valueGPR)); + addSlowPathGenerator( + slowPathMove( + undefinedCase, this, + MacroAssembler::TrustedImmPtr(JSValue::encode(jsUndefined())), valueGPR)); - addSlowPathGenerator( - slowPathCall( - slowCase, this, operationArrayPop, valueGPR, baseGPR)); + addSlowPathGenerator( + slowPathCall( + slowCases, this, operationArrayPop, valueGPR, baseGPR)); - jsValueResult(valueGPR, m_compileIndex); + jsValueResult(valueGPR, m_compileIndex); + break; + } + + default: + CRASH(); + break; + } break; } @@ -3087,9 +3312,9 @@ void SpeculativeJIT::compile(Node& node) m_jit.move(op1.gpr(), GPRInfo::returnValueGPR); // Grab the return address. - m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, GPRInfo::regT1); + m_jit.emitGetFromCallFrameHeaderPtr(JSStack::ReturnPC, GPRInfo::regT1); // Restore our caller's "r". - m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, GPRInfo::callFrameRegister); + m_jit.emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, GPRInfo::callFrameRegister); // Return. m_jit.restoreReturnAddressBeforeReturn(GPRInfo::regT1); m_jit.ret(); @@ -3151,8 +3376,40 @@ void SpeculativeJIT::compile(Node& node) case NewArray: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - if (!globalObject->isHavingABadTime()) + if (!globalObject->isHavingABadTime()) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); + + ASSERT(hasContiguous(globalObject->arrayStructure()->indexingType())); + + unsigned numElements = node.numChildren(); + + GPRTemporary result(this); + GPRTemporary storage(this); + + GPRReg resultGPR = result.gpr(); + GPRReg storageGPR = storage.gpr(); + + emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements); + + // At this point, one way or another, resultGPR and storageGPR have pointers to + // the JSArray and the Butterfly, respectively. + + for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) { + JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]); + GPRReg opGPR = operand.gpr(); + m_jit.storePtr(opGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx)); + } + + // Yuck, we should *really* have a way of also returning the storageGPR. But + // that's the least of what's wrong with this code. We really shouldn't be + // allocating the array after having computed - and probably spilled to the + // stack - all of the things that will go into the array. The solution to that + // bigger problem will also likely fix the redundancy in reloading the storage + // pointer that we currently have. + + cellResult(resultGPR, m_compileIndex); + break; + } if (!node.numChildren()) { flushRegisters(); @@ -3203,15 +3460,61 @@ void SpeculativeJIT::compile(Node& node) case NewArrayWithSize: { JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); - if (!globalObject->isHavingABadTime()) + if (!globalObject->isHavingABadTime()) { globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); + + SpeculateStrictInt32Operand size(this, node.child1()); + GPRTemporary result(this); + GPRTemporary storage(this); + GPRTemporary scratch(this); + + GPRReg sizeGPR = size.gpr(); + GPRReg resultGPR = result.gpr(); + GPRReg storageGPR = storage.gpr(); + GPRReg scratchGPR = scratch.gpr(); + + MacroAssembler::JumpList slowCases; + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX))); + + ASSERT((1 << 3) == sizeof(JSValue)); + m_jit.move(sizeGPR, scratchGPR); + m_jit.lshift32(TrustedImm32(3), scratchGPR); + m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratchGPR, resultGPR); + slowCases.append( + emitAllocateBasicStorage(resultGPR, storageGPR)); + m_jit.subPtr(scratchGPR, storageGPR); + emitAllocateBasicJSObject<JSArray, MarkedBlock::None>( + TrustedImmPtr(globalObject->arrayStructure()), resultGPR, scratchGPR, + storageGPR, sizeof(JSArray), slowCases); + + m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); + m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); + + addSlowPathGenerator(adoptPtr( + new CallArrayAllocatorWithVariableSizeSlowPathGenerator( + slowCases, this, operationNewArrayWithSize, resultGPR, + globalObject->arrayStructure(), + globalObject->arrayStructureWithArrayStorage(), + sizeGPR))); + + cellResult(resultGPR, m_compileIndex); + break; + } SpeculateStrictInt32Operand size(this, node.child1()); GPRReg sizeGPR = size.gpr(); flushRegisters(); GPRResult result(this); - callOperation(operationNewArrayWithSize, result.gpr(), globalObject->arrayStructure(), sizeGPR); - cellResult(result.gpr(), m_compileIndex); + GPRReg resultGPR = result.gpr(); + GPRReg structureGPR = selectScratchGPR(sizeGPR); + MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)); + m_jit.move(TrustedImmPtr(globalObject->arrayStructure()), structureGPR); + MacroAssembler::Jump done = m_jit.jump(); + bigLength.link(&m_jit); + m_jit.move(TrustedImmPtr(globalObject->arrayStructureWithArrayStorage()), structureGPR); + done.link(&m_jit); + callOperation(operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR); + cellResult(resultGPR, m_compileIndex); break; } @@ -3254,10 +3557,35 @@ void SpeculativeJIT::compile(Node& node) } case NewArrayBuffer: { + JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin); + if (!globalObject->isHavingABadTime()) { + globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint()); + + unsigned numElements = node.numConstants(); + + GPRTemporary result(this); + GPRTemporary storage(this); + + GPRReg resultGPR = result.gpr(); + GPRReg storageGPR = storage.gpr(); + + emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements); + + JSValue* data = m_jit.codeBlock()->constantBuffer(node.startConstant()); + for (unsigned index = 0; index < node.numConstants(); ++index) { + m_jit.storePtr( + ImmPtr(bitwise_cast<void*>(JSValue::encode(data[index]))), + MacroAssembler::Address(storageGPR, sizeof(JSValue) * index)); + } + + cellResult(resultGPR, m_compileIndex); + break; + } + flushRegisters(); GPRResult result(this); - callOperation(operationNewArrayBuffer, result.gpr(), node.startConstant(), node.numConstants()); + callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructure(), node.startConstant(), node.numConstants()); cellResult(result.gpr(), m_compileIndex); break; @@ -3375,7 +3703,7 @@ void SpeculativeJIT::compile(Node& node) case GetCallee: { GPRTemporary result(this); - m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(RegisterFile::Callee)), result.gpr()); + m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(JSStack::Callee)), result.gpr()); cellResult(result.gpr(), m_compileIndex); break; } @@ -3384,7 +3712,7 @@ void SpeculativeJIT::compile(Node& node) GPRTemporary result(this); GPRReg resultGPR = result.gpr(); - m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(RegisterFile::ScopeChain)), resultGPR); + m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(JSStack::ScopeChain)), resultGPR); bool checkTopLevel = m_jit.codeBlock()->codeType() == FunctionCode && m_jit.codeBlock()->needsFullScopeChain(); int skip = node.scopeChainDepth(); ASSERT(skip || !checkTopLevel); @@ -3973,14 +4301,14 @@ void SpeculativeJIT::compile(Node& node) // Fast case m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR); #if DFG_ENABLE(JIT_ASSERT) - JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(inlineStorageCapacity)); + JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(firstOutOfLineOffset)); m_jit.breakpoint(); isOutOfLine.link(&m_jit); #endif m_jit.neg32(resolveInfoGPR); m_jit.signExtend32ToPtr(resolveInfoGPR, resolveInfoGPR); m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::butterflyOffset()), resultGPR); - m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr, (inlineStorageCapacity - 2) * static_cast<ptrdiff_t>(sizeof(JSValue))), resultGPR); + m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr, (firstOutOfLineOffset - 2) * static_cast<ptrdiff_t>(sizeof(JSValue))), resultGPR); addSlowPathGenerator( slowPathCall( @@ -4106,7 +4434,7 @@ void SpeculativeJIT::compile(Node& node) } ASSERT(!node.codeOrigin.inlineCallFrame); - m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR); + m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), resultGPR); m_jit.sub32(TrustedImm32(1), resultGPR); integerResult(resultGPR, m_compileIndex); break; @@ -4129,7 +4457,7 @@ void SpeculativeJIT::compile(Node& node) jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1)))), resultGPR); } else { - m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR); + m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), resultGPR); m_jit.sub32(TrustedImm32(1), resultGPR); m_jit.orPtr(GPRInfo::tagTypeNumberRegister, resultGPR); } @@ -4178,7 +4506,7 @@ void SpeculativeJIT::compile(Node& node) m_jit.branch32( JITCompiler::AboveOrEqual, resultGPR, - JITCompiler::payloadFor(RegisterFile::ArgumentCount))); + JITCompiler::payloadFor(JSStack::ArgumentCount))); } JITCompiler::JumpList slowArgument; @@ -4243,7 +4571,7 @@ void SpeculativeJIT::compile(Node& node) m_jit.branch32( JITCompiler::AboveOrEqual, resultGPR, - JITCompiler::payloadFor(RegisterFile::ArgumentCount))); + JITCompiler::payloadFor(JSStack::ArgumentCount))); } JITCompiler::JumpList slowArgument; |