summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-10-17 16:21:14 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2012-10-17 16:21:14 +0200
commit8995b83bcbfbb68245f779b64e5517627c6cc6ea (patch)
tree17985605dab9263cc2444bd4d45f189e142cca7c /Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
parentb9c9652036d5e9f1e29c574f40bc73a35c81ace6 (diff)
downloadqtwebkit-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.cpp560
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;