summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp47
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.cpp32
-rw-r--r--Source/JavaScriptCore/dfg/DFGArrayMode.h23
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp2
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp24
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp49
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp59
-rw-r--r--Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp38
8 files changed, 189 insertions, 85 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index b860a7310..153ba311c 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -147,7 +147,13 @@ void AbstractState::initialize(Graph& graph)
for (size_t i = 0; i < graph.m_mustHandleValues.size(); ++i) {
AbstractValue value;
value.setMostSpecific(graph.m_mustHandleValues[i]);
- block->valuesAtHead.operand(graph.m_mustHandleValues.operandForIndex(i)).merge(value);
+ int operand = graph.m_mustHandleValues.operandForIndex(i);
+ block->valuesAtHead.operand(operand).merge(value);
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog(" Initializing Block #%u, operand r%d, to ", blockIndex, operand);
+ block->valuesAtHead.operand(operand).dump(WTF::dataFile());
+ dataLog("\n");
+#endif
}
block->cfaShouldRevisit = true;
}
@@ -1093,14 +1099,21 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
case NewArray:
- case NewArrayBuffer:
- node.setCanExit(false);
+ node.setCanExit(true);
forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure());
m_haveStructures = true;
break;
+ case NewArrayBuffer:
+ // Unless we're having a bad time, this node can change its mind about what structure
+ // it uses.
+ node.setCanExit(false);
+ forNode(nodeIndex).set(SpecArray);
+ break;
+
case NewArrayWithSize:
- speculateInt32Unary(node);
+ node.setCanExit(true);
+ forNode(node.child1()).filter(SpecInt32);
forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure());
m_haveStructures = true;
break;
@@ -1293,20 +1306,6 @@ bool AbstractState::execute(unsigned indexInBlock)
!value.m_currentKnownStructure.isSubsetOf(set)
|| !isCellSpeculation(value.m_type));
value.filter(set);
- // This is likely to be unnecessary, but it's conservative, and that's a good thing.
- // This is trying to avoid situations where the CFA proves that this structure check
- // must fail due to a future structure proof. We have two options at that point. We
- // can either compile all subsequent code as we would otherwise, or we can ensure
- // that the subsequent code is never reachable. The former is correct because the
- // Proof Is Infallible (TM) -- hence even if we don't force the subsequent code to
- // be unreachable, it must be unreachable nonetheless. But imagine what would happen
- // if the proof was borked. In the former case, we'd get really bizarre bugs where
- // we assumed that the structure of this object was known even though it wasn't. In
- // the latter case, we'd have a slight performance pathology because this would be
- // turned into an OSR exit unnecessarily. Which would you rather have?
- if (value.m_currentKnownStructure.isClear()
- || value.m_futurePossibleStructure.isClear())
- m_isValid = false;
m_haveStructures = true;
break;
}
@@ -1325,10 +1324,6 @@ bool AbstractState::execute(unsigned indexInBlock)
ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad.
value.filter(node.structure());
- // See comment in CheckStructure for why this is here.
- if (value.m_currentKnownStructure.isClear()
- || value.m_futurePossibleStructure.isClear())
- m_isValid = false;
m_haveStructures = true;
node.setCanExit(true);
break;
@@ -1337,9 +1332,11 @@ bool AbstractState::execute(unsigned indexInBlock)
case PutStructure:
case PhantomPutStructure:
node.setCanExit(false);
- clobberStructures(indexInBlock);
- forNode(node.child1()).set(node.structureTransitionData().newStructure);
- m_haveStructures = true;
+ if (!forNode(node.child1()).m_currentKnownStructure.isClear()) {
+ clobberStructures(indexInBlock);
+ forNode(node.child1()).set(node.structureTransitionData().newStructure);
+ m_haveStructures = true;
+ }
break;
case GetButterfly:
case AllocatePropertyStorage:
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
index eda578205..fe2a05b8b 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
@@ -42,10 +42,16 @@ Array::Mode fromObserved(ArrayModes modes, bool makeSafe)
return Array::Undecided;
case asArrayModes(NonArrayWithArrayStorage):
return makeSafe ? Array::ArrayStorageOutOfBounds : Array::ArrayStorage;
+ case asArrayModes(NonArrayWithSlowPutArrayStorage):
+ return Array::SlowPutArrayStorage;
case asArrayModes(ArrayWithArrayStorage):
return makeSafe ? Array::ArrayWithArrayStorageOutOfBounds : Array::ArrayWithArrayStorage;
+ case asArrayModes(ArrayWithSlowPutArrayStorage):
+ return Array::ArrayWithSlowPutArrayStorage;
case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage):
return makeSafe ? Array::PossiblyArrayWithArrayStorageOutOfBounds : Array::PossiblyArrayWithArrayStorage;
+ case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
+ return Array::PossiblyArrayWithSlowPutArrayStorage;
default:
// We know that this is possibly a kind of array for which, though there is no
// useful data in the array profile, we may be able to extract useful data from
@@ -124,15 +130,29 @@ bool modeAlreadyChecked(AbstractValue& value, Array::Mode arrayMode)
case Array::String:
return isStringSpeculation(value.m_type);
- case NON_ARRAY_ARRAY_STORAGE_MODES:
+ case Array::ArrayStorage:
+ case Array::ArrayStorageOutOfBounds:
+ case Array::PossiblyArrayWithArrayStorage:
+ case Array::PossiblyArrayWithArrayStorageOutOfBounds:
return value.m_currentKnownStructure.hasSingleton()
&& (value.m_currentKnownStructure.singleton()->indexingType() & HasArrayStorage);
-
- case ARRAY_WITH_ARRAY_STORAGE_MODES:
+
+ case Array::SlowPutArrayStorage:
+ case Array::PossiblyArrayWithSlowPutArrayStorage:
+ return value.m_currentKnownStructure.hasSingleton()
+ && (value.m_currentKnownStructure.singleton()->indexingType() & HasSlowPutArrayStorage);
+
+ case Array::ArrayWithArrayStorage:
+ case Array::ArrayWithArrayStorageOutOfBounds:
return value.m_currentKnownStructure.hasSingleton()
&& (value.m_currentKnownStructure.singleton()->indexingType() & HasArrayStorage)
&& (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+ case Array::ArrayWithSlowPutArrayStorage:
+ return value.m_currentKnownStructure.hasSingleton()
+ && (value.m_currentKnownStructure.singleton()->indexingType() & HasSlowPutArrayStorage)
+ && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+
case Array::Arguments:
return isArgumentsSpeculation(value.m_type);
@@ -184,14 +204,20 @@ const char* modeToString(Array::Mode mode)
return "String";
case Array::ArrayStorage:
return "ArrayStorage";
+ case Array::SlowPutArrayStorage:
+ return "SlowPutArrayStorage";
case Array::ArrayStorageOutOfBounds:
return "ArrayStorageOutOfBounds";
case Array::ArrayWithArrayStorage:
return "ArrayWithArrayStorage";
+ case Array::ArrayWithSlowPutArrayStorage:
+ return "ArrayWithSlowPutArrayStorage";
case Array::ArrayWithArrayStorageOutOfBounds:
return "ArrayWithArrayStorageOutOfBounds";
case Array::PossiblyArrayWithArrayStorage:
return "PossiblyArrayWithArrayStorage";
+ case Array::PossiblyArrayWithSlowPutArrayStorage:
+ return "PossiblyArrayWithSlowPutArrayStorage";
case Array::PossiblyArrayWithArrayStorageOutOfBounds:
return "PossiblyArrayWithArrayStorageOutOfBounds";
case Array::Arguments:
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h
index 2eb009be0..cc8b1b809 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.h
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h
@@ -47,10 +47,13 @@ enum Mode {
Generic,
String,
ArrayStorage,
+ SlowPutArrayStorage,
ArrayStorageOutOfBounds,
ArrayWithArrayStorage,
+ ArrayWithSlowPutArrayStorage,
ArrayWithArrayStorageOutOfBounds,
PossiblyArrayWithArrayStorage,
+ PossiblyArrayWithSlowPutArrayStorage,
PossiblyArrayWithArrayStorageOutOfBounds,
Arguments,
Int8Array,
@@ -70,11 +73,14 @@ enum Mode {
// have the word "ArrayStorage" in them.
#define NON_ARRAY_ARRAY_STORAGE_MODES \
Array::ArrayStorage: \
+ case Array::SlowPutArrayStorage: \
case Array::ArrayStorageOutOfBounds: \
case Array::PossiblyArrayWithArrayStorage: \
+ case Array::PossiblyArrayWithSlowPutArrayStorage: \
case Array::PossiblyArrayWithArrayStorageOutOfBounds
#define ARRAY_WITH_ARRAY_STORAGE_MODES \
Array::ArrayWithArrayStorage: \
+ case Array::ArrayWithSlowPutArrayStorage: \
case Array::ArrayWithArrayStorageOutOfBounds
#define ALL_ARRAY_STORAGE_MODES \
NON_ARRAY_ARRAY_STORAGE_MODES: \
@@ -83,8 +89,13 @@ enum Mode {
Array::ArrayStorage: \
case Array::ArrayWithArrayStorage: \
case Array::PossiblyArrayWithArrayStorage
+#define SLOW_PUT_ARRAY_STORAGE_MODES \
+ Array::SlowPutArrayStorage: \
+ case Array::ArrayWithSlowPutArrayStorage: \
+ case Array::PossiblyArrayWithSlowPutArrayStorage
#define OUT_OF_BOUNDS_ARRAY_STORAGE_MODES \
- Array::ArrayStorageOutOfBounds: \
+ SLOW_PUT_ARRAY_STORAGE_MODES: \
+ case Array::ArrayStorageOutOfBounds: \
case Array::ArrayWithArrayStorageOutOfBounds: \
case Array::PossiblyArrayWithArrayStorageOutOfBounds
@@ -128,6 +139,16 @@ inline bool isInBoundsAccess(Array::Mode arrayMode)
}
}
+inline bool isSlowPutAccess(Array::Mode arrayMode)
+{
+ switch (arrayMode) {
+ case SLOW_PUT_ARRAY_STORAGE_MODES:
+ return true;
+ default:
+ return false;
+ }
+}
+
inline bool canCSEStorage(Array::Mode arrayMode)
{
switch (arrayMode) {
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 19a389218..67ae7bf03 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1178,7 +1178,7 @@ void DFG_OPERATION operationTearOffArguments(ExecState* exec, JSCell* argumentsC
{
ASSERT(exec->codeBlock()->usesArguments());
if (activationCell) {
- jsCast<Arguments*>(argumentsCell)->didTearOffActivation(exec->globalData(), jsCast<JSActivation*>(activationCell));
+ jsCast<Arguments*>(argumentsCell)->didTearOffActivation(exec, jsCast<JSActivation*>(activationCell));
return;
}
jsCast<Arguments*>(argumentsCell)->tearOff(exec);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index b1f3212f9..07cb11032 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -324,7 +324,8 @@ void SpeculativeJIT::checkArray(Node& node)
m_jit.branchTest8(
MacroAssembler::Zero,
MacroAssembler::Address(temp.gpr(), Structure::indexingTypeOffset()),
- MacroAssembler::TrustedImm32(HasArrayStorage)));
+ MacroAssembler::TrustedImm32(
+ isSlowPutAccess(node.arrayMode()) ? HasSlowPutArrayStorage : HasArrayStorage)));
noResult(m_compileIndex);
return;
@@ -345,7 +346,8 @@ void SpeculativeJIT::checkArray(Node& node)
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branchTest32(
- MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(HasArrayStorage)));
+ MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(
+ isSlowPutAccess(node.arrayMode()) ? HasSlowPutArrayStorage : HasArrayStorage)));
noResult(m_compileIndex);
return;
@@ -3055,28 +3057,24 @@ void SpeculativeJIT::compileGetByValOnArguments(Node& node)
ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), Array::Arguments));
- m_jit.loadPtr(
- MacroAssembler::Address(baseReg, Arguments::offsetOfData()),
- scratchReg);
-
// Two really lame checks.
speculationCheck(
Uncountable, JSValueSource(), NoNode,
m_jit.branchPtr(
MacroAssembler::AboveOrEqual, propertyReg,
- MacroAssembler::Address(scratchReg, OBJECT_OFFSETOF(ArgumentsData, numArguments))));
+ MacroAssembler::Address(baseReg, OBJECT_OFFSETOF(Arguments, m_numArguments))));
speculationCheck(
Uncountable, JSValueSource(), NoNode,
m_jit.branchTestPtr(
MacroAssembler::NonZero,
MacroAssembler::Address(
- scratchReg, OBJECT_OFFSETOF(ArgumentsData, deletedArguments))));
+ baseReg, OBJECT_OFFSETOF(Arguments, m_slowArguments))));
m_jit.move(propertyReg, resultReg);
m_jit.neg32(resultReg);
m_jit.signExtend32ToPtr(resultReg, resultReg);
m_jit.loadPtr(
- MacroAssembler::Address(scratchReg, OBJECT_OFFSETOF(ArgumentsData, registers)),
+ MacroAssembler::Address(baseReg, OBJECT_OFFSETOF(Arguments, m_registers)),
scratchReg);
#if USE(JSVALUE32_64)
@@ -3116,18 +3114,14 @@ void SpeculativeJIT::compileGetArgumentsLength(Node& node)
ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), Array::Arguments));
- m_jit.loadPtr(
- MacroAssembler::Address(baseReg, Arguments::offsetOfData()),
- resultReg);
-
speculationCheck(
Uncountable, JSValueSource(), NoNode,
m_jit.branchTest8(
MacroAssembler::NonZero,
- MacroAssembler::Address(resultReg, OBJECT_OFFSETOF(ArgumentsData, overrodeLength))));
+ MacroAssembler::Address(baseReg, OBJECT_OFFSETOF(Arguments, m_overrodeLength))));
m_jit.load32(
- MacroAssembler::Address(resultReg, OBJECT_OFFSETOF(ArgumentsData, numArguments)),
+ MacroAssembler::Address(baseReg, OBJECT_OFFSETOF(Arguments, m_numArguments)),
resultReg);
integerResult(resultReg, m_compileIndex);
}
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index f40db37a6..85e32ddb9 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2741,25 +2741,37 @@ void SpeculativeJIT::compile(Node& node)
// Check if we're writing to a hole; if so increment m_numValuesInVector.
MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
- 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);
-
- lengthDoesNotNeedUpdate.link(&m_jit);
+ MacroAssembler::Jump isHoleValue;
+ 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);
+
+ lengthDoesNotNeedUpdate.link(&m_jit);
+ }
notHoleValue.link(&m_jit);
// Store the value to the array.
m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
- if (!isInBoundsAccess(node.arrayMode())) {
+ if (!isInBoundsAccess(arrayMode)) {
+ MacroAssembler::JumpList slowCases;
+ slowCases.append(beyondArrayBounds);
+ if (isSlowPutAccess(arrayMode))
+ slowCases.append(isHoleValue);
addSlowPathGenerator(
slowPathCall(
- beyondArrayBounds, this,
+ slowCases, this,
m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
}
@@ -3128,13 +3140,17 @@ void SpeculativeJIT::compile(Node& node)
}
case NewArray: {
+ JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
+ if (!globalObject->isHavingABadTime())
+ globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
+
if (!node.numChildren()) {
flushRegisters();
GPRResult result(this);
GPRResult2 resultTagIgnored(this);
callOperation(
operationNewEmptyArray, resultTagIgnored.gpr(), result.gpr(),
- m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure());
+ globalObject->arrayStructure());
cellResult(result.gpr(), m_compileIndex);
break;
}
@@ -3167,8 +3183,7 @@ void SpeculativeJIT::compile(Node& node)
GPRResult2 resultTag(this);
callOperation(
- operationNewArray, resultTag.gpr(), resultPayload.gpr(),
- m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(),
+ operationNewArray, resultTag.gpr(), resultPayload.gpr(), globalObject->arrayStructure(),
static_cast<void *>(buffer), node.numChildren());
if (scratchSize) {
@@ -3184,6 +3199,10 @@ void SpeculativeJIT::compile(Node& node)
}
case NewArrayWithSize: {
+ JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
+ if (!globalObject->isHavingABadTime())
+ globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
+
SpeculateStrictInt32Operand size(this, node.child1());
GPRReg sizeGPR = size.gpr();
flushRegisters();
@@ -3191,7 +3210,7 @@ void SpeculativeJIT::compile(Node& node)
GPRResult2 resultTagIgnored(this);
callOperation(
operationNewArrayWithSize, resultTagIgnored.gpr(), result.gpr(),
- m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(), sizeGPR);
+ globalObject->arrayStructure(), sizeGPR);
cellResult(result.gpr(), m_compileIndex);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index aa5fe6773..f050af699 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2760,24 +2760,36 @@ void SpeculativeJIT::compile(Node& node)
// Check if we're writing to a hole; if so increment m_numValuesInVector.
MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
- 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);
-
- lengthDoesNotNeedUpdate.link(&m_jit);
+ MacroAssembler::Jump isHoleValue;
+ 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);
+
+ 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])));
if (!isInBoundsAccess(arrayMode)) {
+ MacroAssembler::JumpList slowCases;
+ slowCases.append(beyondArrayBounds);
+ if (isSlowPutAccess(arrayMode))
+ slowCases.append(isHoleValue);
addSlowPathGenerator(
slowPathCall(
- beyondArrayBounds, this,
+ slowCases, this,
m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
NoResult, baseReg, propertyReg, valueReg));
}
@@ -2798,28 +2810,24 @@ void SpeculativeJIT::compile(Node& node)
if (!m_compileOkay)
return;
- m_jit.loadPtr(
- MacroAssembler::Address(baseReg, Arguments::offsetOfData()),
- scratchReg);
-
// Two really lame checks.
speculationCheck(
Uncountable, JSValueSource(), NoNode,
m_jit.branchPtr(
MacroAssembler::AboveOrEqual, propertyReg,
- MacroAssembler::Address(scratchReg, OBJECT_OFFSETOF(ArgumentsData, numArguments))));
+ MacroAssembler::Address(baseReg, OBJECT_OFFSETOF(Arguments, m_numArguments))));
speculationCheck(
Uncountable, JSValueSource(), NoNode,
m_jit.branchTestPtr(
MacroAssembler::NonZero,
MacroAssembler::Address(
- scratchReg, OBJECT_OFFSETOF(ArgumentsData, deletedArguments))));
+ baseReg, OBJECT_OFFSETOF(Arguments, m_slowArguments))));
m_jit.move(propertyReg, scratch2Reg);
m_jit.neg32(scratch2Reg);
m_jit.signExtend32ToPtr(scratch2Reg, scratch2Reg);
m_jit.loadPtr(
- MacroAssembler::Address(scratchReg, OBJECT_OFFSETOF(ArgumentsData, registers)),
+ MacroAssembler::Address(baseReg, OBJECT_OFFSETOF(Arguments, m_registers)),
scratchReg);
m_jit.storePtr(
@@ -3120,12 +3128,14 @@ void SpeculativeJIT::compile(Node& node)
}
case NewArray: {
+ JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
+ if (!globalObject->isHavingABadTime())
+ globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
+
if (!node.numChildren()) {
flushRegisters();
GPRResult result(this);
- callOperation(
- operationNewEmptyArray, result.gpr(),
- m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure());
+ callOperation(operationNewEmptyArray, result.gpr(), globalObject->arrayStructure());
cellResult(result.gpr(), m_compileIndex);
break;
}
@@ -3155,8 +3165,7 @@ void SpeculativeJIT::compile(Node& node)
GPRResult result(this);
callOperation(
- operationNewArray, result.gpr(),
- m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(),
+ operationNewArray, result.gpr(), globalObject->arrayStructure(),
static_cast<void*>(buffer), node.numChildren());
if (scratchSize) {
@@ -3171,11 +3180,15 @@ void SpeculativeJIT::compile(Node& node)
}
case NewArrayWithSize: {
+ JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
+ if (!globalObject->isHavingABadTime())
+ globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
+
SpeculateStrictInt32Operand size(this, node.child1());
GPRReg sizeGPR = size.gpr();
flushRegisters();
GPRResult result(this);
- callOperation(operationNewArrayWithSize, result.gpr(), m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(), sizeGPR);
+ callOperation(operationNewArrayWithSize, result.gpr(), globalObject->arrayStructure(), sizeGPR);
cellResult(result.gpr(), m_compileIndex);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
index f6fe127a3..0838bb7e5 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
@@ -67,7 +67,8 @@ public:
if (!node.shouldGenerate())
continue;
switch (node.op()) {
- case CheckStructure: {
+ case CheckStructure:
+ case StructureTransitionWatchpoint: {
Node& child = m_graph[node.child1()];
if (child.op() != GetLocal)
break;
@@ -91,7 +92,6 @@ public:
case GetByOffset:
case PutByOffset:
case PutStructure:
- case StructureTransitionWatchpoint:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
case GetButterfly:
@@ -105,6 +105,40 @@ public:
// Don't count these uses.
break;
+ case SetLocal: {
+ // Find all uses of the source of the SetLocal. If any of them are a
+ // kind of CheckStructure, then we should notice them to ensure that
+ // we're not hoisting a check that would contravene checks that are
+ // already being performed.
+ VariableAccessData* variable = node.variableAccessData();
+ if (variable->isCaptured() || variable->structureCheckHoistingFailed())
+ break;
+ if (!isCellSpeculation(variable->prediction()))
+ break;
+ NodeIndex source = node.child1().index();
+ for (unsigned subIndexInBlock = 0; subIndexInBlock < block->size(); ++subIndexInBlock) {
+ NodeIndex subNodeIndex = block->at(subIndexInBlock);
+ Node& subNode = m_graph[subNodeIndex];
+ if (!subNode.shouldGenerate())
+ continue;
+ switch (subNode.op()) {
+ case CheckStructure:
+ case StructureTransitionWatchpoint: {
+ if (subNode.child1().index() != source)
+ break;
+
+ noticeStructureCheck(variable, subNode.structureSet());
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ m_graph.vote(node, VoteOther);
+ break;
+ }
+
default:
m_graph.vote(node, VoteOther);
break;