diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGAbstractState.cpp | 47 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGArrayMode.cpp | 32 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGArrayMode.h | 23 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGOperations.cpp | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp | 24 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp | 49 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp | 59 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp | 38 |
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; |