Merge r171389, r171495, r171508, r171510, r171605, r171606, r171611, r171614, r171763 from ftlopt.
Source/JavaScriptCore:
2014-07-28 Mark Hahnenberg <mhahnenberg@apple.com>
Support for-in in the FTL
https://bugs.webkit.org/show_bug.cgi?id=134140
Reviewed by Filip Pizlo.
* dfg/DFGSSALoweringPhase.cpp:
(JSC::DFG::SSALoweringPhase::handleNode):
* ftl/FTLAbstractHeapRepository.cpp:
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileHasIndexedProperty):
(JSC::FTL::LowerDFGToLLVM::compileHasGenericProperty):
(JSC::FTL::LowerDFGToLLVM::compileHasStructureProperty):
(JSC::FTL::LowerDFGToLLVM::compileGetDirectPname):
(JSC::FTL::LowerDFGToLLVM::compileGetEnumerableLength):
(JSC::FTL::LowerDFGToLLVM::compileGetStructurePropertyEnumerator):
(JSC::FTL::LowerDFGToLLVM::compileGetGenericPropertyEnumerator):
(JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorPname):
(JSC::FTL::LowerDFGToLLVM::compileToIndexString):
2014-07-25 Mark Hahnenberg <mhahnenberg@apple.com>
Remove JSPropertyNameIterator
https://bugs.webkit.org/show_bug.cgi?id=135066
Reviewed by Geoffrey Garen.
It has been replaced by JSPropertyNameEnumerator.
* JavaScriptCore.order:
* bytecode/BytecodeBasicBlock.cpp:
(JSC::isBranch):
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecode/PreciseJumpTargets.cpp:
(JSC::getJumpTargetsForBytecodeOffset):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetPropertyNames): Deleted.
(JSC::BytecodeGenerator::emitNextPropertyName): Deleted.
* bytecompiler/BytecodeGenerator.h:
* interpreter/Interpreter.cpp:
* interpreter/Register.h:
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_get_pnames): Deleted.
(JSC::JIT::emit_op_next_pname): Deleted.
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_get_pnames): Deleted.
(JSC::JIT::emit_op_next_pname): Deleted.
* jit/JITOperations.cpp:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_pname): Deleted.
(JSC::JIT::emitSlow_op_get_by_pname): Deleted.
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_by_pname): Deleted.
(JSC::JIT::emitSlow_op_get_by_pname): Deleted.
* llint/LLIntOffsetsExtractor.cpp:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL): Deleted.
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
* runtime/JSPropertyNameIterator.cpp:
(JSC::JSPropertyNameIterator::JSPropertyNameIterator): Deleted.
(JSC::JSPropertyNameIterator::create): Deleted.
(JSC::JSPropertyNameIterator::destroy): Deleted.
(JSC::JSPropertyNameIterator::get): Deleted.
(JSC::JSPropertyNameIterator::visitChildren): Deleted.
* runtime/JSPropertyNameIterator.h:
(JSC::JSPropertyNameIterator::createStructure): Deleted.
(JSC::JSPropertyNameIterator::size): Deleted.
(JSC::JSPropertyNameIterator::setCachedStructure): Deleted.
(JSC::JSPropertyNameIterator::cachedStructure): Deleted.
(JSC::JSPropertyNameIterator::setCachedPrototypeChain): Deleted.
(JSC::JSPropertyNameIterator::cachedPrototypeChain): Deleted.
(JSC::JSPropertyNameIterator::finishCreation): Deleted.
(JSC::Register::propertyNameIterator): Deleted.
(JSC::StructureRareData::enumerationCache): Deleted.
(JSC::StructureRareData::setEnumerationCache): Deleted.
* runtime/Structure.cpp:
(JSC::Structure::addPropertyWithoutTransition):
(JSC::Structure::removePropertyWithoutTransition):
* runtime/Structure.h:
* runtime/StructureInlines.h:
(JSC::Structure::setEnumerationCache): Deleted.
(JSC::Structure::enumerationCache): Deleted.
* runtime/StructureRareData.cpp:
(JSC::StructureRareData::visitChildren):
* runtime/StructureRareData.h:
* runtime/VM.cpp:
(JSC::VM::VM):
2014-07-25 Saam Barati <sbarati@apple.com>
Fix 32-bit build breakage for type profiling
https://bugs.webkit.org/process_bug.cgi
Reviewed by Mark Hahnenberg.
32-bit builds currently break because global variable IDs for high
fidelity type profiling are int64_t. Change this to intptr_t so that
it's 32 bits on 32-bit platforms and 64 bits on 64-bit platforms.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::scopeDependentProfile):
* bytecode/TypeLocation.h:
* runtime/SymbolTable.cpp:
(JSC::SymbolTable::uniqueIDForVariable):
(JSC::SymbolTable::uniqueIDForRegister):
* runtime/SymbolTable.h:
* runtime/TypeLocationCache.cpp:
(JSC::TypeLocationCache::getTypeLocation):
* runtime/TypeLocationCache.h:
* runtime/VM.h:
(JSC::VM::getNextUniqueVariableID):
2014-07-25 Mark Hahnenberg <mhahnenberg@apple.com>
Reindent PropertyNameArray.h
https://bugs.webkit.org/show_bug.cgi?id=135067
Reviewed by Geoffrey Garen.
* runtime/PropertyNameArray.h:
(JSC::RefCountedIdentifierSet::contains):
(JSC::RefCountedIdentifierSet::size):
(JSC::RefCountedIdentifierSet::add):
(JSC::PropertyNameArrayData::create):
(JSC::PropertyNameArrayData::propertyNameVector):
(JSC::PropertyNameArrayData::PropertyNameArrayData):
(JSC::PropertyNameArray::PropertyNameArray):
(JSC::PropertyNameArray::vm):
(JSC::PropertyNameArray::add):
(JSC::PropertyNameArray::addKnownUnique):
(JSC::PropertyNameArray::operator[]):
(JSC::PropertyNameArray::setData):
(JSC::PropertyNameArray::data):
(JSC::PropertyNameArray::releaseData):
(JSC::PropertyNameArray::identifierSet):
(JSC::PropertyNameArray::canAddKnownUniqueForStructure):
(JSC::PropertyNameArray::size):
(JSC::PropertyNameArray::begin):
(JSC::PropertyNameArray::end):
(JSC::PropertyNameArray::numCacheableSlots):
(JSC::PropertyNameArray::setNumCacheableSlotsForObject):
(JSC::PropertyNameArray::setBaseObject):
(JSC::PropertyNameArray::setPreviouslyEnumeratedLength):
2014-07-23 Mark Hahnenberg <mhahnenberg@apple.com>
Refactor our current implementation of for-in
https://bugs.webkit.org/show_bug.cgi?id=134142
Reviewed by Filip Pizlo.
This patch splits for-in loops into three distinct parts:
- Iterating over the indexed properties in the base object.
- Iterating over the Structure properties in the base object.
- Iterating over any other enumerable properties for that object and any objects in the prototype chain.
It does this by emitting these explicit loops in bytecode, using a new set of bytecodes to
support the various operations required for each loop.
* API/JSCallbackObjectFunctions.h:
(JSC::JSCallbackObject<Parent>::getOwnNonIndexPropertyNames):
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CallLinkStatus.h:
(JSC::CallLinkStatus::CallLinkStatus):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetByVal):
(JSC::BytecodeGenerator::emitComplexPopScopes):
(JSC::BytecodeGenerator::emitGetEnumerableLength):
(JSC::BytecodeGenerator::emitHasGenericProperty):
(JSC::BytecodeGenerator::emitHasIndexedProperty):
(JSC::BytecodeGenerator::emitHasStructureProperty):
(JSC::BytecodeGenerator::emitGetStructurePropertyEnumerator):
(JSC::BytecodeGenerator::emitGetGenericPropertyEnumerator):
(JSC::BytecodeGenerator::emitNextEnumeratorPropertyName):
(JSC::BytecodeGenerator::emitToIndexString):
(JSC::BytecodeGenerator::pushIndexedForInScope):
(JSC::BytecodeGenerator::popIndexedForInScope):
(JSC::BytecodeGenerator::pushStructureForInScope):
(JSC::BytecodeGenerator::popStructureForInScope):
(JSC::BytecodeGenerator::invalidateForInContextForLocal):
* bytecompiler/BytecodeGenerator.h:
(JSC::ForInContext::ForInContext):
(JSC::ForInContext::~ForInContext):
(JSC::ForInContext::isValid):
(JSC::ForInContext::invalidate):
(JSC::ForInContext::local):
(JSC::StructureForInContext::StructureForInContext):
(JSC::StructureForInContext::type):
(JSC::StructureForInContext::index):
(JSC::StructureForInContext::property):
(JSC::StructureForInContext::enumerator):
(JSC::IndexedForInContext::IndexedForInContext):
(JSC::IndexedForInContext::type):
(JSC::IndexedForInContext::index):
(JSC::BytecodeGenerator::pushOptimisedForIn): Deleted.
(JSC::BytecodeGenerator::popOptimisedForIn): Deleted.
* bytecompiler/NodesCodegen.cpp:
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ForInNode::tryGetBoundLocal):
(JSC::ForInNode::emitLoopHeader):
(JSC::ForInNode::emitMultiLoopBytecode):
(JSC::ForInNode::emitBytecode):
* debugger/DebuggerScope.h:
* dfg/DFGAbstractHeap.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGHeapLocation.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasArrayMode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
(JSC::JIT::compileHasIndexedProperty):
(JSC::JIT::emitInt32Load):
* jit/JITInlines.h:
(JSC::JIT::emitDoubleGetByVal):
(JSC::JIT::emitLoadForArrayMode):
(JSC::JIT::emitContiguousGetByVal):
(JSC::JIT::emitArrayStorageGetByVal):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_get_enumerable_length):
(JSC::JIT::emit_op_has_structure_property):
(JSC::JIT::emitSlow_op_has_structure_property):
(JSC::JIT::emit_op_has_generic_property):
(JSC::JIT::privateCompileHasIndexedProperty):
(JSC::JIT::emit_op_has_indexed_property):
(JSC::JIT::emitSlow_op_has_indexed_property):
(JSC::JIT::emit_op_get_direct_pname):
(JSC::JIT::emitSlow_op_get_direct_pname):
(JSC::JIT::emit_op_get_structure_property_enumerator):
(JSC::JIT::emit_op_get_generic_property_enumerator):
(JSC::JIT::emit_op_next_enumerator_pname):
(JSC::JIT::emit_op_to_index_string):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_get_enumerable_length):
(JSC::JIT::emit_op_has_structure_property):
(JSC::JIT::emitSlow_op_has_structure_property):
(JSC::JIT::emit_op_has_generic_property):
(JSC::JIT::privateCompileHasIndexedProperty):
(JSC::JIT::emit_op_has_indexed_property):
(JSC::JIT::emitSlow_op_has_indexed_property):
(JSC::JIT::emit_op_get_direct_pname):
(JSC::JIT::emitSlow_op_get_direct_pname):
(JSC::JIT::emit_op_get_structure_property_enumerator):
(JSC::JIT::emit_op_get_generic_property_enumerator):
(JSC::JIT::emit_op_next_enumerator_pname):
(JSC::JIT::emit_op_to_index_string):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitDoubleLoad):
(JSC::JIT::emitContiguousLoad):
(JSC::JIT::emitArrayStorageLoad):
(JSC::JIT::emitDoubleGetByVal): Deleted.
(JSC::JIT::emitContiguousGetByVal): Deleted.
(JSC::JIT::emitArrayStorageGetByVal): Deleted.
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emitContiguousLoad):
(JSC::JIT::emitDoubleLoad):
(JSC::JIT::emitArrayStorageLoad):
(JSC::JIT::emitContiguousGetByVal): Deleted.
(JSC::JIT::emitDoubleGetByVal): Deleted.
(JSC::JIT::emitArrayStorageGetByVal): Deleted.
* llint/LowLevelInterpreter.asm:
* parser/Nodes.h:
* runtime/Arguments.cpp:
(JSC::Arguments::getOwnPropertyNames):
* runtime/ClassInfo.h:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* runtime/EnumerationMode.h: Added.
(JSC::shouldIncludeDontEnumProperties):
(JSC::shouldExcludeDontEnumProperties):
(JSC::shouldIncludeJSObjectPropertyNames):
(JSC::modeThatSkipsJSObject):
* runtime/JSActivation.cpp:
(JSC::JSActivation::getOwnNonIndexPropertyNames):
* runtime/JSArray.cpp:
(JSC::JSArray::getOwnNonIndexPropertyNames):
* runtime/JSArrayBuffer.cpp:
(JSC::JSArrayBuffer::getOwnNonIndexPropertyNames):
* runtime/JSArrayBufferView.cpp:
(JSC::JSArrayBufferView::getOwnNonIndexPropertyNames):
* runtime/JSCell.cpp:
(JSC::JSCell::getEnumerableLength):
(JSC::JSCell::getStructurePropertyNames):
(JSC::JSCell::getGenericPropertyNames):
* runtime/JSCell.h:
* runtime/JSFunction.cpp:
(JSC::JSFunction::getOwnNonIndexPropertyNames):
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::getOwnNonIndexPropertyNames):
* runtime/JSObject.cpp:
(JSC::getClassPropertyNames):
(JSC::JSObject::hasOwnProperty):
(JSC::JSObject::getOwnPropertyNames):
(JSC::JSObject::getOwnNonIndexPropertyNames):
(JSC::JSObject::getEnumerableLength):
(JSC::JSObject::getStructurePropertyNames):
(JSC::JSObject::getGenericPropertyNames):
* runtime/JSObject.h:
* runtime/JSPropertyNameEnumerator.cpp: Added.
(JSC::JSPropertyNameEnumerator::create):
(JSC::JSPropertyNameEnumerator::JSPropertyNameEnumerator):
(JSC::JSPropertyNameEnumerator::finishCreation):
(JSC::JSPropertyNameEnumerator::destroy):
(JSC::JSPropertyNameEnumerator::visitChildren):
* runtime/JSPropertyNameEnumerator.h: Added.
(JSC::JSPropertyNameEnumerator::createStructure):
(JSC::JSPropertyNameEnumerator::propertyNameAtIndex):
(JSC::JSPropertyNameEnumerator::identifierSet):
(JSC::JSPropertyNameEnumerator::cachedPrototypeChain):
(JSC::JSPropertyNameEnumerator::setCachedPrototypeChain):
(JSC::JSPropertyNameEnumerator::cachedStructure):
(JSC::JSPropertyNameEnumerator::cachedStructureID):
(JSC::JSPropertyNameEnumerator::cachedInlineCapacity):
(JSC::JSPropertyNameEnumerator::cachedStructureIDOffset):
(JSC::JSPropertyNameEnumerator::cachedInlineCapacityOffset):
(JSC::JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset):
(JSC::JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset):
(JSC::structurePropertyNameEnumerator):
(JSC::genericPropertyNameEnumerator):
* runtime/JSProxy.cpp:
(JSC::JSProxy::getEnumerableLength):
(JSC::JSProxy::getStructurePropertyNames):
(JSC::JSProxy::getGenericPropertyNames):
* runtime/JSProxy.h:
* runtime/JSSymbolTableObject.cpp:
(JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames):
* runtime/PropertyNameArray.cpp:
(JSC::PropertyNameArray::add):
(JSC::PropertyNameArray::setPreviouslyEnumeratedProperties):
* runtime/PropertyNameArray.h:
(JSC::RefCountedIdentifierSet::contains):
(JSC::RefCountedIdentifierSet::size):
(JSC::RefCountedIdentifierSet::add):
(JSC::PropertyNameArray::PropertyNameArray):
(JSC::PropertyNameArray::add):
(JSC::PropertyNameArray::addKnownUnique):
(JSC::PropertyNameArray::identifierSet):
(JSC::PropertyNameArray::canAddKnownUniqueForStructure):
(JSC::PropertyNameArray::setPreviouslyEnumeratedLength):
* runtime/RegExpObject.cpp:
(JSC::RegExpObject::getOwnNonIndexPropertyNames):
(JSC::RegExpObject::getPropertyNames):
(JSC::RegExpObject::getGenericPropertyNames):
* runtime/RegExpObject.h:
* runtime/StringObject.cpp:
(JSC::StringObject::getOwnPropertyNames):
* runtime/Structure.cpp:
(JSC::Structure::getPropertyNamesFromStructure):
(JSC::Structure::setCachedStructurePropertyNameEnumerator):
(JSC::Structure::cachedStructurePropertyNameEnumerator):
(JSC::Structure::setCachedGenericPropertyNameEnumerator):
(JSC::Structure::cachedGenericPropertyNameEnumerator):
(JSC::Structure::canCacheStructurePropertyNameEnumerator):
(JSC::Structure::canCacheGenericPropertyNameEnumerator):
(JSC::Structure::canAccessPropertiesQuickly):
* runtime/Structure.h:
* runtime/StructureRareData.cpp:
(JSC::StructureRareData::visitChildren):
(JSC::StructureRareData::cachedStructurePropertyNameEnumerator):
(JSC::StructureRareData::setCachedStructurePropertyNameEnumerator):
(JSC::StructureRareData::cachedGenericPropertyNameEnumerator):
(JSC::StructureRareData::setCachedGenericPropertyNameEnumerator):
* runtime/StructureRareData.h:
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
2014-07-23 Saam Barati <sbarati@apple.com>
Make improvements to Type Profiling
https://bugs.webkit.org/show_bug.cgi?id=134860
Reviewed by Filip Pizlo.
I improved the API between the inspector and JSC. We no longer send one huge
string to the inspector. We now send structured data that represents the type
information that JSC has collected. I've also created a beginning implementation
of a type lattice that allows us to resolve a display name for a type that
consists of a single word.
I created a data structure that knows which functions have executed. This
solves the bug where types inside an un-executed function will resolve
to the type of the enclosing expression of that function. This data
structure may also be useful later if the inspector chooses to create a UI
around showing which functions have executed.
Better type information is gathered for objects. StructureShape now
represents an object's prototype chain. StructureShape also collects
the constructor name for an object.
Expression ranges are now zero indexed.
Removed some extraneous methods.
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::scopeDependentProfile):
* bytecode/CodeBlock.h:
* bytecode/TypeLocation.h:
(JSC::TypeLocation::TypeLocation):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedFunctionExecutable::highFidelityTypeProfilingStartOffset):
(JSC::UnlinkedFunctionExecutable::highFidelityTypeProfilingEndOffset):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitHighFidelityTypeProfilingExpressionInfo):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::emitHighFidelityTypeProfilingExpressionInfo): Deleted.
* heap/Heap.cpp:
(JSC::Heap::collect):
* inspector/agents/InspectorRuntimeAgent.cpp:
(Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets):
(Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableAtOffset): Deleted.
* inspector/agents/InspectorRuntimeAgent.h:
* inspector/protocol/Runtime.json:
* runtime/Executable.cpp:
(JSC::ScriptExecutable::ScriptExecutable):
(JSC::ProgramExecutable::ProgramExecutable):
(JSC::FunctionExecutable::FunctionExecutable):
(JSC::ProgramExecutable::initializeGlobalProperties):
* runtime/Executable.h:
(JSC::ScriptExecutable::highFidelityTypeProfilingStartOffset):
(JSC::ScriptExecutable::highFidelityTypeProfilingEndOffset):
* runtime/FunctionHasExecutedCache.cpp: Added.
(JSC::FunctionHasExecutedCache::hasExecutedAtOffset):
(JSC::FunctionHasExecutedCache::insertUnexecutedRange):
(JSC::FunctionHasExecutedCache::removeUnexecutedRange):
* runtime/FunctionHasExecutedCache.h: Added.
(JSC::FunctionHasExecutedCache::FunctionRange::FunctionRange):
(JSC::FunctionHasExecutedCache::FunctionRange::operator==):
(JSC::FunctionHasExecutedCache::FunctionRange::hash):
* runtime/HighFidelityLog.cpp:
(JSC::HighFidelityLog::processHighFidelityLog):
(JSC::HighFidelityLog::actuallyProcessLogThreadFunction): Deleted.
* runtime/HighFidelityLog.h:
(JSC::HighFidelityLog::recordTypeInformationForLocation):
* runtime/HighFidelityTypeProfiler.cpp:
(JSC::HighFidelityTypeProfiler::logTypesForTypeLocation):
(JSC::HighFidelityTypeProfiler::insertNewLocation):
(JSC::HighFidelityTypeProfiler::getTypesForVariableAtOffsetForInspector):
(JSC::descriptorMatchesTypeLocation):
(JSC::HighFidelityTypeProfiler::findLocation):
(JSC::HighFidelityTypeProfiler::getTypesForVariableInAtOffset): Deleted.
(JSC::HighFidelityTypeProfiler::getGlobalTypesForVariableAtOffset): Deleted.
(JSC::HighFidelityTypeProfiler::getLocalTypesForVariableAtOffset): Deleted.
* runtime/HighFidelityTypeProfiler.h:
(JSC::QueryKey::QueryKey):
(JSC::QueryKey::isHashTableDeletedValue):
(JSC::QueryKey::operator==):
(JSC::QueryKey::hash):
(JSC::QueryKeyHash::hash):
(JSC::QueryKeyHash::equal):
(JSC::HighFidelityTypeProfiler::functionHasExecutedCache):
(JSC::HighFidelityTypeProfiler::typeLocationCache):
* runtime/Structure.cpp:
(JSC::Structure::toStructureShape):
* runtime/Structure.h:
* runtime/TypeLocationCache.cpp: Added.
(JSC::TypeLocationCache::getTypeLocation):
* runtime/TypeLocationCache.h: Added.
(JSC::TypeLocationCache::LocationKey::LocationKey):
(JSC::TypeLocationCache::LocationKey::operator==):
(JSC::TypeLocationCache::LocationKey::hash):
* runtime/TypeSet.cpp:
(JSC::TypeSet::getRuntimeTypeForValue):
(JSC::TypeSet::addTypeForValue):
(JSC::TypeSet::seenTypes):
(JSC::TypeSet::doesTypeConformTo):
(JSC::TypeSet::displayName):
(JSC::TypeSet::allPrimitiveTypeNames):
(JSC::TypeSet::allStructureRepresentations):
(JSC::TypeSet::leastCommonAncestor):
(JSC::StructureShape::StructureShape):
(JSC::StructureShape::addProperty):
(JSC::StructureShape::propertyHash):
(JSC::StructureShape::leastCommonAncestor):
(JSC::StructureShape::stringRepresentation):
(JSC::StructureShape::inspectorRepresentation):
(JSC::StructureShape::leastUpperBound): Deleted.
* runtime/TypeSet.h:
(JSC::StructureShape::setConstructorName):
(JSC::StructureShape::constructorName):
(JSC::StructureShape::setProto):
* runtime/VM.cpp:
(JSC::VM::dumpHighFidelityProfilingTypes):
(JSC::VM::getTypesForVariableAtOffset): Deleted.
(JSC::VM::updateHighFidelityTypeProfileState): Deleted.
* runtime/VM.h:
(JSC::VM::isProfilingTypesWithHighFidelity):
(JSC::VM::highFidelityTypeProfiler):
2014-07-23 Filip Pizlo <fpizlo@apple.com>
Fix debug build.
* bytecode/CallLinkStatus.h:
(JSC::CallLinkStatus::CallLinkStatus):
2014-07-20 Filip Pizlo <fpizlo@apple.com>
[ftlopt] Phantoms in SSA form should be aggressively hoisted
https://bugs.webkit.org/show_bug.cgi?id=135111
Reviewed by Oliver Hunt.
In CPS form, Phantom means three things: (1) that the children should be kept alive so long
as they are relevant to OSR (due to a MovHint), (2) that the children are live-in-bytecode
at the point of the Phantom, and (3) that some checks should be performed. In SSA, the
second meaning is not used but the other two stay.
The fact that a Phantom that is used to keep a node alive could be anywhere in the graph,
even in a totally different basic block, complicates some SSA transformations. It's not
possible to just jettison some successor, since tha successor could have a Phantom that we
care about.
This change rationalizes how Phantoms work so that:
1) Phantoms keep children alive so long as those children are relevant to OSR. This is true
in both CPS and SSA. This was true before and it's true now.
2) Phantoms are used for live-in-bytecode only in CPS. This was true before and it's true
now, except that now we also don't bother preserving the live-in-bytecode information
that Phantoms convey, when we are in SSA.
3) Phantoms may incidentally have checks, but in cases where we only want checks, we now
use Check instead of Phantom. Notably, DCE phase has dead nodes decay to Check, not
Phantom.
The biggest part of this change is that in SSA, we canonicalize Phantoms:
- All Phantoms are replaced with Check nodes that include only those edges that have
checks.
- Nodes that were the children of any Phantoms have a Phantom right after them.
For example, the following code:
5: ArithAdd(@1, @2)
6: ArithSub(@5, @3)
7: Phantom(Int32:@5)
would be turned into the following:
5: ArithAdd(@1, @2)
8: Phantom(@5) // @5 was the child of a Phantom, so we create a new Phantom right after
// @5. This is the only Phantom we will have for @5.
6: ArithSub(@5, @3)
7: Check(Int32:@5) // We replace the Phantom with a Check; in this case since Int32: is
// a checking edge, we leave it.
This is a slight speed-up across the board, presumably because we now do a better job of
reducing the size of the graph during compilation. It could also be a fluke, though. The
main purpose of this is to unlock some other work (like CFG simplification in SSA). It will
become a requirement to run phantom canonicalization prior to some SSA phases. None of the
current phases need it, but future phases probably will.
* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDCEPhase.cpp:
(JSC::DFG::DCEPhase::run):
(JSC::DFG::DCEPhase::findTypeCheckRoot):
(JSC::DFG::DCEPhase::countEdge):
(JSC::DFG::DCEPhase::fixupBlock):
(JSC::DFG::DCEPhase::eliminateIrrelevantPhantomChildren):
* dfg/DFGEdge.cpp:
(JSC::DFG::Edge::dump):
* dfg/DFGEdge.h:
(JSC::DFG::Edge::isProved):
(JSC::DFG::Edge::needsCheck): Deleted.
* dfg/DFGNodeFlags.h:
* dfg/DFGPhantomCanonicalizationPhase.cpp: Added.
(JSC::DFG::PhantomCanonicalizationPhase::PhantomCanonicalizationPhase):
(JSC::DFG::PhantomCanonicalizationPhase::run):
(JSC::DFG::performPhantomCanonicalization):
* dfg/DFGPhantomCanonicalizationPhase.h: Added.
* dfg/DFGPhantomRemovalPhase.cpp:
(JSC::DFG::PhantomRemovalPhase::run):
* dfg/DFGPhantomRemovalPhase.h:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::lowJSValue):
(JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther):
2014-07-22 Filip Pizlo <fpizlo@apple.com>
[ftlopt] Get rid of structure checks as a way of checking if a function is in fact a function
https://bugs.webkit.org/show_bug.cgi?id=135146
Reviewed by Oliver Hunt.
This greatly simplifies our closure call optimizations by taking advantage of the type
bits available in the cell header.
* bytecode/CallLinkInfo.cpp:
(JSC::CallLinkInfo::visitWeak):
* bytecode/CallLinkStatus.cpp:
(JSC::CallLinkStatus::CallLinkStatus):
(JSC::CallLinkStatus::computeFor):
(JSC::CallLinkStatus::dump):
* bytecode/CallLinkStatus.h:
(JSC::CallLinkStatus::CallLinkStatus):
(JSC::CallLinkStatus::executable):
(JSC::CallLinkStatus::structure): Deleted.
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::emitFunctionChecks):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::observeUseKindOnNode):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::speculateCellTypeWithoutTypeFiltering):
(JSC::DFG::SpeculativeJIT::speculateCellType):
(JSC::DFG::SpeculativeJIT::speculateFunction):
(JSC::DFG::SpeculativeJIT::speculateFinalObject):
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
(JSC::DFG::isCell):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileCheckExecutable):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::isFunction):
(JSC::FTL::LowerDFGToLLVM::isNotFunction):
(JSC::FTL::LowerDFGToLLVM::speculateFunction):
* jit/ClosureCallStubRoutine.cpp:
(JSC::ClosureCallStubRoutine::ClosureCallStubRoutine):
(JSC::ClosureCallStubRoutine::markRequiredObjectsInternal):
* jit/ClosureCallStubRoutine.h:
(JSC::ClosureCallStubRoutine::structure): Deleted.
* jit/JIT.h:
(JSC::JIT::compileClosureCall): Deleted.
* jit/JITCall.cpp:
(JSC::JIT::privateCompileClosureCall): Deleted.
* jit/JITCall32_64.cpp:
(JSC::JIT::privateCompileClosureCall): Deleted.
* jit/JITOperations.cpp:
* jit/Repatch.cpp:
(JSC::linkClosureCall):
* jit/Repatch.h:
Source/WebCore:
2014-08-06 Mark Hahnenberg <mhahnenberg@apple.com>
Refactor our current implementation of for-in
https://bugs.webkit.org/show_bug.cgi?id=134142
Reviewed by Filip Pizlo.
No new tests.
This patch splits for-in loops into three distinct parts:
- Iterating over the indexed properties in the base object.
- Iterating over the Structure properties in the base object.
- Iterating over any other enumerable properties for that object and any objects in the prototype chain.
It does this by emitting these explicit loops in bytecode, using a new set of bytecodes to
support the various operations required for each loop.
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::getEnumerableLength):
(WebCore::JSDOMWindow::getStructurePropertyNames):
(WebCore::JSDOMWindow::getGenericPropertyNames):
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
* bridge/runtime_array.cpp:
(JSC::RuntimeArray::getOwnPropertyNames):
Source/WebKit2:
2014-08-06 Mark Hahnenberg <mhahnenberg@apple.com>
Refactor our current implementation of for-in
https://bugs.webkit.org/show_bug.cgi?id=134142
Reviewed by Filip Pizlo.
* WebProcess/Plugins/Netscape/JSNPObject.cpp:
(WebKit::JSNPObject::invalidate): Fixed an invalid ASSERT that was crashing in debug builds.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@172176 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h b/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h
index 58c4eb5..99a09df 100644
--- a/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h
+++ b/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h
@@ -516,7 +516,7 @@
for (iterator it = staticValues->begin(); it != end; ++it) {
StringImpl* name = it->key.get();
StaticValueEntry* entry = it->value.get();
- if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)))
+ if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || shouldIncludeDontEnumProperties(mode)))
propertyNames.add(Identifier(exec, name));
}
}
@@ -527,7 +527,7 @@
for (iterator it = staticFunctions->begin(); it != end; ++it) {
StringImpl* name = it->key.get();
StaticFunctionEntry* entry = it->value.get();
- if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))
+ if (!(entry->attributes & kJSPropertyAttributeDontEnum) || shouldIncludeDontEnumProperties(mode))
propertyNames.add(Identifier(exec, name));
}
}
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 4d15027..8c5d273 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -186,6 +186,7 @@
dfg/DFGOSRExitJumpPlaceholder.cpp
dfg/DFGOSRExitPreparation.cpp
dfg/DFGOperations.cpp
+ dfg/DFGPhantomCanonicalizationPhase.cpp
dfg/DFGPhantomRemovalPhase.cpp
dfg/DFGPhase.cpp
dfg/DFGPlan.cpp
@@ -451,7 +452,6 @@
runtime/JSPromiseFunctions.cpp
runtime/JSPromiseReaction.cpp
runtime/JSPromisePrototype.cpp
- runtime/JSPropertyNameIterator.cpp
runtime/JSProxy.cpp
runtime/JSScope.cpp
runtime/JSSegmentedVariableObject.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index b68e87c..ef16b93 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,725 @@
+2014-08-06 Filip Pizlo <fpizlo@apple.com>
+
+ Merge r171389, r171495, r171508, r171510, r171605, r171606, r171611, r171614, r171763 from ftlopt.
+
+ 2014-07-28 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ Support for-in in the FTL
+ https://bugs.webkit.org/show_bug.cgi?id=134140
+
+ Reviewed by Filip Pizlo.
+
+ * dfg/DFGSSALoweringPhase.cpp:
+ (JSC::DFG::SSALoweringPhase::handleNode):
+ * ftl/FTLAbstractHeapRepository.cpp:
+ * ftl/FTLAbstractHeapRepository.h:
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLIntrinsicRepository.h:
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileNode):
+ (JSC::FTL::LowerDFGToLLVM::compileHasIndexedProperty):
+ (JSC::FTL::LowerDFGToLLVM::compileHasGenericProperty):
+ (JSC::FTL::LowerDFGToLLVM::compileHasStructureProperty):
+ (JSC::FTL::LowerDFGToLLVM::compileGetDirectPname):
+ (JSC::FTL::LowerDFGToLLVM::compileGetEnumerableLength):
+ (JSC::FTL::LowerDFGToLLVM::compileGetStructurePropertyEnumerator):
+ (JSC::FTL::LowerDFGToLLVM::compileGetGenericPropertyEnumerator):
+ (JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorPname):
+ (JSC::FTL::LowerDFGToLLVM::compileToIndexString):
+
+ 2014-07-25 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ Remove JSPropertyNameIterator
+ https://bugs.webkit.org/show_bug.cgi?id=135066
+
+ Reviewed by Geoffrey Garen.
+
+ It has been replaced by JSPropertyNameEnumerator.
+
+ * JavaScriptCore.order:
+ * bytecode/BytecodeBasicBlock.cpp:
+ (JSC::isBranch):
+ * bytecode/BytecodeList.json:
+ * bytecode/BytecodeUseDef.h:
+ (JSC::computeUsesForBytecodeOffset):
+ (JSC::computeDefsForBytecodeOffset):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dumpBytecode):
+ * bytecode/PreciseJumpTargets.cpp:
+ (JSC::getJumpTargetsForBytecodeOffset):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitGetPropertyNames): Deleted.
+ (JSC::BytecodeGenerator::emitNextPropertyName): Deleted.
+ * bytecompiler/BytecodeGenerator.h:
+ * interpreter/Interpreter.cpp:
+ * interpreter/Register.h:
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ (JSC::JIT::privateCompileSlowCases):
+ * jit/JIT.h:
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_get_pnames): Deleted.
+ (JSC::JIT::emit_op_next_pname): Deleted.
+ * jit/JITOpcodes32_64.cpp:
+ (JSC::JIT::emit_op_get_pnames): Deleted.
+ (JSC::JIT::emit_op_next_pname): Deleted.
+ * jit/JITOperations.cpp:
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emit_op_get_by_pname): Deleted.
+ (JSC::JIT::emitSlow_op_get_by_pname): Deleted.
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC::JIT::emit_op_get_by_pname): Deleted.
+ (JSC::JIT::emitSlow_op_get_by_pname): Deleted.
+ * llint/LLIntOffsetsExtractor.cpp:
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL): Deleted.
+ * llint/LLIntSlowPaths.h:
+ * llint/LowLevelInterpreter.asm:
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/CommonSlowPaths.cpp:
+ * runtime/JSPropertyNameIterator.cpp:
+ (JSC::JSPropertyNameIterator::JSPropertyNameIterator): Deleted.
+ (JSC::JSPropertyNameIterator::create): Deleted.
+ (JSC::JSPropertyNameIterator::destroy): Deleted.
+ (JSC::JSPropertyNameIterator::get): Deleted.
+ (JSC::JSPropertyNameIterator::visitChildren): Deleted.
+ * runtime/JSPropertyNameIterator.h:
+ (JSC::JSPropertyNameIterator::createStructure): Deleted.
+ (JSC::JSPropertyNameIterator::size): Deleted.
+ (JSC::JSPropertyNameIterator::setCachedStructure): Deleted.
+ (JSC::JSPropertyNameIterator::cachedStructure): Deleted.
+ (JSC::JSPropertyNameIterator::setCachedPrototypeChain): Deleted.
+ (JSC::JSPropertyNameIterator::cachedPrototypeChain): Deleted.
+ (JSC::JSPropertyNameIterator::finishCreation): Deleted.
+ (JSC::Register::propertyNameIterator): Deleted.
+ (JSC::StructureRareData::enumerationCache): Deleted.
+ (JSC::StructureRareData::setEnumerationCache): Deleted.
+ * runtime/Structure.cpp:
+ (JSC::Structure::addPropertyWithoutTransition):
+ (JSC::Structure::removePropertyWithoutTransition):
+ * runtime/Structure.h:
+ * runtime/StructureInlines.h:
+ (JSC::Structure::setEnumerationCache): Deleted.
+ (JSC::Structure::enumerationCache): Deleted.
+ * runtime/StructureRareData.cpp:
+ (JSC::StructureRareData::visitChildren):
+ * runtime/StructureRareData.h:
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+
+ 2014-07-25 Saam Barati <sbarati@apple.com>
+
+ Fix 32-bit build breakage for type profiling
+ https://bugs.webkit.org/process_bug.cgi
+
+ Reviewed by Mark Hahnenberg.
+
+ 32-bit builds currently break because global variable IDs for high
+ fidelity type profiling are int64_t. Change this to intptr_t so that
+ it's 32 bits on 32-bit platforms and 64 bits on 64-bit platforms.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::CodeBlock):
+ (JSC::CodeBlock::scopeDependentProfile):
+ * bytecode/TypeLocation.h:
+ * runtime/SymbolTable.cpp:
+ (JSC::SymbolTable::uniqueIDForVariable):
+ (JSC::SymbolTable::uniqueIDForRegister):
+ * runtime/SymbolTable.h:
+ * runtime/TypeLocationCache.cpp:
+ (JSC::TypeLocationCache::getTypeLocation):
+ * runtime/TypeLocationCache.h:
+ * runtime/VM.h:
+ (JSC::VM::getNextUniqueVariableID):
+
+ 2014-07-25 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ Reindent PropertyNameArray.h
+ https://bugs.webkit.org/show_bug.cgi?id=135067
+
+ Reviewed by Geoffrey Garen.
+
+ * runtime/PropertyNameArray.h:
+ (JSC::RefCountedIdentifierSet::contains):
+ (JSC::RefCountedIdentifierSet::size):
+ (JSC::RefCountedIdentifierSet::add):
+ (JSC::PropertyNameArrayData::create):
+ (JSC::PropertyNameArrayData::propertyNameVector):
+ (JSC::PropertyNameArrayData::PropertyNameArrayData):
+ (JSC::PropertyNameArray::PropertyNameArray):
+ (JSC::PropertyNameArray::vm):
+ (JSC::PropertyNameArray::add):
+ (JSC::PropertyNameArray::addKnownUnique):
+ (JSC::PropertyNameArray::operator[]):
+ (JSC::PropertyNameArray::setData):
+ (JSC::PropertyNameArray::data):
+ (JSC::PropertyNameArray::releaseData):
+ (JSC::PropertyNameArray::identifierSet):
+ (JSC::PropertyNameArray::canAddKnownUniqueForStructure):
+ (JSC::PropertyNameArray::size):
+ (JSC::PropertyNameArray::begin):
+ (JSC::PropertyNameArray::end):
+ (JSC::PropertyNameArray::numCacheableSlots):
+ (JSC::PropertyNameArray::setNumCacheableSlotsForObject):
+ (JSC::PropertyNameArray::setBaseObject):
+ (JSC::PropertyNameArray::setPreviouslyEnumeratedLength):
+
+ 2014-07-23 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ Refactor our current implementation of for-in
+ https://bugs.webkit.org/show_bug.cgi?id=134142
+
+ Reviewed by Filip Pizlo.
+
+ This patch splits for-in loops into three distinct parts:
+
+ - Iterating over the indexed properties in the base object.
+ - Iterating over the Structure properties in the base object.
+ - Iterating over any other enumerable properties for that object and any objects in the prototype chain.
+
+ It does this by emitting these explicit loops in bytecode, using a new set of bytecodes to
+ support the various operations required for each loop.
+
+ * API/JSCallbackObjectFunctions.h:
+ (JSC::JSCallbackObject<Parent>::getOwnNonIndexPropertyNames):
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * bytecode/BytecodeList.json:
+ * bytecode/BytecodeUseDef.h:
+ (JSC::computeUsesForBytecodeOffset):
+ (JSC::computeDefsForBytecodeOffset):
+ * bytecode/CallLinkStatus.h:
+ (JSC::CallLinkStatus::CallLinkStatus):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dumpBytecode):
+ (JSC::CodeBlock::CodeBlock):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitGetByVal):
+ (JSC::BytecodeGenerator::emitComplexPopScopes):
+ (JSC::BytecodeGenerator::emitGetEnumerableLength):
+ (JSC::BytecodeGenerator::emitHasGenericProperty):
+ (JSC::BytecodeGenerator::emitHasIndexedProperty):
+ (JSC::BytecodeGenerator::emitHasStructureProperty):
+ (JSC::BytecodeGenerator::emitGetStructurePropertyEnumerator):
+ (JSC::BytecodeGenerator::emitGetGenericPropertyEnumerator):
+ (JSC::BytecodeGenerator::emitNextEnumeratorPropertyName):
+ (JSC::BytecodeGenerator::emitToIndexString):
+ (JSC::BytecodeGenerator::pushIndexedForInScope):
+ (JSC::BytecodeGenerator::popIndexedForInScope):
+ (JSC::BytecodeGenerator::pushStructureForInScope):
+ (JSC::BytecodeGenerator::popStructureForInScope):
+ (JSC::BytecodeGenerator::invalidateForInContextForLocal):
+ * bytecompiler/BytecodeGenerator.h:
+ (JSC::ForInContext::ForInContext):
+ (JSC::ForInContext::~ForInContext):
+ (JSC::ForInContext::isValid):
+ (JSC::ForInContext::invalidate):
+ (JSC::ForInContext::local):
+ (JSC::StructureForInContext::StructureForInContext):
+ (JSC::StructureForInContext::type):
+ (JSC::StructureForInContext::index):
+ (JSC::StructureForInContext::property):
+ (JSC::StructureForInContext::enumerator):
+ (JSC::IndexedForInContext::IndexedForInContext):
+ (JSC::IndexedForInContext::type):
+ (JSC::IndexedForInContext::index):
+ (JSC::BytecodeGenerator::pushOptimisedForIn): Deleted.
+ (JSC::BytecodeGenerator::popOptimisedForIn): Deleted.
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::ReadModifyResolveNode::emitBytecode):
+ (JSC::AssignResolveNode::emitBytecode):
+ (JSC::ForInNode::tryGetBoundLocal):
+ (JSC::ForInNode::emitLoopHeader):
+ (JSC::ForInNode::emitMultiLoopBytecode):
+ (JSC::ForInNode::emitBytecode):
+ * debugger/DebuggerScope.h:
+ * dfg/DFGAbstractHeap.h:
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGHeapLocation.cpp:
+ (WTF::printInternal):
+ * dfg/DFGHeapLocation.h:
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasHeapPrediction):
+ (JSC::DFG::Node::hasArrayMode):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ (JSC::JIT::privateCompileSlowCases):
+ * jit/JIT.h:
+ (JSC::JIT::compileHasIndexedProperty):
+ (JSC::JIT::emitInt32Load):
+ * jit/JITInlines.h:
+ (JSC::JIT::emitDoubleGetByVal):
+ (JSC::JIT::emitLoadForArrayMode):
+ (JSC::JIT::emitContiguousGetByVal):
+ (JSC::JIT::emitArrayStorageGetByVal):
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_get_enumerable_length):
+ (JSC::JIT::emit_op_has_structure_property):
+ (JSC::JIT::emitSlow_op_has_structure_property):
+ (JSC::JIT::emit_op_has_generic_property):
+ (JSC::JIT::privateCompileHasIndexedProperty):
+ (JSC::JIT::emit_op_has_indexed_property):
+ (JSC::JIT::emitSlow_op_has_indexed_property):
+ (JSC::JIT::emit_op_get_direct_pname):
+ (JSC::JIT::emitSlow_op_get_direct_pname):
+ (JSC::JIT::emit_op_get_structure_property_enumerator):
+ (JSC::JIT::emit_op_get_generic_property_enumerator):
+ (JSC::JIT::emit_op_next_enumerator_pname):
+ (JSC::JIT::emit_op_to_index_string):
+ * jit/JITOpcodes32_64.cpp:
+ (JSC::JIT::emit_op_get_enumerable_length):
+ (JSC::JIT::emit_op_has_structure_property):
+ (JSC::JIT::emitSlow_op_has_structure_property):
+ (JSC::JIT::emit_op_has_generic_property):
+ (JSC::JIT::privateCompileHasIndexedProperty):
+ (JSC::JIT::emit_op_has_indexed_property):
+ (JSC::JIT::emitSlow_op_has_indexed_property):
+ (JSC::JIT::emit_op_get_direct_pname):
+ (JSC::JIT::emitSlow_op_get_direct_pname):
+ (JSC::JIT::emit_op_get_structure_property_enumerator):
+ (JSC::JIT::emit_op_get_generic_property_enumerator):
+ (JSC::JIT::emit_op_next_enumerator_pname):
+ (JSC::JIT::emit_op_to_index_string):
+ * jit/JITOperations.cpp:
+ * jit/JITOperations.h:
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emitDoubleLoad):
+ (JSC::JIT::emitContiguousLoad):
+ (JSC::JIT::emitArrayStorageLoad):
+ (JSC::JIT::emitDoubleGetByVal): Deleted.
+ (JSC::JIT::emitContiguousGetByVal): Deleted.
+ (JSC::JIT::emitArrayStorageGetByVal): Deleted.
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC::JIT::emitContiguousLoad):
+ (JSC::JIT::emitDoubleLoad):
+ (JSC::JIT::emitArrayStorageLoad):
+ (JSC::JIT::emitContiguousGetByVal): Deleted.
+ (JSC::JIT::emitDoubleGetByVal): Deleted.
+ (JSC::JIT::emitArrayStorageGetByVal): Deleted.
+ * llint/LowLevelInterpreter.asm:
+ * parser/Nodes.h:
+ * runtime/Arguments.cpp:
+ (JSC::Arguments::getOwnPropertyNames):
+ * runtime/ClassInfo.h:
+ * runtime/CommonSlowPaths.cpp:
+ (JSC::SLOW_PATH_DECL):
+ * runtime/CommonSlowPaths.h:
+ * runtime/EnumerationMode.h: Added.
+ (JSC::shouldIncludeDontEnumProperties):
+ (JSC::shouldExcludeDontEnumProperties):
+ (JSC::shouldIncludeJSObjectPropertyNames):
+ (JSC::modeThatSkipsJSObject):
+ * runtime/JSActivation.cpp:
+ (JSC::JSActivation::getOwnNonIndexPropertyNames):
+ * runtime/JSArray.cpp:
+ (JSC::JSArray::getOwnNonIndexPropertyNames):
+ * runtime/JSArrayBuffer.cpp:
+ (JSC::JSArrayBuffer::getOwnNonIndexPropertyNames):
+ * runtime/JSArrayBufferView.cpp:
+ (JSC::JSArrayBufferView::getOwnNonIndexPropertyNames):
+ * runtime/JSCell.cpp:
+ (JSC::JSCell::getEnumerableLength):
+ (JSC::JSCell::getStructurePropertyNames):
+ (JSC::JSCell::getGenericPropertyNames):
+ * runtime/JSCell.h:
+ * runtime/JSFunction.cpp:
+ (JSC::JSFunction::getOwnNonIndexPropertyNames):
+ * runtime/JSGenericTypedArrayViewInlines.h:
+ (JSC::JSGenericTypedArrayView<Adaptor>::getOwnNonIndexPropertyNames):
+ * runtime/JSObject.cpp:
+ (JSC::getClassPropertyNames):
+ (JSC::JSObject::hasOwnProperty):
+ (JSC::JSObject::getOwnPropertyNames):
+ (JSC::JSObject::getOwnNonIndexPropertyNames):
+ (JSC::JSObject::getEnumerableLength):
+ (JSC::JSObject::getStructurePropertyNames):
+ (JSC::JSObject::getGenericPropertyNames):
+ * runtime/JSObject.h:
+ * runtime/JSPropertyNameEnumerator.cpp: Added.
+ (JSC::JSPropertyNameEnumerator::create):
+ (JSC::JSPropertyNameEnumerator::JSPropertyNameEnumerator):
+ (JSC::JSPropertyNameEnumerator::finishCreation):
+ (JSC::JSPropertyNameEnumerator::destroy):
+ (JSC::JSPropertyNameEnumerator::visitChildren):
+ * runtime/JSPropertyNameEnumerator.h: Added.
+ (JSC::JSPropertyNameEnumerator::createStructure):
+ (JSC::JSPropertyNameEnumerator::propertyNameAtIndex):
+ (JSC::JSPropertyNameEnumerator::identifierSet):
+ (JSC::JSPropertyNameEnumerator::cachedPrototypeChain):
+ (JSC::JSPropertyNameEnumerator::setCachedPrototypeChain):
+ (JSC::JSPropertyNameEnumerator::cachedStructure):
+ (JSC::JSPropertyNameEnumerator::cachedStructureID):
+ (JSC::JSPropertyNameEnumerator::cachedInlineCapacity):
+ (JSC::JSPropertyNameEnumerator::cachedStructureIDOffset):
+ (JSC::JSPropertyNameEnumerator::cachedInlineCapacityOffset):
+ (JSC::JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset):
+ (JSC::JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset):
+ (JSC::structurePropertyNameEnumerator):
+ (JSC::genericPropertyNameEnumerator):
+ * runtime/JSProxy.cpp:
+ (JSC::JSProxy::getEnumerableLength):
+ (JSC::JSProxy::getStructurePropertyNames):
+ (JSC::JSProxy::getGenericPropertyNames):
+ * runtime/JSProxy.h:
+ * runtime/JSSymbolTableObject.cpp:
+ (JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames):
+ * runtime/PropertyNameArray.cpp:
+ (JSC::PropertyNameArray::add):
+ (JSC::PropertyNameArray::setPreviouslyEnumeratedProperties):
+ * runtime/PropertyNameArray.h:
+ (JSC::RefCountedIdentifierSet::contains):
+ (JSC::RefCountedIdentifierSet::size):
+ (JSC::RefCountedIdentifierSet::add):
+ (JSC::PropertyNameArray::PropertyNameArray):
+ (JSC::PropertyNameArray::add):
+ (JSC::PropertyNameArray::addKnownUnique):
+ (JSC::PropertyNameArray::identifierSet):
+ (JSC::PropertyNameArray::canAddKnownUniqueForStructure):
+ (JSC::PropertyNameArray::setPreviouslyEnumeratedLength):
+ * runtime/RegExpObject.cpp:
+ (JSC::RegExpObject::getOwnNonIndexPropertyNames):
+ (JSC::RegExpObject::getPropertyNames):
+ (JSC::RegExpObject::getGenericPropertyNames):
+ * runtime/RegExpObject.h:
+ * runtime/StringObject.cpp:
+ (JSC::StringObject::getOwnPropertyNames):
+ * runtime/Structure.cpp:
+ (JSC::Structure::getPropertyNamesFromStructure):
+ (JSC::Structure::setCachedStructurePropertyNameEnumerator):
+ (JSC::Structure::cachedStructurePropertyNameEnumerator):
+ (JSC::Structure::setCachedGenericPropertyNameEnumerator):
+ (JSC::Structure::cachedGenericPropertyNameEnumerator):
+ (JSC::Structure::canCacheStructurePropertyNameEnumerator):
+ (JSC::Structure::canCacheGenericPropertyNameEnumerator):
+ (JSC::Structure::canAccessPropertiesQuickly):
+ * runtime/Structure.h:
+ * runtime/StructureRareData.cpp:
+ (JSC::StructureRareData::visitChildren):
+ (JSC::StructureRareData::cachedStructurePropertyNameEnumerator):
+ (JSC::StructureRareData::setCachedStructurePropertyNameEnumerator):
+ (JSC::StructureRareData::cachedGenericPropertyNameEnumerator):
+ (JSC::StructureRareData::setCachedGenericPropertyNameEnumerator):
+ * runtime/StructureRareData.h:
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ * runtime/VM.h:
+
+ 2014-07-23 Saam Barati <sbarati@apple.com>
+
+ Make improvements to Type Profiling
+ https://bugs.webkit.org/show_bug.cgi?id=134860
+
+ Reviewed by Filip Pizlo.
+
+ I improved the API between the inspector and JSC. We no longer send one huge
+ string to the inspector. We now send structured data that represents the type
+ information that JSC has collected. I've also created a beginning implementation
+ of a type lattice that allows us to resolve a display name for a type that
+ consists of a single word.
+
+ I created a data structure that knows which functions have executed. This
+ solves the bug where types inside an un-executed function will resolve
+ to the type of the enclosing expression of that function. This data
+ structure may also be useful later if the inspector chooses to create a UI
+ around showing which functions have executed.
+
+ Better type information is gathered for objects. StructureShape now
+ represents an object's prototype chain. StructureShape also collects
+ the constructor name for an object.
+
+ Expression ranges are now zero indexed.
+
+ Removed some extraneous methods.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::CodeBlock):
+ (JSC::CodeBlock::scopeDependentProfile):
+ * bytecode/CodeBlock.h:
+ * bytecode/TypeLocation.h:
+ (JSC::TypeLocation::TypeLocation):
+ * bytecode/UnlinkedCodeBlock.cpp:
+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+ * bytecode/UnlinkedCodeBlock.h:
+ (JSC::UnlinkedFunctionExecutable::highFidelityTypeProfilingStartOffset):
+ (JSC::UnlinkedFunctionExecutable::highFidelityTypeProfilingEndOffset):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::BytecodeGenerator):
+ (JSC::BytecodeGenerator::emitHighFidelityTypeProfilingExpressionInfo):
+ * bytecompiler/BytecodeGenerator.h:
+ (JSC::BytecodeGenerator::emitHighFidelityTypeProfilingExpressionInfo): Deleted.
+ * heap/Heap.cpp:
+ (JSC::Heap::collect):
+ * inspector/agents/InspectorRuntimeAgent.cpp:
+ (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets):
+ (Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableAtOffset): Deleted.
+ * inspector/agents/InspectorRuntimeAgent.h:
+ * inspector/protocol/Runtime.json:
+ * runtime/Executable.cpp:
+ (JSC::ScriptExecutable::ScriptExecutable):
+ (JSC::ProgramExecutable::ProgramExecutable):
+ (JSC::FunctionExecutable::FunctionExecutable):
+ (JSC::ProgramExecutable::initializeGlobalProperties):
+ * runtime/Executable.h:
+ (JSC::ScriptExecutable::highFidelityTypeProfilingStartOffset):
+ (JSC::ScriptExecutable::highFidelityTypeProfilingEndOffset):
+ * runtime/FunctionHasExecutedCache.cpp: Added.
+ (JSC::FunctionHasExecutedCache::hasExecutedAtOffset):
+ (JSC::FunctionHasExecutedCache::insertUnexecutedRange):
+ (JSC::FunctionHasExecutedCache::removeUnexecutedRange):
+ * runtime/FunctionHasExecutedCache.h: Added.
+ (JSC::FunctionHasExecutedCache::FunctionRange::FunctionRange):
+ (JSC::FunctionHasExecutedCache::FunctionRange::operator==):
+ (JSC::FunctionHasExecutedCache::FunctionRange::hash):
+ * runtime/HighFidelityLog.cpp:
+ (JSC::HighFidelityLog::processHighFidelityLog):
+ (JSC::HighFidelityLog::actuallyProcessLogThreadFunction): Deleted.
+ * runtime/HighFidelityLog.h:
+ (JSC::HighFidelityLog::recordTypeInformationForLocation):
+ * runtime/HighFidelityTypeProfiler.cpp:
+ (JSC::HighFidelityTypeProfiler::logTypesForTypeLocation):
+ (JSC::HighFidelityTypeProfiler::insertNewLocation):
+ (JSC::HighFidelityTypeProfiler::getTypesForVariableAtOffsetForInspector):
+ (JSC::descriptorMatchesTypeLocation):
+ (JSC::HighFidelityTypeProfiler::findLocation):
+ (JSC::HighFidelityTypeProfiler::getTypesForVariableInAtOffset): Deleted.
+ (JSC::HighFidelityTypeProfiler::getGlobalTypesForVariableAtOffset): Deleted.
+ (JSC::HighFidelityTypeProfiler::getLocalTypesForVariableAtOffset): Deleted.
+ * runtime/HighFidelityTypeProfiler.h:
+ (JSC::QueryKey::QueryKey):
+ (JSC::QueryKey::isHashTableDeletedValue):
+ (JSC::QueryKey::operator==):
+ (JSC::QueryKey::hash):
+ (JSC::QueryKeyHash::hash):
+ (JSC::QueryKeyHash::equal):
+ (JSC::HighFidelityTypeProfiler::functionHasExecutedCache):
+ (JSC::HighFidelityTypeProfiler::typeLocationCache):
+ * runtime/Structure.cpp:
+ (JSC::Structure::toStructureShape):
+ * runtime/Structure.h:
+ * runtime/TypeLocationCache.cpp: Added.
+ (JSC::TypeLocationCache::getTypeLocation):
+ * runtime/TypeLocationCache.h: Added.
+ (JSC::TypeLocationCache::LocationKey::LocationKey):
+ (JSC::TypeLocationCache::LocationKey::operator==):
+ (JSC::TypeLocationCache::LocationKey::hash):
+ * runtime/TypeSet.cpp:
+ (JSC::TypeSet::getRuntimeTypeForValue):
+ (JSC::TypeSet::addTypeForValue):
+ (JSC::TypeSet::seenTypes):
+ (JSC::TypeSet::doesTypeConformTo):
+ (JSC::TypeSet::displayName):
+ (JSC::TypeSet::allPrimitiveTypeNames):
+ (JSC::TypeSet::allStructureRepresentations):
+ (JSC::TypeSet::leastCommonAncestor):
+ (JSC::StructureShape::StructureShape):
+ (JSC::StructureShape::addProperty):
+ (JSC::StructureShape::propertyHash):
+ (JSC::StructureShape::leastCommonAncestor):
+ (JSC::StructureShape::stringRepresentation):
+ (JSC::StructureShape::inspectorRepresentation):
+ (JSC::StructureShape::leastUpperBound): Deleted.
+ * runtime/TypeSet.h:
+ (JSC::StructureShape::setConstructorName):
+ (JSC::StructureShape::constructorName):
+ (JSC::StructureShape::setProto):
+ * runtime/VM.cpp:
+ (JSC::VM::dumpHighFidelityProfilingTypes):
+ (JSC::VM::getTypesForVariableAtOffset): Deleted.
+ (JSC::VM::updateHighFidelityTypeProfileState): Deleted.
+ * runtime/VM.h:
+ (JSC::VM::isProfilingTypesWithHighFidelity):
+ (JSC::VM::highFidelityTypeProfiler):
+
+ 2014-07-23 Filip Pizlo <fpizlo@apple.com>
+
+ Fix debug build.
+
+ * bytecode/CallLinkStatus.h:
+ (JSC::CallLinkStatus::CallLinkStatus):
+
+ 2014-07-20 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] Phantoms in SSA form should be aggressively hoisted
+ https://bugs.webkit.org/show_bug.cgi?id=135111
+
+ Reviewed by Oliver Hunt.
+
+ In CPS form, Phantom means three things: (1) that the children should be kept alive so long
+ as they are relevant to OSR (due to a MovHint), (2) that the children are live-in-bytecode
+ at the point of the Phantom, and (3) that some checks should be performed. In SSA, the
+ second meaning is not used but the other two stay.
+
+ The fact that a Phantom that is used to keep a node alive could be anywhere in the graph,
+ even in a totally different basic block, complicates some SSA transformations. It's not
+ possible to just jettison some successor, since tha successor could have a Phantom that we
+ care about.
+
+ This change rationalizes how Phantoms work so that:
+
+ 1) Phantoms keep children alive so long as those children are relevant to OSR. This is true
+ in both CPS and SSA. This was true before and it's true now.
+
+ 2) Phantoms are used for live-in-bytecode only in CPS. This was true before and it's true
+ now, except that now we also don't bother preserving the live-in-bytecode information
+ that Phantoms convey, when we are in SSA.
+
+ 3) Phantoms may incidentally have checks, but in cases where we only want checks, we now
+ use Check instead of Phantom. Notably, DCE phase has dead nodes decay to Check, not
+ Phantom.
+
+ The biggest part of this change is that in SSA, we canonicalize Phantoms:
+
+ - All Phantoms are replaced with Check nodes that include only those edges that have
+ checks.
+
+ - Nodes that were the children of any Phantoms have a Phantom right after them.
+
+ For example, the following code:
+
+ 5: ArithAdd(@1, @2)
+ 6: ArithSub(@5, @3)
+ 7: Phantom(Int32:@5)
+
+ would be turned into the following:
+
+ 5: ArithAdd(@1, @2)
+ 8: Phantom(@5) // @5 was the child of a Phantom, so we create a new Phantom right after
+ // @5. This is the only Phantom we will have for @5.
+ 6: ArithSub(@5, @3)
+ 7: Check(Int32:@5) // We replace the Phantom with a Check; in this case since Int32: is
+ // a checking edge, we leave it.
+
+ This is a slight speed-up across the board, presumably because we now do a better job of
+ reducing the size of the graph during compilation. It could also be a fluke, though. The
+ main purpose of this is to unlock some other work (like CFG simplification in SSA). It will
+ become a requirement to run phantom canonicalization prior to some SSA phases. None of the
+ current phases need it, but future phases probably will.
+
+ * CMakeLists.txt:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ * dfg/DFGDCEPhase.cpp:
+ (JSC::DFG::DCEPhase::run):
+ (JSC::DFG::DCEPhase::findTypeCheckRoot):
+ (JSC::DFG::DCEPhase::countEdge):
+ (JSC::DFG::DCEPhase::fixupBlock):
+ (JSC::DFG::DCEPhase::eliminateIrrelevantPhantomChildren):
+ * dfg/DFGEdge.cpp:
+ (JSC::DFG::Edge::dump):
+ * dfg/DFGEdge.h:
+ (JSC::DFG::Edge::isProved):
+ (JSC::DFG::Edge::needsCheck): Deleted.
+ * dfg/DFGNodeFlags.h:
+ * dfg/DFGPhantomCanonicalizationPhase.cpp: Added.
+ (JSC::DFG::PhantomCanonicalizationPhase::PhantomCanonicalizationPhase):
+ (JSC::DFG::PhantomCanonicalizationPhase::run):
+ (JSC::DFG::performPhantomCanonicalization):
+ * dfg/DFGPhantomCanonicalizationPhase.h: Added.
+ * dfg/DFGPhantomRemovalPhase.cpp:
+ (JSC::DFG::PhantomRemovalPhase::run):
+ * dfg/DFGPhantomRemovalPhase.h:
+ * dfg/DFGPlan.cpp:
+ (JSC::DFG::Plan::compileInThreadImpl):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::lowJSValue):
+ (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther):
+
+ 2014-07-22 Filip Pizlo <fpizlo@apple.com>
+
+ [ftlopt] Get rid of structure checks as a way of checking if a function is in fact a function
+ https://bugs.webkit.org/show_bug.cgi?id=135146
+
+ Reviewed by Oliver Hunt.
+
+ This greatly simplifies our closure call optimizations by taking advantage of the type
+ bits available in the cell header.
+
+ * bytecode/CallLinkInfo.cpp:
+ (JSC::CallLinkInfo::visitWeak):
+ * bytecode/CallLinkStatus.cpp:
+ (JSC::CallLinkStatus::CallLinkStatus):
+ (JSC::CallLinkStatus::computeFor):
+ (JSC::CallLinkStatus::dump):
+ * bytecode/CallLinkStatus.h:
+ (JSC::CallLinkStatus::CallLinkStatus):
+ (JSC::CallLinkStatus::executable):
+ (JSC::CallLinkStatus::structure): Deleted.
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::emitFunctionChecks):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ (JSC::DFG::FixupPhase::observeUseKindOnNode):
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::SafeToExecuteEdge::operator()):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::checkArray):
+ (JSC::DFG::SpeculativeJIT::speculateCellTypeWithoutTypeFiltering):
+ (JSC::DFG::SpeculativeJIT::speculateCellType):
+ (JSC::DFG::SpeculativeJIT::speculateFunction):
+ (JSC::DFG::SpeculativeJIT::speculateFinalObject):
+ (JSC::DFG::SpeculativeJIT::speculate):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGUseKind.cpp:
+ (WTF::printInternal):
+ * dfg/DFGUseKind.h:
+ (JSC::DFG::typeFilterFor):
+ (JSC::DFG::isCell):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileCheckExecutable):
+ (JSC::FTL::LowerDFGToLLVM::speculate):
+ (JSC::FTL::LowerDFGToLLVM::isFunction):
+ (JSC::FTL::LowerDFGToLLVM::isNotFunction):
+ (JSC::FTL::LowerDFGToLLVM::speculateFunction):
+ * jit/ClosureCallStubRoutine.cpp:
+ (JSC::ClosureCallStubRoutine::ClosureCallStubRoutine):
+ (JSC::ClosureCallStubRoutine::markRequiredObjectsInternal):
+ * jit/ClosureCallStubRoutine.h:
+ (JSC::ClosureCallStubRoutine::structure): Deleted.
+ * jit/JIT.h:
+ (JSC::JIT::compileClosureCall): Deleted.
+ * jit/JITCall.cpp:
+ (JSC::JIT::privateCompileClosureCall): Deleted.
+ * jit/JITCall32_64.cpp:
+ (JSC::JIT::privateCompileClosureCall): Deleted.
+ * jit/JITOperations.cpp:
+ * jit/Repatch.cpp:
+ (JSC::linkClosureCall):
+ * jit/Repatch.h:
+
2014-08-06 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com>
[ARM] Incorrect handling of Unicode characters
diff --git a/Source/JavaScriptCore/JavaScriptCore.order b/Source/JavaScriptCore/JavaScriptCore.order
index 633dd45..6117391 100644
--- a/Source/JavaScriptCore/JavaScriptCore.order
+++ b/Source/JavaScriptCore/JavaScriptCore.order
@@ -1354,7 +1354,6 @@
__ZN3JSC17BytecodeGenerator7emitIncEPNS_10RegisterIDE
__ZN3JSC14jsIsObjectTypeEPNS_9ExecStateENS_7JSValueE
__ZN3JSC6JSCell11getCallDataEPS0_RNS_8CallDataE
-__ZN3JSC22JSPropertyNameIterator6createEPNS_9ExecStateEPNS_8JSObjectE
__ZN3JSC8JSObject16getPropertyNamesEPS0_PNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
__ZN3JSC8JSObject19getOwnPropertyNamesEPS0_PNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
__ZN3JSC8JSObject27getOwnNonIndexPropertyNamesEPS0_PNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE
@@ -1638,13 +1637,10 @@
__ZN3JSC3JIT17emit_op_loop_hintEPNS_11InstructionE
__ZN3JSC8Watchdog9isEnabledEv
__ZN3JSC3JIT16emit_op_jeq_nullEPNS_11InstructionE
-__ZN3JSC3JIT18emit_op_get_pnamesEPNS_11InstructionE
__ZN3JSC3JIT11emit_op_jmpEPNS_11InstructionE
-__ZN3JSC3JIT20emit_op_get_by_pnameEPNS_11InstructionE
__ZN3JSC3JIT22compileGetDirectOffsetENS_12X86Registers10RegisterIDES2_S2_S2_NS0_15FinalObjectModeE
__ZN3JSC3JIT17emit_op_new_arrayEPNS_11InstructionE
__ZN3JSC3JIT17emit_op_nstricteqEPNS_11InstructionE
-__ZN3JSC3JIT18emit_op_next_pnameEPNS_11InstructionE
__ZN3JSC3JIT11emit_op_incEPNS_11InstructionE
__ZN3JSC3JIT13emit_op_jlessEPNS_11InstructionE
__ZN3JSC3JIT24emitSlow_op_convert_thisEPNS_11InstructionERPNS_13SlowCaseEntryE
@@ -1663,7 +1659,6 @@
__ZN3JSC12X86Assembler23X86InstructionFormatter11twoByteOp64ENS0_15TwoByteOpcodeIDEiNS_12X86Registers10RegisterIDE
__ZN3JSC23MacroAssemblerX86Common12branchDoubleENS0_15DoubleConditionENS_12X86Registers13XMMRegisterIDES3_
__ZN3JSC12X86Assembler23X86InstructionFormatter9twoByteOpENS0_15TwoByteOpcodeIDEiNS_12X86Registers10RegisterIDE
-__ZN3JSC3JIT24emitSlow_op_get_by_pnameEPNS_11InstructionERPNS_13SlowCaseEntryE
__ZN3JSC3JIT21emitSlow_op_nstricteqEPNS_11InstructionERPNS_13SlowCaseEntryE
__ZN3JSC3JIT15emitSlow_op_incEPNS_11InstructionERPNS_13SlowCaseEntryE
__ZN3JSC3JIT17emitSlow_op_jlessEPNS_11InstructionERPNS_13SlowCaseEntryE
@@ -1675,7 +1670,6 @@
_cti_op_stricteq
_cti_op_jtrue
_cti_op_is_object
-_cti_op_get_pnames
__ZN3JSC8JSString12toThisObjectEPNS_6JSCellEPNS_9ExecStateE
__ZN3JSC12StringObjectC1ERNS_2VMEPNS_9StructureE
__ZNK3JSC6JSCell11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
@@ -2622,7 +2616,6 @@
__ZN3WTF7HashMapImPN3JSC21GCAwareJITStubRoutineENS_7IntHashImEENS_10HashTraitsImEENS6_IS3_EEE4findERKm
__ZN3JSC13JSFinalObject13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE
__ZN3JSC17StructureRareData13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE
-__ZN3JSC22JSPropertyNameIterator13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE
__ZN3JSC14StructureChain13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE
__ZN3JSC14MarkStackArray6expandEv
__ZN3JSC17ProgramExecutable13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE
@@ -2666,7 +2659,6 @@
__ZN3JSC17ProgramExecutable7destroyEPNS_6JSCellE
__ZN3JSC17SharedSymbolTable7destroyEPNS_6JSCellE
__ZN3JSC10JSFunction7destroyEPNS_6JSCellE
-__ZN3JSC22JSPropertyNameIterator7destroyEPNS_6JSCellE
__ZN3JSC19ResolveGlobalStatus10computeForEPNS_9CodeBlockEiPNS_16ResolveOperationERNS_10IdentifierE
__ZN3JSC13GetByIdStatus10computeForERNS_2VMEPNS_9StructureERNS_10IdentifierE
__ZN3JSC3DFG14SpeculativeJIT23emitObjectOrOtherBranchENS0_4EdgeEjj
@@ -4940,7 +4932,6 @@
_llint_slow_path_del_by_id
_llint_slow_path_get_by_val
_llint_slow_path_get_argument_by_val
-_llint_slow_path_get_by_pname
_llint_slow_path_put_by_val
_llint_slow_path_del_by_val
_llint_slow_path_put_by_index
@@ -4968,8 +4959,6 @@
_llint_slow_path_tear_off_arguments
_llint_slow_path_strcat
_llint_slow_path_to_primitive
-_llint_slow_path_get_pnames
-_llint_slow_path_next_pname
_llint_slow_path_push_with_scope
_llint_slow_path_pop_scope
_llint_slow_path_push_name_scope
@@ -5036,7 +5025,6 @@
_llint_op_put_by_id_transition_normal_out_of_line
_llint_op_get_by_val
_llint_op_get_argument_by_val
-_llint_op_get_by_pname
_llint_op_put_by_val
_llint_op_jmp
_llint_op_jeq_null
@@ -5051,7 +5039,6 @@
_llint_op_call_put_result
_llint_op_ret_object_or_this
_llint_op_to_primitive
-_llint_op_next_pname
_llint_op_catch
_llint_op_get_scoped_var
_llint_op_put_scoped_var
@@ -5109,7 +5096,6 @@
_llint_op_call_eval
_llint_generic_return_point
_llint_op_strcat
-_llint_op_get_pnames
_llint_op_push_with_scope
_llint_op_pop_scope
_llint_op_push_name_scope
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
index 79a3322..7cfb60b 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
@@ -433,6 +433,7 @@
<ClCompile Include="..\dfg\DFGOSRExitCompilerCommon.cpp" />
<ClCompile Include="..\dfg\DFGOSRExitJumpPlaceholder.cpp" />
<ClCompile Include="..\dfg\DFGOSRExitPreparation.cpp" />
+ <ClCompile Include="..\dfg\DFGPhantomCanonicalizationPhase.cpp" />
<ClCompile Include="..\dfg\DFGPhantomRemovalPhase.cpp" />
<ClCompile Include="..\dfg\DFGPhase.cpp" />
<ClCompile Include="..\dfg\DFGPlan.cpp" />
@@ -726,7 +727,6 @@
<ClCompile Include="..\runtime\JSPromiseFunctions.cpp" />
<ClCompile Include="..\runtime\JSPromiseReaction.cpp" />
<ClCompile Include="..\runtime\JSPromisePrototype.cpp" />
- <ClCompile Include="..\runtime\JSPropertyNameIterator.cpp" />
<ClCompile Include="..\runtime\JSProxy.cpp" />
<ClCompile Include="..\runtime\JSScope.cpp" />
<ClCompile Include="..\runtime\JSSegmentedVariableObject.cpp" />
@@ -1063,6 +1063,7 @@
<ClInclude Include="..\dfg\DFGOSRExitCompilerCommon.h" />
<ClInclude Include="..\dfg\DFGOSRExitJumpPlaceholder.h" />
<ClInclude Include="..\dfg\DFGOSRExitPreparation.h" />
+ <ClInclude Include="..\dfg\DFGPhantomCanonicalizationPhase.h" />
<ClInclude Include="..\dfg\DFGPhantomRemovalPhase.h" />
<ClInclude Include="..\dfg\DFGPhase.h" />
<ClInclude Include="..\dfg\DFGPlan.h" />
@@ -1479,7 +1480,6 @@
<ClInclude Include="..\runtime\JSPromiseFunctions.h" />
<ClInclude Include="..\runtime\JSPromiseReaction.h" />
<ClInclude Include="..\runtime\JSPromisePrototype.h" />
- <ClInclude Include="..\runtime\JSPropertyNameIterator.h" />
<ClInclude Include="..\runtime\JSProxy.h" />
<ClInclude Include="..\runtime\JSScope.h" />
<ClInclude Include="..\runtime\JSSegmentedVariableObject.h" />
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
index 5d2682b..e39bb6f 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
@@ -657,9 +657,6 @@
<ClCompile Include="..\runtime\JSONObject.cpp">
<Filter>runtime</Filter>
</ClCompile>
- <ClCompile Include="..\runtime\JSPropertyNameIterator.cpp">
- <Filter>runtime</Filter>
- </ClCompile>
<ClCompile Include="..\runtime\JSProxy.cpp">
<Filter>runtime</Filter>
</ClCompile>
@@ -2546,9 +2543,6 @@
<ClInclude Include="..\runtime\JSONObject.h">
<Filter>runtime</Filter>
</ClInclude>
- <ClInclude Include="..\runtime\JSPropertyNameIterator.h">
- <Filter>runtime</Filter>
- </ClInclude>
<ClInclude Include="..\runtime\JSProxy.h">
<Filter>runtime</Filter>
</ClInclude>
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 01c8ee6..90b5b79 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -373,6 +373,8 @@
0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7700911402FF280078EB39 /* SamplingCounter.cpp */; };
0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC0977E1469EBC400CF2442 /* DFGCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F7B3661197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7B365F197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.cpp */; };
+ 0F7B3662197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7B3660197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8023E91613832300A0BA45 /* ByValInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */; };
0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -825,6 +827,8 @@
1CAA9A2318F4A220000A369D /* JSGlobalObjectProfilerAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CAA9A2118F4A220000A369D /* JSGlobalObjectProfilerAgent.h */; };
2600B5A6152BAAA70091EE5F /* JSStringJoiner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */; };
2600B5A7152BAAA70091EE5F /* JSStringJoiner.h in Headers */ = {isa = PBXBuildFile; fileRef = 2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */; };
+ 2A05ABD51961DF2400341750 /* JSPropertyNameEnumerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A05ABD31961DF2400341750 /* JSPropertyNameEnumerator.cpp */; };
+ 2A05ABD61961DF2400341750 /* JSPropertyNameEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */; };
2A111245192FCE79005EE18D /* CustomGetterSetter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A111243192FCE79005EE18D /* CustomGetterSetter.cpp */; };
2A111246192FCE79005EE18D /* CustomGetterSetter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A111244192FCE79005EE18D /* CustomGetterSetter.h */; settings = {ATTRIBUTES = (Private, ); }; };
2A2825D018341F2D0087FBA9 /* DelayedReleaseScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */; };
@@ -850,6 +854,7 @@
2AC922BC18A16182003CE0FB /* FTLDWARFDebugLineInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AC922BA18A16182003CE0FB /* FTLDWARFDebugLineInfo.h */; };
2ACCF3DE185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACCF3DC185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp */; };
2ACCF3DF185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACCF3DD185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h */; };
+ 2AD2EDFB19799E38004D6478 /* EnumerationMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AD2EDFA19799E38004D6478 /* EnumerationMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
2AD8932B17E3868F00668276 /* HeapIterationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AD8932917E3868F00668276 /* HeapIterationScope.h */; };
2ADFA26318EF3540004F9FCC /* GCLogging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ADFA26218EF3540004F9FCC /* GCLogging.cpp */; };
2AF7382C18BBBF92008A5A37 /* StructureIDTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AF7382A18BBBF92008A5A37 /* StructureIDTable.cpp */; };
@@ -858,6 +863,10 @@
41359CF30FDD89AD00206180 /* DateConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = D21202290AD4310C00ED79B6 /* DateConversion.h */; };
4443AE3316E188D90076F110 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51F0EB6105C86C6B00E6DF1B /* Foundation.framework */; };
451539B912DC994500EF7AC4 /* Yarr.h in Headers */ = {isa = PBXBuildFile; fileRef = 451539B812DC994500EF7AC4 /* Yarr.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 52B310FB1974AE610080857C /* FunctionHasExecutedCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B310FA1974AE610080857C /* FunctionHasExecutedCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 52B310FD1974AE870080857C /* FunctionHasExecutedCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52B310FC1974AE870080857C /* FunctionHasExecutedCache.cpp */; };
+ 52B310FF1975B4240080857C /* TypeLocationCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52B310FE1975B4240080857C /* TypeLocationCache.cpp */; };
+ 52B311011975B4670080857C /* TypeLocationCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B311001975B4670080857C /* TypeLocationCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
5510502618EB827500001F3E /* JSCallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 1440F88F0A508B100005F061 /* JSCallbackFunction.h */; };
552EA70C1908704800A66F2F /* JSDataViewPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B66BF17B6B5AB00A7AE3F /* JSDataViewPrototype.cpp */; };
5540757218DA58AD00EFF7F2 /* ArgList.h in Headers */ = {isa = PBXBuildFile; fileRef = BCF605120E203EF800B9A64D /* ArgList.h */; };
@@ -1730,7 +1739,6 @@
A72028BA1797603D0098028C /* JSFunctionInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = A72028B91797603D0098028C /* JSFunctionInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
A72700900DAC6BBC00E548D7 /* JSNotAnObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A72700780DAC605600E548D7 /* JSNotAnObject.cpp */; };
A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; };
- A727FF6B0DA3092200E548D7 /* JSPropertyNameIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */; };
A7280A2811557E3000D56957 /* JSObjectRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A79EDB0811531CD60019E912 /* JSObjectRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
A729009C17976C6000317298 /* MacroAssemblerARMv7.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A729009B17976C6000317298 /* MacroAssemblerARMv7.cpp */; };
A7299D9D17D12837005F5FF9 /* JSSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7299D9B17D12837005F5FF9 /* JSSet.cpp */; };
@@ -2424,7 +2432,13 @@
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>"; };
+ 0F7B365F197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPhantomCanonicalizationPhase.cpp; path = dfg/DFGPhantomCanonicalizationPhase.cpp; sourceTree = "<group>"; };
+ 0F7B3660197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPhantomCanonicalizationPhase.h; path = dfg/DFGPhantomCanonicalizationPhase.h; sourceTree = "<group>"; };
0F2D4DE719832DAC007D4B19 /* TypeLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeLocation.h; sourceTree = "<group>"; };
+ 52B310FA1974AE610080857C /* FunctionHasExecutedCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FunctionHasExecutedCache.h; sourceTree = "<group>"; };
+ 52B310FC1974AE870080857C /* FunctionHasExecutedCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionHasExecutedCache.cpp; sourceTree = "<group>"; };
+ 52B310FE1975B4240080857C /* TypeLocationCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeLocationCache.cpp; sourceTree = "<group>"; };
+ 52B311001975B4670080857C /* TypeLocationCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TypeLocationCache.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>"; };
@@ -2980,6 +2994,8 @@
1CAA9A2118F4A220000A369D /* JSGlobalObjectProfilerAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObjectProfilerAgent.h; sourceTree = "<group>"; };
2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringJoiner.cpp; sourceTree = "<group>"; };
2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringJoiner.h; sourceTree = "<group>"; };
+ 2A05ABD31961DF2400341750 /* JSPropertyNameEnumerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPropertyNameEnumerator.cpp; sourceTree = "<group>"; };
+ 2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPropertyNameEnumerator.h; sourceTree = "<group>"; };
2A111243192FCE79005EE18D /* CustomGetterSetter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CustomGetterSetter.cpp; sourceTree = "<group>"; };
2A111244192FCE79005EE18D /* CustomGetterSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomGetterSetter.h; sourceTree = "<group>"; };
2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayedReleaseScope.h; sourceTree = "<group>"; };
@@ -3006,6 +3022,7 @@
2AC922BA18A16182003CE0FB /* FTLDWARFDebugLineInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLDWARFDebugLineInfo.h; path = ftl/FTLDWARFDebugLineInfo.h; sourceTree = "<group>"; };
2ACCF3DC185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStoreBarrierElisionPhase.cpp; path = dfg/DFGStoreBarrierElisionPhase.cpp; sourceTree = "<group>"; };
2ACCF3DD185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStoreBarrierElisionPhase.h; path = dfg/DFGStoreBarrierElisionPhase.h; sourceTree = "<group>"; };
+ 2AD2EDFA19799E38004D6478 /* EnumerationMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EnumerationMode.h; sourceTree = "<group>"; };
2AD8932917E3868F00668276 /* HeapIterationScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapIterationScope.h; sourceTree = "<group>"; };
2ADFA26218EF3540004F9FCC /* GCLogging.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCLogging.cpp; sourceTree = "<group>"; };
2AF7382A18BBBF92008A5A37 /* StructureIDTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureIDTable.cpp; sourceTree = "<group>"; };
@@ -3400,8 +3417,6 @@
A72700770DAC605600E548D7 /* JSNotAnObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSNotAnObject.h; sourceTree = "<group>"; };
A72700780DAC605600E548D7 /* JSNotAnObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSNotAnObject.cpp; sourceTree = "<group>"; };
A72701B30DADE94900E548D7 /* ExceptionHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionHelpers.h; sourceTree = "<group>"; };
- A727FF650DA3053B00E548D7 /* JSPropertyNameIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPropertyNameIterator.h; sourceTree = "<group>"; };
- A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPropertyNameIterator.cpp; sourceTree = "<group>"; };
A729009B17976C6000317298 /* MacroAssemblerARMv7.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacroAssemblerARMv7.cpp; sourceTree = "<group>"; };
A7299D9B17D12837005F5FF9 /* JSSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSet.cpp; sourceTree = "<group>"; };
A7299D9C17D12837005F5FF9 /* JSSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSet.h; sourceTree = "<group>"; };
@@ -4691,6 +4706,8 @@
BC2680C10E16D4E900A06E92 /* FunctionConstructor.h */,
0FB4B52116B6278D003F696B /* FunctionExecutableDump.cpp */,
0FB4B52216B6278D003F696B /* FunctionExecutableDump.h */,
+ 52B310FA1974AE610080857C /* FunctionHasExecutedCache.h */,
+ 52B310FC1974AE870080857C /* FunctionHasExecutedCache.cpp */,
F692A85C0255597D01FF60F7 /* FunctionPrototype.cpp */,
F692A85D0255597D01FF60F7 /* FunctionPrototype.h */,
0F2B66B217B6B5AB00A7AE3F /* GenericTypedArrayView.h */,
@@ -4800,8 +4817,6 @@
7C184E1D17BEE22E007CB63A /* JSPromisePrototype.h */,
7C008CDC1871258D00955C24 /* JSPromiseReaction.cpp */,
7C008CDD1871258D00955C24 /* JSPromiseReaction.h */,
- A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */,
- A727FF650DA3053B00E548D7 /* JSPropertyNameIterator.h */,
862553CE16136AA5009F17D0 /* JSProxy.cpp */,
862553CF16136AA5009F17D0 /* JSProxy.h */,
14874AE115EBDE4A002E3587 /* JSScope.cpp */,
@@ -4972,6 +4987,8 @@
0F2B66DB17B6B5AB00A7AE3F /* TypedArrays.h */,
0F2B66DC17B6B5AB00A7AE3F /* TypedArrayType.cpp */,
0F2B66DD17B6B5AB00A7AE3F /* TypedArrayType.h */,
+ 52B311001975B4670080857C /* TypeLocationCache.h */,
+ 52B310FE1975B4240080857C /* TypeLocationCache.cpp */,
0F2D4DE319832D91007D4B19 /* TypeSet.cpp */,
0F2D4DE419832D91007D4B19 /* TypeSet.h */,
A7A8AF3217ADB5F3005AB174 /* Uint16Array.h */,
@@ -4996,6 +5013,9 @@
1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */,
A7DCB77912E3D90500911940 /* WriteBarrier.h */,
C2B6D75218A33793004A9301 /* WriteBarrierInlines.h */,
+ 2A05ABD31961DF2400341750 /* JSPropertyNameEnumerator.cpp */,
+ 2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */,
+ 2AD2EDFA19799E38004D6478 /* EnumerationMode.h */,
);
path = runtime;
sourceTree = "<group>";
@@ -5211,6 +5231,8 @@
0FEFC9A81681A3B000567F53 /* DFGOSRExitJumpPlaceholder.h */,
0F235BE917178E7300690C7F /* DFGOSRExitPreparation.cpp */,
0F235BEA17178E7300690C7F /* DFGOSRExitPreparation.h */,
+ 0F7B365F197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.cpp */,
+ 0F7B3660197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.h */,
0FBFDD02196C92BF007A5BFA /* DFGPhantomRemovalPhase.cpp */,
0FBFDD03196C92BF007A5BFA /* DFGPhantomRemovalPhase.h */,
0FFFC94F14EF909500C72532 /* DFGPhase.cpp */,
@@ -5961,6 +5983,7 @@
0F6B1CB91861244C00845D97 /* ArityCheckMode.h in Headers */,
A1A009C11831A26E00CF8711 /* ARM64Assembler.h in Headers */,
86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */,
+ 2AD2EDFB19799E38004D6478 /* EnumerationMode.h in Headers */,
147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */,
2A111246192FCE79005EE18D /* CustomGetterSetter.h in Headers */,
A584032018BFFBE1005A0811 /* InspectorAgent.h in Headers */,
@@ -6267,6 +6290,7 @@
0F235BDD17178E1C00690C7F /* FTLOSRExit.h in Headers */,
0F235BDE17178E1C00690C7F /* FTLOSRExitCompilationInfo.h in Headers */,
0F235BE017178E1C00690C7F /* FTLOSRExitCompiler.h in Headers */,
+ 52B310FB1974AE610080857C /* FunctionHasExecutedCache.h in Headers */,
0FEA0A11170513DB00BB722C /* FTLOutput.h in Headers */,
9E72940B190F0514001A91B5 /* BundlePath.h in Headers */,
0F48532A187DFDEC0083B687 /* FTLRecoveryOpcode.h in Headers */,
@@ -6437,6 +6461,7 @@
0F2B66F217B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructor.h in Headers */,
0F2B66F317B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructorInlines.h in Headers */,
0F2B66F417B6B5AB00A7AE3F /* JSGenericTypedArrayViewInlines.h in Headers */,
+ 0F7B3662197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.h in Headers */,
0F5A1274192D9FDF008764A3 /* DFGDoesGC.h in Headers */,
0F2B66F517B6B5AB00A7AE3F /* JSGenericTypedArrayViewPrototype.h in Headers */,
0F2B66F617B6B5AB00A7AE3F /* JSGenericTypedArrayViewPrototypeInlines.h in Headers */,
@@ -6620,6 +6645,8 @@
0FF729BB166AD360000F5BA3 /* ProfilerCompilationKind.h in Headers */,
0FF729BC166AD360000F5BA3 /* ProfilerCompiledBytecode.h in Headers */,
0FF729BD166AD360000F5BA3 /* ProfilerDatabase.h in Headers */,
+ 2A05ABD61961DF2400341750 /* JSPropertyNameEnumerator.h in Headers */,
+ 52B311011975B4670080857C /* TypeLocationCache.h in Headers */,
0FF729BE166AD360000F5BA3 /* ProfilerExecutionCounter.h in Headers */,
0F190CAD189D82F6000AE5F0 /* ProfilerJettisonReason.h in Headers */,
0FF729BF166AD360000F5BA3 /* ProfilerOrigin.h in Headers */,
@@ -7608,6 +7635,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 52B310FF1975B4240080857C /* TypeLocationCache.cpp in Sources */,
9EA5C7A2190F088700508EBE /* InitializeLLVMMac.cpp in Sources */,
9EA5C7A1190F084200508EBE /* BundlePath.mm in Sources */,
9E729408190F021E001A91B5 /* InitializeLLVMPOSIX.cpp in Sources */,
@@ -7771,6 +7799,7 @@
86880F1F14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp in Sources */,
86880F4D14353B2100B08D42 /* DFGSpeculativeJIT64.cpp in Sources */,
A7D89CFF17A0B8CC00773AD8 /* DFGSSAConversionPhase.cpp in Sources */,
+ 2A05ABD51961DF2400341750 /* JSPropertyNameEnumerator.cpp in Sources */,
0FC20CB918556A3500C9E954 /* DFGSSALoweringPhase.cpp in Sources */,
0F9FB4F417FCB91700CB67F8 /* DFGStackLayoutPhase.cpp in Sources */,
0F4F29DF18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp in Sources */,
@@ -7856,6 +7885,7 @@
0F5A6283188C98D40072C9DF /* FTLValueRange.cpp in Sources */,
147F39CB107EC37600427A48 /* FunctionConstructor.cpp in Sources */,
0FF0F19F16B72A17005DF95B /* FunctionExecutableDump.cpp in Sources */,
+ 52B310FD1974AE870080857C /* FunctionHasExecutedCache.cpp in Sources */,
147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */,
0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */,
C2239D1A16262BDD005AC5FD /* GCThread.cpp in Sources */,
@@ -7957,6 +7987,7 @@
A503FA1D188E0FB000110F14 /* JSJavaScriptCallFramePrototype.cpp in Sources */,
14280875107EC13E0013E7B2 /* JSLock.cpp in Sources */,
0F3D0BBC194A414300FC9CF9 /* ConstantStructureCheck.cpp in Sources */,
+ 0F7B3661197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.cpp in Sources */,
C25D709B16DE99F400FCA6BC /* JSManagedValue.mm in Sources */,
A700874117CBE8EB00C3E643 /* JSMap.cpp in Sources */,
A74DEF95182D991400522C22 /* JSMapIterator.cpp in Sources */,
@@ -7973,7 +8004,6 @@
7C008CD2186F8A9300955C24 /* JSPromiseFunctions.cpp in Sources */,
7C184E1E17BEE22E007CB63A /* JSPromisePrototype.cpp in Sources */,
7C008CDE1871258D00955C24 /* JSPromiseReaction.cpp in Sources */,
- A727FF6B0DA3092200E548D7 /* JSPropertyNameIterator.cpp in Sources */,
862553D116136DA9009F17D0 /* JSProxy.cpp in Sources */,
9928FF3B18AC4AEC00B8CF12 /* JSReplayInputs.cpp in Sources */,
14874AE515EBDE4A002E3587 /* JSScope.cpp in Sources */,
diff --git a/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp b/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp
index 95a7472..a2bfacb 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp
@@ -52,8 +52,6 @@
case op_switch_imm:
case op_switch_char:
case op_switch_string:
- case op_get_pnames:
- case op_next_pname:
case op_check_has_instance:
return true;
default:
diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.json b/Source/JavaScriptCore/bytecode/BytecodeList.json
index c9b47fc..36720ac 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeList.json
+++ b/Source/JavaScriptCore/bytecode/BytecodeList.json
@@ -70,7 +70,6 @@
{ "name" : "op_del_by_id", "length" : 4 },
{ "name" : "op_get_by_val", "length" : 6 },
{ "name" : "op_get_argument_by_val", "length" : 6 },
- { "name" : "op_get_by_pname", "length" : 7 },
{ "name" : "op_put_by_val", "length" : 5 },
{ "name" : "op_put_by_val_direct", "length" : 5 },
{ "name" : "op_del_by_val", "length" : 4 },
@@ -108,8 +107,6 @@
{ "name" : "op_construct_varargs", "length" : 9 },
{ "name" : "op_strcat", "length" : 4 },
{ "name" : "op_to_primitive", "length" : 3 },
- { "name" : "op_get_pnames", "length" : 6 },
- { "name" : "op_next_pname", "length" : 7 },
{ "name" : "op_resolve_scope", "length" : 6 },
{ "name" : "op_get_from_scope", "length" : 8 },
{ "name" : "op_get_from_scope_with_profile", "length" : 9 },
@@ -125,7 +122,16 @@
{ "name" : "op_profile_will_call", "length" : 2 },
{ "name" : "op_profile_did_call", "length" : 2 },
{ "name" : "op_end", "length" : 2 },
- { "name" : "op_profile_types_with_high_fidelity", "length" : 4 }
+ { "name" : "op_profile_types_with_high_fidelity", "length" : 4 },
+ { "name" : "op_get_enumerable_length", "length" : 3 },
+ { "name" : "op_has_indexed_property", "length" : 5 },
+ { "name" : "op_has_structure_property", "length" : 5 },
+ { "name" : "op_has_generic_property", "length" : 4 },
+ { "name" : "op_get_direct_pname", "length" : 7 },
+ { "name" : "op_get_structure_property_enumerator", "length" : 4 },
+ { "name" : "op_get_generic_property_enumerator", "length" : 5 },
+ { "name" : "op_next_enumerator_pname", "length" : 4 },
+ { "name" : "op_to_index_string", "length" : 3 }
]
},
{
diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
index f1bd069..40654cf 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
@@ -118,6 +118,8 @@
functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
return;
}
+ case op_get_enumerable_length:
+ case op_to_index_string:
case op_init_global_const_nop:
case op_init_global_const:
case op_push_name_scope:
@@ -144,12 +146,15 @@
case op_captured_mov:
case op_new_array_with_size:
case op_create_this:
- case op_get_pnames:
case op_del_by_id:
case op_unsigned: {
functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
return;
}
+ case op_has_generic_property:
+ case op_get_structure_property_enumerator:
+ case op_has_indexed_property:
+ case op_next_enumerator_pname:
case op_get_by_val:
case op_get_argument_by_val:
case op_in:
@@ -179,6 +184,8 @@
functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
return;
}
+ case op_has_structure_property:
+ case op_get_generic_property_enumerator:
case op_construct_varargs:
case op_call_varargs: {
functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
@@ -186,21 +193,13 @@
functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
return;
}
- case op_next_pname: {
+ case op_get_direct_pname: {
functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
functor(codeBlock, instruction, opcodeID, instruction[5].u.operand);
return;
}
- case op_get_by_pname: {
- functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
- functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
- functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
- functor(codeBlock, instruction, opcodeID, instruction[5].u.operand);
- functor(codeBlock, instruction, opcodeID, instruction[6].u.operand);
- return;
- }
case op_switch_string:
case op_switch_char:
case op_switch_imm: {
@@ -298,7 +297,15 @@
#undef LLINT_HELPER_OPCODES
return;
// These all have a single destination for the first argument.
- case op_next_pname:
+ case op_to_index_string:
+ case op_get_generic_property_enumerator:
+ case op_get_enumerable_length:
+ case op_has_indexed_property:
+ case op_has_structure_property:
+ case op_has_generic_property:
+ case op_get_direct_pname:
+ case op_get_structure_property_enumerator:
+ case op_next_enumerator_pname:
case op_resolve_scope:
case op_strcat:
case op_tear_off_activation:
@@ -326,7 +333,6 @@
case op_instanceof:
case op_get_by_val:
case op_get_argument_by_val:
- case op_get_by_pname:
case op_get_arguments_length:
case op_typeof:
case op_is_undefined:
@@ -376,12 +382,6 @@
functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
return;
}
- case op_get_pnames: {
- functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
- functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
- functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
- return;
- }
case op_enter: {
for (unsigned i = codeBlock->m_numVars; i--;)
functor(codeBlock, instruction, opcodeID, virtualRegisterForLocal(i).offset());
diff --git a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
index 72575bd..93cb13d 100644
--- a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
+++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -61,8 +61,7 @@
{
if (isLinked()) {
if (stub) {
- if (!Heap::isMarked(stub->structure())
- || !Heap::isMarked(stub->executable())) {
+ if (!Heap::isMarked(stub->executable())) {
if (Options::verboseOSR()) {
dataLog(
"Clearing closure call from ", *repatchBuffer.codeBlock(), " to ",
diff --git a/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp b/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp
index 265ef15b..aa0e962 100644
--- a/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp
+++ b/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp
@@ -40,15 +40,12 @@
CallLinkStatus::CallLinkStatus(JSValue value)
: m_callTarget(value)
, m_executable(0)
- , m_structure(0)
, m_couldTakeSlowPath(false)
, m_isProved(false)
{
if (!value || !value.isCell())
return;
- m_structure = value.asCell()->structure();
-
if (!value.asCell()->inherits(JSFunction::info()))
return;
@@ -176,14 +173,14 @@
return takesSlowPath();
if (ClosureCallStubRoutine* stub = callLinkInfo.stub.get())
- return CallLinkStatus(stub->executable(), stub->structure());
+ return CallLinkStatus(stub->executable());
JSFunction* target = callLinkInfo.lastSeenCallee.get();
if (!target)
return CallLinkStatus();
if (callLinkInfo.hasSeenClosure)
- return CallLinkStatus(target->executable(), target->structure());
+ return CallLinkStatus(target->executable());
return CallLinkStatus(target);
}
@@ -282,9 +279,6 @@
if (!isCompilationThread())
out.print("/", m_executable->hashFor(CodeForCall));
}
-
- if (m_structure)
- out.print(comma, "Structure: ", RawPointer(m_structure));
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecode/CallLinkStatus.h b/Source/JavaScriptCore/bytecode/CallLinkStatus.h
index a8ae082..9a34135 100644
--- a/Source/JavaScriptCore/bytecode/CallLinkStatus.h
+++ b/Source/JavaScriptCore/bytecode/CallLinkStatus.h
@@ -47,7 +47,6 @@
public:
CallLinkStatus()
: m_executable(0)
- , m_structure(0)
, m_couldTakeSlowPath(false)
, m_isProved(false)
{
@@ -62,13 +61,11 @@
explicit CallLinkStatus(JSValue);
- CallLinkStatus(ExecutableBase* executable, Structure* structure)
+ CallLinkStatus(ExecutableBase* executable)
: m_executable(executable)
- , m_structure(structure)
, m_couldTakeSlowPath(false)
, m_isProved(false)
{
- ASSERT(!!executable == !!structure);
}
CallLinkStatus& setIsProved(bool isProved)
@@ -122,7 +119,6 @@
InternalFunction* internalFunction() const;
Intrinsic intrinsicFor(CodeSpecializationKind) const;
ExecutableBase* executable() const { return m_executable; }
- Structure* structure() const { return m_structure; }
bool isProved() const { return m_isProved; }
bool canOptimize() const { return (m_callTarget || m_executable) && !m_couldTakeSlowPath; }
@@ -140,7 +136,6 @@
JSValue m_callTarget;
ExecutableBase* m_executable;
- Structure* m_structure;
bool m_couldTakeSlowPath;
bool m_isProved;
};
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 15c1876..9d5ff16 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -49,7 +49,7 @@
#include "JSFunction.h"
#include "JSNameScope.h"
#include "LLIntEntrypoint.h"
-#include "TypeLocation.h"
+#include "TypeLocationCache.h"
#include "LowLevelInterpreter.h"
#include "JSCInlines.h"
#include "PolymorphicGetByIdList.h"
@@ -1109,17 +1109,6 @@
dumpValueProfiling(out, it, hasPrintedProfiling);
break;
}
- case op_get_by_pname: {
- int r0 = (++it)->u.operand;
- int r1 = (++it)->u.operand;
- int r2 = (++it)->u.operand;
- int r3 = (++it)->u.operand;
- int r4 = (++it)->u.operand;
- int r5 = (++it)->u.operand;
- printLocationAndOp(out, exec, location, it, "get_by_pname");
- out.printf("%s, %s, %s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data(), registerName(r4).data(), registerName(r5).data());
- break;
- }
case op_put_by_val: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
@@ -1366,27 +1355,89 @@
out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
break;
}
- case op_get_pnames: {
- int r0 = it[1].u.operand;
- int r1 = it[2].u.operand;
- int r2 = it[3].u.operand;
- int r3 = it[4].u.operand;
- int offset = it[5].u.operand;
- printLocationAndOp(out, exec, location, it, "get_pnames");
- out.printf("%s, %s, %s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data(), offset, location + offset);
- it += OPCODE_LENGTH(op_get_pnames) - 1;
+ case op_get_enumerable_length: {
+ int dst = it[1].u.operand;
+ int base = it[2].u.operand;
+ printLocationAndOp(out, exec, location, it, "op_get_enumerable_length");
+ out.printf("%s, %s", registerName(dst).data(), registerName(base).data());
+ it += OPCODE_LENGTH(op_get_enumerable_length) - 1;
break;
}
- case op_next_pname: {
- int dest = it[1].u.operand;
+ case op_has_indexed_property: {
+ int dst = it[1].u.operand;
int base = it[2].u.operand;
- int i = it[3].u.operand;
- int size = it[4].u.operand;
- int iter = it[5].u.operand;
- int offset = it[6].u.operand;
- printLocationAndOp(out, exec, location, it, "next_pname");
- out.printf("%s, %s, %s, %s, %s, %d(->%d)", registerName(dest).data(), registerName(base).data(), registerName(i).data(), registerName(size).data(), registerName(iter).data(), offset, location + offset);
- it += OPCODE_LENGTH(op_next_pname) - 1;
+ int propertyName = it[3].u.operand;
+ ArrayProfile* arrayProfile = it[4].u.arrayProfile;
+ printLocationAndOp(out, exec, location, it, "op_has_indexed_property");
+ out.printf("%s, %s, %s, %p", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), arrayProfile);
+ it += OPCODE_LENGTH(op_has_indexed_property) - 1;
+ break;
+ }
+ case op_has_structure_property: {
+ int dst = it[1].u.operand;
+ int base = it[2].u.operand;
+ int propertyName = it[3].u.operand;
+ int enumerator = it[4].u.operand;
+ printLocationAndOp(out, exec, location, it, "op_has_structure_property");
+ out.printf("%s, %s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), registerName(enumerator).data());
+ it += OPCODE_LENGTH(op_has_structure_property) - 1;
+ break;
+ }
+ case op_has_generic_property: {
+ int dst = it[1].u.operand;
+ int base = it[2].u.operand;
+ int propertyName = it[3].u.operand;
+ printLocationAndOp(out, exec, location, it, "op_has_generic_property");
+ out.printf("%s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data());
+ it += OPCODE_LENGTH(op_has_generic_property) - 1;
+ break;
+ }
+ case op_get_direct_pname: {
+ int dst = it[1].u.operand;
+ int base = it[2].u.operand;
+ int propertyName = it[3].u.operand;
+ int index = it[4].u.operand;
+ int enumerator = it[5].u.operand;
+ ValueProfile* profile = it[6].u.profile;
+ printLocationAndOp(out, exec, location, it, "op_get_direct_pname");
+ out.printf("%s, %s, %s, %s, %s, %p", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), registerName(index).data(), registerName(enumerator).data(), profile);
+ it += OPCODE_LENGTH(op_get_direct_pname) - 1;
+ break;
+
+ }
+ case op_get_structure_property_enumerator: {
+ int dst = it[1].u.operand;
+ int base = it[2].u.operand;
+ printLocationAndOp(out, exec, location, it, "op_get_structure_property_enumerator");
+ out.printf("%s, %s", registerName(dst).data(), registerName(base).data());
+ it += OPCODE_LENGTH(op_get_structure_property_enumerator) - 1;
+ break;
+ }
+ case op_get_generic_property_enumerator: {
+ int dst = it[1].u.operand;
+ int base = it[2].u.operand;
+ int length = it[3].u.operand;
+ int structureEnumerator = it[4].u.operand;
+ printLocationAndOp(out, exec, location, it, "op_get_generic_property_enumerator");
+ out.printf("%s, %s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(length).data(), registerName(structureEnumerator).data());
+ it += OPCODE_LENGTH(op_get_generic_property_enumerator) - 1;
+ break;
+ }
+ case op_next_enumerator_pname: {
+ int dst = it[1].u.operand;
+ int enumerator = it[2].u.operand;
+ int index = it[3].u.operand;
+ printLocationAndOp(out, exec, location, it, "op_next_enumerator_pname");
+ out.printf("%s, %s, %s", registerName(dst).data(), registerName(enumerator).data(), registerName(index).data());
+ it += OPCODE_LENGTH(op_next_enumerator_pname) - 1;
+ break;
+ }
+ case op_to_index_string: {
+ int dst = it[1].u.operand;
+ int index = it[2].u.operand;
+ printLocationAndOp(out, exec, location, it, "op_to_index_string");
+ out.printf("%s, %s", registerName(dst).data(), registerName(index).data());
+ it += OPCODE_LENGTH(op_to_index_string) - 1;
break;
}
case op_push_with_scope: {
@@ -1675,12 +1726,17 @@
ASSERT(m_source);
setNumParameters(unlinkedCodeBlock->numParameters());
+ if (vm()->isProfilingTypesWithHighFidelity())
+ vm()->highFidelityTypeProfiler()->functionHasExecutedCache()->removeUnexecutedRange(m_ownerExecutable->sourceID(), m_ownerExecutable->highFidelityTypeProfilingStartOffset(), m_ownerExecutable->highFidelityTypeProfilingEndOffset());
+
setConstantRegisters(unlinkedCodeBlock->constantRegisters());
if (unlinkedCodeBlock->usesGlobalObject())
m_constantRegisters[unlinkedCodeBlock->globalObjectRegister().toConstantIndex()].set(*m_vm, ownerExecutable, m_globalObject.get());
m_functionDecls.resizeToFit(unlinkedCodeBlock->numberOfFunctionDecls());
for (size_t count = unlinkedCodeBlock->numberOfFunctionDecls(), i = 0; i < count; ++i) {
UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionDecl(i);
+ if (vm()->isProfilingTypesWithHighFidelity())
+ vm()->highFidelityTypeProfiler()->functionHasExecutedCache()->insertUnexecutedRange(m_ownerExecutable->sourceID(), unlinkedExecutable->highFidelityTypeProfilingStartOffset(), unlinkedExecutable->highFidelityTypeProfilingEndOffset());
unsigned lineCount = unlinkedExecutable->lineCount();
unsigned firstLine = ownerExecutable->lineNo() + unlinkedExecutable->firstLineOffset();
bool startColumnIsOnOwnerStartLine = !unlinkedExecutable->firstLineOffset();
@@ -1697,6 +1753,8 @@
m_functionExprs.resizeToFit(unlinkedCodeBlock->numberOfFunctionExprs());
for (size_t count = unlinkedCodeBlock->numberOfFunctionExprs(), i = 0; i < count; ++i) {
UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionExpr(i);
+ if (vm()->isProfilingTypesWithHighFidelity())
+ vm()->highFidelityTypeProfiler()->functionHasExecutedCache()->insertUnexecutedRange(m_ownerExecutable->sourceID(), unlinkedExecutable->highFidelityTypeProfilingStartOffset(), unlinkedExecutable->highFidelityTypeProfilingEndOffset());
unsigned lineCount = unlinkedExecutable->lineCount();
unsigned firstLine = ownerExecutable->lineNo() + unlinkedExecutable->firstLineOffset();
bool startColumnIsOnOwnerStartLine = !unlinkedExecutable->firstLineOffset();
@@ -1787,6 +1845,13 @@
instructions[i + j].u.operand = pc[j].u.operand;
}
switch (pc[0].u.opcode) {
+ case op_has_indexed_property: {
+ int arrayProfileIndex = pc[opLength - 1].u.operand;
+ m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i);
+
+ instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex];
+ break;
+ }
case op_call_varargs:
case op_construct_varargs:
case op_get_by_val:
@@ -1797,6 +1862,7 @@
instructions[i + opLength - 2] = &m_arrayProfiles[arrayProfileIndex];
FALLTHROUGH;
}
+ case op_get_direct_pname:
case op_get_by_id: {
ValueProfile* profile = &m_valueProfiles[pc[opLength - 1].u.operand];
ASSERT(profile->m_bytecodeOffset == -1);
@@ -1906,8 +1972,7 @@
if (pc[0].u.opcode == op_get_from_scope_with_profile) {
// The format of this instruction is: get_from_scope_with_profile dst, scope, id, ResolveModeAndType, Structure, Operand, ..., TypeLocation
size_t instructionOffset = i + opLength - 1;
- TypeLocation* location = vm()->nextLocation();
- scopeDependentProfile(op, ident, instructionOffset, location);
+ TypeLocation* location = scopeDependentProfile(op, ident, instructionOffset);
instructions[i + 8].u.location = location;
}
break;
@@ -1933,8 +1998,7 @@
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*
size_t instructionOffset = i + opLength - 1;
- TypeLocation* location = vm()->nextLocation();
- scopeDependentProfile(op, ident, instructionOffset, location);
+ TypeLocation* location = scopeDependentProfile(op, ident, instructionOffset);
instructions[i + 7].u.location = location;
}
break;
@@ -1943,44 +2007,52 @@
case op_profile_types_with_high_fidelity: {
size_t instructionOffset = i + opLength - 1;
unsigned divotStart, divotEnd;
+ GlobalVariableID globalVariableID;
+ RefPtr<TypeSet> globalTypeSet;
bool shouldAnalyze = m_unlinkedCode->highFidelityTypeProfileExpressionInfoForBytecodeOffset(instructionOffset, divotStart, divotEnd);
VirtualRegister virtualRegister(pc[1].u.operand);
SymbolTable* symbolTable = m_symbolTable.get();
- TypeLocation* location = vm()->nextLocation();
- location->m_divotStart = divotStart;
- location->m_divotEnd = divotEnd;
- location->m_sourceID = m_ownerExecutable->sourceID();
ProfileTypesWithHighFidelityBytecodeFlag flag = static_cast<ProfileTypesWithHighFidelityBytecodeFlag>(pc[3].u.operand);
switch (flag) {
case ProfileTypesBytecodeHasGlobalID: {
ConcurrentJITLocker locker(symbolTable->m_lock);
- location->m_globalVariableID = symbolTable->uniqueIDForRegister(locker, virtualRegister.offset(), *vm());
- location->m_globalTypeSet = symbolTable->globalTypeSetForRegister(locker, virtualRegister.offset(), *vm());
+ globalVariableID = symbolTable->uniqueIDForRegister(locker, virtualRegister.offset(), *vm());
+ globalTypeSet = symbolTable->globalTypeSetForRegister(locker, virtualRegister.offset(), *vm());
break;
}
case ProfileTypesBytecodeDoesNotHaveGlobalID:
- case ProfileTypesBytecodeFunctionArgument:
+ case ProfileTypesBytecodeFunctionArgument: {
+ globalVariableID = HighFidelityNoGlobalIDExists;
+ break;
+ }
case ProfileTypesBytecodeFunctionThisObject: {
- location->m_globalVariableID = HighFidelityNoGlobalIDExists;
+ globalVariableID = HighFidelityThisStatement;
break;
}
case ProfileTypesBytecodeFunctionReturnStatement: {
- location->m_globalTypeSet = returnStatementTypeSet();
- location->m_globalVariableID = HighFidelityReturnStatement;
- location->m_divotForFunctionOffsetIfReturnStatement = m_sourceOffset;
+ globalTypeSet = returnStatementTypeSet();
+ globalVariableID = HighFidelityReturnStatement;
if (!shouldAnalyze) {
// Because some return statements are added implicitly (to return undefined at the end of a function), and these nodes don't emit expression ranges, give them some range.
// Currently, this divot is on the open brace of the function.
- location->m_divotStart = location->m_divotEnd = location->m_divotForFunctionOffsetIfReturnStatement;
+ divotStart = divotEnd = m_sourceOffset;
shouldAnalyze = true;
}
break;
}
}
- if (shouldAnalyze)
+ std::pair<TypeLocation*, bool> locationPair = vm()->highFidelityTypeProfiler()->typeLocationCache()->getTypeLocation(globalVariableID, m_ownerExecutable->sourceID(), divotStart, divotEnd, globalTypeSet, vm());
+ TypeLocation* location = locationPair.first;
+ bool isNewLocation = locationPair.second;
+
+ if (ProfileTypesBytecodeFunctionReturnStatement)
+ location->m_divotForFunctionOffsetIfReturnStatement = m_sourceOffset;
+
+ if (shouldAnalyze && isNewLocation)
vm()->highFidelityTypeProfiler()->insertNewLocation(location);
+
instructions[i + 2].u.location = location;
break;
}
@@ -3863,13 +3935,12 @@
}
#endif
-void CodeBlock::scopeDependentProfile(ResolveOp op, const Identifier& ident, size_t instructionOffset, TypeLocation* location)
+TypeLocation* CodeBlock::scopeDependentProfile(ResolveOp op, const Identifier& ident, size_t instructionOffset)
{
unsigned divotStart, divotEnd;
bool shouldAnalyze = m_unlinkedCode->highFidelityTypeProfileExpressionInfoForBytecodeOffset(instructionOffset, divotStart, divotEnd);
- location->m_divotStart = divotStart;
- location->m_divotEnd = divotEnd;
- location->m_sourceID = m_ownerExecutable->sourceID();
+ GlobalVariableID globalVariableID;
+ RefPtr<TypeSet> globalTypeSet;
// FIXME: handle other values for op.type here, and also consider what to do when we can't statically determine the globalID
SymbolTable* symbolTable = nullptr;
@@ -3880,13 +3951,19 @@
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());
+ globalVariableID = symbolTable->uniqueIDForVariable(locker, ident.impl(), *vm());
+ globalTypeSet = symbolTable->globalTypeSetForVariable(locker, ident.impl(), *vm());
} else
- location->m_globalVariableID = HighFidelityNoGlobalIDExists;
+ globalVariableID = HighFidelityNoGlobalIDExists;
- if (shouldAnalyze)
+ std::pair<TypeLocation*, bool> locationPair = vm()->highFidelityTypeProfiler()->typeLocationCache()->getTypeLocation(globalVariableID, m_ownerExecutable->sourceID(), divotStart, divotEnd, globalTypeSet, vm());
+ TypeLocation* location = locationPair.first;
+ bool isNewLocation = locationPair.second;
+
+ if (shouldAnalyze & isNewLocation)
vm()->highFidelityTypeProfiler()->insertNewLocation(location);
+
+ return location;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index 954a28a..4ec760c 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -83,6 +83,7 @@
class ExecState;
class LLIntOffsetsExtractor;
class RepatchBuffer;
+class TypeLocation;
inline VirtualRegister unmodifiedArgumentsRegister(VirtualRegister argumentsRegister) { return VirtualRegister(argumentsRegister.offset() + 1); }
@@ -1019,7 +1020,7 @@
m_rareData = adoptPtr(new RareData);
}
- void scopeDependentProfile(ResolveOp, const Identifier&, size_t, TypeLocation*);
+ TypeLocation* scopeDependentProfile(ResolveOp, const Identifier&, size_t);
#if ENABLE(JIT)
void resetStubInternal(RepatchBuffer&, StructureStubInfo&);
diff --git a/Source/JavaScriptCore/bytecode/PreciseJumpTargets.cpp b/Source/JavaScriptCore/bytecode/PreciseJumpTargets.cpp
index 87f2ceb..6bba492 100644
--- a/Source/JavaScriptCore/bytecode/PreciseJumpTargets.cpp
+++ b/Source/JavaScriptCore/bytecode/PreciseJumpTargets.cpp
@@ -73,12 +73,6 @@
out.append(bytecodeOffset + current[2].u.operand);
break;
}
- case op_get_pnames:
- out.append(bytecodeOffset + current[5].u.operand);
- break;
- case op_next_pname:
- out.append(bytecodeOffset + current[6].u.operand);
- break;
case op_check_has_instance:
out.append(bytecodeOffset + current[4].u.operand);
break;
diff --git a/Source/JavaScriptCore/bytecode/TypeLocation.h b/Source/JavaScriptCore/bytecode/TypeLocation.h
index 7e70547..7a09bd0 100644
--- a/Source/JavaScriptCore/bytecode/TypeLocation.h
+++ b/Source/JavaScriptCore/bytecode/TypeLocation.h
@@ -33,18 +33,22 @@
enum HighFidelityGlobalIDFlags {
HighFidelityNeedsUniqueIDGeneration = -1,
HighFidelityNoGlobalIDExists = -2,
- HighFidelityReturnStatement = -3
+ HighFidelityReturnStatement = -3,
+ HighFidelityThisStatement = -4
};
+typedef intptr_t GlobalVariableID;
+
class TypeLocation {
public:
TypeLocation()
- : m_instructionTypeSet(TypeSet::create())
+ : m_divotForFunctionOffsetIfReturnStatement(UINT_MAX)
+ , m_instructionTypeSet(TypeSet::create())
, m_globalTypeSet(nullptr)
{
}
- int64_t m_globalVariableID;
+ GlobalVariableID m_globalVariableID;
intptr_t m_sourceID;
unsigned m_divotStart;
unsigned m_divotEnd;
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
index 65800c4..5e76737 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
@@ -99,6 +99,8 @@
, m_unlinkedBodyEndColumn(m_lineCount ? node->endColumn() : node->endColumn() - node->startColumn())
, m_startOffset(node->source().startOffset() - source.startOffset())
, m_sourceLength(node->source().length())
+ , m_highFidelityTypeProfilingStartOffset(node->functionNameStart())
+ , m_highFidelityTypeProfilingEndOffset(node->startStartOffset() + node->source().length() - 1)
, m_features(node->features())
, m_functionMode(node->functionMode())
{
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
index 5b8caff..0177470 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
@@ -125,6 +125,8 @@
unsigned unlinkedBodyEndColumn() const { return m_unlinkedBodyEndColumn; }
unsigned startOffset() const { return m_startOffset; }
unsigned sourceLength() { return m_sourceLength; }
+ unsigned highFidelityTypeProfilingStartOffset() const { return m_highFidelityTypeProfilingStartOffset; }
+ unsigned highFidelityTypeProfilingEndOffset() const { return m_highFidelityTypeProfilingEndOffset; }
String paramString() const;
@@ -185,6 +187,8 @@
unsigned m_unlinkedBodyEndColumn;
unsigned m_startOffset;
unsigned m_sourceLength;
+ unsigned m_highFidelityTypeProfilingStartOffset;
+ unsigned m_highFidelityTypeProfilingEndOffset;
CodeFeatures m_features;
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index baea9fb..d940107 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -337,7 +337,7 @@
m_symbolTable->setCaptureEnd(virtualRegisterForLocal(codeBlock->m_numVars).offset());
- bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks;
+ bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks && !isProfilingTypesWithHighFidelity();
m_firstLazyFunction = codeBlock->m_numVars;
for (size_t i = 0; i < functionStack.size(); ++i) {
FunctionBodyNode* function = functionStack[i];
@@ -1116,6 +1116,14 @@
return dst;
}
+void BytecodeGenerator::emitHighFidelityTypeProfilingExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot)
+{
+ unsigned start = startDivot.offset; // Ranges are inclusive of their endpoints, AND 0 indexed.
+ unsigned end = endDivot.offset - 1; // End Ranges already go one past the inclusive range, so subtract 1.
+ unsigned instructionOffset = instructions().size() - 1;
+ m_codeBlock->addHighFidelityTypeProfileExpressionInfo(instructionOffset, start, end);
+}
+
void BytecodeGenerator::emitProfileTypesWithHighFidelity(RegisterID* registerToProfile, ProfileTypesWithHighFidelityBytecodeFlag flag)
{
emitOpcode(op_profile_types_with_high_fidelity);
@@ -1436,18 +1444,30 @@
RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
{
for (size_t i = m_forInContextStack.size(); i > 0; i--) {
- ForInContext& context = m_forInContextStack[i - 1];
- if (context.propertyRegister == property) {
- emitOpcode(op_get_by_pname);
- instructions().append(dst->index());
- instructions().append(base->index());
- instructions().append(property->index());
- instructions().append(context.expectedSubscriptRegister->index());
- instructions().append(context.iterRegister->index());
- instructions().append(context.indexRegister->index());
- return dst;
+ ForInContext* context = m_forInContextStack[i - 1].get();
+ if (context->local() != property)
+ continue;
+
+ if (!context->isValid())
+ break;
+
+ if (context->type() == ForInContext::IndexedForInContextType) {
+ property = static_cast<IndexedForInContext*>(context)->index();
+ break;
}
+
+ ASSERT(context->type() == ForInContext::StructureForInContextType);
+ StructureForInContext* structureContext = static_cast<StructureForInContext*>(context);
+ UnlinkedValueProfile profile = emitProfiledOpcode(op_get_direct_pname);
+ instructions().append(kill(dst));
+ instructions().append(base->index());
+ instructions().append(property->index());
+ instructions().append(structureContext->index()->index());
+ instructions().append(structureContext->enumerator()->index());
+ instructions().append(profile);
+ return dst;
}
+
UnlinkedArrayProfile arrayProfile = newArrayProfile();
UnlinkedValueProfile profile = emitProfiledOpcode(op_get_by_val);
instructions().append(kill(dst));
@@ -2153,7 +2173,7 @@
Vector<ControlFlowContext> savedScopeContextStack;
Vector<SwitchInfo> savedSwitchContextStack;
- Vector<ForInContext> savedForInContextStack;
+ Vector<std::unique_ptr<ForInContext>> savedForInContextStack;
Vector<TryContext> poppedTryContexts;
LabelScopeStore savedLabelScopes;
while (topScope > bottomScope && topScope->isFinallyBlock) {
@@ -2180,7 +2200,7 @@
m_switchContextStack.shrink(finallyContext.switchContextStackSize);
}
if (flipForIns) {
- savedForInContextStack = m_forInContextStack;
+ savedForInContextStack.swap(m_forInContextStack);
m_forInContextStack.shrink(finallyContext.forInContextStackSize);
}
if (flipTries) {
@@ -2220,7 +2240,7 @@
if (flipSwitches)
m_switchContextStack = savedSwitchContextStack;
if (flipForIns)
- m_forInContextStack = savedForInContextStack;
+ m_forInContextStack.swap(savedForInContextStack);
if (flipTries) {
ASSERT(m_tryContextStack.size() == finallyContext.tryContextStackSize);
for (unsigned i = poppedTryContexts.size(); i--;) {
@@ -2258,33 +2278,6 @@
emitComplexPopScopes(&m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta);
}
-RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget)
-{
- size_t begin = instructions().size();
-
- emitOpcode(op_get_pnames);
- instructions().append(dst->index());
- instructions().append(base->index());
- instructions().append(i->index());
- instructions().append(size->index());
- instructions().append(breakTarget->bind(begin, instructions().size()));
- return dst;
-}
-
-RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target)
-{
- size_t begin = instructions().size();
-
- emitOpcode(op_next_pname);
- instructions().append(dst->index());
- instructions().append(base->index());
- instructions().append(i->index());
- instructions().append(size->index());
- instructions().append(iter->index());
- instructions().append(target->bind(begin, instructions().size()));
- return dst;
-}
-
TryData* BytecodeGenerator::pushTry(Label* start)
{
TryData tryData;
@@ -2553,4 +2546,128 @@
emitLabel(scope->breakTarget());
}
+RegisterID* BytecodeGenerator::emitGetEnumerableLength(RegisterID* dst, RegisterID* base)
+{
+ emitOpcode(op_get_enumerable_length);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitHasGenericProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName)
+{
+ emitOpcode(op_has_generic_property);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(propertyName->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitHasIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName)
+{
+ UnlinkedArrayProfile arrayProfile = newArrayProfile();
+ emitOpcode(op_has_indexed_property);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(propertyName->index());
+ instructions().append(arrayProfile);
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitHasStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator)
+{
+ emitOpcode(op_has_structure_property);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(propertyName->index());
+ instructions().append(enumerator->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitGetStructurePropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length)
+{
+ emitOpcode(op_get_structure_property_enumerator);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(length->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitGetGenericPropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length, RegisterID* structureEnumerator)
+{
+ emitOpcode(op_get_generic_property_enumerator);
+ instructions().append(dst->index());
+ instructions().append(base->index());
+ instructions().append(length->index());
+ instructions().append(structureEnumerator->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitNextEnumeratorPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index)
+{
+ emitOpcode(op_next_enumerator_pname);
+ instructions().append(dst->index());
+ instructions().append(enumerator->index());
+ instructions().append(index->index());
+ return dst;
+}
+
+RegisterID* BytecodeGenerator::emitToIndexString(RegisterID* dst, RegisterID* index)
+{
+ emitOpcode(op_to_index_string);
+ instructions().append(dst->index());
+ instructions().append(index->index());
+ return dst;
+}
+
+void BytecodeGenerator::pushIndexedForInScope(RegisterID* localRegister, RegisterID* indexRegister)
+{
+ if (!localRegister)
+ return;
+ m_forInContextStack.append(std::make_unique<IndexedForInContext>(localRegister, indexRegister));
+}
+
+void BytecodeGenerator::popIndexedForInScope(RegisterID* localRegister)
+{
+ if (!localRegister)
+ return;
+ m_forInContextStack.removeLast();
+}
+
+void BytecodeGenerator::pushStructureForInScope(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister)
+{
+ if (!localRegister)
+ return;
+ m_forInContextStack.append(std::make_unique<StructureForInContext>(localRegister, indexRegister, propertyRegister, enumeratorRegister));
+}
+
+void BytecodeGenerator::popStructureForInScope(RegisterID* localRegister)
+{
+ if (!localRegister)
+ return;
+ m_forInContextStack.removeLast();
+}
+
+void BytecodeGenerator::invalidateForInContextForLocal(RegisterID* localRegister)
+{
+ // Lexically invalidating ForInContexts is kind of weak sauce, but it only occurs if
+ // either of the following conditions is true:
+ //
+ // (1) The loop iteration variable is re-assigned within the body of the loop.
+ // (2) The loop iteration variable is captured in the lexical scope of the function.
+ //
+ // These two situations occur sufficiently rarely that it's okay to use this style of
+ // "analysis" to make iteration faster. If we didn't want to do this, we would either have
+ // to perform some flow-sensitive analysis to see if/when the loop iteration variable was
+ // reassigned, or we'd have to resort to runtime checks to see if the variable had been
+ // reassigned from its original value.
+ for (size_t i = m_forInContextStack.size(); i > 0; i--) {
+ ForInContext* context = m_forInContextStack[i - 1].get();
+ if (context->local() != localRegister)
+ continue;
+ context->invalidate();
+ break;
+ }
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 076ca90..eb0a589 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -97,11 +97,76 @@
FinallyContext finallyContext;
};
- struct ForInContext {
- RefPtr<RegisterID> expectedSubscriptRegister;
- RefPtr<RegisterID> iterRegister;
- RefPtr<RegisterID> indexRegister;
- RefPtr<RegisterID> propertyRegister;
+ class ForInContext {
+ public:
+ ForInContext(RegisterID* localRegister)
+ : m_localRegister(localRegister)
+ , m_isValid(true)
+ {
+ }
+
+ virtual ~ForInContext()
+ {
+ }
+
+ bool isValid() const { return m_isValid; }
+ void invalidate() { m_isValid = false; }
+
+ enum ForInContextType {
+ StructureForInContextType,
+ IndexedForInContextType
+ };
+ virtual ForInContextType type() const = 0;
+
+ RegisterID* local() const { return m_localRegister.get(); }
+
+ private:
+ RefPtr<RegisterID> m_localRegister;
+ bool m_isValid;
+ };
+
+ class StructureForInContext : public ForInContext {
+ public:
+ StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister)
+ : ForInContext(localRegister)
+ , m_indexRegister(indexRegister)
+ , m_propertyRegister(propertyRegister)
+ , m_enumeratorRegister(enumeratorRegister)
+ {
+ }
+
+ virtual ForInContextType type() const
+ {
+ return StructureForInContextType;
+ }
+
+ RegisterID* index() const { return m_indexRegister.get(); }
+ RegisterID* property() const { return m_propertyRegister.get(); }
+ RegisterID* enumerator() const { return m_enumeratorRegister.get(); }
+
+ private:
+ RefPtr<RegisterID> m_indexRegister;
+ RefPtr<RegisterID> m_propertyRegister;
+ RefPtr<RegisterID> m_enumeratorRegister;
+ };
+
+ class IndexedForInContext : public ForInContext {
+ public:
+ IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister)
+ : ForInContext(localRegister)
+ , m_indexRegister(indexRegister)
+ {
+ }
+
+ virtual ForInContextType type() const
+ {
+ return IndexedForInContextType;
+ }
+
+ RegisterID* index() const { return m_indexRegister.get(); }
+
+ private:
+ RefPtr<RegisterID> m_indexRegister;
};
struct TryData {
@@ -324,13 +389,6 @@
m_codeBlock->addExpressionInfo(instructionOffset, divotOffset, startOffset, endOffset, line, column);
}
- void emitHighFidelityTypeProfilingExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot)
- {
- unsigned start = startDivot.offset + 1; // Ranges are inclusive of their endpoints, AND 1 indexed.
- unsigned end = endDivot.offset; // End Ranges already go one past the inclusive range, so no need to do + 1 - 1.
- unsigned instructionOffset = instructions().size() - 1;
- m_codeBlock->addHighFidelityTypeProfileExpressionInfo(instructionOffset, start, end);
- }
ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure)
{
@@ -348,6 +406,7 @@
return emitNode(n);
}
+ void emitHighFidelityTypeProfilingExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot);
void emitProfileTypesWithHighFidelity(RegisterID* dst, ProfileTypesWithHighFidelityBytecodeFlag);
RegisterID* emitLoad(RegisterID* dst, bool);
@@ -428,8 +487,14 @@
PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target);
void emitPopScopes(int targetScopeDepth);
- RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget);
- RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target);
+ RegisterID* emitHasIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName);
+ RegisterID* emitHasStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator);
+ RegisterID* emitHasGenericProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName);
+ RegisterID* emitGetEnumerableLength(RegisterID* dst, RegisterID* base);
+ RegisterID* emitGetStructurePropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length);
+ RegisterID* emitGetGenericPropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length, RegisterID* structureEnumerator);
+ RegisterID* emitNextEnumeratorPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index);
+ RegisterID* emitToIndexString(RegisterID* dst, RegisterID* index);
void emitReadOnlyExceptionIfNeeded();
@@ -460,16 +525,11 @@
void pushFinallyContext(StatementNode* finallyBlock);
void popFinallyContext();
- void pushOptimisedForIn(RegisterID* expectedSubscript, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister)
- {
- ForInContext context = { expectedSubscript, iter, index, propertyRegister };
- m_forInContextStack.append(context);
- }
-
- void popOptimisedForIn()
- {
- m_forInContextStack.removeLast();
- }
+ void pushIndexedForInScope(RegisterID* local, RegisterID* index);
+ void popIndexedForInScope(RegisterID* local);
+ void pushStructureForInScope(RegisterID* local, RegisterID* index, RegisterID* property, RegisterID* enumerator);
+ void popStructureForInScope(RegisterID* local);
+ void invalidateForInContextForLocal(RegisterID* local);
LabelScopePtr breakTarget(const Identifier&);
LabelScopePtr continueTarget(const Identifier&);
@@ -668,7 +728,7 @@
Vector<ControlFlowContext, 0, UnsafeVectorOverflow> m_scopeContextStack;
Vector<SwitchInfo> m_switchContextStack;
- Vector<ForInContext> m_forInContextStack;
+ Vector<std::unique_ptr<ForInContext>> m_forInContextStack;
Vector<TryContext> m_tryContextStack;
Vector<std::pair<RefPtr<RegisterID>, const DeconstructionPatternNode*>> m_deconstructedParameters;
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 4bfbb7f..1e796fc 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -1505,12 +1505,14 @@
generator.emitMove(result.get(), local.get());
emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
generator.emitMove(local.get(), result.get());
+ generator.invalidateForInContextForLocal(local.get());
if (generator.isProfilingTypesWithHighFidelity())
generator.emitHighFidelityTypeProfilingExpressionInfo(divotStart(), divotEnd());
return generator.moveToDestinationIfNeeded(dst, result.get());
}
RegisterID* result = emitReadModifyAssignment(generator, local.get(), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
+ generator.invalidateForInContextForLocal(local.get());
return generator.moveToDestinationIfNeeded(dst, result);
}
@@ -1540,11 +1542,13 @@
RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
generator.emitNode(tempDst.get(), m_right);
generator.emitMove(local.get(), tempDst.get());
+ generator.invalidateForInContextForLocal(local.get());
if (generator.isProfilingTypesWithHighFidelity())
generator.emitHighFidelityTypeProfilingExpressionInfo(divotStart(), divotEnd());
return generator.moveToDestinationIfNeeded(dst, tempDst.get());
}
RegisterID* result = generator.emitNode(local.get(), m_right);
+ generator.invalidateForInContextForLocal(local.get());
return generator.moveToDestinationIfNeeded(dst, result);
}
@@ -1920,102 +1924,217 @@
// ------------------------------ ForInNode ------------------------------------
-void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+RegisterID* ForInNode::tryGetBoundLocal(BytecodeGenerator& generator)
{
- LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop);
-
- if (!m_lexpr->isAssignmentLocation()) {
- emitThrowReferenceError(generator, "Left side of for-in statement is not a reference.");
- return;
- }
-
- generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset());
-
- RefPtr<RegisterID> base = generator.newTemporary();
- generator.emitNode(base.get(), m_expr);
- RefPtr<RegisterID> i = generator.newTemporary();
- RefPtr<RegisterID> size = generator.newTemporary();
- RefPtr<RegisterID> expectedSubscript;
- RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), base.get(), i.get(), size.get(), scope->breakTarget());
- generator.emitJump(scope->continueTarget());
-
- RefPtr<Label> loopStart = generator.newLabel();
- generator.emitLabel(loopStart.get());
- generator.emitLoopHint();
-
- RegisterID* propertyName;
- bool optimizedForinAccess = false;
if (m_lexpr->isResolveNode()) {
const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier();
Local local = generator.local(ident);
- if (!local.get()) {
- propertyName = generator.newTemporary();
- RefPtr<RegisterID> protect = propertyName;
+ if (local.isCaptured())
+ return nullptr;
+ return local.get();
+ }
+
+ if (m_lexpr->isDeconstructionNode()) {
+ DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr);
+ auto binding = assignNode->bindings();
+ if (!binding->isBindingNode())
+ return nullptr;
+
+ auto simpleBinding = static_cast<BindingNode*>(binding);
+ const Identifier& ident = simpleBinding->boundProperty();
+ Local local = generator.local(ident);
+ if (local.isCaptured())
+ return nullptr;
+ return local.get();
+ }
+
+ return nullptr;
+}
+
+void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propertyName)
+{
+ if (m_lexpr->isResolveNode()) {
+ const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier();
+ Local local = generator.local(ident);
+ if (local.get())
+ generator.emitMove(local.get(), propertyName);
+ else {
if (generator.isStrictMode())
generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident);
generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
generator.emitPutToScope(scope, ident, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
- } else {
- expectedSubscript = generator.newTemporary();
- propertyName = expectedSubscript.get();
- generator.emitMove(local.get(), propertyName);
- generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), local.get());
- optimizedForinAccess = true;
}
- } else if (m_lexpr->isDotAccessorNode()) {
+ return;
+ }
+ if (m_lexpr->isDotAccessorNode()) {
DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr);
const Identifier& ident = assignNode->identifier();
- propertyName = generator.newTemporary();
- RefPtr<RegisterID> protect = propertyName;
RegisterID* base = generator.emitNode(assignNode->base());
-
generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
generator.emitPutById(base, ident, propertyName);
- } else if (m_lexpr->isBracketAccessorNode()) {
+ return;
+ }
+ if (m_lexpr->isBracketAccessorNode()) {
BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
- propertyName = generator.newTemporary();
- RefPtr<RegisterID> protect = propertyName;
RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
RegisterID* subscript = generator.emitNode(assignNode->subscript());
-
generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
generator.emitPutByVal(base.get(), subscript, propertyName);
- } else {
- ASSERT(m_lexpr->isDeconstructionNode());
- DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr);
- auto binding = assignNode->bindings();
- if (binding->isBindingNode()) {
- auto simpleBinding = static_cast<BindingNode*>(binding);
- Identifier ident = simpleBinding->boundProperty();
- Local local = generator.local(ident);
- propertyName = local.get();
- // 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);
- optimizedForinAccess = true;
- goto completedSimpleBinding;
- } else {
- genericBinding:
- propertyName = generator.newTemporary();
- RefPtr<RegisterID> protect(propertyName);
- assignNode->bindings()->bindValue(generator, propertyName);
- }
- completedSimpleBinding:
- ;
+ return;
}
- generator.emitNode(dst, m_statement);
+ if (m_lexpr->isDeconstructionNode()) {
+ DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr);
+ auto binding = assignNode->bindings();
+ if (!binding->isBindingNode()) {
+ assignNode->bindings()->bindValue(generator, propertyName);
+ return;
+ }
- if (optimizedForinAccess)
- generator.popOptimisedForIn();
+ auto simpleBinding = static_cast<BindingNode*>(binding);
+ const Identifier& ident = simpleBinding->boundProperty();
+ Local local = generator.local(ident);
+ if (!local.get() || local.isCaptured()) {
+ assignNode->bindings()->bindValue(generator, propertyName);
+ return;
+ }
+ generator.emitMove(local.get(), propertyName);
+ return;
+ }
- generator.emitLabel(scope->continueTarget());
- generator.emitNextPropertyName(propertyName, base.get(), i.get(), size.get(), iter.get(), loopStart.get());
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+ if (!m_lexpr->isAssignmentLocation()) {
+ emitThrowReferenceError(generator, "Left side of for-in statement is not a reference.");
+ return;
+ }
+
+ RefPtr<Label> end = generator.newLabel();
+
generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset());
- generator.emitLabel(scope->breakTarget());
+
+ RefPtr<RegisterID> base = generator.newTemporary();
+ RefPtr<RegisterID> length;
+ RefPtr<RegisterID> structureEnumerator;
+ generator.emitNode(base.get(), m_expr);
+ RefPtr<RegisterID> local = this->tryGetBoundLocal(generator);
+
+ // Indexed property loop.
+ {
+ LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop);
+ RefPtr<Label> loopStart = generator.newLabel();
+ RefPtr<Label> loopEnd = generator.newLabel();
+
+ length = generator.emitGetEnumerableLength(generator.newTemporary(), base.get());
+ RefPtr<RegisterID> i = generator.emitLoad(generator.newTemporary(), jsNumber(0));
+ RefPtr<RegisterID> propertyName = generator.newTemporary();
+
+ generator.emitLabel(loopStart.get());
+ generator.emitLoopHint();
+
+ RefPtr<RegisterID> result = generator.emitEqualityOp(op_less, generator.newTemporary(), i.get(), length.get());
+ generator.emitJumpIfFalse(result.get(), loopEnd.get());
+ generator.emitHasIndexedProperty(result.get(), base.get(), i.get());
+ generator.emitJumpIfFalse(result.get(), scope->continueTarget());
+
+ generator.emitToIndexString(propertyName.get(), i.get());
+ this->emitLoopHeader(generator, propertyName.get());
+
+ generator.pushIndexedForInScope(local.get(), i.get());
+ generator.emitNode(dst, m_statement);
+ generator.popIndexedForInScope(local.get());
+
+ generator.emitLabel(scope->continueTarget());
+ generator.emitInc(i.get());
+ generator.emitJump(loopStart.get());
+
+ generator.emitLabel(scope->breakTarget());
+ generator.emitJump(end.get());
+ generator.emitLabel(loopEnd.get());
+ }
+
+ // Structure property loop.
+ {
+ LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop);
+ RefPtr<Label> loopStart = generator.newLabel();
+ RefPtr<Label> loopEnd = generator.newLabel();
+
+ structureEnumerator = generator.emitGetStructurePropertyEnumerator(generator.newTemporary(), base.get(), length.get());
+ RefPtr<RegisterID> i = generator.emitLoad(generator.newTemporary(), jsNumber(0));
+ RefPtr<RegisterID> propertyName = generator.newTemporary();
+ generator.emitNextEnumeratorPropertyName(propertyName.get(), structureEnumerator.get(), i.get());
+
+ generator.emitLabel(loopStart.get());
+ generator.emitLoopHint();
+
+ RefPtr<RegisterID> result = generator.emitUnaryOp(op_eq_null, generator.newTemporary(), propertyName.get());
+ generator.emitJumpIfTrue(result.get(), loopEnd.get());
+ generator.emitHasStructureProperty(result.get(), base.get(), propertyName.get(), structureEnumerator.get());
+ generator.emitJumpIfFalse(result.get(), scope->continueTarget());
+
+ this->emitLoopHeader(generator, propertyName.get());
+
+ generator.pushStructureForInScope(local.get(), i.get(), propertyName.get(), structureEnumerator.get());
+ generator.emitNode(dst, m_statement);
+ generator.popStructureForInScope(local.get());
+
+ generator.emitLabel(scope->continueTarget());
+ generator.emitInc(i.get());
+ generator.emitNextEnumeratorPropertyName(propertyName.get(), structureEnumerator.get(), i.get());
+ generator.emitJump(loopStart.get());
+
+ generator.emitLabel(scope->breakTarget());
+ generator.emitJump(end.get());
+ generator.emitLabel(loopEnd.get());
+ }
+
+ // Generic property loop.
+ {
+ LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop);
+ RefPtr<Label> loopStart = generator.newLabel();
+ RefPtr<Label> loopEnd = generator.newLabel();
+
+ RefPtr<RegisterID> genericEnumerator = generator.emitGetGenericPropertyEnumerator(generator.newTemporary(), base.get(), length.get(), structureEnumerator.get());
+ RefPtr<RegisterID> i = generator.emitLoad(generator.newTemporary(), jsNumber(0));
+ RefPtr<RegisterID> propertyName = generator.newTemporary();
+
+ generator.emitNextEnumeratorPropertyName(propertyName.get(), genericEnumerator.get(), i.get());
+ RefPtr<RegisterID> result = generator.emitUnaryOp(op_eq_null, generator.newTemporary(), propertyName.get());
+ generator.emitJumpIfTrue(result.get(), loopEnd.get());
+
+ generator.emitLabel(loopStart.get());
+ generator.emitLoopHint();
+
+ this->emitLoopHeader(generator, propertyName.get());
+
+ generator.emitNode(dst, m_statement);
+
+ generator.emitLabel(scope->continueTarget());
+ generator.emitInc(i.get());
+ generator.emitNextEnumeratorPropertyName(propertyName.get(), genericEnumerator.get(), i.get());
+ generator.emitUnaryOp(op_eq_null, result.get(), propertyName.get());
+ generator.emitJumpIfTrue(result.get(), loopEnd.get());
+
+ generator.emitHasGenericProperty(result.get(), base.get(), propertyName.get());
+ generator.emitJumpIfTrue(result.get(), loopStart.get());
+ generator.emitJump(scope->continueTarget());
+
+ generator.emitLabel(scope->breakTarget());
+ generator.emitJump(end.get());
+ generator.emitLabel(loopEnd.get());
+ }
+
+ generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset());
+ generator.emitLabel(end.get());
+}
+
+void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+ this->emitMultiLoopBytecode(generator, dst);
}
// ------------------------------ ForOfNode ------------------------------------
diff --git a/Source/JavaScriptCore/debugger/DebuggerScope.h b/Source/JavaScriptCore/debugger/DebuggerScope.h
index f026644..35a6b7d 100644
--- a/Source/JavaScriptCore/debugger/DebuggerScope.h
+++ b/Source/JavaScriptCore/debugger/DebuggerScope.h
@@ -94,7 +94,7 @@
JSScope* jsScope() const { return m_scope.get(); }
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
WriteBarrier<JSScope> m_scope;
WriteBarrier<DebuggerScope> m_next;
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractHeap.h b/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
index 68380c0..a91e32f 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
@@ -53,6 +53,7 @@
macro(JSCell_typeInfoType) \
macro(JSObject_butterfly) \
macro(JSVariableObject_registers) \
+ macro(JSPropertyNameEnumerator_cachedPropertyNames) \
macro(NamedProperties) \
macro(IndexedInt32Properties) \
macro(IndexedDoubleProperties) \
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 0ae42fd..db89748 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -1795,13 +1795,65 @@
break;
}
- case In:
+ case In: {
// FIXME: We can determine when the property definitely exists based on abstract
// value information.
clobberWorld(node->origin.semantic, clobberLimit);
forNode(node).setType(SpecBoolean);
break;
+ }
+ case GetEnumerableLength: {
+ forNode(node).setType(SpecInt32);
+ break;
+ }
+ case HasGenericProperty: {
+ forNode(node).setType(SpecBoolean);
+ break;
+ }
+ case HasStructureProperty: {
+ forNode(node).setType(SpecBoolean);
+ break;
+ }
+ case HasIndexedProperty: {
+ ArrayMode mode = node->arrayMode();
+ switch (mode.type()) {
+ case Array::Int32:
+ case Array::Double:
+ case Array::Contiguous:
+ case Array::ArrayStorage: {
+ break;
+ }
+ default: {
+ clobberWorld(node->origin.semantic, clobberLimit);
+ break;
+ }
+ }
+ forNode(node).setType(SpecBoolean);
+ break;
+ }
+ case GetDirectPname: {
+ clobberWorld(node->origin.semantic, clobberLimit);
+ forNode(node).makeHeapTop();
+ break;
+ }
+ case GetStructurePropertyEnumerator: {
+ forNode(node).setType(SpecCell);
+ break;
+ }
+ case GetGenericPropertyEnumerator: {
+ forNode(node).setType(SpecCell);
+ break;
+ }
+ case GetEnumeratorPname: {
+ forNode(node).setType(SpecString | SpecOther);
+ break;
+ }
+ case ToIndexString: {
+ forNode(node).setType(SpecString);
+ break;
+ }
+
case GetGlobalVar:
forNode(node).makeHeapTop();
break;
@@ -1866,12 +1918,25 @@
case ProfileDidCall:
case Phantom:
case HardPhantom:
- case Check:
case CountExecution:
case CheckTierUpInLoop:
case CheckTierUpAtReturn:
break;
+ case Check: {
+ // Simplify out checks that don't actually do checking.
+ for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
+ Edge edge = node->children.child(i);
+ if (!edge)
+ break;
+ if (edge.isProved() || edge.willNotHaveCheck()) {
+ m_state.setFoundConstants(true);
+ break;
+ }
+ }
+ break;
+ }
+
case StoreBarrier: {
filter(node->child1(), SpecCell);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 13c03f8..110e206 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1107,10 +1107,8 @@
if (JSFunction* function = callLinkStatus.function())
addToGraph(CheckFunction, OpInfo(m_graph.freeze(function)), callTarget, thisArgument);
else {
- ASSERT(callLinkStatus.structure());
ASSERT(callLinkStatus.executable());
- addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(callLinkStatus.structure())), callTarget);
addToGraph(CheckExecutable, OpInfo(callLinkStatus.executable()), callTarget, thisArgument);
}
}
@@ -3208,6 +3206,82 @@
NEXT_OPCODE(op_in);
}
+ case op_get_enumerable_length: {
+ set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetEnumerableLength,
+ get(VirtualRegister(currentInstruction[2].u.operand))));
+ NEXT_OPCODE(op_get_enumerable_length);
+ }
+
+ case op_has_generic_property: {
+ set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(HasGenericProperty,
+ get(VirtualRegister(currentInstruction[2].u.operand)),
+ get(VirtualRegister(currentInstruction[3].u.operand))));
+ NEXT_OPCODE(op_has_generic_property);
+ }
+
+ case op_has_structure_property: {
+ set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(HasStructureProperty,
+ get(VirtualRegister(currentInstruction[2].u.operand)),
+ get(VirtualRegister(currentInstruction[3].u.operand)),
+ get(VirtualRegister(currentInstruction[4].u.operand))));
+ NEXT_OPCODE(op_has_structure_property);
+ }
+
+ case op_has_indexed_property: {
+ Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
+ ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Read);
+ Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
+ Node* hasIterableProperty = addToGraph(HasIndexedProperty, OpInfo(arrayMode.asWord()), base, property);
+ set(VirtualRegister(currentInstruction[1].u.operand), hasIterableProperty);
+ NEXT_OPCODE(op_has_indexed_property);
+ }
+
+ case op_get_direct_pname: {
+ SpeculatedType prediction = getPredictionWithoutOSRExit();
+
+ Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
+ Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
+ Node* index = get(VirtualRegister(currentInstruction[4].u.operand));
+ Node* enumerator = get(VirtualRegister(currentInstruction[5].u.operand));
+
+ addVarArgChild(base);
+ addVarArgChild(property);
+ addVarArgChild(index);
+ addVarArgChild(enumerator);
+ set(VirtualRegister(currentInstruction[1].u.operand),
+ addToGraph(Node::VarArg, GetDirectPname, OpInfo(0), OpInfo(prediction)));
+
+ NEXT_OPCODE(op_get_direct_pname);
+ }
+
+ case op_get_structure_property_enumerator: {
+ set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetStructurePropertyEnumerator,
+ get(VirtualRegister(currentInstruction[2].u.operand)),
+ get(VirtualRegister(currentInstruction[3].u.operand))));
+ NEXT_OPCODE(op_get_structure_property_enumerator);
+ }
+
+ case op_get_generic_property_enumerator: {
+ set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetGenericPropertyEnumerator,
+ get(VirtualRegister(currentInstruction[2].u.operand)),
+ get(VirtualRegister(currentInstruction[3].u.operand)),
+ get(VirtualRegister(currentInstruction[4].u.operand))));
+ NEXT_OPCODE(op_get_generic_property_enumerator);
+ }
+
+ case op_next_enumerator_pname: {
+ set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetEnumeratorPname,
+ get(VirtualRegister(currentInstruction[2].u.operand)),
+ get(VirtualRegister(currentInstruction[3].u.operand))));
+ NEXT_OPCODE(op_next_enumerator_pname);
+ }
+
+ case op_to_index_string: {
+ set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(ToIndexString,
+ get(VirtualRegister(currentInstruction[2].u.operand))));
+ NEXT_OPCODE(op_to_index_string);
+ }
+
default:
// Parse failed! This should not happen because the capabilities checker
// should have caught it.
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index 4c8859b..e775fead 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -193,6 +193,15 @@
case op_switch_char:
case op_in:
case op_get_from_scope:
+ case op_get_enumerable_length:
+ case op_has_generic_property:
+ case op_has_structure_property:
+ case op_has_indexed_property:
+ case op_get_direct_pname:
+ case op_get_structure_property_enumerator:
+ case op_get_generic_property_enumerator:
+ case op_next_enumerator_pname:
+ case op_to_index_string:
return CanCompileAndInline;
case op_put_to_scope: {
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index 51777bb..682301e 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -147,6 +147,87 @@
def(PureValue(node));
return;
+ case HasGenericProperty:
+ case HasStructureProperty:
+ case GetEnumerableLength:
+ case GetStructurePropertyEnumerator:
+ case GetGenericPropertyEnumerator: {
+ read(World);
+ write(SideState);
+ return;
+ }
+
+ case GetDirectPname: {
+ // This reads and writes world because it can end up calling a generic getByVal
+ // if the Structure changed, which could in turn end up calling a getter.
+ read(World);
+ write(World);
+ return;
+ }
+
+ case ToIndexString:
+ case GetEnumeratorPname: {
+ def(PureValue(node));
+ return;
+ }
+
+ case HasIndexedProperty: {
+ read(JSObject_butterfly);
+ ArrayMode mode = node->arrayMode();
+ switch (mode.type()) {
+ case Array::Int32: {
+ if (mode.isInBounds()) {
+ read(Butterfly_publicLength);
+ read(IndexedInt32Properties);
+ def(HeapLocation(HasIndexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), node);
+ return;
+ }
+ read(World);
+ return;
+ }
+
+ case Array::Double: {
+ if (mode.isInBounds()) {
+ read(Butterfly_publicLength);
+ read(IndexedDoubleProperties);
+ def(HeapLocation(HasIndexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), node);
+ return;
+ }
+ read(World);
+ return;
+ }
+
+ case Array::Contiguous: {
+ if (mode.isInBounds()) {
+ read(Butterfly_publicLength);
+ read(IndexedContiguousProperties);
+ def(HeapLocation(HasIndexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), node);
+ return;
+ }
+ read(World);
+ return;
+ }
+
+ case Array::ArrayStorage: {
+ if (mode.isInBounds()) {
+ read(Butterfly_vectorLength);
+ read(IndexedArrayStorageProperties);
+ return;
+ }
+ read(World);
+ return;
+ }
+
+ default: {
+ read(World);
+ write(World);
+ return;
+ }
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return;
+ }
+
case ArithAdd:
case ArithSub:
case ArithNegate:
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index f018e18..ea9a7a3 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -86,6 +86,7 @@
Node* node = block->at(indexInBlock);
+ bool alreadyHandled = false;
bool eliminated = false;
switch (node->op()) {
@@ -173,7 +174,7 @@
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.
+ alreadyHandled = 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];
@@ -181,6 +182,7 @@
if (variant.structureSet().isEmpty()) {
data.variants[i--] = data.variants.last();
data.variants.removeLast();
+ changed = true;
}
}
@@ -189,6 +191,7 @@
emitGetByOffset(
indexInBlock, node, baseValue, data.variants[0], data.identifierNumber);
+ changed = true;
break;
}
@@ -200,7 +203,7 @@
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.
+ alreadyHandled = true; // Don't allow the default constant folder to do things to this.
for (unsigned i = 0; i < data.variants.size(); ++i) {
@@ -210,6 +213,7 @@
if (variant.oldStructure().isEmpty()) {
data.variants[i--] = data.variants.last();
data.variants.removeLast();
+ changed = true;
continue;
}
@@ -218,6 +222,7 @@
variant = PutByIdVariant::replace(
variant.oldStructure(),
variant.offset());
+ changed = true;
}
}
@@ -226,6 +231,7 @@
emitPutByOffset(
indexInBlock, node, baseValue, data.variants[0], data.identifierNumber);
+ changed = true;
break;
}
@@ -238,7 +244,7 @@
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.
+ alreadyHandled = 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)))
@@ -260,6 +266,7 @@
if (status.numVariants() == 1) {
emitGetByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
+ changed = true;
break;
}
@@ -270,6 +277,7 @@
data->variants = status.variants();
data->identifierNumber = identifierNumber;
node->convertToMultiGetByOffset(data);
+ changed = true;
break;
}
@@ -286,7 +294,7 @@
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.
+ alreadyHandled = true; // Don't allow the default constant folder to do things to this.
if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered())
break;
@@ -301,6 +309,13 @@
if (!status.isSimple())
break;
+ ASSERT(status.numVariants());
+
+ if (status.numVariants() > 1 && !isFTL(m_graph.m_plan.mode))
+ break;
+
+ changed = true;
+
for (unsigned i = status.numVariants(); i--;)
addChecks(origin, indexInBlock, status[i].constantChecks());
@@ -309,8 +324,7 @@
break;
}
- if (!isFTL(m_graph.m_plan.mode))
- break;
+ ASSERT(isFTL(m_graph.m_plan.mode));
MultiPutByOffsetData* data = m_graph.m_multiPutByOffsetData.add();
data->variants = status.variants();
@@ -324,6 +338,7 @@
break;
node->convertToIdentity();
+ changed = true;
break;
}
@@ -354,16 +369,34 @@
break;
}
+
+ case Check: {
+ alreadyHandled = true;
+ m_interpreter.execute(indexInBlock);
+ for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
+ Edge edge = node->children.child(i);
+ if (!edge)
+ break;
+ if (edge.isProved() || edge.willNotHaveCheck()) {
+ node->children.removeEdge(i--);
+ changed = true;
+ }
+ }
+ break;
+ }
default:
break;
}
-
+
if (eliminated) {
changed = true;
continue;
}
+ if (alreadyHandled)
+ continue;
+
m_interpreter.execute(indexInBlock);
if (!m_state.isValid()) {
// If we invalidated then we shouldn't attempt to constant-fold. Here's an
diff --git a/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp b/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp
index fd4740d..a69eb00 100644
--- a/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp
@@ -49,12 +49,22 @@
ASSERT(m_graph.m_form == ThreadedCPS || m_graph.m_form == SSA);
// First reset the counts to 0 for all nodes.
+ //
+ // Also take this opportunity to pretend that Check nodes are not NodeMustGenerate. Check
+ // nodes are MustGenerate because they are executed for effect, but they follow the same
+ // DCE rules as nodes that aren't MustGenerate: they only contribute to the ref count of
+ // their children if the edges require checks. Non-checking edges are removed. Note that
+ // for any Checks left over, this phase will turn them back into NodeMustGenerate.
for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
BasicBlock* block = m_graph.block(blockIndex);
if (!block)
continue;
- for (unsigned indexInBlock = block->size(); indexInBlock--;)
- block->at(indexInBlock)->setRefCount(0);
+ for (unsigned indexInBlock = block->size(); indexInBlock--;) {
+ Node* node = block->at(indexInBlock);
+ if (node->op() == Check)
+ node->clearFlags(NodeMustGenerate);
+ node->setRefCount(0);
+ }
for (unsigned phiIndex = block->phis.size(); phiIndex--;)
block->phis[phiIndex]->setRefCount(0);
}
@@ -119,6 +129,30 @@
cleanVariables(m_graph.m_arguments);
}
+ // Just do a basic HardPhantom/Phantom/Check clean-up.
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ unsigned sourceIndex = 0;
+ unsigned targetIndex = 0;
+ while (sourceIndex < block->size()) {
+ Node* node = block->at(sourceIndex++);
+ switch (node->op()) {
+ case Check:
+ case HardPhantom:
+ case Phantom:
+ if (node->children.isEmpty())
+ continue;
+ break;
+ default:
+ break;
+ }
+ block->at(targetIndex++) = node;
+ }
+ block->resize(targetIndex);
+ }
+
m_graph.m_refCountState = ExactRefCount;
return true;
@@ -129,7 +163,7 @@
{
// We may have an "unproved" untyped use for code that is unreachable. The CFA
// will just not have gotten around to it.
- if (edge.willNotHaveCheck())
+ if (edge.isProved() || edge.willNotHaveCheck())
return;
if (!edge->postfixRef())
m_worklist.append(edge.node());
@@ -145,7 +179,7 @@
void countEdge(Node*, Edge edge)
{
// Don't count edges that are already counted for their type checks.
- if (edge.willHaveCheck())
+ if (!(edge.isProved() || edge.willNotHaveCheck()))
return;
countNode(edge.node());
}
@@ -214,10 +248,10 @@
for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) {
Edge edge = m_graph.m_varArgChildren[childIdx];
- if (!edge || edge.willNotHaveCheck())
+ if (!edge || edge.isProved() || edge.willNotHaveCheck())
continue;
- m_insertionSet.insertNode(indexInBlock, SpecNone, Phantom, node->origin, edge);
+ m_insertionSet.insertNode(indexInBlock, SpecNone, Check, node->origin, edge);
}
node->convertToPhantom();
@@ -226,8 +260,14 @@
break;
}
- node->convertToPhantom();
- eliminateIrrelevantPhantomChildren(node);
+ node->convertToCheck();
+ for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
+ Edge edge = node->children.child(i);
+ if (!edge)
+ continue;
+ if (edge.isProved() || edge.willNotHaveCheck())
+ node->children.removeEdge(i--);
+ }
node->setRefCount(1);
break;
} }
@@ -236,17 +276,6 @@
m_insertionSet.execute(block);
}
- void eliminateIrrelevantPhantomChildren(Node* node)
- {
- for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
- Edge edge = node->children.child(i);
- if (!edge)
- continue;
- if (edge.willNotHaveCheck())
- node->children.removeEdge(i--);
- }
- }
-
template<typename VariablesVectorType>
void cleanVariables(VariablesVectorType& variables)
{
@@ -254,7 +283,7 @@
Node* node = variables[i];
if (!node)
continue;
- if (node->op() != Phantom && node->shouldGenerate())
+ if (node->op() != Phantom && node->op() != Check && node->shouldGenerate())
continue;
if (node->op() == GetLocal) {
node = node->child1().node();
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index c5ee7c0..006be82 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -189,6 +189,11 @@
case GetByOffset:
case GetGetterSetterByOffset:
case PutByOffset:
+ case GetEnumerableLength:
+ case HasGenericProperty:
+ case HasStructureProperty:
+ case HasIndexedProperty:
+ case GetDirectPname:
case FiatInt52:
case BooleanToNumber:
return false;
@@ -213,6 +218,10 @@
case NewFunctionExpression:
case NewTypedArray:
case ThrowReferenceError:
+ case GetStructurePropertyEnumerator:
+ case GetGenericPropertyEnumerator:
+ case GetEnumeratorPname:
+ case ToIndexString:
return true;
case MultiPutByOffset:
diff --git a/Source/JavaScriptCore/dfg/DFGEdge.cpp b/Source/JavaScriptCore/dfg/DFGEdge.cpp
index bf05f35..154401e 100644
--- a/Source/JavaScriptCore/dfg/DFGEdge.cpp
+++ b/Source/JavaScriptCore/dfg/DFGEdge.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -36,7 +36,7 @@
void Edge::dump(PrintStream& out) const
{
if (useKindUnchecked() != UntypedUse) {
- if (needsCheck())
+ if (!isProved())
out.print("Check:");
out.print(useKind(), ":");
}
diff --git a/Source/JavaScriptCore/dfg/DFGEdge.h b/Source/JavaScriptCore/dfg/DFGEdge.h
index 4ceda0cb..73bca9c 100644
--- a/Source/JavaScriptCore/dfg/DFGEdge.h
+++ b/Source/JavaScriptCore/dfg/DFGEdge.h
@@ -115,10 +115,6 @@
{
return proofStatus() == IsProved;
}
- bool needsCheck() const
- {
- return proofStatus() == NeedsCheck;
- }
bool willNotHaveCheck() const
{
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 57a6559..b5ae361 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -898,7 +898,11 @@
break;
}
- case CheckExecutable:
+ case CheckExecutable: {
+ fixEdge<FunctionUse>(node->child1());
+ break;
+ }
+
case CheckStructure:
case CheckFunction:
case CheckHasInstance:
@@ -1040,6 +1044,64 @@
observeUseKindOnNode<StringUse>(node);
}
break;
+
+ case GetEnumerableLength: {
+ fixEdge<CellUse>(node->child1());
+ break;
+ }
+ case HasGenericProperty: {
+ fixEdge<StringUse>(node->child2());
+ break;
+ }
+ case HasStructureProperty: {
+ fixEdge<StringUse>(node->child2());
+ fixEdge<KnownCellUse>(node->child3());
+ break;
+ }
+ case HasIndexedProperty: {
+ node->setArrayMode(
+ node->arrayMode().refine(
+ m_graph, node,
+ node->child1()->prediction(),
+ node->child2()->prediction(),
+ SpecNone, node->flags()));
+
+ blessArrayOperation(node->child1(), node->child2(), node->child3());
+ fixEdge<CellUse>(node->child1());
+ fixEdge<KnownInt32Use>(node->child2());
+ break;
+ }
+ case GetDirectPname: {
+ Edge& base = m_graph.varArgChild(node, 0);
+ Edge& property = m_graph.varArgChild(node, 1);
+ Edge& index = m_graph.varArgChild(node, 2);
+ Edge& enumerator = m_graph.varArgChild(node, 3);
+ fixEdge<CellUse>(base);
+ fixEdge<KnownCellUse>(property);
+ fixEdge<KnownInt32Use>(index);
+ fixEdge<KnownCellUse>(enumerator);
+ break;
+ }
+ case GetStructurePropertyEnumerator: {
+ fixEdge<CellUse>(node->child1());
+ fixEdge<KnownInt32Use>(node->child2());
+ break;
+ }
+ case GetGenericPropertyEnumerator: {
+ fixEdge<CellUse>(node->child1());
+ fixEdge<KnownInt32Use>(node->child2());
+ fixEdge<KnownCellUse>(node->child3());
+ break;
+ }
+ case GetEnumeratorPname: {
+ fixEdge<KnownCellUse>(node->child1());
+ fixEdge<KnownInt32Use>(node->child2());
+ break;
+ }
+ case ToIndexString: {
+ fixEdge<KnownInt32Use>(node->child1());
+ break;
+ }
#if !ASSERT_DISABLED
// Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
@@ -1543,6 +1605,7 @@
case CellUse:
case KnownCellUse:
case ObjectUse:
+ case FunctionUse:
case StringUse:
case KnownStringUse:
case StringObjectUse:
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 6d0a864..23c6280 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -157,7 +157,6 @@
NodeType op = node->op();
unsigned refCount = node->refCount();
- bool skipped = !refCount;
bool mustGenerate = node->mustGenerate();
if (mustGenerate)
--refCount;
@@ -181,8 +180,8 @@
// arg# - an argument number.
// id# - the index in the CodeBlock of an identifier { if codeBlock is passed to dump(), the string representation is displayed }.
// var# - the index of a var on the global object, used by GetGlobalVar/PutGlobalVar operations.
- out.printf("% 4d:%s<%c%u:", (int)node->index(), skipped ? " skipped " : " ", mustGenerate ? '!' : ' ', refCount);
- if (node->hasResult() && !skipped && node->hasVirtualRegister())
+ out.printf("% 4d:<%c%u:", (int)node->index(), mustGenerate ? '!' : ' ', refCount);
+ if (node->hasResult() && node->hasVirtualRegister() && node->virtualRegister().isValid())
out.print(node->virtualRegister());
else
out.print("-");
@@ -352,12 +351,10 @@
out.print(")");
- if (!skipped) {
- if (node->hasVariableAccessData(*this) && node->tryGetVariableAccessData())
- out.print(" predicting ", SpeculationDump(node->tryGetVariableAccessData()->prediction()));
- else if (node->hasHeapPrediction())
- out.print(" predicting ", SpeculationDump(node->getHeapPrediction()));
- }
+ if (node->hasVariableAccessData(*this) && node->tryGetVariableAccessData())
+ out.print(" predicting ", SpeculationDump(node->tryGetVariableAccessData()->prediction()));
+ else if (node->hasHeapPrediction())
+ out.print(" predicting ", SpeculationDump(node->getHeapPrediction()));
out.print("\n");
}
diff --git a/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp b/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
index b89d463..60f1aa7 100644
--- a/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
+++ b/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
@@ -108,6 +108,10 @@
out.print("GlobalVariableLoc");
return;
+ case HasIndexedPropertyLoc:
+ out.print("HasIndexedPorpertyLoc");
+ return;
+
case IndexedPropertyLoc:
out.print("IndexedPorpertyLoc");
return;
diff --git a/Source/JavaScriptCore/dfg/DFGHeapLocation.h b/Source/JavaScriptCore/dfg/DFGHeapLocation.h
index 3b08d76..cef0ab2 100644
--- a/Source/JavaScriptCore/dfg/DFGHeapLocation.h
+++ b/Source/JavaScriptCore/dfg/DFGHeapLocation.h
@@ -44,6 +44,7 @@
ClosureVariableLoc,
GetterLoc,
GlobalVariableLoc,
+ HasIndexedPropertyLoc,
IndexedPropertyLoc,
IndexedPropertyStorageLoc,
InstanceOfLoc,
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 5e0b0af..1423394 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -1001,6 +1001,7 @@
bool hasHeapPrediction()
{
switch (op()) {
+ case GetDirectPname:
case GetById:
case GetByIdFlush:
case GetByVal:
@@ -1267,6 +1268,7 @@
case ArrayifyToStructure:
case ArrayPush:
case ArrayPop:
+ case HasIndexedProperty:
return true;
default:
return false;
diff --git a/Source/JavaScriptCore/dfg/DFGNodeFlags.h b/Source/JavaScriptCore/dfg/DFGNodeFlags.h
index 30abaff..81849cf 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeFlags.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeFlags.h
@@ -70,6 +70,9 @@
#define NodeIsFlushed 0x20000 // Used by Graph::computeIsFlushed(), will tell you which local nodes are backwards-reachable from a Flush.
+#define NodeMiscFlag1 0x40000
+#define NodeMiscFlag2 0x80000
+
typedef uint32_t NodeFlags;
static inline bool bytecodeUsesAsNumber(NodeFlags flags)
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 2345f51..3591c19 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -61,7 +61,7 @@
macro(GetArgument, NodeResultJS | NodeMustGenerate) \
macro(Phantom, NodeMustGenerate) \
macro(HardPhantom, NodeMustGenerate) /* Like Phantom, but we never remove any of its children. */ \
- macro(Check, 0) /* Used if we want just a type check but not liveness. DCE eithers kills this or converts it to Phantom. */\
+ macro(Check, NodeMustGenerate) /* Used if we want just a type check but not liveness. Non-checking uses will be removed. */\
macro(Upsilon, NodeRelevantToOSR) \
macro(Phi, NodeRelevantToOSR) \
macro(Flush, NodeMustGenerate) \
@@ -293,6 +293,17 @@
/* Write barriers ! */\
macro(StoreBarrier, NodeMustGenerate) \
macro(StoreBarrierWithNullCheck, NodeMustGenerate) \
+ \
+ /* For-in enumeration opcodes */\
+ macro(GetEnumerableLength, NodeMustGenerate | NodeResultJS) \
+ macro(HasIndexedProperty, NodeResultBoolean) \
+ macro(HasStructureProperty, NodeResultBoolean) \
+ macro(HasGenericProperty, NodeResultBoolean) \
+ macro(GetDirectPname, NodeMustGenerate | NodeHasVarArgs | NodeResultJS) \
+ macro(GetStructurePropertyEnumerator, NodeMustGenerate | NodeResultJS) \
+ macro(GetGenericPropertyEnumerator, NodeMustGenerate | NodeResultJS) \
+ macro(GetEnumeratorPname, NodeMustGenerate | NodeResultJS) \
+ macro(ToIndexString, NodeResultJS)
// This enum generates a monotonically increasing id for all Node types,
// and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask).
diff --git a/Source/JavaScriptCore/dfg/DFGPhantomCanonicalizationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPhantomCanonicalizationPhase.cpp
new file mode 100644
index 0000000..5850582
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGPhantomCanonicalizationPhase.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 "DFGPhantomCanonicalizationPhase.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGGraph.h"
+#include "DFGInsertionSet.h"
+#include "DFGPhase.h"
+#include "DFGPredictionPropagationPhase.h"
+#include "DFGVariableAccessDataDump.h"
+#include "JSCInlines.h"
+
+namespace JSC { namespace DFG {
+
+static const NodeFlags NodeNeedsPhantom = NodeMiscFlag1;
+static const NodeFlags NodeNeedsHardPhantom = NodeMiscFlag2;
+
+class PhantomCanonicalizationPhase : public Phase {
+public:
+ PhantomCanonicalizationPhase(Graph& graph)
+ : Phase(graph, "phantom canonicalization")
+ {
+ }
+
+ bool run()
+ {
+ ASSERT(m_graph.m_form == SSA);
+
+ m_graph.clearFlagsOnAllNodes(NodeNeedsPhantom | NodeNeedsHardPhantom | NodeRelevantToOSR);
+
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+
+ for (unsigned i = block->size(); i--;) {
+ Node* node = block->at(i);
+ if (node->op() == MovHint)
+ node->child1()->mergeFlags(NodeRelevantToOSR);
+ }
+ }
+
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+
+ unsigned sourceIndex = 0;
+ unsigned targetIndex = 0;
+ while (sourceIndex < block->size()) {
+ Node* node = block->at(sourceIndex++);
+ if (node->op() == HardPhantom || node->op() == Phantom || node->op() == Check) {
+ for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
+ Edge edge = node->children.child(i);
+ if (!edge)
+ break;
+ if (node->op() == HardPhantom)
+ edge->mergeFlags(NodeNeedsHardPhantom);
+ if ((edge->flags() & NodeRelevantToOSR) && node->op() == Phantom) {
+ // A Phantom on a node that is RelevantToOSR means that we need to keep
+ // a Phantom on this node instead of just having a Check.
+ edge->mergeFlags(NodeNeedsPhantom);
+ }
+ if (edge.willHaveCheck())
+ continue; // Keep the type check.
+
+ node->children.removeEdge(i--);
+ }
+
+ if (node->children.isEmpty())
+ continue;
+
+ node->convertToCheck();
+ }
+ block->at(targetIndex++) = node;
+ }
+ block->resize(targetIndex);
+ }
+
+ InsertionSet insertionSet(m_graph);
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+
+ for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
+ Node* node = block->at(nodeIndex);
+ if (node->flags() & NodeNeedsHardPhantom) {
+ insertionSet.insertNode(
+ nodeIndex + 1, SpecNone, HardPhantom, node->origin, node->defaultEdge());
+ } else if (node->flags() & NodeNeedsPhantom) {
+ insertionSet.insertNode(
+ nodeIndex + 1, SpecNone, Phantom, node->origin, node->defaultEdge());
+ }
+ }
+ insertionSet.execute(block);
+ }
+
+ return true;
+ }
+};
+
+bool performPhantomCanonicalization(Graph& graph)
+{
+ SamplingRegion samplingRegion("DFG Phantom Canonicalization Phase");
+ return runPhase<PhantomCanonicalizationPhase>(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGPhantomCanonicalizationPhase.h b/Source/JavaScriptCore/dfg/DFGPhantomCanonicalizationPhase.h
new file mode 100644
index 0000000..306b3bd
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGPhantomCanonicalizationPhase.h
@@ -0,0 +1,51 @@
+/*
+ * 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 DFGPhantomCanonicalizationPhase_h
+#define DFGPhantomCanonicalizationPhase_h
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+class Graph;
+
+// Replaces all pre-existing Phantoms with Checks or removes them if the Check is unnecessary. If
+// the Phantom was necessary (it uses a node that is relevant to OSR) then the Phantom is hoisted
+// to just below the node.
+//
+// This phase is only valid in SSA, because it's only in SSA that Phantoms are ignored for the
+// purpose of liveness-at-some-point and are only used for absolute liveness.
+//
+// This phase makes a lot of things easier, like CFG simplification: you don't have to insert any
+// phantoms when jettisoning a CFG edge.
+
+bool performPhantomCanonicalization(Graph&);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGPhantomCanonicalizationPhase_h
diff --git a/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp b/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp
index e3cac84..73d62e8 100644
--- a/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp
@@ -96,14 +96,15 @@
Node* lastNode = nullptr;
while (sourceIndex < block->size()) {
Node* node = block->at(sourceIndex++);
- if (node->op() == Phantom) {
+ switch (node->op()) {
+ case Phantom: {
if (lastNode && (lastNode->origin.forExit != node->origin.forExit || (lastNode->flags() & NodeHasVarArgs)))
lastNode = nullptr;
for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
Edge edge = node->children.child(i);
if (!edge)
break;
- if (edge.useKind() != UntypedUse)
+ if (edge.willHaveCheck())
continue; // Keep the type check.
if (edge->flags() & NodeRelevantToOSR) {
bool found = false;
@@ -123,8 +124,38 @@
changed = true;
}
+ if (node->children.isEmpty()) {
+ changed = true;
+ continue;
+ }
+ break;
+ }
+
+ case Check: {
+ for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
+ Edge edge = node->children.child(i);
+ if (!edge)
+ break;
+ if (edge.willHaveCheck())
+ continue;
+ node->children.removeEdge(i--);
+ changed = true;
+ }
+ if (node->children.isEmpty()) {
+ changed = true;
+ continue;
+ }
+ break;
+ }
+
+ case HardPhantom: {
if (node->children.isEmpty())
continue;
+ break;
+ }
+
+ default:
+ break;
}
lastNode = node;
block->at(targetIndex++) = node;
diff --git a/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.h b/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.h
index f0dd98c..c02afd2 100644
--- a/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.h
+++ b/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.h
@@ -34,6 +34,9 @@
// Cleans up unnecessary Phantoms and Phanton children. This reduces live ranges, but also, it
// eliminates many Phantoms entirely. This invalidates liveness analysis.
+//
+// This should work over all IR forms; however, in SSA form it's better to run
+// PhantomCanonicalizationPhase since it's more powerful.
bool performPhantomRemoval(Graph&);
diff --git a/Source/JavaScriptCore/dfg/DFGPlan.cpp b/Source/JavaScriptCore/dfg/DFGPlan.cpp
index d72945c..3feefbd 100644
--- a/Source/JavaScriptCore/dfg/DFGPlan.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPlan.cpp
@@ -49,6 +49,7 @@
#include "DFGLoopPreHeaderCreationPhase.h"
#include "DFGOSRAvailabilityAnalysisPhase.h"
#include "DFGOSREntrypointCreationPhase.h"
+#include "DFGPhantomCanonicalizationPhase.h"
#include "DFGPhantomRemovalPhase.h"
#include "DFGPredictionInjectionPhase.h"
#include "DFGPredictionPropagationPhase.h"
@@ -311,7 +312,7 @@
return FailPath;
}
- performPhantomRemoval(dfg);
+ performPhantomRemoval(dfg); // Reduce the graph size a bit.
performCriticalEdgeBreaking(dfg);
performLoopPreHeaderCreation(dfg);
performCPSRethreading(dfg);
@@ -321,6 +322,7 @@
performLivenessAnalysis(dfg);
performCFA(dfg);
performConstantFolding(dfg);
+ performPhantomCanonicalization(dfg); // Reduce the graph size a lot.
if (performStrengthReduction(dfg)) {
// State-at-tail and state-at-head will be invalid if we did strength reduction since
// it might increase live ranges.
@@ -328,7 +330,7 @@
performCFA(dfg);
}
performLICM(dfg);
- performPhantomRemoval(dfg);
+ performPhantomCanonicalization(dfg);
performIntegerCheckCombining(dfg);
performGlobalCSE(dfg);
@@ -337,7 +339,7 @@
dfg.m_fixpointState = FixpointConverged;
performStoreBarrierElision(dfg);
- performPhantomRemoval(dfg);
+ performPhantomCanonicalization(dfg);
performLivenessAnalysis(dfg);
performCFA(dfg);
if (Options::validateFTLOSRExitLiveness())
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 893e9b2..5fa8a92 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -185,6 +185,7 @@
case GetMyArgumentByValSafe:
case GetByOffset:
case MultiGetByOffset:
+ case GetDirectPname:
case Call:
case Construct:
case NativeCall:
@@ -584,6 +585,39 @@
changed |= setPrediction(SpecBoolean);
break;
+ case GetEnumerableLength: {
+ changed |= setPrediction(SpecInt32);
+ break;
+ }
+ case HasGenericProperty: {
+ changed |= setPrediction(SpecBoolean);
+ break;
+ }
+ case HasStructureProperty: {
+ changed |= setPrediction(SpecBoolean);
+ break;
+ }
+ case HasIndexedProperty: {
+ changed |= setPrediction(SpecBoolean);
+ break;
+ }
+ case GetStructurePropertyEnumerator: {
+ changed |= setPrediction(SpecCell);
+ break;
+ }
+ case GetGenericPropertyEnumerator: {
+ changed |= setPrediction(SpecCell);
+ break;
+ }
+ case GetEnumeratorPname: {
+ changed |= setPrediction(SpecCell | SpecOther);
+ break;
+ }
+ case ToIndexString: {
+ changed |= setPrediction(SpecString);
+ break;
+ }
+
#ifndef NDEBUG
// These get ignored because they don't return anything.
case StoreBarrier:
diff --git a/Source/JavaScriptCore/dfg/DFGSSALoweringPhase.cpp b/Source/JavaScriptCore/dfg/DFGSSALoweringPhase.cpp
index 993ec1b..c4b67a3 100644
--- a/Source/JavaScriptCore/dfg/DFGSSALoweringPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSSALoweringPhase.cpp
@@ -69,6 +69,7 @@
{
switch (m_node->op()) {
case GetByVal:
+ case HasIndexedProperty:
lowerBoundsCheck(m_node->child1(), m_node->child2(), m_node->child3());
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 370543f..3f782dd 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -53,6 +53,7 @@
case BooleanUse:
case CellUse:
case ObjectUse:
+ case FunctionUse:
case FinalObjectUse:
case ObjectOrOtherUse:
case StringIdentUse:
@@ -258,6 +259,15 @@
case FiatInt52:
case GetGetter:
case GetSetter:
+ case GetEnumerableLength:
+ case HasGenericProperty:
+ case HasStructureProperty:
+ case HasIndexedProperty:
+ case GetDirectPname:
+ case GetStructurePropertyEnumerator:
+ case GetGenericPropertyEnumerator:
+ case GetEnumeratorPname:
+ case ToIndexString:
return true;
case NativeCall:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 63b8fbd..01b313b 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -712,20 +712,14 @@
return;
}
case Array::Arguments:
- speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node,
- m_jit.branch8(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(baseReg, JSCell::typeInfoTypeOffset()),
- MacroAssembler::TrustedImm32(ArgumentsType)));
+ speculateCellTypeWithoutTypeFiltering(node->child1(), baseReg, ArgumentsType);
noResult(m_currentNode);
return;
default:
- speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node,
- m_jit.branch8(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(baseReg, JSCell::typeInfoTypeOffset()),
- MacroAssembler::TrustedImm32(typeForTypedArrayType(node->arrayMode().typedArrayType()))));
+ speculateCellTypeWithoutTypeFiltering(
+ node->child1(), baseReg,
+ typeForTypedArrayType(node->arrayMode().typedArrayType()));
noResult(m_currentNode);
return;
}
@@ -4508,6 +4502,28 @@
cellResult(resultGPR, node);
}
+void SpeculativeJIT::speculateCellTypeWithoutTypeFiltering(
+ Edge edge, GPRReg cellGPR, JSType jsType)
+{
+ speculationCheck(
+ BadType, JSValueSource::unboxedCell(cellGPR), edge,
+ m_jit.branch8(
+ MacroAssembler::NotEqual,
+ MacroAssembler::Address(cellGPR, JSCell::typeInfoTypeOffset()),
+ MacroAssembler::TrustedImm32(jsType)));
+}
+
+void SpeculativeJIT::speculateCellType(
+ Edge edge, GPRReg cellGPR, SpeculatedType specType, JSType jsType)
+{
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(cellGPR), edge, specType,
+ m_jit.branch8(
+ MacroAssembler::NotEqual,
+ MacroAssembler::Address(cellGPR, JSCell::typeInfoTypeOffset()),
+ TrustedImm32(jsType)));
+}
+
void SpeculativeJIT::speculateInt32(Edge edge)
{
if (!needsTypeCheck(edge, SpecInt32))
@@ -4581,18 +4597,22 @@
m_jit.vm()->stringStructure.get()));
}
+void SpeculativeJIT::speculateFunction(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecFunction))
+ return;
+
+ SpeculateCellOperand operand(this, edge);
+ speculateCellType(edge, operand.gpr(), SpecFunction, JSFunctionType);
+}
+
void SpeculativeJIT::speculateFinalObject(Edge edge)
{
if (!needsTypeCheck(edge, SpecFinalObject))
return;
SpeculateCellOperand operand(this, edge);
- GPRReg gpr = operand.gpr();
- DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(gpr), edge, SpecFinalObject, m_jit.branch8(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(gpr, JSCell::typeInfoTypeOffset()),
- TrustedImm32(FinalObjectType)));
+ speculateCellType(edge, operand.gpr(), SpecFinalObject, FinalObjectType);
}
void SpeculativeJIT::speculateObjectOrOther(Edge edge)
@@ -4836,6 +4856,9 @@
case ObjectUse:
speculateObject(edge);
break;
+ case FunctionUse:
+ speculateFunction(edge);
+ break;
case FinalObjectUse:
speculateFinalObject(edge);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 8f33cb2..b828f18 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1034,6 +1034,16 @@
m_jit.setupArgumentsWithExecState(TrustedImmPtr(cell));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_JITOperation_ECZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(C_JITOperation_ECZC operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(C_JITOperation_ECC operation, GPRReg result, GPRReg arg1, JSCell* cell)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell));
@@ -1132,6 +1142,11 @@
m_jit.setupArgumentsExecState();
return appendCallWithCallFrameRollbackOnExceptionSetResult(operation, result);
}
+ JITCompiler::Call callOperation(Z_JITOperation_EC operation, GPRReg result, GPRReg arg1)
+ {
+ m_jit.setupArgumentsWithExecState(arg1);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
template<typename FunctionType, typename ArgumentType1>
JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1)
@@ -1258,6 +1273,11 @@
m_jit.setupArgumentsWithExecState(TrustedImmPtr(cell));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(J_JITOperation_ECZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_JITOperation_ESsiCI operation, GPRReg result, StructureStubInfo* stubInfo, GPRReg arg1, const StringImpl* uid)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1, TrustedImmPtr(uid));
@@ -1273,6 +1293,16 @@
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(J_JITOperation_EJC operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(J_JITOperation_EJZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_JITOperation_EJA operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1, arg2);
@@ -1321,6 +1351,21 @@
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(C_JITOperation_EJJC operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(C_JITOperation_EJZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(C_JITOperation_EJZC operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(S_JITOperation_J operation, GPRReg result, GPRReg arg1)
{
m_jit.setupArguments(arg1);
@@ -1494,6 +1539,16 @@
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(J_JITOperation_EJ operation, GPRReg resultPayload, GPRReg resultTag, GPRReg arg1)
+ {
+ m_jit.setupArgumentsWithExecState(arg1);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
+ JITCompiler::Call callOperation(J_JITOperation_EJC operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(J_JITOperation_EJssZ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1, arg2);
@@ -1525,6 +1580,11 @@
m_jit.setupArgumentsWithExecState(TrustedImmPtr(cell));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(J_JITOperation_ECZ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(J_JITOperation_ESsiCI operation, GPRReg resultTag, GPRReg resultPayload, StructureStubInfo* stubInfo, GPRReg arg1, const StringImpl* uid)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1, TrustedImmPtr(uid));
@@ -2211,6 +2271,9 @@
bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough) { return m_interpreter.needsTypeCheck(edge, typesPassedThrough); }
void typeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail);
+ void speculateCellTypeWithoutTypeFiltering(Edge, GPRReg cellGPR, JSType);
+ void speculateCellType(Edge, GPRReg cellGPR, SpeculatedType, JSType);
+
void speculateInt32(Edge);
#if USE(JSVALUE64)
void convertMachineInt(Edge, GPRReg resultGPR);
@@ -2222,6 +2285,7 @@
void speculateBoolean(Edge);
void speculateCell(Edge);
void speculateObject(Edge);
+ void speculateFunction(Edge);
void speculateFinalObject(Edge);
void speculateObjectOrOther(Edge);
void speculateString(Edge edge, GPRReg cell);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 516bfc6..93d5ce9 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -37,6 +37,7 @@
#include "Debugger.h"
#include "GetterSetter.h"
#include "JSActivation.h"
+#include "JSPropertyNameEnumerator.h"
#include "ObjectPrototype.h"
#include "JSCInlines.h"
@@ -1784,8 +1785,7 @@
}
case MovHint:
- case ZombieHint:
- case Check: {
+ case ZombieHint: {
RELEASE_ASSERT_NOT_REACHED();
break;
}
@@ -3700,6 +3700,7 @@
case CheckExecutable: {
SpeculateCellOperand function(this, node->child1());
+ speculateCellType(node->child1(), function.gpr(), SpecFunction, JSFunctionType);
speculationCheck(BadExecutable, JSValueSource::unboxedCell(function.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, JITCompiler::Address(function.gpr(), JSFunction::offsetOfExecutable()), node->executable()));
noResult(node);
break;
@@ -4601,6 +4602,252 @@
break;
}
+ case GetEnumerableLength: {
+ SpeculateCellOperand base(this, node->child1());
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationGetEnumerableLength, resultGPR, base.gpr());
+ int32Result(resultGPR, node);
+ break;
+ }
+ case HasGenericProperty: {
+ JSValueOperand base(this, node->child1());
+ SpeculateCellOperand property(this, node->child2());
+ GPRResult resultPayload(this);
+ GPRResult2 resultTag(this);
+ GPRReg basePayloadGPR = base.payloadGPR();
+ GPRReg baseTagGPR = base.tagGPR();
+ GPRReg resultPayloadGPR = resultPayload.gpr();
+ GPRReg resultTagGPR = resultTag.gpr();
+
+ flushRegisters();
+ callOperation(operationHasGenericProperty, resultTagGPR, resultPayloadGPR, baseTagGPR, basePayloadGPR, property.gpr());
+ booleanResult(resultPayloadGPR, node);
+ break;
+ }
+ case HasStructureProperty: {
+ JSValueOperand base(this, node->child1());
+ SpeculateCellOperand property(this, node->child2());
+ SpeculateCellOperand enumerator(this, node->child3());
+ GPRTemporary scratch(this);
+ GPRResult resultPayload(this);
+ GPRResult2 resultTag(this);
+
+ GPRReg baseTagGPR = base.tagGPR();
+ GPRReg basePayloadGPR = base.payloadGPR();
+ GPRReg propertyGPR = property.gpr();
+ GPRReg scratchGPR = scratch.gpr();
+ GPRReg resultPayloadGPR = resultPayload.gpr();
+ GPRReg resultTagGPR = resultTag.gpr();
+
+ m_jit.load32(MacroAssembler::Address(basePayloadGPR, JSCell::structureIDOffset()), scratchGPR);
+ MacroAssembler::Jump wrongStructure = m_jit.branch32(MacroAssembler::NotEqual,
+ scratchGPR,
+ MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::cachedStructureIDOffset()));
+
+ moveTrueTo(resultPayloadGPR);
+ MacroAssembler::Jump done = m_jit.jump();
+
+ done.link(&m_jit);
+
+ addSlowPathGenerator(slowPathCall(wrongStructure, this, operationHasGenericProperty, resultTagGPR, resultPayloadGPR, baseTagGPR, basePayloadGPR, propertyGPR));
+ booleanResult(resultPayloadGPR, node);
+ break;
+ }
+ case HasIndexedProperty: {
+ SpeculateCellOperand base(this, node->child1());
+ SpeculateInt32Operand index(this, node->child2());
+ GPRResult resultPayload(this);
+ GPRResult2 resultTag(this);
+
+ GPRReg baseGPR = base.gpr();
+ GPRReg indexGPR = index.gpr();
+ GPRReg resultPayloadGPR = resultPayload.gpr();
+ GPRReg resultTagGPR = resultTag.gpr();
+
+ MacroAssembler::JumpList slowCases;
+ ArrayMode mode = node->arrayMode();
+ switch (mode.type()) {
+ case Array::Int32:
+ case Array::Contiguous: {
+ ASSERT(!!node->child3());
+ StorageOperand storage(this, node->child3());
+ GPRTemporary scratch(this);
+
+ GPRReg storageGPR = storage.gpr();
+ GPRReg scratchGPR = scratch.gpr();
+
+ slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())));
+ m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR);
+ slowCases.append(m_jit.branch32(MacroAssembler::Equal, scratchGPR, TrustedImm32(JSValue::EmptyValueTag)));
+ break;
+ }
+ case Array::Double: {
+ ASSERT(!!node->child3());
+ StorageOperand storage(this, node->child3());
+ FPRTemporary scratch(this);
+ FPRReg scratchFPR = scratch.fpr();
+ GPRReg storageGPR = storage.gpr();
+
+ slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())));
+ m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchFPR);
+ slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, scratchFPR, scratchFPR));
+ break;
+ }
+ case Array::ArrayStorage: {
+ ASSERT(!!node->child3());
+ StorageOperand storage(this, node->child3());
+ GPRTemporary scratch(this);
+
+ GPRReg storageGPR = storage.gpr();
+ GPRReg scratchGPR = scratch.gpr();
+
+ slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset())));
+ m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR);
+ slowCases.append(m_jit.branch32(MacroAssembler::Equal, scratchGPR, TrustedImm32(JSValue::EmptyValueTag)));
+ break;
+ }
+ default: {
+ slowCases.append(m_jit.jump());
+ break;
+ }
+ }
+
+ moveTrueTo(resultPayloadGPR);
+ MacroAssembler::Jump done = m_jit.jump();
+
+ addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedProperty, resultTagGPR, resultPayloadGPR, baseGPR, indexGPR));
+
+ done.link(&m_jit);
+ booleanResult(resultPayloadGPR, node);
+ break;
+ }
+ case GetDirectPname: {
+ Edge& baseEdge = m_jit.graph().varArgChild(node, 0);
+ Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
+ Edge& indexEdge = m_jit.graph().varArgChild(node, 2);
+ Edge& enumeratorEdge = m_jit.graph().varArgChild(node, 3);
+
+ SpeculateCellOperand base(this, baseEdge);
+ SpeculateCellOperand property(this, propertyEdge);
+ SpeculateInt32Operand index(this, indexEdge);
+ SpeculateCellOperand enumerator(this, enumeratorEdge);
+ GPRResult resultPayload(this);
+ GPRResult2 resultTag(this);
+ GPRTemporary scratch(this);
+
+ GPRReg baseGPR = base.gpr();
+ GPRReg propertyGPR = property.gpr();
+ GPRReg indexGPR = index.gpr();
+ GPRReg enumeratorGPR = enumerator.gpr();
+ GPRReg resultTagGPR = resultTag.gpr();
+ GPRReg resultPayloadGPR = resultPayload.gpr();
+ GPRReg scratchGPR = scratch.gpr();
+
+ // Check the structure
+ m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), scratchGPR);
+ MacroAssembler::Jump wrongStructure = m_jit.branch32(MacroAssembler::NotEqual,
+ scratchGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset()));
+
+ // Compute the offset
+ // If index is less than the enumerator's cached inline storage, then it's an inline access
+ MacroAssembler::Jump outOfLineAccess = m_jit.branch32(MacroAssembler::AboveOrEqual,
+ indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
+
+ m_jit.move(indexGPR, scratchGPR);
+ m_jit.signExtend32ToPtr(scratchGPR, scratchGPR);
+ m_jit.load32(MacroAssembler::BaseIndex(baseGPR, scratchGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagGPR);
+ m_jit.load32(MacroAssembler::BaseIndex(baseGPR, scratchGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadGPR);
+
+ MacroAssembler::Jump done = m_jit.jump();
+
+ // Otherwise it's out of line
+ outOfLineAccess.link(&m_jit);
+ m_jit.move(indexGPR, scratchGPR);
+ m_jit.sub32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), scratchGPR);
+ m_jit.neg32(scratchGPR);
+ m_jit.signExtend32ToPtr(scratchGPR, scratchGPR);
+ // We use resultPayloadGPR as a temporary here. We have to make sure clobber it after getting the
+ // value out of indexGPR and enumeratorGPR because resultPayloadGPR could reuse either of those registers.
+ m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), resultPayloadGPR);
+ int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
+ m_jit.load32(MacroAssembler::BaseIndex(resultPayloadGPR, scratchGPR, MacroAssembler::TimesEight, offsetOfFirstProperty + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagGPR);
+ m_jit.load32(MacroAssembler::BaseIndex(resultPayloadGPR, scratchGPR, MacroAssembler::TimesEight, offsetOfFirstProperty + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadGPR);
+
+ done.link(&m_jit);
+
+ m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), scratchGPR);
+ addSlowPathGenerator(slowPathCall(wrongStructure, this, operationGetByValCell, resultTagGPR, resultPayloadGPR, baseGPR, scratchGPR, propertyGPR));
+
+ jsValueResult(resultTagGPR, resultPayloadGPR, node);
+ break;
+ }
+ case GetStructurePropertyEnumerator: {
+ SpeculateCellOperand base(this, node->child1());
+ SpeculateInt32Operand length(this, node->child2());
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationGetStructurePropertyEnumerator, resultGPR, base.gpr(), length.gpr());
+ cellResult(resultGPR, node);
+ break;
+ }
+ case GetGenericPropertyEnumerator: {
+ SpeculateCellOperand base(this, node->child1());
+ SpeculateInt32Operand length(this, node->child2());
+ SpeculateCellOperand enumerator(this, node->child3());
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationGetGenericPropertyEnumerator, resultGPR, base.gpr(), length.gpr(), enumerator.gpr());
+ cellResult(resultGPR, node);
+ break;
+ }
+ case GetEnumeratorPname: {
+ SpeculateCellOperand enumerator(this, node->child1());
+ SpeculateInt32Operand index(this, node->child2());
+ GPRTemporary scratch(this);
+ GPRResult resultPayload(this);
+ GPRResult2 resultTag(this);
+
+ GPRReg enumeratorGPR = enumerator.gpr();
+ GPRReg indexGPR = index.gpr();
+ GPRReg scratchGPR = scratch.gpr();
+ GPRReg resultTagGPR = resultTag.gpr();
+ GPRReg resultPayloadGPR = resultPayload.gpr();
+
+ MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below,
+ indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()));
+
+ m_jit.move(MacroAssembler::TrustedImm32(JSValue::NullTag), resultTagGPR);
+ m_jit.move(MacroAssembler::TrustedImm32(0), resultPayloadGPR);
+
+ MacroAssembler::Jump done = m_jit.jump();
+ inBounds.link(&m_jit);
+
+ m_jit.loadPtr(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), scratchGPR);
+ m_jit.loadPtr(MacroAssembler::BaseIndex(scratchGPR, indexGPR, MacroAssembler::ScalePtr), resultPayloadGPR);
+ m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), resultTagGPR);
+
+ done.link(&m_jit);
+ jsValueResult(resultTagGPR, resultPayloadGPR, node);
+ break;
+ }
+ case ToIndexString: {
+ SpeculateInt32Operand index(this, node->child1());
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationToIndexString, resultGPR, index.gpr());
+ cellResult(resultGPR, node);
+ break;
+ }
+
case ForceOSRExit: {
terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
break;
@@ -4625,6 +4872,7 @@
case Phantom:
case HardPhantom:
+ case Check:
DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate);
noResult(node);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 5b1ac79..069aa19 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -37,6 +37,7 @@
#include "Debugger.h"
#include "GetterSetter.h"
#include "JSCInlines.h"
+#include "JSPropertyNameEnumerator.h"
#include "ObjectPrototype.h"
#include "SpillRegistersMode.h"
@@ -1869,8 +1870,7 @@
}
case MovHint:
- case ZombieHint:
- case Check: {
+ case ZombieHint: {
DFG_CRASH(m_jit.graph(), node, "Unexpected node");
break;
}
@@ -3793,6 +3793,7 @@
case CheckExecutable: {
SpeculateCellOperand function(this, node->child1());
+ speculateCellType(node->child1(), function.gpr(), SpecFunction, JSFunctionType);
speculationCheck(BadExecutable, JSValueSource::unboxedCell(function.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, JITCompiler::Address(function.gpr(), JSFunction::offsetOfExecutable()), node->executable()));
noResult(node);
break;
@@ -4647,6 +4648,7 @@
case Phantom:
case HardPhantom:
+ case Check:
DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate);
noResult(node);
break;
@@ -4670,6 +4672,249 @@
break;
}
+ case GetEnumerableLength: {
+ SpeculateCellOperand base(this, node->child1());
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationGetEnumerableLength, resultGPR, base.gpr());
+ int32Result(resultGPR, node);
+ break;
+ }
+ case HasGenericProperty: {
+ JSValueOperand base(this, node->child1());
+ SpeculateCellOperand property(this, node->child2());
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationHasGenericProperty, resultGPR, base.gpr(), property.gpr());
+ jsValueResult(resultGPR, node, DataFormatJSBoolean);
+ break;
+ }
+ case HasStructureProperty: {
+ JSValueOperand base(this, node->child1());
+ SpeculateCellOperand property(this, node->child2());
+ SpeculateCellOperand enumerator(this, node->child3());
+ GPRTemporary scratch(this);
+ GPRResult result(this);
+
+ GPRReg baseGPR = base.gpr();
+ GPRReg propertyGPR = property.gpr();
+ GPRReg scratchGPR = scratch.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), scratchGPR);
+ MacroAssembler::Jump wrongStructure = m_jit.branch32(MacroAssembler::NotEqual,
+ scratchGPR,
+ MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::cachedStructureIDOffset()));
+
+ moveTrueTo(resultGPR);
+ MacroAssembler::Jump done = m_jit.jump();
+
+ done.link(&m_jit);
+
+ addSlowPathGenerator(slowPathCall(wrongStructure, this, operationHasGenericProperty, resultGPR, baseGPR, propertyGPR));
+ jsValueResult(resultGPR, node, DataFormatJSBoolean);
+ break;
+ }
+ case HasIndexedProperty: {
+ SpeculateCellOperand base(this, node->child1());
+ SpeculateInt32Operand index(this, node->child2());
+ GPRResult result(this);
+
+ GPRReg baseGPR = base.gpr();
+ GPRReg indexGPR = index.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ MacroAssembler::JumpList slowCases;
+ ArrayMode mode = node->arrayMode();
+ switch (mode.type()) {
+ case Array::Int32:
+ case Array::Contiguous: {
+ ASSERT(!!node->child3());
+ StorageOperand storage(this, node->child3());
+ GPRTemporary scratch(this);
+
+ GPRReg storageGPR = storage.gpr();
+ GPRReg scratchGPR = scratch.gpr();
+
+ MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
+ if (mode.isInBounds())
+ speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds);
+ else
+ slowCases.append(outOfBounds);
+
+ m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchGPR);
+ slowCases.append(m_jit.branchTest64(MacroAssembler::Zero, scratchGPR));
+ moveTrueTo(resultGPR);
+ break;
+ }
+ case Array::Double: {
+ ASSERT(!!node->child3());
+ StorageOperand storage(this, node->child3());
+ FPRTemporary scratch(this);
+ FPRReg scratchFPR = scratch.fpr();
+ GPRReg storageGPR = storage.gpr();
+
+ MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
+ if (mode.isInBounds())
+ speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds);
+ else
+ slowCases.append(outOfBounds);
+
+ m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchFPR);
+ slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, scratchFPR, scratchFPR));
+ break;
+ }
+ case Array::ArrayStorage: {
+ ASSERT(!!node->child3());
+ StorageOperand storage(this, node->child3());
+ GPRTemporary scratch(this);
+
+ GPRReg storageGPR = storage.gpr();
+ GPRReg scratchGPR = scratch.gpr();
+
+ MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
+ if (mode.isInBounds())
+ speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds);
+ else
+ slowCases.append(outOfBounds);
+
+ m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), scratchGPR);
+ slowCases.append(m_jit.branchTest64(MacroAssembler::Zero, scratchGPR));
+ moveTrueTo(resultGPR);
+ break;
+ }
+ default: {
+ slowCases.append(m_jit.jump());
+ break;
+ }
+ }
+
+ addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedProperty, resultGPR, baseGPR, indexGPR));
+
+ jsValueResult(resultGPR, node, DataFormatJSBoolean);
+ break;
+ }
+ case GetDirectPname: {
+ Edge& baseEdge = m_jit.graph().varArgChild(node, 0);
+ Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
+ Edge& indexEdge = m_jit.graph().varArgChild(node, 2);
+ Edge& enumeratorEdge = m_jit.graph().varArgChild(node, 3);
+
+ SpeculateCellOperand base(this, baseEdge);
+ SpeculateCellOperand property(this, propertyEdge);
+ SpeculateInt32Operand index(this, indexEdge);
+ SpeculateCellOperand enumerator(this, enumeratorEdge);
+ GPRResult result(this);
+ GPRTemporary scratch1(this);
+ GPRTemporary scratch2(this);
+
+ GPRReg baseGPR = base.gpr();
+ GPRReg propertyGPR = property.gpr();
+ GPRReg indexGPR = index.gpr();
+ GPRReg enumeratorGPR = enumerator.gpr();
+ GPRReg resultGPR = result.gpr();
+ GPRReg scratch1GPR = scratch1.gpr();
+ GPRReg scratch2GPR = scratch2.gpr();
+
+ // Check the structure
+ m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), scratch1GPR);
+ MacroAssembler::Jump wrongStructure = m_jit.branch32(MacroAssembler::NotEqual,
+ scratch1GPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset()));
+
+ // Compute the offset
+ // If index is less than the enumerator's cached inline storage, then it's an inline access
+ MacroAssembler::Jump outOfLineAccess = m_jit.branch32(MacroAssembler::AboveOrEqual,
+ indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
+
+ m_jit.load64(MacroAssembler::BaseIndex(baseGPR, indexGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage()), resultGPR);
+
+ MacroAssembler::Jump done = m_jit.jump();
+
+ // Otherwise it's out of line
+ outOfLineAccess.link(&m_jit);
+ m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratch2GPR);
+ m_jit.move(indexGPR, scratch1GPR);
+ m_jit.sub32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), scratch1GPR);
+ m_jit.neg32(scratch1GPR);
+ m_jit.signExtend32ToPtr(scratch1GPR, scratch1GPR);
+ int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
+ m_jit.load64(MacroAssembler::BaseIndex(scratch2GPR, scratch1GPR, MacroAssembler::TimesEight, offsetOfFirstProperty), resultGPR);
+
+ done.link(&m_jit);
+
+ addSlowPathGenerator(slowPathCall(wrongStructure, this, operationGetByVal, resultGPR, baseGPR, propertyGPR));
+
+ jsValueResult(resultGPR, node);
+ break;
+ }
+ case GetStructurePropertyEnumerator: {
+ SpeculateCellOperand base(this, node->child1());
+ SpeculateInt32Operand length(this, node->child2());
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationGetStructurePropertyEnumerator, resultGPR, base.gpr(), length.gpr());
+ cellResult(resultGPR, node);
+ break;
+ }
+ case GetGenericPropertyEnumerator: {
+ SpeculateCellOperand base(this, node->child1());
+ SpeculateInt32Operand length(this, node->child2());
+ SpeculateCellOperand enumerator(this, node->child3());
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationGetGenericPropertyEnumerator, resultGPR, base.gpr(), length.gpr(), enumerator.gpr());
+ cellResult(resultGPR, node);
+ break;
+ }
+ case GetEnumeratorPname: {
+ SpeculateCellOperand enumerator(this, node->child1());
+ SpeculateInt32Operand index(this, node->child2());
+ GPRTemporary scratch1(this);
+ GPRTemporary scratch2(this);
+ GPRResult result(this);
+
+ GPRReg enumeratorGPR = enumerator.gpr();
+ GPRReg indexGPR = index.gpr();
+ GPRReg scratch1GPR = scratch1.gpr();
+ GPRReg scratch2GPR = scratch2.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below,
+ indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()));
+
+ m_jit.move(MacroAssembler::TrustedImm32(ValueNull), resultGPR);
+
+ MacroAssembler::Jump done = m_jit.jump();
+ inBounds.link(&m_jit);
+
+ m_jit.loadPtr(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), scratch1GPR);
+ m_jit.move(indexGPR, scratch2GPR);
+ m_jit.signExtend32ToPtr(scratch2GPR, scratch2GPR);
+ m_jit.load64(MacroAssembler::BaseIndex(scratch1GPR, scratch2GPR, MacroAssembler::TimesEight), resultGPR);
+
+ done.link(&m_jit);
+ jsValueResult(resultGPR, node);
+ break;
+ }
+ case ToIndexString: {
+ SpeculateInt32Operand index(this, node->child1());
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationToIndexString, resultGPR, index.gpr());
+ cellResult(resultGPR, node);
+ break;
+ }
+
#if ENABLE(FTL_JIT)
case CheckTierUpInLoop: {
MacroAssembler::Jump done = m_jit.branchAdd32(
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.cpp b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
index 913a715..c158149 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.cpp
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
@@ -39,80 +39,84 @@
switch (useKind) {
case UntypedUse:
out.print("Untyped");
- break;
+ return;
case Int32Use:
out.print("Int32");
- break;
+ return;
case KnownInt32Use:
out.print("KnownInt32");
- break;
+ return;
case Int52RepUse:
out.print("Int52Rep");
- break;
+ return;
case MachineIntUse:
out.print("MachineInt");
- break;
+ return;
case NumberUse:
out.print("Number");
- break;
+ return;
case DoubleRepUse:
out.print("DoubleRep");
- break;
+ return;
case DoubleRepRealUse:
out.print("DoubleRepReal");
- break;
+ return;
case DoubleRepMachineIntUse:
out.print("DoubleRepMachineInt");
- break;
+ return;
case BooleanUse:
out.print("Boolean");
- break;
+ return;
case CellUse:
out.print("Cell");
- break;
+ return;
case KnownCellUse:
out.print("KnownCell");
- break;
+ return;
case ObjectUse:
out.print("Object");
- break;
+ return;
+ case FunctionUse:
+ out.print("Function");
+ return;
case FinalObjectUse:
out.print("FinalObject");
- break;
+ return;
case ObjectOrOtherUse:
out.print("ObjectOrOther");
- break;
+ return;
case StringIdentUse:
out.print("StringIdent");
- break;
+ return;
case StringUse:
out.print("String");
- break;
+ return;
case KnownStringUse:
out.print("KnownString");
- break;
+ return;
case StringObjectUse:
out.print("StringObject");
- break;
+ return;
case StringOrStringObjectUse:
out.print("StringOrStringObject");
- break;
+ return;
case NotStringVarUse:
out.print("NotStringVar");
- break;
+ return;
case NotCellUse:
out.print("NotCell");
- break;
+ return;
case OtherUse:
out.print("Other");
- break;
+ return;
case MiscUse:
out.print("Misc");
- break;
- default:
+ return;
+ case LastUseKind:
RELEASE_ASSERT_NOT_REACHED();
- break;
+ return;
}
+ RELEASE_ASSERT_NOT_REACHED();
}
} // namespace WTF
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.h b/Source/JavaScriptCore/dfg/DFGUseKind.h
index d6eeef7..a472935 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.h
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.h
@@ -48,6 +48,7 @@
CellUse,
KnownCellUse,
ObjectUse,
+ FunctionUse,
FinalObjectUse,
ObjectOrOtherUse,
StringIdentUse,
@@ -89,6 +90,8 @@
return SpecCell;
case ObjectUse:
return SpecObject;
+ case FunctionUse:
+ return SpecFunction;
case FinalObjectUse:
return SpecFinalObject;
case ObjectOrOtherUse:
@@ -171,6 +174,7 @@
case CellUse:
case KnownCellUse:
case ObjectUse:
+ case FunctionUse:
case FinalObjectUse:
case StringIdentUse:
case StringUse:
diff --git a/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp b/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp
index 77ba105..82f12d5 100644
--- a/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp
+++ b/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp
@@ -29,6 +29,7 @@
#if ENABLE(FTL_JIT)
#include "GetterSetter.h"
+#include "JSPropertyNameEnumerator.h"
#include "JSScope.h"
#include "JSVariableObject.h"
#include "JSCInlines.h"
diff --git a/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h b/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
index b98b736..0661caa 100644
--- a/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
+++ b/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
@@ -59,6 +59,10 @@
macro(JSFunction_executable, JSFunction::offsetOfExecutable()) \
macro(JSFunction_scope, JSFunction::offsetOfScopeChain()) \
macro(JSObject_butterfly, JSObject::butterflyOffset()) \
+ macro(JSPropertyNameEnumerator_cachedInlineCapacity, JSPropertyNameEnumerator::cachedInlineCapacityOffset()) \
+ macro(JSPropertyNameEnumerator_cachedPropertyNamesLength, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()) \
+ macro(JSPropertyNameEnumerator_cachedPropertyNamesVector, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()) \
+ macro(JSPropertyNameEnumerator_cachedStructureID, JSPropertyNameEnumerator::cachedStructureIDOffset()) \
macro(JSScope_next, JSScope::offsetOfNext()) \
macro(JSString_flags, JSString::offsetOfFlags()) \
macro(JSString_length, JSString::offsetOfLength()) \
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index b9b1be8..ee11907 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -158,6 +158,14 @@
case DoubleConstant:
case Int52Constant:
case BooleanToNumber:
+ case HasGenericProperty:
+ case HasStructureProperty:
+ case GetDirectPname:
+ case GetEnumerableLength:
+ case GetStructurePropertyEnumerator:
+ case GetGenericPropertyEnumerator:
+ case GetEnumeratorPname:
+ case ToIndexString:
// These are OK.
break;
case Identity:
@@ -206,6 +214,17 @@
return CannotCompile;
}
break;
+ case HasIndexedProperty:
+ switch (node->arrayMode().type()) {
+ case Array::ForceExit:
+ case Array::Int32:
+ case Array::Double:
+ case Array::Contiguous:
+ break;
+ default:
+ return CannotCompile;
+ }
+ break;
case GetByVal:
switch (node->arrayMode().type()) {
case Array::ForceExit:
@@ -374,6 +393,7 @@
case CellUse:
case KnownCellUse:
case ObjectUse:
+ case FunctionUse:
case ObjectOrOtherUse:
case StringUse:
case KnownStringUse:
diff --git a/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h b/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
index 2f417b5..d227792 100644
--- a/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
+++ b/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
@@ -54,19 +54,24 @@
#define FOR_EACH_FUNCTION_TYPE(macro) \
macro(C_JITOperation_EC, functionType(intPtr, intPtr, intPtr)) \
+ macro(C_JITOperation_ECZ, functionType(intPtr, intPtr, intPtr, int32)) \
+ macro(C_JITOperation_ECZC, functionType(intPtr, intPtr, intPtr, int32, intPtr)) \
macro(C_JITOperation_EJ, functionType(intPtr, intPtr, int64)) \
macro(C_JITOperation_EJssJss, functionType(intPtr, intPtr, intPtr, intPtr)) \
macro(C_JITOperation_EJssJssJss, functionType(intPtr, intPtr, intPtr, intPtr, intPtr)) \
macro(C_JITOperation_ESt, functionType(intPtr, intPtr, intPtr)) \
+ macro(C_JITOperation_EZ, functionType(intPtr, intPtr, int32)) \
macro(D_JITOperation_D, functionType(doubleType, doubleType)) \
macro(I_JITOperation_EJss, functionType(intPtr, intPtr, intPtr)) \
macro(J_JITOperation_E, functionType(int64, intPtr)) \
macro(J_JITOperation_EA, functionType(int64, intPtr, intPtr)) \
macro(J_JITOperation_EAZ, functionType(int64, intPtr, intPtr, int32)) \
macro(J_JITOperation_ECJ, functionType(int64, intPtr, intPtr, int64)) \
+ macro(J_JITOperation_ECZ, functionType(int64, intPtr, intPtr, int32)) \
macro(J_JITOperation_EDA, functionType(int64, intPtr, doubleType, intPtr)) \
macro(J_JITOperation_EJ, functionType(int64, intPtr, int64)) \
macro(J_JITOperation_EJA, functionType(int64, intPtr, int64, intPtr)) \
+ macro(J_JITOperation_EJC, functionType(int64, intPtr, int64, intPtr)) \
macro(J_JITOperation_EJJ, functionType(int64, intPtr, int64, int64)) \
macro(J_JITOperation_EJssZ, functionType(int64, intPtr, intPtr, int32)) \
macro(J_JITOperation_ESsiJI, functionType(int64, intPtr, intPtr, int64, intPtr)) \
@@ -94,8 +99,9 @@
macro(V_JITOperation_EVwsJ, functionType(voidType, intPtr, intPtr, int64)) \
macro(V_JITOperation_J, functionType(voidType, int64)) \
macro(V_JITOperation_Z, functionType(voidType, int32)) \
- macro(Z_JITOperation_D, functionType(int32, doubleType))
-
+ macro(Z_JITOperation_D, functionType(int32, doubleType)) \
+ macro(Z_JITOperation_EC, functionType(int32, intPtr, intPtr))
+
class IntrinsicRepository : public CommonValues {
public:
IntrinsicRepository(LContext);
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index 68aa7cd..b2ae16e 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -400,6 +400,7 @@
break;
case Phantom:
case HardPhantom:
+ case Check:
compilePhantom();
break;
case ToThis:
@@ -698,6 +699,34 @@
case StoreBarrierWithNullCheck:
compileStoreBarrierWithNullCheck();
break;
+ case HasIndexedProperty:
+ compileHasIndexedProperty();
+ break;
+ case HasGenericProperty:
+ compileHasGenericProperty();
+ break;
+ case HasStructureProperty:
+ compileHasStructureProperty();
+ break;
+ case GetDirectPname:
+ compileGetDirectPname();
+ break;
+ case GetEnumerableLength:
+ compileGetEnumerableLength();
+ break;
+ case GetStructurePropertyEnumerator:
+ compileGetStructurePropertyEnumerator();
+ break;
+ case GetGenericPropertyEnumerator:
+ compileGetGenericPropertyEnumerator();
+ break;
+ case GetEnumeratorPname:
+ compileGetEnumeratorPname();
+ break;
+ case ToIndexString:
+ compileToIndexString();
+ break;
+
case PhantomLocal:
case SetArgument:
case LoopHint:
@@ -1727,6 +1756,8 @@
{
LValue cell = lowCell(m_node->child1());
+ speculateFunction(m_node->child1(), cell);
+
speculate(
BadExecutable, jsValueValue(cell), m_node->child1().node(),
m_out.notEqual(
@@ -4102,6 +4133,225 @@
#endif
}
+ void compileHasIndexedProperty()
+ {
+ switch (m_node->arrayMode().type()) {
+ case Array::Int32:
+ case Array::Contiguous: {
+ LValue base = lowCell(m_node->child1());
+ LValue index = lowInt32(m_node->child2());
+ LValue storage = lowStorage(m_node->child3());
+
+ IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ?
+ m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties;
+
+ LBasicBlock checkHole = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous check hole"));
+ LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous slow case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous continuation"));
+
+ if (!m_node->arrayMode().isInBounds()) {
+ m_out.branch(
+ m_out.aboveOrEqual(
+ index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
+ rarely(slowCase), usually(checkHole));
+ } else
+ m_out.jump(checkHole);
+
+ LBasicBlock lastNext = m_out.appendTo(checkHole, slowCase);
+ ValueFromBlock checkHoleResult = m_out.anchor(
+ m_out.notZero64(m_out.load64(baseIndex(heap, storage, index, m_node->child2()))));
+ m_out.branch(checkHoleResult.value(), usually(continuation), rarely(slowCase));
+
+ m_out.appendTo(slowCase, continuation);
+ ValueFromBlock slowResult = m_out.anchor(m_out.equal(
+ m_out.constInt64(JSValue::encode(jsBoolean(true))),
+ vmCall(m_out.operation(operationHasIndexedProperty), m_callFrame, base, index)));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setBoolean(m_out.phi(m_out.boolean, checkHoleResult, slowResult));
+ return;
+ }
+ case Array::Double: {
+ LValue base = lowCell(m_node->child1());
+ LValue index = lowInt32(m_node->child2());
+ LValue storage = lowStorage(m_node->child3());
+
+ IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
+
+ LBasicBlock checkHole = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double check hole"));
+ LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double slow case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double continuation"));
+
+ if (!m_node->arrayMode().isInBounds()) {
+ m_out.branch(
+ m_out.aboveOrEqual(
+ index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
+ rarely(slowCase), usually(checkHole));
+ } else
+ m_out.jump(checkHole);
+
+ LBasicBlock lastNext = m_out.appendTo(checkHole, slowCase);
+ LValue doubleValue = m_out.loadDouble(baseIndex(heap, storage, index, m_node->child2()));
+ ValueFromBlock checkHoleResult = m_out.anchor(
+ m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue));
+ m_out.branch(checkHoleResult.value(), rarely(slowCase), usually(continuation));
+
+ m_out.appendTo(slowCase, continuation);
+ ValueFromBlock slowResult = m_out.anchor(m_out.equal(
+ m_out.constInt64(JSValue::encode(jsBoolean(true))),
+ vmCall(m_out.operation(operationHasIndexedProperty), m_callFrame, base, index)));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setBoolean(m_out.phi(m_out.boolean, checkHoleResult, slowResult));
+ return;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return;
+ }
+ }
+
+ void compileHasGenericProperty()
+ {
+ LValue base = lowJSValue(m_node->child1());
+ LValue property = lowCell(m_node->child2());
+ setJSValue(vmCall(m_out.operation(operationHasGenericProperty), m_callFrame, base, property));
+ }
+
+ void compileHasStructureProperty()
+ {
+ LValue base = lowJSValue(m_node->child1());
+ LValue property = lowString(m_node->child2());
+ LValue enumerator = lowCell(m_node->child3());
+
+ LBasicBlock correctStructure = FTL_NEW_BLOCK(m_out, ("HasStructureProperty correct structure"));
+ LBasicBlock wrongStructure = FTL_NEW_BLOCK(m_out, ("HasStructureProperty wrong structure"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasStructureProperty continuation"));
+
+ m_out.branch(m_out.notEqual(
+ m_out.load32(base, m_heaps.JSCell_structureID),
+ m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
+ rarely(wrongStructure), usually(correctStructure));
+
+ LBasicBlock lastNext = m_out.appendTo(correctStructure, wrongStructure);
+ ValueFromBlock correctStructureResult = m_out.anchor(m_out.booleanTrue);
+ m_out.jump(continuation);
+
+ m_out.appendTo(wrongStructure, continuation);
+ ValueFromBlock wrongStructureResult = m_out.anchor(
+ m_out.equal(
+ m_out.constInt64(JSValue::encode(jsBoolean(true))),
+ vmCall(m_out.operation(operationHasGenericProperty), m_callFrame, base, property)));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setBoolean(m_out.phi(m_out.boolean, correctStructureResult, wrongStructureResult));
+ }
+
+ void compileGetDirectPname()
+ {
+ LValue base = lowCell(m_graph.varArgChild(m_node, 0));
+ LValue property = lowCell(m_graph.varArgChild(m_node, 1));
+ LValue index = lowInt32(m_graph.varArgChild(m_node, 2));
+ LValue enumerator = lowCell(m_graph.varArgChild(m_node, 3));
+
+ LBasicBlock checkOffset = FTL_NEW_BLOCK(m_out, ("GetDirectPname check offset"));
+ LBasicBlock inlineLoad = FTL_NEW_BLOCK(m_out, ("GetDirectPname inline load"));
+ LBasicBlock outOfLineLoad = FTL_NEW_BLOCK(m_out, ("GetDirectPname out-of-line load"));
+ LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetDirectPname slow case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetDirectPname continuation"));
+
+ m_out.branch(m_out.notEqual(
+ m_out.load32(base, m_heaps.JSCell_structureID),
+ m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
+ rarely(slowCase), usually(checkOffset));
+
+ LBasicBlock lastNext = m_out.appendTo(checkOffset, inlineLoad);
+ m_out.branch(m_out.aboveOrEqual(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity)),
+ unsure(outOfLineLoad), unsure(inlineLoad));
+
+ m_out.appendTo(inlineLoad, outOfLineLoad);
+ ValueFromBlock inlineResult = m_out.anchor(
+ m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(),
+ base, m_out.zeroExt(index, m_out.int64), ScaleEight, JSObject::offsetOfInlineStorage())));
+ m_out.jump(continuation);
+
+ m_out.appendTo(outOfLineLoad, slowCase);
+ LValue storage = m_out.loadPtr(base, m_heaps.JSObject_butterfly);
+ LValue realIndex = m_out.signExt(
+ m_out.neg(m_out.sub(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity))),
+ m_out.int64);
+ int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
+ ValueFromBlock outOfLineResult = m_out.anchor(
+ m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), storage, realIndex, ScaleEight, offsetOfFirstProperty)));
+ m_out.jump(continuation);
+
+ m_out.appendTo(slowCase, continuation);
+ ValueFromBlock slowCaseResult = m_out.anchor(
+ vmCall(m_out.operation(operationGetByVal), m_callFrame, base, property));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setJSValue(m_out.phi(m_out.int64, inlineResult, outOfLineResult, slowCaseResult));
+ }
+
+ void compileGetEnumerableLength()
+ {
+ LValue base = lowCell(m_node->child1());
+ setInt32(vmCall(m_out.operation(operationGetEnumerableLength), m_callFrame, base));
+ }
+
+ void compileGetStructurePropertyEnumerator()
+ {
+ LValue base = lowCell(m_node->child1());
+ LValue length = lowInt32(m_node->child2());
+ setJSValue(vmCall(m_out.operation(operationGetStructurePropertyEnumerator), m_callFrame, base, length));
+ }
+
+ void compileGetGenericPropertyEnumerator()
+ {
+ LValue base = lowCell(m_node->child1());
+ LValue length = lowInt32(m_node->child2());
+ LValue enumerator = lowCell(m_node->child3());
+ setJSValue(vmCall(m_out.operation(operationGetGenericPropertyEnumerator), m_callFrame, base, length, enumerator));
+ }
+
+ void compileGetEnumeratorPname()
+ {
+ LValue enumerator = lowCell(m_node->child1());
+ LValue index = lowInt32(m_node->child2());
+
+ LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorPname in bounds"));
+ LBasicBlock outOfBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorPname out of bounds"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetEnumeratorPname continuation"));
+
+ m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesLength)),
+ usually(inBounds), rarely(outOfBounds));
+
+ LBasicBlock lastNext = m_out.appendTo(inBounds, outOfBounds);
+ LValue storage = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector);
+ ValueFromBlock inBoundsResult = m_out.anchor(
+ m_out.load64(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector,
+ storage, m_out.signExt(index, m_out.int64), ScaleEight)));
+ m_out.jump(continuation);
+
+ m_out.appendTo(outOfBounds, continuation);
+ ValueFromBlock outOfBoundsResult = m_out.anchor(m_out.constInt64(ValueNull));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setJSValue(m_out.phi(m_out.int64, inBoundsResult, outOfBoundsResult));
+ }
+
+ void compileToIndexString()
+ {
+ LValue index = lowInt32(m_node->child1());
+ setJSValue(vmCall(m_out.operation(operationToIndexString), m_callFrame, index));
+ }
+
#if ENABLE(FTL_NATIVE_CALL_INLINING)
LValue getFunctionBySymbol(const CString symbol)
{
@@ -5265,7 +5515,7 @@
LValue lowJSValue(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
{
- ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse);
+ DFG_ASSERT(m_graph, m_node, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse);
DFG_ASSERT(m_graph, m_node, !isDouble(edge.useKind()));
DFG_ASSERT(m_graph, m_node, edge.useKind() != Int52RepUse);
@@ -5559,6 +5809,9 @@
case ObjectUse:
speculateObject(edge);
break;
+ case FunctionUse:
+ speculateFunction(edge);
+ break;
case ObjectOrOtherUse:
speculateObjectOrOther(edge);
break;
@@ -5693,6 +5946,9 @@
}
}
+ LValue isFunction(LValue cell) { return isType(cell, JSFunctionType); }
+ LValue isNotFunction(LValue cell) { return isNotType(cell, JSFunctionType); }
+
LValue isType(LValue cell, JSType type)
{
return m_out.equal(
@@ -5715,12 +5971,22 @@
speculateObject(edge, lowCell(edge));
}
+ void speculateFunction(Edge edge, LValue cell)
+ {
+ FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecFunction, isNotFunction(cell));
+ }
+
+ void speculateFunction(Edge edge)
+ {
+ speculateFunction(edge, lowCell(edge));
+ }
+
void speculateObjectOrOther(Edge edge)
{
if (!m_interpreter.needsTypeCheck(edge))
return;
- LValue value = lowJSValue(edge);
+ LValue value = lowJSValue(edge, ManualOperandSpeculation);
LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther cell case"));
LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther primitive case"));
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index 8b1dc44..62fab26 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -970,8 +970,6 @@
#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()) {
@@ -981,6 +979,11 @@
SamplingRegion samplingRegion("Garbage Collection");
+ if (vm()->isProfilingTypesWithHighFidelity()) {
+ DeferGCForAWhile awhile(*this);
+ vm()->highFidelityLog()->processHighFidelityLog("GC");
+ }
+
RELEASE_ASSERT(!m_deferralDepth);
ASSERT(vm()->currentThreadIsHoldingAPILock());
RELEASE_ASSERT(vm()->atomicStringTable() == wtfThreadData().atomicStringTable());
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp
index db9bec5..9efee15 100644
--- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp
+++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp
@@ -35,6 +35,8 @@
#if ENABLE(INSPECTOR)
#include "Completion.h"
+#include "HighFidelityLog.h"
+#include "HighFidelityTypeProfiler.h"
#include "InjectedScript.h"
#include "InjectedScriptManager.h"
#include "InspectorValues.h"
@@ -43,6 +45,7 @@
#include "ScriptDebugServer.h"
#include "SourceCode.h"
#include <wtf/PassRefPtr.h>
+#include <wtf/CurrentTime.h>
using namespace JSC;
@@ -191,11 +194,41 @@
{
}
-void InspectorRuntimeAgent::getRuntimeTypeForVariableAtOffset(ErrorString*, const String& in_variableName, const String& in_id, int in_divot, String* out_types)
+void InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets(ErrorString* errorString, const RefPtr<Inspector::InspectorArray>& in_locations, RefPtr<Inspector::InspectorArray>& out_types)
{
+ static const bool verbose = false;
VM& vm = globalVM();
- String types(vm.getTypesForVariableAtOffset(in_divot, in_variableName, in_id));
- *out_types = types;
+ out_types = Inspector::InspectorArray::create();
+ if (!vm.isProfilingTypesWithHighFidelity())
+ return;
+
+ double start = currentTimeMS();
+ vm.highFidelityLog()->processHighFidelityLog("User Query");
+
+ for (size_t i = 0; i < in_locations->length(); i++) {
+ RefPtr<Inspector::InspectorValue> value = in_locations->get(i);
+ RefPtr<InspectorObject> location;
+ if (!value->asObject(&location)) {
+ *errorString = ASCIILiteral("Array of TypeLocation objects has an object that does not have type of TypeLocation.");
+ return;
+ }
+
+ int descriptor;
+ String sourceIDAsString;
+ int divot;
+ location->getNumber(ASCIILiteral("typeInformationDescriptor"), &descriptor);
+ location->getString(ASCIILiteral("sourceID"), &sourceIDAsString);
+ location->getNumber(ASCIILiteral("divot"), &divot);
+
+ RefPtr<Inspector::InspectorObject> typeDescription = Inspector::InspectorObject::create();
+ bool okay;
+ vm.highFidelityTypeProfiler()->getTypesForVariableAtOffsetForInspector(static_cast<TypeProfilerSearchDescriptor>(descriptor), divot, sourceIDAsString.toIntPtrStrict(&okay), typeDescription);
+ out_types->pushObject(typeDescription);
+ }
+
+ double end = currentTimeMS();
+ if (verbose)
+ dataLogF("Inspector::getRuntimeTypesForVariablesAtOffsets took %lfms\n", end - start);
}
} // namespace Inspector
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h
index 4677af2..76d3372 100644
--- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h
+++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h
@@ -66,8 +66,8 @@
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 getRuntimeTypeForVariableAtOffset(ErrorString*, const String& in_variableName, const String& in_id, int in_divot, String* out_types) override;
-
+ virtual void getRuntimeTypesForVariablesAtOffsets(ErrorString*, const RefPtr<Inspector::InspectorArray>& in_locations, RefPtr<Inspector::InspectorArray>& out_types) override;
+
void setScriptDebugServer(ScriptDebugServer* scriptDebugServer) { m_scriptDebugServer = scriptDebugServer; }
bool enabled() const { return m_enabled; }
diff --git a/Source/JavaScriptCore/inspector/protocol/Runtime.json b/Source/JavaScriptCore/inspector/protocol/Runtime.json
index a2b5fb3..64d723b 100644
--- a/Source/JavaScriptCore/inspector/protocol/Runtime.json
+++ b/Source/JavaScriptCore/inspector/protocol/Runtime.json
@@ -111,6 +111,39 @@
{ "name": "startOffset", "type": "integer", "description": "Start offset of range (inclusive)." },
{ "name": "endOffset", "type": "integer", "description": "End offset of range (exclusive)." }
]
+ },
+ {
+ "id": "StructureDescription",
+ "type": "object",
+ "properties": [
+ { "name": "fields", "type": "array", "items": { "type": "string" }, "description": "Array of strings, where the strings represent object properties." },
+ { "name": "constructorName", "type": "string", "description": "Name of the constructor." },
+ { "name": "prototypeStructure", "$ref": "StructureDescription", "optional": "true", "description": "Pointer to the StructureRepresentation of the protoype if one exists." }
+ ]
+ },
+ {
+ "id": "TypeDescription",
+ "type": "object",
+ "description": "Container for type information that has been gathered.",
+ "properties": [
+ { "name": "displayTypeName", "type": "string", "optional": true, "description": "What the inspector should display as a simple type." },
+ { "name": "localPrimitiveTypeNames", "type": "array", "items": { "type": "string" }, "optional": "true", "description": "Array of type names for primtive types (int, string, etc) seen at an instruction" },
+ { "name": "localObjectTypeNames", "type": "array", "items": { "type": "string" }, "optional": "true", "description": "Array of type names for all object seen at an instruction" },
+ { "name": "localStructures", "type": "array", "items": { "$ref": "StructureDescription" }, "optional": true, "description": "Array of descriptions for all structures seen at this this instruction." },
+ { "name": "globalPrimitiveTypeNames", "type": "array", "items": { "type": "string" }, "optional": true, "description": "Array of type names for all primitive types seen globally." },
+ { "name": "globalObjectTypeNames", "type": "array", "items": { "type": "string" }, "optional": true, "description": "Array of type names for all primitive types seen globally." },
+ { "name": "globalStructures", "type": "array", "items": { "$ref": "StructureDescription" }, "optional": true, "description": "Array of descriptions for all structures seen for this variable." }
+ ]
+ },
+ {
+ "id": "TypeLocation",
+ "type": "object",
+ "description": "Describes the location of an expression we want type information for.",
+ "properties": [
+ { "name": "typeInformationDescriptor", "type": "integer", "description": "What kind of type information do we want (normal, function return values, 'this' statement)." },
+ { "name": "sourceID", "type": "string", "description": "sourceID uniquely identifying a script" },
+ { "name": "divot", "type": "integer", "description": "character offset for assignment range" }
+ ]
}
],
"commands": [
@@ -198,14 +231,12 @@
"description": "Disables reporting of execution contexts creation."
},
{
- "name": "getRuntimeTypeForVariableAtOffset",
+ "name": "getRuntimeTypesForVariablesAtOffsets",
"parameters": [
- { "name": "variableName", "type": "string", "description": "Variable we want type infromation for." },
- { "name": "sourceID", "type": "string", "description": "sourceID uniquely identifying a script" },
- { "name": "divot", "type": "integer", "description": "character offset for assignment range" }
+ { "name": "locations", "type": "array", "items": { "$ref": "TypeLocation" }, "description": "An array of type locations we're requesting information for. Results are expected in the same order they're sent in."}
],
"returns": [
- { "name": "types", "type": "string", "description": "Types for requested variable." }
+ { "name": "types", "type": "array", "item": { "$ref": "TypeDescription", "description": "Types for requested variable." } }
],
"description": "Returns detailed informtation on given function."
}
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index 9db7acc..b3a5575 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -47,7 +47,6 @@
#include "JSBoundFunction.h"
#include "JSNameScope.h"
#include "JSNotAnObject.h"
-#include "JSPropertyNameIterator.h"
#include "JSStackInlines.h"
#include "JSString.h"
#include "JSWithScope.h"
diff --git a/Source/JavaScriptCore/interpreter/Register.h b/Source/JavaScriptCore/interpreter/Register.h
index 054b570..c6d7b25 100644
--- a/Source/JavaScriptCore/interpreter/Register.h
+++ b/Source/JavaScriptCore/interpreter/Register.h
@@ -39,7 +39,6 @@
class ExecState;
class JSActivation;
class JSObject;
- class JSPropertyNameIterator;
class JSScope;
typedef ExecState CallFrame;
@@ -63,7 +62,6 @@
CallFrame* callFrame() const;
CodeBlock* codeBlock() const;
JSObject* function() const;
- JSPropertyNameIterator* propertyNameIterator() const;
JSScope* scope() const;
int32_t unboxedInt32() const;
int64_t unboxedInt52() const;
diff --git a/Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp
index 3e9b268..7045130 100644
--- a/Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp
+++ b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 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
@@ -39,9 +39,8 @@
ClosureCallStubRoutine::ClosureCallStubRoutine(
const MacroAssemblerCodeRef& code, VM& vm, const JSCell* owner,
- Structure* structure, ExecutableBase* executable, const CodeOrigin& codeOrigin)
+ ExecutableBase* executable, const CodeOrigin& codeOrigin)
: GCAwareJITStubRoutine(code, vm)
- , m_structure(vm, owner, structure)
, m_executable(vm, owner, executable)
, m_codeOrigin(codeOrigin)
{
@@ -53,7 +52,6 @@
void ClosureCallStubRoutine::markRequiredObjectsInternal(SlotVisitor& visitor)
{
- visitor.append(&m_structure);
visitor.append(&m_executable);
}
diff --git a/Source/JavaScriptCore/jit/ClosureCallStubRoutine.h b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.h
index 1523301..363c38c 100644
--- a/Source/JavaScriptCore/jit/ClosureCallStubRoutine.h
+++ b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 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
@@ -37,11 +37,10 @@
public:
ClosureCallStubRoutine(
const MacroAssemblerCodeRef&, VM&, const JSCell* owner,
- Structure*, ExecutableBase*, const CodeOrigin&);
+ ExecutableBase*, const CodeOrigin&);
virtual ~ClosureCallStubRoutine();
- Structure* structure() const { return m_structure.get(); }
ExecutableBase* executable() const { return m_executable.get(); }
const CodeOrigin& codeOrigin() const { return m_codeOrigin; }
@@ -49,7 +48,6 @@
virtual void markRequiredObjectsInternal(SlotVisitor&) override;
private:
- WriteBarrier<Structure> m_structure;
WriteBarrier<ExecutableBase> m_executable;
// This allows us to figure out who a call is linked to by searching through
// stub routines.
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 33e733b..0396e16 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -223,8 +223,6 @@
DEFINE_OP(op_get_arguments_length)
DEFINE_OP(op_get_by_val)
DEFINE_OP(op_get_argument_by_val)
- DEFINE_OP(op_get_by_pname)
- DEFINE_OP(op_get_pnames)
DEFINE_OP(op_check_has_instance)
DEFINE_OP(op_instanceof)
DEFINE_OP(op_is_undefined)
@@ -262,7 +260,6 @@
DEFINE_OP(op_new_func_exp)
DEFINE_OP(op_new_object)
DEFINE_OP(op_new_regexp)
- DEFINE_OP(op_next_pname)
DEFINE_OP(op_not)
DEFINE_OP(op_nstricteq)
DEFINE_OP(op_pop_scope)
@@ -307,6 +304,16 @@
DEFINE_OP(op_resolve_scope)
DEFINE_OP(op_get_from_scope)
DEFINE_OP(op_put_to_scope)
+
+ DEFINE_OP(op_get_enumerable_length)
+ DEFINE_OP(op_has_generic_property)
+ DEFINE_OP(op_has_structure_property)
+ DEFINE_OP(op_has_indexed_property)
+ DEFINE_OP(op_get_direct_pname)
+ DEFINE_OP(op_get_structure_property_enumerator)
+ DEFINE_OP(op_get_generic_property_enumerator)
+ DEFINE_OP(op_next_enumerator_pname)
+ DEFINE_OP(op_to_index_string)
default:
RELEASE_ASSERT_NOT_REACHED();
}
@@ -385,7 +392,6 @@
DEFINE_SLOWCASE_OP(op_get_arguments_length)
DEFINE_SLOWCASE_OP(op_get_by_val)
DEFINE_SLOWCASE_OP(op_get_argument_by_val)
- DEFINE_SLOWCASE_OP(op_get_by_pname)
DEFINE_SLOWCASE_OP(op_check_has_instance)
DEFINE_SLOWCASE_OP(op_instanceof)
DEFINE_SLOWCASE_OP(op_jfalse)
@@ -424,6 +430,9 @@
DEFINE_SLOWCASE_OP(op_sub)
DEFINE_SLOWCASE_OP(op_to_number)
DEFINE_SLOWCASE_OP(op_to_primitive)
+ DEFINE_SLOWCASE_OP(op_has_indexed_property)
+ DEFINE_SLOWCASE_OP(op_has_structure_property)
+ DEFINE_SLOWCASE_OP(op_get_direct_pname)
DEFINE_SLOWCASE_OP(op_resolve_scope)
DEFINE_SLOWCASE_OP(op_get_from_scope)
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index 520ea2a..641ecd3 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -56,7 +56,6 @@
class CodeBlock;
class FunctionExecutable;
class JIT;
- class JSPropertyNameIterator;
class Identifier;
class Interpreter;
class JSScope;
@@ -199,13 +198,6 @@
return JIT(vm, codeBlock).privateCompile(effort);
}
- static void compileClosureCall(VM* vm, CallLinkInfo* callLinkInfo, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, Structure* expectedStructure, ExecutableBase* expectedExecutable, MacroAssemblerCodePtr codePtr)
- {
- JIT jit(vm, callerCodeBlock);
- jit.m_bytecodeOffset = callLinkInfo->codeOrigin.bytecodeIndex;
- jit.privateCompileClosureCall(callLinkInfo, calleeCodeBlock, expectedStructure, expectedExecutable, codePtr);
- }
-
static void compileGetByVal(VM* vm, CodeBlock* codeBlock, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)
{
JIT jit(vm, codeBlock);
@@ -227,6 +219,13 @@
jit.privateCompilePutByVal(byValInfo, returnAddress, arrayMode);
}
+ static void compileHasIndexedProperty(VM* vm, CodeBlock* codeBlock, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)
+ {
+ JIT jit(vm, codeBlock);
+ jit.m_bytecodeOffset = byValInfo->bytecodeIndex;
+ jit.privateCompileHasIndexedProperty(byValInfo, returnAddress, arrayMode);
+ }
+
static CodeRef compileCTINativeCall(VM* vm, NativeFunction func)
{
if (!vm->canUseJIT()) {
@@ -247,11 +246,11 @@
void privateCompileSlowCases();
CompilationResult privateCompile(JITCompilationEffort);
- void privateCompileClosureCall(CallLinkInfo*, CodeBlock* calleeCodeBlock, Structure*, ExecutableBase*, MacroAssemblerCodePtr);
-
void privateCompileGetByVal(ByValInfo*, ReturnAddressPtr, JITArrayMode);
void privateCompilePutByVal(ByValInfo*, ReturnAddressPtr, JITArrayMode);
+ void privateCompileHasIndexedProperty(ByValInfo*, ReturnAddressPtr, JITArrayMode);
+
Label privateCompileCTINativeCall(VM*, bool isConstruct = false);
CodeRef privateCompileCTINativeCall(VM*, NativeFunction);
void privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress);
@@ -337,6 +336,12 @@
// Property is int-checked and zero extended. Base is cell checked.
// Structure is already profiled. Returns the slow cases. Fall-through
// case contains result in regT0, and it is not yet profiled.
+ JumpList emitInt32Load(Instruction* instruction, PatchableJump& badType) { return emitContiguousLoad(instruction, badType, Int32Shape); }
+ JumpList emitDoubleLoad(Instruction*, PatchableJump& badType);
+ JumpList emitContiguousLoad(Instruction*, PatchableJump& badType, IndexingType expectedShape = ContiguousShape);
+ JumpList emitArrayStorageLoad(Instruction*, PatchableJump& badType);
+ JumpList emitLoadForArrayMode(Instruction*, JITArrayMode, PatchableJump& badType);
+
JumpList emitInt32GetByVal(Instruction* instruction, PatchableJump& badType) { return emitContiguousGetByVal(instruction, badType, Int32Shape); }
JumpList emitDoubleGetByVal(Instruction*, PatchableJump& badType);
JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape = ContiguousShape);
@@ -478,7 +483,6 @@
void emit_op_get_arguments_length(Instruction*);
void emit_op_get_by_val(Instruction*);
void emit_op_get_argument_by_val(Instruction*);
- void emit_op_get_by_pname(Instruction*);
void emit_op_init_lazy_reg(Instruction*);
void emit_op_check_has_instance(Instruction*);
void emit_op_instanceof(Instruction*);
@@ -516,8 +520,6 @@
void emit_op_new_func_exp(Instruction*);
void emit_op_new_object(Instruction*);
void emit_op_new_regexp(Instruction*);
- void emit_op_get_pnames(Instruction*);
- void emit_op_next_pname(Instruction*);
void emit_op_not(Instruction*);
void emit_op_nstricteq(Instruction*);
void emit_op_pop_scope(Instruction*);
@@ -550,6 +552,15 @@
void emit_op_unexpected_load(Instruction*);
void emit_op_unsigned(Instruction*);
void emit_op_urshift(Instruction*);
+ void emit_op_get_enumerable_length(Instruction*);
+ void emit_op_has_generic_property(Instruction*);
+ void emit_op_has_structure_property(Instruction*);
+ void emit_op_has_indexed_property(Instruction*);
+ void emit_op_get_direct_pname(Instruction*);
+ void emit_op_get_structure_property_enumerator(Instruction*);
+ void emit_op_get_generic_property_enumerator(Instruction*);
+ void emit_op_next_enumerator_pname(Instruction*);
+ void emit_op_to_index_string(Instruction*);
void emitSlow_op_add(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_bitand(Instruction*, Vector<SlowCaseEntry>::iterator&);
@@ -570,7 +581,6 @@
void emitSlow_op_get_arguments_length(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_get_argument_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
- void emitSlow_op_get_by_pname(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_check_has_instance(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_instanceof(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_jfalse(Instruction*, Vector<SlowCaseEntry>::iterator&);
@@ -603,6 +613,9 @@
void emitSlow_op_to_primitive(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_unsigned(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_urshift(Instruction*, Vector<SlowCaseEntry>::iterator&);
+ void emitSlow_op_has_indexed_property(Instruction*, Vector<SlowCaseEntry>::iterator&);
+ void emitSlow_op_has_structure_property(Instruction*, Vector<SlowCaseEntry>::iterator&);
+ void emitSlow_op_get_direct_pname(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emit_op_resolve_scope(Instruction*);
void emit_op_get_from_scope(Instruction*);
diff --git a/Source/JavaScriptCore/jit/JITCall.cpp b/Source/JavaScriptCore/jit/JITCall.cpp
index 9f4d61f..140e16c 100644
--- a/Source/JavaScriptCore/jit/JITCall.cpp
+++ b/Source/JavaScriptCore/jit/JITCall.cpp
@@ -268,52 +268,6 @@
emitPutCallResult(instruction);
}
-void JIT::privateCompileClosureCall(CallLinkInfo* callLinkInfo, CodeBlock* calleeCodeBlock, Structure* expectedStructure, ExecutableBase* expectedExecutable, MacroAssemblerCodePtr codePtr)
-{
- JumpList slowCases;
-
- slowCases.append(branchTestPtr(NonZero, regT0, tagMaskRegister));
- slowCases.append(branchStructure(NotEqual, Address(regT0, JSCell::structureIDOffset()), expectedStructure));
- slowCases.append(branchPtr(NotEqual, Address(regT0, JSFunction::offsetOfExecutable()), TrustedImmPtr(expectedExecutable)));
-
- loadPtr(Address(regT0, JSFunction::offsetOfScopeChain()), regT1);
- emitPutToCallFrameHeader(regT1, JSStack::ScopeChain);
-
- Call call = nearCall();
- Jump done = jump();
-
- slowCases.link(this);
- move(TrustedImmPtr(callLinkInfo->callReturnLocation.executableAddress()), regT2);
- restoreReturnAddressBeforeReturn(regT2);
- Jump slow = jump();
-
- LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock);
-
- patchBuffer.link(call, FunctionPtr(codePtr.executableAddress()));
- patchBuffer.link(done, callLinkInfo->hotPathOther.labelAtOffset(0));
- patchBuffer.link(slow, CodeLocationLabel(m_vm->getCTIStub(virtualCallThunkGenerator).code()));
-
- RefPtr<ClosureCallStubRoutine> stubRoutine = adoptRef(new ClosureCallStubRoutine(
- FINALIZE_CODE(
- patchBuffer,
- ("Baseline closure call stub for %s, return point %p, target %p (%s)",
- toCString(*m_codeBlock).data(),
- callLinkInfo->hotPathOther.labelAtOffset(0).executableAddress(),
- codePtr.executableAddress(),
- toCString(pointerDump(calleeCodeBlock)).data())),
- *m_vm, m_codeBlock->ownerExecutable(), expectedStructure, expectedExecutable,
- callLinkInfo->codeOrigin));
-
- RepatchBuffer repatchBuffer(m_codeBlock);
-
- repatchBuffer.replaceWithJump(
- RepatchBuffer::startOfBranchPtrWithPatchOnRegister(callLinkInfo->hotPathBegin),
- CodeLocationLabel(stubRoutine->code().code()));
- repatchBuffer.relink(callLinkInfo->callReturnLocation, m_vm->getCTIStub(virtualCallThunkGenerator).code());
-
- callLinkInfo->stub = stubRoutine.release();
-}
-
void JIT::emit_op_call(Instruction* currentInstruction)
{
compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
diff --git a/Source/JavaScriptCore/jit/JITCall32_64.cpp b/Source/JavaScriptCore/jit/JITCall32_64.cpp
index 3a9feb2..f67162d 100644
--- a/Source/JavaScriptCore/jit/JITCall32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITCall32_64.cpp
@@ -359,52 +359,6 @@
emitPutCallResult(instruction);
}
-void JIT::privateCompileClosureCall(CallLinkInfo* callLinkInfo, CodeBlock* calleeCodeBlock, Structure* expectedStructure, ExecutableBase* expectedExecutable, MacroAssemblerCodePtr codePtr)
-{
- JumpList slowCases;
-
- slowCases.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
- slowCases.append(branchPtr(NotEqual, Address(regT0, JSCell::structureIDOffset()), TrustedImmPtr(expectedStructure)));
- slowCases.append(branchPtr(NotEqual, Address(regT0, JSFunction::offsetOfExecutable()), TrustedImmPtr(expectedExecutable)));
-
- loadPtr(Address(regT0, JSFunction::offsetOfScopeChain()), regT1);
- emitPutCellToCallFrameHeader(regT1, JSStack::ScopeChain);
-
- Call call = nearCall();
- Jump done = jump();
-
- slowCases.link(this);
- move(TrustedImmPtr(callLinkInfo->callReturnLocation.executableAddress()), regT2);
- restoreReturnAddressBeforeReturn(regT2);
- Jump slow = jump();
-
- LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock);
-
- patchBuffer.link(call, FunctionPtr(codePtr.executableAddress()));
- patchBuffer.link(done, callLinkInfo->hotPathOther.labelAtOffset(0));
- patchBuffer.link(slow, CodeLocationLabel(m_vm->getCTIStub(virtualCallThunkGenerator).code()));
-
- RefPtr<ClosureCallStubRoutine> stubRoutine = adoptRef(new ClosureCallStubRoutine(
- FINALIZE_CODE(
- patchBuffer,
- ("Baseline closure call stub for %s, return point %p, target %p (%s)",
- toCString(*m_codeBlock).data(),
- callLinkInfo->hotPathOther.labelAtOffset(0).executableAddress(),
- codePtr.executableAddress(),
- toCString(pointerDump(calleeCodeBlock)).data())),
- *m_vm, m_codeBlock->ownerExecutable(), expectedStructure, expectedExecutable,
- callLinkInfo->codeOrigin));
-
- RepatchBuffer repatchBuffer(m_codeBlock);
-
- repatchBuffer.replaceWithJump(
- RepatchBuffer::startOfBranchPtrWithPatchOnRegister(callLinkInfo->hotPathBegin),
- CodeLocationLabel(stubRoutine->code().code()));
- repatchBuffer.relink(callLinkInfo->callReturnLocation, m_vm->getCTIStub(virtualCallThunkGenerator).code());
-
- callLinkInfo->stub = stubRoutine.release();
-}
-
} // namespace JSC
#endif // USE(JSVALUE32_64)
diff --git a/Source/JavaScriptCore/jit/JITInlines.h b/Source/JavaScriptCore/jit/JITInlines.h
index 7072b5e..cdd23cb 100644
--- a/Source/JavaScriptCore/jit/JITInlines.h
+++ b/Source/JavaScriptCore/jit/JITInlines.h
@@ -32,6 +32,50 @@
namespace JSC {
+#if USE(JSVALUE64)
+inline MacroAssembler::JumpList JIT::emitDoubleGetByVal(Instruction* instruction, PatchableJump& badType)
+{
+ JumpList slowCases = emitDoubleLoad(instruction, badType);
+ moveDoubleTo64(fpRegT0, regT0);
+ sub64(tagTypeNumberRegister, regT0);
+ return slowCases;
+}
+#else
+inline MacroAssembler::JumpList JIT::emitDoubleGetByVal(Instruction* instruction, PatchableJump& badType)
+{
+ JumpList slowCases = emitDoubleLoad(instruction, badType);
+ moveDoubleToInts(fpRegT0, regT0, regT1);
+ return slowCases;
+}
+#endif // USE(JSVALUE64)
+
+ALWAYS_INLINE MacroAssembler::JumpList JIT::emitLoadForArrayMode(Instruction* currentInstruction, JITArrayMode arrayMode, PatchableJump& badType)
+{
+ switch (arrayMode) {
+ case JITInt32:
+ return emitInt32Load(currentInstruction, badType);
+ case JITDouble:
+ return emitDoubleLoad(currentInstruction, badType);
+ case JITContiguous:
+ return emitContiguousLoad(currentInstruction, badType);
+ case JITArrayStorage:
+ return emitArrayStorageLoad(currentInstruction, badType);
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+inline MacroAssembler::JumpList JIT::emitContiguousGetByVal(Instruction* instruction, PatchableJump& badType, IndexingType expectedShape)
+{
+ return emitContiguousLoad(instruction, badType, expectedShape);
+}
+
+inline MacroAssembler::JumpList JIT::emitArrayStorageGetByVal(Instruction* instruction, PatchableJump& badType)
+{
+ return emitArrayStorageLoad(instruction, badType);
+}
+
ALWAYS_INLINE bool JIT::isOperandConstantImmediateDouble(int src)
{
return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isDouble();
diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp
index de8adc4..b34d3b8 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2012, 2013, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
*
* Redistribution and use in source and binary forms, with or without
@@ -36,8 +36,10 @@
#include "JSArray.h"
#include "JSCell.h"
#include "JSFunction.h"
-#include "JSPropertyNameIterator.h"
+#include "JSPropertyNameEnumerator.h"
+#include "LinkBuffer.h"
#include "MaxFrameExtentForSlowPathCall.h"
+#include "RepatchBuffer.h"
#include "SlowPathCall.h"
#include "VirtualRegister.h"
@@ -456,106 +458,6 @@
jumpToExceptionHandler();
}
-void JIT::emit_op_get_pnames(Instruction* currentInstruction)
-{
- int dst = currentInstruction[1].u.operand;
- int base = currentInstruction[2].u.operand;
- int i = currentInstruction[3].u.operand;
- int size = currentInstruction[4].u.operand;
- int breakTarget = currentInstruction[5].u.operand;
-
- JumpList isNotObject;
-
- emitGetVirtualRegister(base, regT0);
- if (!m_codeBlock->isKnownNotImmediate(base))
- isNotObject.append(emitJumpIfNotJSCell(regT0));
- if (base != m_codeBlock->thisRegister().offset() || m_codeBlock->isStrictMode())
- isNotObject.append(emitJumpIfCellNotObject(regT0));
-
- // We could inline the case where you have a valid cache, but
- // this call doesn't seem to be hot.
- Label isObject(this);
- callOperation(operationGetPNames, regT0);
- emitStoreCell(dst, returnValueGPR);
- load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3);
- store64(tagTypeNumberRegister, addressFor(i));
- store32(TrustedImm32(Int32Tag), intTagFor(size));
- store32(regT3, intPayloadFor(size));
- Jump end = jump();
-
- isNotObject.link(this);
- move(regT0, regT1);
- and32(TrustedImm32(~TagBitUndefined), regT1);
- addJump(branch32(Equal, regT1, TrustedImm32(ValueNull)), breakTarget);
- callOperation(operationToObject, base, regT0);
- jump().linkTo(isObject, this);
-
- end.link(this);
-}
-
-void JIT::emit_op_next_pname(Instruction* currentInstruction)
-{
- int dst = currentInstruction[1].u.operand;
- int base = currentInstruction[2].u.operand;
- int i = currentInstruction[3].u.operand;
- int size = currentInstruction[4].u.operand;
- int it = currentInstruction[5].u.operand;
- int target = currentInstruction[6].u.operand;
-
- JumpList callHasProperty;
-
- Label begin(this);
- load32(intPayloadFor(i), regT0);
- Jump end = branch32(Equal, regT0, intPayloadFor(size));
-
- // Grab key @ i
- loadPtr(addressFor(it), regT1);
- loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2);
-
- load64(BaseIndex(regT2, regT0, TimesEight), regT2);
-
- emitPutVirtualRegister(dst, regT2);
-
- // Increment i
- add32(TrustedImm32(1), regT0);
- store32(regT0, intPayloadFor(i));
-
- // Verify that i is valid:
- emitGetVirtualRegister(base, regT0);
-
- // Test base's structure
- emitLoadStructure(regT0, regT2, regT3);
- callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))));
-
- // Test base's prototype chain
- loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3);
- loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3);
- addJump(branchTestPtr(Zero, Address(regT3)), target);
-
- Label checkPrototype(this);
- load64(Address(regT2, Structure::prototypeOffset()), regT2);
- callHasProperty.append(emitJumpIfNotJSCell(regT2));
- emitLoadStructure(regT2, regT2, regT1);
- callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3)));
- addPtr(TrustedImm32(sizeof(Structure*)), regT3);
- branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this);
-
- // Continue loop.
- addJump(jump(), target);
-
- // Slow case: Ask the object if i is valid.
- callHasProperty.link(this);
- emitGetVirtualRegister(dst, regT1);
- callOperation(operationHasProperty, regT0, regT1);
-
- // Test for valid key.
- addJump(branchTest32(NonZero, regT0), target);
- jump().linkTo(begin, this);
-
- // End of loop.
- end.link(this);
-}
-
void JIT::emit_op_push_with_scope(Instruction* currentInstruction)
{
emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
@@ -1209,6 +1111,235 @@
slowPathCall.call();
}
+#if USE(JSVALUE64)
+void JIT::emit_op_get_enumerable_length(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_enumerable_length);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_has_structure_property(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int enumerator = currentInstruction[4].u.operand;
+
+ emitGetVirtualRegister(base, regT0);
+ emitGetVirtualRegister(enumerator, regT1);
+ emitJumpSlowCaseIfNotJSCell(regT0, base);
+
+ load32(Address(regT0, JSCell::structureIDOffset()), regT0);
+ addSlowCase(branch32(NotEqual, regT0, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset())));
+
+ move(TrustedImm32(ValueTrue), regT0);
+ emitPutVirtualRegister(dst);
+}
+
+void JIT::emitSlow_op_has_structure_property(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ linkSlowCase(iter);
+ linkSlowCase(iter);
+
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_has_structure_property);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_has_generic_property(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_has_generic_property);
+ slowPathCall.call();
+}
+
+void JIT::privateCompileHasIndexedProperty(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)
+{
+ Instruction* currentInstruction = m_codeBlock->instructions().begin() + byValInfo->bytecodeIndex;
+
+ PatchableJump badType;
+
+ // FIXME: Add support for other types like TypedArrays and Arguments.
+ // See https://bugs.webkit.org/show_bug.cgi?id=135033 and https://bugs.webkit.org/show_bug.cgi?id=135034.
+ JumpList slowCases = emitLoadForArrayMode(currentInstruction, arrayMode, badType);
+ move(TrustedImm64(JSValue::encode(jsBoolean(true))), regT0);
+ Jump done = jump();
+
+ LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock);
+
+ patchBuffer.link(badType, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(returnAddress.value())).labelAtOffset(byValInfo->returnAddressToSlowPath));
+ patchBuffer.link(slowCases, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(returnAddress.value())).labelAtOffset(byValInfo->returnAddressToSlowPath));
+
+ patchBuffer.link(done, byValInfo->badTypeJump.labelAtOffset(byValInfo->badTypeJumpToDone));
+
+ byValInfo->stubRoutine = FINALIZE_CODE_FOR_STUB(
+ m_codeBlock, patchBuffer,
+ ("Baseline has_indexed_property stub for %s, return point %p", toCString(*m_codeBlock).data(), returnAddress.value()));
+
+ RepatchBuffer repatchBuffer(m_codeBlock);
+ repatchBuffer.relink(byValInfo->badTypeJump, CodeLocationLabel(byValInfo->stubRoutine->code().code()));
+ repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(operationHasIndexedPropertyGeneric));
+}
+
+void JIT::emit_op_has_indexed_property(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int property = currentInstruction[3].u.operand;
+ ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+
+ emitGetVirtualRegisters(base, regT0, property, regT1);
+
+ // This is technically incorrect - we're zero-extending an int32. On the hot path this doesn't matter.
+ // We check the value as if it was a uint32 against the m_vectorLength - which will always fail if
+ // number was signed since m_vectorLength is always less than intmax (since the total allocation
+ // size is always less than 4Gb). As such zero extending will have been correct (and extending the value
+ // to 64-bits is necessary since it's used in the address calculation. We zero extend rather than sign
+ // extending since it makes it easier to re-tag the value in the slow case.
+ zeroExtend32ToPtr(regT1, regT1);
+
+ emitJumpSlowCaseIfNotJSCell(regT0, base);
+ emitArrayProfilingSiteWithCell(regT0, regT2, profile);
+ and32(TrustedImm32(IndexingShapeMask), regT2);
+
+ JITArrayMode mode = chooseArrayMode(profile);
+ PatchableJump badType;
+
+ // FIXME: Add support for other types like TypedArrays and Arguments.
+ // See https://bugs.webkit.org/show_bug.cgi?id=135033 and https://bugs.webkit.org/show_bug.cgi?id=135034.
+ JumpList slowCases = emitLoadForArrayMode(currentInstruction, mode, badType);
+
+ move(TrustedImm64(JSValue::encode(jsBoolean(true))), regT0);
+
+ addSlowCase(badType);
+ addSlowCase(slowCases);
+
+ Label done = label();
+
+ emitPutVirtualRegister(dst);
+
+ m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
+}
+
+void JIT::emitSlow_op_has_indexed_property(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int property = currentInstruction[3].u.operand;
+ ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+
+ linkSlowCaseIfNotJSCell(iter, base); // base cell check
+ linkSlowCase(iter); // base array check
+
+ Jump skipProfiling = jump();
+
+ linkSlowCase(iter); // vector length check
+ linkSlowCase(iter); // empty value
+
+ emitArrayProfileOutOfBoundsSpecialCase(profile);
+
+ skipProfiling.link(this);
+
+ Label slowPath = label();
+
+ emitGetVirtualRegister(base, regT0);
+ emitGetVirtualRegister(property, regT1);
+ Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT0, regT1);
+
+ m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
+ m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
+ m_byValInstructionIndex++;
+}
+
+void JIT::emit_op_get_direct_pname(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int index = currentInstruction[4].u.operand;
+ int enumerator = currentInstruction[5].u.operand;
+
+ // Check that base is a cell
+ emitGetVirtualRegister(base, regT0);
+ emitJumpSlowCaseIfNotJSCell(regT0, base);
+
+ // Check the structure
+ emitGetVirtualRegister(enumerator, regT2);
+ load32(Address(regT0, JSCell::structureIDOffset()), regT1);
+ addSlowCase(branch32(NotEqual, regT1, Address(regT2, JSPropertyNameEnumerator::cachedStructureIDOffset())));
+
+ // Compute the offset
+ emitGetVirtualRegister(index, regT1);
+ // If index is less than the enumerator's cached inline storage, then it's an inline access
+ Jump outOfLineAccess = branch32(AboveOrEqual, regT1, Address(regT2, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
+ addPtr(TrustedImm32(JSObject::offsetOfInlineStorage()), regT0);
+ signExtend32ToPtr(regT1, regT1);
+ load64(BaseIndex(regT0, regT1, TimesEight), regT0);
+
+ Jump done = jump();
+
+ // Otherwise it's out of line
+ outOfLineAccess.link(this);
+ loadPtr(Address(regT0, JSObject::butterflyOffset()), regT0);
+ sub32(Address(regT2, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), regT1);
+ neg32(regT1);
+ signExtend32ToPtr(regT1, regT1);
+ int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
+ load64(BaseIndex(regT0, regT1, TimesEight, offsetOfFirstProperty), regT0);
+
+ done.link(this);
+ emitValueProfilingSite();
+ emitPutVirtualRegister(dst, regT0);
+}
+
+void JIT::emitSlow_op_get_direct_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ int base = currentInstruction[2].u.operand;
+ linkSlowCaseIfNotJSCell(iter, base);
+ linkSlowCase(iter);
+
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_direct_pname);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_get_structure_property_enumerator(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_structure_property_enumerator);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_get_generic_property_enumerator(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_generic_property_enumerator);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_next_enumerator_pname(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int enumerator = currentInstruction[2].u.operand;
+ int index = currentInstruction[3].u.operand;
+
+ emitGetVirtualRegister(index, regT0);
+ emitGetVirtualRegister(enumerator, regT1);
+ Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()));
+
+ move(TrustedImm32(ValueNull), regT0);
+
+ Jump done = jump();
+ inBounds.link(this);
+
+ loadPtr(Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), regT1);
+ signExtend32ToPtr(regT0, regT0);
+ load64(BaseIndex(regT1, regT0, TimesEight), regT0);
+
+ done.link(this);
+ emitPutVirtualRegister(dst);
+}
+
+void JIT::emit_op_to_index_string(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_to_index_string);
+ slowPathCall.call();
+}
+#endif // USE(JSVALUE64)
+
} // namespace JSC
#endif // ENABLE(JIT)
diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
index a540d6e..e1d34d9 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -36,10 +36,11 @@
#include "JSArray.h"
#include "JSCell.h"
#include "JSFunction.h"
-#include "JSPropertyNameIterator.h"
+#include "JSPropertyNameEnumerator.h"
#include "JSVariableObject.h"
#include "LinkBuffer.h"
#include "MaxFrameExtentForSlowPathCall.h"
+#include "RepatchBuffer.h"
#include "SlowPathCall.h"
#include "VirtualRegister.h"
@@ -767,105 +768,6 @@
jumpToExceptionHandler();
}
-void JIT::emit_op_get_pnames(Instruction* currentInstruction)
-{
- int dst = currentInstruction[1].u.operand;
- int base = currentInstruction[2].u.operand;
- int i = currentInstruction[3].u.operand;
- int size = currentInstruction[4].u.operand;
- int breakTarget = currentInstruction[5].u.operand;
-
- JumpList isNotObject;
-
- emitLoad(base, regT1, regT0);
- if (!m_codeBlock->isKnownNotImmediate(base))
- isNotObject.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
- if (VirtualRegister(base) != m_codeBlock->thisRegister() || m_codeBlock->isStrictMode())
- isNotObject.append(emitJumpIfCellNotObject(regT0));
-
- // We could inline the case where you have a valid cache, but
- // this call doesn't seem to be hot.
- Label isObject(this);
- callOperation(operationGetPNames, regT0);
- emitStoreCell(dst, returnValueGPR);
- load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3);
- store32(TrustedImm32(Int32Tag), intTagFor(i));
- store32(TrustedImm32(0), intPayloadFor(i));
- store32(TrustedImm32(Int32Tag), intTagFor(size));
- store32(regT3, payloadFor(size));
- Jump end = jump();
-
- isNotObject.link(this);
- addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), breakTarget);
- addJump(branch32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag)), breakTarget);
- callOperation(operationToObject, base, regT1, regT0);
- jump().linkTo(isObject, this);
-
- end.link(this);
-}
-
-void JIT::emit_op_next_pname(Instruction* currentInstruction)
-{
- int dst = currentInstruction[1].u.operand;
- int base = currentInstruction[2].u.operand;
- int i = currentInstruction[3].u.operand;
- int size = currentInstruction[4].u.operand;
- int it = currentInstruction[5].u.operand;
- int target = currentInstruction[6].u.operand;
-
- JumpList callHasProperty;
-
- Label begin(this);
- load32(intPayloadFor(i), regT0);
- Jump end = branch32(Equal, regT0, intPayloadFor(size));
-
- // Grab key @ i
- loadPtr(payloadFor(it), regT1);
- loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2);
- load32(BaseIndex(regT2, regT0, TimesEight), regT2);
- store32(TrustedImm32(JSValue::CellTag), tagFor(dst));
- store32(regT2, payloadFor(dst));
-
- // Increment i
- add32(TrustedImm32(1), regT0);
- store32(regT0, intPayloadFor(i));
-
- // Verify that i is valid:
- loadPtr(payloadFor(base), regT0);
-
- // Test base's structure
- loadPtr(Address(regT0, JSCell::structureIDOffset()), regT2);
- callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))));
-
- // Test base's prototype chain
- loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3);
- loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3);
- addJump(branchTestPtr(Zero, Address(regT3)), target);
-
- Label checkPrototype(this);
- callHasProperty.append(branch32(Equal, Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::NullTag)));
- loadPtr(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
- loadPtr(Address(regT2, JSCell::structureIDOffset()), regT2);
- callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3)));
- addPtr(TrustedImm32(sizeof(Structure*)), regT3);
- branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this);
-
- // Continue loop.
- addJump(jump(), target);
-
- // Slow case: Ask the object if i is valid.
- callHasProperty.link(this);
- loadPtr(addressFor(dst), regT1);
- callOperation(operationHasProperty, regT0, regT1);
-
- // Test for valid key.
- addJump(branchTest32(NonZero, regT0), target);
- jump().linkTo(begin, this);
-
- // End of loop.
- end.link(this);
-}
-
void JIT::emit_op_push_with_scope(Instruction* currentInstruction)
{
emitLoad(currentInstruction[1].u.operand, regT1, regT0);
@@ -1176,6 +1078,236 @@
callOperation(WithProfile, operationGetByValGeneric, dst, regT1, regT0, regT3, regT2);
}
+void JIT::emit_op_get_enumerable_length(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_enumerable_length);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_has_structure_property(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int enumerator = currentInstruction[4].u.operand;
+
+ emitLoadPayload(base, regT0);
+ emitJumpSlowCaseIfNotJSCell(base);
+
+ emitLoadPayload(enumerator, regT1);
+
+ load32(Address(regT0, JSCell::structureIDOffset()), regT0);
+ addSlowCase(branch32(NotEqual, regT0, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset())));
+
+ move(TrustedImm32(1), regT0);
+ emitStoreBool(dst, regT0);
+}
+
+void JIT::emitSlow_op_has_structure_property(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ linkSlowCase(iter);
+ linkSlowCase(iter);
+
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_has_structure_property);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_has_generic_property(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_has_generic_property);
+ slowPathCall.call();
+}
+
+void JIT::privateCompileHasIndexedProperty(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)
+{
+ Instruction* currentInstruction = m_codeBlock->instructions().begin() + byValInfo->bytecodeIndex;
+
+ PatchableJump badType;
+
+ // FIXME: Add support for other types like TypedArrays and Arguments.
+ // See https://bugs.webkit.org/show_bug.cgi?id=135033 and https://bugs.webkit.org/show_bug.cgi?id=135034.
+ JumpList slowCases = emitLoadForArrayMode(currentInstruction, arrayMode, badType);
+ move(TrustedImm32(1), regT0);
+ Jump done = jump();
+
+ LinkBuffer patchBuffer(*m_vm, this, m_codeBlock);
+
+ patchBuffer.link(badType, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(returnAddress.value())).labelAtOffset(byValInfo->returnAddressToSlowPath));
+ patchBuffer.link(slowCases, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(returnAddress.value())).labelAtOffset(byValInfo->returnAddressToSlowPath));
+
+ patchBuffer.link(done, byValInfo->badTypeJump.labelAtOffset(byValInfo->badTypeJumpToDone));
+
+ byValInfo->stubRoutine = FINALIZE_CODE_FOR_STUB(
+ m_codeBlock, patchBuffer,
+ ("Baseline has_indexed_property stub for %s, return point %p", toCString(*m_codeBlock).data(), returnAddress.value()));
+
+ RepatchBuffer repatchBuffer(m_codeBlock);
+ repatchBuffer.relink(byValInfo->badTypeJump, CodeLocationLabel(byValInfo->stubRoutine->code().code()));
+ repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(operationHasIndexedPropertyGeneric));
+}
+
+void JIT::emit_op_has_indexed_property(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int property = currentInstruction[3].u.operand;
+ ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+
+ emitLoadPayload(base, regT0);
+ emitJumpSlowCaseIfNotJSCell(base);
+
+ emitLoadPayload(property, regT1);
+
+ // This is technically incorrect - we're zero-extending an int32. On the hot path this doesn't matter.
+ // We check the value as if it was a uint32 against the m_vectorLength - which will always fail if
+ // number was signed since m_vectorLength is always less than intmax (since the total allocation
+ // size is always less than 4Gb). As such zero extending will have been correct (and extending the value
+ // to 64-bits is necessary since it's used in the address calculation. We zero extend rather than sign
+ // extending since it makes it easier to re-tag the value in the slow case.
+ zeroExtend32ToPtr(regT1, regT1);
+
+ emitArrayProfilingSiteWithCell(regT0, regT2, profile);
+ and32(TrustedImm32(IndexingShapeMask), regT2);
+
+ JITArrayMode mode = chooseArrayMode(profile);
+ PatchableJump badType;
+
+ // FIXME: Add support for other types like TypedArrays and Arguments.
+ // See https://bugs.webkit.org/show_bug.cgi?id=135033 and https://bugs.webkit.org/show_bug.cgi?id=135034.
+ JumpList slowCases = emitLoadForArrayMode(currentInstruction, mode, badType);
+ move(TrustedImm32(1), regT0);
+
+ addSlowCase(badType);
+ addSlowCase(slowCases);
+
+ Label done = label();
+
+ emitStoreBool(dst, regT0);
+
+ m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
+}
+
+void JIT::emitSlow_op_has_indexed_property(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int property = currentInstruction[3].u.operand;
+ ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+
+ linkSlowCaseIfNotJSCell(iter, base); // base cell check
+ linkSlowCase(iter); // base array check
+
+ Jump skipProfiling = jump();
+
+ linkSlowCase(iter); // vector length check
+ linkSlowCase(iter); // empty value
+
+ emitArrayProfileOutOfBoundsSpecialCase(profile);
+
+ skipProfiling.link(this);
+
+ Label slowPath = label();
+
+ emitLoad(base, regT1, regT0);
+ emitLoad(property, regT3, regT2);
+ Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT1, regT0, regT3, regT2);
+
+ m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
+ m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
+ m_byValInstructionIndex++;
+}
+
+void JIT::emit_op_get_direct_pname(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int index = currentInstruction[4].u.operand;
+ int enumerator = currentInstruction[5].u.operand;
+
+ // Check that base is a cell
+ emitLoadPayload(base, regT0);
+ emitJumpSlowCaseIfNotJSCell(base);
+
+ // Check the structure
+ emitLoadPayload(enumerator, regT1);
+ load32(Address(regT0, JSCell::structureIDOffset()), regT2);
+ addSlowCase(branch32(NotEqual, regT2, Address(regT1, JSPropertyNameEnumerator::cachedStructureIDOffset())));
+
+ // Compute the offset
+ emitLoadPayload(index, regT2);
+ // If index is less than the enumerator's cached inline storage, then it's an inline access
+ Jump outOfLineAccess = branch32(AboveOrEqual, regT2, Address(regT1, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
+ addPtr(TrustedImm32(JSObject::offsetOfInlineStorage()), regT0);
+ load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+ load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+
+ Jump done = jump();
+
+ // Otherwise it's out of line
+ outOfLineAccess.link(this);
+ loadPtr(Address(regT0, JSObject::butterflyOffset()), regT0);
+ sub32(Address(regT1, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), regT2);
+ neg32(regT2);
+ int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
+ load32(BaseIndex(regT0, regT2, TimesEight, offsetOfFirstProperty + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+ load32(BaseIndex(regT0, regT2, TimesEight, offsetOfFirstProperty + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+
+ done.link(this);
+ emitValueProfilingSite();
+ emitStore(dst, regT1, regT0);
+}
+
+void JIT::emitSlow_op_get_direct_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ int base = currentInstruction[2].u.operand;
+ linkSlowCaseIfNotJSCell(iter, base);
+ linkSlowCase(iter);
+
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_direct_pname);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_get_structure_property_enumerator(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_structure_property_enumerator);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_get_generic_property_enumerator(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_generic_property_enumerator);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_next_enumerator_pname(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int enumerator = currentInstruction[2].u.operand;
+ int index = currentInstruction[3].u.operand;
+
+ emitLoadPayload(index, regT0);
+ emitLoadPayload(enumerator, regT1);
+ Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()));
+
+ move(TrustedImm32(JSValue::NullTag), regT2);
+ move(TrustedImm32(0), regT0);
+
+ Jump done = jump();
+ inBounds.link(this);
+
+ loadPtr(Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), regT1);
+ loadPtr(BaseIndex(regT1, regT0, timesPtr()), regT0);
+ move(TrustedImm32(JSValue::CellTag), regT2);
+
+ done.link(this);
+ emitStore(dst, regT2, regT0);
+}
+
+void JIT::emit_op_to_index_string(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_to_index_string);
+ slowPathCall.call();
+}
+
} // namespace JSC
#endif // USE(JSVALUE32_64)
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index 169ce43..b1b608e4 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -45,7 +45,7 @@
#include "JITToDFGDeferredCompilationCallback.h"
#include "JSGlobalObjectFunctions.h"
#include "JSNameScope.h"
-#include "JSPropertyNameIterator.h"
+#include "JSPropertyNameEnumerator.h"
#include "JSStackInlines.h"
#include "JSWithScope.h"
#include "ObjectConstructor.h"
@@ -776,13 +776,10 @@
if (!calleeAsFunctionCell)
return false;
- VM& vm = execCallee->vm();
JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell);
JSFunction* oldCallee = callLinkInfo.callee.get();
- if (!oldCallee
- || oldCallee->structure(vm) != callee->structure(vm)
- || oldCallee->executable() != callee->executable())
+ if (!oldCallee || oldCallee->executable() != callee->executable())
return false;
ASSERT(callee->executable()->hasJITCodeForCall());
@@ -801,8 +798,7 @@
}
linkClosureCall(
- execCallee, callLinkInfo, codeBlock,
- callee->structure(), callee->executable(), codePtr, registers);
+ execCallee, callLinkInfo, codeBlock, callee->executable(), codePtr, registers);
return true;
}
@@ -1498,6 +1494,64 @@
return JSValue::encode(result);
}
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ JSValue baseValue = JSValue::decode(encodedBase);
+ JSValue subscript = JSValue::decode(encodedSubscript);
+
+ ASSERT(baseValue.isObject());
+ ASSERT(subscript.isUInt32());
+
+ JSObject* object = asObject(baseValue);
+ bool didOptimize = false;
+
+ unsigned bytecodeOffset = exec->locationAsBytecodeOffset();
+ ASSERT(bytecodeOffset);
+ ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1);
+ ASSERT(!byValInfo.stubRoutine);
+
+ if (hasOptimizableIndexing(object->structure(vm))) {
+ // Attempt to optimize.
+ JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm));
+ if (arrayMode != byValInfo.arrayMode) {
+ JIT::compileHasIndexedProperty(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
+ didOptimize = true;
+ }
+ }
+
+ if (!didOptimize) {
+ // If we take slow path more than 10 times without patching then make sure we
+ // never make that mistake again. Or, if we failed to patch and we have some object
+ // that intercepts indexed get, then don't even wait until 10 times. For cases
+ // where we see non-index-intercepting objects, this gives 10 iterations worth of
+ // opportunity for us to observe that the get_by_val may be polymorphic.
+ if (++byValInfo.slowPathCount >= 10
+ || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
+ // Don't ever try to optimize.
+ RepatchBuffer repatchBuffer(exec->codeBlock());
+ repatchBuffer.relinkCallerToFunction(ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationHasIndexedPropertyGeneric));
+ }
+ }
+
+ return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript.asUInt32())));
+}
+
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ JSValue baseValue = JSValue::decode(encodedBase);
+ JSValue subscript = JSValue::decode(encodedSubscript);
+
+ ASSERT(baseValue.isObject());
+ ASSERT(subscript.isUInt32());
+
+ JSObject* object = asObject(baseValue);
+ return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript.asUInt32())));
+}
+
EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
{
VM& vm = exec->vm();
@@ -1557,18 +1611,6 @@
return JSValue::encode(result);
}
-JSCell* JIT_OPERATION operationGetPNames(ExecState* exec, JSObject* obj)
-{
- VM& vm = exec->vm();
- NativeCallFrameTracer tracer(&vm, exec);
-
- Structure* structure = obj->structure(vm);
- JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
- if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(exec))
- jsPropertyNameIterator = JSPropertyNameIterator::create(exec, obj);
- return jsPropertyNameIterator;
-}
-
EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedProto)
{
VM& vm = exec->vm();
@@ -1813,6 +1855,72 @@
#endif // COMPILER(CLANG)
}
+int32_t JIT_OPERATION operationGetEnumerableLength(ExecState* exec, JSCell* baseCell)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ JSObject* base = baseCell->toObject(exec, exec->lexicalGlobalObject());
+ return base->methodTable(vm)->getEnumerableLength(exec, base);
+}
+
+EncodedJSValue JIT_OPERATION operationHasGenericProperty(ExecState* exec, EncodedJSValue encodedBaseValue, JSCell* propertyName)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ JSValue baseValue = JSValue::decode(encodedBaseValue);
+ if (baseValue.isUndefinedOrNull())
+ return JSValue::encode(jsBoolean(false));
+
+ JSObject* base = baseValue.toObject(exec);
+ return JSValue::encode(jsBoolean(base->hasProperty(exec, asString(propertyName)->toIdentifier(exec))));
+}
+
+EncodedJSValue JIT_OPERATION operationHasIndexedProperty(ExecState* exec, JSCell* baseCell, int32_t subscript)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ JSObject* object = baseCell->toObject(exec, exec->lexicalGlobalObject());
+ return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript)));
+}
+
+JSCell* JIT_OPERATION operationGetStructurePropertyEnumerator(ExecState* exec, JSCell* cell, int32_t length)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ JSObject* base = cell->toObject(exec, exec->lexicalGlobalObject());
+ ASSERT(length >= 0);
+
+ return structurePropertyNameEnumerator(exec, base, static_cast<uint32_t>(length));
+}
+
+JSCell* JIT_OPERATION operationGetGenericPropertyEnumerator(ExecState* exec, JSCell* baseCell, int32_t length, JSCell* structureEnumeratorCell)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ JSObject* base = baseCell->toObject(exec, exec->lexicalGlobalObject());
+ ASSERT(length >= 0);
+
+ return genericPropertyNameEnumerator(exec, base, length, jsCast<JSPropertyNameEnumerator*>(structureEnumeratorCell));
+}
+
+EncodedJSValue JIT_OPERATION operationNextEnumeratorPname(ExecState* exec, JSCell* enumeratorCell, int32_t index)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorCell);
+ JSString* propertyName = enumerator->propertyNameAtIndex(index);
+ return JSValue::encode(propertyName ? propertyName : jsNull());
+}
+
+JSCell* JIT_OPERATION operationToIndexString(ExecState* exec, int32_t index)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ return jsString(exec, Identifier::from(exec, index).string());
+}
+
} // extern "C"
// Note: getHostCallReturnValueWithExecState() needs to be placed before the
diff --git a/Source/JavaScriptCore/jit/JITOperations.h b/Source/JavaScriptCore/jit/JITOperations.h
index 0cbeae0..88b47bc 100644
--- a/Source/JavaScriptCore/jit/JITOperations.h
+++ b/Source/JavaScriptCore/jit/JITOperations.h
@@ -97,10 +97,13 @@
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_ECI)(ExecState*, JSCell*, StringImpl*);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_ECZ)(ExecState*, JSCell*, int32_t);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EDA)(ExecState*, double, JSArray*);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EE)(ExecState*, ExecState*);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EI)(ExecState*, StringImpl*);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJ)(ExecState*, EncodedJSValue);
+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);
+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJC)(ExecState*, EncodedJSValue, JSCell*);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJA)(ExecState*, EncodedJSValue, JSArray*);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJIdc)(ExecState*, EncodedJSValue, const Identifier*);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
@@ -119,9 +122,14 @@
typedef JSCell* JIT_OPERATION (*C_JITOperation_E)(ExecState*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EZ)(ExecState*, int32_t);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EC)(ExecState*, JSCell*);
+typedef JSCell* JIT_OPERATION (*C_JITOperation_ECZ)(ExecState*, JSCell*, int32_t);
+typedef JSCell* JIT_OPERATION (*C_JITOperation_ECZC)(ExecState*, JSCell*, int32_t, JSCell*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EIcf)(ExecState*, InlineCallFrame*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EJ)(ExecState*, EncodedJSValue);
+typedef JSCell* JIT_OPERATION (*C_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);
+typedef JSCell* JIT_OPERATION (*C_JITOperation_EJZC)(ExecState*, EncodedJSValue, int32_t, JSCell*);
+typedef JSCell* JIT_OPERATION (*C_JITOperation_EJJC)(ExecState*, EncodedJSValue, EncodedJSValue, JSCell*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EJssSt)(ExecState*, JSString*, Structure*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EJssJss)(ExecState*, JSString*, JSString*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EJssJssJss)(ExecState*, JSString*, JSString*, JSString*);
@@ -137,6 +145,7 @@
typedef int64_t JIT_OPERATION(*Q_JITOperation_D)(double);
typedef int32_t JIT_OPERATION (*Z_JITOperation_D)(double);
typedef int32_t JIT_OPERATION (*Z_JITOperation_E)(ExecState*);
+typedef int32_t JIT_OPERATION (*Z_JITOperation_EC)(ExecState*, JSCell*);
typedef size_t JIT_OPERATION (*S_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef size_t JIT_OPERATION (*S_JITOperation_EJ)(ExecState*, EncodedJSValue);
typedef size_t JIT_OPERATION (*S_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
@@ -280,6 +289,8 @@
EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationGetByValString(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
void JIT_OPERATION operationTearOffActivation(ExecState*, JSCell*) WTF_INTERNAL;
void JIT_OPERATION operationTearOffArguments(ExecState*, JSCell*, JSCell*) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationDeleteById(ExecState*, EncodedJSValue base, const Identifier*) WTF_INTERNAL;
@@ -305,6 +316,14 @@
void JIT_OPERATION operationExceptionFuzz();
+int32_t JIT_OPERATION operationGetEnumerableLength(ExecState*, JSCell*);
+EncodedJSValue JIT_OPERATION operationHasGenericProperty(ExecState*, EncodedJSValue, JSCell*);
+EncodedJSValue JIT_OPERATION operationHasIndexedProperty(ExecState*, JSCell*, int32_t);
+JSCell* JIT_OPERATION operationGetStructurePropertyEnumerator(ExecState*, JSCell*, int32_t);
+JSCell* JIT_OPERATION operationGetGenericPropertyEnumerator(ExecState*, JSCell*, int32_t, JSCell*);
+EncodedJSValue JIT_OPERATION operationNextEnumeratorPname(ExecState*, JSCell*, int32_t);
+JSCell* JIT_OPERATION operationToIndexString(ExecState*, int32_t);
+
} // extern "C"
inline P_JITOperation_ECli operationLinkFor(
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
index a155baa..da5dab7 100644
--- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
+++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
@@ -35,7 +35,6 @@
#include "JITInlines.h"
#include "JSArray.h"
#include "JSFunction.h"
-#include "JSPropertyNameIterator.h"
#include "JSVariableObject.h"
#include "LinkBuffer.h"
#include "RepatchBuffer.h"
@@ -151,7 +150,7 @@
m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
}
-JIT::JumpList JIT::emitDoubleGetByVal(Instruction*, PatchableJump& badType)
+JIT::JumpList JIT::emitDoubleLoad(Instruction*, PatchableJump& badType)
{
JumpList slowCases;
@@ -160,13 +159,11 @@
slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength())));
loadDouble(BaseIndex(regT2, regT1, TimesEight), fpRegT0);
slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
- moveDoubleTo64(fpRegT0, regT0);
- sub64(tagTypeNumberRegister, regT0);
return slowCases;
}
-JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape)
+JIT::JumpList JIT::emitContiguousLoad(Instruction*, PatchableJump& badType, IndexingType expectedShape)
{
JumpList slowCases;
@@ -179,7 +176,7 @@
return slowCases;
}
-JIT::JumpList JIT::emitArrayStorageGetByVal(Instruction*, PatchableJump& badType)
+JIT::JumpList JIT::emitArrayStorageLoad(Instruction*, PatchableJump& badType)
{
JumpList slowCases;
@@ -264,51 +261,6 @@
load64(BaseIndex(scratch, offset, TimesEight, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)), result);
}
-void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
-{
- int dst = currentInstruction[1].u.operand;
- int base = currentInstruction[2].u.operand;
- int property = currentInstruction[3].u.operand;
- unsigned expected = currentInstruction[4].u.operand;
- int iter = currentInstruction[5].u.operand;
- int i = currentInstruction[6].u.operand;
-
- emitGetVirtualRegister(property, regT0);
- addSlowCase(branch64(NotEqual, regT0, addressFor(expected)));
- emitGetVirtualRegisters(base, regT0, iter, regT1);
- emitJumpSlowCaseIfNotJSCell(regT0, base);
-
- // Test base's structure
- emitLoadStructure(regT0, regT2, regT3);
- addSlowCase(branchPtr(NotEqual, regT2, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))));
- load32(addressFor(i), regT3);
- sub32(TrustedImm32(1), regT3);
- addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots))));
- Jump inlineProperty = branch32(Below, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructureInlineCapacity)));
- add32(TrustedImm32(firstOutOfLineOffset), regT3);
- sub32(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructureInlineCapacity)), regT3);
- inlineProperty.link(this);
- compileGetDirectOffset(regT0, regT0, regT3, regT1);
-
- emitPutVirtualRegister(dst, regT0);
-}
-
-void JIT::emitSlow_op_get_by_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- int dst = currentInstruction[1].u.operand;
- int base = currentInstruction[2].u.operand;
- int property = currentInstruction[3].u.operand;
-
- linkSlowCase(iter);
- linkSlowCaseIfNotJSCell(iter, base);
- linkSlowCase(iter);
- linkSlowCase(iter);
-
- emitGetVirtualRegister(base, regT0);
- emitGetVirtualRegister(property, regT1);
- callOperation(operationGetByValGeneric, dst, regT0, regT1);
-}
-
void JIT::emit_op_put_by_val(Instruction* currentInstruction)
{
int base = currentInstruction[1].u.operand;
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
index 88974f1..9a8d5f1 100644
--- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
@@ -35,7 +35,6 @@
#include "JITInlines.h"
#include "JSArray.h"
#include "JSFunction.h"
-#include "JSPropertyNameIterator.h"
#include "JSVariableObject.h"
#include "LinkBuffer.h"
#include "RepatchBuffer.h"
@@ -173,15 +172,13 @@
m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
}
-JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape)
+JIT::JumpList JIT::emitContiguousLoad(Instruction*, PatchableJump& badType, IndexingType expectedShape)
{
JumpList slowCases;
badType = patchableBranch32(NotEqual, regT1, TrustedImm32(expectedShape));
-
loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength())));
-
load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
slowCases.append(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag)));
@@ -189,32 +186,27 @@
return slowCases;
}
-JIT::JumpList JIT::emitDoubleGetByVal(Instruction*, PatchableJump& badType)
+JIT::JumpList JIT::emitDoubleLoad(Instruction*, PatchableJump& badType)
{
JumpList slowCases;
badType = patchableBranch32(NotEqual, regT1, TrustedImm32(DoubleShape));
-
loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength())));
-
loadDouble(BaseIndex(regT3, regT2, TimesEight), fpRegT0);
slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
- moveDoubleToInts(fpRegT0, regT0, regT1);
return slowCases;
}
-JIT::JumpList JIT::emitArrayStorageGetByVal(Instruction*, PatchableJump& badType)
+JIT::JumpList JIT::emitArrayStorageLoad(Instruction*, PatchableJump& badType)
{
JumpList slowCases;
add32(TrustedImm32(-ArrayStorageShape), regT1, regT3);
badType = patchableBranch32(Above, regT3, TrustedImm32(SlowPutArrayStorageShape - ArrayStorageShape));
-
loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, ArrayStorage::vectorLengthOffset())));
-
load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
slowCases.append(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag)));
@@ -613,54 +605,6 @@
load32(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) + (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)), resultTag);
}
-void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
-{
- int dst = currentInstruction[1].u.operand;
- int base = currentInstruction[2].u.operand;
- int property = currentInstruction[3].u.operand;
- unsigned expected = currentInstruction[4].u.operand;
- int iter = currentInstruction[5].u.operand;
- int i = currentInstruction[6].u.operand;
-
- emitLoad2(property, regT1, regT0, base, regT3, regT2);
- emitJumpSlowCaseIfNotJSCell(property, regT1);
- addSlowCase(branchPtr(NotEqual, regT0, payloadFor(expected)));
- // Property registers are now available as the property is known
- emitJumpSlowCaseIfNotJSCell(base, regT3);
- emitLoadPayload(iter, regT1);
-
- // Test base's structure
- loadPtr(Address(regT2, JSCell::structureIDOffset()), regT0);
- addSlowCase(branchPtr(NotEqual, regT0, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))));
- load32(addressFor(i), regT3);
- sub32(TrustedImm32(1), regT3);
- addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots))));
- Jump inlineProperty = branch32(Below, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructureInlineCapacity)));
- add32(TrustedImm32(firstOutOfLineOffset), regT3);
- sub32(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructureInlineCapacity)), regT3);
- inlineProperty.link(this);
- compileGetDirectOffset(regT2, regT1, regT0, regT3);
-
- emitStore(dst, regT1, regT0);
-}
-
-void JIT::emitSlow_op_get_by_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- int dst = currentInstruction[1].u.operand;
- int base = currentInstruction[2].u.operand;
- int property = currentInstruction[3].u.operand;
-
- linkSlowCaseIfNotJSCell(iter, property);
- linkSlowCase(iter);
- linkSlowCaseIfNotJSCell(iter, base);
- linkSlowCase(iter);
- linkSlowCase(iter);
-
- emitLoad(base, regT1, regT0);
- emitLoad(property, regT3, regT2);
- callOperation(operationGetByValGeneric, dst, regT1, regT0, regT3, regT2);
-}
-
void JIT::emitVarInjectionCheck(bool needsVarInjectionChecks)
{
if (!needsVarInjectionChecks)
diff --git a/Source/JavaScriptCore/jit/Repatch.cpp b/Source/JavaScriptCore/jit/Repatch.cpp
index 715bc7e..d6e5cca 100644
--- a/Source/JavaScriptCore/jit/Repatch.cpp
+++ b/Source/JavaScriptCore/jit/Repatch.cpp
@@ -1607,8 +1607,8 @@
}
void linkClosureCall(
- ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCodeBlock,
- Structure* structure, ExecutableBase* executable, MacroAssemblerCodePtr codePtr,
+ ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCodeBlock,
+ ExecutableBase* executable, MacroAssemblerCodePtr codePtr,
RegisterPreservationMode registers)
{
ASSERT(!callLinkInfo.stub);
@@ -1642,10 +1642,10 @@
#endif
slowPath.append(
- branchStructure(stubJit,
+ stubJit.branch8(
CCallHelpers::NotEqual,
- CCallHelpers::Address(calleeGPR, JSCell::structureIDOffset()),
- structure));
+ CCallHelpers::Address(calleeGPR, JSCell::typeInfoTypeOffset()),
+ CCallHelpers::TrustedImm32(JSFunctionType)));
slowPath.append(
stubJit.branchPtr(
@@ -1699,7 +1699,7 @@
("Closure call stub for %s, return point %p, target %p (%s)",
toCString(*callerCodeBlock).data(), callLinkInfo.callReturnLocation.labelAtOffset(0).executableAddress(),
codePtr.executableAddress(), toCString(pointerDump(calleeCodeBlock)).data())),
- *vm, callerCodeBlock->ownerExecutable(), structure, executable, callLinkInfo.codeOrigin));
+ *vm, callerCodeBlock->ownerExecutable(), executable, callLinkInfo.codeOrigin));
RepatchBuffer repatchBuffer(callerCodeBlock);
diff --git a/Source/JavaScriptCore/jit/Repatch.h b/Source/JavaScriptCore/jit/Repatch.h
index ee9950e..d60f4fd 100644
--- a/Source/JavaScriptCore/jit/Repatch.h
+++ b/Source/JavaScriptCore/jit/Repatch.h
@@ -41,7 +41,7 @@
void repatchIn(ExecState*, JSCell*, const Identifier&, bool wasFound, const PropertySlot&, StructureStubInfo&);
void linkFor(ExecState*, CallLinkInfo&, CodeBlock*, JSFunction* callee, MacroAssemblerCodePtr, CodeSpecializationKind, RegisterPreservationMode);
void linkSlowFor(ExecState*, CallLinkInfo&, CodeSpecializationKind, RegisterPreservationMode);
-void linkClosureCall(ExecState*, CallLinkInfo&, CodeBlock*, Structure*, ExecutableBase*, MacroAssemblerCodePtr, RegisterPreservationMode);
+void linkClosureCall(ExecState*, CallLinkInfo&, CodeBlock*, ExecutableBase*, MacroAssemblerCodePtr, RegisterPreservationMode);
void resetGetByID(RepatchBuffer&, StructureStubInfo&);
void resetPutByID(RepatchBuffer&, StructureStubInfo&);
void resetIn(RepatchBuffer&, StructureStubInfo&);
diff --git a/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp b/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
index 84256ae..1eefa4e 100644
--- a/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
+++ b/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
@@ -39,7 +39,6 @@
#include "VM.h"
#include "JSGlobalObject.h"
#include "JSObject.h"
-#include "JSPropertyNameIterator.h"
#include "JSStack.h"
#include "JSString.h"
#include "JSTypeInfo.h"
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index 134e9d0..730a3e7 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -42,7 +42,6 @@
#include "JSCJSValue.h"
#include "JSGlobalObjectFunctions.h"
#include "JSNameScope.h"
-#include "JSPropertyNameIterator.h"
#include "JSStackInlines.h"
#include "JSString.h"
#include "JSWithScope.h"
@@ -776,12 +775,6 @@
LLINT_RETURN_PROFILED(op_get_argument_by_val, getByVal(exec, arguments, LLINT_OP_C(3).jsValue()));
}
-LLINT_SLOW_PATH_DECL(slow_path_get_by_pname)
-{
- LLINT_BEGIN();
- LLINT_RETURN(getByVal(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue()));
-}
-
LLINT_SLOW_PATH_DECL(slow_path_put_by_val)
{
LLINT_BEGIN();
@@ -1290,42 +1283,6 @@
LLINT_RETURN(LLINT_OP_C(2).jsValue().toPrimitive(exec));
}
-LLINT_SLOW_PATH_DECL(slow_path_get_pnames)
-{
- LLINT_BEGIN();
- JSValue v = LLINT_OP(2).jsValue();
- if (v.isUndefinedOrNull()) {
- pc += pc[5].u.operand;
- LLINT_END();
- }
-
- JSObject* o = v.toObject(exec);
- Structure* structure = o->structure();
- JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
- if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(exec))
- jsPropertyNameIterator = JSPropertyNameIterator::create(exec, o);
-
- LLINT_OP(1) = JSValue(jsPropertyNameIterator);
- LLINT_OP(2) = JSValue(o);
- LLINT_OP(3) = Register::withInt(0);
- LLINT_OP(4) = Register::withInt(jsPropertyNameIterator->size());
-
- pc += OPCODE_LENGTH(op_get_pnames);
- LLINT_END();
-}
-
-LLINT_SLOW_PATH_DECL(slow_path_next_pname)
-{
- LLINT_BEGIN();
- JSObject* base = asObject(LLINT_OP(2).jsValue());
- JSString* property = asString(LLINT_OP(1).jsValue());
- if (base->hasProperty(exec, Identifier(exec, property->value(exec)))) {
- // Go to target.
- pc += pc[6].u.operand;
- } // Else, don't change the PC, so the interpreter will reloop.
- LLINT_END();
-}
-
LLINT_SLOW_PATH_DECL(slow_path_push_with_scope)
{
LLINT_BEGIN();
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.h b/Source/JavaScriptCore/llint/LLIntSlowPaths.h
index 2465bfd..fdec52d 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.h
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.h
@@ -76,7 +76,6 @@
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_del_by_id);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_argument_by_val);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_pname);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val_direct);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_del_by_val);
@@ -107,8 +106,6 @@
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_tear_off_arguments);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_strcat);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_pnames);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_next_pname);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_pop_scope);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_push_name_scope);
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index f04ef7b..d023565 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -1145,12 +1145,6 @@
dispatch(4)
-_llint_op_get_pnames:
- traceExecution()
- callSlowPath(_llint_slow_path_get_pnames)
- dispatch(0) # The slow_path either advances the PC or jumps us to somewhere else.
-
-
_llint_op_push_with_scope:
traceExecution()
callSlowPath(_llint_slow_path_push_with_scope)
@@ -1220,6 +1214,50 @@
_llint_native_construct_trampoline:
nativeCallTrampoline(NativeExecutable::m_constructor)
+_llint_op_get_enumerable_length:
+ traceExecution()
+ callSlowPath(_slow_path_get_enumerable_length)
+ dispatch(3)
+
+_llint_op_has_indexed_property:
+ traceExecution()
+ callSlowPath(_slow_path_has_indexed_property)
+ dispatch(5)
+
+_llint_op_has_structure_property:
+ traceExecution()
+ callSlowPath(_slow_path_has_structure_property)
+ dispatch(5)
+
+_llint_op_has_generic_property:
+ traceExecution()
+ callSlowPath(_slow_path_has_generic_property)
+ dispatch(4)
+
+_llint_op_get_direct_pname:
+ traceExecution()
+ callSlowPath(_slow_path_get_direct_pname)
+ dispatch(7)
+
+_llint_op_get_structure_property_enumerator:
+ traceExecution()
+ callSlowPath(_slow_path_get_structure_property_enumerator)
+ dispatch(4)
+
+_llint_op_get_generic_property_enumerator:
+ traceExecution()
+ callSlowPath(_slow_path_get_generic_property_enumerator)
+ dispatch(5)
+
+_llint_op_next_enumerator_pname:
+ traceExecution()
+ callSlowPath(_slow_path_next_enumerator_pname)
+ dispatch(4)
+
+_llint_op_to_index_string:
+ traceExecution()
+ callSlowPath(_slow_path_to_index_string)
+ dispatch(3)
# Lastly, make sure that we can link even though we don't support all opcodes.
# These opcodes should never arise when using LLInt or either JIT. We assert
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index 1d19fc6..9345cda 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -1613,37 +1613,6 @@
dispatch(6)
-_llint_op_get_by_pname:
- traceExecution()
- loadi 12[PC], t0
- loadConstantOrVariablePayload(t0, CellTag, t1, .opGetByPnameSlow)
- loadi 16[PC], t0
- bpneq t1, PayloadOffset[cfr, t0, 8], .opGetByPnameSlow
- loadi 8[PC], t0
- loadConstantOrVariablePayload(t0, CellTag, t2, .opGetByPnameSlow)
- loadi 20[PC], t0
- loadi PayloadOffset[cfr, t0, 8], t3
- loadp JSCell::m_structureID[t2], t0
- bpneq t0, JSPropertyNameIterator::m_cachedStructure[t3], .opGetByPnameSlow
- loadi 24[PC], t0
- loadi [cfr, t0, 8], t0
- subi 1, t0
- biaeq t0, JSPropertyNameIterator::m_numCacheableSlots[t3], .opGetByPnameSlow
- bilt t0, JSPropertyNameIterator::m_cachedStructureInlineCapacity[t3], .opGetByPnameInlineProperty
- addi firstOutOfLineOffset, t0
- subi JSPropertyNameIterator::m_cachedStructureInlineCapacity[t3], t0
-.opGetByPnameInlineProperty:
- loadPropertyAtVariableOffset(t0, t2, t1, t3)
- loadi 4[PC], t0
- storei t1, TagOffset[cfr, t0, 8]
- storei t3, PayloadOffset[cfr, t0, 8]
- dispatch(7)
-
-.opGetByPnameSlow:
- callSlowPath(_llint_slow_path_get_by_pname)
- dispatch(7)
-
-
macro contiguousPutByVal(storeCallback)
biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .outOfBounds
.storeResult:
@@ -2038,46 +2007,6 @@
dispatch(3)
-_llint_op_next_pname:
- traceExecution()
- loadi 12[PC], t1
- loadi 16[PC], t2
- loadi PayloadOffset[cfr, t1, 8], t0
- bieq t0, PayloadOffset[cfr, t2, 8], .opNextPnameEnd
- loadi 20[PC], t2
- loadi PayloadOffset[cfr, t2, 8], t2
- loadp JSPropertyNameIterator::m_jsStrings[t2], t3
- loadi [t3, t0, 8], t3
- addi 1, t0
- storei t0, PayloadOffset[cfr, t1, 8]
- loadi 4[PC], t1
- storei CellTag, TagOffset[cfr, t1, 8]
- storei t3, PayloadOffset[cfr, t1, 8]
- loadi 8[PC], t3
- loadi PayloadOffset[cfr, t3, 8], t3
- loadp JSCell::m_structureID[t3], t1
- bpneq t1, JSPropertyNameIterator::m_cachedStructure[t2], .opNextPnameSlow
- loadp JSPropertyNameIterator::m_cachedPrototypeChain[t2], t0
- loadp StructureChain::m_vector[t0], t0
- btpz [t0], .opNextPnameTarget
-.opNextPnameCheckPrototypeLoop:
- bieq Structure::m_prototype + TagOffset[t1], NullTag, .opNextPnameSlow
- loadp Structure::m_prototype + PayloadOffset[t1], t2
- loadp JSCell::m_structureID[t2], t1
- bpneq t1, [t0], .opNextPnameSlow
- addp 4, t0
- btpnz [t0], .opNextPnameCheckPrototypeLoop
-.opNextPnameTarget:
- dispatchBranch(24[PC])
-
-.opNextPnameEnd:
- dispatch(7)
-
-.opNextPnameSlow:
- callSlowPath(_llint_slow_path_next_pname) # This either keeps the PC where it was (causing us to loop) or sets it to target.
- dispatch(0)
-
-
_llint_op_catch:
# This is where we end up from the JIT's throw trampoline (because the
# machine code return address will be set to _llint_op_catch), and from
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
index 8b7a1a0..087521c 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -1510,38 +1510,6 @@
dispatch(6)
-_llint_op_get_by_pname:
- traceExecution()
- loadisFromInstruction(3, t1)
- loadConstantOrVariable(t1, t0)
- loadisFromInstruction(4, t1)
- assertNotConstant(t1)
- bqneq t0, [cfr, t1, 8], .opGetByPnameSlow
- loadisFromInstruction(2, t2)
- loadisFromInstruction(5, t3)
- loadConstantOrVariableCell(t2, t0, .opGetByPnameSlow)
- assertNotConstant(t3)
- loadq [cfr, t3, 8], t1
- loadStructureWithScratch(t0, t2, t3)
- bpneq t2, JSPropertyNameIterator::m_cachedStructure[t1], .opGetByPnameSlow
- loadisFromInstruction(6, t3)
- loadi PayloadOffset[cfr, t3, 8], t3
- subi 1, t3
- biaeq t3, JSPropertyNameIterator::m_numCacheableSlots[t1], .opGetByPnameSlow
- bilt t3, JSPropertyNameIterator::m_cachedStructureInlineCapacity[t1], .opGetByPnameInlineProperty
- addi firstOutOfLineOffset, t3
- subi JSPropertyNameIterator::m_cachedStructureInlineCapacity[t1], t3
-.opGetByPnameInlineProperty:
- loadPropertyAtVariableOffset(t3, t0, t0)
- loadisFromInstruction(1, t1)
- storeq t0, [cfr, t1, 8]
- dispatch(7)
-
-.opGetByPnameSlow:
- callSlowPath(_llint_slow_path_get_by_pname)
- dispatch(7)
-
-
macro contiguousPutByVal(storeCallback)
biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .outOfBounds
.storeResult:
@@ -1934,49 +1902,6 @@
dispatch(3)
-_llint_op_next_pname:
- traceExecution()
- loadisFromInstruction(3, t1)
- loadisFromInstruction(4, t2)
- assertNotConstant(t1)
- assertNotConstant(t2)
- loadi PayloadOffset[cfr, t1, 8], t0
- bieq t0, PayloadOffset[cfr, t2, 8], .opNextPnameEnd
- loadisFromInstruction(5, t2)
- assertNotConstant(t2)
- loadp [cfr, t2, 8], t2
- loadp JSPropertyNameIterator::m_jsStrings[t2], t3
- loadq [t3, t0, 8], t3
- addi 1, t0
- storei t0, PayloadOffset[cfr, t1, 8]
- loadisFromInstruction(1, t1)
- storeq t3, [cfr, t1, 8]
- loadisFromInstruction(2, t3)
- assertNotConstant(t3)
- loadq [cfr, t3, 8], t3
- loadStructureWithScratch(t3, t1, t0)
- bpneq t1, JSPropertyNameIterator::m_cachedStructure[t2], .opNextPnameSlow
- loadp JSPropertyNameIterator::m_cachedPrototypeChain[t2], t0
- loadp StructureChain::m_vector[t0], t0
- btpz [t0], .opNextPnameTarget
-.opNextPnameCheckPrototypeLoop:
- bqeq Structure::m_prototype[t1], ValueNull, .opNextPnameSlow
- loadq Structure::m_prototype[t1], t2
- loadStructureWithScratch(t2, t1, t3)
- bpneq t1, [t0], .opNextPnameSlow
- addp 8, t0
- btpnz [t0], .opNextPnameCheckPrototypeLoop
-.opNextPnameTarget:
- dispatchIntIndirect(6)
-
-.opNextPnameEnd:
- dispatch(7)
-
-.opNextPnameSlow:
- callSlowPath(_llint_slow_path_next_pname) # This either keeps the PC where it was (causing us to loop) or sets it to target.
- dispatch(0)
-
-
_llint_op_catch:
# This is where we end up from the JIT's throw trampoline (because the
# machine code return address will be set to _llint_op_catch), and from
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index a3b4153..06a27ed 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -1280,6 +1280,10 @@
ForInNode(VM*, const JSTokenLocation&, DeconstructionPatternNode*, ExpressionNode*, StatementNode*);
private:
+ RegisterID* tryGetBoundLocal(BytecodeGenerator&);
+ void emitLoopHeader(BytecodeGenerator&, RegisterID* propertyName);
+ void emitMultiLoopBytecode(BytecodeGenerator&, RegisterID* dst);
+
virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
};
diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp
index dc89331..8f4a778 100644
--- a/Source/JavaScriptCore/runtime/Arguments.cpp
+++ b/Source/JavaScriptCore/runtime/Arguments.cpp
@@ -221,7 +221,7 @@
continue;
propertyNames.add(Identifier::from(exec, i));
}
- if (mode == IncludeDontEnumProperties) {
+ if (shouldIncludeDontEnumProperties(mode)) {
propertyNames.add(exec->propertyNames().callee);
propertyNames.add(exec->propertyNames().length);
}
diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h
index 4fd4309..cb5058c 100644
--- a/Source/JavaScriptCore/runtime/ClassInfo.h
+++ b/Source/JavaScriptCore/runtime/ClassInfo.h
@@ -82,6 +82,12 @@
typedef void (*GetPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
GetPropertyNamesFunctionPtr getPropertyNames;
+ typedef uint32_t (*GetEnumerableLengthFunctionPtr)(ExecState*, JSObject*);
+ GetEnumerableLengthFunctionPtr getEnumerableLength;
+
+ GetPropertyNamesFunctionPtr getStructurePropertyNames;
+ GetPropertyNamesFunctionPtr getGenericPropertyNames;
+
typedef String (*ClassNameFunctionPtr)(const JSObject*);
ClassNameFunctionPtr className;
@@ -137,6 +143,9 @@
&ClassName::getOwnPropertyNames, \
&ClassName::getOwnNonIndexPropertyNames, \
&ClassName::getPropertyNames, \
+ &ClassName::getEnumerableLength, \
+ &ClassName::getStructurePropertyNames, \
+ &ClassName::getGenericPropertyNames, \
&ClassName::className, \
&ClassName::customHasInstance, \
&ClassName::defineOwnProperty, \
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
index fe91c98..2d4f5a3 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
@@ -42,7 +42,7 @@
#include "JSCJSValue.h"
#include "JSGlobalObjectFunctions.h"
#include "JSNameScope.h"
-#include "JSPropertyNameIterator.h"
+#include "JSPropertyNameEnumerator.h"
#include "JSString.h"
#include "JSWithScope.h"
#include "LLIntCommon.h"
@@ -537,4 +537,103 @@
END();
}
+SLOW_PATH_DECL(slow_path_get_enumerable_length)
+{
+ BEGIN();
+ JSValue baseValue = OP(2).jsValue();
+ if (baseValue.isUndefinedOrNull())
+ RETURN(jsNumber(0));
+
+ JSObject* base = baseValue.toObject(exec);
+ RETURN(jsNumber(base->methodTable(vm)->getEnumerableLength(exec, base)));
+}
+
+SLOW_PATH_DECL(slow_path_has_indexed_property)
+{
+ BEGIN();
+ JSObject* base = OP(2).jsValue().toObject(exec);
+ JSValue property = OP(3).jsValue();
+ pc[4].u.arrayProfile->observeStructure(base->structure(vm));
+ ASSERT(property.isUInt32());
+ RETURN(jsBoolean(base->hasProperty(exec, property.asUInt32())));
+}
+
+SLOW_PATH_DECL(slow_path_has_structure_property)
+{
+ BEGIN();
+ JSObject* base = OP(2).jsValue().toObject(exec);
+ JSValue property = OP(3).jsValue();
+ ASSERT(property.isString());
+ JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(4).jsValue().asCell());
+ if (base->structure(vm)->id() == enumerator->cachedStructureID())
+ RETURN(jsBoolean(true));
+ RETURN(jsBoolean(base->hasProperty(exec, asString(property.asCell())->toIdentifier(exec))));
+}
+
+SLOW_PATH_DECL(slow_path_has_generic_property)
+{
+ BEGIN();
+ JSObject* base = OP(2).jsValue().toObject(exec);
+ JSValue property = OP(3).jsValue();
+ bool result;
+ if (property.isString())
+ result = base->hasProperty(exec, asString(property.asCell())->toIdentifier(exec));
+ else {
+ ASSERT(property.isUInt32());
+ result = base->hasProperty(exec, property.asUInt32());
+ }
+ RETURN(jsBoolean(result));
+}
+
+SLOW_PATH_DECL(slow_path_get_direct_pname)
+{
+ BEGIN();
+ JSValue baseValue = OP(2).jsValue();
+ JSValue property = OP(3).jsValue();
+ ASSERT(property.isString());
+ RETURN(baseValue.get(exec, property.toString(exec)->toIdentifier(exec)));
+}
+
+SLOW_PATH_DECL(slow_path_get_structure_property_enumerator)
+{
+ BEGIN();
+ JSValue baseValue = OP(2).jsValue();
+ if (baseValue.isUndefinedOrNull())
+ RETURN(JSPropertyNameEnumerator::create(vm));
+
+ JSObject* base = baseValue.toObject(exec);
+ uint32_t length = OP(3).jsValue().asUInt32();
+
+ RETURN(structurePropertyNameEnumerator(exec, base, length));
+}
+
+SLOW_PATH_DECL(slow_path_get_generic_property_enumerator)
+{
+ BEGIN();
+ JSValue baseValue = OP(2).jsValue();
+ if (baseValue.isUndefinedOrNull())
+ RETURN(JSPropertyNameEnumerator::create(vm));
+
+ JSObject* base = baseValue.toObject(exec);
+ uint32_t length = OP(3).jsValue().asUInt32();
+ JSPropertyNameEnumerator* structureEnumerator = jsCast<JSPropertyNameEnumerator*>(OP(4).jsValue().asCell());
+
+ RETURN(genericPropertyNameEnumerator(exec, base, length, structureEnumerator));
+}
+
+SLOW_PATH_DECL(slow_path_next_enumerator_pname)
+{
+ BEGIN();
+ JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(2).jsValue().asCell());
+ uint32_t index = OP(3).jsValue().asUInt32();
+ JSString* propertyName = enumerator->propertyNameAtIndex(index);
+ RETURN(propertyName ? propertyName : jsNull());
+}
+
+SLOW_PATH_DECL(slow_path_to_index_string)
+{
+ BEGIN();
+ RETURN(jsString(exec, Identifier::from(exec, OP(2).jsValue().asUInt32()).string()));
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
index 8f3a033..09e7844 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
@@ -224,6 +224,15 @@
SLOW_PATH_HIDDEN_DECL(slow_path_del_by_val);
SLOW_PATH_HIDDEN_DECL(slow_path_strcat);
SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_enumerable_length);
+SLOW_PATH_HIDDEN_DECL(slow_path_has_generic_property);
+SLOW_PATH_HIDDEN_DECL(slow_path_has_structure_property);
+SLOW_PATH_HIDDEN_DECL(slow_path_has_indexed_property);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_direct_pname);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_structure_property_enumerator);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_generic_property_enumerator);
+SLOW_PATH_HIDDEN_DECL(slow_path_next_enumerator_pname);
+SLOW_PATH_HIDDEN_DECL(slow_path_to_index_string);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/EnumerationMode.h b/Source/JavaScriptCore/runtime/EnumerationMode.h
new file mode 100644
index 0000000..91a3aab
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/EnumerationMode.h
@@ -0,0 +1,87 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 EnumerationMode_h
+#define EnumerationMode_h
+
+namespace JSC {
+
+enum EnumerationMode {
+ ExcludeDontEnumProperties,
+ ExcludeDontEnumPropertiesAndSkipJSObject,
+ IncludeDontEnumProperties,
+ IncludeDontEnumPropertiesAndSkipJSObject
+};
+
+inline bool shouldIncludeDontEnumProperties(EnumerationMode mode)
+{
+ switch (mode) {
+ case IncludeDontEnumProperties:
+ case IncludeDontEnumPropertiesAndSkipJSObject:
+ return true;
+ default:
+ return false;
+ }
+}
+
+inline bool shouldExcludeDontEnumProperties(EnumerationMode mode)
+{
+ switch (mode) {
+ case ExcludeDontEnumProperties:
+ case ExcludeDontEnumPropertiesAndSkipJSObject:
+ return true;
+ default:
+ return false;
+ }
+}
+
+inline bool shouldIncludeJSObjectPropertyNames(EnumerationMode mode)
+{
+ switch (mode) {
+ case IncludeDontEnumProperties:
+ case ExcludeDontEnumProperties:
+ return true;
+ case ExcludeDontEnumPropertiesAndSkipJSObject:
+ case IncludeDontEnumPropertiesAndSkipJSObject:
+ return false;
+ }
+}
+
+inline EnumerationMode modeThatSkipsJSObject(EnumerationMode mode)
+{
+ switch (mode) {
+ case IncludeDontEnumProperties:
+ return IncludeDontEnumPropertiesAndSkipJSObject;
+ case ExcludeDontEnumProperties:
+ return ExcludeDontEnumPropertiesAndSkipJSObject;
+ case ExcludeDontEnumPropertiesAndSkipJSObject:
+ case IncludeDontEnumPropertiesAndSkipJSObject:
+ return mode;
+ }
+}
+
+} // namespace JSC
+
+#endif // EnumerationMode_h
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp
index e175531..4c56b44 100644
--- a/Source/JavaScriptCore/runtime/Executable.cpp
+++ b/Source/JavaScriptCore/runtime/Executable.cpp
@@ -30,6 +30,7 @@
#include "BytecodeGenerator.h"
#include "CodeBlock.h"
#include "DFGDriver.h"
+#include "HighFidelityTypeProfiler.h"
#include "JIT.h"
#include "LLIntEntrypoint.h"
#include "JSCInlines.h"
@@ -103,6 +104,8 @@
, m_lastLine(-1)
, m_startColumn(UINT_MAX)
, m_endColumn(UINT_MAX)
+ , m_highFidelityTypeProfilingStartOffset(UINT_MAX)
+ , m_highFidelityTypeProfilingEndOffset(UINT_MAX)
{
}
@@ -373,6 +376,10 @@
ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source)
: ScriptExecutable(exec->vm().programExecutableStructure.get(), exec->vm(), source, false)
{
+ m_highFidelityTypeProfilingStartOffset = 0;
+ m_highFidelityTypeProfilingEndOffset = source.length() - 1;
+ if (exec->vm().isProfilingTypesWithHighFidelity())
+ exec->vm().highFidelityTypeProfiler()->functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_highFidelityTypeProfilingStartOffset, m_highFidelityTypeProfilingEndOffset);
}
void ProgramExecutable::destroy(JSCell* cell)
@@ -396,6 +403,8 @@
ASSERT(endColumn != UINT_MAX);
m_startColumn = startColumn;
m_endColumn = endColumn;
+ m_highFidelityTypeProfilingStartOffset = unlinkedExecutable->highFidelityTypeProfilingStartOffset();
+ m_highFidelityTypeProfilingEndOffset = unlinkedExecutable->highFidelityTypeProfilingEndOffset();
}
void FunctionExecutable::destroy(JSCell* cell)
@@ -492,6 +501,11 @@
UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get();
JSValue value = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, m_source, lineNo()), scope);
globalObject->addFunction(callFrame, functionDeclarations[i].first, value);
+ if (vm.isProfilingTypesWithHighFidelity()) {
+ vm.highFidelityTypeProfiler()->functionHasExecutedCache()->insertUnexecutedRange(sourceID(),
+ unlinkedFunctionExecutable->highFidelityTypeProfilingStartOffset(),
+ unlinkedFunctionExecutable->highFidelityTypeProfilingEndOffset());
+ }
}
for (size_t i = 0; i < variableDeclarations.size(); ++i) {
diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h
index cd82d3f..1b24e6a 100644
--- a/Source/JavaScriptCore/runtime/Executable.h
+++ b/Source/JavaScriptCore/runtime/Executable.h
@@ -365,6 +365,8 @@
int lastLine() const { return m_lastLine; }
unsigned startColumn() const { return m_startColumn; }
unsigned endColumn() const { return m_endColumn; }
+ unsigned highFidelityTypeProfilingStartOffset() const { return m_highFidelityTypeProfilingStartOffset; }
+ unsigned highFidelityTypeProfilingEndOffset() const { return m_highFidelityTypeProfilingEndOffset; }
bool usesEval() const { return m_features & EvalFeature; }
bool usesArguments() const { return m_features & ArgumentsFeature; }
@@ -435,6 +437,8 @@
int m_lastLine;
unsigned m_startColumn;
unsigned m_endColumn;
+ unsigned m_highFidelityTypeProfilingStartOffset;
+ unsigned m_highFidelityTypeProfilingEndOffset;
};
class EvalExecutable : public ScriptExecutable {
diff --git a/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp b/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp
new file mode 100644
index 0000000..e323b93
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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 "FunctionHasExecutedCache.h"
+
+namespace JSC {
+
+bool FunctionHasExecutedCache::hasExecutedAtOffset(intptr_t id, unsigned offset)
+{
+ if (m_rangeMap.find(id) == m_rangeMap.end())
+ return false;
+
+ RangeMap& map = m_rangeMap.find(id)->second;
+ unsigned distance = UINT_MAX;
+ bool hasExecuted = false;
+ for (auto iter = map.begin(), end = map.end(); iter != end; ++iter) {
+ const FunctionRange& range = iter->first;
+ if (range.m_start <= offset && offset <= range.m_end && range.m_end - range.m_start < distance) {
+ hasExecuted = iter->second;
+ distance = range.m_end - range.m_start;
+ }
+ }
+
+ return hasExecuted;
+}
+
+void FunctionHasExecutedCache::insertUnexecutedRange(intptr_t id, unsigned start, unsigned end)
+{
+ if (m_rangeMap.find(id) == m_rangeMap.end()) {
+ RangeMap map;
+ m_rangeMap[id] = map;
+ }
+
+ RangeMap& map = m_rangeMap.find(id)->second;
+ FunctionRange range;
+ range.m_start = start;
+ range.m_end = end;
+ // Only insert unexecuted ranges once for a given sourceID because we may run into a situation where an executable executes, then is GCed, and then is allocated again,
+ // and tries to reinsert itself, claiming it has never run, but this is false because it indeed already executed.
+ if (map.find(range) == map.end())
+ map[range] = false;
+}
+
+void FunctionHasExecutedCache::removeUnexecutedRange(intptr_t id, unsigned start, unsigned end)
+{
+ // FIXME: We should never have an instance where we return here, but currently do in some situations. Find out why.
+ if (m_rangeMap.find(id) == m_rangeMap.end())
+ return;
+
+ RangeMap& map = m_rangeMap.find(id)->second;
+
+ FunctionRange range;
+ range.m_start = start;
+ range.m_end = end;
+ map[range] = true;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h b/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h
new file mode 100644
index 0000000..8c769f9
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h
@@ -0,0 +1,63 @@
+/*
+ * 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 FunctionHasExecutedCache_h
+#define FunctionHasExecutedCache_h
+
+#include <unordered_map>
+#include <wtf/HashMethod.h>
+
+namespace JSC {
+
+class FunctionHasExecutedCache {
+public:
+ struct FunctionRange {
+ FunctionRange() {}
+ bool operator==(const FunctionRange& other) const
+ {
+ return m_start == other.m_start && m_end == other.m_end;
+ }
+ unsigned hash() const
+ {
+ return m_start * m_end;
+ }
+
+ unsigned m_start;
+ unsigned m_end;
+ };
+
+ bool hasExecutedAtOffset(intptr_t id, unsigned offset);
+ void insertUnexecutedRange(intptr_t id, unsigned start, unsigned end);
+ void removeUnexecutedRange(intptr_t id, unsigned start, unsigned end);
+
+private:
+ typedef std::unordered_map<FunctionRange, bool, HashMethod<FunctionRange>> RangeMap;
+ typedef std::unordered_map<intptr_t, RangeMap> SourceIDToRangeMap;
+ SourceIDToRangeMap m_rangeMap;
+};
+
+} // namespace JSC
+
+#endif // FunctionHasExecutedCache_h
diff --git a/Source/JavaScriptCore/runtime/HighFidelityLog.cpp b/Source/JavaScriptCore/runtime/HighFidelityLog.cpp
index 802867c..90a891f 100644
--- a/Source/JavaScriptCore/runtime/HighFidelityLog.cpp
+++ b/Source/JavaScriptCore/runtime/HighFidelityLog.cpp
@@ -53,45 +53,25 @@
delete[] m_nextBuffer;
}
-void HighFidelityLog::processHighFidelityLog(bool asynchronously, String reason)
+void HighFidelityLog::processHighFidelityLog(String reason)
{
- // This should only be called from the main execution thread.
if (!m_currentOffset)
return;
if (verbose)
dataLog("Process caller:'", reason,"'");
- ByteSpinLocker* locker = new ByteSpinLocker(m_lock);
- ThreadData* data = new ThreadData;
- data->m_proccessLogToOffset = m_currentOffset;
- data->m_processLogPtr = m_logStartPtr;
- data->m_locker = locker;
-
- m_currentOffset = 0;
- std::swap(m_logStartPtr, m_nextBuffer);
-
- if (asynchronously)
- createThread(actuallyProcessLogThreadFunction, data, "ProcessHighFidelityLog");
- else
- actuallyProcessLogThreadFunction(data);
-}
-
-void HighFidelityLog::actuallyProcessLogThreadFunction(void* arg)
-{
double before = currentTimeMS();
- ThreadData* data = static_cast<ThreadData*>(arg);
- LogEntry* entry = data->m_processLogPtr;
+ LogEntry* entry = m_logStartPtr;
HashMap<StructureID, RefPtr<StructureShape>> seenShapes;
- size_t processLogToOffset = data->m_proccessLogToOffset;
size_t i = 0;
- while (i < processLogToOffset) {
+ while (i < m_currentOffset) {
StructureID id = entry->structureID;
RefPtr<StructureShape> shape;
if (id) {
auto iter = seenShapes.find(id);
if (iter == seenShapes.end()) {
- shape = entry->value.asCell()->structure()->toStructureShape();
+ shape = Heap::heap(entry->value.asCell())->structureIDTable().get(entry->structureID)->toStructureShape(entry->value);
seenShapes.set(id, shape);
} else
shape = iter->value;
@@ -105,11 +85,12 @@
i++;
}
- delete data->m_locker;
- delete data;
- double after = currentTimeMS();
- if (verbose)
+ m_currentOffset = 0;
+
+ if (verbose) {
+ double after = currentTimeMS();
dataLogF(" Processing the log took: '%f' ms\n", after - before);
+ }
}
} //namespace JSC
diff --git a/Source/JavaScriptCore/runtime/HighFidelityLog.h b/Source/JavaScriptCore/runtime/HighFidelityLog.h
index f63519f..e45f349 100644
--- a/Source/JavaScriptCore/runtime/HighFidelityLog.h
+++ b/Source/JavaScriptCore/runtime/HighFidelityLog.h
@@ -69,14 +69,13 @@
m_currentOffset += 1;
if (m_currentOffset == m_highFidelityLogSize)
- processHighFidelityLog(true, "Log Full");
+ processHighFidelityLog("Log Full");
}
- void processHighFidelityLog(bool asynchronously = false, String = "");
+ void processHighFidelityLog(String);
private:
void initializeHighFidelityLog();
- static void actuallyProcessLogThreadFunction(void*);
unsigned m_highFidelityLogSize;
size_t m_currentOffset;
diff --git a/Source/JavaScriptCore/runtime/HighFidelityTypeProfiler.cpp b/Source/JavaScriptCore/runtime/HighFidelityTypeProfiler.cpp
index 4bf7d12..dcf1085 100644
--- a/Source/JavaScriptCore/runtime/HighFidelityTypeProfiler.cpp
+++ b/Source/JavaScriptCore/runtime/HighFidelityTypeProfiler.cpp
@@ -26,40 +26,33 @@
#include "config.h"
#include "HighFidelityTypeProfiler.h"
+#include "InspectorJSTypeBuilders.h"
#include "TypeLocation.h"
namespace JSC {
static const bool verbose = false;
-String HighFidelityTypeProfiler::getTypesForVariableInAtOffset(unsigned divot, const String& variableName, intptr_t sourceID)
+void HighFidelityTypeProfiler::logTypesForTypeLocation(TypeLocation* location)
{
- String global = getGlobalTypesForVariableAtOffset(divot, variableName, sourceID);
- if (!global.isEmpty())
- return global;
-
- return getLocalTypesForVariableAtOffset(divot, variableName, sourceID);
-}
+ TypeProfilerSearchDescriptor descriptor = location->m_globalVariableID == HighFidelityReturnStatement ? TypeProfilerSearchDescriptorFunctionReturn
+ : location->m_globalVariableID == HighFidelityThisStatement ? TypeProfilerSearchDescriptorThisStatement
+ : TypeProfilerSearchDescriptorNormal;
-String HighFidelityTypeProfiler::getGlobalTypesForVariableAtOffset(unsigned divot, const String& , intptr_t sourceID)
-{
- TypeLocation* location = findLocation(divot, sourceID);
- if (!location)
- return "";
+ dataLogF("[Start, End]::[%u, %u]\n", location->m_divotStart, location->m_divotEnd);
- if (location->m_globalVariableID == HighFidelityNoGlobalIDExists)
- return "";
+ if (findLocation(location->m_divotStart, location->m_sourceID, descriptor))
+ dataLog("\t\t[Entry IS in System]\n");
+ else
+ dataLog("\t\t[Entry IS NOT in system]\n");
- return location->m_globalTypeSet->seenTypes();
-}
+ dataLog("\t\t", location->m_globalVariableID == HighFidelityReturnStatement ? "[Return Statement]"
+ : location->m_globalVariableID == HighFidelityThisStatement ? "[This Statement]"
+ : "[Normal Statement]", "\n");
-String HighFidelityTypeProfiler::getLocalTypesForVariableAtOffset(unsigned divot, const String& , intptr_t sourceID)
-{
- TypeLocation* location = findLocation(divot, sourceID);
- if (!location)
- return "";
-
- return location->m_instructionTypeSet->seenTypes();
+ dataLog("\t\t#Local#\n\t\t", location->m_instructionTypeSet->seenTypes().replace("\n", "\n\t\t"), "\n");
+ if (location->m_globalTypeSet)
+ dataLog("\t\t#Global#\n\t\t", location->m_globalTypeSet->seenTypes().replace("\n", "\n\t\t"), "\n");
}
void HighFidelityTypeProfiler::insertNewLocation(TypeLocation* location)
@@ -76,22 +69,67 @@
bucket.append(location);
}
-TypeLocation* HighFidelityTypeProfiler::findLocation(unsigned divot, intptr_t sourceID)
+void HighFidelityTypeProfiler::getTypesForVariableAtOffsetForInspector(TypeProfilerSearchDescriptor descriptor, unsigned divot, intptr_t sourceID, RefPtr<Inspector::InspectorObject>& ret)
{
- ASSERT(m_bucketMap.contains(sourceID));
+ TypeLocation* location = findLocation(divot, sourceID, descriptor);
+ if (!location)
+ return;
+
+ if (location->m_globalTypeSet && location->m_globalVariableID != HighFidelityNoGlobalIDExists) {
+ ret->setString(ASCIILiteral("displayTypeName"), location->m_globalTypeSet->displayName());
+ ret->setArray(ASCIILiteral("globalPrimitiveTypeNames"), location->m_globalTypeSet->allPrimitiveTypeNames()->asArray());
+ ret->setArray(ASCIILiteral("globalStructures"), location->m_globalTypeSet->allStructureRepresentations()->asArray());
+ } else
+ ret->setString(ASCIILiteral("displayTypeName"), location->m_instructionTypeSet->displayName());
+
+ ret->setArray(ASCIILiteral("localPrimitiveTypeNames"), location->m_instructionTypeSet->allPrimitiveTypeNames()->asArray());
+ ret->setArray(ASCIILiteral("localStructures"), location->m_instructionTypeSet->allStructureRepresentations()->asArray());
+}
+
+static bool descriptorMatchesTypeLocation(TypeProfilerSearchDescriptor descriptor, TypeLocation* location)
+{
+ if (descriptor == TypeProfilerSearchDescriptorFunctionReturn && location->m_globalVariableID == HighFidelityReturnStatement)
+ return true;
+
+ if (descriptor == TypeProfilerSearchDescriptorThisStatement && location->m_globalVariableID == HighFidelityThisStatement)
+ return true;
+
+ if (descriptor == TypeProfilerSearchDescriptorNormal && location->m_globalVariableID != HighFidelityReturnStatement && location->m_globalVariableID != HighFidelityThisStatement)
+ return true;
+
+ return false;
+}
+
+TypeLocation* HighFidelityTypeProfiler::findLocation(unsigned divot, intptr_t sourceID, TypeProfilerSearchDescriptor descriptor)
+{
+ QueryKey queryKey(sourceID, divot);
+ auto iter = m_queryCache.find(queryKey);
+ if (iter != m_queryCache.end())
+ return iter->value;
+
+ if (!m_functionHasExecutedCache.hasExecutedAtOffset(sourceID, divot))
+ return nullptr;
+
+ ASSERT(m_bucketMap.contains(sourceID));
Vector<TypeLocation*>& bucket = m_bucketMap.find(sourceID)->value;
- unsigned distance = UINT_MAX; // Because assignments may be nested, make sure we find the closest enclosing assignment to this character offset.
TypeLocation* bestMatch = nullptr;
+ unsigned distance = UINT_MAX; // Because assignments may be nested, make sure we find the closest enclosing assignment to this character offset.
for (size_t i = 0, size = bucket.size(); i < size; i++) {
TypeLocation* location = bucket.at(i);
- if (location->m_divotStart <= divot && divot <= location->m_divotEnd && location->m_divotEnd - location->m_divotStart <= distance) {
+ if (descriptor == TypeProfilerSearchDescriptorFunctionReturn && descriptorMatchesTypeLocation(descriptor, location) && location->m_divotForFunctionOffsetIfReturnStatement == divot)
+ return location;
+
+ if (location->m_divotStart <= divot && divot <= location->m_divotEnd && location->m_divotEnd - location->m_divotStart <= distance && descriptorMatchesTypeLocation(descriptor, location)) {
distance = location->m_divotEnd - location->m_divotStart;
bestMatch = location;
}
}
- // FIXME: BestMatch should never be null. This doesn't hold currently because we ignore some Eval/With/VarInjection variable assignments.
+ if (bestMatch)
+ m_queryCache.set(queryKey, bestMatch);
+ // FIXME: BestMatch should never be null past this point. This doesn't hold currently because we ignore var assignments when code contains eval/With (VarInjection).
+ // https://bugs.webkit.org/show_bug.cgi?id=135184
return bestMatch;
}
diff --git a/Source/JavaScriptCore/runtime/HighFidelityTypeProfiler.h b/Source/JavaScriptCore/runtime/HighFidelityTypeProfiler.h
index e04bb6a..1955d59 100644
--- a/Source/JavaScriptCore/runtime/HighFidelityTypeProfiler.h
+++ b/Source/JavaScriptCore/runtime/HighFidelityTypeProfiler.h
@@ -27,31 +27,93 @@
#define HighFidelityTypeProfiler_h
#include "CodeBlock.h"
-#include <unordered_map>
+#include "FunctionHasExecutedCache.h"
+#include "TypeLocationCache.h"
#include <wtf/HashMap.h>
-#include <wtf/HashMethod.h>
#include <wtf/text/WTFString.h>
#include <wtf/Vector.h>
+namespace Inspector { namespace TypeBuilder { namespace Runtime {
+class TypeDescription;
+}}}
+namespace Inspector {
+class InspectorObject;
+}
+
namespace JSC {
class TypeLocation;
-class HighFidelityTypeProfiler {
+struct QueryKey {
+ QueryKey()
+ : m_sourceID(0)
+ , m_divot(0)
+ { }
-public:
- String getTypesForVariableInAtOffset(unsigned divot, const String& variableName, intptr_t sourceID);
- String getGlobalTypesForVariableAtOffset(unsigned divot, const String& variableName, intptr_t sourceID);
- String getLocalTypesForVariableAtOffset(unsigned divot, const String& variableName, intptr_t sourceID);
- void insertNewLocation(TypeLocation*);
-
-private:
- TypeLocation* findLocation(unsigned divot, intptr_t sourceID);
+ QueryKey(intptr_t sourceID, unsigned divot)
+ : m_sourceID(sourceID)
+ , m_divot(divot)
+ { }
- typedef HashMap<intptr_t, Vector<TypeLocation*>> SourceIDToLocationBucketMap;
- SourceIDToLocationBucketMap m_bucketMap;
+ QueryKey(WTF::HashTableDeletedValueType)
+ : m_sourceID(INTPTR_MAX)
+ , m_divot(UINT_MAX)
+ { }
+
+ bool isHashTableDeletedValue() const { return m_sourceID == INTPTR_MAX && m_divot == UINT_MAX; }
+ bool operator==(const QueryKey& other) const { return m_sourceID == other.m_sourceID && m_divot == other.m_divot; }
+ unsigned hash() const { return m_sourceID + m_divot; }
+
+ intptr_t m_sourceID;
+ unsigned m_divot;
+};
+
+struct QueryKeyHash {
+ static unsigned hash(const QueryKey& key) { return key.hash(); }
+ static bool equal(const QueryKey& a, const QueryKey& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
};
} //namespace JSC
+namespace WTF {
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::QueryKey> {
+ typedef JSC::QueryKeyHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::QueryKey> : SimpleClassHashTraits<JSC::QueryKey> { };
+
+} // namespace WTF
+
+namespace JSC {
+
+enum TypeProfilerSearchDescriptor {
+ TypeProfilerSearchDescriptorNormal = 1,
+ TypeProfilerSearchDescriptorThisStatement = 2,
+ TypeProfilerSearchDescriptorFunctionReturn = 3
+};
+
+class HighFidelityTypeProfiler {
+public:
+ void logTypesForTypeLocation(TypeLocation*);
+ void getTypesForVariableAtOffsetForInspector(TypeProfilerSearchDescriptor descriptor, unsigned divot, intptr_t sourceID, RefPtr<Inspector::InspectorObject>&);
+ void insertNewLocation(TypeLocation*);
+ FunctionHasExecutedCache* functionHasExecutedCache() { return &m_functionHasExecutedCache; }
+ TypeLocationCache* typeLocationCache() { return &m_typeLocationCache; }
+
+private:
+ TypeLocation* findLocation(unsigned divot, intptr_t sourceID, TypeProfilerSearchDescriptor descriptor);
+ typedef HashMap<intptr_t, Vector<TypeLocation*>> SourceIDToLocationBucketMap;
+ SourceIDToLocationBucketMap m_bucketMap;
+ FunctionHasExecutedCache m_functionHasExecutedCache;
+ TypeLocationCache m_typeLocationCache;
+ typedef HashMap<QueryKey, TypeLocation*> TypeLocationQueryCache;
+ TypeLocationQueryCache m_queryCache;
+};
+
+} // namespace JSC
+
#endif //HighFidelityTypeProfiler_h
diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp
index c6d1114..c266a01 100644
--- a/Source/JavaScriptCore/runtime/JSActivation.cpp
+++ b/Source/JavaScriptCore/runtime/JSActivation.cpp
@@ -115,14 +115,14 @@
JSActivation* thisObject = jsCast<JSActivation*>(object);
CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(thisObject->m_registers));
- if (mode == IncludeDontEnumProperties && !thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()))
+ if (shouldIncludeDontEnumProperties(mode) && !thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()))
propertyNames.add(exec->propertyNames().arguments);
{
ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock);
SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker);
for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) {
- if (it->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
+ if (it->value.getAttributes() & DontEnum && !shouldIncludeDontEnumProperties(mode))
continue;
if (!thisObject->isValid(it->value))
continue;
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index 8857dab..4ed59d0 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -227,7 +227,7 @@
{
JSArray* thisObject = jsCast<JSArray*>(object);
- if (mode == IncludeDontEnumProperties)
+ if (shouldIncludeDontEnumProperties(mode))
propertyNames.add(exec->propertyNames().length);
JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
diff --git a/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp b/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
index 368b1e3..c1cad10 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
+++ b/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
@@ -119,7 +119,7 @@
{
JSArrayBuffer* thisObject = jsCast<JSArrayBuffer*>(object);
- if (mode == IncludeDontEnumProperties)
+ if (shouldIncludeDontEnumProperties(mode))
array.add(exec->propertyNames().byteLength);
Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp b/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
index c44ab52..cb5c8a2f 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
+++ b/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
@@ -201,7 +201,7 @@
JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
// length/byteOffset/byteLength are DontEnum, at least in Firefox.
- if (mode == IncludeDontEnumProperties) {
+ if (shouldIncludeDontEnumProperties(mode)) {
array.add(exec->propertyNames().byteOffset);
array.add(exec->propertyNames().byteLength);
array.add(exec->propertyNames().buffer);
diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp
index 84349fe..b38f138 100644
--- a/Source/JavaScriptCore/runtime/JSCell.cpp
+++ b/Source/JavaScriptCore/runtime/JSCell.cpp
@@ -236,4 +236,19 @@
return 0;
}
+uint32_t JSCell::getEnumerableLength(ExecState*, JSObject*)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void JSCell::getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void JSCell::getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h
index abf4557..aa6f3a8 100644
--- a/Source/JavaScriptCore/runtime/JSCell.h
+++ b/Source/JavaScriptCore/runtime/JSCell.h
@@ -25,6 +25,7 @@
#include "CallData.h"
#include "ConstructData.h"
+#include "EnumerationMode.h"
#include "Heap.h"
#include "IndexingType.h"
#include "JSLock.h"
@@ -46,11 +47,6 @@
class PropertyNameArray;
class Structure;
-enum EnumerationMode {
- ExcludeDontEnumProperties,
- IncludeDontEnumProperties
-};
-
template<typename T> void* allocateCell(Heap&);
template<typename T> void* allocateCell(Heap&, size_t);
@@ -209,6 +205,11 @@
static NO_RETURN_DUE_TO_CRASH void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static NO_RETURN_DUE_TO_CRASH void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static NO_RETURN_DUE_TO_CRASH void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
+ static NO_RETURN_DUE_TO_CRASH uint32_t getEnumerableLength(ExecState*, JSObject*);
+ static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
static String className(const JSObject*);
JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue);
static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index 4846a2c..56678ee 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -378,7 +378,7 @@
void JSFunction::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
JSFunction* thisObject = jsCast<JSFunction*>(object);
- if (!thisObject->isHostOrBuiltinFunction() && (mode == IncludeDontEnumProperties)) {
+ if (!thisObject->isHostOrBuiltinFunction() && shouldIncludeDontEnumProperties(mode)) {
VM& vm = exec->vm();
// Make sure prototype has been reified.
PropertySlot slot(thisObject);
diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
index 3df2f68..6d0d21f 100644
--- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
+++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
@@ -415,7 +415,7 @@
{
JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
- if (mode == IncludeDontEnumProperties)
+ if (shouldIncludeDontEnumProperties(mode))
array.add(exec->propertyNames().length);
Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index cbe8053..2412ab6 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -76,7 +76,7 @@
continue;
for (auto iter = table->begin(); iter != table->end(); ++iter) {
- if ((!(iter->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((iter->attributes() & BuiltinOrFunction) && didReify))
+ if ((!(iter->attributes() & DontEnum) || shouldIncludeDontEnumProperties(mode)) && !((iter->attributes() & BuiltinOrFunction) && didReify))
propertyNames.add(Identifier(&vm, iter.key()));
}
}
@@ -1305,6 +1305,12 @@
return const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
}
+bool JSObject::hasOwnProperty(ExecState* exec, unsigned propertyName) const
+{
+ PropertySlot slot(this);
+ return const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlotByIndex(const_cast<JSObject*>(this), exec, propertyName, slot);
+}
+
bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
{
JSObject* thisObject = jsCast<JSObject*>(cell);
@@ -1485,6 +1491,12 @@
void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
+ if (!shouldIncludeJSObjectPropertyNames(mode)) {
+ // We still have to get non-indexed properties from any subclasses of JSObject that have them.
+ object->methodTable(exec->vm())->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
+ return;
+ }
+
// Add numeric properties first. That appears to be the accepted convention.
// FIXME: Filling PropertyNameArray with an identifier for every integer
// is incredibly inefficient for large arrays. We need a different approach,
@@ -1501,7 +1513,7 @@
for (unsigned i = 0; i < usedLength; ++i) {
if (!butterfly->contiguous()[i])
continue;
- propertyNames.add(Identifier::from(exec, i));
+ propertyNames.add(i);
}
break;
}
@@ -1513,7 +1525,7 @@
double value = butterfly->contiguousDouble()[i];
if (value != value)
continue;
- propertyNames.add(Identifier::from(exec, i));
+ propertyNames.add(i);
}
break;
}
@@ -1524,7 +1536,7 @@
unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
for (unsigned i = 0; i < usedVectorLength; ++i) {
if (storage->m_vector[i])
- propertyNames.add(Identifier::from(exec, i));
+ propertyNames.add(i);
}
if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
@@ -1533,13 +1545,13 @@
SparseArrayValueMap::const_iterator end = map->end();
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
- if (mode == IncludeDontEnumProperties || !(it->value.attributes & DontEnum))
+ if (shouldIncludeDontEnumProperties(mode) || !(it->value.attributes & DontEnum))
keys.uncheckedAppend(static_cast<unsigned>(it->key));
}
std::sort(keys.begin(), keys.end());
for (unsigned i = 0; i < keys.size(); ++i)
- propertyNames.add(Identifier::from(exec, keys[i]));
+ propertyNames.add(keys[i]);
}
break;
}
@@ -1547,7 +1559,7 @@
default:
RELEASE_ASSERT_NOT_REACHED();
}
-
+
object->methodTable(exec->vm())->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
}
@@ -1555,12 +1567,11 @@
{
getClassPropertyNames(exec, object->classInfo(), propertyNames, mode, object->staticFunctionsReified());
+ if (!shouldIncludeJSObjectPropertyNames(mode))
+ return;
+
VM& vm = exec->vm();
- bool canCachePropertiesFromStructure = !propertyNames.size();
object->structure(vm)->getPropertyNamesFromStructure(vm, propertyNames, mode);
-
- if (canCachePropertiesFromStructure)
- propertyNames.setNumCacheableSlotsForObject(object, propertyNames.size());
}
double JSObject::toNumber(ExecState* exec) const
@@ -2691,4 +2702,85 @@
setButterflyWithoutChangingStructure(vm, Butterfly::fromBase(newBase, preCapacity, outOfLineCapacityAfter));
}
+uint32_t JSObject::getEnumerableLength(ExecState* exec, JSObject* object)
+{
+ VM& vm = exec->vm();
+ Structure* structure = object->structure(vm);
+ if (structure->holesMustForwardToPrototype(vm))
+ return 0;
+ switch (object->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return 0;
+
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = object->butterfly();
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ if (!butterfly->contiguous()[i])
+ return 0;
+ }
+ return usedLength;
+ }
+
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = object->butterfly();
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ double value = butterfly->contiguousDouble()[i];
+ if (value != value)
+ return 0;
+ }
+ return usedLength;
+ }
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
+ ArrayStorage* storage = object->m_butterfly->arrayStorage();
+ if (storage->m_sparseMap.get())
+ return 0;
+
+ unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
+ for (unsigned i = 0; i < usedVectorLength; ++i) {
+ if (!storage->m_vector[i])
+ return 0;
+ }
+ return usedVectorLength;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+void JSObject::getStructurePropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ VM& vm = exec->vm();
+ object->structure(vm)->getPropertyNamesFromStructure(vm, propertyNames, mode);
+}
+
+void JSObject::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ VM& vm = exec->vm();
+ object->methodTable(vm)->getOwnPropertyNames(object, exec, propertyNames, modeThatSkipsJSObject(mode));
+
+ if (object->prototype().isNull())
+ return;
+
+ JSObject* prototype = asObject(object->prototype());
+ while (true) {
+ if (prototype->structure(vm)->typeInfo().overridesGetPropertyNames()) {
+ prototype->methodTable(vm)->getPropertyNames(prototype, exec, propertyNames, mode);
+ break;
+ }
+ prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode);
+ JSValue nextProto = prototype->prototype();
+ if (nextProto.isNull())
+ break;
+ prototype = asObject(nextProto);
+ }
+}
+
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 5b73b7f..6b7496d 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -464,6 +464,7 @@
JS_EXPORT_PRIVATE bool hasProperty(ExecState*, PropertyName) const;
JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const;
bool hasOwnProperty(ExecState*, PropertyName) const;
+ bool hasOwnProperty(ExecState*, unsigned) const;
JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
@@ -477,6 +478,10 @@
JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static uint32_t getEnumerableLength(ExecState*, JSObject*);
+ JS_EXPORT_PRIVATE static void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp
new file mode 100644
index 0000000..affa8d1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 "JSPropertyNameEnumerator.h"
+
+#include "JSCInlines.h"
+#include "StrongInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSPropertyNameEnumerator::s_info = { "JSPropertyNameEnumerator", 0, 0, CREATE_METHOD_TABLE(JSPropertyNameEnumerator) };
+
+JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm)
+{
+ if (!vm.emptyPropertyNameEnumerator.get()) {
+ PropertyNameArray propertyNames(&vm);
+ vm.emptyPropertyNameEnumerator = Strong<JSCell>(vm, create(vm, 0, propertyNames));
+ }
+ return jsCast<JSPropertyNameEnumerator*>(vm.emptyPropertyNameEnumerator.get());
+}
+
+JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm, Structure* structure, PropertyNameArray& propertyNames)
+{
+ StructureID structureID = structure ? structure->id() : 0;
+ uint32_t inlineCapacity = structure ? structure->inlineCapacity() : 0;
+ JSPropertyNameEnumerator* enumerator = new (NotNull,
+ allocateCell<JSPropertyNameEnumerator>(vm.heap)) JSPropertyNameEnumerator(vm, structureID, inlineCapacity, propertyNames.identifierSet());
+ enumerator->finishCreation(vm, propertyNames.data());
+ return enumerator;
+}
+
+JSPropertyNameEnumerator::JSPropertyNameEnumerator(VM& vm, StructureID structureID, uint32_t inlineCapacity, RefCountedIdentifierSet* set)
+ : JSCell(vm, vm.propertyNameEnumeratorStructure.get())
+ , m_identifierSet(set)
+ , m_cachedStructureID(structureID)
+ , m_cachedInlineCapacity(inlineCapacity)
+{
+}
+
+void JSPropertyNameEnumerator::finishCreation(VM& vm, PassRefPtr<PropertyNameArrayData> idents)
+{
+ Base::finishCreation(vm);
+
+ RefPtr<PropertyNameArrayData> identifiers = idents;
+ PropertyNameArrayData::PropertyNameVector& vector = identifiers->propertyNameVector();
+ m_propertyNames.resize(vector.size());
+ for (unsigned i = 0; i < vector.size(); ++i) {
+ const Identifier& identifier = vector[i];
+ m_propertyNames[i].set(vm, this, jsString(&vm, identifier.string()));
+ }
+}
+
+void JSPropertyNameEnumerator::destroy(JSCell* cell)
+{
+ jsCast<JSPropertyNameEnumerator*>(cell)->JSPropertyNameEnumerator::~JSPropertyNameEnumerator();
+}
+
+void JSPropertyNameEnumerator::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ Base::visitChildren(cell, visitor);
+ JSPropertyNameEnumerator* thisObject = jsCast<JSPropertyNameEnumerator*>(cell);
+ for (unsigned i = 0; i < thisObject->m_propertyNames.size(); ++i)
+ visitor.append(&thisObject->m_propertyNames[i]);
+ visitor.append(&thisObject->m_prototypeChain);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h b/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h
new file mode 100644
index 0000000..9a5a6e3
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h
@@ -0,0 +1,155 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 JSPropertyNameEnumerator_h
+#define JSPropertyNameEnumerator_h
+
+#include "JSCell.h"
+#include "Operations.h"
+#include "PropertyNameArray.h"
+#include "Structure.h"
+
+namespace JSC {
+
+class Identifier;
+
+class JSPropertyNameEnumerator : public JSCell {
+public:
+ typedef JSCell Base;
+
+ static JSPropertyNameEnumerator* create(VM&);
+ static JSPropertyNameEnumerator* create(VM&, Structure*, PropertyNameArray&);
+
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
+ static void destroy(JSCell*);
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+ }
+
+ DECLARE_EXPORT_INFO;
+
+ JSString* propertyNameAtIndex(uint32_t index) const
+ {
+ if (index >= m_propertyNames.size())
+ return nullptr;
+ return m_propertyNames[index].get();
+ }
+
+ RefCountedIdentifierSet* identifierSet() const
+ {
+ return m_identifierSet.get();
+ }
+
+ StructureChain* cachedPrototypeChain() const { return m_prototypeChain.get(); }
+ void setCachedPrototypeChain(VM& vm, StructureChain* prototypeChain) { return m_prototypeChain.set(vm, this, prototypeChain); }
+
+ Structure* cachedStructure(VM& vm) const { return vm.heap.structureIDTable().get(m_cachedStructureID); }
+ StructureID cachedStructureID() const { return m_cachedStructureID; }
+ uint32_t cachedInlineCapacity() const { return m_cachedInlineCapacity; }
+ static ptrdiff_t cachedStructureIDOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedStructureID); }
+ static ptrdiff_t cachedInlineCapacityOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedInlineCapacity); }
+ static ptrdiff_t cachedPropertyNamesLengthOffset()
+ {
+ return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_propertyNames) + Vector<WriteBarrier<JSString>>::sizeMemoryOffset();
+ }
+ static ptrdiff_t cachedPropertyNamesVectorOffset()
+ {
+ return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_propertyNames) + Vector<WriteBarrier<JSString>>::dataMemoryOffset();
+ }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+private:
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+ JSPropertyNameEnumerator(VM&, StructureID, uint32_t, RefCountedIdentifierSet*);
+ void finishCreation(VM&, PassRefPtr<PropertyNameArrayData>);
+
+ Vector<WriteBarrier<JSString>> m_propertyNames;
+ RefPtr<RefCountedIdentifierSet> m_identifierSet;
+ StructureID m_cachedStructureID;
+ WriteBarrier<StructureChain> m_prototypeChain;
+ uint32_t m_cachedInlineCapacity;
+};
+
+inline JSPropertyNameEnumerator* structurePropertyNameEnumerator(ExecState* exec, JSObject* base, uint32_t length)
+{
+ VM& vm = exec->vm();
+ Structure* structure = base->structure(vm);
+ if (JSPropertyNameEnumerator* enumerator = structure->cachedStructurePropertyNameEnumerator())
+ return enumerator;
+
+ if (!structure->canAccessPropertiesQuickly() || length != base->getArrayLength())
+ return JSPropertyNameEnumerator::create(vm);
+
+ PropertyNameArray propertyNames(exec);
+ base->methodTable(vm)->getStructurePropertyNames(base, exec, propertyNames, ExcludeDontEnumProperties);
+
+ JSPropertyNameEnumerator* enumerator = JSPropertyNameEnumerator::create(vm, structure, propertyNames);
+ if (structure->canCacheStructurePropertyNameEnumerator())
+ structure->setCachedStructurePropertyNameEnumerator(vm, enumerator);
+ return enumerator;
+}
+
+inline JSPropertyNameEnumerator* genericPropertyNameEnumerator(ExecState* exec, JSObject* base, uint32_t length, JSPropertyNameEnumerator* structureEnumerator)
+{
+ VM& vm = exec->vm();
+ Structure* structure = base->structure(vm);
+ if (JSPropertyNameEnumerator* enumerator = structure->cachedGenericPropertyNameEnumerator()) {
+ if (!length && enumerator->cachedPrototypeChain() == structure->prototypeChain(exec))
+ return enumerator;
+ }
+
+ PropertyNameArray propertyNames(exec);
+ propertyNames.setPreviouslyEnumeratedLength(length);
+ propertyNames.setPreviouslyEnumeratedProperties(structureEnumerator);
+
+ // If we still have the same Structure that we started with, our Structure allows us to access its properties
+ // quickly (i.e. the Structure property loop was able to do things), and we iterated the full length of the
+ // object (i.e. there are no more own indexed properties that need to be enumerated), then the generic property
+ // iteration can skip any properties it would get from the JSObject base class. This turns out to be important
+ // for hot loops because most of our time is then dominated by trying to add the own Structure properties to
+ // the new generic PropertyNameArray and failing because we've already visited them.
+ Structure* cachedStructure = structureEnumerator->cachedStructure(vm);
+ if (structure == cachedStructure && structure->canAccessPropertiesQuickly() && static_cast<uint32_t>(length) == base->getArrayLength())
+ base->methodTable(vm)->getGenericPropertyNames(base, exec, propertyNames, ExcludeDontEnumProperties);
+ else
+ base->methodTable(vm)->getPropertyNames(base, exec, propertyNames, ExcludeDontEnumProperties);
+
+ normalizePrototypeChain(exec, base);
+
+ JSPropertyNameEnumerator* enumerator = JSPropertyNameEnumerator::create(vm, base->structure(vm), propertyNames);
+ enumerator->setCachedPrototypeChain(vm, structure->prototypeChain(exec));
+ if (!length && structure->canCacheGenericPropertyNameEnumerator())
+ structure->setCachedGenericPropertyNameEnumerator(vm, enumerator);
+ return enumerator;
+}
+
+} // namespace JSC
+
+#endif // JSPropertyNameEnumerator_h
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
deleted file mode 100644
index 7c39cd8..0000000
--- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2008, 2009 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.
- * 3. Neither the name of Apple Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "JSPropertyNameIterator.h"
-
-#include "JSCInlines.h"
-#include "JSGlobalObject.h"
-#include <wtf/StdLibExtras.h>
-
-namespace JSC {
-
-const ClassInfo JSPropertyNameIterator::s_info = { "JSPropertyNameIterator", 0, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) };
-
-inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots)
- : JSCell(exec->vm(), exec->vm().propertyNameIteratorStructure.get())
- , m_numCacheableSlots(numCacheableSlots)
- , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size())
- , m_jsStrings(m_jsStringsSize ? std::make_unique<WriteBarrier<Unknown>[]>(m_jsStringsSize) : nullptr)
-{
-}
-
-JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o)
-{
- ASSERT(!o->structure()->enumerationCache() ||
- o->structure()->enumerationCache()->cachedStructure() != o->structure() ||
- o->structure()->enumerationCache()->cachedPrototypeChain() != o->structure()->prototypeChain(exec));
-
- VM& vm = exec->vm();
-
- PropertyNameArray propertyNames(exec);
- o->methodTable()->getPropertyNames(o, exec, propertyNames, ExcludeDontEnumProperties);
- size_t numCacheableSlots = 0;
- if (!o->structure()->hasNonEnumerableProperties() && !o->structure()->hasGetterSetterProperties()
- && !o->structure()->isUncacheableDictionary() && !o->structure()->typeInfo().overridesGetPropertyNames())
- numCacheableSlots = propertyNames.numCacheableSlots();
-
- JSPropertyNameIterator* jsPropertyNameIterator = new (NotNull, allocateCell<JSPropertyNameIterator>(vm.heap)) JSPropertyNameIterator(exec, propertyNames.data(), numCacheableSlots);
- jsPropertyNameIterator->finishCreation(vm, propertyNames.data(), o);
-
- if (o->structure()->isDictionary())
- return jsPropertyNameIterator;
-
- if (o->structure()->typeInfo().overridesGetPropertyNames())
- return jsPropertyNameIterator;
-
- if (hasIndexedProperties(o->indexingType()))
- return jsPropertyNameIterator;
-
- size_t count = normalizePrototypeChain(exec, o);
- StructureChain* structureChain = o->structure()->prototypeChain(exec);
- WriteBarrier<Structure>* structure = structureChain->head();
- for (size_t i = 0; i < count; ++i) {
- if (structure[i]->typeInfo().overridesGetPropertyNames())
- return jsPropertyNameIterator;
- }
-
- jsPropertyNameIterator->setCachedPrototypeChain(vm, structureChain);
- jsPropertyNameIterator->setCachedStructure(vm, o->structure());
- o->structure()->setEnumerationCache(vm, jsPropertyNameIterator);
- return jsPropertyNameIterator;
-}
-
-void JSPropertyNameIterator::destroy(JSCell* cell)
-{
- static_cast<JSPropertyNameIterator*>(cell)->JSPropertyNameIterator::~JSPropertyNameIterator();
-}
-
-JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i)
-{
- JSValue identifier = m_jsStrings[i].get();
- if (m_cachedStructure.get() == base->structure() && m_cachedPrototypeChain.get() == base->structure()->prototypeChain(exec))
- return identifier;
-
- if (!base->hasProperty(exec, Identifier(exec, asString(identifier)->value(exec))))
- return JSValue();
- return identifier;
-}
-
-void JSPropertyNameIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- JSPropertyNameIterator* thisObject = jsCast<JSPropertyNameIterator*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- visitor.appendValues(thisObject->m_jsStrings.get(), thisObject->m_jsStringsSize);
- visitor.append(&thisObject->m_cachedPrototypeChain);
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
deleted file mode 100644
index e7bf9af..0000000
--- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2008, 2009 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.
- * 3. Neither the name of Apple Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 JSPropertyNameIterator_h
-#define JSPropertyNameIterator_h
-
-#include "JSObject.h"
-#include "JSString.h"
-#include "PropertyNameArray.h"
-#include <memory>
-
-namespace JSC {
-
- class Identifier;
- class JSObject;
- class LLIntOffsetsExtractor;
-
- class JSPropertyNameIterator : public JSCell {
- friend class JIT;
-
- public:
- typedef JSCell Base;
-
- static JSPropertyNameIterator* create(ExecState*, JSObject*);
-
- static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
- static void destroy(JSCell*);
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
- }
-
- static void visitChildren(JSCell*, SlotVisitor&);
-
- JSValue get(ExecState*, JSObject*, size_t i);
- size_t size() { return m_jsStringsSize; }
-
- void setCachedStructure(VM& vm, Structure* structure)
- {
- ASSERT(!m_cachedStructure);
- ASSERT(structure);
- m_cachedStructure.set(vm, this, structure);
- }
- Structure* cachedStructure() { return m_cachedStructure.get(); }
-
- void setCachedPrototypeChain(VM& vm, StructureChain* cachedPrototypeChain) { m_cachedPrototypeChain.set(vm, this, cachedPrototypeChain); }
- StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); }
-
- DECLARE_EXPORT_INFO;
-
- protected:
- static const unsigned StructureFlags = StructureIsImmortal;
-
- void finishCreation(VM& vm, PropertyNameArrayData* propertyNameArrayData, JSObject* object)
- {
- Base::finishCreation(vm);
- PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector();
- for (size_t i = 0; i < m_jsStringsSize; ++i)
- m_jsStrings[i].set(vm, this, jsOwnedString(&vm, propertyNameVector[i].string()));
- m_cachedStructureInlineCapacity = object->structure()->inlineCapacity();
- }
-
- private:
- friend class LLIntOffsetsExtractor;
-
- JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot);
-
- WriteBarrier<Structure> m_cachedStructure;
- WriteBarrier<StructureChain> m_cachedPrototypeChain;
- uint32_t m_numCacheableSlots;
- uint32_t m_jsStringsSize;
- unsigned m_cachedStructureInlineCapacity;
- std::unique_ptr<WriteBarrier<Unknown>[]> m_jsStrings;
- };
-
- ALWAYS_INLINE JSPropertyNameIterator* Register::propertyNameIterator() const
- {
- return jsCast<JSPropertyNameIterator*>(jsValue().asCell());
- }
-
- inline JSPropertyNameIterator* StructureRareData::enumerationCache()
- {
- return m_enumerationCache.get();
- }
-
- inline void StructureRareData::setEnumerationCache(VM& vm, JSPropertyNameIterator* value)
- {
- m_enumerationCache.set(vm, this, value);
- }
-
-} // namespace JSC
-
-#endif // JSPropertyNameIterator_h
diff --git a/Source/JavaScriptCore/runtime/JSProxy.cpp b/Source/JavaScriptCore/runtime/JSProxy.cpp
index d70bc49..4070bf1 100644
--- a/Source/JavaScriptCore/runtime/JSProxy.cpp
+++ b/Source/JavaScriptCore/runtime/JSProxy.cpp
@@ -114,6 +114,24 @@
thisObject->target()->methodTable(exec->vm())->getPropertyNames(thisObject->target(), exec, propertyNames, mode);
}
+uint32_t JSProxy::getEnumerableLength(ExecState* exec, JSObject* object)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ return thisObject->target()->methodTable(exec->vm())->getEnumerableLength(exec, thisObject->target());
+}
+
+void JSProxy::getStructurePropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ thisObject->target()->methodTable(exec->vm())->getStructurePropertyNames(thisObject->target(), exec, propertyNames, mode);
+}
+
+void JSProxy::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ thisObject->target()->methodTable(exec->vm())->getGenericPropertyNames(thisObject->target(), exec, propertyNames, mode);
+}
+
void JSProxy::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
JSProxy* thisObject = jsCast<JSProxy*>(object);
diff --git a/Source/JavaScriptCore/runtime/JSProxy.h b/Source/JavaScriptCore/runtime/JSProxy.h
index 4be56a2..cda621b 100644
--- a/Source/JavaScriptCore/runtime/JSProxy.h
+++ b/Source/JavaScriptCore/runtime/JSProxy.h
@@ -83,6 +83,9 @@
JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned);
JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static uint32_t getEnumerableLength(ExecState*, JSObject*);
+ JS_EXPORT_PRIVATE static void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
private:
diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
index 31a8359..5cfd421 100644
--- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
@@ -63,7 +63,7 @@
for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) {
if (it->key->isEmptyUnique())
continue;
- if (!(it->value.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties))
+ if (!(it->value.getAttributes() & DontEnum) || shouldIncludeDontEnumProperties(mode))
propertyNames.add(Identifier(exec, it->key.get()));
}
}
diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp
index a8f64ea..4475b89 100644
--- a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp
+++ b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp
@@ -23,33 +23,32 @@
#include "JSCInlines.h"
#include "JSObject.h"
+#include "JSPropertyNameEnumerator.h"
#include "Structure.h"
#include "StructureChain.h"
namespace JSC {
-static const size_t setThreshold = 20;
-
void PropertyNameArray::add(StringImpl* identifier)
{
ASSERT(!identifier || identifier == StringImpl::empty() || identifier->isAtomic());
-
- size_t size = m_data->propertyNameVector().size();
- if (size < setThreshold) {
- for (size_t i = 0; i < size; ++i) {
- if (identifier == m_data->propertyNameVector()[i].impl())
- return;
- }
- } else {
- if (m_set.isEmpty()) {
- for (size_t i = 0; i < size; ++i)
- m_set.add(m_data->propertyNameVector()[i].impl());
- }
- if (!m_set.add(identifier).isNewEntry)
- return;
+ if (!ASSERT_DISABLED) {
+ uint32_t index = PropertyName(Identifier(m_vm, identifier)).asIndex();
+ ASSERT_UNUSED(index, index == PropertyName::NotAnIndex || index >= m_previouslyEnumeratedLength);
}
+ if (m_alternateSet && m_alternateSet->contains(identifier))
+ return;
+
+ if (!m_set->add(identifier).isNewEntry)
+ return;
+
addKnownUnique(identifier);
}
+void PropertyNameArray::setPreviouslyEnumeratedProperties(const JSPropertyNameEnumerator* enumerator)
+{
+ m_alternateSet = enumerator->identifierSet();
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.h b/Source/JavaScriptCore/runtime/PropertyNameArray.h
index bfbddaa..994f09c 100644
--- a/Source/JavaScriptCore/runtime/PropertyNameArray.h
+++ b/Source/JavaScriptCore/runtime/PropertyNameArray.h
@@ -27,88 +27,122 @@
#include <wtf/Vector.h>
namespace JSC {
-
- class Structure;
- class StructureChain;
- // FIXME: Rename to PropertyNameArray.
- class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> {
- public:
- typedef Vector<Identifier, 20> PropertyNameVector;
+class JSPropertyNameEnumerator;
+class Structure;
+class StructureChain;
- static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); }
+class RefCountedIdentifierSet : public RefCounted<RefCountedIdentifierSet> {
+public:
+ typedef HashSet<StringImpl*, PtrHash<StringImpl*>> Set;
- PropertyNameVector& propertyNameVector() { return m_propertyNameVector; }
+ bool contains(StringImpl* impl) const { return m_set.contains(impl); }
+ size_t size() const { return m_set.size(); }
+ Set::AddResult add(StringImpl* impl) { return m_set.add(impl); }
- private:
- PropertyNameArrayData()
- {
- }
+private:
+ Set m_set;
+};
- PropertyNameVector m_propertyNameVector;
- };
+// FIXME: Rename to PropertyNameArray.
+class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> {
+public:
+ typedef Vector<Identifier, 20> PropertyNameVector;
- // FIXME: Rename to PropertyNameArrayBuilder.
- class PropertyNameArray {
- public:
- PropertyNameArray(VM* vm)
- : m_data(PropertyNameArrayData::create())
- , m_vm(vm)
- , m_numCacheableSlots(0)
- , m_baseObject(0)
- {
- }
+ static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); }
- PropertyNameArray(ExecState* exec)
- : m_data(PropertyNameArrayData::create())
- , m_vm(&exec->vm())
- , m_numCacheableSlots(0)
- , m_baseObject(0)
- {
- }
+ PropertyNameVector& propertyNameVector() { return m_propertyNameVector; }
- VM* vm() { return m_vm; }
+private:
+ PropertyNameArrayData()
+ {
+ }
- void add(const Identifier& identifier) { add(identifier.impl()); }
- JS_EXPORT_PRIVATE void add(StringImpl*);
- void addKnownUnique(StringImpl* identifier) { m_data->propertyNameVector().append(Identifier(m_vm, identifier)); }
+ PropertyNameVector m_propertyNameVector;
+};
- Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; }
- const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; }
+// FIXME: Rename to PropertyNameArrayBuilder.
+class PropertyNameArray {
+public:
+ PropertyNameArray(VM* vm)
+ : m_data(PropertyNameArrayData::create())
+ , m_set(adoptRef(new RefCountedIdentifierSet))
+ , m_vm(vm)
+ , m_numCacheableSlots(0)
+ , m_baseObject(0)
+ , m_previouslyEnumeratedLength(0)
+ {
+ }
- void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; }
- PropertyNameArrayData* data() { return m_data.get(); }
- PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); }
+ PropertyNameArray(ExecState* exec)
+ : m_data(PropertyNameArrayData::create())
+ , m_set(adoptRef(new RefCountedIdentifierSet))
+ , m_vm(&exec->vm())
+ , m_numCacheableSlots(0)
+ , m_baseObject(0)
+ , m_previouslyEnumeratedLength(0)
+ {
+ }
- // FIXME: Remove these functions.
- typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator;
- size_t size() const { return m_data->propertyNameVector().size(); }
- const_iterator begin() const { return m_data->propertyNameVector().begin(); }
- const_iterator end() const { return m_data->propertyNameVector().end(); }
+ VM* vm() { return m_vm; }
- size_t numCacheableSlots() const { return m_numCacheableSlots; }
- void setNumCacheableSlotsForObject(JSObject* object, size_t numCacheableSlots)
- {
- if (object != m_baseObject)
- return;
- m_numCacheableSlots = numCacheableSlots;
- }
- void setBaseObject(JSObject* object)
- {
- if (m_baseObject)
- return;
- m_baseObject = object;
- }
+ void add(uint32_t index)
+ {
+ if (index < m_previouslyEnumeratedLength)
+ return;
+ add(Identifier::from(m_vm, index));
+ }
- private:
- typedef HashSet<StringImpl*, PtrHash<StringImpl*>> IdentifierSet;
+ void add(const Identifier& identifier) { add(identifier.impl()); }
+ JS_EXPORT_PRIVATE void add(StringImpl*);
+ void addKnownUnique(StringImpl* identifier)
+ {
+ m_set->add(identifier);
+ m_data->propertyNameVector().append(Identifier(m_vm, identifier));
+ }
- RefPtr<PropertyNameArrayData> m_data;
- IdentifierSet m_set;
- VM* m_vm;
- size_t m_numCacheableSlots;
- JSObject* m_baseObject;
- };
+ Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; }
+ const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; }
+
+ void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; }
+ PropertyNameArrayData* data() { return m_data.get(); }
+ PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); }
+
+ RefCountedIdentifierSet* identifierSet() const { return m_set.get(); }
+
+ // FIXME: Remove these functions.
+ bool canAddKnownUniqueForStructure() const { return !m_set->size() && (!m_alternateSet || !m_alternateSet->size()); }
+ typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator;
+ size_t size() const { return m_data->propertyNameVector().size(); }
+ const_iterator begin() const { return m_data->propertyNameVector().begin(); }
+ const_iterator end() const { return m_data->propertyNameVector().end(); }
+
+ size_t numCacheableSlots() const { return m_numCacheableSlots; }
+ void setNumCacheableSlotsForObject(JSObject* object, size_t numCacheableSlots)
+ {
+ if (object != m_baseObject)
+ return;
+ m_numCacheableSlots = numCacheableSlots;
+ }
+ void setBaseObject(JSObject* object)
+ {
+ if (m_baseObject)
+ return;
+ m_baseObject = object;
+ }
+
+ void setPreviouslyEnumeratedLength(uint32_t length) { m_previouslyEnumeratedLength = length; }
+ void setPreviouslyEnumeratedProperties(const JSPropertyNameEnumerator*);
+
+private:
+ RefPtr<PropertyNameArrayData> m_data;
+ RefPtr<RefCountedIdentifierSet> m_set;
+ RefPtr<RefCountedIdentifierSet> m_alternateSet;
+ VM* m_vm;
+ size_t m_numCacheableSlots;
+ JSObject* m_baseObject;
+ uint32_t m_previouslyEnumeratedLength;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp
index 038bd78..9b173fc 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp
@@ -106,18 +106,25 @@
void RegExpObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- if (mode == IncludeDontEnumProperties)
+ if (shouldIncludeDontEnumProperties(mode))
propertyNames.add(exec->propertyNames().lastIndex);
Base::getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
}
void RegExpObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- if (mode == IncludeDontEnumProperties)
+ if (shouldIncludeDontEnumProperties(mode))
propertyNames.add(exec->propertyNames().lastIndex);
Base::getPropertyNames(object, exec, propertyNames, mode);
}
+void RegExpObject::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ if (shouldIncludeDontEnumProperties(mode))
+ propertyNames.add(exec->propertyNames().lastIndex);
+ Base::getGenericPropertyNames(object, exec, propertyNames, mode);
+}
+
static bool reject(ExecState* exec, bool throwException, const char* message)
{
if (throwException)
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.h b/Source/JavaScriptCore/runtime/RegExpObject.h
index a33f6b5..870038c 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.h
+++ b/Source/JavaScriptCore/runtime/RegExpObject.h
@@ -77,13 +77,14 @@
JS_EXPORT_PRIVATE RegExpObject(VM&, Structure*, RegExp*);
JS_EXPORT_PRIVATE void finishCreation(VM&);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | Base::StructureFlags;
static void visitChildren(JSCell*, SlotVisitor&);
JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
private:
diff --git a/Source/JavaScriptCore/runtime/StringObject.cpp b/Source/JavaScriptCore/runtime/StringObject.cpp
index 30c0150..5001bcc 100644
--- a/Source/JavaScriptCore/runtime/StringObject.cpp
+++ b/Source/JavaScriptCore/runtime/StringObject.cpp
@@ -150,7 +150,7 @@
int size = thisObject->internalValue()->length();
for (int i = 0; i < size; ++i)
propertyNames.add(Identifier::from(exec, i));
- if (mode == IncludeDontEnumProperties)
+ if (shouldIncludeDontEnumProperties(mode))
propertyNames.add(exec->propertyNames().length);
return JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
}
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index 542a997..674f2b4 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -30,7 +30,7 @@
#include "DumpContext.h"
#include "JSCInlines.h"
#include "JSObject.h"
-#include "JSPropertyNameIterator.h"
+#include "JSPropertyNameEnumerator.h"
#include "Lookup.h"
#include "PropertyMapHashTable.h"
#include "PropertyNameArray.h"
@@ -712,8 +712,6 @@
PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes)
{
- ASSERT(!enumerationCache());
-
DeferGC deferGC(vm.heap);
materializePropertyMapIfNecessaryForPinning(vm, deferGC);
@@ -725,7 +723,6 @@
PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, PropertyName propertyName)
{
ASSERT(isUncacheableDictionary());
- ASSERT(!enumerationCache());
DeferGC deferGC(vm.heap);
materializePropertyMapIfNecessaryForPinning(vm, deferGC);
@@ -946,12 +943,12 @@
if (!propertyTable())
return;
- bool knownUnique = !propertyNames.size();
+ bool knownUnique = propertyNames.canAddKnownUniqueForStructure();
PropertyTable::iterator end = propertyTable()->end();
for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
ASSERT(hasNonEnumerableProperties() || !(iter->attributes & DontEnum));
- if (!iter->key->isEmptyUnique() && (!(iter->attributes & DontEnum) || mode == IncludeDontEnumProperties)) {
+ if (!iter->key->isEmptyUnique() && (!(iter->attributes & DontEnum) || shouldIncludeDontEnumProperties(mode))) {
if (knownUnique)
propertyNames.addKnownUnique(iter->key);
else
@@ -1037,36 +1034,73 @@
}
}
-
-PassRefPtr<StructureShape> Structure::toStructureShape()
+PassRefPtr<StructureShape> Structure::toStructureShape(JSValue value)
{
- Vector<Structure*, 8> structures;
- Structure* structure;
- PropertyTable* table;
- RefPtr<StructureShape> shape = StructureShape::create();
+ RefPtr<StructureShape> baseShape = StructureShape::create();
+ RefPtr<StructureShape> curShape = baseShape;
+ Structure* curStructure = this;
+ JSValue curValue = value;
+ while (curStructure) {
+ Vector<Structure*, 8> structures;
+ Structure* structure;
+ PropertyTable* table;
- findStructuresAndMapForMaterialization(structures, structure, table);
-
- if (table) {
- PropertyTable::iterator iter = table->begin();
- PropertyTable::iterator end = table->end();
+ curStructure->findStructuresAndMapForMaterialization(structures, structure, table);
+ if (table) {
+ PropertyTable::iterator iter = table->begin();
+ PropertyTable::iterator end = table->end();
+ for (; iter != end; ++iter)
+ curShape->addProperty(iter->key);
+
+ structure->m_lock.unlock();
+ }
+ for (unsigned i = structures.size(); i--;) {
+ Structure* structure = structures[i];
+ if (structure->m_nameInPrevious)
+ curShape->addProperty(structure->m_nameInPrevious.get());
+ }
- for (; iter != end; ++iter)
- shape->addProperty(iter->key);
-
- structure->m_lock.unlock();
+ bool foundCtorName = false;
+ if (JSObject* profilingVal = curValue.getObject()) {
+ ExecState* exec = profilingVal->globalObject()->globalExec();
+ PropertySlot slot(storedPrototype());
+ PropertyName constructor(exec->propertyNames().constructor);
+ if (profilingVal->getPropertySlot(exec, constructor, slot)) {
+ if (slot.isValue()) {
+ JSValue constructorValue = slot.getValue(exec, constructor);
+ if (constructorValue.isCell()) {
+ if (JSCell* constructorCell = constructorValue.asCell()) {
+ if (JSObject* ctorObject = constructorCell->getObject()) {
+ if (JSFunction* constructorFunction = jsDynamicCast<JSFunction*>(ctorObject)) {
+ curShape->setConstructorName(constructorFunction->calculatedDisplayName(exec));
+ foundCtorName = true;
+ } else if (InternalFunction* constructorFunction = jsDynamicCast<InternalFunction*>(ctorObject)) {
+ curShape->setConstructorName(constructorFunction->calculatedDisplayName(exec));
+ foundCtorName = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!foundCtorName)
+ curShape->setConstructorName(curStructure->classInfo()->className);
+
+ curShape->markAsFinal();
+
+ if (curStructure->storedPrototypeStructure()) {
+ RefPtr<StructureShape> newShape = StructureShape::create();
+ curShape->setProto(newShape);
+ curShape = newShape;
+ curValue = curStructure->storedPrototype();
+ }
+
+ curStructure = curStructure->storedPrototypeStructure();
}
- for (unsigned i = structures.size(); i--;) {
- Structure* structure = structures[i];
- if (!structure->m_nameInPrevious)
- continue;
-
- shape->addProperty(structure->m_nameInPrevious.get());
- }
-
- shape->markAsFinal();
- return shape.release();
+ return baseShape.release();
}
void Structure::dump(PrintStream& out) const
@@ -1212,4 +1246,74 @@
return false;
}
+void Structure::setCachedStructurePropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+{
+ ASSERT(!isDictionary());
+ if (!hasRareData())
+ allocateRareData(vm);
+ rareData()->setCachedStructurePropertyNameEnumerator(vm, enumerator);
+}
+
+JSPropertyNameEnumerator* Structure::cachedStructurePropertyNameEnumerator() const
+{
+ if (!hasRareData())
+ return nullptr;
+ return rareData()->cachedStructurePropertyNameEnumerator();
+}
+
+void Structure::setCachedGenericPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+{
+ ASSERT(!isDictionary());
+ if (!hasRareData())
+ allocateRareData(vm);
+ rareData()->setCachedGenericPropertyNameEnumerator(vm, enumerator);
+}
+
+JSPropertyNameEnumerator* Structure::cachedGenericPropertyNameEnumerator() const
+{
+ if (!hasRareData())
+ return nullptr;
+ return rareData()->cachedGenericPropertyNameEnumerator();
+}
+
+bool Structure::canCacheStructurePropertyNameEnumerator() const
+{
+ if (isDictionary())
+ return false;
+ return true;
+}
+
+bool Structure::canCacheGenericPropertyNameEnumerator() const
+{
+ if (!canCacheStructurePropertyNameEnumerator())
+ return false;
+
+ if (hasIndexedProperties(indexingType()))
+ return false;
+
+ StructureChain* structureChain = m_cachedPrototypeChain.get();
+ ASSERT(structureChain);
+ WriteBarrier<Structure>* structure = structureChain->head();
+ while (true) {
+ if (!structure->get())
+ break;
+ if (structure->get()->typeInfo().overridesGetPropertyNames())
+ return false;
+ structure++;
+ }
+
+ return true;
+}
+
+bool Structure::canAccessPropertiesQuickly() const
+{
+ if (hasNonEnumerableProperties())
+ return false;
+ if (hasGetterSetterProperties())
+ return false;
+ if (isUncacheableDictionary())
+ return false;
+ return true;
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 08fce96..fc9878c 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -288,8 +288,14 @@
return !JSC::isValidOffset(m_offset);
}
- void setEnumerationCache(VM&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
- JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
+ void setCachedStructurePropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
+ void setCachedGenericPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
+ JSPropertyNameEnumerator* cachedStructurePropertyNameEnumerator() const;
+ JSPropertyNameEnumerator* cachedGenericPropertyNameEnumerator() const;
+ bool canCacheStructurePropertyNameEnumerator() const;
+ bool canCacheGenericPropertyNameEnumerator() const;
+ bool canAccessPropertiesQuickly() const;
+
void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
JSString* objectToStringValue()
@@ -397,7 +403,7 @@
structure->startWatchingInternalPropertiesIfNecessary(vm);
}
- PassRefPtr<StructureShape> toStructureShape();
+ PassRefPtr<StructureShape> toStructureShape(JSValue);
void dump(PrintStream&) const;
void dumpInContext(PrintStream&, DumpContext*) const;
diff --git a/Source/JavaScriptCore/runtime/StructureInlines.h b/Source/JavaScriptCore/runtime/StructureInlines.h
index 83bab0c9..ffb7577 100644
--- a/Source/JavaScriptCore/runtime/StructureInlines.h
+++ b/Source/JavaScriptCore/runtime/StructureInlines.h
@@ -148,21 +148,6 @@
return false;
}
-inline void Structure::setEnumerationCache(VM& vm, JSPropertyNameIterator* enumerationCache)
-{
- ASSERT(!isDictionary());
- if (!hasRareData())
- allocateRareData(vm);
- rareData()->setEnumerationCache(vm, enumerationCache);
-}
-
-inline JSPropertyNameIterator* Structure::enumerationCache()
-{
- if (!hasRareData())
- return 0;
- return rareData()->enumerationCache();
-}
-
inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const
{
if (isObject())
diff --git a/Source/JavaScriptCore/runtime/StructureRareData.cpp b/Source/JavaScriptCore/runtime/StructureRareData.cpp
index c4a34dc..ed15302 100644
--- a/Source/JavaScriptCore/runtime/StructureRareData.cpp
+++ b/Source/JavaScriptCore/runtime/StructureRareData.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "StructureRareData.h"
-#include "JSPropertyNameIterator.h"
+#include "JSPropertyNameEnumerator.h"
#include "JSString.h"
#include "JSCInlines.h"
@@ -66,7 +66,28 @@
JSCell::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_previous);
visitor.append(&thisObject->m_objectToStringValue);
- visitor.append(&thisObject->m_enumerationCache);
+ visitor.append(&thisObject->m_cachedStructurePropertyNameEnumerator);
+ visitor.append(&thisObject->m_cachedGenericPropertyNameEnumerator);
+}
+
+JSPropertyNameEnumerator* StructureRareData::cachedStructurePropertyNameEnumerator() const
+{
+ return m_cachedStructurePropertyNameEnumerator.get();
+}
+
+void StructureRareData::setCachedStructurePropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+{
+ m_cachedStructurePropertyNameEnumerator.set(vm, this, enumerator);
+}
+
+JSPropertyNameEnumerator* StructureRareData::cachedGenericPropertyNameEnumerator() const
+{
+ return m_cachedGenericPropertyNameEnumerator.get();
+}
+
+void StructureRareData::setCachedGenericPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+{
+ m_cachedGenericPropertyNameEnumerator.set(vm, this, enumerator);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StructureRareData.h b/Source/JavaScriptCore/runtime/StructureRareData.h
index ae694fe..dab3e5f 100644
--- a/Source/JavaScriptCore/runtime/StructureRareData.h
+++ b/Source/JavaScriptCore/runtime/StructureRareData.h
@@ -33,7 +33,7 @@
namespace JSC {
-class JSPropertyNameIterator;
+class JSPropertyNameEnumerator;
class Structure;
class StructureRareData : public JSCell {
@@ -55,8 +55,10 @@
JSString* objectToStringValue() const;
void setObjectToStringValue(VM&, JSString* value);
- JSPropertyNameIterator* enumerationCache();
- void setEnumerationCache(VM&, JSPropertyNameIterator* value);
+ JSPropertyNameEnumerator* cachedStructurePropertyNameEnumerator() const;
+ JSPropertyNameEnumerator* cachedGenericPropertyNameEnumerator() const;
+ void setCachedStructurePropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
+ void setCachedGenericPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
DECLARE_EXPORT_INFO;
@@ -69,7 +71,8 @@
WriteBarrier<Structure> m_previous;
WriteBarrier<JSString> m_objectToStringValue;
- WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
+ WriteBarrier<JSPropertyNameEnumerator> m_cachedStructurePropertyNameEnumerator;
+ WriteBarrier<JSPropertyNameEnumerator> m_cachedGenericPropertyNameEnumerator;
typedef HashMap<PropertyOffset, RefPtr<WatchpointSet>, WTF::IntHash<PropertyOffset>, WTF::UnsignedWithZeroKeyHashTraits<PropertyOffset>> PropertyWatchpointMap;
std::unique_ptr<PropertyWatchpointMap> m_replacementWatchpointSets;
diff --git a/Source/JavaScriptCore/runtime/SymbolTable.cpp b/Source/JavaScriptCore/runtime/SymbolTable.cpp
index 206e11c..e1784c5 100644
--- a/Source/JavaScriptCore/runtime/SymbolTable.cpp
+++ b/Source/JavaScriptCore/runtime/SymbolTable.cpp
@@ -192,13 +192,13 @@
return result;
}
-int64_t SymbolTable::uniqueIDForVariable(const ConcurrentJITLocker&, StringImpl* key, VM& vm)
+GlobalVariableID SymbolTable::uniqueIDForVariable(const ConcurrentJITLocker&, StringImpl* key, VM& vm)
{
auto iter = m_uniqueIDMap->find(key);
auto end = m_uniqueIDMap->end();
ASSERT_UNUSED(end, iter != end);
- int64_t& id = iter->value;
+ GlobalVariableID& id = iter->value;
if (id == HighFidelityNeedsUniqueIDGeneration) {
id = vm.getNextUniqueVariableID();
m_uniqueTypeSetMap->set(key, TypeSet::create()); //make a new global typeset for the ID
@@ -207,7 +207,7 @@
return id;
}
-int64_t SymbolTable::uniqueIDForRegister(const ConcurrentJITLocker& locker, int registerIndex, VM& vm)
+GlobalVariableID SymbolTable::uniqueIDForRegister(const ConcurrentJITLocker& locker, int registerIndex, VM& vm)
{
auto iter = m_registerToVariableMap->find(registerIndex);
auto end = m_registerToVariableMap->end();
diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h
index 1a3d997..32f0dd0 100644
--- a/Source/JavaScriptCore/runtime/SymbolTable.h
+++ b/Source/JavaScriptCore/runtime/SymbolTable.h
@@ -337,7 +337,7 @@
typedef JSCell Base;
typedef HashMap<RefPtr<StringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<StringImpl>>, SymbolTableIndexHashTraits> Map;
- typedef HashMap<RefPtr<StringImpl>, int64_t> UniqueIDMap;
+ typedef HashMap<RefPtr<StringImpl>, GlobalVariableID> UniqueIDMap;
typedef HashMap<RefPtr<StringImpl>, RefPtr<TypeSet>> UniqueTypeSetMap;
typedef HashMap<int, RefPtr<StringImpl>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int>> RegisterToVariableMap;
@@ -458,8 +458,8 @@
return contains(locker, key);
}
- int64_t uniqueIDForVariable(const ConcurrentJITLocker&, StringImpl* key, VM& vm);
- int64_t uniqueIDForRegister(const ConcurrentJITLocker& locker, int registerIndex, VM& vm);
+ GlobalVariableID uniqueIDForVariable(const ConcurrentJITLocker&, StringImpl* key, VM& vm);
+ GlobalVariableID uniqueIDForRegister(const ConcurrentJITLocker& locker, int registerIndex, VM& vm);
RefPtr<TypeSet> globalTypeSetForRegister(const ConcurrentJITLocker& locker, int registerIndex, VM& vm);
RefPtr<TypeSet> globalTypeSetForVariable(const ConcurrentJITLocker& locker, StringImpl* key, VM& vm);
diff --git a/Source/JavaScriptCore/runtime/TypeLocationCache.cpp b/Source/JavaScriptCore/runtime/TypeLocationCache.cpp
new file mode 100644
index 0000000..40fa9b0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeLocationCache.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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 "TypeLocationCache.h"
+
+#include "VM.h"
+
+namespace JSC {
+
+std::pair<TypeLocation*, bool> TypeLocationCache::getTypeLocation(GlobalVariableID globalVariableID, intptr_t sourceID, unsigned start, unsigned end, PassRefPtr<TypeSet> globalTypeSet, VM* vm)
+{
+ LocationKey key;
+ key.m_globalVariableID = globalVariableID;
+ key.m_sourceID = sourceID;
+ key.m_start = start;
+ key.m_end = end;
+
+ bool isNewLocation = false;
+ if (m_locationMap.find(key) == m_locationMap.end()) {
+ TypeLocation* location = vm->nextLocation();
+ location->m_globalVariableID = globalVariableID;
+ location->m_sourceID = sourceID;
+ location->m_divotStart = start;
+ location->m_divotEnd = end;
+ location->m_globalTypeSet = globalTypeSet;
+
+ m_locationMap[key] = location;
+ isNewLocation = true;
+ }
+
+ TypeLocation* location = m_locationMap.find(key)->second;
+ return std::pair<TypeLocation*, bool>(location, isNewLocation);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/TypeLocationCache.h b/Source/JavaScriptCore/runtime/TypeLocationCache.h
new file mode 100644
index 0000000..9f85666
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeLocationCache.h
@@ -0,0 +1,68 @@
+/*
+ * 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 TypeLocationCache_h
+#define TypeLocationCache_h
+
+#include "TypeLocation.h"
+#include <unordered_map>
+#include <wtf/HashMethod.h>
+
+namespace JSC {
+
+class VM;
+
+class TypeLocationCache {
+public:
+ struct LocationKey {
+ LocationKey() {}
+ bool operator==(const LocationKey& other) const
+ {
+ return m_globalVariableID == other.m_globalVariableID
+ && m_sourceID == other.m_sourceID
+ && m_start == other.m_start
+ && m_end == other.m_end;
+ }
+
+ unsigned hash() const
+ {
+ return m_globalVariableID + m_sourceID + m_start + m_end;
+ }
+
+ GlobalVariableID m_globalVariableID;
+ intptr_t m_sourceID;
+ unsigned m_start;
+ unsigned m_end;
+ };
+
+ std::pair<TypeLocation*, bool> getTypeLocation(GlobalVariableID, intptr_t, unsigned start, unsigned end, PassRefPtr<TypeSet>, VM*);
+private:
+ typedef std::unordered_map<LocationKey, TypeLocation*, HashMethod<LocationKey>> LocationMap;
+ LocationMap m_locationMap;
+};
+
+} // namespace JSC
+
+#endif // TypeLocationCache_h
diff --git a/Source/JavaScriptCore/runtime/TypeSet.cpp b/Source/JavaScriptCore/runtime/TypeSet.cpp
index 723d820..07790fa 100644
--- a/Source/JavaScriptCore/runtime/TypeSet.cpp
+++ b/Source/JavaScriptCore/runtime/TypeSet.cpp
@@ -26,6 +26,7 @@
#include "config.h"
#include "TypeSet.h"
+#include "InspectorJSTypeBuilders.h"
#include "JSCJSValue.h"
#include "JSCJSValueInlines.h"
#include <wtf/text/CString.h>
@@ -58,8 +59,6 @@
ret = TypeNumber;
else if (v.isString())
ret = TypeString;
- else if (v.isPrimitive())
- ret = TypePrimitive;
else if (v.isObject())
ret = TypeObject;
else
@@ -73,7 +72,7 @@
RuntimeType t = getRuntimeTypeForValue(v);
m_seenTypes = m_seenTypes | t;
- if (id && shape) {
+ if (id && shape && !v.isString() && !v.isFunction()) {
ASSERT(m_structureIDHistory.isValidKey(id));
auto iter = m_structureIDHistory.find(id);
if (iter == m_structureIDHistory.end()) {
@@ -95,7 +94,7 @@
}
}
-String TypeSet::seenTypes()
+String TypeSet::seenTypes() const
{
if (m_seenTypes == TypeNothing)
return "(Unreached Statement)";
@@ -116,17 +115,13 @@
seen.append("Number ");
if (m_seenTypes & TypeString)
seen.append("String ");
- if (m_seenTypes & TypePrimitive)
- seen.append("Primitive ");
if (m_seenTypes & TypeObject)
seen.append("Object ");
for (size_t i = 0; i < m_structureHistory->size(); i++) {
RefPtr<StructureShape> shape = m_structureHistory->at(i);
- if (!shape->m_constructorName.isEmpty()) {
- seen.append(shape->m_constructorName);
- seen.append(" ");
- }
+ seen.append(shape->m_constructorName);
+ seen.append(" ");
}
if (m_structureHistory->size())
@@ -139,20 +134,131 @@
seen.append("]");
if (m_structureHistory->size()) {
- seen.append("\nLUB: ");
- seen.append(StructureShape::leastUpperBound(m_structureHistory));
+ seen.append("\nLeast Common Ancestor: ");
+ seen.append(leastCommonAncestor());
}
return seen.toString();
}
+bool TypeSet::doesTypeConformTo(uint32_t test) const
+{
+ // This function checks if our seen types conform to the types described by the test bitstring. (i.e we haven't seen more types than test).
+ // We are <= to those types if ANDing with the bitstring doesn't zero out any of our bits.
+
+ // For example:
+
+ // 0b0110 (seen)
+ // 0b1111 (test)
+ // ------ (AND)
+ // 0b0110 == seen
+
+ // 0b0110 (seen)
+ // 0b0010 (test)
+ // ------ (AND)
+ // 0b0010 != seen
+
+ return (m_seenTypes & test) == m_seenTypes;
+}
+
+String TypeSet::displayName() const
+{
+ if (m_seenTypes == TypeNothing)
+ return "";
+
+ if (m_structureHistory->size() && doesTypeConformTo(TypeObject | TypeNull | TypeUndefined)) {
+ String ctorName = leastCommonAncestor();
+
+ if (doesTypeConformTo(TypeObject))
+ return ctorName;
+ else if (doesTypeConformTo(TypeObject | TypeNull | TypeUndefined))
+ return ctorName + "?";
+ }
+
+ // The order of these checks are important. For example, if a value is only a function, it conforms to TypeFunction, but it also conforms to TypeFunction | TypeNull.
+ // Therefore, more specific types must be checked first.
+
+ if (doesTypeConformTo(TypeFunction))
+ return "Function";
+ if (doesTypeConformTo(TypeUndefined))
+ return "Undefined";
+ if (doesTypeConformTo(TypeNull))
+ return "Null";
+ if (doesTypeConformTo(TypeBoolean))
+ return "Boolean";
+ if (doesTypeConformTo(TypeMachineInt))
+ return "Integer";
+ if (doesTypeConformTo(TypeNumber | TypeMachineInt))
+ return "Number";
+ if (doesTypeConformTo(TypeString))
+ return "String";
+
+ if (doesTypeConformTo(TypeNull | TypeUndefined))
+ return "(?)";
+
+ if (doesTypeConformTo(TypeFunction | TypeNull | TypeUndefined))
+ return "Function?";
+ if (doesTypeConformTo(TypeBoolean | TypeNull | TypeUndefined))
+ return "Boolean?";
+ if (doesTypeConformTo(TypeMachineInt | TypeNull | TypeUndefined))
+ return "Integer?";
+ if (doesTypeConformTo(TypeNumber | TypeMachineInt | TypeNull | TypeUndefined))
+ return "Number?";
+ if (doesTypeConformTo(TypeString | TypeNull | TypeUndefined))
+ return "String?";
+
+ if (doesTypeConformTo(TypeObject | TypeFunction | TypeString))
+ return "Object";
+ if (doesTypeConformTo(TypeObject | TypeFunction | TypeString | TypeNull | TypeUndefined))
+ return "Object?";
+
+ return "(many)";
+}
+
+PassRefPtr<Inspector::TypeBuilder::Array<String>> TypeSet::allPrimitiveTypeNames() const
+{
+ RefPtr<Inspector::TypeBuilder::Array<String>> seen = Inspector::TypeBuilder::Array<String>::create();
+ if (m_seenTypes & TypeFunction)
+ seen->addItem("Function");
+ if (m_seenTypes & TypeUndefined)
+ seen->addItem("Undefined");
+ if (m_seenTypes & TypeNull)
+ seen->addItem("Null");
+ if (m_seenTypes & TypeBoolean)
+ seen->addItem("Boolean");
+ if (m_seenTypes & TypeMachineInt)
+ seen->addItem("Integer");
+ if (m_seenTypes & TypeNumber)
+ seen->addItem("Number");
+ if (m_seenTypes & TypeString)
+ seen->addItem("String");
+
+ return seen.release();
+}
+
+PassRefPtr<Inspector::TypeBuilder::Array<Inspector::InspectorObject>> TypeSet::allStructureRepresentations() const
+{
+ RefPtr<Inspector::TypeBuilder::Array<Inspector::InspectorObject>> ret = Inspector::TypeBuilder::Array<Inspector::InspectorObject>::create();
+
+ for (size_t i = 0; i < m_structureHistory->size(); i++)
+ ret->addItem(m_structureHistory->at(i)->inspectorRepresentation());
+
+ return ret.release();
+}
+
+String TypeSet::leastCommonAncestor() const
+{
+ return StructureShape::leastCommonAncestor(m_structureHistory);
+}
+
void TypeSet::dumpSeenTypes()
{
dataLog(seenTypes(), "\n");
}
StructureShape::StructureShape()
- : m_propertyHash(nullptr)
+ : m_proto(nullptr)
+ , m_propertyHash(nullptr)
, m_final(false)
{
}
@@ -166,7 +272,7 @@
void StructureShape::addProperty(RefPtr<StringImpl> impl)
{
ASSERT(!m_final);
- m_fields.set(impl, true);
+ m_fields.append(impl);
}
String StructureShape::propertyHash()
@@ -177,53 +283,77 @@
StringBuilder builder;
builder.append(":");
+ builder.append(m_constructorName);
+ builder.append(":");
+
for (auto iter = m_fields.begin(), end = m_fields.end(); iter != end; ++iter) {
- String property = String(iter->key);
+ String property = String((*iter));
property.replace(":", "\\:"); // Ensure that hash({"foo:", "bar"}) != hash({"foo", ":bar"}) because we're using colons as a separator and colons are legal characters in field names in JS.
builder.append(property);
}
+ if (m_proto) {
+ builder.append(":");
+ builder.append("__proto__");
+ builder.append(m_proto->propertyHash());
+ }
+
m_propertyHash = std::make_unique<String>(builder.toString());
return *m_propertyHash;
}
-String StructureShape::leastUpperBound(Vector<RefPtr<StructureShape>>* shapes)
+String StructureShape::leastCommonAncestor(const Vector<RefPtr<StructureShape>>* shapes)
{
if (!shapes->size())
return "";
- StringBuilder lub;
RefPtr<StructureShape> origin = shapes->at(0);
- lub.append("{");
- for (auto iter = origin->m_fields.begin(), end = origin->m_fields.end(); iter != end; ++iter) {
- bool shouldAdd = true;
- for (size_t i = 1, size = shapes->size(); i < size; i++) {
- // If all other Shapes have the same field as origin, add it to the least upper bound.
- if (!shapes->at(i)->m_fields.contains(iter->key)) {
- shouldAdd = false;
- break;
+ for (size_t i = 1; i < shapes->size(); i++) {
+ bool foundLUB = false;
+ while (!foundLUB) {
+ RefPtr<StructureShape> check = shapes->at(i);
+ String curCtorName = origin->m_constructorName;
+ while (check) {
+ if (check->m_constructorName == curCtorName) {
+ foundLUB = true;
+ break;
+ }
+ check = check->m_proto;
+ }
+ if (!foundLUB) {
+ origin = origin->m_proto;
+ // All Objects must share the 'Object' Prototype. Therefore, at the very least, we should always converge on 'Object' before reaching a null prototype.
+ RELEASE_ASSERT(origin);
}
}
- if (shouldAdd)
- lub.append(String(iter->key.get()) + String(", "));
+
+ if (origin->m_constructorName == "Object")
+ break;
}
- if (lub.length() >= 3)
- lub.resize(lub.length() - 2); // Remove the trailing ', '
-
- lub.append("}");
-
- return lub.toString();
+ return origin->m_constructorName;
}
String StructureShape::stringRepresentation()
{
StringBuilder representation;
+ RefPtr<StructureShape> curShape = this;
+
representation.append("{");
- for (auto iter = m_fields.begin(), end = m_fields.end(); iter != end; ++iter) {
- String prop(iter->key.get());
- representation.append(prop);
- representation.append(", ");
+ while (curShape) {
+ for (auto iter = curShape->m_fields.begin(), end = curShape->m_fields.end(); iter != end; ++iter) {
+ String prop((*iter).get());
+ representation.append(prop);
+ representation.append(", ");
+ }
+
+ if (curShape->m_proto) {
+ String prot = String("__proto__") + String(" [") + curShape->m_proto->m_constructorName + String("]");
+ representation.append(prot);
+ representation.append(", ");
+ }
+
+ curShape = curShape->m_proto;
}
if (representation.length() >= 3)
@@ -234,4 +364,30 @@
return representation.toString();
}
+PassRefPtr<Inspector::InspectorObject> StructureShape::inspectorRepresentation()
+{
+ RefPtr<Inspector::InspectorObject> base = Inspector::InspectorObject::create();
+ RefPtr<Inspector::InspectorObject> currentObject = base;
+ RefPtr<StructureShape> currentShape = this;
+
+ while (currentShape) {
+ RefPtr<Inspector::TypeBuilder::Array<String>> fields = Inspector::TypeBuilder::Array<String>::create();
+ for (auto iter = currentShape->m_fields.begin(), end = currentShape->m_fields.end(); iter != end; ++iter)
+ fields->addItem((*iter).get());
+
+ currentObject->setArray(ASCIILiteral("fields"), fields->asArray());
+ currentObject->setString(ASCIILiteral("constructorName"), currentShape->m_constructorName);
+
+ if (currentShape->m_proto) {
+ RefPtr<Inspector::InspectorObject> nextObject = Inspector::InspectorObject::create();
+ currentObject->setObject(ASCIILiteral("prototypeStructure"), nextObject);
+ currentObject = nextObject;
+ }
+
+ currentShape = currentShape->m_proto;
+ }
+
+ return base.release();
+}
+
} //namespace JSC
diff --git a/Source/JavaScriptCore/runtime/TypeSet.h b/Source/JavaScriptCore/runtime/TypeSet.h
index 9e236d6..070ff1e 100644
--- a/Source/JavaScriptCore/runtime/TypeSet.h
+++ b/Source/JavaScriptCore/runtime/TypeSet.h
@@ -32,6 +32,15 @@
#include <wtf/text/WTFString.h>
#include <wtf/Vector.h>
+namespace Inspector { namespace TypeBuilder {
+template<typename T>
+class Array;
+}}
+
+namespace Inspector {
+class InspectorObject;
+}
+
namespace JSC {
class JSValue;
@@ -45,8 +54,7 @@
TypeMachineInt = 0x10,
TypeNumber = 0x20,
TypeString = 0x40,
- TypePrimitive = 0x80,
- TypeObject = 0x100
+ TypeObject = 0x80
};
class StructureShape : public RefCounted<StructureShape> {
@@ -59,12 +67,17 @@
String propertyHash();
void markAsFinal();
void addProperty(RefPtr<StringImpl>);
- static String leastUpperBound(Vector<RefPtr<StructureShape>>*);
String stringRepresentation();
- void setConstructorName(String name) { m_constructorName = name; }
+ PassRefPtr<Inspector::InspectorObject> inspectorRepresentation();
+ void setConstructorName(String name) { m_constructorName = (name.isEmpty() ? "Object" : name); }
+ String constructorName() { return m_constructorName; }
+ void setProto(PassRefPtr<StructureShape> shape) { m_proto = shape; }
private:
- HashMap<RefPtr<StringImpl>, bool> m_fields;
+ static String leastCommonAncestor(const Vector<RefPtr<StructureShape>>*);
+
+ Vector<RefPtr<StringImpl>> m_fields;
+ RefPtr<StructureShape> m_proto;
std::unique_ptr<String> m_propertyHash;
String m_constructorName;
bool m_final;
@@ -77,11 +90,17 @@
TypeSet();
void addTypeForValue(JSValue v, PassRefPtr<StructureShape>, StructureID);
static RuntimeType getRuntimeTypeForValue(JSValue);
- JS_EXPORT_PRIVATE String seenTypes();
+ JS_EXPORT_PRIVATE String seenTypes() const;
+ String displayName() const;
+ PassRefPtr<Inspector::TypeBuilder::Array<String>> allPrimitiveTypeNames() const;
+ PassRefPtr<Inspector::TypeBuilder::Array<Inspector::InspectorObject>> allStructureRepresentations() const;
private:
- uint32_t m_seenTypes;
+ String leastCommonAncestor() const;
void dumpSeenTypes();
+ bool doesTypeConformTo(uint32_t test) const;
+
+ uint32_t m_seenTypes;
Vector<RefPtr<StructureShape>>* m_structureHistory;
HashMap<StructureID, uint8_t> m_structureIDHistory;
};
diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp
index 2ed04a4..6776be4 100644
--- a/Source/JavaScriptCore/runtime/VM.cpp
+++ b/Source/JavaScriptCore/runtime/VM.cpp
@@ -65,7 +65,7 @@
#include "JSNotAnObject.h"
#include "JSPromiseDeferred.h"
#include "JSPromiseReaction.h"
-#include "JSPropertyNameIterator.h"
+#include "JSPropertyNameEnumerator.h"
#include "JSWithScope.h"
#include "Lexer.h"
#include "Lookup.h"
@@ -208,7 +208,7 @@
terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
- propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
+ propertyNameEnumeratorStructure.set(*this, JSPropertyNameEnumerator::createStructure(*this, 0, jsNull()));
getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
customGetterSetterStructure.set(*this, CustomGetterSetter::createStructure(*this, 0, jsNull()));
apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
@@ -856,43 +856,16 @@
}
}
-String VM::getTypesForVariableAtOffset(unsigned offset, const String& variableName, const String& sourceIDAsString)
-{
- if (!isProfilingTypesWithHighFidelity())
- return "(Not Profiling)";
-
- bool okay;
- intptr_t sourceID = sourceIDAsString.toIntPtrStrict(&okay);
- if (!okay)
- CRASH();
-
- updateHighFidelityTypeProfileState();
- return m_highFidelityTypeProfiler->getTypesForVariableInAtOffset(offset, variableName, sourceID);
-}
-
-void VM::updateHighFidelityTypeProfileState()
-{
- if (!isProfilingTypesWithHighFidelity())
- return;
-
- highFidelityLog()->processHighFidelityLog(false, "VM Update");
-}
-
void VM::dumpHighFidelityProfilingTypes()
{
if (!isProfilingTypesWithHighFidelity())
return;
- updateHighFidelityTypeProfileState();
+ highFidelityLog()->processHighFidelityLog("VM Dump Types");
HighFidelityTypeProfiler* profiler = m_highFidelityTypeProfiler.get();
for (Bag<TypeLocation>::iterator iter = m_locationInfo.begin(); !!iter; ++iter) {
TypeLocation* location = *iter;
- dataLogF("[Start, End]::[%u, %u] ", location->m_divotStart, location->m_divotEnd);
- dataLog("\n\t\t#Local#\n\t\t",
- profiler->getLocalTypesForVariableAtOffset(location->m_divotStart, "", location->m_sourceID).replace("\n", "\n\t\t"),
- "\n\t\t#Global#\n\t\t",
- profiler->getGlobalTypesForVariableAtOffset(location->m_divotStart, "", location->m_sourceID).replace("\n", "\n\t\t"),
- "\n");
+ profiler->logTypesForTypeLocation(location);
}
}
diff --git a/Source/JavaScriptCore/runtime/VM.h b/Source/JavaScriptCore/runtime/VM.h
index abc8002..b28d3ba 100644
--- a/Source/JavaScriptCore/runtime/VM.h
+++ b/Source/JavaScriptCore/runtime/VM.h
@@ -244,6 +244,7 @@
Strong<Structure> stringStructure;
Strong<Structure> notAnObjectStructure;
Strong<Structure> propertyNameIteratorStructure;
+ Strong<Structure> propertyNameEnumeratorStructure;
Strong<Structure> getterSetterStructure;
Strong<Structure> customGetterSetterStructure;
Strong<Structure> apiWrapperStructure;
@@ -270,6 +271,7 @@
Strong<Structure> promiseReactionStructure;
#endif
Strong<JSCell> iterationTerminator;
+ Strong<JSCell> emptyPropertyNameEnumerator;
AtomicStringTable* m_atomicStringTable;
CommonIdentifiers* propertyNames;
@@ -493,13 +495,11 @@
BuiltinExecutables* builtinExecutables() { return m_builtinExecutables.get(); }
bool isProfilingTypesWithHighFidelity() { return !!m_highFidelityTypeProfiler; }
- String getTypesForVariableAtOffset(unsigned divot, const String& variableName, const String& sourceID);
HighFidelityLog* highFidelityLog() { return m_highFidelityLog.get(); }
HighFidelityTypeProfiler* highFidelityTypeProfiler() { return m_highFidelityTypeProfiler.get(); }
- void updateHighFidelityTypeProfileState();
TypeLocation* nextLocation() { return m_locationInfo.add(); } //TODO: possible optmization: when codeblocks die, report which locations are no longer being changed so we don't walk over them
JS_EXPORT_PRIVATE void dumpHighFidelityProfilingTypes();
- int64_t getNextUniqueVariableID() { return m_nextUniqueVariableID++; }
+ GlobalVariableID getNextUniqueVariableID() { return m_nextUniqueVariableID++; }
private:
friend class LLIntOffsetsExtractor;
@@ -551,7 +551,7 @@
HashMap<String, RefPtr<WatchpointSet>> m_impurePropertyWatchpointSets;
std::unique_ptr<HighFidelityTypeProfiler> m_highFidelityTypeProfiler;
std::unique_ptr<HighFidelityLog> m_highFidelityLog;
- int64_t m_nextUniqueVariableID;
+ GlobalVariableID m_nextUniqueVariableID;
Bag<TypeLocation> m_locationInfo;
};
diff --git a/Source/JavaScriptCore/tests/stress/for-in-capture-string-loop-var.js b/Source/JavaScriptCore/tests/stress/for-in-capture-string-loop-var.js
new file mode 100644
index 0000000..c92bf68
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/for-in-capture-string-loop-var.js
@@ -0,0 +1,22 @@
+(function() {
+ // Capture the loop variable and modify it inside the loop.
+ var foo = function() {
+ var captured;
+ var g = function() {
+ captured = "foo";
+ };
+ var sum = 0;
+ var o = {"foo": 1, "bar": 2};
+ for (captured in o) {
+ g();
+ sum += o[captured];
+ }
+ return sum;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() != 2)
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
diff --git a/Source/JavaScriptCore/tests/stress/for-in-delete-during-iteration.js b/Source/JavaScriptCore/tests/stress/for-in-delete-during-iteration.js
new file mode 100644
index 0000000..13d5049
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/for-in-delete-during-iteration.js
@@ -0,0 +1,70 @@
+(function() {
+ // Remove a yet-to-be-visited indexed property during iteration.
+ var foo = function() {
+ var a = [1, 2, 3, 4, 5];
+ var result = "";
+ for (var p in a) {
+ if (p == 2)
+ delete a[3];
+ result += a[p];
+ }
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() !== "1235")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
+(function() {
+ // Remove a yet-to-be-visited non-indexed property during iteration.
+ var foo = function() {
+ var o = {};
+ o.x = "x";
+ o.y = "y";
+ o.z = "z";
+ var result = "";
+ for (var p in o) {
+ if (p == "x") {
+ delete o.y;
+ o.a = "a";
+ }
+ result += o[p];
+ }
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ // Note: it's undefined whether we visit o.a or not. Currently we do.
+ if (foo() !== "xza")
+ throw new Error("bad result");
+ }
+})();
+(function() {
+ // Remove then re-add a property during iteration.
+ var foo = function() {
+ var A = function() {};
+ A.prototype.x = "A.x";
+ A.prototype.y = "A.y";
+ var o = new A();
+ o.z = "o.z";
+ o.y = "o.y";
+ o.x = "o.x";
+ var result = "";
+ for (var p in o) {
+ if (p == "z")
+ delete o.x;
+ if (p == "y")
+ o.x = "o.x";
+ result += o[p];
+ }
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() !== "o.zo.yo.x")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
diff --git a/Source/JavaScriptCore/tests/stress/for-in-modify-int-loop-var.js b/Source/JavaScriptCore/tests/stress/for-in-modify-int-loop-var.js
new file mode 100644
index 0000000..82397bc
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/for-in-modify-int-loop-var.js
@@ -0,0 +1,21 @@
+(function() {
+ // Change integer value of the loop variable in the loop.
+ var foo = function() {
+ var a = [1, 2, 3];
+ var sum = 0;
+ for (var i in a) {
+ i += 10;
+ sum += i;
+ }
+ return sum;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ var result = foo();
+ if (typeof result !== "string")
+ throw new Error("result should have type string");
+ if (result !== "0010110210")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
diff --git a/Source/JavaScriptCore/tests/stress/for-in-modify-string-loop-var.js b/Source/JavaScriptCore/tests/stress/for-in-modify-string-loop-var.js
new file mode 100644
index 0000000..071a086
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/for-in-modify-string-loop-var.js
@@ -0,0 +1,19 @@
+(function() {
+ // Change string value of the loop variable in the loop.
+ var foo = function() {
+ var sum = 0;
+ var a = [1, 2, 3];
+ a.foo = 42;
+ for (var i in a) {
+ i = "foo";
+ sum += a[i];
+ }
+ return sum;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() != 42 * 4)
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
diff --git a/Source/JavaScriptCore/tests/stress/for-in-prototype.js b/Source/JavaScriptCore/tests/stress/for-in-prototype.js
new file mode 100644
index 0000000..d12a1bd
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/for-in-prototype.js
@@ -0,0 +1,57 @@
+(function() {
+ // Iterate when the base object's properties shadow properties in the prototype chain.
+ var foo = function() {
+ var A = function() { };
+ A.prototype.x = 42;
+ var o = new A();
+ o.x = 43;
+ var result = "";
+ for (var p in o)
+ result += o[p];
+ return result;
+ };
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() !== "43")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
+(function() {
+ // Iterate when the prototype has the same range of indexed properties as the base object.
+ var foo = function() {
+ var A = function() {};
+ A.prototype[0] = 42;
+ var a = new A();
+ a[0] = 43;
+ var result = "";
+ for (var p in a)
+ result += a[p];
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() !== "43")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
+(function() {
+ // Iterate when the prototype has indexed properties beyond the range of the base object.
+ var foo = function() {
+ var A = function() {};
+ A.prototype[0] = 42;
+ A.prototype[1] = 3;
+ var a = new A();
+ a[0] = 43;
+ var result = "";
+ for (var p in a)
+ result += a[p];
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() !== "433")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
diff --git a/Source/JavaScriptCore/tests/stress/for-in-shadow-prototype-property.js b/Source/JavaScriptCore/tests/stress/for-in-shadow-prototype-property.js
new file mode 100644
index 0000000..855ab08
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/for-in-shadow-prototype-property.js
@@ -0,0 +1,22 @@
+(function() {
+ // Add a property to the base object that shadows a property in the prototype during iteration.
+ var foo = function() {
+ var A = function() {};
+ A.prototype.x = "A.x";
+ A.prototype.y = "A.y";
+ var o = new A();
+ var result = "";
+ for (var p in o) {
+ if (p == "x")
+ o.y = "o.y";
+ result += o[p];
+ }
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() !== "A.xo.y")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
diff --git a/Source/JavaScriptCore/tests/stress/for-in-string.js b/Source/JavaScriptCore/tests/stress/for-in-string.js
new file mode 100644
index 0000000..44640e6
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/for-in-string.js
@@ -0,0 +1,16 @@
+(function() {
+ // Iterate over characters in a string.
+ var o = "hello";
+ var foo = function(o) {
+ var result = "";
+ for (var s in o)
+ result += o[s];
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo("hello") !== "hello")
+ throw new Error("incorrect result");
+ }
+ foo(null);
+})();
diff --git a/Source/JavaScriptCore/tests/stress/for-in-tests.js b/Source/JavaScriptCore/tests/stress/for-in-tests.js
new file mode 100644
index 0000000..572e271
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/for-in-tests.js
@@ -0,0 +1,77 @@
+(function() {
+ // Iterate over an array with normal indexed properties.
+ var foo = function() {
+ var a = [1, 2, 3, 4, 5];
+ var sum = 0;
+ var result = "";
+ for (var p in a)
+ result += a[p];
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() !== "12345")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
+(function() {
+ // Iterate over an object with normal non-indexed properties.
+ var foo = function() {
+ var o = {};
+ o.x = 1;
+ o.y = 2;
+ o.z = 3;
+ var result = "";
+ for (var p in o)
+ result += o[p];
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() !== "123")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
+(function() {
+ // Iterate over an object with both indexed and non-indexed properties.
+ var foo = function() {
+ var o = {};
+ o.x = 1;
+ o.y = 2;
+ o.z = 3;
+ o[0] = 4;
+ o[1] = 5;
+ o[2] = 6;
+ var result = "";
+ for (var p in o)
+ result += o[p];
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() != "456123")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
+(function() {
+ // Iterate over an array with both indexed and non-indexed properties.
+ var foo = function() {
+ var a = [4, 5, 6];
+ a.x = 1;
+ a.y = 2;
+ a.z = 3;
+ var result = "";
+ for (var p in a)
+ result += a[p];
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() !== "456123")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();
diff --git a/Source/JavaScriptCore/tests/stress/for-in-typed-array.js b/Source/JavaScriptCore/tests/stress/for-in-typed-array.js
new file mode 100644
index 0000000..08f8828
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/for-in-typed-array.js
@@ -0,0 +1,18 @@
+(function() {
+ // Iterate over typed arrays.
+ var foo = function() {
+ var a = new Uint8Array(5);
+ for (var i = 0; i < a.length; ++i)
+ a[i] = i;
+ var result = "";
+ for (var p in a)
+ result += a[p];
+ return result;
+ };
+ noInline(foo);
+ for (var i = 0; i < 10000; ++i) {
+ if (foo() !== "01234")
+ throw new Error("bad result");
+ }
+ foo(null);
+})();