source: webkit/trunk/Source/JavaScriptCore/jsc.cpp@ 171660

Last change on this file since 171660 was 171660, checked in by [email protected], 11 years ago

Merge r170090, r170092, r170129, r170141, r170161, r170215, r170275, r170375, r170376, r170382, r170383, r170399, r170436, r170489, r170490, r170556 from ftlopt.

Source/JavaScriptCore:

This fixes the previous mismerge and adds test coverage for the thing that went wrong.

Additional changes listed here:

  • jsc.cpp:

(functionHasCustomProperties): Expose a way of checking hasCustomProperties(), which the DOM relies on. The regression I previously introduced was because this didn't work right. Now we can test it!

  • runtime/Structure.cpp:

(JSC::Structure::Structure): This was supposed to be setDidTransition(true); the last merge had it set to false.

  • tests/stress/has-custom-properties.js: Added. This test failed with the mismerge.

2014-06-27 Michael Saboff <[email protected]>


Unreviewed build fix after r169795.


Fixed ASSERT for 32 bit build.


  • dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR):


2014-06-24 Saam Barati <[email protected]>


Web Inspector: debugger should be able to show variable types
https://bugs.webkit.org/show_bug.cgi?id=133395


Reviewed by Filip Pizlo.


Increase the amount of type information the VM gathers when directed
to do so. This initial commit is working towards the goal of
capturing, and then showing (via the Web Inspector) type information for all
assignment and load operations. This patch doesn't have the feature fully
implemented, but it ensures the VM has no performance regressions
unless the feature is specifically turned on.


  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/BytecodeList.json:
  • bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): (JSC::computeDefsForBytecodeOffset):
  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::CodeBlock): (JSC::CodeBlock::finalizeUnconditionally):
  • bytecode/CodeBlock.h:
  • bytecode/Instruction.h:
  • bytecode/TypeLocation.h: Added. (JSC::TypeLocation::TypeLocation):
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitMove): (JSC::BytecodeGenerator::emitProfileTypesWithHighFidelity): (JSC::BytecodeGenerator::emitPutToScope): (JSC::BytecodeGenerator::emitPutById): (JSC::BytecodeGenerator::emitPutByVal):
  • bytecompiler/BytecodeGenerator.h: (JSC::BytecodeGenerator::isProfilingTypesWithHighFidelity):
  • bytecompiler/NodesCodegen.cpp: (JSC::PostfixNode::emitResolve): (JSC::PrefixNode::emitResolve): (JSC::ReadModifyResolveNode::emitBytecode): (JSC::AssignResolveNode::emitBytecode): (JSC::ConstDeclNode::emitCodeSingle): (JSC::ForInNode::emitBytecode):
  • heap/Heap.cpp: (JSC::Heap::collect):
  • inspector/agents/InspectorRuntimeAgent.cpp: (Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableInTextRange):
  • inspector/agents/InspectorRuntimeAgent.h:
  • inspector/protocol/Runtime.json:
  • jsc.cpp: (GlobalObject::finishCreation): (functionDumpTypesForAllVariables):
  • llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): (JSC::LLInt::putToScopeCommon):
  • llint/LLIntSlowPaths.h:
  • llint/LowLevelInterpreter.asm:
  • runtime/HighFidelityLog.cpp: Added. (JSC::HighFidelityLog::initializeHighFidelityLog): (JSC::HighFidelityLog::~HighFidelityLog): (JSC::HighFidelityLog::recordTypeInformationForLocation): (JSC::HighFidelityLog::processHighFidelityLog): (JSC::HighFidelityLog::actuallyProcessLogThreadFunction):
  • runtime/HighFidelityLog.h: Added. (JSC::HighFidelityLog::HighFidelityLog):
  • runtime/HighFidelityTypeProfiler.cpp: Added. (JSC::HighFidelityTypeProfiler::getTypesForVariableInRange): (JSC::HighFidelityTypeProfiler::getGlobalTypesForVariableInRange): (JSC::HighFidelityTypeProfiler::getLocalTypesForVariableInRange): (JSC::HighFidelityTypeProfiler::insertNewLocation): (JSC::HighFidelityTypeProfiler::getLocationBasedHash):
  • runtime/HighFidelityTypeProfiler.h: Added.
  • runtime/Options.h:
  • runtime/Structure.cpp: (JSC::Structure::toStructureShape):
  • runtime/Structure.h:
  • runtime/SymbolTable.cpp: (JSC::SymbolTable::SymbolTable): (JSC::SymbolTable::cloneCapturedNames): (JSC::SymbolTable::uniqueIDForVariable): (JSC::SymbolTable::uniqueIDForRegister): (JSC::SymbolTable::globalTypeSetForRegister): (JSC::SymbolTable::globalTypeSetForVariable):
  • runtime/SymbolTable.h: (JSC::SymbolTable::add): (JSC::SymbolTable::set):
  • runtime/TypeSet.cpp: Added. (JSC::TypeSet::TypeSet): (JSC::TypeSet::getRuntimeTypeForValue): (JSC::TypeSet::addTypeForValue): (JSC::TypeSet::removeDuplicatesInStructureHistory): (JSC::TypeSet::seenTypes): (JSC::TypeSet::dumpSeenTypes): (JSC::StructureShape::StructureShape): (JSC::StructureShape::markAsFinal): (JSC::StructureShape::addProperty): (JSC::StructureShape::propertyHash): (JSC::StructureShape::leastUpperBound): (JSC::StructureShape::stringRepresentation):
  • runtime/TypeSet.h: Added. (JSC::StructureShape::create): (JSC::TypeSet::create):
  • runtime/VM.cpp: (JSC::VM::VM): (JSC::VM::getTypesForVariableInRange): (JSC::VM::updateHighFidelityTypeProfileState): (JSC::VM::dumpHighFidelityProfilingTypes):
  • runtime/VM.h: (JSC::VM::isProfilingTypesWithHighFidelity): (JSC::VM::highFidelityLog): (JSC::VM::highFidelityTypeProfiler): (JSC::VM::nextLocation): (JSC::VM::getNextUniqueVariableID):


2014-06-26 Mark Lam <[email protected]>


Remove unused instantiation of the WithScope structure.
<https://webkit.org/b/134331>


Reviewed by Oliver Hunt.


The WithScope structure instance is the VM is unused, and is now removed.


  • runtime/VM.cpp: (JSC::VM::VM):
  • runtime/VM.h:


2014-06-25 Mark Hahnenberg <[email protected]>


Structure bit fields should have a consistent format
https://bugs.webkit.org/show_bug.cgi?id=134307


Reviewed by Filip Pizlo.


Currently we use C-style bit fields for a number of member variables in Structure to save space.
This makes it difficult to load these fields in the JIT. We should instead use our own bitfield
format to make it easy to load and test these variables in JIT code.


  • runtime/JSObject.cpp: (JSC::JSObject::putDirectNonIndexAccessor): (JSC::JSObject::reifyStaticFunctionsForDelete):
  • runtime/Structure.cpp: (JSC::StructureTransitionTable::contains): (JSC::StructureTransitionTable::get): (JSC::StructureTransitionTable::add): (JSC::Structure::Structure): (JSC::Structure::materializePropertyMap): (JSC::Structure::addPropertyTransition): (JSC::Structure::despecifyFunctionTransition): (JSC::Structure::toDictionaryTransition): (JSC::Structure::freezeTransition): (JSC::Structure::preventExtensionsTransition): (JSC::Structure::takePropertyTableOrCloneIfPinned): (JSC::Structure::nonPropertyTransition): (JSC::Structure::flattenDictionaryStructure): (JSC::Structure::addPropertyWithoutTransition): (JSC::Structure::pin): (JSC::Structure::allocateRareData): (JSC::Structure::cloneRareDataFrom): (JSC::Structure::getConcurrently): (JSC::Structure::putSpecificValue): (JSC::Structure::getPropertyNamesFromStructure): (JSC::Structure::visitChildren): (JSC::Structure::checkConsistency):
  • runtime/Structure.h: (JSC::Structure::isExtensible): (JSC::Structure::isDictionary): (JSC::Structure::isUncacheableDictionary): (JSC::Structure::propertyAccessesAreCacheable): (JSC::Structure::previousID): (JSC::Structure::setHasGetterSetterPropertiesWithProtoCheck): (JSC::Structure::setContainsReadOnlyProperties): (JSC::Structure::disableSpecificFunctionTracking): (JSC::Structure::objectToStringValue): (JSC::Structure::setObjectToStringValue): (JSC::Structure::setPreviousID): (JSC::Structure::clearPreviousID): (JSC::Structure::previous): (JSC::Structure::rareData): (JSC::Structure::didTransition): Deleted. (JSC::Structure::hasGetterSetterProperties): Deleted. (JSC::Structure::hasReadOnlyOrGetterSetterPropertiesExcludingProto): Deleted. (JSC::Structure::setHasGetterSetterProperties): Deleted. (JSC::Structure::hasNonEnumerableProperties): Deleted. (JSC::Structure::staticFunctionsReified): Deleted. (JSC::Structure::setStaticFunctionsReified): Deleted.
  • runtime/StructureInlines.h: (JSC::Structure::setEnumerationCache): (JSC::Structure::enumerationCache): (JSC::Structure::checkOffsetConsistency):


2014-06-24 Mark Lam <[email protected]>


[ftlopt] Renamed DebuggerActivation to DebuggerScope.
<https://webkit.org/b/134273>


Reviewed by Michael Saboff.


  • CMakeLists.txt:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • debugger/DebuggerActivation.cpp: Removed.
  • debugger/DebuggerActivation.h: Removed.
  • debugger/DebuggerScope.cpp: Copied from ../../trunk/Source/JavaScriptCore/debugger/DebuggerActivation.cpp. (JSC::DebuggerScope::DebuggerScope): (JSC::DebuggerScope::finishCreation): (JSC::DebuggerScope::visitChildren): (JSC::DebuggerScope::className): (JSC::DebuggerScope::getOwnPropertySlot): (JSC::DebuggerScope::put): (JSC::DebuggerScope::deleteProperty): (JSC::DebuggerScope::getOwnPropertyNames): (JSC::DebuggerScope::defineOwnProperty): (JSC::DebuggerActivation::DebuggerActivation): Deleted. (JSC::DebuggerActivation::finishCreation): Deleted. (JSC::DebuggerActivation::visitChildren): Deleted. (JSC::DebuggerActivation::className): Deleted. (JSC::DebuggerActivation::getOwnPropertySlot): Deleted. (JSC::DebuggerActivation::put): Deleted. (JSC::DebuggerActivation::deleteProperty): Deleted. (JSC::DebuggerActivation::getOwnPropertyNames): Deleted. (JSC::DebuggerActivation::defineOwnProperty): Deleted.
  • debugger/DebuggerScope.h: Copied from ../../trunk/Source/JavaScriptCore/debugger/DebuggerActivation.h. (JSC::DebuggerScope::create): (JSC::DebuggerActivation::create): Deleted.
  • runtime/VM.cpp: (JSC::VM::VM):
  • runtime/VM.h:


2014-06-24 Filip Pizlo <[email protected]>


[ftlopt] PutByIdFlush can also be converted to a PutByOffset so don't assert otherwise
https://bugs.webkit.org/show_bug.cgi?id=134265


Reviewed by Geoffrey Garen.


More assertion fallout from the PutById folding work.


  • dfg/DFGNode.h: (JSC::DFG::Node::convertToPutByOffset):


2014-06-24 Filip Pizlo <[email protected]>


[ftlopt] GC should notify us if it resets to_this
https://bugs.webkit.org/show_bug.cgi?id=128231


Reviewed by Geoffrey Garen.


  • CMakeLists.txt:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/BytecodeList.json:
  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::finalizeUnconditionally):
  • bytecode/Instruction.h:
  • bytecode/ToThisStatus.cpp: Added. (JSC::merge): (WTF::printInternal):
  • bytecode/ToThisStatus.h: Added.
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::BytecodeGenerator):
  • dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock):
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/CommonSlowPaths.cpp: (JSC::SLOW_PATH_DECL):


2014-06-24 Filip Pizlo <[email protected]>


[ftlopt] StructureAbstractValue::onlyStructure() should return nullptr if isClobbered()
https://bugs.webkit.org/show_bug.cgi?id=134256


Reviewed by Michael Saboff.


This isn't testable right now (i.e. it's benign) but we should get it right anyway. The
point is to be able to precisely model what goes on in the snippets of code between a
side-effect and an InvalidationPoint.


This patch also cleans up onlyStructure() by delegating more work to
StructureSet::onlyStructure().


  • dfg/DFGStructureAbstractValue.h: (JSC::DFG::StructureAbstractValue::onlyStructure):


2014-06-24 Filip Pizlo <[email protected]>


[ftlopt][REGRESSION] PutById AI is introducing watchable structures without watching them
https://bugs.webkit.org/show_bug.cgi?id=134260


Reviewed by Geoffrey Garen.


This was causing loads of assertion failures in debug builds.


  • dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):


2014-06-21 Filip Pizlo <[email protected]>


[ftlopt] Fold GetById/PutById to MultiGetByOffset/GetByOffset or MultiPutByOffset/PutByOffset, which implies handling non-singleton sets
https://bugs.webkit.org/show_bug.cgi?id=134090


Reviewed by Oliver Hunt.


This pretty much finishes off the work to eliminate the special-casing of singleton
structure sets by making it possible to fold GetById and PutById to various polymorphic
forms of the ByOffset nodes.


  • bytecode/GetByIdStatus.cpp: (JSC::GetByIdStatus::computeForStubInfo): (JSC::GetByIdStatus::computeFor):
  • bytecode/GetByIdStatus.h:
  • bytecode/PutByIdStatus.cpp: (JSC::PutByIdStatus::computeFor):
  • bytecode/PutByIdStatus.h:
  • bytecode/PutByIdVariant.h: (JSC::PutByIdVariant::constantChecks):
  • dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
  • dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock):
  • dfg/DFGConstantFoldingPhase.cpp: (JSC::DFG::ConstantFoldingPhase::foldConstants): (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): (JSC::DFG::ConstantFoldingPhase::addChecks):
  • dfg/DFGNode.h: (JSC::DFG::Node::convertToMultiGetByOffset): (JSC::DFG::Node::convertToMultiPutByOffset):
  • dfg/DFGSpeculativeJIT64.cpp: Also convert all release assertions to DFG assertions in this file, because I was hitting some of them while debugging. (JSC::DFG::SpeculativeJIT::fillJSValue): (JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull): (JSC::DFG::SpeculativeJIT::emitCall): (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Strict): (JSC::DFG::SpeculativeJIT::fillSpeculateInt52): (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): (JSC::DFG::SpeculativeJIT::fillSpeculateCell): (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): (JSC::DFG::SpeculativeJIT::compileLogicalNot): (JSC::DFG::SpeculativeJIT::emitBranch): (JSC::DFG::SpeculativeJIT::compile):
  • dfg/DFGStructureAbstractValue.h: (JSC::DFG::StructureAbstractValue::set):


2014-06-19 Filip Pizlo <[email protected]>


[ftlopt] StructureSet::onlyStructure() should return nullptr if it's not a singleton (instead of asserting)
https://bugs.webkit.org/show_bug.cgi?id=134077


Reviewed by Sam Weinig.


This makes StructureSet and StructureAbstractValue more consistent and fixes a debug assert
in the abstract interpreter.


  • bytecode/StructureSet.h: (JSC::StructureSet::onlyStructure):


2014-06-18 Filip Pizlo <[email protected]>


DFG AI and constant folder should be able to precisely prune MultiGetByOffset/MultiPutByOffset even if the base structure abstract value is not a singleton
https://bugs.webkit.org/show_bug.cgi?id=133918


Reviewed by Mark Hahnenberg.


This also adds pruning of PutStructure, since I basically had no choice but
to implement such logic within MultiPutByOffset.


Also adds a bunch of PutById cache status dumping to bytecode dumping.


  • bytecode/GetByIdVariant.cpp: (JSC::GetByIdVariant::dumpInContext):
  • bytecode/GetByIdVariant.h: (JSC::GetByIdVariant::structureSet):
  • bytecode/PutByIdVariant.h: (JSC::PutByIdVariant::oldStructure):
  • bytecode/StructureSet.cpp: (JSC::StructureSet::filter): (JSC::StructureSet::filterArrayModes):
  • bytecode/StructureSet.h:
  • dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
  • dfg/DFGAbstractValue.cpp: (JSC::DFG::AbstractValue::changeStructure): (JSC::DFG::AbstractValue::contains):
  • dfg/DFGAbstractValue.h: (JSC::DFG::AbstractValue::couldBeType): (JSC::DFG::AbstractValue::isType):
  • dfg/DFGConstantFoldingPhase.cpp: (JSC::DFG::ConstantFoldingPhase::foldConstants): (JSC::DFG::ConstantFoldingPhase::emitGetByOffset): (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): (JSC::DFG::ConstantFoldingPhase::addBaseCheck):
  • dfg/DFGGraph.cpp: (JSC::DFG::Graph::freezeStrong):
  • dfg/DFGGraph.h:
  • dfg/DFGStructureAbstractValue.h: (JSC::DFG::StructureAbstractValue::operator=):
  • ftl/FTLLowerDFGToLLVM.cpp: (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
  • tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js: Added. (foo): (fu): (bar): (baz): (.bar): (.baz):
  • tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js: Added. (foo): (fu): (bar): (baz): (.bar): (.baz):
  • tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js: Added. (foo): (fu): (bar): (baz): (.bar): (.baz):


2014-06-18 Mark Hahnenberg <[email protected]>


Remove CompoundType and LeafType
https://bugs.webkit.org/show_bug.cgi?id=134037


Reviewed by Filip Pizlo.


We don't use them for anything. We'll replace them with a generic CellType type for all
the objects that are JSCells, aren't JSObjects, and for which we generally don't care about
their JSType at runtime.


  • llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions):
  • runtime/ArrayBufferNeuteringWatchpoint.cpp: (JSC::ArrayBufferNeuteringWatchpoint::createStructure):
  • runtime/Executable.h: (JSC::ExecutableBase::createStructure): (JSC::NativeExecutable::createStructure):
  • runtime/JSPromiseDeferred.h: (JSC::JSPromiseDeferred::createStructure):
  • runtime/JSPromiseReaction.h: (JSC::JSPromiseReaction::createStructure):
  • runtime/JSPropertyNameIterator.h: (JSC::JSPropertyNameIterator::createStructure):
  • runtime/JSType.h:
  • runtime/JSTypeInfo.h: (JSC::TypeInfo::TypeInfo):
  • runtime/MapData.h: (JSC::MapData::createStructure):
  • runtime/PropertyMapHashTable.h: (JSC::PropertyTable::createStructure):
  • runtime/RegExp.h: (JSC::RegExp::createStructure):
  • runtime/SparseArrayValueMap.cpp: (JSC::SparseArrayValueMap::createStructure):
  • runtime/Structure.cpp: (JSC::Structure::Structure):
  • runtime/StructureChain.h: (JSC::StructureChain::createStructure):
  • runtime/StructureRareData.cpp: (JSC::StructureRareData::createStructure):
  • runtime/SymbolTable.h: (JSC::SymbolTable::createStructure):
  • runtime/WeakMapData.h: (JSC::WeakMapData::createStructure):


2014-06-17 Filip Pizlo <[email protected]>


[ftlopt] PutStructure and PhantomPutStructure shouldn't leave the world in a clobbered state
https://bugs.webkit.org/show_bug.cgi?id=134002


Reviewed by Mark Hahnenberg.


The effect of this bug was that if we had a PutStructure or PhantomPutStructure then any
JSConstants would be in a Clobbered state, so we wouldn't take advantage of our knowledge
of the structure if that structure was watchable.


Also kill PhantomPutStructure.


  • dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransition): (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions):
  • dfg/DFGClobberize.h: (JSC::DFG::clobberize):
  • dfg/DFGDoesGC.cpp: (JSC::DFG::doesGC):
  • dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode):
  • dfg/DFGGraph.cpp: (JSC::DFG::Graph::visitChildren):
  • dfg/DFGNode.h: (JSC::DFG::Node::hasTransition):
  • dfg/DFGNodeType.h:
  • dfg/DFGPredictionPropagationPhase.cpp: (JSC::DFG::PredictionPropagationPhase::propagate):
  • dfg/DFGSafeToExecute.h: (JSC::DFG::safeToExecute):
  • dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile):
  • dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile):
  • dfg/DFGStructureAbstractValue.cpp: (JSC::DFG::StructureAbstractValue::observeTransition): (JSC::DFG::StructureAbstractValue::observeTransitions):
  • dfg/DFGValidate.cpp: (JSC::DFG::Validate::validate):
  • dfg/DFGWatchableStructureWatchingPhase.cpp: (JSC::DFG::WatchableStructureWatchingPhase::run):
  • ftl/FTLCapabilities.cpp: (JSC::FTL::canCompile):
  • ftl/FTLLowerDFGToLLVM.cpp: (JSC::FTL::LowerDFGToLLVM::compileNode): (JSC::FTL::LowerDFGToLLVM::compilePhantomPutStructure): Deleted.


2014-06-17 Filip Pizlo <[email protected]>


[ftlopt] DFG put_by_id should inline accesses with a slightly polymorphic base
https://bugs.webkit.org/show_bug.cgi?id=133964


Reviewed by Mark Hahnenberg.


  • bytecode/PutByIdStatus.cpp: (JSC::PutByIdStatus::appendVariant): (JSC::PutByIdStatus::computeForStubInfo):
  • bytecode/PutByIdVariant.cpp: (JSC::PutByIdVariant::oldStructureForTransition): (JSC::PutByIdVariant::writesStructures): (JSC::PutByIdVariant::reallocatesStorage): (JSC::PutByIdVariant::attemptToMerge): (JSC::PutByIdVariant::attemptToMergeTransitionWithReplace): (JSC::PutByIdVariant::dumpInContext):
  • bytecode/PutByIdVariant.h: (JSC::PutByIdVariant::PutByIdVariant): (JSC::PutByIdVariant::replace): (JSC::PutByIdVariant::transition): (JSC::PutByIdVariant::structure): (JSC::PutByIdVariant::oldStructure):
  • dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
  • dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::handlePutById): (JSC::DFG::ByteCodeParser::parseBlock):
  • dfg/DFGConstantFoldingPhase.cpp: (JSC::DFG::ConstantFoldingPhase::foldConstants): (JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
  • dfg/DFGGraph.cpp: (JSC::DFG::Graph::visitChildren):
  • dfg/DFGNode.cpp: (JSC::DFG::MultiPutByOffsetData::writesStructures): (JSC::DFG::MultiPutByOffsetData::reallocatesStorage):
  • ftl/FTLAbbreviations.h: (JSC::FTL::getLinkage):
  • ftl/FTLLowerDFGToLLVM.cpp: (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol):

Source/WebCore:

This fixes the previous mismerge and adds test coverage for the thing that went wrong.
Also, this adds some helpers for making it easier to inspect JavaScript values.

  • testing/Internals.cpp:

(WebCore::Internals::description):

  • testing/Internals.h:
  • testing/Internals.idl:

2014-07-25 Mark Lam <[email protected]>


[ftlopt] Renamed DebuggerActivation to DebuggerScope.
<https://webkit.org/b/134273>


Reviewed by Michael Saboff.


No new tests.


  • ForwardingHeaders/debugger/DebuggerActivation.h: Removed.
  • Removed because this is not used.

Source/WebKit/mac:

2014-07-25 Mark Lam <[email protected]>


[ftlopt] Renamed DebuggerActivation to DebuggerScope.
<https://webkit.org/b/134273>


Reviewed by Michael Saboff.


  • WebView/WebScriptDebugDelegate.mm:
  • Removed unneeded #include.

Source/WTF:

  • wtf/text/WTFString.h:

LayoutTests:

  • js/regress/fold-get-by-id-to-multi-get-by-offset-expected.txt: Added.
  • js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int-expected.txt: Added.
  • js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html: Added.
  • js/regress/fold-get-by-id-to-multi-get-by-offset.html: Added.
  • js/regress/fold-multi-get-by-offset-to-get-by-offset-expected.txt: Added.
  • js/regress/fold-multi-get-by-offset-to-get-by-offset.html: Added.
  • js/regress/fold-multi-get-by-offset-to-poly-get-by-offset-expected.txt: Added.
  • js/regress/fold-multi-get-by-offset-to-poly-get-by-offset.html: Added.
  • js/regress/fold-multi-put-by-offset-to-poly-put-by-offset-expected.txt: Added.
  • js/regress/fold-multi-put-by-offset-to-poly-put-by-offset.html: Added.
  • js/regress/fold-multi-put-by-offset-to-put-by-offset-expected.txt: Added.
  • js/regress/fold-multi-put-by-offset-to-put-by-offset.html: Added.
  • js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset-expected.txt: Added.
  • js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.html: Added.
  • js/regress/fold-put-by-id-to-multi-put-by-offset-expected.txt: Added.
  • js/regress/fold-put-by-id-to-multi-put-by-offset.html: Added.
  • js/regress/fold-put-structure-expected.txt: Added.
  • js/regress/fold-put-structure.html: Added.
  • js/regress/hoist-poly-check-structure-effectful-loop-expected.txt: Added.
  • js/regress/hoist-poly-check-structure-effectful-loop.html: Added.
  • js/regress/hoist-poly-check-structure-expected.txt: Added.
  • js/regress/hoist-poly-check-structure.html: Added.
  • js/regress/put-by-id-replace-and-transition-expected.txt: Added.
  • js/regress/put-by-id-replace-and-transition.html: Added.
  • js/regress/put-by-id-slightly-polymorphic-expected.txt: Added.
  • js/regress/put-by-id-slightly-polymorphic.html: Added.
  • js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset-rare-int.js: Added.

(foo):
(fu):
(bar):
(.bar):
(Number):

  • js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset.js: Added.

(foo):
(fu):
(bar):
(.bar):
(Number):

  • js/regress/script-tests/fold-multi-get-by-offset-to-get-by-offset.js: Added.

(foo):
(fu):
(bar):
(.bar):

  • js/regress/script-tests/fold-multi-get-by-offset-to-poly-get-by-offset.js: Added.

(foo):
(fu):
(bar):
(.bar):

  • js/regress/script-tests/fold-multi-put-by-offset-to-poly-put-by-offset.js: Added.

(foo):
(fu):
(bar):
(.bar):

  • js/regress/script-tests/fold-multi-put-by-offset-to-put-by-offset.js: Added.

(foo):
(fu):
(bar):
(.bar):

  • js/regress/script-tests/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.js: Added.

(foo):
(fu):
(bar):
(.bar):

  • js/regress/script-tests/fold-put-by-id-to-multi-put-by-offset.js: Added.

(foo):
(fu):
(bar):
(.bar):

  • js/regress/script-tests/fold-put-structure.js: Added.

(foo):
(fu):
(bar):
(.bar):

  • js/regress/script-tests/hoist-poly-check-structure-effectful-loop.js: Added.

(foo):
(test):

  • js/regress/script-tests/hoist-poly-check-structure.js: Added.

(foo):
(test):

  • js/regress/script-tests/put-by-id-replace-and-transition.js: Added.
  • js/regress/script-tests/put-by-id-slightly-polymorphic.js: Added.
  • Property svn:eol-style set to native
File size: 48.6 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012, 2013 Apple Inc. All rights reserved.
4 * Copyright (C) 2006 Bjoern Graf ([email protected])
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24
25#include "ArrayPrototype.h"
26#include "ButterflyInlines.h"
27#include "BytecodeGenerator.h"
28#include "CodeBlock.h"
29#include "Completion.h"
30#include "CopiedSpaceInlines.h"
31#include "ExceptionHelpers.h"
32#include "HeapStatistics.h"
33#include "InitializeThreading.h"
34#include "Interpreter.h"
35#include "JSArray.h"
36#include "JSArrayBuffer.h"
37#include "JSCInlines.h"
38#include "JSFunction.h"
39#include "JSLock.h"
40#include "JSProxy.h"
41#include "JSString.h"
42#include "ProfilerDatabase.h"
43#include "SamplingTool.h"
44#include "StackVisitor.h"
45#include "StructureInlines.h"
46#include "StructureRareDataInlines.h"
47#include "TestRunnerUtils.h"
48#include <math.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <thread>
53#include <wtf/CurrentTime.h>
54#include <wtf/MainThread.h>
55#include <wtf/StringPrintStream.h>
56#include <wtf/text/StringBuilder.h>
57
58#if !OS(WINDOWS)
59#include <unistd.h>
60#endif
61
62#if HAVE(READLINE)
63// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
64// We #define it to something else to avoid this conflict.
65#define Function ReadlineFunction
66#include <readline/history.h>
67#include <readline/readline.h>
68#undef Function
69#endif
70
71#if HAVE(SYS_TIME_H)
72#include <sys/time.h>
73#endif
74
75#if HAVE(SIGNAL_H)
76#include <signal.h>
77#endif
78
79#if COMPILER(MSVC) && !OS(WINCE)
80#include <crtdbg.h>
81#include <mmsystem.h>
82#include <windows.h>
83#endif
84
85#if PLATFORM(IOS) && CPU(ARM_THUMB2)
86#include <fenv.h>
87#include <arm/arch.h>
88#endif
89
90#if PLATFORM(EFL)
91#include <Ecore.h>
92#endif
93
94using namespace JSC;
95using namespace WTF;
96
97namespace {
98
99NO_RETURN_WITH_VALUE static void jscExit(int status)
100{
101#if ENABLE(DFG_JIT)
102 if (DFG::isCrashing()) {
103 for (;;) {
104#if OS(WINDOWS)
105 Sleep(1000);
106#else
107 pause();
108#endif
109 }
110 }
111#endif // ENABLE(DFG_JIT)
112 exit(status);
113}
114
115class Element;
116class ElementHandleOwner;
117class Masuqerader;
118class Root;
119class RuntimeArray;
120
121class Element : public JSNonFinalObject {
122public:
123 Element(VM& vm, Structure* structure, Root* root)
124 : Base(vm, structure)
125 , m_root(root)
126 {
127 }
128
129 typedef JSNonFinalObject Base;
130 static const bool needsDestruction = false;
131
132 Root* root() const { return m_root; }
133 void setRoot(Root* root) { m_root = root; }
134
135 static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root)
136 {
137 Structure* structure = createStructure(vm, globalObject, jsNull());
138 Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure, root);
139 element->finishCreation(vm);
140 return element;
141 }
142
143 void finishCreation(VM&);
144
145 static ElementHandleOwner* handleOwner();
146
147 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
148 {
149 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
150 }
151
152 DECLARE_INFO;
153
154private:
155 Root* m_root;
156};
157
158class ElementHandleOwner : public WeakHandleOwner {
159public:
160 virtual bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
161 {
162 Element* element = jsCast<Element*>(handle.slot()->asCell());
163 return visitor.containsOpaqueRoot(element->root());
164 }
165};
166
167class Masquerader : public JSNonFinalObject {
168public:
169 Masquerader(VM& vm, Structure* structure)
170 : Base(vm, structure)
171 {
172 }
173
174 typedef JSNonFinalObject Base;
175
176 static Masquerader* create(VM& vm, JSGlobalObject* globalObject)
177 {
178 globalObject->masqueradesAsUndefinedWatchpoint()->fireAll();
179 Structure* structure = createStructure(vm, globalObject, jsNull());
180 Masquerader* result = new (NotNull, allocateCell<Masquerader>(vm.heap, sizeof(Masquerader))) Masquerader(vm, structure);
181 result->finishCreation(vm);
182 return result;
183 }
184
185 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
186 {
187 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
188 }
189
190 DECLARE_INFO;
191
192protected:
193 static const unsigned StructureFlags = JSC::MasqueradesAsUndefined | Base::StructureFlags;
194};
195
196class Root : public JSDestructibleObject {
197public:
198 Root(VM& vm, Structure* structure)
199 : Base(vm, structure)
200 {
201 }
202
203 Element* element()
204 {
205 return m_element.get();
206 }
207
208 void setElement(Element* element)
209 {
210 Weak<Element> newElement(element, Element::handleOwner());
211 m_element.swap(newElement);
212 }
213
214 static Root* create(VM& vm, JSGlobalObject* globalObject)
215 {
216 Structure* structure = createStructure(vm, globalObject, jsNull());
217 Root* root = new (NotNull, allocateCell<Root>(vm.heap, sizeof(Root))) Root(vm, structure);
218 root->finishCreation(vm);
219 return root;
220 }
221
222 typedef JSDestructibleObject Base;
223
224 DECLARE_INFO;
225 static const bool needsDestruction = true;
226
227 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
228 {
229 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
230 }
231
232 static void visitChildren(JSCell* thisObject, SlotVisitor& visitor)
233 {
234 Base::visitChildren(thisObject, visitor);
235 visitor.addOpaqueRoot(thisObject);
236 }
237
238private:
239 Weak<Element> m_element;
240};
241
242class ImpureGetter : public JSNonFinalObject {
243public:
244 ImpureGetter(VM& vm, Structure* structure)
245 : Base(vm, structure)
246 {
247 }
248
249 DECLARE_INFO;
250 typedef JSNonFinalObject Base;
251
252 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
253 {
254 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
255 }
256
257 static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate)
258 {
259 ImpureGetter* getter = new (NotNull, allocateCell<ImpureGetter>(vm.heap, sizeof(ImpureGetter))) ImpureGetter(vm, structure);
260 getter->finishCreation(vm, delegate);
261 return getter;
262 }
263
264 void finishCreation(VM& vm, JSObject* delegate)
265 {
266 Base::finishCreation(vm);
267 if (delegate)
268 m_delegate.set(vm, this, delegate);
269 }
270
271 static const unsigned StructureFlags = JSC::HasImpureGetOwnPropertySlot | JSC::OverridesGetOwnPropertySlot | JSC::OverridesVisitChildren | Base::StructureFlags;
272
273 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName name, PropertySlot& slot)
274 {
275 ImpureGetter* thisObject = jsCast<ImpureGetter*>(object);
276
277 if (thisObject->m_delegate && thisObject->m_delegate->getPropertySlot(exec, name, slot))
278 return true;
279
280 return Base::getOwnPropertySlot(object, exec, name, slot);
281 }
282
283 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
284 {
285 Base::visitChildren(cell, visitor);
286 ImpureGetter* thisObject = jsCast<ImpureGetter*>(cell);
287 visitor.append(&thisObject->m_delegate);
288 }
289
290 void setDelegate(VM& vm, JSObject* delegate)
291 {
292 m_delegate.set(vm, this, delegate);
293 }
294
295private:
296 WriteBarrier<JSObject> m_delegate;
297};
298
299class RuntimeArray : public JSArray {
300public:
301 typedef JSArray Base;
302
303 static RuntimeArray* create(ExecState* exec)
304 {
305 VM& vm = exec->vm();
306 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
307 Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject));
308 RuntimeArray* runtimeArray = new (NotNull, allocateCell<RuntimeArray>(*exec->heap())) RuntimeArray(exec, structure);
309 runtimeArray->finishCreation(exec);
310 vm.heap.addFinalizer(runtimeArray, destroy);
311 return runtimeArray;
312 }
313
314 ~RuntimeArray() { }
315
316 static void destroy(JSCell* cell)
317 {
318 static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
319 }
320
321 static const bool needsDestruction = false;
322
323 static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
324 {
325 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
326 if (propertyName == exec->propertyNames().length) {
327 slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
328 return true;
329 }
330
331 unsigned index = propertyName.asIndex();
332 if (index < thisObject->getLength()) {
333 ASSERT(index != PropertyName::NotAnIndex);
334 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
335 return true;
336 }
337
338 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
339 }
340
341 static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
342 {
343 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
344 if (index < thisObject->getLength()) {
345 slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
346 return true;
347 }
348
349 return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
350 }
351
352 static NO_RETURN_DUE_TO_CRASH void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&)
353 {
354 RELEASE_ASSERT_NOT_REACHED();
355 }
356
357 static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName)
358 {
359 RELEASE_ASSERT_NOT_REACHED();
360#if !COMPILER(CLANG) && !COMPILER(MSVC)
361 return true;
362#endif
363 }
364
365 unsigned getLength() const { return m_vector.size(); }
366
367 DECLARE_INFO;
368
369 static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject)
370 {
371 return globalObject->arrayPrototype();
372 }
373
374 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
375 {
376 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayClass);
377 }
378
379protected:
380 void finishCreation(ExecState* exec)
381 {
382 Base::finishCreation(exec->vm());
383 ASSERT(inherits(info()));
384
385 for (size_t i = 0; i < exec->argumentCount(); i++)
386 m_vector.append(exec->argument(i).toInt32(exec));
387 }
388
389 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSArray::StructureFlags;
390
391private:
392 RuntimeArray(ExecState* exec, Structure* structure)
393 : JSArray(exec->vm(), structure, 0)
394 {
395 }
396
397 static EncodedJSValue lengthGetter(ExecState* exec, JSObject*, EncodedJSValue thisValue, PropertyName)
398 {
399 RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(JSValue::decode(thisValue));
400 if (!thisObject)
401 return throwVMTypeError(exec);
402 return JSValue::encode(jsNumber(thisObject->getLength()));
403 }
404
405 Vector<int> m_vector;
406};
407
408const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Element) };
409const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Masquerader) };
410const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Root) };
411const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ImpureGetter) };
412const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(RuntimeArray) };
413
414ElementHandleOwner* Element::handleOwner()
415{
416 static ElementHandleOwner* owner = 0;
417 if (!owner)
418 owner = new ElementHandleOwner();
419 return owner;
420}
421
422void Element::finishCreation(VM& vm)
423{
424 Base::finishCreation(vm);
425 m_root->setElement(this);
426}
427
428}
429
430static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
431
432static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
433static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
434static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
435static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
436
437static EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState*);
438static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState*);
439static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*);
440static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*);
441static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
442static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
443static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
444static EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState*);
445static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
446static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*);
447static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
448static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
449static EncodedJSValue JSC_HOST_CALL functionDeleteAllCompiledCode(ExecState*);
450#ifndef NDEBUG
451static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
452static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
453#endif
454static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
455static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
456static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
457static EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState*);
458static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
459static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
460static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
461static EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState*);
462static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*);
463static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
464static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
465static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
466static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
467static EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*);
468static EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*);
469static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*);
470static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
471static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
472static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
473static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
474static EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState*);
475static EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables (ExecState*);
476
477#if ENABLE(SAMPLING_FLAGS)
478static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
479static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
480#endif
481
482struct Script {
483 bool isFile;
484 char* argument;
485
486 Script(bool isFile, char *argument)
487 : isFile(isFile)
488 , argument(argument)
489 {
490 }
491};
492
493class CommandLine {
494public:
495 CommandLine(int argc, char** argv)
496 : m_interactive(false)
497 , m_dump(false)
498 , m_exitCode(false)
499 , m_profile(false)
500 {
501 parseArguments(argc, argv);
502 }
503
504 bool m_interactive;
505 bool m_dump;
506 bool m_exitCode;
507 Vector<Script> m_scripts;
508 Vector<String> m_arguments;
509 bool m_profile;
510 String m_profilerOutput;
511
512 void parseArguments(int, char**);
513};
514
515static const char interactivePrompt[] = ">>> ";
516
517class StopWatch {
518public:
519 void start();
520 void stop();
521 long getElapsedMS(); // call stop() first
522
523private:
524 double m_startTime;
525 double m_stopTime;
526};
527
528void StopWatch::start()
529{
530 m_startTime = monotonicallyIncreasingTime();
531}
532
533void StopWatch::stop()
534{
535 m_stopTime = monotonicallyIncreasingTime();
536}
537
538long StopWatch::getElapsedMS()
539{
540 return static_cast<long>((m_stopTime - m_startTime) * 1000);
541}
542
543class GlobalObject : public JSGlobalObject {
544private:
545 GlobalObject(VM&, Structure*);
546
547public:
548 typedef JSGlobalObject Base;
549
550 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
551 {
552 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
553 object->finishCreation(vm, arguments);
554 vm.heap.addFinalizer(object, destroy);
555 return object;
556 }
557
558 static const bool needsDestruction = false;
559
560 DECLARE_INFO;
561 static const GlobalObjectMethodTable s_globalObjectMethodTable;
562
563 static Structure* createStructure(VM& vm, JSValue prototype)
564 {
565 return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
566 }
567
568 static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return true; }
569
570protected:
571 void finishCreation(VM& vm, const Vector<String>& arguments)
572 {
573 Base::finishCreation(vm);
574
575 addFunction(vm, "debug", functionDebug, 1);
576 addFunction(vm, "describe", functionDescribe, 1);
577 addFunction(vm, "describeArray", functionDescribeArray, 1);
578 addFunction(vm, "print", functionPrint, 1);
579 addFunction(vm, "quit", functionQuit, 0);
580 addFunction(vm, "gc", functionGCAndSweep, 0);
581 addFunction(vm, "fullGC", functionFullGC, 0);
582 addFunction(vm, "edenGC", functionEdenGC, 0);
583 addFunction(vm, "deleteAllCompiledCode", functionDeleteAllCompiledCode, 0);
584#ifndef NDEBUG
585 addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
586 addFunction(vm, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
587#endif
588 addFunction(vm, "version", functionVersion, 1);
589 addFunction(vm, "run", functionRun, 1);
590 addFunction(vm, "load", functionLoad, 1);
591 addFunction(vm, "readFile", functionReadFile, 1);
592 addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
593 addFunction(vm, "jscStack", functionJSCStack, 1);
594 addFunction(vm, "readline", functionReadline, 0);
595 addFunction(vm, "preciseTime", functionPreciseTime, 0);
596 addFunction(vm, "neverInlineFunction", functionNeverInlineFunction, 1);
597 addFunction(vm, "noInline", functionNeverInlineFunction, 1);
598 addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
599 addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1);
600 addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
601 addFunction(vm, "transferArrayBuffer", functionTransferArrayBuffer, 1);
602#if ENABLE(SAMPLING_FLAGS)
603 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
604 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
605#endif
606 addConstructableFunction(vm, "Root", functionCreateRoot, 0);
607 addConstructableFunction(vm, "Element", functionCreateElement, 1);
608 addFunction(vm, "getElement", functionGetElement, 1);
609 addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
610
611 putDirectNativeFunction(vm, this, Identifier(&vm, "DFGTrue"), 0, functionFalse1, DFGTrueIntrinsic, DontEnum | JSC::Function);
612 putDirectNativeFunction(vm, this, Identifier(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum | JSC::Function);
613 putDirectNativeFunction(vm, this, Identifier(&vm, "isFinalTier"), 0, functionFalse2, IsFinalTierIntrinsic, DontEnum | JSC::Function);
614 putDirectNativeFunction(vm, this, Identifier(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum | JSC::Function);
615 putDirectNativeFunction(vm, this, Identifier(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum | JSC::Function);
616
617 addFunction(vm, "effectful42", functionEffectful42, 0);
618 addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
619 addFunction(vm, "hasCustomProperties", functionHasCustomProperties, 0);
620
621 addFunction(vm, "createProxy", functionCreateProxy, 1);
622 addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
623
624 addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
625 addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
626 addFunction(vm, "dumpTypesForAllVariables", functionDumpTypesForAllVariables , 4);
627
628 JSArray* array = constructEmptyArray(globalExec(), 0);
629 for (size_t i = 0; i < arguments.size(); ++i)
630 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
631 putDirect(vm, Identifier(globalExec(), "arguments"), array);
632
633 putDirect(vm, Identifier(globalExec(), "console"), jsUndefined());
634 }
635
636 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
637 {
638 Identifier identifier(&vm, name);
639 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
640 }
641
642 void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
643 {
644 Identifier identifier(&vm, name);
645 putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function));
646 }
647};
648
649const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
650const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, 0, &shouldInterruptScriptBeforeTimeout };
651
652
653GlobalObject::GlobalObject(VM& vm, Structure* structure)
654 : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
655{
656}
657
658static inline String stringFromUTF(const char* utf8)
659{
660 // Find the the first non-ascii character, or nul.
661 const char* pos = utf8;
662 while (*pos > 0)
663 pos++;
664 size_t asciiLength = pos - utf8;
665
666 // Fast case - string is all ascii.
667 if (!*pos)
668 return String(utf8, asciiLength);
669
670 // Slow case - contains non-ascii characters, use fromUTF8WithLatin1Fallback.
671 ASSERT(*pos < 0);
672 ASSERT(strlen(utf8) == asciiLength + strlen(pos));
673 return String::fromUTF8WithLatin1Fallback(utf8, asciiLength + strlen(pos));
674}
675
676static inline SourceCode jscSource(const char* utf8, const String& filename)
677{
678 String str = stringFromUTF(utf8);
679 return makeSource(str, filename);
680}
681
682EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
683{
684 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
685 if (i)
686 putchar(' ');
687
688 printf("%s", exec->uncheckedArgument(i).toString(exec)->value(exec).utf8().data());
689 }
690
691 putchar('\n');
692 fflush(stdout);
693 return JSValue::encode(jsUndefined());
694}
695
696#ifndef NDEBUG
697EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
698{
699 if (!exec->callerFrame()->isVMEntrySentinel())
700 exec->vm().interpreter->dumpCallFrame(exec->callerFrame());
701 return JSValue::encode(jsUndefined());
702}
703#endif
704
705EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
706{
707 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
708 return JSValue::encode(jsUndefined());
709}
710
711EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
712{
713 if (exec->argumentCount() < 1)
714 return JSValue::encode(jsUndefined());
715 return JSValue::encode(jsString(exec, toString(exec->argument(0))));
716}
717
718EncodedJSValue JSC_HOST_CALL functionDescribeArray(ExecState* exec)
719{
720 if (exec->argumentCount() < 1)
721 return JSValue::encode(jsUndefined());
722 JSObject* object = jsDynamicCast<JSObject*>(exec->argument(0));
723 if (!object)
724 return JSValue::encode(jsString(exec, "<not object>"));
725 return JSValue::encode(jsString(exec, toString("<Public length: ", object->getArrayLength(), "; vector length: ", object->getVectorLength(), ">")));
726}
727
728class FunctionJSCStackFunctor {
729public:
730 FunctionJSCStackFunctor(StringBuilder& trace)
731 : m_trace(trace)
732 {
733 }
734
735 StackVisitor::Status operator()(StackVisitor& visitor)
736 {
737 m_trace.append(String::format(" %zu %s\n", visitor->index(), visitor->toString().utf8().data()));
738 return StackVisitor::Continue;
739 }
740
741private:
742 StringBuilder& m_trace;
743};
744
745EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
746{
747 StringBuilder trace;
748 trace.appendLiteral("--> Stack trace:\n");
749
750 FunctionJSCStackFunctor functor(trace);
751 exec->iterate(functor);
752 fprintf(stderr, "%s", trace.toString().utf8().data());
753 return JSValue::encode(jsUndefined());
754}
755
756EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
757{
758 JSLockHolder lock(exec);
759 return JSValue::encode(Root::create(exec->vm(), exec->lexicalGlobalObject()));
760}
761
762EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
763{
764 JSLockHolder lock(exec);
765 JSValue arg = exec->argument(0);
766 return JSValue::encode(Element::create(exec->vm(), exec->lexicalGlobalObject(), arg.isNull() ? nullptr : jsCast<Root*>(exec->argument(0))));
767}
768
769EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
770{
771 JSLockHolder lock(exec);
772 Element* result = jsCast<Root*>(exec->argument(0).asCell())->element();
773 return JSValue::encode(result ? result : jsUndefined());
774}
775
776EncodedJSValue JSC_HOST_CALL functionSetElementRoot(ExecState* exec)
777{
778 JSLockHolder lock(exec);
779 Element* element = jsCast<Element*>(exec->argument(0));
780 Root* root = jsCast<Root*>(exec->argument(1));
781 element->setRoot(root);
782 return JSValue::encode(jsUndefined());
783}
784
785EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
786{
787 JSLockHolder lock(exec);
788 JSValue target = exec->argument(0);
789 if (!target.isObject())
790 return JSValue::encode(jsUndefined());
791 JSObject* jsTarget = asObject(target.asCell());
792 Structure* structure = JSProxy::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsTarget->prototype());
793 JSProxy* proxy = JSProxy::create(exec->vm(), structure, jsTarget);
794 return JSValue::encode(proxy);
795}
796
797EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
798{
799 JSLockHolder lock(exec);
800 RuntimeArray* array = RuntimeArray::create(exec);
801 return JSValue::encode(array);
802}
803
804EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
805{
806 JSLockHolder lock(exec);
807 JSValue target = exec->argument(0);
808 JSObject* delegate = nullptr;
809 if (target.isObject())
810 delegate = asObject(target.asCell());
811 Structure* structure = ImpureGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
812 ImpureGetter* result = ImpureGetter::create(exec->vm(), structure, delegate);
813 return JSValue::encode(result);
814}
815
816EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
817{
818 JSLockHolder lock(exec);
819 JSValue base = exec->argument(0);
820 if (!base.isObject())
821 return JSValue::encode(jsUndefined());
822 JSValue delegate = exec->argument(1);
823 if (!delegate.isObject())
824 return JSValue::encode(jsUndefined());
825 ImpureGetter* impureGetter = jsCast<ImpureGetter*>(asObject(base.asCell()));
826 impureGetter->setDelegate(exec->vm(), asObject(delegate.asCell()));
827 return JSValue::encode(jsUndefined());
828}
829
830EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState* exec)
831{
832 JSLockHolder lock(exec);
833 exec->heap()->collectAllGarbage();
834 return JSValue::encode(jsUndefined());
835}
836
837EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState* exec)
838{
839 JSLockHolder lock(exec);
840 exec->heap()->collect(FullCollection);
841 return JSValue::encode(jsUndefined());
842}
843
844EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
845{
846 JSLockHolder lock(exec);
847 exec->heap()->collect(EdenCollection);
848 return JSValue::encode(jsUndefined());
849}
850
851EncodedJSValue JSC_HOST_CALL functionDeleteAllCompiledCode(ExecState* exec)
852{
853 JSLockHolder lock(exec);
854 exec->heap()->deleteAllCompiledCode();
855 return JSValue::encode(jsUndefined());
856}
857
858#ifndef NDEBUG
859EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
860{
861 JSLockHolder lock(exec);
862 exec->vm().releaseExecutableMemory();
863 return JSValue::encode(jsUndefined());
864}
865#endif
866
867EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
868{
869 // We need this function for compatibility with the Mozilla JS tests but for now
870 // we don't actually do any version-specific handling
871 return JSValue::encode(jsUndefined());
872}
873
874EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
875{
876 String fileName = exec->argument(0).toString(exec)->value(exec);
877 Vector<char> script;
878 if (!fillBufferWithContentsOfFile(fileName, script))
879 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
880
881 GlobalObject* globalObject = GlobalObject::create(exec->vm(), GlobalObject::createStructure(exec->vm(), jsNull()), Vector<String>());
882
883 JSArray* array = constructEmptyArray(globalObject->globalExec(), 0);
884 for (unsigned i = 1; i < exec->argumentCount(); ++i)
885 array->putDirectIndex(globalObject->globalExec(), i - 1, exec->uncheckedArgument(i));
886 globalObject->putDirect(
887 exec->vm(), Identifier(globalObject->globalExec(), "arguments"), array);
888
889 JSValue exception;
890 StopWatch stopWatch;
891 stopWatch.start();
892 evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception);
893 stopWatch.stop();
894
895 if (!!exception) {
896 exec->vm().throwException(globalObject->globalExec(), exception);
897 return JSValue::encode(jsUndefined());
898 }
899
900 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
901}
902
903EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
904{
905 String fileName = exec->argument(0).toString(exec)->value(exec);
906 Vector<char> script;
907 if (!fillBufferWithContentsOfFile(fileName, script))
908 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
909
910 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
911
912 JSValue evaluationException;
913 JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
914 if (evaluationException)
915 exec->vm().throwException(exec, evaluationException);
916 return JSValue::encode(result);
917}
918
919EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
920{
921 String fileName = exec->argument(0).toString(exec)->value(exec);
922 Vector<char> script;
923 if (!fillBufferWithContentsOfFile(fileName, script))
924 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
925
926 return JSValue::encode(jsString(exec, stringFromUTF(script.data())));
927}
928
929EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
930{
931 String fileName = exec->argument(0).toString(exec)->value(exec);
932 Vector<char> script;
933 if (!fillBufferWithContentsOfFile(fileName, script))
934 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
935
936 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
937
938 StopWatch stopWatch;
939 stopWatch.start();
940
941 JSValue syntaxException;
942 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
943 stopWatch.stop();
944
945 if (!validSyntax)
946 exec->vm().throwException(exec, syntaxException);
947 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
948}
949
950#if ENABLE(SAMPLING_FLAGS)
951EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
952{
953 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
954 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
955 if ((flag >= 1) && (flag <= 32))
956 SamplingFlags::setFlag(flag);
957 }
958 return JSValue::encode(jsNull());
959}
960
961EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
962{
963 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
964 unsigned flag = static_cast<unsigned>(exec->uncheckedArgument(i).toNumber(exec));
965 if ((flag >= 1) && (flag <= 32))
966 SamplingFlags::clearFlag(flag);
967 }
968 return JSValue::encode(jsNull());
969}
970#endif
971
972EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
973{
974 Vector<char, 256> line;
975 int c;
976 while ((c = getchar()) != EOF) {
977 // FIXME: Should we also break on \r?
978 if (c == '\n')
979 break;
980 line.append(c);
981 }
982 line.append('\0');
983 return JSValue::encode(jsString(exec, line.data()));
984}
985
986EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
987{
988 return JSValue::encode(jsNumber(currentTime()));
989}
990
991EncodedJSValue JSC_HOST_CALL functionNeverInlineFunction(ExecState* exec)
992{
993 return JSValue::encode(setNeverInline(exec));
994}
995
996EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState* exec)
997{
998 return JSValue::encode(optimizeNextInvocation(exec));
999}
1000
1001EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
1002{
1003 return JSValue::encode(numberOfDFGCompiles(exec));
1004}
1005
1006EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
1007{
1008 if (exec->argumentCount() < 1)
1009 return JSValue::encode(jsUndefined());
1010
1011 CodeBlock* block = getSomeBaselineCodeBlockForFunction(exec->argument(0));
1012 if (!block)
1013 return JSValue::encode(jsNumber(0));
1014
1015 return JSValue::encode(jsNumber(block->reoptimizationRetryCounter()));
1016}
1017
1018EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
1019{
1020 if (exec->argumentCount() < 1)
1021 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Not enough arguments")));
1022
1023 JSArrayBuffer* buffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0));
1024 if (!buffer)
1025 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Expected an array buffer")));
1026
1027 ArrayBufferContents dummyContents;
1028 buffer->impl()->transfer(dummyContents);
1029
1030 return JSValue::encode(jsUndefined());
1031}
1032
1033EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
1034{
1035 jscExit(EXIT_SUCCESS);
1036
1037#if COMPILER(MSVC)
1038 // Without this, Visual Studio will complain that this method does not return a value.
1039 return JSValue::encode(jsUndefined());
1040#endif
1041}
1042
1043EncodedJSValue JSC_HOST_CALL functionFalse1(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1044EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*) { return JSValue::encode(jsBoolean(false)); }
1045
1046EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
1047EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
1048
1049EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
1050
1051EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*)
1052{
1053 return JSValue::encode(jsNumber(42));
1054}
1055
1056EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState* exec)
1057{
1058 return JSValue::encode(Masquerader::create(exec->vm(), exec->lexicalGlobalObject()));
1059}
1060
1061EncodedJSValue JSC_HOST_CALL functionHasCustomProperties(ExecState* exec)
1062{
1063 JSValue value = exec->argument(0);
1064 if (value.isObject())
1065 return JSValue::encode(jsBoolean(asObject(value)->hasCustomProperties()));
1066 return JSValue::encode(jsBoolean(false));
1067}
1068
1069EncodedJSValue JSC_HOST_CALL functionDumpTypesForAllVariables(ExecState* exec)
1070{
1071 exec->vm().dumpHighFidelityProfilingTypes();
1072 return JSValue::encode(jsUndefined());
1073}
1074
1075// Use SEH for Release builds only to get rid of the crash report dialog
1076// (luckily the same tests fail in Release and Debug builds so far). Need to
1077// be in a separate main function because the jscmain function requires object
1078// unwinding.
1079
1080#if COMPILER(MSVC) && !defined(_DEBUG) && !OS(WINCE)
1081#define TRY __try {
1082#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
1083#else
1084#define TRY
1085#define EXCEPT(x)
1086#endif
1087
1088int jscmain(int argc, char** argv);
1089
1090static double s_desiredTimeout;
1091
1092static NO_RETURN_DUE_TO_CRASH void timeoutThreadMain(void*)
1093{
1094 auto timeout = std::chrono::microseconds(static_cast<std::chrono::microseconds::rep>(s_desiredTimeout * 1000000));
1095 std::this_thread::sleep_for(timeout);
1096
1097 dataLog("Timed out after ", s_desiredTimeout, " seconds!\n");
1098 CRASH();
1099}
1100
1101int main(int argc, char** argv)
1102{
1103#if PLATFORM(IOS) && CPU(ARM_THUMB2)
1104 // Enabled IEEE754 denormal support.
1105 fenv_t env;
1106 fegetenv( &env );
1107 env.__fpscr &= ~0x01000000u;
1108 fesetenv( &env );
1109#endif
1110
1111#if OS(WINDOWS)
1112#if !OS(WINCE)
1113 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1114 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1115 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1116 ::SetErrorMode(0);
1117
1118#if defined(_DEBUG)
1119 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1120 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1121 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1122 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1123 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1124 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
1125#endif
1126#endif
1127
1128 timeBeginPeriod(1);
1129#endif
1130
1131#if PLATFORM(EFL)
1132 ecore_init();
1133#endif
1134
1135 // Initialize JSC before getting VM.
1136#if ENABLE(SAMPLING_REGIONS)
1137 WTF::initializeMainThread();
1138#endif
1139 JSC::initializeThreading();
1140
1141#if !OS(WINCE)
1142 if (char* timeoutString = getenv("JSC_timeout")) {
1143 if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
1144 dataLog(
1145 "WARNING: timeout string is malformed, got ", timeoutString,
1146 " but expected a number. Not using a timeout.\n");
1147 } else
1148 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");
1149 }
1150#endif
1151
1152#if PLATFORM(IOS)
1153 Options::crashIfCantAllocateJITMemory() = true;
1154#endif
1155
1156 // We can't use destructors in the following code because it uses Windows
1157 // Structured Exception Handling
1158 int res = 0;
1159 TRY
1160 res = jscmain(argc, argv);
1161 EXCEPT(res = 3)
1162 if (Options::logHeapStatisticsAtExit())
1163 HeapStatistics::reportSuccess();
1164
1165#if PLATFORM(EFL)
1166 ecore_shutdown();
1167#endif
1168
1169 jscExit(res);
1170}
1171
1172static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
1173{
1174 const char* script;
1175 String fileName;
1176 Vector<char> scriptBuffer;
1177
1178 if (dump)
1179 JSC::Options::dumpGeneratedBytecodes() = true;
1180
1181 VM& vm = globalObject->vm();
1182
1183#if ENABLE(SAMPLING_FLAGS)
1184 SamplingFlags::start();
1185#endif
1186
1187 bool success = true;
1188 for (size_t i = 0; i < scripts.size(); i++) {
1189 if (scripts[i].isFile) {
1190 fileName = scripts[i].argument;
1191 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
1192 return false; // fail early so we can catch missing files
1193 script = scriptBuffer.data();
1194 } else {
1195 script = scripts[i].argument;
1196 fileName = "[Command Line]";
1197 }
1198
1199 vm.startSampling();
1200
1201 JSValue evaluationException;
1202 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
1203 success = success && !evaluationException;
1204 if (dump && !evaluationException)
1205 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1206 if (evaluationException) {
1207 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1208 Identifier stackID(globalObject->globalExec(), "stack");
1209 JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
1210 if (!stackValue.isUndefinedOrNull())
1211 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1212 }
1213
1214 vm.stopSampling();
1215 globalObject->globalExec()->clearException();
1216 }
1217
1218#if ENABLE(SAMPLING_FLAGS)
1219 SamplingFlags::stop();
1220#endif
1221#if ENABLE(SAMPLING_REGIONS)
1222 SamplingRegion::dump();
1223#endif
1224 vm.dumpSampleData(globalObject->globalExec());
1225#if ENABLE(SAMPLING_COUNTERS)
1226 AbstractSamplingCounter::dump();
1227#endif
1228#if ENABLE(REGEXP_TRACING)
1229 vm.dumpRegExpTrace();
1230#endif
1231 return success;
1232}
1233
1234#define RUNNING_FROM_XCODE 0
1235
1236static void runInteractive(GlobalObject* globalObject)
1237{
1238 String interpreterName("Interpreter");
1239
1240 bool shouldQuit = false;
1241 while (!shouldQuit) {
1242#if HAVE(READLINE) && !RUNNING_FROM_XCODE
1243 ParserError error;
1244 String source;
1245 do {
1246 error = ParserError();
1247 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
1248 shouldQuit = !line;
1249 if (!line)
1250 break;
1251 source = source + line;
1252 source = source + '\n';
1253 checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
1254 if (!line[0])
1255 break;
1256 add_history(line);
1257 } while (error.m_syntaxErrorType == ParserError::SyntaxErrorRecoverable);
1258
1259 if (error.m_type != ParserError::ErrorNone) {
1260 printf("%s:%d\n", error.m_message.utf8().data(), error.m_line);
1261 continue;
1262 }
1263
1264
1265 JSValue evaluationException;
1266 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException);
1267#else
1268 printf("%s", interactivePrompt);
1269 Vector<char, 256> line;
1270 int c;
1271 while ((c = getchar()) != EOF) {
1272 // FIXME: Should we also break on \r?
1273 if (c == '\n')
1274 break;
1275 line.append(c);
1276 }
1277 if (line.isEmpty())
1278 break;
1279 line.append('\0');
1280
1281 JSValue evaluationException;
1282 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
1283#endif
1284 if (evaluationException)
1285 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1286 else
1287 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
1288
1289 globalObject->globalExec()->clearException();
1290 }
1291 printf("\n");
1292}
1293
1294static NO_RETURN void printUsageStatement(bool help = false)
1295{
1296 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
1297 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
1298 fprintf(stderr, " -e Evaluate argument as script code\n");
1299 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
1300 fprintf(stderr, " -h|--help Prints this help message\n");
1301 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
1302#if HAVE(SIGNAL_H)
1303 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
1304#endif
1305 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
1306 fprintf(stderr, " -x Output exit code before terminating\n");
1307 fprintf(stderr, "\n");
1308 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
1309 fprintf(stderr, " --dumpOptions Dumps all JSC VM options before continuing\n");
1310 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
1311 fprintf(stderr, "\n");
1312
1313 jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
1314}
1315
1316void CommandLine::parseArguments(int argc, char** argv)
1317{
1318 int i = 1;
1319 bool needToDumpOptions = false;
1320 bool needToExit = false;
1321
1322 for (; i < argc; ++i) {
1323 const char* arg = argv[i];
1324 if (!strcmp(arg, "-f")) {
1325 if (++i == argc)
1326 printUsageStatement();
1327 m_scripts.append(Script(true, argv[i]));
1328 continue;
1329 }
1330 if (!strcmp(arg, "-e")) {
1331 if (++i == argc)
1332 printUsageStatement();
1333 m_scripts.append(Script(false, argv[i]));
1334 continue;
1335 }
1336 if (!strcmp(arg, "-i")) {
1337 m_interactive = true;
1338 continue;
1339 }
1340 if (!strcmp(arg, "-d")) {
1341 m_dump = true;
1342 continue;
1343 }
1344 if (!strcmp(arg, "-p")) {
1345 if (++i == argc)
1346 printUsageStatement();
1347 m_profile = true;
1348 m_profilerOutput = argv[i];
1349 continue;
1350 }
1351 if (!strcmp(arg, "-s")) {
1352#if HAVE(SIGNAL_H)
1353 signal(SIGILL, _exit);
1354 signal(SIGFPE, _exit);
1355 signal(SIGBUS, _exit);
1356 signal(SIGSEGV, _exit);
1357#endif
1358 continue;
1359 }
1360 if (!strcmp(arg, "-x")) {
1361 m_exitCode = true;
1362 continue;
1363 }
1364 if (!strcmp(arg, "--")) {
1365 ++i;
1366 break;
1367 }
1368 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
1369 printUsageStatement(true);
1370
1371 if (!strcmp(arg, "--options")) {
1372 needToDumpOptions = true;
1373 needToExit = true;
1374 continue;
1375 }
1376 if (!strcmp(arg, "--dumpOptions")) {
1377 needToDumpOptions = true;
1378 continue;
1379 }
1380
1381 // See if the -- option is a JSC VM option.
1382 // NOTE: At this point, we know that the arg starts with "--". Skip it.
1383 if (JSC::Options::setOption(&arg[2])) {
1384 // The arg was recognized as a VM option and has been parsed.
1385 continue; // Just continue with the next arg.
1386 }
1387
1388 // This arg is not recognized by the VM nor by jsc. Pass it on to the
1389 // script.
1390 m_scripts.append(Script(true, argv[i]));
1391 }
1392
1393 if (m_scripts.isEmpty())
1394 m_interactive = true;
1395
1396 for (; i < argc; ++i)
1397 m_arguments.append(argv[i]);
1398
1399 if (needToDumpOptions)
1400 JSC::Options::dumpAllOptions(stderr);
1401 if (needToExit)
1402 jscExit(EXIT_SUCCESS);
1403}
1404
1405int jscmain(int argc, char** argv)
1406{
1407 // Note that the options parsing can affect VM creation, and thus
1408 // comes first.
1409 CommandLine options(argc, argv);
1410 VM* vm = VM::create(LargeHeap).leakRef();
1411 int result;
1412 {
1413 JSLockHolder locker(vm);
1414
1415 if (options.m_profile && !vm->m_perBytecodeProfiler)
1416 vm->m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*vm));
1417
1418 GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
1419 bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump);
1420 if (options.m_interactive && success)
1421 runInteractive(globalObject);
1422
1423 result = success ? 0 : 3;
1424
1425 if (options.m_exitCode)
1426 printf("jsc exiting %d\n", result);
1427
1428 if (options.m_profile) {
1429 if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
1430 fprintf(stderr, "could not save profiler output.\n");
1431 }
1432
1433#if ENABLE(JIT)
1434 if (Options::enableExceptionFuzz())
1435 printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
1436#endif
1437 }
1438
1439 return result;
1440}
1441
1442static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
1443{
1444 FILE* f = fopen(fileName.utf8().data(), "r");
1445 if (!f) {
1446 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
1447 return false;
1448 }
1449
1450 size_t bufferSize = 0;
1451 size_t bufferCapacity = 1024;
1452
1453 buffer.resize(bufferCapacity);
1454
1455 while (!feof(f) && !ferror(f)) {
1456 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
1457 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
1458 bufferCapacity *= 2;
1459 buffer.resize(bufferCapacity);
1460 }
1461 }
1462 fclose(f);
1463 buffer[bufferSize] = '\0';
1464
1465 if (buffer[0] == '#' && buffer[1] == '!')
1466 buffer[0] = buffer[1] = '/';
1467
1468 return true;
1469}
Note: See TracBrowser for help on using the repository browser.