Source/JavaScriptCore:
2014-06-27 Michael Saboff <msaboff@apple.com>
Unreviewed build fix after r169795.
Fixed ASSERT for 32 bit build.
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::silentSavePlanForGPR):
2014-06-24 Saam Barati <sbarati@apple.com>
Web Inspector: debugger should be able to show variable types
https://bugs.webkit.org/show_bug.cgi?id=133395
Reviewed by Filip Pizlo.
Increase the amount of type information the VM gathers when directed
to do so. This initial commit is working towards the goal of
capturing, and then showing (via the Web Inspector) type information for all
assignment and load operations. This patch doesn't have the feature fully
implemented, but it ensures the VM has no performance regressions
unless the feature is specifically turned on.
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecode/CodeBlock.h:
* bytecode/Instruction.h:
* bytecode/TypeLocation.h: Added.
(JSC::TypeLocation::TypeLocation):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitMove):
(JSC::BytecodeGenerator::emitProfileTypesWithHighFidelity):
(JSC::BytecodeGenerator::emitPutToScope):
(JSC::BytecodeGenerator::emitPutById):
(JSC::BytecodeGenerator::emitPutByVal):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::isProfilingTypesWithHighFidelity):
* bytecompiler/NodesCodegen.cpp:
(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ConstDeclNode::emitCodeSingle):
(JSC::ForInNode::emitBytecode):
* heap/Heap.cpp:
(JSC::Heap::collect):
* inspector/agents/InspectorRuntimeAgent.cpp:
(Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableInTextRange):
* inspector/agents/InspectorRuntimeAgent.h:
* inspector/protocol/Runtime.json:
* jsc.cpp:
(GlobalObject::finishCreation):
(functionDumpTypesForAllVariables):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
(JSC::LLInt::putToScopeCommon):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* runtime/HighFidelityLog.cpp: Added.
(JSC::HighFidelityLog::initializeHighFidelityLog):
(JSC::HighFidelityLog::~HighFidelityLog):
(JSC::HighFidelityLog::recordTypeInformationForLocation):
(JSC::HighFidelityLog::processHighFidelityLog):
(JSC::HighFidelityLog::actuallyProcessLogThreadFunction):
* runtime/HighFidelityLog.h: Added.
(JSC::HighFidelityLog::HighFidelityLog):
* runtime/HighFidelityTypeProfiler.cpp: Added.
(JSC::HighFidelityTypeProfiler::getTypesForVariableInRange):
(JSC::HighFidelityTypeProfiler::getGlobalTypesForVariableInRange):
(JSC::HighFidelityTypeProfiler::getLocalTypesForVariableInRange):
(JSC::HighFidelityTypeProfiler::insertNewLocation):
(JSC::HighFidelityTypeProfiler::getLocationBasedHash):
* runtime/HighFidelityTypeProfiler.h: Added.
* runtime/Options.h:
* runtime/Structure.cpp:
(JSC::Structure::toStructureShape):
* runtime/Structure.h:
* runtime/SymbolTable.cpp:
(JSC::SymbolTable::SymbolTable):
(JSC::SymbolTable::cloneCapturedNames):
(JSC::SymbolTable::uniqueIDForVariable):
(JSC::SymbolTable::uniqueIDForRegister):
(JSC::SymbolTable::globalTypeSetForRegister):
(JSC::SymbolTable::globalTypeSetForVariable):
* runtime/SymbolTable.h:
(JSC::SymbolTable::add):
(JSC::SymbolTable::set):
* runtime/TypeSet.cpp: Added.
(JSC::TypeSet::TypeSet):
(JSC::TypeSet::getRuntimeTypeForValue):
(JSC::TypeSet::addTypeForValue):
(JSC::TypeSet::removeDuplicatesInStructureHistory):
(JSC::TypeSet::seenTypes):
(JSC::TypeSet::dumpSeenTypes):
(JSC::StructureShape::StructureShape):
(JSC::StructureShape::markAsFinal):
(JSC::StructureShape::addProperty):
(JSC::StructureShape::propertyHash):
(JSC::StructureShape::leastUpperBound):
(JSC::StructureShape::stringRepresentation):
* runtime/TypeSet.h: Added.
(JSC::StructureShape::create):
(JSC::TypeSet::create):
* runtime/VM.cpp:
(JSC::VM::VM):
(JSC::VM::getTypesForVariableInRange):
(JSC::VM::updateHighFidelityTypeProfileState):
(JSC::VM::dumpHighFidelityProfilingTypes):
* runtime/VM.h:
(JSC::VM::isProfilingTypesWithHighFidelity):
(JSC::VM::highFidelityLog):
(JSC::VM::highFidelityTypeProfiler):
(JSC::VM::nextLocation):
(JSC::VM::getNextUniqueVariableID):
2014-06-26 Mark Lam <mark.lam@apple.com>
Remove unused instantiation of the WithScope structure.
<https://webkit.org/b/134331>
Reviewed by Oliver Hunt.
The WithScope structure instance is the VM is unused, and is now removed.
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
2014-06-25 Mark Hahnenberg <mhahnenberg@apple.com>
Structure bit fields should have a consistent format
https://bugs.webkit.org/show_bug.cgi?id=134307
Reviewed by Filip Pizlo.
Currently we use C-style bit fields for a number of member variables in Structure to save space.
This makes it difficult to load these fields in the JIT. We should instead use our own bitfield
format to make it easy to load and test these variables in JIT code.
* runtime/JSObject.cpp:
(JSC::JSObject::putDirectNonIndexAccessor):
(JSC::JSObject::reifyStaticFunctionsForDelete):
* runtime/Structure.cpp:
(JSC::StructureTransitionTable::contains):
(JSC::StructureTransitionTable::get):
(JSC::StructureTransitionTable::add):
(JSC::Structure::Structure):
(JSC::Structure::materializePropertyMap):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::despecifyFunctionTransition):
(JSC::Structure::toDictionaryTransition):
(JSC::Structure::freezeTransition):
(JSC::Structure::preventExtensionsTransition):
(JSC::Structure::takePropertyTableOrCloneIfPinned):
(JSC::Structure::nonPropertyTransition):
(JSC::Structure::flattenDictionaryStructure):
(JSC::Structure::addPropertyWithoutTransition):
(JSC::Structure::pin):
(JSC::Structure::allocateRareData):
(JSC::Structure::cloneRareDataFrom):
(JSC::Structure::getConcurrently):
(JSC::Structure::putSpecificValue):
(JSC::Structure::getPropertyNamesFromStructure):
(JSC::Structure::visitChildren):
(JSC::Structure::checkConsistency):
* runtime/Structure.h:
(JSC::Structure::isExtensible):
(JSC::Structure::isDictionary):
(JSC::Structure::isUncacheableDictionary):
(JSC::Structure::propertyAccessesAreCacheable):
(JSC::Structure::previousID):
(JSC::Structure::setHasGetterSetterPropertiesWithProtoCheck):
(JSC::Structure::setContainsReadOnlyProperties):
(JSC::Structure::disableSpecificFunctionTracking):
(JSC::Structure::objectToStringValue):
(JSC::Structure::setObjectToStringValue):
(JSC::Structure::setPreviousID):
(JSC::Structure::clearPreviousID):
(JSC::Structure::previous):
(JSC::Structure::rareData):
(JSC::Structure::didTransition): Deleted.
(JSC::Structure::hasGetterSetterProperties): Deleted.
(JSC::Structure::hasReadOnlyOrGetterSetterPropertiesExcludingProto): Deleted.
(JSC::Structure::setHasGetterSetterProperties): Deleted.
(JSC::Structure::hasNonEnumerableProperties): Deleted.
(JSC::Structure::staticFunctionsReified): Deleted.
(JSC::Structure::setStaticFunctionsReified): Deleted.
* runtime/StructureInlines.h:
(JSC::Structure::setEnumerationCache):
(JSC::Structure::enumerationCache):
(JSC::Structure::checkOffsetConsistency):
2014-06-24 Mark Lam <mark.lam@apple.com>
[ftlopt] Renamed DebuggerActivation to DebuggerScope.
<https://webkit.org/b/134273>
Reviewed by Michael Saboff.
* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* debugger/DebuggerActivation.cpp: Removed.
* debugger/DebuggerActivation.h: Removed.
* debugger/DebuggerScope.cpp: Copied from ../../trunk/Source/JavaScriptCore/debugger/DebuggerActivation.cpp.
(JSC::DebuggerScope::DebuggerScope):
(JSC::DebuggerScope::finishCreation):
(JSC::DebuggerScope::visitChildren):
(JSC::DebuggerScope::className):
(JSC::DebuggerScope::getOwnPropertySlot):
(JSC::DebuggerScope::put):
(JSC::DebuggerScope::deleteProperty):
(JSC::DebuggerScope::getOwnPropertyNames):
(JSC::DebuggerScope::defineOwnProperty):
(JSC::DebuggerActivation::DebuggerActivation): Deleted.
(JSC::DebuggerActivation::finishCreation): Deleted.
(JSC::DebuggerActivation::visitChildren): Deleted.
(JSC::DebuggerActivation::className): Deleted.
(JSC::DebuggerActivation::getOwnPropertySlot): Deleted.
(JSC::DebuggerActivation::put): Deleted.
(JSC::DebuggerActivation::deleteProperty): Deleted.
(JSC::DebuggerActivation::getOwnPropertyNames): Deleted.
(JSC::DebuggerActivation::defineOwnProperty): Deleted.
* debugger/DebuggerScope.h: Copied from ../../trunk/Source/JavaScriptCore/debugger/DebuggerActivation.h.
(JSC::DebuggerScope::create):
(JSC::DebuggerActivation::create): Deleted.
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
2014-06-24 Filip Pizlo <fpizlo@apple.com>
[ftlopt] PutByIdFlush can also be converted to a PutByOffset so don't assert otherwise
https://bugs.webkit.org/show_bug.cgi?id=134265
Reviewed by Geoffrey Garen.
More assertion fallout from the PutById folding work.
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToPutByOffset):
2014-06-24 Filip Pizlo <fpizlo@apple.com>
[ftlopt] GC should notify us if it resets to_this
https://bugs.webkit.org/show_bug.cgi?id=128231
Reviewed by Geoffrey Garen.
* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeList.json:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecode/Instruction.h:
* bytecode/ToThisStatus.cpp: Added.
(JSC::merge):
(WTF::printInternal):
* bytecode/ToThisStatus.h: Added.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
2014-06-24 Filip Pizlo <fpizlo@apple.com>
[ftlopt] StructureAbstractValue::onlyStructure() should return nullptr if isClobbered()
https://bugs.webkit.org/show_bug.cgi?id=134256
Reviewed by Michael Saboff.
This isn't testable right now (i.e. it's benign) but we should get it right anyway. The
point is to be able to precisely model what goes on in the snippets of code between a
side-effect and an InvalidationPoint.
This patch also cleans up onlyStructure() by delegating more work to
StructureSet::onlyStructure().
* dfg/DFGStructureAbstractValue.h:
(JSC::DFG::StructureAbstractValue::onlyStructure):
2014-06-24 Filip Pizlo <fpizlo@apple.com>
[ftlopt][REGRESSION] PutById AI is introducing watchable structures without watching them
https://bugs.webkit.org/show_bug.cgi?id=134260
Reviewed by Geoffrey Garen.
This was causing loads of assertion failures in debug builds.
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
2014-06-21 Filip Pizlo <fpizlo@apple.com>
[ftlopt] Fold GetById/PutById to MultiGetByOffset/GetByOffset or MultiPutByOffset/PutByOffset, which implies handling non-singleton sets
https://bugs.webkit.org/show_bug.cgi?id=134090
Reviewed by Oliver Hunt.
This pretty much finishes off the work to eliminate the special-casing of singleton
structure sets by making it possible to fold GetById and PutById to various polymorphic
forms of the ByOffset nodes.
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeForStubInfo):
(JSC::GetByIdStatus::computeFor):
* bytecode/GetByIdStatus.h:
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFor):
* bytecode/PutByIdStatus.h:
* bytecode/PutByIdVariant.h:
(JSC::PutByIdVariant::constantChecks):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
(JSC::DFG::ConstantFoldingPhase::addChecks):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToMultiGetByOffset):
(JSC::DFG::Node::convertToMultiPutByOffset):
* dfg/DFGSpeculativeJIT64.cpp: Also convert all release assertions to DFG assertions in this file, because I was hitting some of them while debugging.
(JSC::DFG::SpeculativeJIT::fillJSValue):
(JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull):
(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt32Strict):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt52):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
(JSC::DFG::SpeculativeJIT::compileLogicalNot):
(JSC::DFG::SpeculativeJIT::emitBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureAbstractValue.h:
(JSC::DFG::StructureAbstractValue::set):
2014-06-19 Filip Pizlo <fpizlo@apple.com>
[ftlopt] StructureSet::onlyStructure() should return nullptr if it's not a singleton (instead of asserting)
https://bugs.webkit.org/show_bug.cgi?id=134077
Reviewed by Sam Weinig.
This makes StructureSet and StructureAbstractValue more consistent and fixes a debug assert
in the abstract interpreter.
* bytecode/StructureSet.h:
(JSC::StructureSet::onlyStructure):
2014-06-18 Filip Pizlo <fpizlo@apple.com>
DFG AI and constant folder should be able to precisely prune MultiGetByOffset/MultiPutByOffset even if the base structure abstract value is not a singleton
https://bugs.webkit.org/show_bug.cgi?id=133918
Reviewed by Mark Hahnenberg.
This also adds pruning of PutStructure, since I basically had no choice but
to implement such logic within MultiPutByOffset.
Also adds a bunch of PutById cache status dumping to bytecode dumping.
* bytecode/GetByIdVariant.cpp:
(JSC::GetByIdVariant::dumpInContext):
* bytecode/GetByIdVariant.h:
(JSC::GetByIdVariant::structureSet):
* bytecode/PutByIdVariant.h:
(JSC::PutByIdVariant::oldStructure):
* bytecode/StructureSet.cpp:
(JSC::StructureSet::filter):
(JSC::StructureSet::filterArrayModes):
* bytecode/StructureSet.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGAbstractValue.cpp:
(JSC::DFG::AbstractValue::changeStructure):
(JSC::DFG::AbstractValue::contains):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::couldBeType):
(JSC::DFG::AbstractValue::isType):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::emitGetByOffset):
(JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
(JSC::DFG::ConstantFoldingPhase::addBaseCheck):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::freezeStrong):
* dfg/DFGGraph.h:
* dfg/DFGStructureAbstractValue.h:
(JSC::DFG::StructureAbstractValue::operator=):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
* tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js: Added.
(foo):
(fu):
(bar):
(baz):
(.bar):
(.baz):
* tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js: Added.
(foo):
(fu):
(bar):
(baz):
(.bar):
(.baz):
* tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js: Added.
(foo):
(fu):
(bar):
(baz):
(.bar):
(.baz):
2014-06-18 Mark Hahnenberg <mhahnenberg@apple.com>
Remove CompoundType and LeafType
https://bugs.webkit.org/show_bug.cgi?id=134037
Reviewed by Filip Pizlo.
We don't use them for anything. We'll replace them with a generic CellType type for all
the objects that are JSCells, aren't JSObjects, and for which we generally don't care about
their JSType at runtime.
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* runtime/ArrayBufferNeuteringWatchpoint.cpp:
(JSC::ArrayBufferNeuteringWatchpoint::createStructure):
* runtime/Executable.h:
(JSC::ExecutableBase::createStructure):
(JSC::NativeExecutable::createStructure):
* runtime/JSPromiseDeferred.h:
(JSC::JSPromiseDeferred::createStructure):
* runtime/JSPromiseReaction.h:
(JSC::JSPromiseReaction::createStructure):
* runtime/JSPropertyNameIterator.h:
(JSC::JSPropertyNameIterator::createStructure):
* runtime/JSType.h:
* runtime/JSTypeInfo.h:
(JSC::TypeInfo::TypeInfo):
* runtime/MapData.h:
(JSC::MapData::createStructure):
* runtime/PropertyMapHashTable.h:
(JSC::PropertyTable::createStructure):
* runtime/RegExp.h:
(JSC::RegExp::createStructure):
* runtime/SparseArrayValueMap.cpp:
(JSC::SparseArrayValueMap::createStructure):
* runtime/Structure.cpp:
(JSC::Structure::Structure):
* runtime/StructureChain.h:
(JSC::StructureChain::createStructure):
* runtime/StructureRareData.cpp:
(JSC::StructureRareData::createStructure):
* runtime/SymbolTable.h:
(JSC::SymbolTable::createStructure):
* runtime/WeakMapData.h:
(JSC::WeakMapData::createStructure):
2014-06-17 Filip Pizlo <fpizlo@apple.com>
[ftlopt] PutStructure and PhantomPutStructure shouldn't leave the world in a clobbered state
https://bugs.webkit.org/show_bug.cgi?id=134002
Reviewed by Mark Hahnenberg.
The effect of this bug was that if we had a PutStructure or PhantomPutStructure then any
JSConstants would be in a Clobbered state, so we wouldn't take advantage of our knowledge
of the structure if that structure was watchable.
Also kill PhantomPutStructure.
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransition):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::visitChildren):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasTransition):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureAbstractValue.cpp:
(JSC::DFG::StructureAbstractValue::observeTransition):
(JSC::DFG::StructureAbstractValue::observeTransitions):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validate):
* dfg/DFGWatchableStructureWatchingPhase.cpp:
(JSC::DFG::WatchableStructureWatchingPhase::run):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compilePhantomPutStructure): Deleted.
2014-06-17 Filip Pizlo <fpizlo@apple.com>
[ftlopt] DFG put_by_id should inline accesses with a slightly polymorphic base
https://bugs.webkit.org/show_bug.cgi?id=133964
Reviewed by Mark Hahnenberg.
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::appendVariant):
(JSC::PutByIdStatus::computeForStubInfo):
* bytecode/PutByIdVariant.cpp:
(JSC::PutByIdVariant::oldStructureForTransition):
(JSC::PutByIdVariant::writesStructures):
(JSC::PutByIdVariant::reallocatesStorage):
(JSC::PutByIdVariant::attemptToMerge):
(JSC::PutByIdVariant::attemptToMergeTransitionWithReplace):
(JSC::PutByIdVariant::dumpInContext):
* bytecode/PutByIdVariant.h:
(JSC::PutByIdVariant::PutByIdVariant):
(JSC::PutByIdVariant::replace):
(JSC::PutByIdVariant::transition):
(JSC::PutByIdVariant::structure):
(JSC::PutByIdVariant::oldStructure):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handlePutById):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::visitChildren):
* dfg/DFGNode.cpp:
(JSC::DFG::MultiPutByOffsetData::writesStructures):
(JSC::DFG::MultiPutByOffsetData::reallocatesStorage):
* ftl/FTLAbbreviations.h:
(JSC::FTL::getLinkage):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset):
(JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol):
Source/WebCore:
2014-07-25 Mark Lam <mark.lam@apple.com>
[ftlopt] Renamed DebuggerActivation to DebuggerScope.
<https://webkit.org/b/134273>
Reviewed by Michael Saboff.
No new tests.
* ForwardingHeaders/debugger/DebuggerActivation.h: Removed.
- Removed because this is not used.
Source/WebKit/mac:
2014-07-25 Mark Lam <mark.lam@apple.com>
[ftlopt] Renamed DebuggerActivation to DebuggerScope.
<https://webkit.org/b/134273>
Reviewed by Michael Saboff.
* WebView/WebScriptDebugDelegate.mm:
- Removed unneeded #include.
LayoutTests:
2014-07-25 Filip Pizlo <fpizlo@apple.com>
[ftlopt] Fold GetById/PutById to MultiGetByOffset/GetByOffset or MultiPutByOffset/PutByOffset, which implies handling non-singleton sets
https://bugs.webkit.org/show_bug.cgi?id=134090
Reviewed by Oliver Hunt.
* js/regress/fold-get-by-id-to-multi-get-by-offset-expected.txt: Added.
* js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int-expected.txt: Added.
* js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html: Added.
* js/regress/fold-get-by-id-to-multi-get-by-offset.html: Added.
* js/regress/fold-put-by-id-to-multi-put-by-offset-expected.txt: Added.
* js/regress/fold-put-by-id-to-multi-put-by-offset.html: Added.
* js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset-rare-int.js: Added.
(foo):
(fu):
(bar):
(.bar):
(Number):
* js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
(Number):
* js/regress/script-tests/fold-put-by-id-to-multi-put-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
2014-06-19 Filip Pizlo <fpizlo@apple.com>
[ftlopt] LICM should be able to hoist CheckStructure even if the loop clobbers structures so long as the structures being checked are watchable
https://bugs.webkit.org/show_bug.cgi?id=134056
Unreviewed, just landing the test cases for this attempted optimization. The test cases
will still be valid once we find a smart way of doing this optimization.
* js/regress/hoist-poly-check-structure-effectful-loop-expected.txt: Added.
* js/regress/hoist-poly-check-structure-effectful-loop.html: Added.
* js/regress/hoist-poly-check-structure-expected.txt: Added.
* js/regress/hoist-poly-check-structure.html: Added.
* js/regress/script-tests/hoist-poly-check-structure-effectful-loop.js: Added.
(foo):
(test):
* js/regress/script-tests/hoist-poly-check-structure.js: Added.
(foo):
(test):
2014-06-18 Filip Pizlo <fpizlo@apple.com>
DFG AI and constant folder should be able to precisely prune MultiGetByOffset/MultiPutByOffset even if the base structure abstract value is not a singleton
https://bugs.webkit.org/show_bug.cgi?id=133918
Reviewed by Mark Hahnenberg.
* js/regress/fold-multi-get-by-offset-to-get-by-offset-expected.txt: Added.
* js/regress/fold-multi-get-by-offset-to-get-by-offset.html: Added.
* js/regress/fold-multi-get-by-offset-to-poly-get-by-offset-expected.txt: Added.
* js/regress/fold-multi-get-by-offset-to-poly-get-by-offset.html: Added.
* js/regress/fold-multi-put-by-offset-to-poly-put-by-offset-expected.txt: Added.
* js/regress/fold-multi-put-by-offset-to-poly-put-by-offset.html: Added.
* js/regress/fold-multi-put-by-offset-to-put-by-offset-expected.txt: Added.
* js/regress/fold-multi-put-by-offset-to-put-by-offset.html: Added.
* js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset-expected.txt: Added.
* js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.html: Added.
* js/regress/fold-put-structure-expected.txt: Added.
* js/regress/fold-put-structure.html: Added.
* js/regress/script-tests/fold-multi-get-by-offset-to-get-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
* js/regress/script-tests/fold-multi-get-by-offset-to-poly-get-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
* js/regress/script-tests/fold-multi-put-by-offset-to-poly-put-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
* js/regress/script-tests/fold-multi-put-by-offset-to-put-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
* js/regress/script-tests/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
* js/regress/script-tests/fold-put-structure.js: Added.
(foo):
(fu):
(bar):
(.bar):
2014-06-17 Filip Pizlo <fpizlo@apple.com>
[ftlopt] DFG put_by_id should inline accesses with a slightly polymorphic base
https://bugs.webkit.org/show_bug.cgi?id=133964
Reviewed by Mark Hahnenberg.
* js/regress/put-by-id-replace-and-transition-expected.txt: Added.
* js/regress/put-by-id-replace-and-transition.html: Added.
* js/regress/put-by-id-slightly-polymorphic-expected.txt: Added.
* js/regress/put-by-id-slightly-polymorphic.html: Added.
* js/regress/script-tests/put-by-id-replace-and-transition.js: Added.
* js/regress/script-tests/put-by-id-slightly-polymorphic.js: Added.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@171641
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2014-07-25 Filip Pizlo <fpizlo@apple.com>
+
+ Merge r170090, r170092, r170129, r170141, r170161, r170215, r170275, r170375, r170376, r170382, r170383, r170399, r170436, r170489, r170490, r170556 from ftlopt.
+
+ 2014-07-25 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] Fold GetById/PutById to MultiGetByOffset/GetByOffset or MultiPutByOffset/PutByOffset, which implies handling non-singleton sets
+ https://bugs.webkit.org/show_bug.cgi?id=134090
+
+ Reviewed by Oliver Hunt.
+
+ * js/regress/fold-get-by-id-to-multi-get-by-offset-expected.txt: Added.
+ * js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int-expected.txt: Added.
+ * js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html: Added.
+ * js/regress/fold-get-by-id-to-multi-get-by-offset.html: Added.
+ * js/regress/fold-put-by-id-to-multi-put-by-offset-expected.txt: Added.
+ * js/regress/fold-put-by-id-to-multi-put-by-offset.html: Added.
+ * js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset-rare-int.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (.bar):
+ (Number):
+ * js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (.bar):
+ (Number):
+ * js/regress/script-tests/fold-put-by-id-to-multi-put-by-offset.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (.bar):
+
+ 2014-06-19 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] LICM should be able to hoist CheckStructure even if the loop clobbers structures so long as the structures being checked are watchable
+ https://bugs.webkit.org/show_bug.cgi?id=134056
+
+ Unreviewed, just landing the test cases for this attempted optimization. The test cases
+ will still be valid once we find a smart way of doing this optimization.
+
+ * js/regress/hoist-poly-check-structure-effectful-loop-expected.txt: Added.
+ * js/regress/hoist-poly-check-structure-effectful-loop.html: Added.
+ * js/regress/hoist-poly-check-structure-expected.txt: Added.
+ * js/regress/hoist-poly-check-structure.html: Added.
+ * js/regress/script-tests/hoist-poly-check-structure-effectful-loop.js: Added.
+ (foo):
+ (test):
+ * js/regress/script-tests/hoist-poly-check-structure.js: Added.
+ (foo):
+ (test):
+
+ 2014-06-18 Filip Pizlo <fpizlo@apple.com>
+
+ DFG AI and constant folder should be able to precisely prune MultiGetByOffset/MultiPutByOffset even if the base structure abstract value is not a singleton
+ https://bugs.webkit.org/show_bug.cgi?id=133918
+
+ Reviewed by Mark Hahnenberg.
+
+ * js/regress/fold-multi-get-by-offset-to-get-by-offset-expected.txt: Added.
+ * js/regress/fold-multi-get-by-offset-to-get-by-offset.html: Added.
+ * js/regress/fold-multi-get-by-offset-to-poly-get-by-offset-expected.txt: Added.
+ * js/regress/fold-multi-get-by-offset-to-poly-get-by-offset.html: Added.
+ * js/regress/fold-multi-put-by-offset-to-poly-put-by-offset-expected.txt: Added.
+ * js/regress/fold-multi-put-by-offset-to-poly-put-by-offset.html: Added.
+ * js/regress/fold-multi-put-by-offset-to-put-by-offset-expected.txt: Added.
+ * js/regress/fold-multi-put-by-offset-to-put-by-offset.html: Added.
+ * js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset-expected.txt: Added.
+ * js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.html: Added.
+ * js/regress/fold-put-structure-expected.txt: Added.
+ * js/regress/fold-put-structure.html: Added.
+ * js/regress/script-tests/fold-multi-get-by-offset-to-get-by-offset.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (.bar):
+ * js/regress/script-tests/fold-multi-get-by-offset-to-poly-get-by-offset.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (.bar):
+ * js/regress/script-tests/fold-multi-put-by-offset-to-poly-put-by-offset.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (.bar):
+ * js/regress/script-tests/fold-multi-put-by-offset-to-put-by-offset.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (.bar):
+ * js/regress/script-tests/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (.bar):
+ * js/regress/script-tests/fold-put-structure.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (.bar):
+
+ 2014-06-17 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] DFG put_by_id should inline accesses with a slightly polymorphic base
+ https://bugs.webkit.org/show_bug.cgi?id=133964
+
+ Reviewed by Mark Hahnenberg.
+
+ * js/regress/put-by-id-replace-and-transition-expected.txt: Added.
+ * js/regress/put-by-id-replace-and-transition.html: Added.
+ * js/regress/put-by-id-slightly-polymorphic-expected.txt: Added.
+ * js/regress/put-by-id-slightly-polymorphic.html: Added.
+ * js/regress/script-tests/put-by-id-replace-and-transition.js: Added.
+ * js/regress/script-tests/put-by-id-slightly-polymorphic.js: Added.
+
2014-07-25 Zalan Bujtas <zalan@apple.com>
Subpixel rendering: Rounded rect gets non-renderable at certain subpixel size.
--- /dev/null
+JSRegress/fold-get-by-id-to-multi-get-by-offset
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+JSRegress/fold-get-by-id-to-multi-get-by-offset-rare-int
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/fold-get-by-id-to-multi-get-by-offset-rare-int.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/fold-get-by-id-to-multi-get-by-offset.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/fold-multi-get-by-offset-to-get-by-offset
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/fold-multi-get-by-offset-to-get-by-offset.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/fold-multi-get-by-offset-to-poly-get-by-offset
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/fold-multi-get-by-offset-to-poly-get-by-offset.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/fold-multi-put-by-offset-to-poly-put-by-offset
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/fold-multi-put-by-offset-to-poly-put-by-offset.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/fold-multi-put-by-offset-to-put-by-offset
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/fold-multi-put-by-offset-to-put-by-offset.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/fold-put-by-id-to-multi-put-by-offset
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/fold-put-by-id-to-multi-put-by-offset.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/fold-put-structure
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/fold-put-structure.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/hoist-poly-check-structure-effectful-loop
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/hoist-poly-check-structure-effectful-loop.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/hoist-poly-check-structure
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/hoist-poly-check-structure.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/put-by-id-replace-and-transition
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/put-by-id-replace-and-transition.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+JSRegress/put-by-id-slightly-polymorphic
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/put-by-id-slightly-polymorphic.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+function foo(o) {
+ return o.f;
+}
+
+function fu(o) {
+ return o.e;
+}
+
+function bar(f, o) {
+ return f(o);
+}
+
+for (var i = 0; i < 1000; ++i) {
+ var o = {f:1};
+ o["i" + i] = 42;
+ foo(o);
+ fu({f:1, e:2});
+ fu({e:1, f:2});
+}
+
+for (var i = 0; i < 100; ++i) {
+ bar(foo, {f:1});
+ bar(function() { }, null);
+ bar(function() { return 42 }, null);
+}
+
+Number.prototype.f = 100;
+
+(function(f, o, p) {
+ var result = 0;
+ var n = 1000000;
+ for (var i = 0; i < n + 1; ++i) {
+ result += fu(o);
+ var q;
+ if (i == n)
+ q = 42;
+ else
+ q = o;
+ result += bar(f, q);
+ var tmp = o;
+ o = p;
+ p = tmp;
+ }
+ if (result != (o.f + o.e + p.f + p.e) * n / 2 + 100 + p.e)
+ throw "Error: bad result: " + result;
+})(foo, {f:42, e:43}, {e:44, f:45});
+
--- /dev/null
+function foo(o) {
+ return o.f;
+}
+
+function fu(o) {
+ return o.e;
+}
+
+function bar(f, o) {
+ return f(o);
+}
+
+for (var i = 0; i < 1000; ++i) {
+ var o = {f:1};
+ o["i" + i] = 42;
+ foo(o);
+ fu({f:1, e:2});
+ fu({e:1, f:2});
+}
+
+for (var i = 0; i < 100; ++i) {
+ bar(foo, {f:1});
+ bar(function() { }, null);
+ bar(function() { return 42 }, null);
+}
+
+Number.prototype.f = 100;
+
+(function(f, o, p) {
+ var result = 0;
+ var n = 1000000;
+ for (var i = 0; i < n; ++i) {
+ result += fu(o);
+ result += bar(f, o);
+ var tmp = o;
+ o = p;
+ p = tmp;
+ }
+ if (result != (o.f + o.e + p.f + p.e) * n / 2)
+ throw "Error: bad result: " + result;
+})(foo, {f:42, e:43}, {e:44, f:45});
+
--- /dev/null
+function foo(o) {
+ return o.f;
+}
+
+function fu(o) {
+ return o.e;
+}
+
+function bar(f, o) {
+ return f(o);
+}
+
+for (var i = 0; i < 100; ++i) {
+ foo({f:1, e:2});
+ foo({e:1, f:2});
+ foo({d:1, e:2, f:3});
+ fu({f:1, e:2});
+ fu({e:1, f:2});
+ fu({d:1, e:2, f:3});
+}
+
+for (var i = 0; i < 100; ++i) {
+ bar(foo, {f:1});
+ bar(function() { }, null);
+ bar(function() { return 42 }, null);
+}
+
+(function(f, o) {
+ var result = 0;
+ var n = 1000000;
+ for (var i = 0; i < n; ++i) {
+ var p;
+ if (i == n - 1) // Defeat LICM.
+ p = {f: 42, e: 42};
+ else
+ p = o;
+ result += fu(p);
+ result += bar(f, p);
+ }
+ if (result != (n - 1) * (o.f + o.e) + 42 * 2)
+ throw "Error: bad result: " + result;
+})(foo, {f:42, e:2});
+
--- /dev/null
+function foo(o) {
+ return o.f;
+}
+
+function fu(o) {
+ return o.e;
+}
+
+function bar(f, o) {
+ return f(o);
+}
+
+for (var i = 0; i < 100; ++i) {
+ foo({f:1, e:2});
+ foo({e:1, f:2});
+ foo({d:1, e:2, f:3});
+ fu({f:1, e:2});
+ fu({e:1, f:2});
+ fu({d:1, e:2, f:3});
+}
+
+for (var i = 0; i < 100; ++i) {
+ bar(foo, {f:1});
+ bar(function() { }, null);
+ bar(function() { return 42 }, null);
+}
+
+(function(f, o, p) {
+ var result = 0;
+ var n = 1000000;
+ for (var i = 0; i < n; ++i) {
+ result += fu(o);
+ result += bar(f, o);
+ var tmp = o;
+ o = p;
+ p = tmp;
+ }
+ if (result != n * o.f + n * o.e)
+ throw "Error: bad result: " + result;
+})(foo, {f:42, e:23}, {f:42, e:23, g:100});
+
--- /dev/null
+function foo(o) {
+ o.f = 1;
+}
+
+function fu(o) {
+ o.e = 2;
+}
+
+function bar(f, o) {
+ f(o);
+}
+
+for (var i = 0; i < 100; ++i) {
+ foo({f:1, e:2});
+ foo({e:1, f:2});
+ foo({d:1, e:2, f:3});
+ fu({f:1, e:2});
+ fu({e:1, f:2});
+ fu({d:1, e:2, f:3});
+}
+
+for (var i = 0; i < 100; ++i) {
+ bar(foo, {f:1});
+ bar(function() { }, null);
+ bar(function() { return 42 }, null);
+}
+
+(function(f, o, p) {
+ var result = 0;
+ var n = 1000000;
+ for (var i = 0; i < n; ++i) {
+ fu(o);
+ bar(f, o);
+ var tmp = o;
+ o = p;
+ p = tmp;
+ }
+ if (o.e != 2)
+ throw "Error: bad value in o.e: " + o.e;
+ if (o.f != 1)
+ throw "Error: bad value in o.f: " + o.f;
+ if (p.e != 2)
+ throw "Error: bad value in p.e: " + p.e;
+ if (p.f != 1)
+ throw "Error: bad value in p.f: " + p.f;
+})(foo, {f:42, e:23}, {f:42, e:23, g:100});
+
--- /dev/null
+function foo(o) {
+ o.f = 1;
+}
+
+function fu(o) {
+ o.e = 2;
+}
+
+function bar(f, o) {
+ f(o);
+}
+
+for (var i = 0; i < 100; ++i) {
+ foo({f:1, e:2});
+ foo({e:1, f:2});
+ foo({d:1, e:2, f:3});
+ fu({f:1, e:2});
+ fu({e:1, f:2});
+ fu({d:1, e:2, f:3});
+}
+
+for (var i = 0; i < 100; ++i) {
+ bar(foo, {f:1});
+ bar(function() { }, null);
+ bar(function() { return 42 }, null);
+}
+
+(function(f, o) {
+ var result = 0;
+ var n = 1000000;
+ for (var i = 0; i < n; ++i) {
+ fu(o);
+ bar(f, o);
+ }
+ if (o.e != 2)
+ throw "Error: bad value in o.e: " + o.e;
+ if (o.f != 1)
+ throw "Error: bad value in o.f: " + o.f;
+})(foo, {f:42, e:23});
+
--- /dev/null
+function foo(o) {
+ o.f = 1;
+}
+
+function fu(o) {
+ o.e = 2;
+}
+
+function bar(f, o) {
+ f(o);
+}
+
+for (var i = 0; i < 100; ++i) {
+ foo({f:1, e:2});
+ foo({e:1, f:2});
+ foo({d:1, e:2, f:3});
+ fu({f:1, e:2});
+ fu({e:1, f:2});
+ fu({d:1, e:2, f:3});
+}
+
+for (var i = 0; i < 100; ++i) {
+ bar(foo, {f:1});
+ bar(function() { }, null);
+ bar(function() { return 42 }, null);
+}
+
+(function(f, o) {
+ var result = 0;
+ var n = 1000000;
+ var p;
+ for (var i = 0; i < n; ++i) {
+ var q;
+ if (i & 1)
+ q = o;
+ else
+ p = q = {e:61};
+ fu(q);
+ bar(f, q);
+ }
+ if (o.e != 2)
+ throw "Error: bad value in o.e: " + o.e;
+ if (o.f != 1)
+ throw "Error: bad value in o.f: " + o.f;
+ if (p.e != 2)
+ throw "Error: bad value in p.e: " + p.e;
+ if (p.f != 1)
+ throw "Error: bad value in p.f: " + p.f;
+})(foo, {e:23, f:42});
+
--- /dev/null
+function foo(o) {
+ o.f = 1;
+}
+
+function fu(o) {
+ o.e = 2;
+}
+
+function bar(f, o) {
+ f(o);
+}
+
+for (var i = 0; i < 1000; ++i) {
+ var o = {};
+ o["i" + i] = 42;
+ foo(o);
+ fu({f:1, e:2});
+ fu({e:1, f:2, g:3});
+}
+
+for (var i = 0; i < 100; ++i) {
+ bar(foo, {f:1});
+ bar(function() { }, null);
+ bar(function() { return 42 }, null);
+}
+
+(function(f, o, p) {
+ var result = 0;
+ var n = 1000000;
+ for (var i = 0; i < n; ++i) {
+ fu(o);
+ bar(f, o);
+ var tmp = o;
+ o = p;
+ p = tmp;
+ }
+ if (o.e != 2)
+ throw "Error: bad value in o.e: " + o.e;
+ if (o.f != 1)
+ throw "Error: bad value in o.f: " + o.f;
+ if (p.e != 2)
+ throw "Error: bad value in p.e: " + p.e;
+ if (p.f != 1)
+ throw "Error: bad value in p.f: " + p.f;
+})(foo, {f:42, e:23}, {e:23, f:42, g:100});
+
--- /dev/null
+function foo(o) {
+ o.f = 1;
+}
+
+function fu(o) {
+ o.e = 2;
+}
+
+function bar(f, o) {
+ f(o);
+}
+
+for (var i = 0; i < 100; ++i) {
+ foo({e:2});
+ foo({e:1, f:2});
+ fu({f:1, e:2});
+ fu({e:1, f:2});
+ fu({d:1, e:2, f:3});
+}
+
+for (var i = 0; i < 100; ++i) {
+ bar(foo, {e:1});
+ bar(function() { }, null);
+ bar(function() { return 42 }, null);
+}
+
+(function(f, o) {
+ var result = 0;
+ var n = 1000000;
+ for (var i = 0; i < n; ++i) {
+ fu(o);
+ bar(f, o);
+ }
+ if (o.e != 2)
+ throw "Error: bad value in o.e: " + o.e;
+ if (o.f != 1)
+ throw "Error: bad value in o.f: " + o.f;
+})(foo, {e:42, f:23});
+
--- /dev/null
+function foo(o, p) {
+ var result = 0;
+ for (var i = 0; i < 100; ++i) {
+ result += o.f;
+ p.g = 42;
+ }
+ return result;
+}
+
+noInline(foo);
+
+function test(o) {
+ if (foo(o, {}) != 100)
+ throw new Error("Error: bad result: " + result);
+}
+
+for (var i = 0; i < 100; ++i) {
+ test({f:1, g:2});
+ test({f:1, h:2});
+ test({f:1, i:2});
+ test({f:1, j:2});
+ test({f:1, k:2});
+ test({f:1, l:2});
+}
+
+for (var i = 0; i < 10000; ++i)
+ test({f:1, g:2});
--- /dev/null
+function foo(o) {
+ var result = 0;
+ for (var i = 0; i < 100; ++i)
+ result += o.f;
+ return result;
+}
+
+noInline(foo);
+
+function test(o) {
+ if (foo(o) != 100)
+ throw new Error("Error: bad result: " + result);
+}
+
+for (var i = 0; i < 100; ++i) {
+ test({f:1});
+ test({f:1, g:2});
+ test({f:1, g:2, h:3});
+ test({f:1, g:2, h:3, i:4});
+ test({f:1, g:2, h:3, i:4, j:5});
+ test({f:1, g:2, h:3, i:4, j:5, k:6});
+}
+
+for (var i = 0; i < 10000; ++i)
+ test({f:1});
--- /dev/null
+(function() {
+ var o;
+ var n = 1000000;
+ for (var i = 0; i < n; ++i) {
+ if (i & 1)
+ o = {f: 1};
+ else
+ o = {f: 1, g: 2};
+ o.g = i;
+ }
+ if (o.g != n - 1)
+ throw "Error: bad value of o.g: " + o.g;
+})();
--- /dev/null
+(function() {
+ var o = {f: 1, g: 2};
+ var p = {f: 1};
+ var n = 1000000;
+ for (var i = 0; i < n; ++i) {
+ o.f = i;
+ var tmp = o;
+ o = p;
+ p = tmp;
+ }
+ if (o.f != n - 2)
+ throw "Error: bad value of o.f: " + o.f;
+ if (p.f != n - 1)
+ throw "Error: vad value of p.f: " + p.f;
+})();
bytecode/StructureSet.cpp
bytecode/StructureStubClearingWatchpoint.cpp
bytecode/StructureStubInfo.cpp
+ bytecode/ToThisStatus.cpp
bytecode/UnlinkedCodeBlock.cpp
bytecode/UnlinkedInstructionStream.cpp
bytecode/ValueRecovery.cpp
bytecompiler/NodesCodegen.cpp
debugger/Debugger.cpp
- debugger/DebuggerActivation.cpp
debugger/DebuggerCallFrame.cpp
+ debugger/DebuggerScope.cpp
dfg/DFGAbstractHeap.cpp
dfg/DFGAbstractValue.cpp
2014-07-25 Filip Pizlo <fpizlo@apple.com>
+ Merge r170090, r170092, r170129, r170141, r170161, r170215, r170275, r170375, r170376, r170382, r170383, r170399, r170436, r170489, r170490, r170556 from ftlopt.
+
+ 2014-06-27 Michael Saboff <msaboff@apple.com>
+
+ Unreviewed build fix after r169795.
+
+ Fixed ASSERT for 32 bit build.
+
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR):
+
+ 2014-06-24 Saam Barati <sbarati@apple.com>
+
+ Web Inspector: debugger should be able to show variable types
+ https://bugs.webkit.org/show_bug.cgi?id=133395
+
+ Reviewed by Filip Pizlo.
+
+ Increase the amount of type information the VM gathers when directed
+ to do so. This initial commit is working towards the goal of
+ capturing, and then showing (via the Web Inspector) type information for all
+ assignment and load operations. This patch doesn't have the feature fully
+ implemented, but it ensures the VM has no performance regressions
+ unless the feature is specifically turned on.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * bytecode/BytecodeList.json:
+ * bytecode/BytecodeUseDef.h:
+ (JSC::computeUsesForBytecodeOffset):
+ (JSC::computeDefsForBytecodeOffset):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dumpBytecode):
+ (JSC::CodeBlock::CodeBlock):
+ (JSC::CodeBlock::finalizeUnconditionally):
+ * bytecode/CodeBlock.h:
+ * bytecode/Instruction.h:
+ * bytecode/TypeLocation.h: Added.
+ (JSC::TypeLocation::TypeLocation):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitMove):
+ (JSC::BytecodeGenerator::emitProfileTypesWithHighFidelity):
+ (JSC::BytecodeGenerator::emitPutToScope):
+ (JSC::BytecodeGenerator::emitPutById):
+ (JSC::BytecodeGenerator::emitPutByVal):
+ * bytecompiler/BytecodeGenerator.h:
+ (JSC::BytecodeGenerator::isProfilingTypesWithHighFidelity):
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::PostfixNode::emitResolve):
+ (JSC::PrefixNode::emitResolve):
+ (JSC::ReadModifyResolveNode::emitBytecode):
+ (JSC::AssignResolveNode::emitBytecode):
+ (JSC::ConstDeclNode::emitCodeSingle):
+ (JSC::ForInNode::emitBytecode):
+ * heap/Heap.cpp:
+ (JSC::Heap::collect):
+ * inspector/agents/InspectorRuntimeAgent.cpp:
+ (Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableInTextRange):
+ * inspector/agents/InspectorRuntimeAgent.h:
+ * inspector/protocol/Runtime.json:
+ * jsc.cpp:
+ (GlobalObject::finishCreation):
+ (functionDumpTypesForAllVariables):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ (JSC::LLInt::putToScopeCommon):
+ * llint/LLIntSlowPaths.h:
+ * llint/LowLevelInterpreter.asm:
+ * runtime/HighFidelityLog.cpp: Added.
+ (JSC::HighFidelityLog::initializeHighFidelityLog):
+ (JSC::HighFidelityLog::~HighFidelityLog):
+ (JSC::HighFidelityLog::recordTypeInformationForLocation):
+ (JSC::HighFidelityLog::processHighFidelityLog):
+ (JSC::HighFidelityLog::actuallyProcessLogThreadFunction):
+ * runtime/HighFidelityLog.h: Added.
+ (JSC::HighFidelityLog::HighFidelityLog):
+ * runtime/HighFidelityTypeProfiler.cpp: Added.
+ (JSC::HighFidelityTypeProfiler::getTypesForVariableInRange):
+ (JSC::HighFidelityTypeProfiler::getGlobalTypesForVariableInRange):
+ (JSC::HighFidelityTypeProfiler::getLocalTypesForVariableInRange):
+ (JSC::HighFidelityTypeProfiler::insertNewLocation):
+ (JSC::HighFidelityTypeProfiler::getLocationBasedHash):
+ * runtime/HighFidelityTypeProfiler.h: Added.
+ * runtime/Options.h:
+ * runtime/Structure.cpp:
+ (JSC::Structure::toStructureShape):
+ * runtime/Structure.h:
+ * runtime/SymbolTable.cpp:
+ (JSC::SymbolTable::SymbolTable):
+ (JSC::SymbolTable::cloneCapturedNames):
+ (JSC::SymbolTable::uniqueIDForVariable):
+ (JSC::SymbolTable::uniqueIDForRegister):
+ (JSC::SymbolTable::globalTypeSetForRegister):
+ (JSC::SymbolTable::globalTypeSetForVariable):
+ * runtime/SymbolTable.h:
+ (JSC::SymbolTable::add):
+ (JSC::SymbolTable::set):
+ * runtime/TypeSet.cpp: Added.
+ (JSC::TypeSet::TypeSet):
+ (JSC::TypeSet::getRuntimeTypeForValue):
+ (JSC::TypeSet::addTypeForValue):
+ (JSC::TypeSet::removeDuplicatesInStructureHistory):
+ (JSC::TypeSet::seenTypes):
+ (JSC::TypeSet::dumpSeenTypes):
+ (JSC::StructureShape::StructureShape):
+ (JSC::StructureShape::markAsFinal):
+ (JSC::StructureShape::addProperty):
+ (JSC::StructureShape::propertyHash):
+ (JSC::StructureShape::leastUpperBound):
+ (JSC::StructureShape::stringRepresentation):
+ * runtime/TypeSet.h: Added.
+ (JSC::StructureShape::create):
+ (JSC::TypeSet::create):
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ (JSC::VM::getTypesForVariableInRange):
+ (JSC::VM::updateHighFidelityTypeProfileState):
+ (JSC::VM::dumpHighFidelityProfilingTypes):
+ * runtime/VM.h:
+ (JSC::VM::isProfilingTypesWithHighFidelity):
+ (JSC::VM::highFidelityLog):
+ (JSC::VM::highFidelityTypeProfiler):
+ (JSC::VM::nextLocation):
+ (JSC::VM::getNextUniqueVariableID):
+
+ 2014-06-26 Mark Lam <mark.lam@apple.com>
+
+ Remove unused instantiation of the WithScope structure.
+ <https://webkit.org/b/134331>
+
+ Reviewed by Oliver Hunt.
+
+ The WithScope structure instance is the VM is unused, and is now removed.
+
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ * runtime/VM.h:
+
+ 2014-06-25 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ Structure bit fields should have a consistent format
+ https://bugs.webkit.org/show_bug.cgi?id=134307
+
+ Reviewed by Filip Pizlo.
+
+ Currently we use C-style bit fields for a number of member variables in Structure to save space.
+ This makes it difficult to load these fields in the JIT. We should instead use our own bitfield
+ format to make it easy to load and test these variables in JIT code.
+
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::putDirectNonIndexAccessor):
+ (JSC::JSObject::reifyStaticFunctionsForDelete):
+ * runtime/Structure.cpp:
+ (JSC::StructureTransitionTable::contains):
+ (JSC::StructureTransitionTable::get):
+ (JSC::StructureTransitionTable::add):
+ (JSC::Structure::Structure):
+ (JSC::Structure::materializePropertyMap):
+ (JSC::Structure::addPropertyTransition):
+ (JSC::Structure::despecifyFunctionTransition):
+ (JSC::Structure::toDictionaryTransition):
+ (JSC::Structure::freezeTransition):
+ (JSC::Structure::preventExtensionsTransition):
+ (JSC::Structure::takePropertyTableOrCloneIfPinned):
+ (JSC::Structure::nonPropertyTransition):
+ (JSC::Structure::flattenDictionaryStructure):
+ (JSC::Structure::addPropertyWithoutTransition):
+ (JSC::Structure::pin):
+ (JSC::Structure::allocateRareData):
+ (JSC::Structure::cloneRareDataFrom):
+ (JSC::Structure::getConcurrently):
+ (JSC::Structure::putSpecificValue):
+ (JSC::Structure::getPropertyNamesFromStructure):
+ (JSC::Structure::visitChildren):
+ (JSC::Structure::checkConsistency):
+ * runtime/Structure.h:
+ (JSC::Structure::isExtensible):
+ (JSC::Structure::isDictionary):
+ (JSC::Structure::isUncacheableDictionary):
+ (JSC::Structure::propertyAccessesAreCacheable):
+ (JSC::Structure::previousID):
+ (JSC::Structure::setHasGetterSetterPropertiesWithProtoCheck):
+ (JSC::Structure::setContainsReadOnlyProperties):
+ (JSC::Structure::disableSpecificFunctionTracking):
+ (JSC::Structure::objectToStringValue):
+ (JSC::Structure::setObjectToStringValue):
+ (JSC::Structure::setPreviousID):
+ (JSC::Structure::clearPreviousID):
+ (JSC::Structure::previous):
+ (JSC::Structure::rareData):
+ (JSC::Structure::didTransition): Deleted.
+ (JSC::Structure::hasGetterSetterProperties): Deleted.
+ (JSC::Structure::hasReadOnlyOrGetterSetterPropertiesExcludingProto): Deleted.
+ (JSC::Structure::setHasGetterSetterProperties): Deleted.
+ (JSC::Structure::hasNonEnumerableProperties): Deleted.
+ (JSC::Structure::staticFunctionsReified): Deleted.
+ (JSC::Structure::setStaticFunctionsReified): Deleted.
+ * runtime/StructureInlines.h:
+ (JSC::Structure::setEnumerationCache):
+ (JSC::Structure::enumerationCache):
+ (JSC::Structure::checkOffsetConsistency):
+
+ 2014-06-24 Mark Lam <mark.lam@apple.com>
+
+ [ftlopt] Renamed DebuggerActivation to DebuggerScope.
+ <https://webkit.org/b/134273>
+
+ Reviewed by Michael Saboff.
+
+ * CMakeLists.txt:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * debugger/DebuggerActivation.cpp: Removed.
+ * debugger/DebuggerActivation.h: Removed.
+ * debugger/DebuggerScope.cpp: Copied from ../../trunk/Source/JavaScriptCore/debugger/DebuggerActivation.cpp.
+ (JSC::DebuggerScope::DebuggerScope):
+ (JSC::DebuggerScope::finishCreation):
+ (JSC::DebuggerScope::visitChildren):
+ (JSC::DebuggerScope::className):
+ (JSC::DebuggerScope::getOwnPropertySlot):
+ (JSC::DebuggerScope::put):
+ (JSC::DebuggerScope::deleteProperty):
+ (JSC::DebuggerScope::getOwnPropertyNames):
+ (JSC::DebuggerScope::defineOwnProperty):
+ (JSC::DebuggerActivation::DebuggerActivation): Deleted.
+ (JSC::DebuggerActivation::finishCreation): Deleted.
+ (JSC::DebuggerActivation::visitChildren): Deleted.
+ (JSC::DebuggerActivation::className): Deleted.
+ (JSC::DebuggerActivation::getOwnPropertySlot): Deleted.
+ (JSC::DebuggerActivation::put): Deleted.
+ (JSC::DebuggerActivation::deleteProperty): Deleted.
+ (JSC::DebuggerActivation::getOwnPropertyNames): Deleted.
+ (JSC::DebuggerActivation::defineOwnProperty): Deleted.
+ * debugger/DebuggerScope.h: Copied from ../../trunk/Source/JavaScriptCore/debugger/DebuggerActivation.h.
+ (JSC::DebuggerScope::create):
+ (JSC::DebuggerActivation::create): Deleted.
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ * runtime/VM.h:
+
+ 2014-06-24 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] PutByIdFlush can also be converted to a PutByOffset so don't assert otherwise
+ https://bugs.webkit.org/show_bug.cgi?id=134265
+
+ Reviewed by Geoffrey Garen.
+
+ More assertion fallout from the PutById folding work.
+
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::convertToPutByOffset):
+
+ 2014-06-24 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] GC should notify us if it resets to_this
+ https://bugs.webkit.org/show_bug.cgi?id=128231
+
+ Reviewed by Geoffrey Garen.
+
+ * CMakeLists.txt:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * bytecode/BytecodeList.json:
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dumpBytecode):
+ (JSC::CodeBlock::finalizeUnconditionally):
+ * bytecode/Instruction.h:
+ * bytecode/ToThisStatus.cpp: Added.
+ (JSC::merge):
+ (WTF::printInternal):
+ * bytecode/ToThisStatus.h: Added.
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::BytecodeGenerator):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/CommonSlowPaths.cpp:
+ (JSC::SLOW_PATH_DECL):
+
+ 2014-06-24 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] StructureAbstractValue::onlyStructure() should return nullptr if isClobbered()
+ https://bugs.webkit.org/show_bug.cgi?id=134256
+
+ Reviewed by Michael Saboff.
+
+ This isn't testable right now (i.e. it's benign) but we should get it right anyway. The
+ point is to be able to precisely model what goes on in the snippets of code between a
+ side-effect and an InvalidationPoint.
+
+ This patch also cleans up onlyStructure() by delegating more work to
+ StructureSet::onlyStructure().
+
+ * dfg/DFGStructureAbstractValue.h:
+ (JSC::DFG::StructureAbstractValue::onlyStructure):
+
+ 2014-06-24 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt][REGRESSION] PutById AI is introducing watchable structures without watching them
+ https://bugs.webkit.org/show_bug.cgi?id=134260
+
+ Reviewed by Geoffrey Garen.
+
+ This was causing loads of assertion failures in debug builds.
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+
+ 2014-06-21 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] Fold GetById/PutById to MultiGetByOffset/GetByOffset or MultiPutByOffset/PutByOffset, which implies handling non-singleton sets
+ https://bugs.webkit.org/show_bug.cgi?id=134090
+
+ Reviewed by Oliver Hunt.
+
+ This pretty much finishes off the work to eliminate the special-casing of singleton
+ structure sets by making it possible to fold GetById and PutById to various polymorphic
+ forms of the ByOffset nodes.
+
+ * bytecode/GetByIdStatus.cpp:
+ (JSC::GetByIdStatus::computeForStubInfo):
+ (JSC::GetByIdStatus::computeFor):
+ * bytecode/GetByIdStatus.h:
+ * bytecode/PutByIdStatus.cpp:
+ (JSC::PutByIdStatus::computeFor):
+ * bytecode/PutByIdStatus.h:
+ * bytecode/PutByIdVariant.h:
+ (JSC::PutByIdVariant::constantChecks):
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ (JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
+ (JSC::DFG::ConstantFoldingPhase::addChecks):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::convertToMultiGetByOffset):
+ (JSC::DFG::Node::convertToMultiPutByOffset):
+ * dfg/DFGSpeculativeJIT64.cpp: Also convert all release assertions to DFG assertions in this file, because I was hitting some of them while debugging.
+ (JSC::DFG::SpeculativeJIT::fillJSValue):
+ (JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull):
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Strict):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateInt52):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
+ (JSC::DFG::SpeculativeJIT::compileLogicalNot):
+ (JSC::DFG::SpeculativeJIT::emitBranch):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGStructureAbstractValue.h:
+ (JSC::DFG::StructureAbstractValue::set):
+
+ 2014-06-19 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] StructureSet::onlyStructure() should return nullptr if it's not a singleton (instead of asserting)
+ https://bugs.webkit.org/show_bug.cgi?id=134077
+
+ Reviewed by Sam Weinig.
+
+ This makes StructureSet and StructureAbstractValue more consistent and fixes a debug assert
+ in the abstract interpreter.
+
+ * bytecode/StructureSet.h:
+ (JSC::StructureSet::onlyStructure):
+
+ 2014-06-18 Filip Pizlo <fpizlo@apple.com>
+
+ DFG AI and constant folder should be able to precisely prune MultiGetByOffset/MultiPutByOffset even if the base structure abstract value is not a singleton
+ https://bugs.webkit.org/show_bug.cgi?id=133918
+
+ Reviewed by Mark Hahnenberg.
+
+ This also adds pruning of PutStructure, since I basically had no choice but
+ to implement such logic within MultiPutByOffset.
+
+ Also adds a bunch of PutById cache status dumping to bytecode dumping.
+
+ * bytecode/GetByIdVariant.cpp:
+ (JSC::GetByIdVariant::dumpInContext):
+ * bytecode/GetByIdVariant.h:
+ (JSC::GetByIdVariant::structureSet):
+ * bytecode/PutByIdVariant.h:
+ (JSC::PutByIdVariant::oldStructure):
+ * bytecode/StructureSet.cpp:
+ (JSC::StructureSet::filter):
+ (JSC::StructureSet::filterArrayModes):
+ * bytecode/StructureSet.h:
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGAbstractValue.cpp:
+ (JSC::DFG::AbstractValue::changeStructure):
+ (JSC::DFG::AbstractValue::contains):
+ * dfg/DFGAbstractValue.h:
+ (JSC::DFG::AbstractValue::couldBeType):
+ (JSC::DFG::AbstractValue::isType):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ (JSC::DFG::ConstantFoldingPhase::emitGetByOffset):
+ (JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
+ (JSC::DFG::ConstantFoldingPhase::addBaseCheck):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::freezeStrong):
+ * dfg/DFGGraph.h:
+ * dfg/DFGStructureAbstractValue.h:
+ (JSC::DFG::StructureAbstractValue::operator=):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
+ * tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (baz):
+ (.bar):
+ (.baz):
+ * tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (baz):
+ (.bar):
+ (.baz):
+ * tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js: Added.
+ (foo):
+ (fu):
+ (bar):
+ (baz):
+ (.bar):
+ (.baz):
+
+ 2014-06-18 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ Remove CompoundType and LeafType
+ https://bugs.webkit.org/show_bug.cgi?id=134037
+
+ Reviewed by Filip Pizlo.
+
+ We don't use them for anything. We'll replace them with a generic CellType type for all
+ the objects that are JSCells, aren't JSObjects, and for which we generally don't care about
+ their JSType at runtime.
+
+ * llint/LLIntData.cpp:
+ (JSC::LLInt::Data::performAssertions):
+ * runtime/ArrayBufferNeuteringWatchpoint.cpp:
+ (JSC::ArrayBufferNeuteringWatchpoint::createStructure):
+ * runtime/Executable.h:
+ (JSC::ExecutableBase::createStructure):
+ (JSC::NativeExecutable::createStructure):
+ * runtime/JSPromiseDeferred.h:
+ (JSC::JSPromiseDeferred::createStructure):
+ * runtime/JSPromiseReaction.h:
+ (JSC::JSPromiseReaction::createStructure):
+ * runtime/JSPropertyNameIterator.h:
+ (JSC::JSPropertyNameIterator::createStructure):
+ * runtime/JSType.h:
+ * runtime/JSTypeInfo.h:
+ (JSC::TypeInfo::TypeInfo):
+ * runtime/MapData.h:
+ (JSC::MapData::createStructure):
+ * runtime/PropertyMapHashTable.h:
+ (JSC::PropertyTable::createStructure):
+ * runtime/RegExp.h:
+ (JSC::RegExp::createStructure):
+ * runtime/SparseArrayValueMap.cpp:
+ (JSC::SparseArrayValueMap::createStructure):
+ * runtime/Structure.cpp:
+ (JSC::Structure::Structure):
+ * runtime/StructureChain.h:
+ (JSC::StructureChain::createStructure):
+ * runtime/StructureRareData.cpp:
+ (JSC::StructureRareData::createStructure):
+ * runtime/SymbolTable.h:
+ (JSC::SymbolTable::createStructure):
+ * runtime/WeakMapData.h:
+ (JSC::WeakMapData::createStructure):
+
+ 2014-06-17 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] PutStructure and PhantomPutStructure shouldn't leave the world in a clobbered state
+ https://bugs.webkit.org/show_bug.cgi?id=134002
+
+ Reviewed by Mark Hahnenberg.
+
+ The effect of this bug was that if we had a PutStructure or PhantomPutStructure then any
+ JSConstants would be in a Clobbered state, so we wouldn't take advantage of our knowledge
+ of the structure if that structure was watchable.
+
+ Also kill PhantomPutStructure.
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransition):
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::visitChildren):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasTransition):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGStructureAbstractValue.cpp:
+ (JSC::DFG::StructureAbstractValue::observeTransition):
+ (JSC::DFG::StructureAbstractValue::observeTransitions):
+ * dfg/DFGValidate.cpp:
+ (JSC::DFG::Validate::validate):
+ * dfg/DFGWatchableStructureWatchingPhase.cpp:
+ (JSC::DFG::WatchableStructureWatchingPhase::run):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileNode):
+ (JSC::FTL::LowerDFGToLLVM::compilePhantomPutStructure): Deleted.
+
+ 2014-06-17 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] DFG put_by_id should inline accesses with a slightly polymorphic base
+ https://bugs.webkit.org/show_bug.cgi?id=133964
+
+ Reviewed by Mark Hahnenberg.
+
+ * bytecode/PutByIdStatus.cpp:
+ (JSC::PutByIdStatus::appendVariant):
+ (JSC::PutByIdStatus::computeForStubInfo):
+ * bytecode/PutByIdVariant.cpp:
+ (JSC::PutByIdVariant::oldStructureForTransition):
+ (JSC::PutByIdVariant::writesStructures):
+ (JSC::PutByIdVariant::reallocatesStorage):
+ (JSC::PutByIdVariant::attemptToMerge):
+ (JSC::PutByIdVariant::attemptToMergeTransitionWithReplace):
+ (JSC::PutByIdVariant::dumpInContext):
+ * bytecode/PutByIdVariant.h:
+ (JSC::PutByIdVariant::PutByIdVariant):
+ (JSC::PutByIdVariant::replace):
+ (JSC::PutByIdVariant::transition):
+ (JSC::PutByIdVariant::structure):
+ (JSC::PutByIdVariant::oldStructure):
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handlePutById):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ (JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::visitChildren):
+ * dfg/DFGNode.cpp:
+ (JSC::DFG::MultiPutByOffsetData::writesStructures):
+ (JSC::DFG::MultiPutByOffsetData::reallocatesStorage):
+ * ftl/FTLAbbreviations.h:
+ (JSC::FTL::getLinkage):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset):
+ (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol):
+
+2014-07-25 Filip Pizlo <fpizlo@apple.com>
+
Add an option to disable native call inlining. Disable it for now to see how it
affects the bots.
<ClCompile Include="..\bytecode\StructureSet.cpp" />
<ClCompile Include="..\bytecode\StructureStubClearingWatchpoint.cpp" />
<ClCompile Include="..\bytecode\StructureStubInfo.cpp" />
+ <ClCompile Include="..\bytecode\ToThisStatus.cpp" />
<ClCompile Include="..\bytecode\UnlinkedCodeBlock.cpp" />
<ClCompile Include="..\bytecode\UnlinkedInstructionStream.cpp" />
<ClCompile Include="..\bytecode\ValueRecovery.cpp" />
<ClCompile Include="..\bytecompiler\BytecodeGenerator.cpp" />
<ClCompile Include="..\bytecompiler\NodesCodegen.cpp" />
<ClCompile Include="..\debugger\Debugger.cpp" />
- <ClCompile Include="..\debugger\DebuggerActivation.cpp" />
<ClCompile Include="..\debugger\DebuggerCallFrame.cpp" />
+ <ClCompile Include="..\debugger\DebuggerScope.cpp" />
<ClCompile Include="..\dfg\DFGAbstractHeap.cpp" />
<ClCompile Include="..\dfg\DFGAbstractValue.cpp" />
<ClCompile Include="..\dfg\DFGArgumentsSimplificationPhase.cpp" />
<ClInclude Include="..\bytecode\StructureSet.h" />
<ClInclude Include="..\bytecode\StructureStubClearingWatchpoint.h" />
<ClInclude Include="..\bytecode\StructureStubInfo.h" />
+ <ClInclude Include="..\bytecode\ToThisStatus.h" />
<ClInclude Include="..\bytecode\UnlinkedCodeBlock.h" />
<ClInclude Include="..\bytecode\UnlinkedInstructionStream.h" />
<ClInclude Include="..\bytecode\ValueProfile.h" />
<ClInclude Include="..\config.h" />
<ClInclude Include="..\debugger\Breakpoint.h" />
<ClInclude Include="..\debugger\Debugger.h" />
- <ClInclude Include="..\debugger\DebuggerActivation.h" />
<ClInclude Include="..\debugger\DebuggerCallFrame.h" />
<ClInclude Include="..\debugger\DebuggerPrimitives.h" />
+ <ClInclude Include="..\debugger\DebuggerScope.h" />
<ClInclude Include="..\dfg\DFGAbstractHeap.h" />
<ClInclude Include="..\dfg\DFGAbstractInterpreter.h" />
<ClInclude Include="..\dfg\DFGAbstractInterpreterInlines.h" />
<ClCompile Include="..\debugger\Debugger.cpp">
<Filter>debugger</Filter>
</ClCompile>
- <ClCompile Include="..\debugger\DebuggerActivation.cpp">
+ <ClCompile Include="..\debugger\DebuggerCallFrame.cpp">
<Filter>debugger</Filter>
</ClCompile>
- <ClCompile Include="..\debugger\DebuggerCallFrame.cpp">
+ <ClCompile Include="..\debugger\DebuggerScope.cpp">
<Filter>debugger</Filter>
</ClCompile>
<ClCompile Include="..\disassembler\Disassembler.cpp">
<ClInclude Include="..\debugger\Debugger.h">
<Filter>debugger</Filter>
</ClInclude>
- <ClInclude Include="..\debugger\DebuggerActivation.h">
- <Filter>debugger</Filter>
- </ClInclude>
<ClInclude Include="..\debugger\DebuggerCallFrame.h">
<Filter>debugger</Filter>
</ClInclude>
<ClInclude Include="..\debugger\DebuggerPrimitives.h">
<Filter>debugger</Filter>
</ClInclude>
+ <ClInclude Include="..\debugger\DebuggerScope.h">
+ <Filter>debugger</Filter>
+ </ClInclude>
<ClInclude Include="..\dfg\DFGDriver.h">
<Filter>dfg</Filter>
</ClInclude>
0F2BDC4D1522818600CD8910 /* DFGMinifiedNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */; };
0F2BDC4F15228BF300CD8910 /* DFGValueSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */; };
0F2BDC5115228FFD00CD8910 /* DFGVariableEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */; };
+ 0F2D4DDD19832D34007D4B19 /* DebuggerScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DDB19832D34007D4B19 /* DebuggerScope.cpp */; };
+ 0F2D4DDE19832D34007D4B19 /* DebuggerScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DDC19832D34007D4B19 /* DebuggerScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F2D4DE819832DAC007D4B19 /* ToThisStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DE519832DAC007D4B19 /* ToThisStatus.cpp */; };
+ 0F2D4DE919832DAC007D4B19 /* ToThisStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DE619832DAC007D4B19 /* ToThisStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F2D4DEA19832DAC007D4B19 /* TypeLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DE719832DAC007D4B19 /* TypeLocation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F2D4DEB19832DC4007D4B19 /* HighFidelityLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DDF19832D91007D4B19 /* HighFidelityLog.cpp */; };
+ 0F2D4DEC19832DC4007D4B19 /* HighFidelityLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DE019832D91007D4B19 /* HighFidelityLog.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F2D4DED19832DC4007D4B19 /* HighFidelityTypeProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DE119832D91007D4B19 /* HighFidelityTypeProfiler.cpp */; };
+ 0F2D4DEE19832DC4007D4B19 /* HighFidelityTypeProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DE219832D91007D4B19 /* HighFidelityTypeProfiler.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F2D4DEF19832DD3007D4B19 /* TypeSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DE319832D91007D4B19 /* TypeSet.cpp */; };
+ 0F2D4DF019832DD6007D4B19 /* TypeSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DE419832D91007D4B19 /* TypeSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F2E892C16D028AD009E4FD2 /* UnusedPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 65987F2F16828A7E003C2F8D /* UnusedPointer.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F2E892D16D02BAF009E4FD2 /* DFGMinifiedID.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51016B3A964003F696B /* DFGMinifiedID.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F2FC77216E12F710038D976 /* DFGDCEPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */; };
BC18C52E0E16FCE100B34460 /* Lexer.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C52D0E16FCE100B34460 /* Lexer.lut.h */; };
BC257DE80E1F51C50016B6C9 /* Arguments.h in Headers */ = {isa = PBXBuildFile; fileRef = BC257DE60E1F51C50016B6C9 /* Arguments.h */; };
BC3046070E1F497F003232CF /* Error.h in Headers */ = {isa = PBXBuildFile; fileRef = BC3046060E1F497F003232CF /* Error.h */; settings = {ATTRIBUTES = (Private, ); }; };
- BC3135640F302FA3003DFD3A /* DebuggerActivation.h in Headers */ = {isa = PBXBuildFile; fileRef = BC3135620F302FA3003DFD3A /* DebuggerActivation.h */; settings = {ATTRIBUTES = (Private, ); }; };
- BC3135650F302FA3003DFD3A /* DebuggerActivation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC3135630F302FA3003DFD3A /* DebuggerActivation.cpp */; };
BC6AAAE50E1F426500AD87D8 /* ClassInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC756FC90E2031B200DE7D12 /* JSGlobalObjectFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = BC756FC70E2031B200DE7D12 /* JSGlobalObjectFunctions.h */; };
BC87CDB910712AD4000614CF /* JSONObject.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC87CDB810712ACA000614CF /* JSONObject.lut.h */; };
0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMinifiedNode.cpp; path = dfg/DFGMinifiedNode.cpp; sourceTree = "<group>"; };
0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGValueSource.cpp; path = dfg/DFGValueSource.cpp; sourceTree = "<group>"; };
0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableEvent.cpp; path = dfg/DFGVariableEvent.cpp; sourceTree = "<group>"; };
+ 0F2D4DDB19832D34007D4B19 /* DebuggerScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerScope.cpp; sourceTree = "<group>"; };
+ 0F2D4DDC19832D34007D4B19 /* DebuggerScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerScope.h; sourceTree = "<group>"; };
+ 0F2D4DDF19832D91007D4B19 /* HighFidelityLog.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HighFidelityLog.cpp; sourceTree = "<group>"; };
+ 0F2D4DE019832D91007D4B19 /* HighFidelityLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HighFidelityLog.h; sourceTree = "<group>"; };
+ 0F2D4DE119832D91007D4B19 /* HighFidelityTypeProfiler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HighFidelityTypeProfiler.cpp; sourceTree = "<group>"; };
+ 0F2D4DE219832D91007D4B19 /* HighFidelityTypeProfiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HighFidelityTypeProfiler.h; sourceTree = "<group>"; };
+ 0F2D4DE319832D91007D4B19 /* TypeSet.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeSet.cpp; sourceTree = "<group>"; };
+ 0F2D4DE419832D91007D4B19 /* TypeSet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TypeSet.h; sourceTree = "<group>"; };
+ 0F2D4DE519832DAC007D4B19 /* ToThisStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ToThisStatus.cpp; sourceTree = "<group>"; };
+ 0F2D4DE619832DAC007D4B19 /* ToThisStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ToThisStatus.h; sourceTree = "<group>"; };
+ 0F2D4DE719832DAC007D4B19 /* TypeLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeLocation.h; sourceTree = "<group>"; };
0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDCEPhase.cpp; path = dfg/DFGDCEPhase.cpp; sourceTree = "<group>"; };
0F2FC77116E12F6F0038D976 /* DFGDCEPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDCEPhase.h; path = dfg/DFGDCEPhase.h; sourceTree = "<group>"; };
0F2FCCF218A60070001A27F8 /* DFGGraphSafepoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGGraphSafepoint.cpp; path = dfg/DFGGraphSafepoint.cpp; sourceTree = "<group>"; };
BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPrototype.h; sourceTree = "<group>"; };
BC2680E60E16D52300A06E92 /* NumberConstructor.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NumberConstructor.lut.h; sourceTree = "<group>"; };
BC3046060E1F497F003232CF /* Error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Error.h; sourceTree = "<group>"; };
- BC3135620F302FA3003DFD3A /* DebuggerActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerActivation.h; sourceTree = "<group>"; };
- BC3135630F302FA3003DFD3A /* DebuggerActivation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerActivation.cpp; sourceTree = "<group>"; };
BC337BDE0E1AF0B80076918A /* GetterSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetterSetter.h; sourceTree = "<group>"; };
BC337BEA0E1B00CB0076918A /* Error.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Error.cpp; sourceTree = "<group>"; };
BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClassInfo.h; sourceTree = "<group>"; };
FEA0861E182B7A0400F6D851 /* Breakpoint.h */,
F692A8580255597D01FF60F7 /* Debugger.cpp */,
F692A8590255597D01FF60F7 /* Debugger.h */,
- BC3135630F302FA3003DFD3A /* DebuggerActivation.cpp */,
- BC3135620F302FA3003DFD3A /* DebuggerActivation.h */,
149559ED0DDCDDF700648087 /* DebuggerCallFrame.cpp */,
1480DB9B0DDC227F003CFDF2 /* DebuggerCallFrame.h */,
FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */,
+ 0F2D4DDB19832D34007D4B19 /* DebuggerScope.cpp */,
+ 0F2D4DDC19832D34007D4B19 /* DebuggerScope.h */,
);
path = debugger;
sourceTree = "<group>";
7EF6E0BB0EB7A1EC0079AFAF /* runtime */ = {
isa = PBXGroup;
children = (
- 9E72940A190F0514001A91B5 /* BundlePath.h */,
- 9E729409190F0306001A91B5 /* BundlePath.mm */,
BCF605110E203EF800B9A64D /* ArgList.cpp */,
BCF605120E203EF800B9A64D /* ArgList.h */,
BC257DE50E1F51C50016B6C9 /* Arguments.cpp */,
704FD35305697E6D003DBED9 /* BooleanObject.h */,
BC7952340E15EB5600A898AB /* BooleanPrototype.cpp */,
BC7952350E15EB5600A898AB /* BooleanPrototype.h */,
+ 9E72940A190F0514001A91B5 /* BundlePath.h */,
+ 9E729409190F0306001A91B5 /* BundlePath.mm */,
0FB7F38B15ED8E3800F167B2 /* Butterfly.h */,
0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */,
BCA62DFE0E2826230004F30D /* CallData.cpp */,
0F2B66B317B6B5AB00A7AE3F /* GenericTypedArrayViewInlines.h */,
BC02E9B80E184545000F9297 /* GetterSetter.cpp */,
BC337BDE0E1AF0B80076918A /* GetterSetter.h */,
+ 0F2D4DDF19832D91007D4B19 /* HighFidelityLog.cpp */,
+ 0F2D4DE019832D91007D4B19 /* HighFidelityLog.h */,
+ 0F2D4DE119832D91007D4B19 /* HighFidelityTypeProfiler.cpp */,
+ 0F2D4DE219832D91007D4B19 /* HighFidelityTypeProfiler.h */,
933A349D038AE80F008635CE /* Identifier.cpp */,
933A349A038AE7C6008635CE /* Identifier.h */,
8606DDE918DA44AB00A383D0 /* IdentifierInlines.h */,
0FB7F38F15ED8E3800F167B2 /* IndexingType.h */,
E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */,
E178633F0D9BEC0000D74E75 /* InitializeThreading.h */,
- A7A8AF2B17ADB5F3005AB174 /* Int8Array.h */,
A7A8AF2C17ADB5F3005AB174 /* Int16Array.h */,
A7A8AF2D17ADB5F3005AB174 /* Int32Array.h */,
+ A7A8AF2B17ADB5F3005AB174 /* Int8Array.h */,
A78853F717972629001440E4 /* IntendedStructureChain.cpp */,
A78853F817972629001440E4 /* IntendedStructureChain.h */,
BC9BB95B0E19680600DF8855 /* InternalFunction.cpp */,
A59455911824744700CC3843 /* JSGlobalObjectDebuggable.h */,
BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */,
BC756FC70E2031B200DE7D12 /* JSGlobalObjectFunctions.h */,
- 0F2B66C917B6B5AB00A7AE3F /* JSInt8Array.h */,
0F2B66CA17B6B5AB00A7AE3F /* JSInt16Array.h */,
0F2B66CB17B6B5AB00A7AE3F /* JSInt32Array.h */,
+ 0F2B66C917B6B5AB00A7AE3F /* JSInt8Array.h */,
65EA4C99092AF9E20093D800 /* JSLock.cpp */,
65EA4C9A092AF9E20093D800 /* JSLock.h */,
A700873F17CBE8EB00C3E643 /* JSMap.cpp */,
0F2B66D017B6B5AB00A7AE3F /* JSTypedArrays.cpp */,
0F2B66D117B6B5AB00A7AE3F /* JSTypedArrays.h */,
6507D2970E871E4A00D7D896 /* JSTypeInfo.h */,
- 0F2B66D217B6B5AB00A7AE3F /* JSUint8Array.h */,
- 0F2B66D317B6B5AB00A7AE3F /* JSUint8ClampedArray.h */,
0F2B66D417B6B5AB00A7AE3F /* JSUint16Array.h */,
0F2B66D517B6B5AB00A7AE3F /* JSUint32Array.h */,
+ 0F2B66D217B6B5AB00A7AE3F /* JSUint8Array.h */,
+ 0F2B66D317B6B5AB00A7AE3F /* JSUint8ClampedArray.h */,
BC22A39A0E16E14800AF21C8 /* JSVariableObject.cpp */,
14F252560D08DD8D004ECFFF /* JSVariableObject.h */,
A7CA3AE117DA41AE006538AF /* JSWeakMap.cpp */,
0F2B66DB17B6B5AB00A7AE3F /* TypedArrays.h */,
0F2B66DC17B6B5AB00A7AE3F /* TypedArrayType.cpp */,
0F2B66DD17B6B5AB00A7AE3F /* TypedArrayType.h */,
- A7A8AF3017ADB5F3005AB174 /* Uint8Array.h */,
- A7A8AF3117ADB5F3005AB174 /* Uint8ClampedArray.h */,
+ 0F2D4DE319832D91007D4B19 /* TypeSet.cpp */,
+ 0F2D4DE419832D91007D4B19 /* TypeSet.h */,
A7A8AF3217ADB5F3005AB174 /* Uint16Array.h */,
866739D113BFDE710023D87C /* Uint16WithFraction.h */,
A7A8AF3317ADB5F3005AB174 /* Uint32Array.h */,
+ A7A8AF3017ADB5F3005AB174 /* Uint8Array.h */,
+ A7A8AF3117ADB5F3005AB174 /* Uint8ClampedArray.h */,
E18E3A570DF9278C00D90B34 /* VM.cpp */,
E18E3A560DF9278C00D90B34 /* VM.h */,
FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */,
0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */,
BCCF0D0B0EF0B8A500413C8F /* StructureStubInfo.cpp */,
BCCF0D070EF0AAB900413C8F /* StructureStubInfo.h */,
+ 0F2D4DE519832DAC007D4B19 /* ToThisStatus.cpp */,
+ 0F2D4DE619832DAC007D4B19 /* ToThisStatus.h */,
+ 0F2D4DE719832DAC007D4B19 /* TypeLocation.h */,
A79E781E15EECBA80047C855 /* UnlinkedCodeBlock.cpp */,
A79E781F15EECBA80047C855 /* UnlinkedCodeBlock.h */,
B59F89381891ADB500D5CCDC /* UnlinkedInstructionStream.cpp */,
BCD2034C0E17135E002C7E82 /* DatePrototype.h in Headers */,
BCD203E80E1718F4002C7E82 /* DatePrototype.lut.h in Headers */,
BC18C3FA0E16F5CD00B34460 /* Debugger.h in Headers */,
- BC3135640F302FA3003DFD3A /* DebuggerActivation.h in Headers */,
BC18C3FB0E16F5CD00B34460 /* DebuggerCallFrame.h in Headers */,
FEA08621182B7A0400F6D851 /* DebuggerPrimitives.h in Headers */,
0F136D4D174AD69E0075B354 /* DeferGC.h in Headers */,
C283190016FE4B7D00157BFD /* HandleBlock.h in Headers */,
C283190216FE533E00157BFD /* HandleBlockInlines.h in Headers */,
0F0B83A914BCF56200885B4F /* HandlerInfo.h in Headers */,
+ 0F2D4DEC19832DC4007D4B19 /* HighFidelityLog.h in Headers */,
142E3136134FF0A600AFADB5 /* HandleSet.h in Headers */,
142E3138134FF0A600AFADB5 /* HandleStack.h in Headers */,
1478297B1379E8A800A7C2A3 /* HandleTypes.h in Headers */,
A53243981856A489002ED692 /* InspectorJS.json in Headers */,
A532438818568335002ED692 /* InspectorJSBackendDispatchers.h in Headers */,
A532438A18568335002ED692 /* InspectorJSFrontendDispatchers.h in Headers */,
+ 0F2D4DEE19832DC4007D4B19 /* HighFidelityTypeProfiler.h in Headers */,
8606DDEA18DA44AB00A383D0 /* IdentifierInlines.h in Headers */,
A532438C18568335002ED692 /* InspectorJSTypeBuilders.h in Headers */,
A50E4B6218809DD50068A46D /* InspectorRuntimeAgent.h in Headers */,
0F2B66EA17B6B5AB00A7AE3F /* JSArrayBufferViewInlines.h in Headers */,
A7BDAECB17F4EA1400F6140C /* JSArrayIterator.h in Headers */,
BC18C4180E16F5CD00B34460 /* JSBase.h in Headers */,
+ 0F2D4DE919832DAC007D4B19 /* ToThisStatus.h in Headers */,
140D17D70E8AD4A9000CD17D /* JSBasePrivate.h in Headers */,
86FA9E92142BBB2E001773B7 /* JSBoundFunction.h in Headers */,
BC18C4190E16F5CD00B34460 /* JSCallbackConstructor.h in Headers */,
6507D29E0E871E5E00D7D896 /* JSTypeInfo.h in Headers */,
0F2B670217B6B5AB00A7AE3F /* JSUint16Array.h in Headers */,
0F2B670317B6B5AB00A7AE3F /* JSUint32Array.h in Headers */,
+ 0F2D4DF019832DD6007D4B19 /* TypeSet.h in Headers */,
0F2B670017B6B5AB00A7AE3F /* JSUint8Array.h in Headers */,
0F2B670117B6B5AB00A7AE3F /* JSUint8ClampedArray.h in Headers */,
86E3C612167BABD7006D760A /* JSValue.h in Headers */,
969A079B0ED1D3AE00F1F681 /* Opcode.h in Headers */,
0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */,
A70447EA17A0BD4600F5898E /* OperandsInlines.h in Headers */,
+ 0F2D4DDE19832D34007D4B19 /* DebuggerScope.h in Headers */,
BC18C4480E16F5CD00B34460 /* Operations.h in Headers */,
0FE228ED1436AB2700196C48 /* Options.h in Headers */,
BC18C44B0E16F5CD00B34460 /* Parser.h in Headers */,
0F50AF3C193E8B3900674EE8 /* DFGStructureClobberState.h in Headers */,
A57D23EE1891B5540031C7FA /* RegularExpression.h in Headers */,
0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */,
+ 0F2D4DEA19832DAC007D4B19 /* TypeLocation.h in Headers */,
A5BA15E8182340B300A82E69 /* RemoteInspector.h in Headers */,
A5BA15EA182340B400A82E69 /* RemoteInspectorConstants.h in Headers */,
A5BA15F0182345AF00A82E69 /* RemoteInspectorDebuggable.h in Headers */,
147F39C5107EC37600427A48 /* DateInstance.cpp in Sources */,
147F39C6107EC37600427A48 /* DatePrototype.cpp in Sources */,
14280823107EC02C0013E7B2 /* Debugger.cpp in Sources */,
- BC3135650F302FA3003DFD3A /* DebuggerActivation.cpp in Sources */,
149559EE0DDCDDF700648087 /* DebuggerCallFrame.cpp in Sources */,
2A7A58EF1808A4C40020BDF7 /* DeferGC.cpp in Sources */,
0FC712DE17CD8779008CC93C /* DeferredCompilationCallback.cpp in Sources */,
0F55C19417276E4600CEABFD /* DFGAbstractValue.cpp in Sources */,
0F16015D156198C900C2587C /* DFGArgumentsSimplificationPhase.cpp in Sources */,
0F485321187750560083B687 /* DFGArithMode.cpp in Sources */,
+ 0F2D4DDD19832D34007D4B19 /* DebuggerScope.cpp in Sources */,
0F63948415E48118006A597C /* DFGArrayMode.cpp in Sources */,
+ 0F2D4DED19832DC4007D4B19 /* HighFidelityTypeProfiler.cpp in Sources */,
A7D9A29417A0BC7400EE2618 /* DFGAtTailAbstractState.cpp in Sources */,
0F666EC61835672B00D017F1 /* DFGAvailability.cpp in Sources */,
0F714CA416EA92F000F3EBEB /* DFGBackwardsPropagationPhase.cpp in Sources */,
A7B48F490EE8936F00DCBDB6 /* ExecutableAllocator.cpp in Sources */,
86DB64640F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp in Sources */,
0F56A1D515001CF4002992B1 /* ExecutionCounter.cpp in Sources */,
+ 0F2D4DEB19832DC4007D4B19 /* HighFidelityLog.cpp in Sources */,
0F0332C018ADFAE1005F979A /* ExitingJITType.cpp in Sources */,
0FB105851675480F00F8AB6E /* ExitKind.cpp in Sources */,
0FEA0A1C1708B00700BB722C /* FTLAbstractHeap.cpp in Sources */,
A72028B61797601E0098028C /* JSCTestRunnerUtils.cpp in Sources */,
0F2B66EB17B6B5AB00A7AE3F /* JSDataView.cpp in Sources */,
0F2B66ED17B6B5AB00A7AE3F /* JSDataViewPrototype.cpp in Sources */,
+ 0F2D4DE819832DAC007D4B19 /* ToThisStatus.cpp in Sources */,
978801401471AD920041B016 /* JSDateMath.cpp in Sources */,
140566D6107EC271005DBC8D /* JSFunction.cpp in Sources */,
147F39D2107EC37600427A48 /* JSGlobalObject.cpp in Sources */,
14469DEB107EC7E700650446 /* StringConstructor.cpp in Sources */,
14469DEC107EC7E700650446 /* StringObject.cpp in Sources */,
14469DED107EC7E700650446 /* StringPrototype.cpp in Sources */,
+ 0F2D4DEF19832DD3007D4B19 /* TypeSet.cpp in Sources */,
9335F24D12E6765B002B5553 /* StringRecursionChecker.cpp in Sources */,
BCDE3B430E6C832D001453A7 /* Structure.cpp in Sources */,
7E4EE70F0EBB7A5B005934AA /* StructureChain.cpp in Sources */,
{ "name" : "op_create_arguments", "length" : 2 },
{ "name" : "op_create_this", "length" : 4 },
{ "name" : "op_get_callee", "length" : 3 },
- { "name" : "op_to_this", "length" : 3 },
+ { "name" : "op_to_this", "length" : 4 },
{ "name" : "op_new_object", "length" : 4 },
{ "name" : "op_new_array", "length" : 5 },
{ "name" : "op_new_array_with_size", "length" : 4 },
{ "name" : "op_resolve_scope", "length" : 6 },
{ "name" : "op_get_from_scope", "length" : 8 },
{ "name" : "op_put_to_scope", "length" : 7 },
+ { "name" : "op_put_to_scope_with_profile", "length" : 8 },
{ "name" : "op_push_with_scope", "length" : 2 },
{ "name" : "op_pop_scope", "length" : 1 },
{ "name" : "op_push_name_scope", "length" : 4 },
{ "name" : "op_debug", "length" : 3 },
{ "name" : "op_profile_will_call", "length" : 2 },
{ "name" : "op_profile_did_call", "length" : 2 },
- { "name" : "op_end", "length" : 2 }
+ { "name" : "op_end", "length" : 2 },
+ { "name" : "op_profile_types_with_high_fidelity", "length" : 4 }
]
},
{
case op_tear_off_activation:
case op_profile_will_call:
case op_profile_did_call:
+ case op_profile_types_with_high_fidelity:
case op_throw:
case op_push_with_scope:
case op_end:
case op_put_by_id_transition_normal_out_of_line:
case op_put_by_id_out_of_line:
case op_put_by_id:
+ case op_put_to_scope_with_profile:
case op_put_to_scope: {
functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
case op_push_name_scope:
case op_push_with_scope:
case op_put_to_scope:
+ case op_put_to_scope_with_profile:
case op_pop_scope:
case op_end:
case op_profile_will_call:
case op_put_by_val_direct:
case op_put_by_index:
case op_tear_off_arguments:
+ case op_profile_types_with_high_fidelity:
case op_touch_entry:
#define LLINT_HELPER_OPCODES(opcode, length) case opcode:
FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES);
#include "DFGJITCode.h"
#include "DFGWorklist.h"
#include "Debugger.h"
+#include "HighFidelityTypeProfiler.h"
#include "Interpreter.h"
#include "JIT.h"
#include "JITStubs.h"
#include "JSFunction.h"
#include "JSNameScope.h"
#include "LLIntEntrypoint.h"
+#include "TypeLocation.h"
#include "LowLevelInterpreter.h"
#include "JSCInlines.h"
#include "PolymorphicGetByIdList.h"
#endif
}
+void CodeBlock::printPutByIdCacheStatus(PrintStream& out, ExecState* exec, int location, const StubInfoMap& map)
+{
+ Instruction* instruction = instructions().begin() + location;
+
+ const Identifier& ident = identifier(instruction[2].u.operand);
+
+ UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations.
+
+#if ENABLE(LLINT)
+ if (Structure* structure = instruction[4].u.structure.get()) {
+ switch (exec->interpreter()->getOpcodeID(instruction[0].u.opcode)) {
+ case op_put_by_id:
+ case op_put_by_id_out_of_line:
+ out.print(" llint(");
+ dumpStructure(out, "struct", exec, structure, ident);
+ out.print(")");
+ break;
+
+ case op_put_by_id_transition_direct:
+ case op_put_by_id_transition_normal:
+ case op_put_by_id_transition_direct_out_of_line:
+ case op_put_by_id_transition_normal_out_of_line:
+ out.print(" llint(");
+ dumpStructure(out, "prev", exec, structure, ident);
+ out.print(", ");
+ dumpStructure(out, "next", exec, instruction[6].u.structure.get(), ident);
+ if (StructureChain* chain = instruction[7].u.structureChain.get()) {
+ out.print(", ");
+ dumpChain(out, exec, chain, ident);
+ }
+ out.print(")");
+ break;
+
+ default:
+ out.print(" llint(unknown)");
+ break;
+ }
+ }
+#endif
+
+#if ENABLE(JIT)
+ if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) {
+ StructureStubInfo& stubInfo = *stubPtr;
+ if (stubInfo.resetByGC)
+ out.print(" (Reset By GC)");
+
+ if (stubInfo.seen) {
+ out.printf(" jit(");
+
+ switch (stubInfo.accessType) {
+ case access_put_by_id_replace:
+ out.print("replace, ");
+ dumpStructure(out, "struct", exec, stubInfo.u.putByIdReplace.baseObjectStructure.get(), ident);
+ break;
+ case access_put_by_id_transition_normal:
+ case access_put_by_id_transition_direct:
+ out.print("transition, ");
+ dumpStructure(out, "prev", exec, stubInfo.u.putByIdTransition.previousStructure.get(), ident);
+ out.print(", ");
+ dumpStructure(out, "next", exec, stubInfo.u.putByIdTransition.structure.get(), ident);
+ if (StructureChain* chain = stubInfo.u.putByIdTransition.chain.get()) {
+ out.print(", ");
+ dumpChain(out, exec, chain, ident);
+ }
+ break;
+ case access_put_by_id_list: {
+ out.printf("list = [");
+ PolymorphicPutByIdList* list = stubInfo.u.putByIdList.list;
+ CommaPrinter comma;
+ for (unsigned i = 0; i < list->size(); ++i) {
+ out.print(comma, "(");
+ const PutByIdAccess& access = list->at(i);
+
+ if (access.isReplace()) {
+ out.print("replace, ");
+ dumpStructure(out, "struct", exec, access.oldStructure(), ident);
+ } else if (access.isSetter()) {
+ out.print("setter, ");
+ dumpStructure(out, "struct", exec, access.oldStructure(), ident);
+ } else if (access.isCustom()) {
+ out.print("custom, ");
+ dumpStructure(out, "struct", exec, access.oldStructure(), ident);
+ } else if (access.isTransition()) {
+ out.print("transition, ");
+ dumpStructure(out, "prev", exec, access.oldStructure(), ident);
+ out.print(", ");
+ dumpStructure(out, "next", exec, access.newStructure(), ident);
+ if (access.chain()) {
+ out.print(", ");
+ dumpChain(out, exec, access.chain(), ident);
+ }
+ } else
+ out.print("unknown");
+
+ out.print(")");
+ }
+ out.print("]");
+ break;
+ }
+ case access_unset:
+ out.printf("unset");
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ out.printf(")");
+ }
+ }
+#else
+ UNUSED_PARAM(map);
+#endif
+}
+
void CodeBlock::printCallOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op, CacheDumpMode cacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap& map)
{
int dst = (++it)->u.operand;
Structure* structure = (++it)->u.structure.get();
if (structure)
out.print(" cache(struct = ", RawPointer(structure), ")");
+ out.print(" ", (++it)->u.toThisStatus);
break;
}
case op_new_object: {
++it;
break;
}
+ case op_profile_types_with_high_fidelity: {
+ int r0 = (++it)->u.operand;
+ ++it;
+ ++it;
+ printLocationAndOp(out, exec, location, it, "op_profile_types_with_high_fidelity");
+ out.printf("%s", registerName(r0).data());
+ break;
+ }
case op_not: {
printUnaryOp(out, exec, location, it, "not");
break;
}
case op_put_by_id: {
printPutByIdOp(out, exec, location, it, "put_by_id");
+ printPutByIdCacheStatus(out, exec, location, stubInfos);
break;
}
case op_put_by_id_out_of_line: {
printPutByIdOp(out, exec, location, it, "put_by_id_out_of_line");
+ printPutByIdCacheStatus(out, exec, location, stubInfos);
break;
}
case op_put_by_id_transition_direct: {
printPutByIdOp(out, exec, location, it, "put_by_id_transition_direct");
+ printPutByIdCacheStatus(out, exec, location, stubInfos);
break;
}
case op_put_by_id_transition_direct_out_of_line: {
printPutByIdOp(out, exec, location, it, "put_by_id_transition_direct_out_of_line");
+ printPutByIdCacheStatus(out, exec, location, stubInfos);
break;
}
case op_put_by_id_transition_normal: {
printPutByIdOp(out, exec, location, it, "put_by_id_transition_normal");
+ printPutByIdCacheStatus(out, exec, location, stubInfos);
break;
}
case op_put_by_id_transition_normal_out_of_line: {
printPutByIdOp(out, exec, location, it, "put_by_id_transition_normal_out_of_line");
+ printPutByIdCacheStatus(out, exec, location, stubInfos);
break;
}
case op_put_getter_setter: {
operand);
break;
}
+ case op_put_to_scope_with_profile:
case op_put_to_scope: {
int r0 = (++it)->u.operand;
int id0 = (++it)->u.operand;
++it; // Structure
int operand = (++it)->u.operand; // Operand
printLocationAndOp(out, exec, location, it, "put_to_scope");
+ if (opcode == op_put_to_scope_with_profile)
+ ++it;
out.printf("%s, %s, %s, %u<%s|%s>, <structure>, %d",
registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data(),
modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()),
break;
}
+ case op_put_to_scope_with_profile:
case op_put_to_scope: {
// put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand
const Identifier& ident = identifier(pc[2].u.operand);
} else if (op.structure)
instructions[i + 5].u.structure.set(*vm(), ownerExecutable, op.structure);
instructions[i + 6].u.pointer = reinterpret_cast<void*>(op.operand);
+
+ if (pc[0].u.opcode == op_put_to_scope_with_profile) {
+ // The format of this instruction is: put_to_scope_with_profile scope, id, value, ResolveModeAndType, Structure, Operand, TypeLocation*
+ TypeLocation* location = vm()->nextLocation();
+ size_t instructionOffset = i + opLength - 1;
+ int divot, startOffset, endOffset;
+ unsigned line = 0, column = 0;
+ expressionRangeForBytecodeOffset(instructionOffset, divot, startOffset, endOffset, line, column);
+
+ location->m_line = line;
+ location->m_column = column;
+ location->m_sourceID = m_ownerExecutable->sourceID();
+
+ // FIXME: handle other values for op.type here, and also consider what to do when we can't statically determine the globalID
+ SymbolTable* symbolTable = 0;
+ if (op.type == ClosureVar)
+ symbolTable = op.activation->symbolTable();
+ else if (op.type == GlobalVar)
+ symbolTable = m_globalObject.get()->symbolTable();
+
+ if (symbolTable) {
+ ConcurrentJITLocker locker(symbolTable->m_lock);
+ location->m_globalVariableID = symbolTable->uniqueIDForVariable(locker, ident.impl(), *vm());
+ location->m_globalTypeSet =symbolTable->globalTypeSetForVariable(locker, ident.impl(), *vm());
+ } else
+ location->m_globalVariableID = HighFidelityNoGlobalIDExists;
+
+ vm()->highFidelityTypeProfiler()->insertNewLocation(location);
+ instructions[i + 7].u.location = location;
+ }
break;
}
+
+ case op_profile_types_with_high_fidelity: {
+
+ VirtualRegister virtualRegister(pc[1].u.operand);
+ SymbolTable* symbolTable = m_symbolTable.get();
+ TypeLocation* location = vm()->nextLocation();
+ size_t instructionOffset = i + opLength - 1;
+ int divot, startOffset, endOffset;
+ unsigned line = 0, column = 0;
+ expressionRangeForBytecodeOffset(instructionOffset, divot, startOffset, endOffset, line, column);
+
+ int hasGlobalIDFlag = pc[3].u.operand;
+ if (hasGlobalIDFlag) {
+ ConcurrentJITLocker locker(symbolTable->m_lock);
+ location->m_globalVariableID = symbolTable->uniqueIDForRegister(locker, virtualRegister.offset(), *vm());
+ location->m_globalTypeSet = symbolTable->globalTypeSetForRegister(locker, virtualRegister.offset(), *vm());
+ } else
+ location->m_globalVariableID = HighFidelityNoGlobalIDExists;
+
+ location->m_line = line;
+ location->m_column = column;
+ location->m_sourceID = m_ownerExecutable->sourceID();
+
+ vm()->highFidelityTypeProfiler()->insertNewLocation(location);
+ instructions[i + 2].u.location = location;
+ break;
+ }
+
+
case op_captured_mov:
case op_new_captured_func: {
if (pc[3].u.index == UINT_MAX) {
if (Options::verboseOSR())
dataLogF("Clearing LLInt to_this with structure %p.\n", curInstruction[2].u.structure.get());
curInstruction[2].u.structure.clear();
+ curInstruction[3].u.toThisStatus = merge(
+ curInstruction[3].u.toThisStatus, ToThisClearedByGC);
break;
case op_get_callee:
if (!curInstruction[2].u.jsCell || Heap::isMarked(curInstruction[2].u.jsCell.get()))
break;
}
case op_get_from_scope:
+ case op_put_to_scope_with_profile:
case op_put_to_scope: {
ResolveModeAndType modeAndType =
ResolveModeAndType(curInstruction[4].u.operand);
bool isKnownToBeLiveDuringGC(); // Will only return valid results when called during GC. Assumes that you've already established that the owner executable is live.
+
protected:
virtual void visitWeakReferences(SlotVisitor&) override;
virtual void finalizeUnconditionally() override;
enum CacheDumpMode { DumpCaches, DontDumpCaches };
void printCallOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap&);
void printPutByIdOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
+ void printPutByIdCacheStatus(PrintStream&, ExecState*, int location, const StubInfoMap&);
void printLocationAndOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
void printLocationOpAndRegisterOperand(PrintStream&, ExecState*, int location, const Instruction*& it, const char* op, int operand);
variant.m_structureSet.add(structure);
variant.m_specificValue = JSValue(specificValue);
- result.appendVariant(variant);
+ bool didAppend = result.appendVariant(variant);
+ ASSERT_UNUSED(didAppend, didAppend);
return result;
}
return computeFor(profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid);
}
-GetByIdStatus GetByIdStatus::computeFor(VM& vm, Structure* structure, StringImpl* uid)
+GetByIdStatus GetByIdStatus::computeFor(VM& vm, const StructureSet& set, StringImpl* uid)
{
// For now we only handle the super simple self access case. We could handle the
// prototype case in the future.
- if (!structure)
- return GetByIdStatus(TakesSlowPath);
+ if (set.isEmpty())
+ return GetByIdStatus();
if (toUInt32FromStringImpl(uid) != PropertyName::NotAnIndex)
return GetByIdStatus(TakesSlowPath);
- if (structure->typeInfo().overridesGetOwnPropertySlot() && structure->typeInfo().type() != GlobalObjectType)
- return GetByIdStatus(TakesSlowPath);
+ GetByIdStatus result;
+ result.m_state = Simple;
+ result.m_wasSeenInJIT = false;
+ for (unsigned i = 0; i < set.size(); ++i) {
+ Structure* structure = set[i];
+ if (structure->typeInfo().overridesGetOwnPropertySlot() && structure->typeInfo().type() != GlobalObjectType)
+ return GetByIdStatus(TakesSlowPath);
+
+ if (!structure->propertyAccessesAreCacheable())
+ return GetByIdStatus(TakesSlowPath);
+
+ unsigned attributes;
+ JSCell* specificValue;
+ PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue);
+ if (!isValidOffset(offset))
+ return GetByIdStatus(TakesSlowPath); // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it.
+ if (attributes & Accessor)
+ return GetByIdStatus(MakesCalls); // We could be smarter here, like strenght-reducing this to a Call.
+ if (structure->isDictionary())
+ specificValue = 0;
+
+ if (!result.appendVariant(GetByIdVariant(structure, offset, specificValue)))
+ return GetByIdStatus(TakesSlowPath);
+ }
- if (!structure->propertyAccessesAreCacheable())
- return GetByIdStatus(TakesSlowPath);
-
- unsigned attributes;
- JSCell* specificValue;
- PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue);
- if (!isValidOffset(offset))
- return GetByIdStatus(TakesSlowPath); // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it.
- if (attributes & Accessor)
- return GetByIdStatus(MakesCalls);
- if (structure->isDictionary())
- specificValue = 0;
- return GetByIdStatus(
- Simple, false, GetByIdVariant(StructureSet(structure), offset, specificValue));
+ return result;
}
bool GetByIdStatus::makesCalls() const
}
static GetByIdStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex, StringImpl* uid);
- static GetByIdStatus computeFor(VM&, Structure*, StringImpl* uid);
+ static GetByIdStatus computeFor(VM&, const StructureSet&, StringImpl* uid);
static GetByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin, StringImpl* uid);
out.print(
"<", inContext(structureSet(), context), ", ",
- "[", listDumpInContext(m_constantChecks, context), "], ",
- "alternateBase = ", inContext(JSValue(m_alternateBase), context), ", ",
- "specificValue = ", inContext(specificValue(), context), ", ",
- "offset = ", offset());
+ "[", listDumpInContext(m_constantChecks, context), "]");
+ if (m_alternateBase)
+ out.print(", alternateBase = ", inContext(JSValue(m_alternateBase), context));
+ if (specificValue())
+ out.print(", specificValue = ", inContext(specificValue(), context));
+ out.print(", offset = ", offset());
if (m_callLinkStatus)
- out.print("call = ", *m_callLinkStatus);
+ out.print(", call = ", *m_callLinkStatus);
out.print(">");
}
bool isSet() const { return !!m_structureSet.size(); }
bool operator!() const { return !isSet(); }
const StructureSet& structureSet() const { return m_structureSet; }
+ StructureSet& structureSet() { return m_structureSet; }
const ConstantStructureCheckVector& constantChecks() const { return m_constantChecks; }
JSObject* alternateBase() const { return m_alternateBase; }
JSValue specificValue() const { return m_specificValue; }
/*
- * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "MacroAssembler.h"
#include "Opcode.h"
+#include "TypeLocation.h"
#include "PropertySlot.h"
#include "SpecialPointer.h"
#include "Structure.h"
#include "StructureChain.h"
+#include "ToThisStatus.h"
#include "VirtualRegister.h"
#include <wtf/VectorTraits.h>
WriteBarrierBase<JSActivation> activation;
void* pointer;
bool* predicatePointer;
+ ToThisStatus toThisStatus;
+ TypeLocation* location;
} u;
private:
bool PutByIdStatus::appendVariant(const PutByIdVariant& variant)
{
for (unsigned i = 0; i < m_variants.size(); ++i) {
- if (m_variants[i].oldStructure() == variant.oldStructure())
+ if (m_variants[i].attemptToMerge(variant))
+ return true;
+ }
+ for (unsigned i = 0; i < m_variants.size(); ++i) {
+ if (m_variants[i].oldStructure().overlaps(variant.oldStructure()))
return false;
}
m_variants.append(variant);
access.newStructure()->getConcurrently(*profiledBlock->vm(), uid);
if (!isValidOffset(offset))
return PutByIdStatus(TakesSlowPath);
+ RefPtr<IntendedStructureChain> chain;
+ if (access.chain()) {
+ chain = adoptRef(new IntendedStructureChain(
+ profiledBlock, access.oldStructure(), access.chain()));
+ if (!chain->isStillValid())
+ continue;
+ }
bool ok = result.appendVariant(PutByIdVariant::transition(
- access.oldStructure(), access.newStructure(),
- access.chain() ? adoptRef(new IntendedStructureChain(
- profiledBlock, access.oldStructure(), access.chain())) : 0,
- offset));
+ access.oldStructure(), access.newStructure(), chain.get(), offset));
if (!ok)
return PutByIdStatus(TakesSlowPath);
break;
return computeFor(baselineBlock, baselineMap, codeOrigin.bytecodeIndex, uid);
}
-PutByIdStatus PutByIdStatus::computeFor(VM& vm, JSGlobalObject* globalObject, Structure* structure, StringImpl* uid, bool isDirect)
+PutByIdStatus PutByIdStatus::computeFor(VM& vm, JSGlobalObject* globalObject, const StructureSet& set, StringImpl* uid, bool isDirect)
{
if (toUInt32FromStringImpl(uid) != PropertyName::NotAnIndex)
return PutByIdStatus(TakesSlowPath);
- if (!structure)
- return PutByIdStatus(TakesSlowPath);
+ if (set.isEmpty())
+ return PutByIdStatus();
- if (structure->typeInfo().overridesGetOwnPropertySlot() && structure->typeInfo().type() != GlobalObjectType)
- return PutByIdStatus(TakesSlowPath);
+ PutByIdStatus result;
+ result.m_state = Simple;
+ for (unsigned i = 0; i < set.size(); ++i) {
+ Structure* structure = set[i];
+
+ if (structure->typeInfo().overridesGetOwnPropertySlot() && structure->typeInfo().type() != GlobalObjectType)
+ return PutByIdStatus(TakesSlowPath);
- if (!structure->propertyAccessesAreCacheable())
- return PutByIdStatus(TakesSlowPath);
+ if (!structure->propertyAccessesAreCacheable())
+ return PutByIdStatus(TakesSlowPath);
- unsigned attributes;
- JSCell* specificValue;
- PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue);
- if (isValidOffset(offset)) {
- if (attributes & CustomAccessor)
- return PutByIdStatus(MakesCalls);
+ unsigned attributes;
+ JSCell* specificValue;
+ PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue);
+ if (isValidOffset(offset)) {
+ if (attributes & CustomAccessor)
+ return PutByIdStatus(MakesCalls);
- if (attributes & (Accessor | ReadOnly))
- return PutByIdStatus(TakesSlowPath);
- if (specificValue) {
- // We need the PutById slow path to verify that we're storing the right value into
- // the specialized slot.
- return PutByIdStatus(TakesSlowPath);
+ if (attributes & (Accessor | ReadOnly))
+ return PutByIdStatus(TakesSlowPath);
+ if (specificValue) {
+ // We need the PutById slow path to verify that we're storing the right value into
+ // the specialized slot.
+ return PutByIdStatus(TakesSlowPath);
+ }
+ if (!result.appendVariant(PutByIdVariant::replace(structure, offset)))
+ return PutByIdStatus(TakesSlowPath);
+ continue;
}
- return PutByIdVariant::replace(structure, offset);
- }
- // Our hypothesis is that we're doing a transition. Before we prove that this is really
- // true, we want to do some sanity checks.
+ // Our hypothesis is that we're doing a transition. Before we prove that this is really
+ // true, we want to do some sanity checks.
- // Don't cache put transitions on dictionaries.
- if (structure->isDictionary())
- return PutByIdStatus(TakesSlowPath);
+ // Don't cache put transitions on dictionaries.
+ if (structure->isDictionary())
+ return PutByIdStatus(TakesSlowPath);
- // If the structure corresponds to something that isn't an object, then give up, since
- // we don't want to be adding properties to strings.
- if (structure->typeInfo().type() == StringType)
- return PutByIdStatus(TakesSlowPath);
+ // If the structure corresponds to something that isn't an object, then give up, since
+ // we don't want to be adding properties to strings.
+ if (structure->typeInfo().type() == StringType)
+ return PutByIdStatus(TakesSlowPath);
- RefPtr<IntendedStructureChain> chain;
- if (!isDirect) {
- chain = adoptRef(new IntendedStructureChain(globalObject, structure));
+ RefPtr<IntendedStructureChain> chain;
+ if (!isDirect) {
+ chain = adoptRef(new IntendedStructureChain(globalObject, structure));
- // If the prototype chain has setters or read-only properties, then give up.
- if (chain->mayInterceptStoreTo(vm, uid))
- return PutByIdStatus(TakesSlowPath);
+ // If the prototype chain has setters or read-only properties, then give up.
+ if (chain->mayInterceptStoreTo(vm, uid))
+ return PutByIdStatus(TakesSlowPath);
- // If the prototype chain hasn't been normalized (i.e. there are proxies or dictionaries)
- // then give up. The dictionary case would only happen if this structure has not been
- // used in an optimized put_by_id transition. And really the only reason why we would
- // bail here is that I don't really feel like having the optimizing JIT go and flatten
- // dictionaries if we have evidence to suggest that those objects were never used as
- // prototypes in a cacheable prototype access - i.e. there's a good chance that some of
- // the other checks below will fail.
- if (structure->isProxy() || !chain->isNormalized())
+ // If the prototype chain hasn't been normalized (i.e. there are proxies or dictionaries)
+ // then give up. The dictionary case would only happen if this structure has not been
+ // used in an optimized put_by_id transition. And really the only reason why we would
+ // bail here is that I don't really feel like having the optimizing JIT go and flatten
+ // dictionaries if we have evidence to suggest that those objects were never used as
+ // prototypes in a cacheable prototype access - i.e. there's a good chance that some of
+ // the other checks below will fail.
+ if (structure->isProxy() || !chain->isNormalized())
+ return PutByIdStatus(TakesSlowPath);
+ }
+
+ // We only optimize if there is already a structure that the transition is cached to.
+ // Among other things, this allows us to guard against a transition with a specific
+ // value.
+ //
+ // - If we're storing a value that could be specific: this would only be a problem if
+ // the existing transition did have a specific value already, since if it didn't,
+ // then we would behave "as if" we were not storing a specific value. If it did
+ // have a specific value, then we'll know - the fact that we pass 0 for
+ // specificValue will tell us.
+ //
+ // - If we're not storing a value that could be specific: again, this would only be a
+ // problem if the existing transition did have a specific value, which we check for
+ // by passing 0 for the specificValue.
+ Structure* transition = Structure::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, 0, offset);
+ if (!transition)
+ return PutByIdStatus(TakesSlowPath); // This occurs in bizarre cases only. See above.
+ ASSERT(!transition->transitionDidInvolveSpecificValue());
+ ASSERT(isValidOffset(offset));
+
+ bool didAppend = result.appendVariant(
+ PutByIdVariant::transition(structure, transition, chain.release(), offset));
+ if (!didAppend)
return PutByIdStatus(TakesSlowPath);
}
- // We only optimize if there is already a structure that the transition is cached to.
- // Among other things, this allows us to guard against a transition with a specific
- // value.
- //
- // - If we're storing a value that could be specific: this would only be a problem if
- // the existing transition did have a specific value already, since if it didn't,
- // then we would behave "as if" we were not storing a specific value. If it did
- // have a specific value, then we'll know - the fact that we pass 0 for
- // specificValue will tell us.
- //
- // - If we're not storing a value that could be specific: again, this would only be a
- // problem if the existing transition did have a specific value, which we check for
- // by passing 0 for the specificValue.
- Structure* transition = Structure::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, 0, offset);
- if (!transition)
- return PutByIdStatus(TakesSlowPath); // This occurs in bizarre cases only. See above.
- ASSERT(!transition->transitionDidInvolveSpecificValue());
- ASSERT(isValidOffset(offset));
-
- return PutByIdVariant::transition(structure, transition, chain.release(), offset);
+ return result;
}
void PutByIdStatus::dump(PrintStream& out) const
}
static PutByIdStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex, StringImpl* uid);
- static PutByIdStatus computeFor(VM&, JSGlobalObject*, Structure*, StringImpl* uid, bool isDirect);
+ static PutByIdStatus computeFor(VM&, JSGlobalObject*, const StructureSet&, StringImpl* uid, bool isDirect);
static PutByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin, StringImpl* uid);
namespace JSC {
+Structure* PutByIdVariant::oldStructureForTransition() const
+{
+ ASSERT(kind() == Transition);
+ ASSERT(m_oldStructure.size() <= 2);
+ for (unsigned i = m_oldStructure.size(); i--;) {
+ Structure* structure = m_oldStructure[i];
+ if (structure != m_newStructure)
+ return structure;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+bool PutByIdVariant::writesStructures() const
+{
+ return kind() == Transition;
+}
+
+bool PutByIdVariant::reallocatesStorage() const
+{
+ if (kind() != Transition)
+ return false;
+
+ if (oldStructureForTransition()->outOfLineCapacity() == newStructure()->outOfLineCapacity())
+ return false;
+
+ return true;
+}
+
+bool PutByIdVariant::attemptToMerge(const PutByIdVariant& other)
+{
+ if (m_offset != other.m_offset)
+ return false;
+
+ switch (m_kind) {
+ case Replace:
+ switch (other.m_kind) {
+ case Replace: {
+ ASSERT(m_constantChecks.isEmpty());
+ ASSERT(other.m_constantChecks.isEmpty());
+
+ m_oldStructure.merge(other.m_oldStructure);
+ return true;
+ }
+
+ case Transition: {
+ PutByIdVariant newVariant = other;
+ if (newVariant.attemptToMergeTransitionWithReplace(*this)) {
+ *this = newVariant;
+ return true;
+ }
+ return false;
+ }
+
+ default:
+ return false;
+ }
+
+ case Transition:
+ switch (other.m_kind) {
+ case Replace:
+ return attemptToMergeTransitionWithReplace(other);
+
+ default:
+ return false;
+ }
+
+ default:
+ return false;
+ }
+}
+
+bool PutByIdVariant::attemptToMergeTransitionWithReplace(const PutByIdVariant& replace)
+{
+ ASSERT(m_kind == Transition);
+ ASSERT(replace.m_kind == Replace);
+ ASSERT(m_offset == replace.m_offset);
+ ASSERT(!replace.writesStructures());
+ ASSERT(!replace.reallocatesStorage());
+
+ // This sort of merging only works when we have one path along which we add a new field which
+ // transitions to structure S while the other path was already on structure S. This doesn't
+ // work if we need to reallocate anything or if the replace path is polymorphic.
+
+ if (reallocatesStorage())
+ return false;
+
+ if (replace.m_oldStructure.onlyStructure() != m_newStructure)
+ return false;
+
+ m_oldStructure.merge(m_newStructure);
+ return true;
+}
+
void PutByIdVariant::dump(PrintStream& out) const
{
dumpInContext(out, 0);
case Replace:
out.print(
- "<Replace: ", pointerDumpInContext(structure(), context), ", ", offset(), ">");
+ "<Replace: ", inContext(structure(), context), ", ", offset(), ">");
return;
case Transition:
out.print(
- "<Transition: ", pointerDumpInContext(oldStructure(), context), " -> ",
+ "<Transition: ", inContext(oldStructure(), context), " -> ",
pointerDumpInContext(newStructure(), context), ", [",
listDumpInContext(constantChecks(), context), "], ", offset(), ">");
return;
#include "IntendedStructureChain.h"
#include "PropertyOffset.h"
+#include "StructureSet.h"
namespace JSC {
PutByIdVariant()
: m_kind(NotSet)
- , m_oldStructure(0)
- , m_newStructure(0)
+ , m_newStructure(nullptr)
, m_offset(invalidOffset)
{
}
- static PutByIdVariant replace(Structure* structure, PropertyOffset offset)
+ static PutByIdVariant replace(const StructureSet& structure, PropertyOffset offset)
{
PutByIdVariant result;
result.m_kind = Replace;
}
static PutByIdVariant transition(
- Structure* oldStructure, Structure* newStructure,
+ const StructureSet& oldStructure, Structure* newStructure,
PassRefPtr<IntendedStructureChain> structureChain, PropertyOffset offset)
{
PutByIdVariant result;
bool isSet() const { return kind() != NotSet; }
bool operator!() const { return !isSet(); }
- Structure* structure() const
+ const StructureSet& structure() const
{
ASSERT(kind() == Replace);
return m_oldStructure;
}
- Structure* oldStructure() const
+ const StructureSet& oldStructure() const
{
ASSERT(kind() == Transition || kind() == Replace);
return m_oldStructure;
}
+ StructureSet& oldStructure()
+ {
+ ASSERT(kind() == Transition || kind() == Replace);
+ return m_oldStructure;
+ }
+
+ Structure* oldStructureForTransition() const;
+
Structure* newStructure() const
{
ASSERT(kind() == Transition);
return m_newStructure;
}
+
+ bool writesStructures() const;
+ bool reallocatesStorage() const;
const ConstantStructureCheckVector& constantChecks() const
{
- ASSERT(kind() == Transition);
return m_constantChecks;
}
return m_offset;
}
+ bool attemptToMerge(const PutByIdVariant& other);
+
void dump(PrintStream&) const;
void dumpInContext(PrintStream&, DumpContext*) const;
private:
+ bool attemptToMergeTransitionWithReplace(const PutByIdVariant& replace);
+
Kind m_kind;
- Structure* m_oldStructure;
+ StructureSet m_oldStructure;
Structure* m_newStructure;
ConstantStructureCheckVector m_constantChecks;
PropertyOffset m_offset;
#include "config.h"
#include "StructureSet.h"
+#include "DFGAbstractValue.h"
#include <wtf/CommaPrinter.h>
namespace JSC {
clear();
}
+namespace {
+
+class StructureAbstractValueContains {
+public:
+ StructureAbstractValueContains(const DFG::StructureAbstractValue& value)
+ : m_value(value)
+ {
+ }
+
+ bool operator()(Structure* structure)
+ {
+ return m_value.contains(structure);
+ }
+private:
+ const DFG::StructureAbstractValue& m_value;
+};
+
+class SpeculatedTypeContains {
+public:
+ SpeculatedTypeContains(SpeculatedType type)
+ : m_type(type)
+ {
+ }
+
+ bool operator()(Structure* structure)
+ {
+ return m_type & speculationFromStructure(structure);
+ }
+private:
+ SpeculatedType m_type;
+};
+
+class ArrayModesContains {
+public:
+ ArrayModesContains(ArrayModes arrayModes)
+ : m_arrayModes(arrayModes)
+ {
+ }
+
+ bool operator()(Structure* structure)
+ {
+ return m_arrayModes & arrayModeFromStructure(structure);
+ }
+private:
+ ArrayModes m_arrayModes;
+};
+
+} // anonymous namespace
+
+void StructureSet::filter(const DFG::StructureAbstractValue& other)
+{
+ StructureAbstractValueContains functor(other);
+ genericFilter(functor);
+}
+
+void StructureSet::filter(SpeculatedType type)
+{
+ SpeculatedTypeContains functor(type);
+ genericFilter(functor);
+}
+
+void StructureSet::filterArrayModes(ArrayModes arrayModes)
+{
+ ArrayModesContains functor(arrayModes);
+ genericFilter(functor);
+}
+
+void StructureSet::filter(const DFG::AbstractValue& other)
+{
+ filter(other.m_structure);
+ filter(other.m_type);
+ filterArrayModes(other.m_arrayModes);
+}
+
bool StructureSet::isSubsetOf(const StructureSet& other) const
{
if (isThin()) {
namespace DFG {
class StructureAbstractValue;
+struct AbstractValue;
}
class StructureSet {
Structure* onlyStructure() const
{
- if (isThin()) {
- ASSERT(singleStructure());
+ if (isThin())
return singleStructure();
- }
- ASSERT(structureList()->m_length == 1);
- return structureList()->list()[0];
+ OutOfLineList* list = structureList();
+ if (list->m_length != 1)
+ return nullptr;
+ return list->list()[0];
}
bool isEmpty() const
void filter(const StructureSet&);
void exclude(const StructureSet&);
+ void filter(const DFG::StructureAbstractValue&);
+ void filter(SpeculatedType);
+ void filterArrayModes(ArrayModes);
+ void filter(const DFG::AbstractValue&);
+
template<typename Functor>
void genericFilter(Functor& functor)
{
--- /dev/null
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ToThisStatus.h"
+
+namespace JSC {
+
+ToThisStatus merge(ToThisStatus a, ToThisStatus b)
+{
+ switch (a) {
+ case ToThisOK:
+ return b;
+ case ToThisConflicted:
+ return ToThisConflicted;
+ case ToThisClearedByGC:
+ if (b == ToThisConflicted)
+ return ToThisConflicted;
+ return ToThisClearedByGC;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return ToThisConflicted;
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream& out, ToThisStatus status)
+{
+ switch (status) {
+ case ToThisOK:
+ out.print("OK");
+ return;
+ case ToThisConflicted:
+ out.print("Conflicted");
+ return;
+ case ToThisClearedByGC:
+ out.print("ClearedByGC");
+ return;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
--- /dev/null
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ToThisStatus_h
+#define ToThisStatus_h
+
+#include <wtf/PrintStream.h>
+
+namespace JSC {
+
+enum ToThisStatus {
+ ToThisOK,
+ ToThisConflicted,
+ ToThisClearedByGC
+};
+
+ToThisStatus merge(ToThisStatus, ToThisStatus);
+
+} // namespace JSC
+
+namespace WTF {
+
+void printInternal(PrintStream&, JSC::ToThisStatus);
+
+} // namespace WTF
+
+#endif // ToThisStatus_h
+
--- /dev/null
+/*
+ * Copyright (C) 2014 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TypeLocation_h
+#define TypeLocation_h
+
+#include "TypeSet.h"
+
+namespace JSC {
+
+enum HighFidelityGlobalIDFlags {
+ HighFidelityNeedsUniqueIDGeneration = -1,
+ HighFidelityNoGlobalIDExists = -2
+};
+
+class TypeLocation {
+
+public:
+ TypeLocation()
+ : m_instructionTypeSet(TypeSet::create())
+ , m_globalTypeSet(nullptr)
+ {
+ }
+
+ int64_t m_globalVariableID;
+ intptr_t m_sourceID;
+ unsigned m_line;
+ unsigned m_column;
+ RefPtr<TypeSet> m_instructionTypeSet;
+ RefPtr<TypeSet> m_globalTypeSet;
+};
+
+} //namespace JSC
+
+#endif //TypeLocation_h
emitOpcode(op_to_this);
instructions().append(kill(&m_thisRegister));
instructions().append(0);
+ instructions().append(0);
}
}
instructions().append(src->index());
if (captureMode == IsCaptured)
instructions().append(watchableVariable(dst->index()));
+
+ if (!dst->isTemporary() && isProfilingTypesWithHighFidelity())
+ emitProfileTypesWithHighFidelity(dst, true);
+
return dst;
}
return dst;
}
+void BytecodeGenerator::emitProfileTypesWithHighFidelity(RegisterID* registerToProfile, bool hasGlobalID)
+{
+ emitOpcode(op_profile_types_with_high_fidelity);
+ instructions().append(registerToProfile->index());
+ instructions().append(0); // placeholder for TypeLocation
+ // This is a flag indicating whether we should track this value to its globalID or not.
+ if (hasGlobalID)
+ instructions().append(1);
+ else
+ instructions().append(0);
+}
+
RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, bool b)
{
return emitLoad(dst, jsBoolean(b));
m_codeBlock->addPropertyAccessInstruction(instructions().size());
// put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand
- emitOpcode(op_put_to_scope);
+ if (isProfilingTypesWithHighFidelity())
+ emitOpcode(op_put_to_scope_with_profile);
+ else
+ emitOpcode(op_put_to_scope);
instructions().append(scope->index());
instructions().append(addConstant(identifier));
instructions().append(value->index());
instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand());
instructions().append(0);
instructions().append(0);
+ if (isProfilingTypesWithHighFidelity())
+ instructions().append(0);
return value;
}
instructions().append(0);
instructions().append(0);
instructions().append(0);
+
+ if (isProfilingTypesWithHighFidelity())
+ emitProfileTypesWithHighFidelity(value, false);
+
return value;
}
instructions().append(property->index());
instructions().append(value->index());
instructions().append(arrayProfile);
+
+ if (isProfilingTypesWithHighFidelity())
+ emitProfileTypesWithHighFidelity(value, false);
+
return value;
}
return emitNode(n);
}
+ void emitProfileTypesWithHighFidelity(RegisterID* dst, bool);
+
RegisterID* emitLoad(RegisterID* dst, bool);
RegisterID* emitLoad(RegisterID* dst, double);
RegisterID* emitLoad(RegisterID* dst, const Identifier&);
VM* m_vm;
+ bool isProfilingTypesWithHighFidelity() { return vm()->isProfilingTypesWithHighFidelity(); }
+
OpcodeID m_lastOpcodeID;
#ifndef NDEBUG
size_t m_lastOpcodePosition;
if (local.isReadOnly()) {
generator.emitReadOnlyExceptionIfNeeded();
localReg = generator.emitMove(generator.tempDestination(dst), localReg);
- } else if (local.isCaptured()) {
+ } else if (local.isCaptured() || generator.isProfilingTypesWithHighFidelity()) {
RefPtr<RegisterID> tempDst = generator.finalDestination(dst);
ASSERT(dst != localReg);
RefPtr<RegisterID> tempDstSrc = generator.newTemporary();
generator.emitToNumber(tempDst.get(), localReg);
generator.emitMove(tempDstSrc.get(), localReg);
emitIncOrDec(generator, tempDstSrc.get(), m_operator);
+ if (generator.isProfilingTypesWithHighFidelity())
+ generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
generator.emitMove(localReg, tempDstSrc.get());
return tempDst.get();
}
if (local.isReadOnly()) {
generator.emitReadOnlyExceptionIfNeeded();
localReg = generator.emitMove(generator.tempDestination(dst), localReg);
- } else if (local.isCaptured()) {
+ } else if (local.isCaptured() || generator.isProfilingTypesWithHighFidelity()) {
RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
generator.emitMove(tempDst.get(), localReg);
emitIncOrDec(generator, tempDst.get(), m_operator);
+ if (generator.isProfilingTypesWithHighFidelity())
+ generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
generator.emitMove(localReg, tempDst.get());
return generator.moveToDestinationIfNeeded(dst, tempDst.get());
}
RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
+ JSTextPosition newDivot = divotStart() + m_ident.length();
if (Local local = generator.local(m_ident)) {
if (local.isReadOnly()) {
generator.emitReadOnlyExceptionIfNeeded();
}
if (local.isCaptured()
+ || generator.isProfilingTypesWithHighFidelity()
|| generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
RefPtr<RegisterID> result = generator.newTemporary();
generator.emitMove(result.get(), local.get());
emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
+ if (generator.isProfilingTypesWithHighFidelity())
+ generator.emitExpressionInfo(newDivot, divotStart(), newDivot);
generator.emitMove(local.get(), result.get());
return generator.moveToDestinationIfNeeded(dst, result.get());
}
return generator.moveToDestinationIfNeeded(dst, result);
}
- JSTextPosition newDivot = divotStart() + m_ident.length();
generator.emitExpressionInfo(newDivot, divotStart(), newDivot);
RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident);
RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, ThrowIfNotFound);
generator.emitReadOnlyExceptionIfNeeded();
return generator.emitNode(dst, m_right);
}
- if (local.isCaptured()) {
+ if (local.isCaptured() || generator.isProfilingTypesWithHighFidelity()) {
RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
generator.emitNode(tempDst.get(), m_right);
+ if (generator.isProfilingTypesWithHighFidelity())
+ generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
generator.emitMove(local.get(), tempDst.get());
return generator.moveToDestinationIfNeeded(dst, tempDst.get());
}
if (!m_init)
return local.get();
- if (local.isCaptured()) {
+ // FIXME: Maybe call emitExpressionInfo here.
+ if (local.isCaptured() || generator.isProfilingTypesWithHighFidelity()) {
RefPtr<RegisterID> tempDst = generator.newTemporary();
generator.emitNode(tempDst.get(), m_init);
return generator.emitMove(local.get(), tempDst.get());
Identifier ident = simpleBinding->boundProperty();
Local local = generator.local(ident);
propertyName = local.get();
- if (!propertyName || local.isCaptured())
+ // FIXME: Should I emit expression info here?
+ if (!propertyName || local.isCaptured() || generator.isProfilingTypesWithHighFidelity())
goto genericBinding;
expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName);
/*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2009, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
*/
#include "config.h"
-#include "DebuggerActivation.h"
+#include "DebuggerScope.h"
#include "JSActivation.h"
#include "JSCInlines.h"
namespace JSC {
-STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DebuggerActivation);
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DebuggerScope);
-const ClassInfo DebuggerActivation::s_info = { "DebuggerActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(DebuggerActivation) };
+const ClassInfo DebuggerScope::s_info = { "DebuggerScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(DebuggerScope) };
-DebuggerActivation::DebuggerActivation(VM& vm)
- : JSNonFinalObject(vm, vm.debuggerActivationStructure.get())
+DebuggerScope::DebuggerScope(VM& vm)
+ : JSNonFinalObject(vm, vm.debuggerScopeStructure.get())
{
}
-void DebuggerActivation::finishCreation(VM& vm, JSObject* activation)
+void DebuggerScope::finishCreation(VM& vm, JSObject* activation)
{
Base::finishCreation(vm);
ASSERT(activation);
m_activation.set(vm, this, jsCast<JSActivation*>(activation));
}
-void DebuggerActivation::visitChildren(JSCell* cell, SlotVisitor& visitor)
+void DebuggerScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
- DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(cell);
+ DebuggerScope* thisObject = jsCast<DebuggerScope*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
visitor.append(&thisObject->m_activation);
}
-String DebuggerActivation::className(const JSObject* object)
+String DebuggerScope::className(const JSObject* object)
{
- const DebuggerActivation* thisObject = jsCast<const DebuggerActivation*>(object);
+ const DebuggerScope* thisObject = jsCast<const DebuggerScope*>(object);
return thisObject->m_activation->methodTable()->className(thisObject->m_activation.get());
}
-bool DebuggerActivation::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+bool DebuggerScope::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
- DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(object);
+ DebuggerScope* thisObject = jsCast<DebuggerScope*>(object);
return thisObject->m_activation->methodTable()->getOwnPropertySlot(thisObject->m_activation.get(), exec, propertyName, slot);
}
-void DebuggerActivation::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+void DebuggerScope::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
{
- DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(cell);
+ DebuggerScope* thisObject = jsCast<DebuggerScope*>(cell);
thisObject->m_activation->methodTable()->put(thisObject->m_activation.get(), exec, propertyName, value, slot);
}
-bool DebuggerActivation::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
+bool DebuggerScope::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
{
- DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(cell);
+ DebuggerScope* thisObject = jsCast<DebuggerScope*>(cell);
return thisObject->m_activation->methodTable()->deleteProperty(thisObject->m_activation.get(), exec, propertyName);
}
-void DebuggerActivation::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+void DebuggerScope::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(object);
+ DebuggerScope* thisObject = jsCast<DebuggerScope*>(object);
thisObject->m_activation->methodTable()->getPropertyNames(thisObject->m_activation.get(), exec, propertyNames, mode);
}
-bool DebuggerActivation::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
+bool DebuggerScope::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
{
- DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(object);
+ DebuggerScope* thisObject = jsCast<DebuggerScope*>(object);
return thisObject->m_activation->methodTable()->defineOwnProperty(thisObject->m_activation.get(), exec, propertyName, descriptor, shouldThrow);
}
/*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2009, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DebuggerActivation_h
-#define DebuggerActivation_h
+#ifndef DebuggerScope_h
+#define DebuggerScope_h
#include "JSObject.h"
namespace JSC {
-class DebuggerActivation : public JSNonFinalObject {
+class DebuggerScope : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
- static DebuggerActivation* create(VM& vm, JSObject* object)
+ static DebuggerScope* create(VM& vm, JSObject* object)
{
- DebuggerActivation* activation = new (NotNull, allocateCell<DebuggerActivation>(vm.heap)) DebuggerActivation(vm);
+ DebuggerScope* activation = new (NotNull, allocateCell<DebuggerScope>(vm.heap)) DebuggerScope(vm);
activation->finishCreation(vm, object);
return activation;
}
JS_EXPORT_PRIVATE void finishCreation(VM&, JSObject* activation);
private:
- JS_EXPORT_PRIVATE DebuggerActivation(VM&);
+ JS_EXPORT_PRIVATE DebuggerScope(VM&);
WriteBarrier<JSActivation> m_activation;
};
} // namespace JSC
-#endif // DebuggerActivation_h
+#endif // DebuggerScope_h
break;
case GetById:
- case GetByIdFlush:
+ case GetByIdFlush: {
if (!node->prediction()) {
m_state.setIsValid(false);
break;
}
- if (isCellSpeculation(node->child1()->prediction())) {
- // This use of onlyStructure() should be replaced by giving GetByIdStatus the ability
- // to compute things based on a StructureSet, and then to factor ByteCodeParser's
- // ability to generate code based on a GetByIdStatus out of ByteCodeParser so that
- // ConstantFoldingPhase can use it.
- // https://bugs.webkit.org/show_bug.cgi?id=133229
- if (Structure* structure = forNode(node->child1()).m_structure.onlyStructure()) {
- GetByIdStatus status = GetByIdStatus::computeFor(
- m_graph.m_vm, structure,
- m_graph.identifiers()[node->identifierNumber()]);
- if (status.isSimple() && status.numVariants() == 1) {
- // Assert things that we can't handle and that the computeFor() method
- // above won't be able to return.
- ASSERT(status[0].structureSet().size() == 1);
- ASSERT(status[0].constantChecks().isEmpty());
- ASSERT(!status[0].alternateBase());
-
- if (status[0].specificValue()) {
- if (status[0].specificValue().isCell()) {
- Structure* structure = status[0].specificValue().asCell()->structure();
- m_graph.watchpoints().consider(structure);
- }
- setConstant(node, *m_graph.freeze(status[0].specificValue()));
- } else
- forNode(node).makeHeapTop();
- filter(node->child1(), status[0].structureSet());
+
+ AbstractValue& value = forNode(node->child1());
+ if (!value.m_structure.isTop() && !value.m_structure.isClobbered()
+ && (node->child1().useKind() == CellUse || !(value.m_type & ~SpecCell))) {
+ GetByIdStatus status = GetByIdStatus::computeFor(
+ m_graph.m_vm, value.m_structure.set(),
+ m_graph.identifiers()[node->identifierNumber()]);
+ if (status.isSimple()) {
+ // Figure out what the result is going to be - is it TOP, a constant, or maybe
+ // something more subtle?
+ AbstractValue result;
+ for (unsigned i = status.numVariants(); i--;) {
+ if (!status[i].specificValue()) {
+ result.makeHeapTop();
+ break;
+ }
- m_state.setFoundConstants(true);
- break;
+ AbstractValue thisResult;
+ thisResult.set(
+ m_graph, *m_graph.freeze(status[i].specificValue()),
+ m_state.structureClobberState());
+ result.merge(thisResult);
}
+ if (status.numVariants() == 1 || isFTL(m_graph.m_plan.mode))
+ m_state.setFoundConstants(true);
+ forNode(node) = result;
+ break;
}
}
+
clobberWorld(node->origin.semantic, clobberLimit);
forNode(node).makeHeapTop();
break;
+ }
case GetArrayLength:
forNode(node).setType(SpecInt32);
}
case PutStructure:
- case PhantomPutStructure:
if (!forNode(node->child1()).m_structure.isClear()) {
- observeTransition(
- clobberLimit, node->transition()->previous, node->transition()->next);
- forNode(node->child1()).set(m_graph, node->transition()->next);
+ if (forNode(node->child1()).m_structure.onlyStructure() == node->transition()->next)
+ m_state.setFoundConstants(true);
+ else {
+ observeTransition(
+ clobberLimit, node->transition()->previous, node->transition()->next);
+ forNode(node->child1()).changeStructure(m_graph, node->transition()->next);
+ }
}
break;
case GetButterfly:
}
case MultiGetByOffset: {
- AbstractValue& value = forNode(node->child1());
- ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this.
-
- // This should just filter down the cases in MultiGetByOffset. If that results in all
- // cases having the same offset then we should strength reduce it to a CheckStructure +
- // GetByOffset.
- // https://bugs.webkit.org/show_bug.cgi?id=133229
- if (Structure* structure = value.m_structure.onlyStructure()) {
- bool done = false;
- for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) {
- const GetByIdVariant& variant = node->multiGetByOffsetData().variants[i];
- if (!variant.structureSet().contains(structure))
- continue;
-
- if (variant.alternateBase())
- break;
-
- filter(value, structure);
- forNode(node).makeHeapTop();
- m_state.setFoundConstants(true);
- done = true;
- break;
+ // This code will filter the base value in a manner that is possibly different (either more
+ // or less precise) than the way it would be filtered if this was strength-reduced to a
+ // CheckStructure. This is fine. It's legal for different passes over the code to prove
+ // different things about the code, so long as all of them are sound. That even includes
+ // one guy proving that code should never execute (due to a contradiction) and another guy
+ // not finding that contradiction. If someone ever proved that there would be a
+ // contradiction then there must always be a contradiction even if subsequent passes don't
+ // realize it. This is the case here.
+
+ // Ordinarily you have to be careful with calling setFoundConstants()
+ // because of the effect on compile times, but this node is FTL-only.
+ m_state.setFoundConstants(true);
+
+ AbstractValue base = forNode(node->child1());
+ StructureSet baseSet;
+ AbstractValue result;
+ for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) {
+ GetByIdVariant& variant = node->multiGetByOffsetData().variants[i];
+ StructureSet set = variant.structureSet();
+ set.filter(base);
+ if (set.isEmpty())
+ continue;
+ baseSet.merge(set);
+ if (!variant.specificValue()) {
+ result.makeHeapTop();
+ continue;
}
- if (done)
- break;
+ AbstractValue thisResult;
+ thisResult.set(
+ m_graph,
+ *m_graph.freeze(variant.specificValue()),
+ m_state.structureClobberState());
+ result.merge(thisResult);
}
- StructureSet set;
- for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;)
- set.merge(node->multiGetByOffsetData().variants[i].structureSet());
+ if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction)
+ m_state.setIsValid(false);
- filter(node->child1(), set);
- forNode(node).makeHeapTop();
+ forNode(node) = result;
break;
}
}
case MultiPutByOffset: {
- AbstractValue& value = forNode(node->child1());
- ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this.
-
- // This should just filter down the cases in MultiPutByOffset. If that results in either
- // one case, or nothing but replace cases and they have the same offset, then we should
- // just strength reduce it to the appropriate combination of CheckStructure,
- // [Re]AllocatePropertyStorage, PutStructure, and PutByOffset.
- // https://bugs.webkit.org/show_bug.cgi?id=133229
- if (Structure* structure = value.m_structure.onlyStructure()) {
- bool done = false;
- for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
- const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
- if (variant.oldStructure() != structure)
- continue;
-
- if (variant.kind() == PutByIdVariant::Replace) {
- filter(node->child1(), structure);
- m_state.setFoundConstants(true);
- done = true;
- break;
- }
-
- ASSERT(variant.kind() == PutByIdVariant::Transition);
- clobberStructures(clobberLimit);
- forNode(node->child1()).set(m_graph, variant.newStructure());
- m_state.setFoundConstants(true);
- done = true;
- break;
- }
- if (done)
- break;
- }
-
- StructureSet oldSet;
StructureSet newSet;
TransitionVector transitions;
+
+ // Ordinarily you have to be careful with calling setFoundConstants()
+ // because of the effect on compile times, but this node is FTL-only.
+ m_state.setFoundConstants(true);
+
+ AbstractValue base = forNode(node->child1());
+
for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
- oldSet.add(variant.oldStructure());
+ StructureSet thisSet = variant.oldStructure();
+ thisSet.filter(base);
+ if (thisSet.isEmpty())
+ continue;
if (variant.kind() == PutByIdVariant::Transition) {
- transitions.append(Transition(variant.oldStructure(), variant.newStructure()));
+ if (thisSet.onlyStructure() != variant.newStructure()) {
+ transitions.append(
+ Transition(variant.oldStructureForTransition(), variant.newStructure()));
+ } // else this is really a replace.
newSet.add(variant.newStructure());
} else {
ASSERT(variant.kind() == PutByIdVariant::Replace);
- newSet.add(variant.oldStructure());
+ newSet.merge(thisSet);
}
}
- filter(node->child1(), oldSet);
observeTransitions(clobberLimit, transitions);
- forNode(node->child1()).set(m_graph, newSet);
+ if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
+ m_state.setIsValid(false);
break;
}
case PutById:
case PutByIdFlush:
- case PutByIdDirect:
- // This use of onlyStructure() should be replaced by giving PutByIdStatus the ability
- // to compute things based on a StructureSet, and then to factor ByteCodeParser's
- // ability to generate code based on a PutByIdStatus out of ByteCodeParser so that
- // ConstantFoldingPhase can use it.
- // https://bugs.webkit.org/show_bug.cgi?id=133229
- if (Structure* structure = forNode(node->child1()).m_structure.onlyStructure()) {
+ case PutByIdDirect: {
+ AbstractValue& value = forNode(node->child1());
+ if (!value.m_structure.isTop() && !value.m_structure.isClobbered()) {
PutByIdStatus status = PutByIdStatus::computeFor(
m_graph.m_vm,
m_graph.globalObjectFor(node->origin.semantic),
- structure,
+ value.m_structure.set(),
m_graph.identifiers()[node->identifierNumber()],
node->op() == PutByIdDirect);
- if (status.isSimple() && status.numVariants() == 1) {
- if (status[0].kind() == PutByIdVariant::Replace) {
- filter(node->child1(), structure);
- m_state.setFoundConstants(true);
- break;
+
+ if (status.isSimple()) {
+ StructureSet newSet;
+ TransitionVector transitions;
+
+ for (unsigned i = status.numVariants(); i--;) {
+ const PutByIdVariant& variant = status[i];
+ if (variant.kind() == PutByIdVariant::Transition) {
+ transitions.append(
+ Transition(
+ variant.oldStructureForTransition(), variant.newStructure()));
+ m_graph.watchpoints().consider(variant.newStructure());
+ newSet.add(variant.newStructure());
+ } else {
+ ASSERT(variant.kind() == PutByIdVariant::Replace);
+ newSet.merge(variant.oldStructure());
+ }
}
- if (status[0].kind() == PutByIdVariant::Transition
- && structure->transitionWatchpointSetHasBeenInvalidated()) {
- m_graph.watchpoints().consider(status[0].newStructure());
- clobberStructures(clobberLimit);
- forNode(node->child1()).set(m_graph, status[0].newStructure());
+
+ if (status.numVariants() == 1 || isFTL(m_graph.m_plan.mode))
m_state.setFoundConstants(true);
- break;
- }
+
+ observeTransitions(clobberLimit, transitions);
+ if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
+ m_state.setIsValid(false);
+ break;
}
}
+
clobberWorld(node->origin.semantic, clobberLimit);
break;
+ }
case In:
// FIXME: We can determine when the property definitely exists based on abstract
{
AbstractValue::TransitionObserver transitionObserver(from, to);
forAllValues(clobberLimit, transitionObserver);
- setDidClobber();
+
+ ASSERT(!from->dfgShouldWatch()); // We don't need to claim to be in a clobbered state because 'from' was never watchable (during the time we were compiling), hence no constants ever introduced into the DFG IR that ever had a watchable structure would ever have the same structure as from.
}
template<typename AbstractStateType>
{
AbstractValue::TransitionsObserver transitionsObserver(vector);
forAllValues(clobberLimit, transitionsObserver);
- setDidClobber();
+
+ if (!ASSERT_DISABLED) {
+ // We don't need to claim to be in a clobbered state because none of the Transition::previous structures are watchable.
+ for (unsigned i = vector.size(); i--;)
+ ASSERT(!vector[i].previous->dfgShouldWatch());
+ }
}
template<typename AbstractStateType>
return normalizeClarity(graph);
}
+FiltrationResult AbstractValue::changeStructure(Graph& graph, const StructureSet& other)
+{
+ m_type &= other.speculationFromStructures();
+ m_arrayModes = other.arrayModesFromStructures();
+ m_structure = other;
+
+ filterValueByType();
+
+ return normalizeClarity(graph);
+}
+
FiltrationResult AbstractValue::filterArrayModes(ArrayModes arrayModes)
{
ASSERT(arrayModes);
return result;
}
+bool AbstractValue::contains(Structure* structure) const
+{
+ return couldBeType(speculationFromStructure(structure))
+ && (m_arrayModes & arrayModeFromStructure(structure))
+ && m_structure.contains(structure);
+}
+
FiltrationResult AbstractValue::filter(const AbstractValue& other)
{
m_type &= other.m_type;
checkConsistency();
}
- bool couldBeType(SpeculatedType desiredType)
+ bool couldBeType(SpeculatedType desiredType) const
{
return !!(m_type & desiredType);
}
- bool isType(SpeculatedType desiredType)
+ bool isType(SpeculatedType desiredType) const
{
return !(m_type & ~desiredType);
}
FiltrationResult filterByValue(const FrozenValue& value);
FiltrationResult filter(const AbstractValue&);
+ FiltrationResult changeStructure(Graph&, const StructureSet&);
+
+ bool contains(Structure*) const;
+
bool validate(JSValue value) const
{
if (isHeapTop())
addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base);
emitChecks(variant.constantChecks());
- ASSERT(variant.oldStructure()->transitionWatchpointSetHasBeenInvalidated());
+ ASSERT(variant.oldStructureForTransition()->transitionWatchpointSetHasBeenInvalidated());
Node* propertyStorage;
Transition* transition = m_graph.m_transitions.add(
- variant.oldStructure(), variant.newStructure());
+ variant.oldStructureForTransition(), variant.newStructure());
- if (variant.oldStructure()->outOfLineCapacity()
- != variant.newStructure()->outOfLineCapacity()) {
+ if (variant.reallocatesStorage()) {
// If we're growing the property storage then it must be because we're
// storing into the out-of-line storage.
ASSERT(!isInlineOffset(variant.offset()));
- if (!variant.oldStructure()->outOfLineCapacity()) {
+ if (!variant.oldStructureForTransition()->outOfLineCapacity()) {
propertyStorage = addToGraph(
AllocatePropertyStorage, OpInfo(transition), base);
} else {
Node* op1 = getThis();
if (op1->op() != ToThis) {
Structure* cachedStructure = currentInstruction[2].u.structure.get();
- if (!cachedStructure
+ if (currentInstruction[2].u.toThisStatus != ToThisOK
+ || !cachedStructure
|| cachedStructure->classInfo()->methodTable.toThis != JSObject::info()->methodTable.toThis
|| m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex)
|| m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)
case GlobalPropertyWithVarInjectionChecks: {
SpeculatedType prediction = getPrediction();
GetByIdStatus status = GetByIdStatus::computeFor(*m_vm, structure, uid);
- if (status.state() != GetByIdStatus::Simple || status.numVariants() != 1) {
+ if (status.state() != GetByIdStatus::Simple
+ || status.numVariants() != 1
+ || status[0].structureSet().size() != 1) {
set(VirtualRegister(dst), addToGraph(GetByIdFlush, OpInfo(identifierNumber), OpInfo(prediction), get(VirtualRegister(scope))));
break;
}
case GlobalProperty:
case GlobalPropertyWithVarInjectionChecks: {
PutByIdStatus status = PutByIdStatus::computeFor(*m_vm, globalObject, structure, uid, false);
- if (status.numVariants() != 1 || status[0].kind() != PutByIdVariant::Replace) {
+ if (status.numVariants() != 1
+ || status[0].kind() != PutByIdVariant::Replace
+ || status[0].structure().size() != 1) {
addToGraph(PutById, OpInfo(identifierNumber), get(VirtualRegister(scope)), get(VirtualRegister(value)));
break;
}
- Node* base = cellConstantWithStructureCheck(globalObject, status[0].structure());
+ ASSERT(status[0].structure().onlyStructure() == structure);
+ Node* base = cellConstantWithStructureCheck(globalObject, structure);
addToGraph(Phantom, get(VirtualRegister(scope)));
handlePutByOffset(base, identifierNumber, static_cast<PropertyOffset>(operand), get(VirtualRegister(value)));
// Keep scope alive until after put.
return;
case PutStructure:
- case PhantomPutStructure:
write(JSCell_structureID);
write(JSCell_typeInfoType);
write(JSCell_typeInfoFlags);
break;
}
+ case PutStructure: {
+ if (m_state.forNode(node->child1()).m_structure.onlyStructure() != node->transition()->next)
+ break;
+
+ node->convertToPhantom();
+ eliminated = true;
+ break;
+ }
+
case CheckFunction: {
if (m_state.forNode(node->child1()).value() != node->function()->value())
break;
}
case MultiGetByOffset: {
- Edge childEdge = node->child1();
- Node* child = childEdge.node();
+ Edge baseEdge = node->child1();
+ Node* base = baseEdge.node();
MultiGetByOffsetData& data = node->multiGetByOffsetData();
- Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
- if (!structure)
- break;
+ // First prune the variants, then check if the MultiGetByOffset can be
+ // strength-reduced to a GetByOffset.
- for (unsigned i = data.variants.size(); i--;) {
- const GetByIdVariant& variant = data.variants[i];
- if (!variant.structureSet().contains(structure))
- continue;
-
- if (variant.alternateBase())
- break;
-
- emitGetByOffset(indexInBlock, node, structure, variant, data.identifierNumber);
- eliminated = true;
- break;
+ AbstractValue baseValue = m_state.forNode(base);
+
+ m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
+ eliminated = true; // Don't allow the default constant folder to do things to this.
+
+ for (unsigned i = 0; i < data.variants.size(); ++i) {
+ GetByIdVariant& variant = data.variants[i];
+ variant.structureSet().filter(baseValue);
+ if (variant.structureSet().isEmpty()) {
+ data.variants[i--] = data.variants.last();
+ data.variants.removeLast();
+ }
}
+
+ if (data.variants.size() != 1)
+ break;
+
+ emitGetByOffset(
+ indexInBlock, node, baseValue, data.variants[0], data.identifierNumber);
break;
}
case MultiPutByOffset: {
- Edge childEdge = node->child1();
- Node* child = childEdge.node();
+ Edge baseEdge = node->child1();
+ Node* base = baseEdge.node();
MultiPutByOffsetData& data = node->multiPutByOffsetData();
+
+ AbstractValue baseValue = m_state.forNode(base);
- Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
- if (!structure)
- break;
+ m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
+ eliminated = true; // Don't allow the default constant folder to do things to this.
- for (unsigned i = data.variants.size(); i--;) {
- const PutByIdVariant& variant = data.variants[i];
- if (variant.oldStructure() != structure)
+
+ for (unsigned i = 0; i < data.variants.size(); ++i) {
+ PutByIdVariant& variant = data.variants[i];
+ variant.oldStructure().filter(baseValue);
+
+ if (variant.oldStructure().isEmpty()) {
+ data.variants[i--] = data.variants.last();
+ data.variants.removeLast();
continue;
+ }
- emitPutByOffset(indexInBlock, node, structure, variant, data.identifierNumber);
- eliminated = true;
- break;
+ if (variant.kind() == PutByIdVariant::Transition
+ && variant.oldStructure().onlyStructure() == variant.newStructure()) {
+ variant = PutByIdVariant::replace(
+ variant.oldStructure(),
+ variant.offset());
+ }
}
+
+ if (data.variants.size() != 1)
+ break;
+
+ emitPutByOffset(
+ indexInBlock, node, baseValue, data.variants[0], data.identifierNumber);
break;
}
Node* child = childEdge.node();
unsigned identifierNumber = node->identifierNumber();
- if (childEdge.useKind() != CellUse)
+ AbstractValue baseValue = m_state.forNode(child);
+
+ m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
+ eliminated = true; // Don't allow the default constant folder to do things to this.
+
+ if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered()
+ || (node->child1().useKind() == UntypedUse || (baseValue.m_type & ~SpecCell)))
break;
- Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
- if (!structure)
- break;
-
GetByIdStatus status = GetByIdStatus::computeFor(
- vm(), structure, m_graph.identifiers()[identifierNumber]);
+ vm(), baseValue.m_structure.set(), m_graph.identifiers()[identifierNumber]);
+ if (!status.isSimple())
+ break;
- if (!status.isSimple() || status.numVariants() != 1 ||
- !status[0].constantChecks().isEmpty() || status[0].alternateBase()) {
- // FIXME: We could handle prototype cases.
- // https://bugs.webkit.org/show_bug.cgi?id=110386
+ for (unsigned i = status.numVariants(); i--;) {
+ if (!status[i].constantChecks().isEmpty()
+ || status[i].alternateBase()) {
+ // FIXME: We could handle prototype cases.
+ // https://bugs.webkit.org/show_bug.cgi?id=110386
+ break;
+ }
+ }
+
+ if (status.numVariants() == 1) {
+ emitGetByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
break;
}
- emitGetByOffset(indexInBlock, node, structure, status[0], identifierNumber);
- eliminated = true;
+ if (!isFTL(m_graph.m_plan.mode))
+ break;
+
+ MultiGetByOffsetData* data = m_graph.m_multiGetByOffsetData.add();
+ data->variants = status.variants();
+ data->identifierNumber = identifierNumber;
+ node->convertToMultiGetByOffset(data);
break;
}
case PutById:
- case PutByIdDirect: {
+ case PutByIdDirect:
+ case PutByIdFlush: {
NodeOrigin origin = node->origin;
Edge childEdge = node->child1();
Node* child = childEdge.node();
ASSERT(childEdge.useKind() == CellUse);
- Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
- if (!structure)
+ AbstractValue baseValue = m_state.forNode(child);
+
+ m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
+ eliminated = true; // Don't allow the default constant folder to do things to this.
+
+ if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered())
break;
PutByIdStatus status = PutByIdStatus::computeFor(
vm(),
m_graph.globalObjectFor(origin.semantic),
- structure,
+ baseValue.m_structure.set(),
m_graph.identifiers()[identifierNumber],
node->op() == PutByIdDirect);
if (!status.isSimple())
break;
- if (status.numVariants() != 1)
+
+ for (unsigned i = status.numVariants(); i--;)
+ addChecks(origin, indexInBlock, status[i].constantChecks());
+
+ if (status.numVariants() == 1) {
+ emitPutByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
break;
+ }
- emitPutByOffset(indexInBlock, node, structure, status[0], identifierNumber);
- eliminated = true;
+ if (!isFTL(m_graph.m_plan.mode))
+ break;
+
+ MultiPutByOffsetData* data = m_graph.m_multiPutByOffsetData.add();
+ data->variants = status.variants();
+ data->identifierNumber = identifierNumber;
+ node->convertToMultiPutByOffset(data);
break;
}
return changed;
}
- void emitGetByOffset(unsigned indexInBlock, Node* node, Structure* structure, const GetByIdVariant& variant, unsigned identifierNumber)
+ void emitGetByOffset(unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const GetByIdVariant& variant, unsigned identifierNumber)
{
NodeOrigin origin = node->origin;
Edge childEdge = node->child1();
Node* child = childEdge.node();
- bool needsCellCheck = m_state.forNode(child).m_type & ~SpecCell;
-
- ASSERT(!variant.alternateBase());
- ASSERT_UNUSED(structure, variant.structureSet().contains(structure));
-
- // Now before we do anything else, push the CFA forward over the GetById
- // and make sure we signal to the loop that it should continue and not
- // do any eliminations.
- m_interpreter.execute(indexInBlock);
-
- if (needsCellCheck) {
- m_insertionSet.insertNode(
- indexInBlock, SpecNone, Phantom, origin, childEdge);
- }
+ addBaseCheck(indexInBlock, node, baseValue, variant.structureSet());
if (variant.specificValue()) {
m_graph.convertToConstant(node, m_graph.freeze(variant.specificValue()));
return;
}
- childEdge.setUseKind(KnownCellUse);
+ if (variant.alternateBase()) {
+ child = m_insertionSet.insertConstant(indexInBlock, origin, variant.alternateBase());
+ childEdge = Edge(child, KnownCellUse);
+ } else
+ childEdge.setUseKind(KnownCellUse);
Edge propertyStorage;
m_graph.m_storageAccessData.append(storageAccessData);
}
- void emitPutByOffset(unsigned indexInBlock, Node* node, Structure* structure, const PutByIdVariant& variant, unsigned identifierNumber)
+ void emitPutByOffset(unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const PutByIdVariant& variant, unsigned identifierNumber)
{
NodeOrigin origin = node->origin;
Edge childEdge = node->child1();
- Node* child = childEdge.node();
-
- ASSERT(variant.oldStructure() == structure);
-
- bool needsCellCheck = m_state.forNode(child).m_type & ~SpecCell;
- // Now before we do anything else, push the CFA forward over the PutById
- // and make sure we signal to the loop that it should continue and not
- // do any eliminations.
- m_interpreter.execute(indexInBlock);
-
- if (needsCellCheck) {
- m_insertionSet.insertNode(
- indexInBlock, SpecNone, Phantom, origin, childEdge);
- }
+ addBaseCheck(indexInBlock, node, baseValue, variant.oldStructure());
childEdge.setUseKind(KnownCellUse);
Transition* transition = 0;
if (variant.kind() == PutByIdVariant::Transition) {
- transition = m_graph.m_transitions.add(structure, variant.newStructure());
-
- for (unsigned i = 0; i < variant.constantChecks().size(); ++i) {
- addStructureTransitionCheck(
- origin, indexInBlock,
- variant.constantChecks()[i].constant(),
- variant.constantChecks()[i].structure());
- }
+ transition = m_graph.m_transitions.add(
+ variant.oldStructureForTransition(), variant.newStructure());
}
Edge propertyStorage;
if (isInlineOffset(variant.offset()))
propertyStorage = childEdge;
- else if (
- variant.kind() == PutByIdVariant::Replace
- || structure->outOfLineCapacity() == variant.newStructure()->outOfLineCapacity()) {
+ else if (!variant.reallocatesStorage()) {
propertyStorage = Edge(m_insertionSet.insertNode(
indexInBlock, SpecNone, GetButterfly, origin, childEdge));
- } else if (!structure->outOfLineCapacity()) {
+ } else if (!variant.oldStructureForTransition()->outOfLineCapacity()) {
ASSERT(variant.newStructure()->outOfLineCapacity());
ASSERT(!isInlineOffset(variant.offset()));
Node* allocatePropertyStorage = m_insertionSet.insertNode(
m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node->child1().node(), KnownCellUse));
propertyStorage = Edge(allocatePropertyStorage);
} else {
- ASSERT(structure->outOfLineCapacity());
- ASSERT(variant.newStructure()->outOfLineCapacity() > structure->outOfLineCapacity());
+ ASSERT(variant.oldStructureForTransition()->outOfLineCapacity());
+ ASSERT(variant.newStructure()->outOfLineCapacity() > variant.oldStructureForTransition()->outOfLineCapacity());
ASSERT(!isInlineOffset(variant.offset()));
Node* reallocatePropertyStorage = m_insertionSet.insertNode(
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
}
+
+ void addBaseCheck(
+ unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const StructureSet& set)
+ {
+ if (!baseValue.m_structure.isSubsetOf(set)) {
+ // Arises when we prune MultiGetByOffset. We could have a
+ // MultiGetByOffset with a single variant that checks for structure S,
+ // and the input has structures S and T, for example.
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, CheckStructure, node->origin,
+ OpInfo(m_graph.addStructureSet(set)), node->child1());
+ return;
+ }
+
+ if (baseValue.m_type & ~SpecCell) {
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, Phantom, node->origin, node->child1());
+ }
+ }
+
+ void addChecks(
+ NodeOrigin origin, unsigned indexInBlock, const ConstantStructureCheckVector& checks)
+ {
+ for (unsigned i = 0; i < checks.size(); ++i) {
+ addStructureTransitionCheck(
+ origin, indexInBlock, checks[i].constant(), checks[i].structure());
+ }
+ }
void addStructureTransitionCheck(NodeOrigin origin, unsigned indexInBlock, JSCell* cell, Structure* structure)
{
case PutByVal:
case PutByValAlias:
case PutStructure:
- case PhantomPutStructure:
case GetByOffset:
case GetGetterSetterByOffset:
case PutByOffset:
case Phi:
case Upsilon:
case GetArgument:
- case PhantomPutStructure:
case GetIndexedPropertyStorage:
case GetTypedArrayByteOffset:
case LastNodeType:
break;
case PutStructure:
- case PhantomPutStructure:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
visitor.appendUnbarrieredReadOnlyPointer(
case MultiPutByOffset:
for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
- visitor.appendUnbarrieredReadOnlyPointer(variant.oldStructure());
+ const StructureSet& set = variant.oldStructure();
+ for (unsigned j = set.size(); j--;)
+ visitor.appendUnbarrieredReadOnlyPointer(set[j]);
if (variant.kind() == PutByIdVariant::Transition)
visitor.appendUnbarrieredReadOnlyPointer(variant.newStructure());
}
FrozenValue* Graph::freezeStrong(JSValue value)
{
- FrozenValue* result = freeze(value);
+ FrozenValue* result = freezeFragile(value);
result->strengthenTo(StrongValue);
return result;
}
void dethread();
FrozenValue* freezeFragile(JSValue value);
- FrozenValue* freeze(JSValue value); // We use weak freezing by default.
- FrozenValue* freezeStrong(JSValue value); // Shorthand for freeze(value)->markStrongly().
+ FrozenValue* freeze(JSValue value); // We use weak freezing by default. Shorthand for freezeFragile(value)->strengthenTo(WeakValue);
+ FrozenValue* freezeStrong(JSValue value); // Shorthand for freezeFragile(value)->strengthenTo(StrongValue).
void convertToConstant(Node* node, FrozenValue* value);
void convertToConstant(Node* node, JSValue value);
bool MultiPutByOffsetData::writesStructures() const
{
for (unsigned i = variants.size(); i--;) {
- if (variants[i].kind() == PutByIdVariant::Transition)
+ if (variants[i].writesStructures())
return true;
}
return false;
bool MultiPutByOffsetData::reallocatesStorage() const
{
for (unsigned i = variants.size(); i--;) {
- if (variants[i].kind() != PutByIdVariant::Transition)
- continue;
-
- if (variants[i].oldStructure()->outOfLineCapacity() ==
- variants[i].newStructure()->outOfLineCapacity())
- continue;
-
- return true;
+ if (variants[i].reallocatesStorage())
+ return true;
}
return false;
}
m_flags &= ~NodeClobbersWorld;
}
+ void convertToMultiGetByOffset(MultiGetByOffsetData* data)
+ {
+ ASSERT(m_op == GetById || m_op == GetByIdFlush);
+ m_opInfo = bitwise_cast<intptr_t>(data);
+ child1().setUseKind(CellUse);
+ m_op = MultiGetByOffset;
+ m_flags &= ~NodeClobbersWorld;
+ }
+
void convertToPutByOffset(unsigned storageAccessDataIndex, Edge storage)
{
- ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == MultiPutByOffset);
+ ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == PutByIdFlush || m_op == MultiPutByOffset);
m_opInfo = storageAccessDataIndex;
children.setChild3(children.child2());
children.setChild2(children.child1());
m_flags &= ~NodeClobbersWorld;
}
+ void convertToMultiPutByOffset(MultiPutByOffsetData* data)
+ {
+ ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == PutByIdFlush);
+ m_opInfo = bitwise_cast<intptr_t>(data);
+ m_op = MultiPutByOffset;
+ m_flags &= ~NodeClobbersWorld;
+ }
+
void convertToPhantomLocal()
{
ASSERT(m_op == Phantom && (child1()->op() == Phi || child1()->op() == SetLocal || child1()->op() == SetArgument));
{
switch (op()) {
case PutStructure:
- case PhantomPutStructure:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
return true;
macro(CheckStructure, NodeMustGenerate) \
macro(CheckExecutable, NodeMustGenerate) \
macro(PutStructure, NodeMustGenerate) \
- macro(PhantomPutStructure, NodeMustGenerate) \
macro(AllocatePropertyStorage, NodeMustGenerate | NodeResultStorage) \
macro(ReallocatePropertyStorage, NodeMustGenerate | NodeResultStorage) \
macro(GetButterfly, NodeResultStorage) \
case GetLocalUnlinked:
case GetMyArgumentsLength:
case GetMyArgumentByVal:
- case PhantomPutStructure:
case PhantomArguments:
case CheckArray:
case Arrayify:
graph, node, state.forNode(graph.varArgChild(node, 0)));
case PutStructure:
- case PhantomPutStructure:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
return state.forNode(node->child1()).m_structure.isSubsetOf(
break;
}
- case PhantomPutStructure: {
- ASSERT(isKnownCell(node->child1().node()));
- m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node);
- noResult(node);
- break;
- }
-
case PutStructure: {
Structure* oldStructure = node->transition()->previous;
Structure* newStructure = node->transition()->next;
default:
m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
- RELEASE_ASSERT(spillFormat & DataFormatJS);
+ DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat & DataFormatJS);
break;
}
info.fillJSValue(*m_stream, gpr, spillFormat);
case DataFormatDouble:
case DataFormatInt52:
// this type currently never occurs
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format");
return InvalidGPRReg;
}
}
if (branchIndexInBlock != UINT_MAX) {
Node* branchNode = m_block->at(branchIndexInBlock);
- RELEASE_ASSERT(node->adjustedRefCount() == 1);
+ DFG_ASSERT(m_jit.graph(), node, node->adjustedRefCount() == 1);
nonSpeculativePeepholeBranchNull(operand, branchNode, invert);
bool isCall = node->op() == Call;
if (!isCall)
- RELEASE_ASSERT(node->op() == Construct);
-
+ DFG_ASSERT(m_jit.graph(), node, node->op() == Construct);
+
// For constructors, the this argument is not passed but we have to make space
// for it.
int dummyThisArgument = isCall ? 0 : 1;
DataFormat spillFormat = info.spillFormat();
- RELEASE_ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInt32);
+ DFG_ASSERT(m_jit.graph(), m_currentNode, (spillFormat & DataFormatJS) || spillFormat == DataFormatInt32);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
}
case DataFormatJS: {
- RELEASE_ASSERT(!(type & SpecInt52));
+ DFG_ASSERT(m_jit.graph(), m_currentNode, !(type & SpecInt52));
// Check the value is an integer.
GPRReg gpr = info.gpr();
m_gprs.lock(gpr);
case DataFormatStorage:
case DataFormatInt52:
case DataFormatStrictInt52:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format");
return InvalidGPRReg;
}
}
{
DataFormat mustBeDataFormatInt32;
GPRReg result = fillSpeculateInt32Internal<true>(edge, mustBeDataFormatInt32);
- RELEASE_ASSERT(mustBeDataFormatInt32 == DataFormatInt32);
+ DFG_ASSERT(m_jit.graph(), m_currentNode, mustBeDataFormatInt32 == DataFormatInt32);
return result;
}
DataFormat spillFormat = info.spillFormat();
- RELEASE_ASSERT(spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52);
+ DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
return InvalidGPRReg;
}
}
}
DataFormat spillFormat = info.spillFormat();
- RELEASE_ASSERT(spillFormat == DataFormatDouble);
+ DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat == DataFormatDouble);
FPRReg fpr = fprAllocate();
m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
return fpr;
}
- RELEASE_ASSERT(info.registerFormat() == DataFormatDouble);
+ DFG_ASSERT(m_jit.graph(), m_currentNode, info.registerFormat() == DataFormatDouble);
FPRReg fpr = info.fpr();
m_fprs.lock(fpr);
return fpr;
case DataFormatStorage:
case DataFormatInt52:
case DataFormatStrictInt52:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format");
return InvalidGPRReg;
}
}
terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
return gpr;
}
- RELEASE_ASSERT(info.spillFormat() & DataFormatJS);
+ DFG_ASSERT(m_jit.graph(), m_currentNode, info.spillFormat() & DataFormatJS);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
case DataFormatStorage:
case DataFormatInt52:
case DataFormatStrictInt52:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format");
return InvalidGPRReg;
}
}
return compileStringZeroLength(node);
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Bad use kind");
break;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), m_currentNode, "Bad use kind");
}
}
case Identity: {
// CSE should always eliminate this.
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Unexpected Identity node");
break;
}
case MovHint:
case ZombieHint:
case Check: {
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Unexpected node");
break;
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Bad flush format");
break;
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Bad use kind");
}
break;
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Bad use kind");
break;
}
break;
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Bad use kind");
break;
}
break;
switch (node->arrayMode().type()) {
case Array::SelectUsingPredictions:
case Array::ForceExit:
- RELEASE_ASSERT_NOT_REACHED();
- terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
+ DFG_CRASH(m_jit.graph(), node, "Bad array mode type");
break;
case Array::Generic: {
JSValueOperand base(this, node->child1());
switch (arrayMode.type()) {
case Array::SelectUsingPredictions:
case Array::ForceExit:
- RELEASE_ASSERT_NOT_REACHED();
- terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
- alreadyHandled = true;
+ DFG_CRASH(m_jit.graph(), node, "Bad array mode type");
break;
case Array::Generic: {
- RELEASE_ASSERT(node->op() == PutByVal);
+ DFG_ASSERT(m_jit.graph(), node, node->op() == PutByVal);
JSValueOperand arg1(this, child1);
JSValueOperand arg2(this, child2);
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Bad use kind");
break;
}
break;
}
case ToPrimitive: {
- RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
+ DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse);
JSValueOperand op1(this, node->child1());
GPRTemporary result(this, Reuse, op1);
JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType());
- RELEASE_ASSERT(structure->indexingType() == node->indexingType());
+ DFG_ASSERT(m_jit.graph(), node, structure->indexingType() == node->indexingType());
ASSERT(
hasUndecided(structure->indexingType())
|| hasInt32(structure->indexingType())
emitAllocateJSArray(resultGPR, globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), storageGPR, numElements);
- RELEASE_ASSERT(indexingType & IsArray);
+ DFG_ASSERT(m_jit.graph(), node, indexingType & IsArray);
JSValue* data = m_jit.codeBlock()->constantBuffer(node->startConstant());
if (indexingType == ArrayWithDouble) {
for (unsigned index = 0; index < node->numConstants(); ++index) {
break;
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Bad use kind");
break;
}
break;
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Bad use kind");
break;
}
break;
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Bad use kind");
break;
}
break;
break;
}
- case PhantomPutStructure: {
- ASSERT(isKnownCell(node->child1().node()));
- m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node);
- noResult(node);
- break;
- }
-
case PutStructure: {
Structure* oldStructure = node->transition()->previous;
Structure* newStructure = node->transition()->next;
break;
case CreateActivation: {
- RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame);
+ DFG_ASSERT(m_jit.graph(), node, !node->origin.semantic.inlineCallFrame);
JSValueOperand value(this, node->child1());
GPRTemporary result(this, Reuse, value);
}
case TearOffActivation: {
- RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame);
+ DFG_ASSERT(m_jit.graph(), node, !node->origin.semantic.inlineCallFrame);
JSValueOperand activationValue(this, node->child1());
GPRTemporary scratch(this);
m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic))));
}
- RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame);
+ DFG_ASSERT(m_jit.graph(), node, !node->origin.semantic.inlineCallFrame);
m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), resultGPR);
m_jit.sub32(TrustedImm32(1), resultGPR);
int32Result(resultGPR, node);
JITCompiler::JumpList slowArgument;
JITCompiler::JumpList slowArgumentOutOfBounds;
if (m_jit.symbolTableFor(node->origin.semantic)->slowArguments()) {
- RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame);
+ DFG_ASSERT(m_jit.graph(), node, !node->origin.semantic.inlineCallFrame);
const SlowArgument* slowArguments = m_jit.graph().m_slowArguments.get();
slowArgumentOutOfBounds.append(
JITCompiler::JumpList slowArgument;
JITCompiler::JumpList slowArgumentOutOfBounds;
if (m_jit.symbolTableFor(node->origin.semantic)->slowArguments()) {
- RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame);
+ DFG_ASSERT(m_jit.graph(), node, !node->origin.semantic.inlineCallFrame);
const SlowArgument* slowArguments = m_jit.graph().m_slowArguments.get();
slowArgumentOutOfBounds.append(
break;
case Unreachable:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Unexpected Unreachable node");
break;
case StoreBarrier:
case CheckTierUpInLoop:
case CheckTierUpAtReturn:
case CheckTierUpAndOSREnter:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Unexpected tier-up node");
break;
#endif // ENABLE(FTL_JIT)
case MultiGetByOffset:
case MultiPutByOffset:
case FiatInt52:
- RELEASE_ASSERT_NOT_REACHED();
+ DFG_CRASH(m_jit.graph(), node, "Unexpected FTL node");
break;
}
void StructureAbstractValue::observeTransition(Structure* from, Structure* to)
{
SAMPLE("StructureAbstractValue observeTransition");
+
+ ASSERT(!from->dfgShouldWatch());
if (isTop())
return;
if (!m_set.contains(from))
return;
- if (from->dfgShouldWatch()) {
- setClobbered(true);
- return;
- }
-
if (!m_set.add(to))
return;
StructureSet newStructures;
for (unsigned i = vector.size(); i--;) {
+ ASSERT(!vector[i].previous->dfgShouldWatch());
+
if (!m_set.contains(vector[i].previous))
continue;
- if (vector[i].previous->dfgShouldWatch())
- setClobbered(true);
- else
- newStructures.add(vector[i].next);
+ newStructures.add(vector[i].next);
}
if (!m_set.merge(newStructures))
setClobbered(other.isClobbered());
}
+ ALWAYS_INLINE StructureAbstractValue& operator=(Structure* structure)
+ {
+ m_set = structure;
+ setClobbered(false);
+ return *this;
+ }
+ ALWAYS_INLINE StructureAbstractValue& operator=(const StructureSet& other)
+ {
+ m_set = other;
+ setClobbered(false);
+ return *this;
+ }
ALWAYS_INLINE StructureAbstractValue& operator=(const StructureAbstractValue& other)
{
m_set = other.m_set;
return equalsSlow(other);
}
+ const StructureSet& set() const
+ {
+ ASSERT(!isTop());
+ return m_set;
+ }
+
size_t size() const
{
ASSERT(!isTop());
Structure* operator[](size_t i) const { return at(i); }
- // FIXME: Eliminate all uses of this method. There shouldn't be any
- // special-casing for the one-structure case.
- // https://bugs.webkit.org/show_bug.cgi?id=133229
+ // In most cases, what you really want to do is verify whether the set is top or clobbered, and
+ // if not, enumerate the set of structures. Use this only in cases where the singleton case is
+ // meaningfully special, like for transitions.
Structure* onlyStructure() const
{
- if (isTop() || size() != 1)
+ if (isTop() || isClobbered())
return nullptr;
- return at(0);
+ return m_set.onlyStructure();
}
void dumpInContext(PrintStream&, DumpContext*) const;
VALIDATE((node), !!node->child1());
VALIDATE((node), !!node->child2());
break;
+ case PutStructure:
+ VALIDATE((node), !node->transition()->previous->dfgShouldWatch());
+ break;
+ case MultiPutByOffset:
+ for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
+ const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
+ if (variant.kind() != PutByIdVariant::Transition)
+ continue;
+ VALIDATE((node), !variant.oldStructureForTransition()->dfgShouldWatch());
+ }
+ break;
default:
break;
}
break;
case PutStructure:
- case PhantomPutStructure:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
RELEASE_ASSERT(node->transition()->previous->transitionWatchpointSetHasBeenInvalidated());
static inline void addTargetDependentFunctionAttr(LValue function, const char* key, const char* value) { llvm->AddTargetDependentFunctionAttr(function, key, value); }
static inline void removeFunctionAttr(LValue function, LLVMAttribute pa) { llvm->RemoveFunctionAttr(function, pa); }
-
-
+static inline LLVMLinkage getLinkage(LValue global) { return llvm->GetLinkage(global); }
static inline void setLinkage(LValue global, LLVMLinkage linkage) { llvm->SetLinkage(global, linkage); }
static inline void setVisibility(LValue global, LLVMVisibility viz) { llvm->SetVisibility(global, viz); }
static inline LLVMBool isDeclaration(LValue global) { return llvm->IsDeclaration(global); }
static inline LValue getFirstGlobal(LModule module) { return llvm->GetFirstGlobal(module); }
static inline LValue getNextGlobal(LValue global) { return llvm->GetNextGlobal(global); }
-
-
-
-
static inline LValue addExternFunction(LModule module, const char* name, LType type)
{
LValue result = addFunction(module, name, type);
case CheckStructure:
case ArrayifyToStructure:
case PutStructure:
- case PhantomPutStructure:
case GetButterfly:
case NewObject:
case NewArray:
case PutStructure:
compilePutStructure();
break;
- case PhantomPutStructure:
- compilePhantomPutStructure();
- break;
case GetById:
compileGetById();
break;
cell, m_heaps.JSCell_structureID);
}
- void compilePhantomPutStructure()
- {
- m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
- }
-
void compileGetById()
{
// Pretty much the only reason why we don't also support GetByIdFlush is because:
LValue base = lowCell(m_node->child1());
MultiGetByOffsetData& data = m_node->multiGetByOffsetData();
+
+ if (data.variants.isEmpty()) {
+ // Protect against creating a Phi function with zero inputs. LLVM doesn't like that.
+ terminate(BadCache);
+ return;
+ }
Vector<LBasicBlock, 2> blocks(data.variants.size());
for (unsigned i = data.variants.size(); i--;)
Vector<SwitchCase, 2> cases;
for (unsigned i = data.variants.size(); i--;) {
PutByIdVariant variant = data.variants[i];
- cases.append(
- SwitchCase(weakStructure(variant.oldStructure()), blocks[i], Weight(1)));
+ for (unsigned j = variant.oldStructure().size(); j--;) {
+ cases.append(
+ SwitchCase(weakStructure(variant.oldStructure()[j]), blocks[i], Weight(1)));
+ }
}
m_out.switchInstruction(
m_out.load32(base, m_heaps.JSCell_structureID), cases, exit, Weight(0));
} else {
m_graph.m_plan.transitions.addLazily(
codeBlock(), m_node->origin.semantic.codeOriginOwner(),
- variant.oldStructure(), variant.newStructure());
+ variant.oldStructureForTransition(), variant.newStructure());
storage = storageForTransition(
- base, variant.offset(), variant.oldStructure(), variant.newStructure());
+ base, variant.offset(),
+ variant.oldStructureForTransition(), variant.newStructure());
- ASSERT(variant.oldStructure()->indexingType() == variant.newStructure()->indexingType());
- ASSERT(variant.oldStructure()->typeInfo().inlineTypeFlags() == variant.newStructure()->typeInfo().inlineTypeFlags());
- ASSERT(variant.oldStructure()->typeInfo().type() == variant.newStructure()->typeInfo().type());
+ ASSERT(variant.oldStructureForTransition()->indexingType() == variant.newStructure()->indexingType());
+ ASSERT(variant.oldStructureForTransition()->typeInfo().inlineTypeFlags() == variant.newStructure()->typeInfo().inlineTypeFlags());
+ ASSERT(variant.oldStructureForTransition()->typeInfo().type() == variant.newStructure()->typeInfo().type());
m_out.store32(
weakStructure(variant.newStructure()), base, m_heaps.JSCell_structureID);
}
for (CString* symbol = namedFunctions.begin(); symbol != namedFunctions.end(); ++symbol) {
LValue function = getNamedFunction(m_ftlState.module, symbol->data());
- setVisibility(function, LLVMHiddenVisibility);
+ LLVMLinkage linkage = getLinkage(function);
+ if (linkage != LLVMInternalLinkage && linkage != LLVMPrivateLinkage)
+ setVisibility(function, LLVMHiddenVisibility);
if (!isDeclaration(function)) {
setLinkage(function, LLVMPrivateLinkage);
for (CString* symbol = namedGlobals.begin(); symbol != namedGlobals.end(); ++symbol) {
LValue global = getNamedGlobal(m_ftlState.module, symbol->data());
- setVisibility(global, LLVMHiddenVisibility);
+ LLVMLinkage linkage = getLinkage(global);
+ if (linkage != LLVMInternalLinkage && linkage != LLVMPrivateLinkage)
+ setVisibility(global, LLVMHiddenVisibility);
if (!isDeclaration(global))
setLinkage(global, LLVMPrivateLinkage);
}
#include "HeapIterationScope.h"
#include "HeapRootVisitor.h"
#include "HeapStatistics.h"
+#include "HighFidelityLog.h"
#include "IncrementalSweeper.h"
#include "Interpreter.h"
#include "JSGlobalObject.h"
#if ENABLE(ALLOCATION_LOGGING)
dataLogF("JSC GC starting collection.\n");
#endif
+ if (vm()->isProfilingTypesWithHighFidelity())
+ vm()->highFidelityLog()->processHighFidelityLog(false, "GC");
double before = 0;
if (Options::logGC()) {
{
}
+void InspectorRuntimeAgent::getRuntimeTypeForVariableInTextRange(ErrorString*, const String& in_variableName, const String& in_id, int in_startLine, int in_startColumn, int in_endLine, int in_endColumn, String* out_types)
+{
+ VM& vm = globalVM();
+ String types(vm.getTypesForVariableInRange(in_startLine, in_startColumn, in_endLine, in_endColumn, in_variableName, in_id));
+ *out_types = types;
+}
+
} // namespace Inspector
#endif // ENABLE(INSPECTOR)
virtual void getProperties(ErrorString*, const String& objectId, const bool* ownProperties, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::InternalPropertyDescriptor>>& internalProperties) override final;
virtual void releaseObjectGroup(ErrorString*, const String& objectGroup) override final;
virtual void run(ErrorString*) override;
+ virtual void getRuntimeTypeForVariableInTextRange(ErrorString*, const String& in_variableName, const String& in_id, int in_startLine, int in_startColumn, int in_endLine, int in_endColumn, String* out_types) override;
void setScriptDebugServer(ScriptDebugServer* scriptDebugServer) { m_scriptDebugServer = scriptDebugServer; }
{
"name": "disable",
"description": "Disables reporting of execution contexts creation."
+ },
+ {
+ "name": "getRuntimeTypeForVariableInTextRange",
+ "parameters": [
+ { "name": "variableName", "type": "string", "description": "Variable we want type infromation for." },
+ { "name": "sourceID", "type": "string", "description": "sourceID uniquely identifying a script" },
+ { "name": "startLine", "type": "integer", "description": "start line for variable name" },
+ { "name": "startColumn", "type": "integer", "description": "start column for variable name" },
+ { "name": "endLine", "type": "integer", "description": "end line for variable name" },
+ { "name": "endColumn", "type": "integer", "description": "end column for variable name" }
+ ],
+ "returns": [
+ { "name": "types", "type": "string", "description": "Types for requested variable." }
+ ],
+ "description": "Returns detailed informtation on given function."
}
],
"events": [
#include "ArrayPrototype.h"
#include "ButterflyInlines.h"
#include "BytecodeGenerator.h"
+#include "CodeBlock.h"
#include "Completion.h"
#include "CopiedSpaceInlines.h"
#include "ExceptionHelpers.h"
static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables (ExecState*);
#if ENABLE(SAMPLING_FLAGS)
static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
+ addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 4);
JSArray* array = constructEmptyArray(globalExec(), 0);
for (size_t i = 0; i < arguments.size(); ++i)
return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
}
+EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
+{
+ exec->vm().dumpHighFidelityProfilingTypes();
+ return JSValue::encode(jsUndefined());
+}
+
// Use SEH for Release builds only to get rid of the crash report dialog
// (luckily the same tests fail in Release and Debug builds so far). Need to
// be in a separate main function because the jscmain function requires object
#elif CPU(X86_64) && OS(WINDOWS)
ASSERT(maxFrameExtentForSlowPathCall == 64);
#endif
- ASSERT(StringType == 5);
- ASSERT(ObjectType == 18);
- ASSERT(FinalObjectType == 19);
+ ASSERT(StringType == 6);
+ ASSERT(ObjectType == 17);
+ ASSERT(FinalObjectType == 18);
ASSERT(MasqueradesAsUndefined == 1);
ASSERT(ImplementsHasInstance == 2);
ASSERT(ImplementsDefaultHasInstance == 8);