diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-11-29 12:18:48 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-11-29 12:18:57 +0100 |
commit | 4c01d0526ba4dd8cff0c0ff22a6f0ab5eb973064 (patch) | |
tree | bed2fe914fe0f7ec70abfb47d2d84af8a3604d09 /Source/JavaScriptCore | |
parent | 01485457c9a5da3f1121015afd25bb53af77662e (diff) | |
download | qtwebkit-4c01d0526ba4dd8cff0c0ff22a6f0ab5eb973064.tar.gz |
Imported WebKit commit c60cfe0fc09efd257aa0111d7b133b02deb8a63e (http://svn.webkit.org/repository/webkit/trunk@136119)
New snapshot that includes the fix for installing the QtWebProcess into libexec
Change-Id: I01344e079cbdac5678c4cba6ffcc05f4597cf0d7
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'Source/JavaScriptCore')
58 files changed, 1816 insertions, 1007 deletions
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index a77e9e451..7e5656025 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -100,6 +100,7 @@ SET(JavaScriptCore_SOURCES dfg/DFGStructureCheckHoistingPhase.cpp dfg/DFGThunks.cpp dfg/DFGValueSource.cpp + dfg/DFGVariableAccessDataDump.cpp dfg/DFGVariableEvent.cpp dfg/DFGVariableEventStream.cpp dfg/DFGValidate.cpp diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index ba2979bc2..9ab660ba2 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,420 @@ +2012-11-28 Filip Pizlo <fpizlo@apple.com> + + SpeculatedType dumping should not use the static char buffer[thingy] idiom + https://bugs.webkit.org/show_bug.cgi?id=103584 + + Reviewed by Michael Saboff. + + Changed SpeculatedType to be "dumpable" by saying things like: + + dataLog("thingy = ", SpeculationDump(thingy)) + + Removed the old stringification functions, and changed all code that referred to them + to use the new dataLog()/print() style. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * bytecode/SpeculatedType.cpp: + (JSC::dumpSpeculation): + (JSC::speculationToAbbreviatedString): + (JSC::dumpSpeculationAbbreviated): + * bytecode/SpeculatedType.h: + * bytecode/ValueProfile.h: + (JSC::ValueProfileBase::dump): + * bytecode/VirtualRegister.h: + (WTF::printInternal): + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::dump): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::injectLazyOperandSpeculation): + (JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::predictArgumentTypes): + * dfg/DFGGraph.h: + (Graph): + * dfg/DFGStructureAbstractValue.h: + * dfg/DFGVariableAccessDataDump.cpp: Added. + (JSC::DFG::VariableAccessDataDump::VariableAccessDataDump): + (JSC::DFG::VariableAccessDataDump::dump): + * dfg/DFGVariableAccessDataDump.h: Added. + (VariableAccessDataDump): + +2012-11-28 Michael Saboff <msaboff@apple.com> + + Change Bytecompiler s_dumpsGeneratedCode to an Options value + https://bugs.webkit.org/show_bug.cgi?id=103588 + + Reviewed by Filip Pizlo. + + Moved the control of dumping bytecodes to Options::dumpGeneratedBytecodes. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecompiler/BytecodeGenerator.cpp: + * bytecompiler/BytecodeGenerator.h: + * jsc.cpp: + (runWithScripts): + * runtime/Options.h: + +2012-11-28 Mark Hahnenberg <mhahnenberg@apple.com> + + Copying phase should use work lists + https://bugs.webkit.org/show_bug.cgi?id=101390 + + Reviewed by Filip Pizlo. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/BlockAllocator.cpp: + (JSC::BlockAllocator::BlockAllocator): + * heap/BlockAllocator.h: New RegionSet for CopyWorkListSegments. + (BlockAllocator): + (JSC::CopyWorkListSegment): + * heap/CopiedBlock.h: Added a per-block CopyWorkList to keep track of the JSCells that need to be revisited during the copying + phase to copy their backing stores. + (CopiedBlock): + (JSC::CopiedBlock::CopiedBlock): + (JSC::CopiedBlock::didSurviveGC): + (JSC::CopiedBlock::didEvacuateBytes): There is now a one-to-one relationship between GCThreads and the CopiedBlocks they're + responsible for evacuating, we no longer need any of that fancy compare and swap stuff. + (JSC::CopiedBlock::pin): + (JSC::CopiedBlock::hasWorkList): + (JSC::CopiedBlock::workList): + * heap/CopiedBlockInlines.h: Added. + (JSC::CopiedBlock::reportLiveBytes): Since we now have to grab a SpinLock to perform operations on the CopyWorkList during marking, + we don't need to do any of that fancy compare and swap stuff we were doing for tracking live bytes. + * heap/CopiedSpace.h: + (CopiedSpace): + * heap/CopiedSpaceInlines.h: + (JSC::CopiedSpace::pin): + * heap/CopyVisitor.cpp: + (JSC::CopyVisitor::copyFromShared): We now iterate over a range of CopiedBlocks rather than MarkedBlocks and revisit the cells in those + blocks' CopyWorkLists. + * heap/CopyVisitor.h: + (CopyVisitor): + * heap/CopyVisitorInlines.h: + (JSC::CopyVisitor::visitCell): The function responsible for calling the correct copyBackingStore() function for each JSCell from + a CopiedBlock's CopyWorkList. + (JSC::CopyVisitor::didCopy): We no longer need to check if the block is empty here because we know exactly when we're done + evacuating a CopiedBlock, which is when we've gone through all of the CopiedBlock's CopyWorkList. + * heap/CopyWorkList.h: Added. + (CopyWorkListSegment): Individual chunk of a CopyWorkList that is allocated from the BlockAllocator. + (JSC::CopyWorkListSegment::create): + (JSC::CopyWorkListSegment::size): + (JSC::CopyWorkListSegment::isFull): + (JSC::CopyWorkListSegment::get): + (JSC::CopyWorkListSegment::append): + (JSC::CopyWorkListSegment::CopyWorkListSegment): + (JSC::CopyWorkListSegment::data): + (JSC::CopyWorkListSegment::endOfBlock): + (CopyWorkListIterator): Responsible for giving CopyVisitors a contiguous notion of access across the separate CopyWorkListSegments + that make up each CopyWorkList. + (JSC::CopyWorkListIterator::get): + (JSC::CopyWorkListIterator::operator*): + (JSC::CopyWorkListIterator::operator->): + (JSC::CopyWorkListIterator::operator++): + (JSC::CopyWorkListIterator::operator==): + (JSC::CopyWorkListIterator::operator!=): + (JSC::CopyWorkListIterator::CopyWorkListIterator): + (CopyWorkList): Data structure that keeps track of the JSCells that need copying in a particular CopiedBlock. + (JSC::CopyWorkList::CopyWorkList): + (JSC::CopyWorkList::~CopyWorkList): + (JSC::CopyWorkList::append): + (JSC::CopyWorkList::begin): + (JSC::CopyWorkList::end): + * heap/GCThreadSharedData.cpp: + (JSC::GCThreadSharedData::GCThreadSharedData): We no longer use the m_blockSnapshot from the Heap during the copying phase. + (JSC::GCThreadSharedData::didStartCopying): We now copy the set of all blocks in the CopiedSpace to a separate vector for + iterating over during the copying phase since the set stored in the CopiedSpace will change as blocks are evacuated and + recycled throughout the copying phase. + * heap/GCThreadSharedData.h: + (GCThreadSharedData): + * heap/Heap.h: + (Heap): + * heap/SlotVisitor.h: We now need to know the object who is being marked that has a backing store so that we can store it + in a CopyWorkList to revisit later during the copying phase. + * heap/SlotVisitorInlines.h: + (JSC::SlotVisitor::copyLater): + * runtime/JSObject.cpp: + (JSC::JSObject::visitButterfly): + +2012-11-28 Filip Pizlo <fpizlo@apple.com> + + Disassembly methods should be able to disassemble to any PrintStream& rather than always using WTF::dataFile() + https://bugs.webkit.org/show_bug.cgi?id=103492 + + Reviewed by Mark Hahnenberg. + + Switched disassembly code to use PrintStream&, and to use print() rather than printf(). + + * dfg/DFGDisassembler.cpp: + (JSC::DFG::Disassembler::dump): + (DFG): + (JSC::DFG::Disassembler::dumpDisassembly): + * dfg/DFGDisassembler.h: + (Disassembler): + * dfg/DFGGraph.cpp: + (JSC::DFG::printWhiteSpace): + (JSC::DFG::Graph::dumpCodeOrigin): + (JSC::DFG::Graph::printNodeWhiteSpace): + (JSC::DFG::Graph::dump): + (DFG): + (JSC::DFG::Graph::dumpBlockHeader): + * dfg/DFGGraph.h: + (Graph): + * jit/JITDisassembler.cpp: + (JSC::JITDisassembler::dump): + (JSC::JITDisassembler::dumpForInstructions): + (JSC::JITDisassembler::dumpDisassembly): + * jit/JITDisassembler.h: + (JITDisassembler): + +2012-11-28 Filip Pizlo <fpizlo@apple.com> + + It should be possible to say dataLog("count = ", count, "\n") instead of dataLogF("count = %d\n", count) + https://bugs.webkit.org/show_bug.cgi?id=103009 + + Reviewed by Michael Saboff. + + Instead of converting all of JSC to use the new dataLog()/print() methods, I just changed + one place: dumping of abstract values. This is mainly just to ensure that the code I + added to WTF is actually doing things. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::dump): + (WTF): + (WTF::printInternal): + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::dump): + (WTF): + (WTF::printInternal): + +2012-11-28 Oliver Hunt <oliver@apple.com> + + Make source cache include more information about the function extent. + https://bugs.webkit.org/show_bug.cgi?id=103552 + + Reviewed by Gavin Barraclough. + + Add a bit more information to the source cache. + + * parser/Parser.cpp: + (JSC::::parseFunctionInfo): + Store the function start offset + * parser/SourceProviderCacheItem.h: + (JSC::SourceProviderCacheItem::SourceProviderCacheItem): + (SourceProviderCacheItem): + Add additional field for the start of the real function string, and re-arrange + fields to avoid growing the struct. + +2012-11-27 Filip Pizlo <fpizlo@apple.com> + + Convert some remaining uses of FILE* to PrintStream&. + + Rubber stamped by Mark Hahnenberg. + + * bytecode/ValueProfile.h: + (JSC::ValueProfileBase::dump): + * bytecode/ValueRecovery.h: + (JSC::ValueRecovery::dump): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * dfg/DFGNode.h: + (JSC::DFG::Node::dumpChildren): + +2012-11-27 Filip Pizlo <fpizlo@apple.com> + + Fix indentation in JSValue.h + + Rubber stamped by Mark Hahnenberg. + + * runtime/JSValue.h: + +2012-11-26 Filip Pizlo <fpizlo@apple.com> + + DFG SetLocal should use forwardSpeculationCheck instead of its own half-baked version of same + https://bugs.webkit.org/show_bug.cgi?id=103353 + + Reviewed by Oliver Hunt and Gavin Barraclough. + + Made it possible to use forward speculations for most of the operand classes. Changed the conditional + direction parameter from being 'bool isForward' to an enum (SpeculationDirection). Changed SetLocal + to use forward speculations and got rid of its half-baked version of same. + + Also added the ability to force the DFG's disassembler to dump all nodes, even ones that are dead. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGDisassembler.cpp: + (JSC::DFG::Disassembler::dump): + * dfg/DFGDriver.cpp: + (JSC::DFG::compile): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::speculationCheck): + (DFG): + (JSC::DFG::SpeculativeJIT::convertLastOSRExitToForward): + (JSC::DFG::SpeculativeJIT::speculationWatchpoint): + (JSC::DFG::SpeculativeJIT::terminateSpeculativeExecution): + (JSC::DFG::SpeculativeJIT::fillStorage): + * dfg/DFGSpeculativeJIT.h: + (SpeculativeJIT): + (JSC::DFG::SpeculateIntegerOperand::SpeculateIntegerOperand): + (JSC::DFG::SpeculateIntegerOperand::gpr): + (SpeculateIntegerOperand): + (JSC::DFG::SpeculateDoubleOperand::SpeculateDoubleOperand): + (JSC::DFG::SpeculateDoubleOperand::fpr): + (SpeculateDoubleOperand): + (JSC::DFG::SpeculateCellOperand::SpeculateCellOperand): + (JSC::DFG::SpeculateCellOperand::gpr): + (SpeculateCellOperand): + (JSC::DFG::SpeculateBooleanOperand::SpeculateBooleanOperand): + (JSC::DFG::SpeculateBooleanOperand::gpr): + (SpeculateBooleanOperand): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt): + (JSC::DFG::SpeculativeJIT::fillSpeculateIntStrict): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt): + (JSC::DFG::SpeculativeJIT::fillSpeculateIntStrict): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compile): + * runtime/Options.h: + (JSC): + +2012-11-26 Daniel Bates <dbates@webkit.org> + + Substitute "allSeparators8Bit" for "allSeperators8Bit" in JSC::jsSpliceSubstringsWithSeparators() + <https://bugs.webkit.org/show_bug.cgi?id=103303> + + Reviewed by Simon Fraser. + + Fix misspelled word, "Seperators" [sic], in a local variable name in JSC::jsSpliceSubstringsWithSeparators(). + + * runtime/StringPrototype.cpp: + (JSC::jsSpliceSubstringsWithSeparators): + +2012-11-26 Daniel Bates <dbates@webkit.org> + + JavaScript fails to handle String.replace() with large replacement string + https://bugs.webkit.org/show_bug.cgi?id=102956 + <rdar://problem/12738012> + + Reviewed by Oliver Hunt. + + Fix an issue where we didn't check for overflow when computing the length + of the result of String.replace() with a large replacement string. + + * runtime/StringPrototype.cpp: + (JSC::jsSpliceSubstringsWithSeparators): + +2012-11-26 Zeno Albisser <zeno@webkit.org> + + [Qt] Fix the LLInt build on Mac + https://bugs.webkit.org/show_bug.cgi?id=97587 + + Reviewed by Simon Hausmann. + + * DerivedSources.pri: + * JavaScriptCore.pro: + +2012-11-26 Oliver Hunt <oliver@apple.com> + + 32-bit build fix. Move the method decalration outside of the X86_64 only section. + + * assembler/MacroAssembler.h: + (MacroAssembler): + (JSC::MacroAssembler::shouldConsiderBlinding): + +2012-11-26 Oliver Hunt <oliver@apple.com> + + Don't blind all the things. + https://bugs.webkit.org/show_bug.cgi?id=102572 + + Reviewed by Gavin Barraclough. + + No longer blind all the constants in the instruction stream. We use a + simple non-deterministic filter to avoid blinding everything. Also modified + the basic integer blinding logic to avoid blinding small negative values. + + * assembler/MacroAssembler.h: + (MacroAssembler): + (JSC::MacroAssembler::shouldConsiderBlinding): + (JSC::MacroAssembler::shouldBlind): + +2012-11-26 Mark Hahnenberg <mhahnenberg@apple.com> + + JSObject::copyButterfly doesn't handle undecided indexing types correctly + https://bugs.webkit.org/show_bug.cgi?id=102573 + + Reviewed by Filip Pizlo. + + We don't do any copying into the newly allocated vector and we don't zero-initialize CopiedBlocks + during the copying phase, so we end up with uninitialized memory in arrays which have undecided indexing + types. We should just do the actual memcpy from the old block to the new one. + + * runtime/JSObject.cpp: + (JSC::JSObject::copyButterfly): Just do the same thing that we do for other contiguous indexing types. + +2012-11-26 Julien BRIANCEAU <jbrianceau@nds.com> + + [sh4] JavaScriptCore JIT build is broken since r135330 + Add missing implementation for sh4 arch. + https://bugs.webkit.org/show_bug.cgi?id=103145 + + Reviewed by Oliver Hunt. + + * assembler/MacroAssemblerSH4.h: + (JSC::MacroAssemblerSH4::canJumpReplacePatchableBranchPtrWithPatch): + (MacroAssemblerSH4): + (JSC::MacroAssemblerSH4::startOfBranchPtrWithPatchOnRegister): + (JSC::MacroAssemblerSH4::revertJumpReplacementToBranchPtrWithPatch): + (JSC::MacroAssemblerSH4::startOfPatchableBranchPtrWithPatchOnAddress): + (JSC::MacroAssemblerSH4::revertJumpReplacementToPatchableBranchPtrWithPatch): + * assembler/SH4Assembler.h: + (JSC::SH4Assembler::revertJump): + (SH4Assembler): + (JSC::SH4Assembler::printInstr): + +2012-11-26 Yuqiang Xian <yuqiang.xian@intel.com> + + Use load64 instead of loadPtr to load a JSValue on JSVALUE64 platforms + https://bugs.webkit.org/show_bug.cgi?id=100909 + + Reviewed by Brent Fulgham. + + This is a (trivial) fix after r132701. + + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + +2012-11-26 Gabor Ballabas <gaborb@inf.u-szeged.hu> + + [Qt][ARM] REGRESSION(r130826): It made 33 JSC test and 466 layout tests crash + https://bugs.webkit.org/show_bug.cgi?id=98857 + + Reviewed by Zoltan Herczeg. + + Implement a new version of patchableBranch32 to fix crashing JSC + tests. + + * assembler/MacroAssembler.h: + (MacroAssembler): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::patchableBranch32): + (MacroAssemblerARM): + 2012-11-21 Filip Pizlo <fpizlo@apple.com> Any function that can log things should be able to easily log them to a memory buffer as well diff --git a/Source/JavaScriptCore/DerivedSources.pri b/Source/JavaScriptCore/DerivedSources.pri index f9bbbf67c..8bbc29d2a 100644 --- a/Source/JavaScriptCore/DerivedSources.pri +++ b/Source/JavaScriptCore/DerivedSources.pri @@ -102,15 +102,13 @@ for(dir, DIRS) { exists($$file): LLINT_FILES += $$file } -if(linux-*|win32) { - #GENERATOR: LLInt - llint.output = ${QMAKE_FILE_IN_PATH}$${QMAKE_DIR_SEP}LLIntAssembly.h - llint.script = $$PWD/offlineasm/asm.rb - llint.input = LLINT_FILES - llint.depends = $$LLINT_DEPENDENCY - llint.commands = ruby $$llint.script $$LLINT_ASSEMBLER ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} - GENERATORS += llint -} +#GENERATOR: LLInt +llint.output = ${QMAKE_FILE_IN_PATH}$${QMAKE_DIR_SEP}LLIntAssembly.h +llint.script = $$PWD/offlineasm/asm.rb +llint.input = LLINT_FILES +llint.depends = $$LLINT_DEPENDENCY +llint.commands = ruby $$llint.script $$LLINT_ASSEMBLER ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} +GENERATORS += llint linux-*:if(isEqual(QT_ARCH, "i386")|isEqual(QT_ARCH, "x86_64")) { # GENERATOR: disassembler diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index d7afaf18a..c42ee7dfe 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -250,6 +250,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/dfg/DFGValidate.cpp \ Source/JavaScriptCore/dfg/DFGValidate.h \ Source/JavaScriptCore/dfg/DFGVariableAccessData.h \ + Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.cpp \ + Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.h \ Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp \ Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.h \ Source/JavaScriptCore/disassembler/Disassembler.cpp \ diff --git a/Source/JavaScriptCore/JavaScriptCore.pro b/Source/JavaScriptCore/JavaScriptCore.pro index 924261d4f..13130b87f 100644 --- a/Source/JavaScriptCore/JavaScriptCore.pro +++ b/Source/JavaScriptCore/JavaScriptCore.pro @@ -7,18 +7,16 @@ TEMPLATE = subdirs CONFIG += ordered -if(linux-*|win32*) { - LLIntOffsetsExtractor.file = LLIntOffsetsExtractor.pro - LLIntOffsetsExtractor.makefile = Makefile.LLIntOffsetsExtractor - SUBDIRS += LLIntOffsetsExtractor -} +LLIntOffsetsExtractor.file = LLIntOffsetsExtractor.pro +LLIntOffsetsExtractor.makefile = Makefile.LLIntOffsetsExtractor +SUBDIRS += LLIntOffsetsExtractor derived_sources.file = DerivedSources.pri target.file = Target.pri SUBDIRS += derived_sources target -if(linux-*|win32*):addStrictSubdirOrderBetween(LLIntOffsetsExtractor, derived_sources) +addStrictSubdirOrderBetween(LLIntOffsetsExtractor, derived_sources) addStrictSubdirOrderBetween(derived_sources, target) jsc.file = jsc.pro diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index bda9b27ff..a2c4b5f52 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -237,6 +237,8 @@ 0FD82E56141DAF0800179C94 /* DFGOSREntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E52141DAEDE00179C94 /* DFGOSREntry.cpp */; }; 0FD82E57141DAF1000179C94 /* DFGOSREntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E53141DAEDE00179C94 /* DFGOSREntry.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FD82E86141F3FF100179C94 /* SpeculatedType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */; }; + 0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */; }; + 0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; }; 0FEB3ECD16237F4D00AB67AD /* TypedArrayDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEB3ECB16237F4700AB67AD /* TypedArrayDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -721,6 +723,7 @@ C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */; settings = {ATTRIBUTES = (Private, ); }; }; C21122E315DD9AB300790E3A /* MarkStackInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122E015DD9AB300790E3A /* MarkStackInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2160FE715F7E95E00942DFC /* SlotVisitorInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C218D1401655CFD50062BB81 /* CopyWorkList.h in Headers */ = {isa = PBXBuildFile; fileRef = C218D13F1655CFD50062BB81 /* CopyWorkList.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2239D1716262BDD005AC5FD /* CopyVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2239D1216262BDD005AC5FD /* CopyVisitor.cpp */; }; C2239D1816262BDD005AC5FD /* CopyVisitor.h in Headers */ = {isa = PBXBuildFile; fileRef = C2239D1316262BDD005AC5FD /* CopyVisitor.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2239D1916262BDD005AC5FD /* CopyVisitorInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2239D1416262BDD005AC5FD /* CopyVisitorInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -744,6 +747,7 @@ C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E526BC1590EF000054E48D /* HeapTimer.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2EAA3FA149A835E00FCE112 /* CopiedSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EAA3F8149A830800FCE112 /* CopiedSpace.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2EAD2FC14F0249800A4B159 /* CopiedAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EAD2FB14F0249800A4B159 /* CopiedAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C2FC9BD316644DFB00810D33 /* CopiedBlockInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2FC9BD216644DFB00810D33 /* CopiedBlockInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; DDF7ABD411F60ED200108E36 /* GCActivityCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = DDF7ABD211F60ED200108E36 /* GCActivityCallback.h */; settings = {ATTRIBUTES = (Private, ); }; }; E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */ = {isa = PBXBuildFile; fileRef = E124A8F50E555775003091F1 /* OpaqueJSString.h */; settings = {ATTRIBUTES = (Private, ); }; }; E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E124A8F60E555775003091F1 /* OpaqueJSString.cpp */; }; @@ -1034,6 +1038,8 @@ 0FD82E52141DAEDE00179C94 /* DFGOSREntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSREntry.cpp; path = dfg/DFGOSREntry.cpp; sourceTree = "<group>"; }; 0FD82E53141DAEDE00179C94 /* DFGOSREntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSREntry.h; path = dfg/DFGOSREntry.h; sourceTree = "<group>"; }; 0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpeculatedType.cpp; sourceTree = "<group>"; }; + 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessDataDump.cpp; path = dfg/DFGVariableAccessDataDump.cpp; sourceTree = "<group>"; }; + 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessDataDump.h; path = dfg/DFGVariableAccessDataDump.h; sourceTree = "<group>"; }; 0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; }; 0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; }; 0FEB3ECB16237F4700AB67AD /* TypedArrayDescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypedArrayDescriptor.h; sourceTree = "<group>"; }; @@ -1518,6 +1524,7 @@ C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCThreadSharedData.cpp; sourceTree = "<group>"; }; C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCThreadSharedData.h; sourceTree = "<group>"; }; C21122E015DD9AB300790E3A /* MarkStackInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStackInlines.h; sourceTree = "<group>"; }; + C218D13F1655CFD50062BB81 /* CopyWorkList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyWorkList.h; sourceTree = "<group>"; }; C2239D1216262BDD005AC5FD /* CopyVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopyVisitor.cpp; sourceTree = "<group>"; }; C2239D1316262BDD005AC5FD /* CopyVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyVisitor.h; sourceTree = "<group>"; }; C2239D1416262BDD005AC5FD /* CopyVisitorInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyVisitorInlines.h; sourceTree = "<group>"; }; @@ -1540,6 +1547,7 @@ C2E526BC1590EF000054E48D /* HeapTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapTimer.h; sourceTree = "<group>"; }; C2EAA3F8149A830800FCE112 /* CopiedSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedSpace.h; sourceTree = "<group>"; }; C2EAD2FB14F0249800A4B159 /* CopiedAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedAllocator.h; sourceTree = "<group>"; }; + C2FC9BD216644DFB00810D33 /* CopiedBlockInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedBlockInlines.h; sourceTree = "<group>"; }; D21202280AD4310C00ED79B6 /* DateConversion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateConversion.cpp; sourceTree = "<group>"; }; D21202290AD4310C00ED79B6 /* DateConversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateConversion.h; sourceTree = "<group>"; }; DDF7ABD211F60ED200108E36 /* GCActivityCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCActivityCallback.h; sourceTree = "<group>"; }; @@ -1936,6 +1944,8 @@ 14150132154BB13F005D8C98 /* WeakSetInlines.h */, 0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */, 0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */, + C218D13F1655CFD50062BB81 /* CopyWorkList.h */, + C2FC9BD216644DFB00810D33 /* CopiedBlockInlines.h */, ); path = heap; sourceTree = "<group>"; @@ -2464,6 +2474,8 @@ 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */, 0F2BDC401522801700CD8910 /* DFGValueSource.h */, 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */, + 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */, + 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */, 0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */, 0F2BDC411522801700CD8910 /* DFGVariableEvent.h */, 0F2BDC421522801700CD8910 /* DFGVariableEventStream.cpp */, @@ -2638,6 +2650,8 @@ 86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */, C2EAD2FC14F0249800A4B159 /* CopiedAllocator.h in Headers */, C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */, + C218D1401655CFD50062BB81 /* CopyWorkList.h in Headers */, + C2FC9BD316644DFB00810D33 /* CopiedBlockInlines.h in Headers */, FE4A332015BD2E07006F54F3 /* VMInspector.h in Headers */, C2239D1816262BDD005AC5FD /* CopyVisitor.h in Headers */, C2239D1916262BDD005AC5FD /* CopyVisitorInlines.h in Headers */, @@ -3039,6 +3053,7 @@ A77F1825164192C700640A47 /* ParserModes.h in Headers */, 0FAF7EFE165BA91F000C8455 /* JITDisassembler.h in Headers */, 0F73D7AF165A143000ACAB71 /* ClosureCallStubRoutine.h in Headers */, + 0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3621,6 +3636,7 @@ 0FAF7EFD165BA91B000C8455 /* JITDisassembler.cpp in Sources */, 0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */, 0F9D3370165DBB90005AD387 /* Disassembler.cpp in Sources */, + 0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri index e15b21dae..e1caa725f 100644 --- a/Source/JavaScriptCore/Target.pri +++ b/Source/JavaScriptCore/Target.pri @@ -136,6 +136,7 @@ SOURCES += \ dfg/DFGStructureCheckHoistingPhase.cpp \ dfg/DFGThunks.cpp \ dfg/DFGValueSource.cpp \ + dfg/DFGVariableAccessDataDump.cpp \ dfg/DFGVariableEvent.cpp \ dfg/DFGVariableEventStream.cpp \ dfg/DFGValidate.cpp \ diff --git a/Source/JavaScriptCore/assembler/MacroAssembler.h b/Source/JavaScriptCore/assembler/MacroAssembler.h index 642b5ca6b..3d57340f9 100644 --- a/Source/JavaScriptCore/assembler/MacroAssembler.h +++ b/Source/JavaScriptCore/assembler/MacroAssembler.h @@ -266,12 +266,14 @@ public: { return PatchableJump(branchTest32(cond, reg, mask)); } - +#endif // !CPU(ARM_THUMB2) + +#if !CPU(ARM) PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm) { return PatchableJump(branch32(cond, reg, imm)); } -#endif +#endif // !(CPU(ARM) void jump(Label target) { @@ -306,7 +308,12 @@ public: ASSERT(condition == Equal || condition == NotEqual); return condition; } - + + static const unsigned BlindingModulus = 64; + bool shouldConsiderBlinding() + { + return !(random() & (BlindingModulus - 1)); + } // Ptr methods // On 32-bit platforms (i.e. x86), these methods directly map onto their 32-bit equivalents. @@ -837,26 +844,25 @@ public: using MacroAssemblerBase::and64; using MacroAssemblerBase::convertInt32ToDouble; using MacroAssemblerBase::store64; - bool shouldBlindDouble(double value) { // Don't trust NaN or +/-Infinity if (!isfinite(value)) - return true; + return shouldConsiderBlinding(); // Try to force normalisation, and check that there's no change // in the bit pattern if (bitwise_cast<uint64_t>(value * 1.0) != bitwise_cast<uint64_t>(value)) - return true; + return shouldConsiderBlinding(); value = abs(value); // Only allow a limited set of fractional components double scaledValue = value * 8; if (scaledValue / 8 != value) - return true; + return shouldConsiderBlinding(); double frac = scaledValue - floor(scaledValue); if (frac != 0.0) - return true; + return shouldConsiderBlinding(); return value > 0xff; } @@ -885,8 +891,14 @@ public: default: { if (value <= 0xff) return false; + if (~value <= 0xff) + return false; } } + + if (!shouldConsiderBlinding()) + return false; + return shouldBlindForSpecificArch(value); } @@ -938,6 +950,9 @@ public: default: { if (value <= 0xff) return false; + if (~value <= 0xff) + return false; + JSValue jsValue = JSValue::decode(value); if (jsValue.isInt32()) return shouldBlind(Imm32(jsValue.asInt32())); @@ -948,6 +963,10 @@ public: return false; } } + + if (!shouldConsiderBlinding()) + return false; + return shouldBlindForSpecificArch(value); } @@ -1066,7 +1085,13 @@ public: default: if (value <= 0xff) return false; + if (~value <= 0xff) + return false; } + + if (!shouldConsiderBlinding()) + return false; + return shouldBlindForSpecificArch(value); #endif } diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h index 9c77e9349..e6b5ad383 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h @@ -570,11 +570,7 @@ public: Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0) { - ARMWord tmp = (static_cast<unsigned>(right.m_value) == 0x80000000) ? ARMAssembler::InvalidImmediate : m_assembler.getOp2(-right.m_value); - if (tmp != ARMAssembler::InvalidImmediate) - m_assembler.cmn(left, tmp); - else - m_assembler.cmp(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); + internalCompare32(left, right); return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); } @@ -807,6 +803,14 @@ public: return Jump(m_assembler.jmp(ARMCondition(cond))); } + PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm) + { + internalCompare32(reg, imm); + Jump jump(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMCondition(cond), true)); + m_assembler.bx(ARMRegisters::S1, ARMCondition(cond)); + return PatchableJump(jump); + } + void breakpoint() { m_assembler.bkpt(0); @@ -1320,6 +1324,15 @@ private: friend class LinkBuffer; friend class RepatchBuffer; + void internalCompare32(RegisterID left, TrustedImm32 right) + { + ARMWord tmp = (static_cast<unsigned>(right.m_value) == 0x80000000) ? ARMAssembler::InvalidImmediate : m_assembler.getOp2(-right.m_value); + if (tmp != ARMAssembler::InvalidImmediate) + m_assembler.cmn(left, tmp); + else + m_assembler.cmp(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); + } + static void linkCall(void* code, Call call, FunctionPtr function) { ARMAssembler::linkCall(code, call.m_label, function.value()); diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h b/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h index b6f3e6d57..ec025cec3 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h @@ -2216,6 +2216,29 @@ void or32(TrustedImm32 imm, RegisterID src, RegisterID dest) return 0; } + static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; } + + static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label) + { + return label.labelAtOffset(0); + } + + static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue) + { + SH4Assembler::revertJump(instructionStart.dataLocation(), reinterpret_cast<uintptr_t>(initialValue) & 0xffff); + } + + static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr) + { + UNREACHABLE_FOR_PLATFORM(); + return CodeLocationLabel(); + } + + static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue) + { + UNREACHABLE_FOR_PLATFORM(); + } + protected: SH4Assembler::Condition SH4Condition(RelationalCondition cond) { diff --git a/Source/JavaScriptCore/assembler/SH4Assembler.h b/Source/JavaScriptCore/assembler/SH4Assembler.h index 2cd0aa82e..39f5585be 100644 --- a/Source/JavaScriptCore/assembler/SH4Assembler.h +++ b/Source/JavaScriptCore/assembler/SH4Assembler.h @@ -1462,6 +1462,20 @@ public: // Linking & patching + static void revertJump(void* instructionStart, SH4Word imm) + { + SH4Word *insn = reinterpret_cast<SH4Word*>(instructionStart); + SH4Word disp; + + ASSERT((insn[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); + + disp = insn[0] & 0x00ff; + insn += 2 + (disp << 1); // PC += 4 + (disp*4) + insn = (SH4Word *) ((unsigned) insn & (~3)); + insn[0] = imm; + cacheFlush(insn, sizeof(SH4Word)); + } + void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type = JumpFar) { ASSERT(to.isSet()); @@ -1755,6 +1769,9 @@ public: case FCNVDS_DRM_FPUL_OPCODE: format = " FCNVDS FR%d, FPUL\n"; break; + case FCNVSD_FPUL_DRN_OPCODE: + format = " FCNVSD FPUL, FR%d\n"; + break; } if (format) { if (isdoubleInst) diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 206d281a2..6e1edaa0e 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -497,7 +497,7 @@ void CodeBlock::dump() static_cast<unsigned long>(instructions().size() * sizeof(Instruction)), this, codeTypeToString(codeType()), m_numParameters, m_numCalleeRegisters, m_numVars); - if (symbolTable()->captureCount()) + if (symbolTable() && symbolTable()->captureCount()) dataLogF("; %d captured var(s)", symbolTable()->captureCount()); if (usesArguments()) { dataLogF( @@ -1891,7 +1891,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin } m_instructions = WTF::RefCountedArray<Instruction>(instructions); - if (BytecodeGenerator::dumpsGeneratedCode()) + if (Options::dumpGeneratedBytecodes()) dump(); m_globalData->finishedCompiling(this); } diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.cpp b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp index 399ab29c8..a07ca2b22 100644 --- a/Source/JavaScriptCore/bytecode/SpeculatedType.cpp +++ b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp @@ -34,144 +34,143 @@ #include "JSFunction.h" #include "ValueProfile.h" #include <wtf/BoundsCheckedPointer.h> +#include <wtf/StringPrintStream.h> namespace JSC { -const char* speculationToString(SpeculatedType value) +void dumpSpeculation(PrintStream& out, SpeculatedType value) { - if (value == SpecNone) - return "None"; + if (value == SpecNone) { + out.print("None"); + return; + } - static const int size = 256; - static char description[size]; - BoundsCheckedPointer<char> ptr(description, size); + StringPrintStream myOut; bool isTop = true; if (value & SpecCellOther) - ptr.strcat("Othercell"); + myOut.print("Othercell"); else isTop = false; if (value & SpecObjectOther) - ptr.strcat("Otherobj"); + myOut.print("Otherobj"); else isTop = false; if (value & SpecFinalObject) - ptr.strcat("Final"); + myOut.print("Final"); else isTop = false; if (value & SpecArray) - ptr.strcat("Array"); + myOut.print("Array"); else isTop = false; if (value & SpecInt8Array) - ptr.strcat("Int8array"); + myOut.print("Int8array"); else isTop = false; if (value & SpecInt16Array) - ptr.strcat("Int16array"); + myOut.print("Int16array"); else isTop = false; if (value & SpecInt32Array) - ptr.strcat("Int32array"); + myOut.print("Int32array"); else isTop = false; if (value & SpecUint8Array) - ptr.strcat("Uint8array"); + myOut.print("Uint8array"); else isTop = false; if (value & SpecUint8ClampedArray) - ptr.strcat("Uint8clampedarray"); + myOut.print("Uint8clampedarray"); else isTop = false; if (value & SpecUint16Array) - ptr.strcat("Uint16array"); + myOut.print("Uint16array"); else isTop = false; if (value & SpecUint32Array) - ptr.strcat("Uint32array"); + myOut.print("Uint32array"); else isTop = false; if (value & SpecFloat32Array) - ptr.strcat("Float32array"); + myOut.print("Float32array"); else isTop = false; if (value & SpecFloat64Array) - ptr.strcat("Float64array"); + myOut.print("Float64array"); else isTop = false; if (value & SpecFunction) - ptr.strcat("Function"); + myOut.print("Function"); else isTop = false; if (value & SpecMyArguments) - ptr.strcat("Myarguments"); + myOut.print("Myarguments"); else isTop = false; if (value & SpecForeignArguments) - ptr.strcat("Foreignarguments"); + myOut.print("Foreignarguments"); else isTop = false; if (value & SpecString) - ptr.strcat("String"); + myOut.print("String"); else isTop = false; if (value & SpecInt32) - ptr.strcat("Int"); + myOut.print("Int"); else isTop = false; if (value & SpecDoubleReal) - ptr.strcat("Doublereal"); + myOut.print("Doublereal"); else isTop = false; if (value & SpecDoubleNaN) - ptr.strcat("Doublenan"); + myOut.print("Doublenan"); else isTop = false; if (value & SpecBoolean) - ptr.strcat("Bool"); + myOut.print("Bool"); else isTop = false; if (value & SpecOther) - ptr.strcat("Other"); + myOut.print("Other"); else isTop = false; - if (isTop) { - ptr = description; - ptr.strcat("Top"); - } + if (isTop) + out.print("Top"); + else + out.print(myOut.toCString()); if (value & SpecEmpty) - ptr.strcat("Empty"); - - *ptr++ = 0; - - return description; + out.print("Empty"); } -const char* speculationToAbbreviatedString(SpeculatedType prediction) +// We don't expose this because we don't want anyone relying on the fact that this method currently +// just returns string constants. +static const char* speculationToAbbreviatedString(SpeculatedType prediction) { if (isFinalObjectSpeculation(prediction)) return "<Final>"; @@ -218,6 +217,11 @@ const char* speculationToAbbreviatedString(SpeculatedType prediction) return ""; } +void dumpSpeculationAbbreviated(PrintStream& out, SpeculatedType value) +{ + out.print(speculationToAbbreviatedString(value)); +} + SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo) { if (classInfo == &JSFinalObject::s_info) diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h index 656bc79ee..261a26b0e 100644 --- a/Source/JavaScriptCore/bytecode/SpeculatedType.h +++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h @@ -289,8 +289,11 @@ inline bool isEmptySpeculation(SpeculatedType value) return value == SpecEmpty; } -const char* speculationToString(SpeculatedType value); -const char* speculationToAbbreviatedString(SpeculatedType value); +void dumpSpeculation(PrintStream&, SpeculatedType); +void dumpSpeculationAbbreviated(PrintStream&, SpeculatedType); + +MAKE_PRINT_ADAPTOR(SpeculationDump, SpeculatedType, dumpSpeculation); +MAKE_PRINT_ADAPTOR(AbbreviatedSpeculationDump, SpeculatedType, dumpSpeculationAbbreviated); // Merge two predictions. Note that currently this just does left | right. It may // seem tempting to do so directly, but you would be doing so at your own peril, diff --git a/Source/JavaScriptCore/bytecode/ValueProfile.h b/Source/JavaScriptCore/bytecode/ValueProfile.h index 31e76842f..e56e6eb6e 100644 --- a/Source/JavaScriptCore/bytecode/ValueProfile.h +++ b/Source/JavaScriptCore/bytecode/ValueProfile.h @@ -38,6 +38,7 @@ #include "SpeculatedType.h" #include "Structure.h" #include "WriteBarrier.h" +#include <wtf/PrintStream.h> namespace JSC { @@ -109,27 +110,24 @@ struct ValueProfileBase { return false; } - void dump(FILE* out) + void dump(PrintStream& out) { - fprintf(out, - "samples = %u, prediction = %s", - totalNumberOfSamples(), - speculationToString(m_prediction)); - fprintf(out, ", value = "); + out.print("samples = ", totalNumberOfSamples(), " prediction = ", SpeculationDump(m_prediction)); + out.printf(", value = "); if (m_singletonValueIsTop) - fprintf(out, "TOP"); + out.printf("TOP"); else - fprintf(out, "%s", m_singletonValue.description()); + out.printf("%s", m_singletonValue.description()); bool first = true; for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { JSValue value = JSValue::decode(m_buckets[i]); if (!!value) { if (first) { - fprintf(out, ": "); + out.printf(": "); first = false; } else - fprintf(out, ", "); - fprintf(out, "%s", value.description()); + out.printf(", "); + out.printf("%s", value.description()); } } } diff --git a/Source/JavaScriptCore/bytecode/ValueRecovery.h b/Source/JavaScriptCore/bytecode/ValueRecovery.h index 93ad221d8..fc991a413 100644 --- a/Source/JavaScriptCore/bytecode/ValueRecovery.h +++ b/Source/JavaScriptCore/bytecode/ValueRecovery.h @@ -274,70 +274,70 @@ public: return JSValue::decode(m_source.constant); } - void dump(FILE* out) const + void dump(PrintStream& out) const { switch (technique()) { case AlreadyInJSStack: - fprintf(out, "-"); + out.printf("-"); break; case AlreadyInJSStackAsUnboxedInt32: - fprintf(out, "(int32)"); + out.printf("(int32)"); break; case AlreadyInJSStackAsUnboxedCell: - fprintf(out, "(cell)"); + out.printf("(cell)"); break; case AlreadyInJSStackAsUnboxedBoolean: - fprintf(out, "(bool)"); + out.printf("(bool)"); break; case AlreadyInJSStackAsUnboxedDouble: - fprintf(out, "(double)"); + out.printf("(double)"); break; case InGPR: - fprintf(out, "%%r%d", gpr()); + out.printf("%%r%d", gpr()); break; case UnboxedInt32InGPR: - fprintf(out, "int32(%%r%d)", gpr()); + out.printf("int32(%%r%d)", gpr()); break; case UnboxedBooleanInGPR: - fprintf(out, "bool(%%r%d)", gpr()); + out.printf("bool(%%r%d)", gpr()); break; case UInt32InGPR: - fprintf(out, "uint32(%%r%d)", gpr()); + out.printf("uint32(%%r%d)", gpr()); break; case InFPR: - fprintf(out, "%%fr%d", fpr()); + out.printf("%%fr%d", fpr()); break; #if USE(JSVALUE32_64) case InPair: - fprintf(out, "pair(%%r%d, %%r%d)", tagGPR(), payloadGPR()); + out.printf("pair(%%r%d, %%r%d)", tagGPR(), payloadGPR()); break; #endif case DisplacedInJSStack: - fprintf(out, "*%d", virtualRegister()); + out.printf("*%d", virtualRegister()); break; case Int32DisplacedInJSStack: - fprintf(out, "*int32(%d)", virtualRegister()); + out.printf("*int32(%d)", virtualRegister()); break; case DoubleDisplacedInJSStack: - fprintf(out, "*double(%d)", virtualRegister()); + out.printf("*double(%d)", virtualRegister()); break; case CellDisplacedInJSStack: - fprintf(out, "*cell(%d)", virtualRegister()); + out.printf("*cell(%d)", virtualRegister()); break; case BooleanDisplacedInJSStack: - fprintf(out, "*bool(%d)", virtualRegister()); + out.printf("*bool(%d)", virtualRegister()); break; case ArgumentsThatWereNotCreated: - fprintf(out, "arguments"); + out.printf("arguments"); break; case Constant: - fprintf(out, "[%s]", constant().description()); + out.printf("[%s]", constant().description()); break; case DontKnow: - fprintf(out, "!"); + out.printf("!"); break; default: - fprintf(out, "?%d", technique()); + out.printf("?%d", technique()); break; } } diff --git a/Source/JavaScriptCore/bytecode/VirtualRegister.h b/Source/JavaScriptCore/bytecode/VirtualRegister.h index b95f8b8fa..a6dc8d565 100644 --- a/Source/JavaScriptCore/bytecode/VirtualRegister.h +++ b/Source/JavaScriptCore/bytecode/VirtualRegister.h @@ -27,6 +27,7 @@ #define VirtualRegister_h #include <wtf/Platform.h> +#include <wtf/PrintStream.h> namespace JSC { @@ -37,4 +38,13 @@ COMPILE_ASSERT(sizeof(VirtualRegister) == sizeof(int), VirtualRegister_is_32bit) } // namespace JSC +namespace WTF { + +inline void printInternal(PrintStream& out, JSC::VirtualRegister value) +{ + out.print(static_cast<int>(value)); +} + +} // namespace WTF + #endif // VirtualRegister_h diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index c6f81f3c3..35976257b 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -38,6 +38,7 @@ #include "JSFunction.h" #include "JSNameScope.h" #include "LowLevelInterpreter.h" +#include "Options.h" #include "StrongInlines.h" #include <wtf/text/WTFString.h> @@ -146,18 +147,6 @@ void ResolveResult::checkValidity() } #endif -static bool s_dumpsGeneratedCode = false; - -void BytecodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode) -{ - s_dumpsGeneratedCode = dumpsGeneratedCode; -} - -bool BytecodeGenerator::dumpsGeneratedCode() -{ - return s_dumpsGeneratedCode; -} - ParserError BytecodeGenerator::generate() { SamplingRegion samplingRegion("Bytecode Generation"); diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h index 2e7aa2035..a5bb95b6c 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -209,9 +209,6 @@ namespace JSC { typedef DeclarationStacks::VarStack VarStack; typedef DeclarationStacks::FunctionStack FunctionStack; - JS_EXPORT_PRIVATE static void setDumpsGeneratedCode(bool dumpsGeneratedCode); - static bool dumpsGeneratedCode(); - BytecodeGenerator(JSGlobalData&, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode); BytecodeGenerator(JSGlobalData&, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode); BytecodeGenerator(JSGlobalData&, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode); diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h index fd3220494..0ce01ab56 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h @@ -373,13 +373,12 @@ struct AbstractValue { void dump(PrintStream& out) const { - out.printf("(%s, %s, ", speculationToString(m_type), arrayModesToString(m_arrayModes)); - m_currentKnownStructure.dump(out); - out.printf(", "); - m_futurePossibleStructure.dump(out); + out.print( + "(", SpeculationDump(m_type), ", ", arrayModesToString(m_arrayModes), ", ", + m_currentKnownStructure, ", ", m_futurePossibleStructure); if (!!m_value) - out.printf(", %s", m_value.description()); - out.printf(")"); + out.print(", ", m_value.description()); + out.print(")"); } // A great way to think about the difference between m_currentKnownStructure and diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 9b879b9e3..c5ffb1fc6 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -247,6 +247,17 @@ private: setDirect(m_inlineStackTop->remapOperand(operand), value, setMode); } + void setPair(int operand1, NodeIndex value1, int operand2, NodeIndex value2) + { + // First emit dead SetLocals for the benefit of OSR. + set(operand1, value1); + set(operand2, value2); + + // Now emit the real SetLocals. + set(operand1, value1); + set(operand2, value2); + } + NodeIndex injectLazyOperandSpeculation(NodeIndex nodeIndex) { Node& node = m_graph[nodeIndex]; @@ -256,8 +267,7 @@ private: m_inlineStackTop->m_lazyOperands.prediction( LazyOperandValueProfileKey(m_currentIndex, node.local())); #if DFG_ENABLE(DEBUG_VERBOSE) - dataLogF("Lazy operand [@%u, bc#%u, r%d] prediction: %s\n", - nodeIndex, m_currentIndex, node.local(), speculationToString(prediction)); + dataLog("Lazy operand [@", nodeIndex, ", bc#", m_currentIndex, ", r", node.local(), "] prediction: ", SpeculationDump(prediction), "\n"); #endif node.variableAccessData()->predict(prediction); return nodeIndex; @@ -876,7 +886,7 @@ private: SpeculatedType prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex); #if DFG_ENABLE(DEBUG_VERBOSE) - dataLogF("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, speculationToString(prediction)); + dataLog("Dynamic [@", nodeIndex, ", bc#", bytecodeIndex, "] prediction: ", SpeculationDump(prediction), "\n"); #endif return prediction; @@ -2299,8 +2309,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) unsigned srcDst = currentInstruction[2].u.operand; ASSERT(result != srcDst); // Required for assumptions we make during OSR. NodeIndex op = get(srcDst); - set(result, op); - set(srcDst, makeSafe(addToGraph(ArithAdd, op, one()))); + setPair(result, op, srcDst, makeSafe(addToGraph(ArithAdd, op, one()))); NEXT_OPCODE(op_post_inc); } @@ -2315,8 +2324,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) unsigned result = currentInstruction[1].u.operand; unsigned srcDst = currentInstruction[2].u.operand; NodeIndex op = get(srcDst); - set(result, op); - set(srcDst, makeSafe(addToGraph(ArithSub, op, one()))); + setPair(result, op, srcDst, makeSafe(addToGraph(ArithSub, op, one()))); NEXT_OPCODE(op_post_dec); } @@ -3115,21 +3123,11 @@ bool ByteCodeParser::parseBlock(unsigned limit) NodeIndex base = 0; NodeIndex value = 0; - if (parseResolveOperations(prediction, identifier, operations, putToBaseOperation, &base, &value)) { - // First create OSR hints only. - set(baseDst, base); - set(valueDst, value); - - // If we try to hoist structure checks into here, then we're guaranteed that they will occur - // *after* we have already set up the values for OSR. - - // Then do the real SetLocals. - set(baseDst, base); - set(valueDst, value); - } else { + if (parseResolveOperations(prediction, identifier, operations, putToBaseOperation, &base, &value)) + setPair(baseDst, base, valueDst, value); + else { addToGraph(ForceOSRExit); - set(baseDst, addToGraph(GarbageValue)); - set(valueDst, addToGraph(GarbageValue)); + setPair(baseDst, addToGraph(GarbageValue), valueDst, addToGraph(GarbageValue)); } NEXT_OPCODE(op_resolve_with_base); @@ -3143,21 +3141,11 @@ bool ByteCodeParser::parseBlock(unsigned limit) NodeIndex base = 0; NodeIndex value = 0; - if (parseResolveOperations(prediction, identifier, operations, 0, &base, &value)) { - // First create OSR hints only. - set(baseDst, base); - set(valueDst, value); - - // If we try to hoist structure checks into here, then we're guaranteed that they will occur - // *after* we have already set up the values for OSR. - - // Then do the real SetLocals. - set(baseDst, base); - set(valueDst, value); - } else { + if (parseResolveOperations(prediction, identifier, operations, 0, &base, &value)) + setPair(baseDst, base, valueDst, value); + else { addToGraph(ForceOSRExit); - set(baseDst, addToGraph(GarbageValue)); - set(valueDst, addToGraph(GarbageValue)); + setPair(baseDst, addToGraph(GarbageValue), valueDst, addToGraph(GarbageValue)); } NEXT_OPCODE(op_resolve_with_this); @@ -3664,7 +3652,7 @@ void ByteCodeParser::parseCodeBlock() codeBlock->needsFullScopeChain()?"true":"false", codeBlock->ownerExecutable()->needsActivation()?"true":"false", codeBlock->ownerExecutable()->isStrictMode()?"true":"false"); - codeBlock->baselineVersion()->dump(m_exec); + codeBlock->baselineVersion()->dump(); #endif for (unsigned jumpTargetIndex = 0; jumpTargetIndex <= codeBlock->numberOfJumpTargets(); ++jumpTargetIndex) { diff --git a/Source/JavaScriptCore/dfg/DFGDisassembler.cpp b/Source/JavaScriptCore/dfg/DFGDisassembler.cpp index 654824196..f09b974a5 100644 --- a/Source/JavaScriptCore/dfg/DFGDisassembler.cpp +++ b/Source/JavaScriptCore/dfg/DFGDisassembler.cpp @@ -39,12 +39,12 @@ Disassembler::Disassembler(Graph& graph) m_labelForNodeIndex.resize(graph.size()); } -void Disassembler::dump(LinkBuffer& linkBuffer) +void Disassembler::dump(PrintStream& out, LinkBuffer& linkBuffer) { m_graph.m_dominators.computeIfNecessary(m_graph); - dataLogF("Generated JIT code for DFG CodeBlock %p, instruction count = %u:\n", m_graph.m_codeBlock, m_graph.m_codeBlock->instructionCount()); - dataLogF(" Code at [%p, %p):\n", linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()); + out.print("Generated JIT code for DFG CodeBlock ", RawPointer(m_graph.m_codeBlock), ", instruction count = ", m_graph.m_codeBlock->instructionCount(), ":\n"); + out.print(" Code at [", RawPointer(linkBuffer.debugAddress()), ", ", RawPointer(static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()), "):\n"); const char* prefix = " "; const char* disassemblyPrefix = " "; @@ -55,11 +55,11 @@ void Disassembler::dump(LinkBuffer& linkBuffer) BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block) continue; - dumpDisassembly(disassemblyPrefix, linkBuffer, previousLabel, m_labelForBlockIndex[blockIndex], lastNodeIndex); - m_graph.dumpBlockHeader(prefix, blockIndex, Graph::DumpLivePhisOnly); + dumpDisassembly(out, disassemblyPrefix, linkBuffer, previousLabel, m_labelForBlockIndex[blockIndex], lastNodeIndex); + m_graph.dumpBlockHeader(out, prefix, blockIndex, Graph::DumpLivePhisOnly); NodeIndex lastNodeIndexForDisassembly = block->at(0); for (size_t i = 0; i < block->size(); ++i) { - if (!m_graph[block->at(i)].willHaveCodeGenOrOSR()) + if (!m_graph[block->at(i)].willHaveCodeGenOrOSR() && !Options::showAllDFGNodes()) continue; MacroAssembler::Label currentLabel; if (m_labelForNodeIndex[block->at(i)].isSet()) @@ -74,19 +74,24 @@ void Disassembler::dump(LinkBuffer& linkBuffer) else currentLabel = m_endOfMainPath; } - dumpDisassembly(disassemblyPrefix, linkBuffer, previousLabel, currentLabel, lastNodeIndexForDisassembly); - m_graph.dumpCodeOrigin(prefix, lastNodeIndex, block->at(i)); - m_graph.dump(prefix, block->at(i)); + dumpDisassembly(out, disassemblyPrefix, linkBuffer, previousLabel, currentLabel, lastNodeIndexForDisassembly); + m_graph.dumpCodeOrigin(out, prefix, lastNodeIndex, block->at(i)); + m_graph.dump(out, prefix, block->at(i)); lastNodeIndex = block->at(i); lastNodeIndexForDisassembly = block->at(i); } } - dumpDisassembly(disassemblyPrefix, linkBuffer, previousLabel, m_endOfMainPath, lastNodeIndex); - dataLogF("%s(End Of Main Path)\n", prefix); - dumpDisassembly(disassemblyPrefix, linkBuffer, previousLabel, m_endOfCode, NoNode); + dumpDisassembly(out, disassemblyPrefix, linkBuffer, previousLabel, m_endOfMainPath, lastNodeIndex); + out.print(prefix, "(End Of Main Path)\n"); + dumpDisassembly(out, disassemblyPrefix, linkBuffer, previousLabel, m_endOfCode, NoNode); +} + +void Disassembler::dump(LinkBuffer& linkBuffer) +{ + dump(WTF::dataFile(), linkBuffer); } -void Disassembler::dumpDisassembly(const char* prefix, LinkBuffer& linkBuffer, MacroAssembler::Label& previousLabel, MacroAssembler::Label currentLabel, NodeIndex context) +void Disassembler::dumpDisassembly(PrintStream& out, const char* prefix, LinkBuffer& linkBuffer, MacroAssembler::Label& previousLabel, MacroAssembler::Label currentLabel, NodeIndex context) { size_t prefixLength = strlen(prefix); int amountOfNodeWhiteSpace; @@ -104,7 +109,7 @@ void Disassembler::dumpDisassembly(const char* prefix, LinkBuffer& linkBuffer, M CodeLocationLabel end = linkBuffer.locationOf(currentLabel); previousLabel = currentLabel; ASSERT(bitwise_cast<uintptr_t>(end.executableAddress()) >= bitwise_cast<uintptr_t>(start.executableAddress())); - disassemble(start, bitwise_cast<uintptr_t>(end.executableAddress()) - bitwise_cast<uintptr_t>(start.executableAddress()), prefixBuffer.get(), WTF::dataFile()); + disassemble(start, bitwise_cast<uintptr_t>(end.executableAddress()) - bitwise_cast<uintptr_t>(start.executableAddress()), prefixBuffer.get(), out); } } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGDisassembler.h b/Source/JavaScriptCore/dfg/DFGDisassembler.h index 470a989ef..8cc58c666 100644 --- a/Source/JavaScriptCore/dfg/DFGDisassembler.h +++ b/Source/JavaScriptCore/dfg/DFGDisassembler.h @@ -62,10 +62,11 @@ public: m_endOfCode = label; } + void dump(PrintStream&, LinkBuffer&); void dump(LinkBuffer&); private: - void dumpDisassembly(const char* prefix, LinkBuffer&, MacroAssembler::Label& previousLabel, MacroAssembler::Label currentLabel, NodeIndex context); + void dumpDisassembly(PrintStream&, const char* prefix, LinkBuffer&, MacroAssembler::Label& previousLabel, MacroAssembler::Label currentLabel, NodeIndex context); Graph& m_graph; MacroAssembler::Label m_startOfCode; diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index 19587ba64..270f53b87 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -27,7 +27,7 @@ #include "DFGGraph.h" #include "CodeBlock.h" -#include <wtf/BoundsCheckedPointer.h> +#include "DFGVariableAccessDataDump.h" #if ENABLE(DFG_JIT) @@ -57,51 +57,13 @@ const char *Graph::opName(NodeType op) return dfgOpNames[op]; } -const char* Graph::nameOfVariableAccessData(VariableAccessData* variableAccessData) -{ - // Variables are already numbered. For readability of IR dumps, this returns - // an alphabetic name for the variable access data, so that you don't have to - // reason about two numbers (variable number and live range number), but instead - // a number and a letter. - - unsigned index = std::numeric_limits<unsigned>::max(); - for (unsigned i = 0; i < m_variableAccessData.size(); ++i) { - if (&m_variableAccessData[i] == variableAccessData) { - index = i; - break; - } - } - - ASSERT(index != std::numeric_limits<unsigned>::max()); - - if (!index) - return "A"; - - static char buf[100]; - BoundsCheckedPointer<char> ptr(buf, sizeof(buf)); - - while (index) { - *ptr++ = 'A' + (index % 26); - index /= 26; - } - - if (variableAccessData->isCaptured()) - *ptr++ = '*'; - - ptr.strcat(speculationToAbbreviatedString(variableAccessData->prediction())); - - *ptr++ = 0; - - return buf; -} - -static void printWhiteSpace(unsigned amount) +static void printWhiteSpace(PrintStream& out, unsigned amount) { while (amount-- > 0) - dataLogF(" "); + out.print(" "); } -void Graph::dumpCodeOrigin(const char* prefix, NodeIndex prevNodeIndex, NodeIndex nodeIndex) +void Graph::dumpCodeOrigin(PrintStream& out, const char* prefix, NodeIndex prevNodeIndex, NodeIndex nodeIndex) { if (prevNodeIndex == NoNode) return; @@ -124,16 +86,16 @@ void Graph::dumpCodeOrigin(const char* prefix, NodeIndex prevNodeIndex, NodeInde // Print the pops. for (unsigned i = previousInlineStack.size(); i-- > indexOfDivergence;) { - dataLogF("%s", prefix); - printWhiteSpace(i * 2); - dataLogF("<-- %p\n", previousInlineStack[i].inlineCallFrame->executable.get()); + out.print(prefix); + printWhiteSpace(out, i * 2); + out.print("<-- ", RawPointer(previousInlineStack[i].inlineCallFrame->executable.get()), "\n"); } // Print the pushes. for (unsigned i = indexOfDivergence; i < currentInlineStack.size(); ++i) { - dataLogF("%s", prefix); - printWhiteSpace(i * 2); - dataLogF("--> %p\n", currentInlineStack[i].inlineCallFrame->executable.get()); + out.print(prefix); + printWhiteSpace(out, i * 2); + out.print("--> ", RawPointer(currentInlineStack[i].inlineCallFrame->executable.get()), "\n"); } } @@ -142,12 +104,20 @@ int Graph::amountOfNodeWhiteSpace(Node& node) return (node.codeOrigin.inlineDepth() - 1) * 2; } -void Graph::printNodeWhiteSpace(Node& node) +void Graph::printNodeWhiteSpace(PrintStream& out, Node& node) { - printWhiteSpace(amountOfNodeWhiteSpace(node)); + printWhiteSpace(out, amountOfNodeWhiteSpace(node)); } -void Graph::dump(const char* prefix, NodeIndex nodeIndex) +void Graph::dump(PrintStream& out, Edge edge) +{ + out.print( + useKindToString(edge.useKind()), + "@", edge.index(), + AbbreviatedSpeculationDump(at(edge).prediction())); +} + +void Graph::dump(PrintStream& out, const char* prefix, NodeIndex nodeIndex) { Node& node = at(nodeIndex); NodeType op = node.op(); @@ -157,9 +127,9 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex) bool mustGenerate = node.mustGenerate(); if (mustGenerate) --refCount; - - dataLogF("%s", prefix); - printNodeWhiteSpace(node); + + out.print(prefix); + printNodeWhiteSpace(out, node); // Example/explanation of dataflow dump output // @@ -178,95 +148,84 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex) // $# - the index in the CodeBlock of a constant { for numeric constants the value is displayed | for integers, in both decimal and hex }. // 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. - dataLogF("% 4d:%s<%c%u:", (int)nodeIndex, skipped ? " skipped " : " ", mustGenerate ? '!' : ' ', refCount); + out.printf("% 4d:%s<%c%u:", (int)nodeIndex, skipped ? " skipped " : " ", mustGenerate ? '!' : ' ', refCount); if (node.hasResult() && !skipped && node.hasVirtualRegister()) - dataLogF("%u", node.virtualRegister()); + out.print(node.virtualRegister()); else - dataLogF("-"); - dataLogF(">\t%s(", opName(op)); + out.print("-"); + out.print(">\t", opName(op), "("); bool hasPrinted = false; if (node.flags() & NodeHasVarArgs) { for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++) { if (hasPrinted) - dataLogF(", "); + out.print(", "); else hasPrinted = true; if (!m_varArgChildren[childIdx]) continue; - dataLogF("%s@%u%s", - useKindToString(m_varArgChildren[childIdx].useKind()), - m_varArgChildren[childIdx].index(), - speculationToAbbreviatedString( - at(m_varArgChildren[childIdx]).prediction())); + dump(out, m_varArgChildren[childIdx]); } } else { if (!!node.child1()) { - dataLogF("%s@%u%s", - useKindToString(node.child1().useKind()), - node.child1().index(), - speculationToAbbreviatedString(at(node.child1()).prediction())); + dump(out, node.child1()); + hasPrinted = true; } if (!!node.child2()) { - dataLogF(", %s@%u%s", - useKindToString(node.child2().useKind()), - node.child2().index(), - speculationToAbbreviatedString(at(node.child2()).prediction())); + out.print(", "); // Whether or not there is a first child, we print a comma to ensure that we see a blank entry if there wasn't one. + dump(out, node.child2()); + hasPrinted = true; } if (!!node.child3()) { - dataLogF(", %s@%u%s", - useKindToString(node.child3().useKind()), - node.child3().index(), - speculationToAbbreviatedString(at(node.child3()).prediction())); + if (!node.child1() && !node.child2()) + out.print(", "); // If the third child is the first non-empty one then make sure we have two blanks preceding it. + out.print(", "); + dump(out, node.child3()); + hasPrinted = true; } - hasPrinted = !!node.child1(); } if (strlen(nodeFlagsAsString(node.flags()))) { - dataLogF("%s%s", hasPrinted ? ", " : "", nodeFlagsAsString(node.flags())); + out.print(hasPrinted ? ", " : "", nodeFlagsAsString(node.flags())); hasPrinted = true; } if (node.hasArrayMode()) { - dataLogF("%s%s", hasPrinted ? ", " : "", node.arrayMode().toString()); + out.print(hasPrinted ? ", " : "", node.arrayMode().toString()); hasPrinted = true; } if (node.hasVarNumber()) { - dataLogF("%svar%u", hasPrinted ? ", " : "", node.varNumber()); + out.print(hasPrinted ? ", " : "", "var", node.varNumber()); hasPrinted = true; } if (node.hasRegisterPointer()) { - dataLogF( - "%sglobal%u(%p)", hasPrinted ? ", " : "", - globalObjectFor(node.codeOrigin)->findRegisterIndex(node.registerPointer()), - node.registerPointer()); + out.print(hasPrinted ? ", " : "", "global", globalObjectFor(node.codeOrigin)->findRegisterIndex(node.registerPointer()), "(", RawPointer(node.registerPointer()), ")"); hasPrinted = true; } if (node.hasIdentifier()) { - dataLogF("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), m_codeBlock->identifier(node.identifierNumber()).string().utf8().data()); + out.print(hasPrinted ? ", " : "", "id", node.identifierNumber(), "{", m_codeBlock->identifier(node.identifierNumber()).string(), "}"); hasPrinted = true; } if (node.hasStructureSet()) { for (size_t i = 0; i < node.structureSet().size(); ++i) { - dataLogF("%sstruct(%p: %s)", hasPrinted ? ", " : "", node.structureSet()[i], indexingTypeToString(node.structureSet()[i]->indexingType())); + out.print(hasPrinted ? ", " : "", "struct(", RawPointer(node.structureSet()[i]), ": ", indexingTypeToString(node.structureSet()[i]->indexingType()), ")"); hasPrinted = true; } } if (node.hasStructure()) { - dataLogF("%sstruct(%p: %s)", hasPrinted ? ", " : "", node.structure(), indexingTypeToString(node.structure()->indexingType())); + out.print(hasPrinted ? ", " : "", "struct(", RawPointer(node.structure()), ": ", indexingTypeToString(node.structure()->indexingType()), ")"); hasPrinted = true; } if (node.hasStructureTransitionData()) { - dataLogF("%sstruct(%p -> %p)", hasPrinted ? ", " : "", node.structureTransitionData().previousStructure, node.structureTransitionData().newStructure); + out.print(hasPrinted ? ", " : "", "struct(", RawPointer(node.structureTransitionData().previousStructure), " -> ", RawPointer(node.structureTransitionData().newStructure), ")"); hasPrinted = true; } if (node.hasFunction()) { - dataLogF("%s%p", hasPrinted ? ", " : "", node.function()); + out.print(hasPrinted ? ", " : "", RawPointer(node.function())); hasPrinted = true; } if (node.hasStorageAccessData()) { StorageAccessData& storageAccessData = m_storageAccessData[node.storageAccessDataIndex()]; - dataLogF("%sid%u{%s}", hasPrinted ? ", " : "", storageAccessData.identifierNumber, m_codeBlock->identifier(storageAccessData.identifierNumber).string().utf8().data()); - - dataLogF(", %lu", static_cast<unsigned long>(storageAccessData.offset)); + out.print(hasPrinted ? ", " : "", "id", storageAccessData.identifierNumber, "{", m_codeBlock->identifier(storageAccessData.identifierNumber).string(), "}"); + out.print(", ", static_cast<ptrdiff_t>(storageAccessData.offset)); hasPrinted = true; } ASSERT(node.hasVariableAccessData() == node.hasLocal()); @@ -274,138 +233,139 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex) VariableAccessData* variableAccessData = node.variableAccessData(); int operand = variableAccessData->operand(); if (operandIsArgument(operand)) - dataLogF("%sarg%u(%s)", hasPrinted ? ", " : "", operandToArgument(operand), nameOfVariableAccessData(variableAccessData)); + out.print(hasPrinted ? ", " : "", "arg", operandToArgument(operand), "(", VariableAccessDataDump(*this, variableAccessData), ")"); else - dataLogF("%sr%u(%s)", hasPrinted ? ", " : "", operand, nameOfVariableAccessData(variableAccessData)); + out.print(hasPrinted ? ", " : "", "r", operand, "(", VariableAccessDataDump(*this, variableAccessData), ")"); hasPrinted = true; } if (node.hasConstantBuffer()) { if (hasPrinted) - dataLogF(", "); - dataLogF("%u:[", node.startConstant()); + out.print(", "); + out.print(node.startConstant(), ":["); for (unsigned i = 0; i < node.numConstants(); ++i) { if (i) - dataLogF(", "); - dataLogF("%s", m_codeBlock->constantBuffer(node.startConstant())[i].description()); + out.print(", "); + out.print(m_codeBlock->constantBuffer(node.startConstant())[i].description()); } - dataLogF("]"); + out.print("]"); hasPrinted = true; } if (node.hasIndexingType()) { if (hasPrinted) - dataLogF(", "); - dataLogF("%s", indexingTypeToString(node.indexingType())); + out.print(", "); + out.print(indexingTypeToString(node.indexingType())); } if (op == JSConstant) { - dataLogF("%s$%u", hasPrinted ? ", " : "", node.constantNumber()); + out.print(hasPrinted ? ", " : "", "$", node.constantNumber()); JSValue value = valueOfJSConstant(nodeIndex); - dataLogF(" = %s", value.description()); + out.print(" = ", value.description()); hasPrinted = true; } if (op == WeakJSConstant) { - dataLogF("%s%p", hasPrinted ? ", " : "", node.weakConstant()); + out.print(hasPrinted ? ", " : "", RawPointer(node.weakConstant())); hasPrinted = true; } if (node.isBranch() || node.isJump()) { - dataLogF("%sT:#%u", hasPrinted ? ", " : "", node.takenBlockIndex()); + out.print(hasPrinted ? ", " : "", "T:#", node.takenBlockIndex()); hasPrinted = true; } if (node.isBranch()) { - dataLogF("%sF:#%u", hasPrinted ? ", " : "", node.notTakenBlockIndex()); + out.print(hasPrinted ? ", " : "", "F:#", node.notTakenBlockIndex()); hasPrinted = true; } - dataLogF("%sbc#%u", hasPrinted ? ", " : "", node.codeOrigin.bytecodeIndex); + out.print(hasPrinted ? ", " : "", "bc#", node.codeOrigin.bytecodeIndex); hasPrinted = true; + (void)hasPrinted; - dataLogF(")"); + out.print(")"); if (!skipped) { if (node.hasVariableAccessData()) - dataLogF(" predicting %s%s", speculationToString(node.variableAccessData()->prediction()), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : ""); + out.print(" predicting ", SpeculationDump(node.variableAccessData()->prediction()), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : ""); else if (node.hasHeapPrediction()) - dataLogF(" predicting %s", speculationToString(node.getHeapPrediction())); + out.print(" predicting ", SpeculationDump(node.getHeapPrediction())); } - dataLogF("\n"); + out.print("\n"); } -void Graph::dumpBlockHeader(const char* prefix, BlockIndex blockIndex, PhiNodeDumpMode phiNodeDumpMode) +void Graph::dumpBlockHeader(PrintStream& out, const char* prefix, BlockIndex blockIndex, PhiNodeDumpMode phiNodeDumpMode) { BasicBlock* block = m_blocks[blockIndex].get(); - dataLogF("%sBlock #%u (bc#%u): %s%s\n", prefix, (int)blockIndex, block->bytecodeBegin, block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : ""); - dataLogF("%s Predecessors:", prefix); + out.print(prefix, "Block #", blockIndex, " (bc#", block->bytecodeBegin, "): ", block->isReachable ? "" : "(skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n"); + out.print(prefix, " Predecessors:"); for (size_t i = 0; i < block->m_predecessors.size(); ++i) - dataLogF(" #%u", block->m_predecessors[i]); - dataLogF("\n"); + out.print(" #", block->m_predecessors[i]); + out.print("\n"); if (m_dominators.isValid()) { - dataLogF("%s Dominated by:", prefix); + out.print(prefix, " Dominated by:"); for (size_t i = 0; i < m_blocks.size(); ++i) { if (!m_dominators.dominates(i, blockIndex)) continue; - dataLogF(" #%lu", static_cast<unsigned long>(i)); + out.print(" #", i); } - dataLogF("\n"); - dataLogF("%s Dominates:", prefix); + out.print("\n"); + out.print(prefix, " Dominates:"); for (size_t i = 0; i < m_blocks.size(); ++i) { if (!m_dominators.dominates(blockIndex, i)) continue; - dataLogF(" #%lu", static_cast<unsigned long>(i)); + out.print(" #", i); } - dataLogF("\n"); + out.print("\n"); } - dataLogF("%s Phi Nodes:", prefix); + out.print(prefix, " Phi Nodes:"); for (size_t i = 0; i < block->phis.size(); ++i) { NodeIndex phiNodeIndex = block->phis[i]; Node& phiNode = at(phiNodeIndex); if (!phiNode.shouldGenerate() && phiNodeDumpMode == DumpLivePhisOnly) continue; - dataLogF(" @%u->(", phiNodeIndex); + out.print(" @", phiNodeIndex, "->("); if (phiNode.child1()) { - dataLogF("@%u", phiNode.child1().index()); + out.print("@", phiNode.child1().index()); if (phiNode.child2()) { - dataLogF(", @%u", phiNode.child2().index()); + out.print(", @", phiNode.child2().index()); if (phiNode.child3()) - dataLogF(", @%u", phiNode.child3().index()); + out.print(", @", phiNode.child3().index()); } } - dataLogF(")%s", i + 1 < block->phis.size() ? "," : ""); + out.print(")", i + 1 < block->phis.size() ? "," : ""); } - dataLogF("\n"); + out.print("\n"); } -void Graph::dump() +void Graph::dump(PrintStream& out) { NodeIndex lastNodeIndex = NoNode; for (size_t b = 0; b < m_blocks.size(); ++b) { BasicBlock* block = m_blocks[b].get(); if (!block) continue; - dumpBlockHeader("", b, DumpAllPhis); - dataLogF(" vars before: "); + dumpBlockHeader(out, "", b, DumpAllPhis); + out.print(" vars before: "); if (block->cfaHasVisited) - dumpOperands(block->valuesAtHead, WTF::dataFile()); + dumpOperands(block->valuesAtHead, out); else - dataLogF("<empty>"); - dataLogF("\n"); - dataLogF(" var links: "); - dumpOperands(block->variablesAtHead, WTF::dataFile()); - dataLogF("\n"); + out.print("<empty>"); + out.print("\n"); + out.print(" var links: "); + dumpOperands(block->variablesAtHead, out); + out.print("\n"); for (size_t i = 0; i < block->size(); ++i) { - dumpCodeOrigin("", lastNodeIndex, block->at(i)); - dump("", block->at(i)); + dumpCodeOrigin(out, "", lastNodeIndex, block->at(i)); + dump(out, "", block->at(i)); lastNodeIndex = block->at(i); } - dataLogF(" vars after: "); + out.print(" vars after: "); if (block->cfaHasVisited) - dumpOperands(block->valuesAtTail, WTF::dataFile()); + dumpOperands(block->valuesAtTail, out); else - dataLogF("<empty>"); - dataLogF("\n"); - dataLogF(" var links: "); - dumpOperands(block->variablesAtTail, WTF::dataFile()); - dataLogF("\n"); + out.print("<empty>"); + out.print("\n"); + out.print(" var links: "); + dumpOperands(block->variablesAtTail, out); + out.print("\n"); } } @@ -460,7 +420,9 @@ void Graph::predictArgumentTypes() at(m_arguments[arg]).variableAccessData()->predict(profile->computeUpdatedPrediction()); #if DFG_ENABLE(DEBUG_VERBOSE) - dataLogF("Argument [%zu] prediction: %s\n", arg, speculationToString(at(m_arguments[arg]).variableAccessData()->prediction())); + dataLog( + "Argument [", arg, "] prediction: ", + SpeculationDump(at(m_arguments[arg]).variableAccessData()->prediction()), "\n"); #endif } } diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 0c77b2959..d91d37394 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -190,16 +190,17 @@ public: } // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names). - void dump(); + void dump(PrintStream& = WTF::dataFile()); enum PhiNodeDumpMode { DumpLivePhisOnly, DumpAllPhis }; - void dumpBlockHeader(const char* prefix, BlockIndex, PhiNodeDumpMode); - void dump(const char* prefix, NodeIndex); + void dumpBlockHeader(PrintStream&, const char* prefix, BlockIndex, PhiNodeDumpMode); + void dump(PrintStream&, Edge); + void dump(PrintStream&, const char* prefix, NodeIndex); static int amountOfNodeWhiteSpace(Node&); - static void printNodeWhiteSpace(Node&); + static void printNodeWhiteSpace(PrintStream&, Node&); // Dump the code origin of the given node as a diff from the code origin of the // preceding node. - void dumpCodeOrigin(const char* prefix, NodeIndex, NodeIndex); + void dumpCodeOrigin(PrintStream&, const char* prefix, NodeIndex, NodeIndex); BlockIndex blockIndexForBytecodeOffset(Vector<BlockIndex>& blocks, unsigned bytecodeBegin); @@ -326,9 +327,6 @@ public: static const char *opName(NodeType); - // This is O(n), and should only be used for verbose dumps. - const char* nameOfVariableAccessData(VariableAccessData*); - void predictArgumentTypes(); StructureSet* addStructureSet(const StructureSet& structureSet) diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index 18c8ce16f..5f7890a96 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -1158,17 +1158,17 @@ struct Node { return nodeCanSpeculateInteger(arithNodeFlags()); } - void dumpChildren(FILE* out) + void dumpChildren(PrintStream& out) { if (!child1()) return; - fprintf(out, "@%u", child1().index()); + out.printf("@%u", child1().index()); if (!child2()) return; - fprintf(out, ", @%u", child2().index()); + out.printf(", @%u", child2().index()); if (!child3()) return; - fprintf(out, ", @%u", child3().index()); + out.printf(", @%u", child3().index()); } // Used to look up exception handling information (currently implemented as a bytecode index). diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp index b83c0b3f5..3138daea9 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp @@ -684,7 +684,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov // 16) Load the result of the last bytecode operation into regT0. if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) - m_jit.loadPtr(AssemblyHelpers::addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); + m_jit.load64(AssemblyHelpers::addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); // 17) Adjust the call frame pointer. diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 41276d233..d7f7b2fab 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -147,6 +147,13 @@ void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource speculationCheck(kind, jsValueSource, nodeUse.index(), jumpToFail, recovery); } +void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery, SpeculationDirection direction) +{ + speculationCheck(kind, jsValueSource, nodeIndex, jumpToFail, recovery); + if (direction == ForwardSpeculation) + convertLastOSRExitToForward(); +} + JumpReplacementWatchpoint* SpeculativeJIT::speculationWatchpoint(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex) { if (!m_compileOkay) @@ -170,10 +177,13 @@ JumpReplacementWatchpoint* SpeculativeJIT::speculationWatchpoint(ExitKind kind) void SpeculativeJIT::convertLastOSRExitToForward(const ValueRecovery& valueRecovery) { if (!valueRecovery) { - // Check that the preceding node was a SetLocal with the same code origin. - Node* setLocal = &at(m_jit.graph().m_blocks[m_block]->at(m_indexInBlock - 1)); - ASSERT_UNUSED(setLocal, setLocal->op() == SetLocal); - ASSERT_UNUSED(setLocal, setLocal->codeOrigin == at(m_compileIndex).codeOrigin); + // Check that either the current node is a SetLocal, or the preceding node was a + // SetLocal with the same code origin. + if (at(m_compileIndex).op() != SetLocal) { + Node* setLocal = &at(m_jit.graph().m_blocks[m_block]->at(m_indexInBlock - 1)); + ASSERT_UNUSED(setLocal, setLocal->op() == SetLocal); + ASSERT_UNUSED(setLocal, setLocal->codeOrigin == at(m_compileIndex).codeOrigin); + } // Find the next node. unsigned indexInBlock = m_indexInBlock + 1; @@ -239,10 +249,10 @@ JumpReplacementWatchpoint* SpeculativeJIT::forwardSpeculationWatchpoint(ExitKind return result; } -JumpReplacementWatchpoint* SpeculativeJIT::speculationWatchpointWithConditionalDirection(ExitKind kind, bool isForward) +JumpReplacementWatchpoint* SpeculativeJIT::speculationWatchpoint(ExitKind kind, SpeculationDirection direction) { JumpReplacementWatchpoint* result = speculationWatchpoint(kind); - if (isForward) + if (direction == ForwardSpeculation) convertLastOSRExitToForward(); return result; } @@ -262,9 +272,9 @@ void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValu forwardSpeculationCheck(kind, jsValueSource, nodeIndex, jumpVector[i], valueRecovery); } -void SpeculativeJIT::speculationCheckWithConditionalDirection(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, bool isForward) +void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, SpeculationDirection direction) { - if (isForward) + if (direction == ForwardSpeculation) forwardSpeculationCheck(kind, jsValueSource, nodeIndex, jumpToFail); else speculationCheck(kind, jsValueSource, nodeIndex, jumpToFail); @@ -288,7 +298,7 @@ void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs js terminateSpeculativeExecution(kind, jsValueRegs, nodeUse.index()); } -void SpeculativeJIT::terminateSpeculativeExecutionWithConditionalDirection(ExitKind kind, JSValueRegs jsValueRegs, NodeIndex nodeIndex, bool isForward) +void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, NodeIndex nodeIndex, SpeculationDirection direction) { ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); #if DFG_ENABLE(DEBUG_VERBOSE) @@ -296,7 +306,7 @@ void SpeculativeJIT::terminateSpeculativeExecutionWithConditionalDirection(ExitK #endif if (!m_compileOkay) return; - speculationCheckWithConditionalDirection(kind, jsValueRegs, nodeIndex, m_jit.jump(), isForward); + speculationCheck(kind, jsValueRegs, nodeIndex, m_jit.jump(), direction); m_compileOkay = false; } @@ -662,7 +672,7 @@ GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex) } // Must be a cell; fill it as a cell and then return the pointer. - return fillSpeculateCell(nodeIndex); + return fillSpeculateCell(nodeIndex, BackwardSpeculation); } case DataFormatStorage: { @@ -672,7 +682,7 @@ GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex) } default: - return fillSpeculateCell(nodeIndex); + return fillSpeculateCell(nodeIndex, BackwardSpeculation); } } diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index f1384e269..5f6fe842c 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -53,6 +53,7 @@ class SpeculateCellOperand; class SpeculateBooleanOperand; enum GeneratedOperandType { GeneratedOperandTypeUnknown, GeneratedOperandInteger, GeneratedOperandDouble, GeneratedOperandJSValue}; +enum SpeculationDirection { ForwardSpeculation, BackwardSpeculation }; // === SpeculativeJIT === // @@ -306,11 +307,11 @@ public: // Called by the speculative operand types, below, to fill operand to // machine registers, implicitly generating speculation checks as needed. - GPRReg fillSpeculateInt(NodeIndex, DataFormat& returnFormat); + GPRReg fillSpeculateInt(NodeIndex, DataFormat& returnFormat, SpeculationDirection); GPRReg fillSpeculateIntStrict(NodeIndex); - FPRReg fillSpeculateDouble(NodeIndex); - GPRReg fillSpeculateCell(NodeIndex, bool isForwardSpeculation = false); - GPRReg fillSpeculateBoolean(NodeIndex); + FPRReg fillSpeculateDouble(NodeIndex, SpeculationDirection); + GPRReg fillSpeculateCell(NodeIndex, SpeculationDirection); + GPRReg fillSpeculateBoolean(NodeIndex, SpeculationDirection); GeneratedOperandType checkGeneratedTypeForToInt32(NodeIndex); void addSlowPathGenerator(PassOwnPtr<SlowPathGenerator>); @@ -2448,15 +2449,16 @@ public: // that you've ensured that there exists a MovHint prior to your use of forwardSpeculationCheck(). void forwardSpeculationCheck(ExitKind, JSValueSource, NodeIndex, MacroAssembler::Jump jumpToFail, const ValueRecovery& = ValueRecovery()); void forwardSpeculationCheck(ExitKind, JSValueSource, NodeIndex, const MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& = ValueRecovery()); - void speculationCheckWithConditionalDirection(ExitKind, JSValueSource, NodeIndex, MacroAssembler::Jump jumpToFail, bool isForward); + void speculationCheck(ExitKind, JSValueSource, NodeIndex, MacroAssembler::Jump jumpToFail, SpeculationDirection); + void speculationCheck(ExitKind, JSValueSource, NodeIndex, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&, SpeculationDirection); // Called when we statically determine that a speculation will fail. void terminateSpeculativeExecution(ExitKind, JSValueRegs, NodeIndex); void terminateSpeculativeExecution(ExitKind, JSValueRegs, Edge); - void terminateSpeculativeExecutionWithConditionalDirection(ExitKind, JSValueRegs, NodeIndex, bool isForward); + void terminateSpeculativeExecution(ExitKind, JSValueRegs, NodeIndex, SpeculationDirection); // Issue a forward speculation watchpoint, which will exit to the next instruction rather // than the current one. JumpReplacementWatchpoint* forwardSpeculationWatchpoint(ExitKind = UncountableWatchpoint); - JumpReplacementWatchpoint* speculationWatchpointWithConditionalDirection(ExitKind, bool isForward); + JumpReplacementWatchpoint* speculationWatchpoint(ExitKind, SpeculationDirection); const TypedArrayDescriptor* typedArrayDescriptor(ArrayMode); @@ -2467,7 +2469,7 @@ public: void arrayify(Node&); template<bool strict> - GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat); + GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat, SpeculationDirection); // It is possible, during speculative generation, to reach a situation in which we // can statically determine a speculation will fail (for example, when two nodes @@ -2963,13 +2965,14 @@ private: class SpeculateIntegerOperand { public: - explicit SpeculateIntegerOperand(SpeculativeJIT* jit, Edge use) + explicit SpeculateIntegerOperand(SpeculativeJIT* jit, Edge use, SpeculationDirection direction = BackwardSpeculation) : m_jit(jit) , m_index(use.index()) , m_gprOrInvalid(InvalidGPRReg) #ifndef NDEBUG , m_format(DataFormatNone) #endif + , m_direction(direction) { ASSERT(m_jit); ASSERT(use.useKind() != DoubleUse); @@ -2998,7 +3001,7 @@ public: GPRReg gpr() { if (m_gprOrInvalid == InvalidGPRReg) - m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format); + m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format, m_direction); return m_gprOrInvalid; } @@ -3012,6 +3015,7 @@ private: NodeIndex m_index; GPRReg m_gprOrInvalid; DataFormat m_format; + SpeculationDirection m_direction; }; class SpeculateStrictInt32Operand { @@ -3058,10 +3062,11 @@ private: class SpeculateDoubleOperand { public: - explicit SpeculateDoubleOperand(SpeculativeJIT* jit, Edge use) + explicit SpeculateDoubleOperand(SpeculativeJIT* jit, Edge use, SpeculationDirection direction = BackwardSpeculation) : m_jit(jit) , m_index(use.index()) , m_fprOrInvalid(InvalidFPRReg) + , m_direction(direction) { ASSERT(m_jit); ASSERT(use.useKind() == DoubleUse); @@ -3083,7 +3088,7 @@ public: FPRReg fpr() { if (m_fprOrInvalid == InvalidFPRReg) - m_fprOrInvalid = m_jit->fillSpeculateDouble(index()); + m_fprOrInvalid = m_jit->fillSpeculateDouble(index(), m_direction); return m_fprOrInvalid; } @@ -3096,15 +3101,16 @@ private: SpeculativeJIT* m_jit; NodeIndex m_index; FPRReg m_fprOrInvalid; + SpeculationDirection m_direction; }; class SpeculateCellOperand { public: - explicit SpeculateCellOperand(SpeculativeJIT* jit, Edge use, bool isForwardSpeculation = false) + explicit SpeculateCellOperand(SpeculativeJIT* jit, Edge use, SpeculationDirection direction = BackwardSpeculation) : m_jit(jit) , m_index(use.index()) , m_gprOrInvalid(InvalidGPRReg) - , m_isForwardSpeculation(isForwardSpeculation) + , m_direction(direction) { ASSERT(m_jit); ASSERT(use.useKind() != DoubleUse); @@ -3126,7 +3132,7 @@ public: GPRReg gpr() { if (m_gprOrInvalid == InvalidGPRReg) - m_gprOrInvalid = m_jit->fillSpeculateCell(index(), m_isForwardSpeculation); + m_gprOrInvalid = m_jit->fillSpeculateCell(index(), m_direction); return m_gprOrInvalid; } @@ -3139,15 +3145,16 @@ private: SpeculativeJIT* m_jit; NodeIndex m_index; GPRReg m_gprOrInvalid; - bool m_isForwardSpeculation; + SpeculationDirection m_direction; }; class SpeculateBooleanOperand { public: - explicit SpeculateBooleanOperand(SpeculativeJIT* jit, Edge use) + explicit SpeculateBooleanOperand(SpeculativeJIT* jit, Edge use, SpeculationDirection direction = BackwardSpeculation) : m_jit(jit) , m_index(use.index()) , m_gprOrInvalid(InvalidGPRReg) + , m_direction(direction) { ASSERT(m_jit); ASSERT(use.useKind() != DoubleUse); @@ -3169,7 +3176,7 @@ public: GPRReg gpr() { if (m_gprOrInvalid == InvalidGPRReg) - m_gprOrInvalid = m_jit->fillSpeculateBoolean(index()); + m_gprOrInvalid = m_jit->fillSpeculateBoolean(index(), m_direction); return m_gprOrInvalid; } @@ -3182,6 +3189,7 @@ private: SpeculativeJIT* m_jit; NodeIndex m_index; GPRReg m_gprOrInvalid; + SpeculationDirection m_direction; }; } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 05af6962e..f5b9ec9ce 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -1087,13 +1087,13 @@ void SpeculativeJIT::emitCall(Node& node) } template<bool strict> -GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat) +GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat, SpeculationDirection direction) { #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("SpecInt@%d ", nodeIndex); #endif if (isKnownNotInteger(nodeIndex)) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); returnFormat = DataFormatInteger; return allocate(); } @@ -1121,7 +1121,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& // If we know this was spilled as an integer we can fill without checking. if (!isInt32Speculation(type)) - speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag))); + speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)), direction); GPRReg gpr = allocate(); m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr); @@ -1139,7 +1139,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& m_gprs.lock(tagGPR); m_gprs.lock(payloadGPR); if (!isInt32Speculation(type)) - speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag))); + speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag)), direction); m_gprs.unlock(tagGPR); m_gprs.release(tagGPR); m_gprs.release(payloadGPR); @@ -1172,26 +1172,26 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& } } -GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat) +GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat, SpeculationDirection direction) { - return fillSpeculateIntInternal<false>(nodeIndex, returnFormat); + return fillSpeculateIntInternal<false>(nodeIndex, returnFormat, direction); } GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex) { DataFormat mustBeDataFormatInteger; - GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger); + GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger, BackwardSpeculation); ASSERT(mustBeDataFormatInteger == DataFormatInteger); return result; } -FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) +FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex, SpeculationDirection direction) { #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("SpecDouble@%d ", nodeIndex); #endif if (isKnownNotNumber(nodeIndex)) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return fprAllocate(); } @@ -1234,7 +1234,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) if (spillFormat != DataFormatJSInteger && spillFormat != DataFormatInteger) { JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)); if (!isNumberSpeculation(type)) - speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::LowestTag))); + speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::LowestTag)), direction); m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr); hasUnboxedDouble = m_jit.jump(); @@ -1269,7 +1269,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) FPRTemporary scratch(this); JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag)); if (!isNumberSpeculation(type)) - speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag))); + speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)), direction); unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr()); hasUnboxedDouble = m_jit.jump(); isInteger.link(&m_jit); @@ -1320,13 +1320,13 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) } } -GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpeculation) +GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, SpeculationDirection direction) { #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("SpecCell@%d ", nodeIndex); #endif if (isKnownNotCell(nodeIndex)) { - terminateSpeculativeExecutionWithConditionalDirection(Uncountable, JSValueRegs(), NoNode, isForwardSpeculation); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return allocate(); } @@ -1350,7 +1350,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatCell); if (!isCellSpeculation(type)) - speculationCheckWithConditionalDirection(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)), isForwardSpeculation); + speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)), direction); GPRReg gpr = allocate(); m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr); m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); @@ -1371,7 +1371,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec m_gprs.lock(tagGPR); m_gprs.lock(payloadGPR); if (!isCellSpeculation(type)) - speculationCheckWithConditionalDirection(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag)), isForwardSpeculation); + speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag)), direction); m_gprs.unlock(tagGPR); m_gprs.release(tagGPR); m_gprs.release(payloadGPR); @@ -1395,7 +1395,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec } } -GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) +GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex, SpeculationDirection direction) { #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("SpecBool@%d ", nodeIndex); @@ -1406,7 +1406,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) GenerationInfo& info = m_generationInfo[virtualRegister]; if ((node.hasConstant() && !valueOfJSConstant(nodeIndex).isBoolean()) || !(info.isJSBoolean() || info.isUnknownJS())) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return allocate(); } @@ -1426,7 +1426,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatBoolean); if (!isBooleanSpeculation(type)) - speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag))); + speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)), direction); GPRReg gpr = allocate(); m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr); @@ -1448,7 +1448,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) m_gprs.lock(tagGPR); m_gprs.lock(payloadGPR); if (!isBooleanSpeculation(type)) - speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag))); + speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag)), direction); m_gprs.unlock(tagGPR); m_gprs.release(tagGPR); @@ -2241,39 +2241,9 @@ void SpeculativeJIT::compile(Node& node) // stack. compileMovHint(node); - // As far as OSR is concerned, we're on the bytecode index corresponding - // to the *next* instruction, since we've already "executed" the - // SetLocal and whatever other DFG Nodes are associated with the same - // bytecode index as the SetLocal. - ASSERT(m_codeOriginForOSR == node.codeOrigin); - Node* nextNode = &at(block()->at(m_indexInBlock + 1)); - - // But even more oddly, we need to be super careful about the following - // sequence: - // - // a: Foo() - // b: SetLocal(@a) - // c: Flush(@b) - // - // This next piece of crazy takes care of this. - if (nextNode->op() == Flush && nextNode->child1() == m_compileIndex) - nextNode = &at(block()->at(m_indexInBlock + 2)); - - // Oddly, it's possible for the bytecode index for the next node to be - // equal to ours. This will happen for op_post_inc. And, even more oddly, - // this is just fine. Ordinarily, this wouldn't be fine, since if the - // next node failed OSR then we'd be OSR-ing with this SetLocal's local - // variable already set even though from the standpoint of the old JIT, - // this SetLocal should not have executed. But for op_post_inc, it's just - // fine, because this SetLocal's local (i.e. the LHS in a x = y++ - // statement) would be dead anyway - so the fact that DFG would have - // already made the assignment, and baked it into the stack during - // OSR exit, would not be visible to the old JIT in any way. - m_codeOriginForOSR = nextNode->codeOrigin; - if (!node.variableAccessData()->isCaptured() && !m_jit.graph().isCreatedThisArgument(node.local())) { if (node.variableAccessData()->shouldUseDoubleFormat()) { - SpeculateDoubleOperand value(this, node.child1()); + SpeculateDoubleOperand value(this, node.child1(), ForwardSpeculation); m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); // Indicate that it's no longer necessary to retrieve the value of @@ -2291,14 +2261,14 @@ void SpeculativeJIT::compile(Node& node) break; } if (isInt32Speculation(predictedType)) { - SpeculateIntegerOperand value(this, node.child1()); + SpeculateIntegerOperand value(this, node.child1(), ForwardSpeculation); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); recordSetLocal(node.local(), ValueSource(Int32InJSStack)); break; } if (isCellSpeculation(predictedType)) { - SpeculateCellOperand cell(this, node.child1()); + SpeculateCellOperand cell(this, node.child1(), ForwardSpeculation); GPRReg cellGPR = cell.gpr(); m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); @@ -2306,7 +2276,7 @@ void SpeculativeJIT::compile(Node& node) break; } if (isBooleanSpeculation(predictedType)) { - SpeculateBooleanOperand value(this, node.child1()); + SpeculateBooleanOperand value(this, node.child1(), ForwardSpeculation); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); recordSetLocal(node.local(), ValueSource(BooleanInJSStack)); @@ -4172,18 +4142,19 @@ void SpeculativeJIT::compile(Node& node) break; } - SpeculateCellOperand base(this, node.child1(), node.op() == ForwardCheckStructure); + SpeculationDirection direction = node.op() == ForwardCheckStructure ? ForwardSpeculation : BackwardSpeculation; + SpeculateCellOperand base(this, node.child1(), direction); ASSERT(node.structureSet().size()); if (node.structureSet().size() == 1) { - speculationCheckWithConditionalDirection( + speculationCheck( BadCache, JSValueSource::unboxedCell(base.gpr()), NoNode, m_jit.branchWeakPtr( JITCompiler::NotEqual, JITCompiler::Address(base.gpr(), JSCell::structureOffset()), node.structureSet()[0]), - node.op() == ForwardCheckStructure); + direction); } else { GPRTemporary structure(this); @@ -4194,11 +4165,11 @@ void SpeculativeJIT::compile(Node& node) for (size_t i = 0; i < node.structureSet().size() - 1; ++i) done.append(m_jit.branchWeakPtr(JITCompiler::Equal, structure.gpr(), node.structureSet()[i])); - speculationCheckWithConditionalDirection( + speculationCheck( BadCache, JSValueSource::unboxedCell(base.gpr()), NoNode, m_jit.branchWeakPtr( JITCompiler::NotEqual, structure.gpr(), node.structureSet().last()), - node.op() == ForwardCheckStructure); + direction); done.link(&m_jit); } @@ -4216,13 +4187,16 @@ void SpeculativeJIT::compile(Node& node) // we'll just rely on the fact that when a watchpoint fires then that's // quite a hint already. + SpeculationDirection direction = node.op() == ForwardStructureTransitionWatchpoint ? ForwardSpeculation : BackwardSpeculation; + m_jit.addWeakReference(node.structure()); node.structure()->addTransitionWatchpoint( - speculationWatchpointWithConditionalDirection( - BadCache, node.op() == ForwardStructureTransitionWatchpoint)); + speculationWatchpoint( + m_jit.graph()[node.child1()].op() == WeakJSConstant ? BadWeakConstantCache : BadCache, + direction)); #if !ASSERT_DISABLED - SpeculateCellOperand op1(this, node.child1()); + SpeculateCellOperand op1(this, node.child1(), direction); JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureOffset()), TrustedImmPtr(node.structure())); m_jit.breakpoint(); isOK.link(&m_jit); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index da6583c70..7b43c5cfc 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -1062,7 +1062,7 @@ void SpeculativeJIT::emitCall(Node& node) } template<bool strict> -GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat) +GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat, SpeculationDirection direction) { #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("SpecInt@%d ", nodeIndex); @@ -1075,7 +1075,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& switch (info.registerFormat()) { case DataFormatNone: { if ((node.hasConstant() && !isInt32Constant(nodeIndex)) || info.spillFormat() == DataFormatDouble) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); returnFormat = DataFormatInteger; return allocate(); } @@ -1126,7 +1126,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& GPRReg gpr = info.gpr(); m_gprs.lock(gpr); if (!isInt32Speculation(type)) - speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branch64(MacroAssembler::Below, gpr, GPRInfo::tagTypeNumberRegister)); + speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branch64(MacroAssembler::Below, gpr, GPRInfo::tagTypeNumberRegister), direction); info.fillJSValue(*m_stream, gpr, DataFormatJSInteger); // If !strict we're done, return. if (!strict) { @@ -1183,7 +1183,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& case DataFormatBoolean: case DataFormatJSCell: case DataFormatJSBoolean: { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); returnFormat = DataFormatInteger; return allocate(); } @@ -1197,20 +1197,20 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& } } -GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat) +GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat, SpeculationDirection direction) { - return fillSpeculateIntInternal<false>(nodeIndex, returnFormat); + return fillSpeculateIntInternal<false>(nodeIndex, returnFormat, direction); } GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex) { DataFormat mustBeDataFormatInteger; - GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger); + GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger, BackwardSpeculation); ASSERT(mustBeDataFormatInteger == DataFormatInteger); return result; } -FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) +FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex, SpeculationDirection direction) { #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("SpecDouble@%d ", nodeIndex); @@ -1244,7 +1244,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) info.fillDouble(*m_stream, fpr); return fpr; } - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return fprAllocate(); } @@ -1287,7 +1287,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) ASSERT_NOT_REACHED(); case DataFormatCell: - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return fprAllocate(); case DataFormatJSCell: @@ -1301,7 +1301,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) JITCompiler::Jump isInteger = m_jit.branch64(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister); if (!isNumberSpeculation(type)) - speculationCheck(BadType, JSValueRegs(jsValueGpr), nodeIndex, m_jit.branchTest64(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister)); + speculationCheck(BadType, JSValueRegs(jsValueGpr), nodeIndex, m_jit.branchTest64(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister), direction); // First, if we get here we have a double encoded as a JSValue m_jit.move(jsValueGpr, tempGpr); @@ -1364,7 +1364,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) } } -GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpeculation) +GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, SpeculationDirection direction) { #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("SpecCell@%d ", nodeIndex); @@ -1377,7 +1377,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec switch (info.registerFormat()) { case DataFormatNone: { if (info.spillFormat() == DataFormatInteger || info.spillFormat() == DataFormatDouble) { - terminateSpeculativeExecutionWithConditionalDirection(Uncountable, JSValueRegs(), NoNode, isForwardSpeculation); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return allocate(); } @@ -1391,7 +1391,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec info.fillJSValue(*m_stream, gpr, DataFormatJSCell); return gpr; } - terminateSpeculativeExecutionWithConditionalDirection(Uncountable, JSValueRegs(), NoNode, isForwardSpeculation); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return gpr; } ASSERT(info.spillFormat() & DataFormatJS); @@ -1400,7 +1400,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec info.fillJSValue(*m_stream, gpr, DataFormatJS); if (!isCellSpeculation(type)) - speculationCheckWithConditionalDirection(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister), isForwardSpeculation); + speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister), direction); info.fillJSValue(*m_stream, gpr, DataFormatJSCell); return gpr; } @@ -1416,7 +1416,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec GPRReg gpr = info.gpr(); m_gprs.lock(gpr); if (!isCellSpeculation(type)) - speculationCheckWithConditionalDirection(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister), isForwardSpeculation); + speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister), direction); info.fillJSValue(*m_stream, gpr, DataFormatJSCell); return gpr; } @@ -1427,7 +1427,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec case DataFormatDouble: case DataFormatJSBoolean: case DataFormatBoolean: { - terminateSpeculativeExecutionWithConditionalDirection(Uncountable, JSValueRegs(), NoNode, isForwardSpeculation); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return allocate(); } @@ -1440,7 +1440,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex, bool isForwardSpec } } -GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) +GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex, SpeculationDirection direction) { #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("SpecBool@%d ", nodeIndex); @@ -1453,7 +1453,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) switch (info.registerFormat()) { case DataFormatNone: { if (info.spillFormat() == DataFormatInteger || info.spillFormat() == DataFormatDouble) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return allocate(); } @@ -1467,7 +1467,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean); return gpr; } - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return gpr; } ASSERT(info.spillFormat() & DataFormatJS); @@ -1477,7 +1477,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) info.fillJSValue(*m_stream, gpr, DataFormatJS); if (!isBooleanSpeculation(type)) { m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); - speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTest64(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); + speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTest64(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg), direction); m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); } info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean); @@ -1496,7 +1496,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) m_gprs.lock(gpr); if (!isBooleanSpeculation(type)) { m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); - speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTest64(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); + speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTest64(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg), direction); m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); } info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean); @@ -1509,7 +1509,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) case DataFormatDouble: case DataFormatJSCell: case DataFormatCell: { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); + terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode, direction); return allocate(); } @@ -2219,39 +2219,9 @@ void SpeculativeJIT::compile(Node& node) // stack. compileMovHint(node); - // As far as OSR is concerned, we're on the bytecode index corresponding - // to the *next* instruction, since we've already "executed" the - // SetLocal and whatever other DFG Nodes are associated with the same - // bytecode index as the SetLocal. - ASSERT(m_codeOriginForOSR == node.codeOrigin); - Node* nextNode = &at(block()->at(m_indexInBlock + 1)); - - // But even more oddly, we need to be super careful about the following - // sequence: - // - // a: Foo() - // b: SetLocal(@a) - // c: Flush(@b) - // - // This next piece of crazy takes care of this. - if (nextNode->op() == Flush && nextNode->child1() == m_compileIndex) - nextNode = &at(block()->at(m_indexInBlock + 2)); - - // Oddly, it's possible for the bytecode index for the next node to be - // equal to ours. This will happen for op_post_inc. And, even more oddly, - // this is just fine. Ordinarily, this wouldn't be fine, since if the - // next node failed OSR then we'd be OSR-ing with this SetLocal's local - // variable already set even though from the standpoint of the old JIT, - // this SetLocal should not have executed. But for op_post_inc, it's just - // fine, because this SetLocal's local (i.e. the LHS in a x = y++ - // statement) would be dead anyway - so the fact that DFG would have - // already made the assignment, and baked it into the stack during - // OSR exit, would not be visible to the old JIT in any way. - m_codeOriginForOSR = nextNode->codeOrigin; - if (!node.variableAccessData()->isCaptured() && !m_jit.graph().isCreatedThisArgument(node.local())) { if (node.variableAccessData()->shouldUseDoubleFormat()) { - SpeculateDoubleOperand value(this, node.child1()); + SpeculateDoubleOperand value(this, node.child1(), ForwardSpeculation); m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); // Indicate that it's no longer necessary to retrieve the value of @@ -2263,14 +2233,14 @@ void SpeculativeJIT::compile(Node& node) SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction(); if (isInt32Speculation(predictedType)) { - SpeculateIntegerOperand value(this, node.child1()); + SpeculateIntegerOperand value(this, node.child1(), ForwardSpeculation); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); recordSetLocal(node.local(), ValueSource(Int32InJSStack)); break; } if (isCellSpeculation(predictedType)) { - SpeculateCellOperand cell(this, node.child1()); + SpeculateCellOperand cell(this, node.child1(), ForwardSpeculation); GPRReg cellGPR = cell.gpr(); m_jit.store64(cellGPR, JITCompiler::addressFor(node.local())); noResult(m_compileIndex); @@ -2278,7 +2248,7 @@ void SpeculativeJIT::compile(Node& node) break; } if (isBooleanSpeculation(predictedType)) { - SpeculateBooleanOperand boolean(this, node.child1()); + SpeculateBooleanOperand boolean(this, node.child1(), ForwardSpeculation); m_jit.store64(boolean.gpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); recordSetLocal(node.local(), ValueSource(BooleanInJSStack)); @@ -4110,7 +4080,8 @@ void SpeculativeJIT::compile(Node& node) break; } - SpeculateCellOperand base(this, node.child1(), node.op() == ForwardCheckStructure); + SpeculationDirection direction = node.op() == ForwardCheckStructure ? ForwardSpeculation : BackwardSpeculation; + SpeculateCellOperand base(this, node.child1(), direction); ASSERT(node.structureSet().size()); @@ -4121,13 +4092,13 @@ void SpeculativeJIT::compile(Node& node) exitKind = BadCache; if (node.structureSet().size() == 1) { - speculationCheckWithConditionalDirection( + speculationCheck( exitKind, JSValueRegs(base.gpr()), NoNode, m_jit.branchWeakPtr( JITCompiler::NotEqual, JITCompiler::Address(base.gpr(), JSCell::structureOffset()), node.structureSet()[0]), - node.op() == ForwardCheckStructure); + direction); } else { GPRTemporary structure(this); @@ -4138,11 +4109,11 @@ void SpeculativeJIT::compile(Node& node) for (size_t i = 0; i < node.structureSet().size() - 1; ++i) done.append(m_jit.branchWeakPtr(JITCompiler::Equal, structure.gpr(), node.structureSet()[i])); - speculationCheckWithConditionalDirection( + speculationCheck( exitKind, JSValueRegs(base.gpr()), NoNode, m_jit.branchWeakPtr( JITCompiler::NotEqual, structure.gpr(), node.structureSet().last()), - node.op() == ForwardCheckStructure); + direction); done.link(&m_jit); } @@ -4160,14 +4131,16 @@ void SpeculativeJIT::compile(Node& node) // we'll just rely on the fact that when a watchpoint fires then that's // quite a hint already. + SpeculationDirection direction = node.op() == ForwardStructureTransitionWatchpoint ? ForwardSpeculation : BackwardSpeculation; + m_jit.addWeakReference(node.structure()); node.structure()->addTransitionWatchpoint( - speculationWatchpointWithConditionalDirection( + speculationWatchpoint( m_jit.graph()[node.child1()].op() == WeakJSConstant ? BadWeakConstantCache : BadCache, - node.op() == ForwardStructureTransitionWatchpoint)); + direction)); #if !ASSERT_DISABLED - SpeculateCellOperand op1(this, node.child1()); + SpeculateCellOperand op1(this, node.child1(), direction); JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureOffset()), TrustedImmPtr(node.structure())); m_jit.breakpoint(); isOK.link(&m_jit); diff --git a/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h index 25606b9be..626a11f0b 100644 --- a/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h +++ b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h @@ -301,14 +301,14 @@ public: void dump(PrintStream& out) const { if (isTop()) { - out.printf("TOP"); + out.print("TOP"); return; } - out.printf("["); + out.print("["); if (m_structure) - out.printf("%p", m_structure); - out.printf("]"); + out.print(RawPointer(m_structure)); + out.print("]"); } private: diff --git a/Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.cpp b/Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.cpp new file mode 100644 index 000000000..920858cef --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 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 "DFGVariableAccessDataDump.h" + +#if ENABLE(DFG_JIT) + +#include "DFGGraph.h" +#include "DFGVariableAccessData.h" + +namespace JSC { namespace DFG { + +VariableAccessDataDump::VariableAccessDataDump(Graph& graph, VariableAccessData* data) + : m_graph(graph) + , m_data(data) +{ +} + +void VariableAccessDataDump::dump(PrintStream& out) const +{ + unsigned index = std::numeric_limits<unsigned>::max(); + for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) { + if (&m_graph.m_variableAccessData[i] == m_data) { + index = i; + break; + } + } + + ASSERT(index != std::numeric_limits<unsigned>::max()); + + if (!index) { + out.print("a"); + return; + } + + while (index) { + out.print(CharacterDump('A' + (index % 26))); + index /= 26; + } + + if (m_data->isCaptured()) + out.print("*"); + + out.print(AbbreviatedSpeculationDump(m_data->prediction())); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + + diff --git a/Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.h b/Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.h new file mode 100644 index 000000000..1422d7fac --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2012 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 DFGVariableAccessDataDump_h +#define DFGVariableAccessDataDump_h + +#include <wtf/Platform.h> + +#if ENABLE(DFG_JIT) + +#include <wtf/PrintStream.h> + +namespace JSC { namespace DFG { + +class Graph; +class VariableAccessData; + +class VariableAccessDataDump { +public: + VariableAccessDataDump(Graph&, VariableAccessData*); + + void dump(PrintStream&) const; + +private: + Graph& m_graph; + VariableAccessData* m_data; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGVariableAccessDataDump_h + diff --git a/Source/JavaScriptCore/heap/BlockAllocator.cpp b/Source/JavaScriptCore/heap/BlockAllocator.cpp index 2d7b57f9a..f94025c1a 100644 --- a/Source/JavaScriptCore/heap/BlockAllocator.cpp +++ b/Source/JavaScriptCore/heap/BlockAllocator.cpp @@ -27,6 +27,7 @@ #include "BlockAllocator.h" #include "CopiedBlock.h" +#include "CopyWorkList.h" #include "MarkedBlock.h" #include "WeakBlock.h" #include <wtf/CurrentTime.h> @@ -37,6 +38,7 @@ BlockAllocator::BlockAllocator() : m_copiedRegionSet(CopiedBlock::blockSize) , m_markedRegionSet(MarkedBlock::blockSize) , m_weakAndMarkStackRegionSet(WeakBlock::blockSize) + , m_workListRegionSet(CopyWorkListSegment::blockSize) , m_numberOfEmptyRegions(0) , m_isCurrentlyAllocating(false) , m_blockFreeingThreadShouldQuit(false) diff --git a/Source/JavaScriptCore/heap/BlockAllocator.h b/Source/JavaScriptCore/heap/BlockAllocator.h index 75c59b783..417f81da0 100644 --- a/Source/JavaScriptCore/heap/BlockAllocator.h +++ b/Source/JavaScriptCore/heap/BlockAllocator.h @@ -37,6 +37,7 @@ namespace JSC { class BlockAllocator; class CopiedBlock; +class CopyWorkListSegment; class MarkStackSegment; class MarkedBlock; class Region; @@ -188,6 +189,7 @@ private: RegionSet m_markedRegionSet; // WeakBlocks and MarkStackSegments use the same RegionSet since they're the same size. RegionSet m_weakAndMarkStackRegionSet; + RegionSet m_workListRegionSet; DoublyLinkedList<Region> m_emptyRegions; size_t m_numberOfEmptyRegions; @@ -327,6 +329,12 @@ inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<MarkStackSegment> } template <> +inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<CopyWorkListSegment>() +{ + return m_workListRegionSet; +} + +template <> inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<CopiedBlock> >() { return m_copiedRegionSet; @@ -350,6 +358,12 @@ inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<MarkSta return m_weakAndMarkStackRegionSet; } +template <> +inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<CopyWorkListSegment> >() +{ + return m_workListRegionSet; +} + template <typename T> inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor() { diff --git a/Source/JavaScriptCore/heap/CopiedBlock.h b/Source/JavaScriptCore/heap/CopiedBlock.h index 83fdb08da..7f585585c 100644 --- a/Source/JavaScriptCore/heap/CopiedBlock.h +++ b/Source/JavaScriptCore/heap/CopiedBlock.h @@ -27,11 +27,14 @@ #define CopiedBlock_h #include "BlockAllocator.h" +#include "CopyWorkList.h" #include "HeapBlock.h" #include "JSValue.h" #include "JSValueInlines.h" #include "Options.h" #include <wtf/Atomics.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> namespace JSC { @@ -44,12 +47,13 @@ public: static CopiedBlock* create(DeadBlock*); static CopiedBlock* createNoZeroFill(DeadBlock*); + void pin(); bool isPinned(); unsigned liveBytes(); - void reportLiveBytes(unsigned); + void reportLiveBytes(JSCell*, unsigned); void didSurviveGC(); - bool didEvacuateBytes(unsigned); + void didEvacuateBytes(unsigned); bool shouldEvacuate(); bool canBeRecycled(); @@ -74,10 +78,18 @@ public: static const size_t blockSize = 32 * KB; + bool hasWorkList(); + CopyWorkList& workList(); + private: CopiedBlock(Region*); void zeroFillWilderness(); // Can be called at any time to zero-fill to the end of the block. +#if ENABLE(PARALLEL_GC) + SpinLock m_workListLock; +#endif + OwnPtr<CopyWorkList> m_workList; + size_t m_remaining; uintptr_t m_isPinned; unsigned m_liveBytes; @@ -114,45 +126,24 @@ inline CopiedBlock::CopiedBlock(Region* region) , m_isPinned(false) , m_liveBytes(0) { - ASSERT(is8ByteAligned(reinterpret_cast<void*>(m_remaining))); -} - -inline void CopiedBlock::reportLiveBytes(unsigned bytes) -{ #if ENABLE(PARALLEL_GC) - unsigned oldValue = 0; - unsigned newValue = 0; - do { - oldValue = m_liveBytes; - newValue = oldValue + bytes; - } while (!WTF::weakCompareAndSwap(&m_liveBytes, oldValue, newValue)); -#else - m_liveBytes += bytes; + m_workListLock.Init(); #endif + ASSERT(is8ByteAligned(reinterpret_cast<void*>(m_remaining))); } inline void CopiedBlock::didSurviveGC() { m_liveBytes = 0; m_isPinned = false; + if (m_workList) + m_workList.clear(); } -inline bool CopiedBlock::didEvacuateBytes(unsigned bytes) +inline void CopiedBlock::didEvacuateBytes(unsigned bytes) { ASSERT(m_liveBytes >= bytes); -#if ENABLE(PARALLEL_GC) - unsigned oldValue = 0; - unsigned newValue = 0; - do { - oldValue = m_liveBytes; - newValue = oldValue - bytes; - } while (!WTF::weakCompareAndSwap(&m_liveBytes, oldValue, newValue)); - ASSERT(m_liveBytes < oldValue); - return !newValue; -#else m_liveBytes -= bytes; - return !m_liveBytes; -#endif } inline bool CopiedBlock::canBeRecycled() @@ -165,6 +156,13 @@ inline bool CopiedBlock::shouldEvacuate() return static_cast<double>(m_liveBytes) / static_cast<double>(payloadCapacity()) <= Options::minCopiedBlockUtilization(); } +inline void CopiedBlock::pin() +{ + m_isPinned = true; + if (m_workList) + m_workList.clear(); +} + inline bool CopiedBlock::isPinned() { return m_isPinned; @@ -230,6 +228,16 @@ inline size_t CopiedBlock::capacity() return region()->blockSize(); } +inline bool CopiedBlock::hasWorkList() +{ + return !!m_workList; +} + +inline CopyWorkList& CopiedBlock::workList() +{ + return *m_workList; +} + } // namespace JSC #endif diff --git a/Source/JavaScriptCore/heap/CopiedBlockInlines.h b/Source/JavaScriptCore/heap/CopiedBlockInlines.h new file mode 100644 index 000000000..0068abcdd --- /dev/null +++ b/Source/JavaScriptCore/heap/CopiedBlockInlines.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 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 CopiedBlockInlines_h +#define CopiedBlockInlines_h + +#include "CopiedBlock.h" +#include "Heap.h" + +namespace JSC { + +inline void CopiedBlock::reportLiveBytes(JSCell* owner, unsigned bytes) +{ +#if ENABLE(PARALLEL_GC) + SpinLockHolder locker(&m_workListLock); +#endif + m_liveBytes += bytes; + + if (!shouldEvacuate()) { + pin(); + return; + } + + if (!m_workList) + m_workList = adoptPtr(new CopyWorkList(Heap::heap(owner)->blockAllocator())); + + m_workList->append(owner); +} + +} // namespace JSC + +#endif // CopiedBlockInlines_h diff --git a/Source/JavaScriptCore/heap/CopiedSpace.h b/Source/JavaScriptCore/heap/CopiedSpace.h index 3a698e8dc..e3727100e 100644 --- a/Source/JavaScriptCore/heap/CopiedSpace.h +++ b/Source/JavaScriptCore/heap/CopiedSpace.h @@ -47,6 +47,7 @@ class CopiedBlock; class CopiedSpace { friend class CopyVisitor; + friend class GCThreadSharedData; friend class SlotVisitor; friend class JIT; public: diff --git a/Source/JavaScriptCore/heap/CopiedSpaceInlines.h b/Source/JavaScriptCore/heap/CopiedSpaceInlines.h index 9d222f549..41f94dd74 100644 --- a/Source/JavaScriptCore/heap/CopiedSpaceInlines.h +++ b/Source/JavaScriptCore/heap/CopiedSpaceInlines.h @@ -54,7 +54,7 @@ inline bool CopiedSpace::contains(void* ptr, CopiedBlock*& result) inline void CopiedSpace::pin(CopiedBlock* block) { - block->m_isPinned = true; + block->pin(); } inline void CopiedSpace::pinIfNecessary(void* opaquePointer) diff --git a/Source/JavaScriptCore/heap/CopyVisitor.cpp b/Source/JavaScriptCore/heap/CopyVisitor.cpp index 22ab57882..281d4bd3b 100644 --- a/Source/JavaScriptCore/heap/CopyVisitor.cpp +++ b/Source/JavaScriptCore/heap/CopyVisitor.cpp @@ -27,6 +27,7 @@ #include "CopyVisitor.h" #include "CopyVisitorInlines.h" +#include "CopyWorkList.h" #include "GCThreadSharedData.h" #include "JSCell.h" #include "JSObject.h" @@ -41,17 +42,24 @@ CopyVisitor::CopyVisitor(GCThreadSharedData& shared) void CopyVisitor::copyFromShared() { - GCCopyPhaseFunctor functor(*this); - Vector<MarkedBlock*>& blocksToCopy = m_shared.m_blocksToCopy; - size_t startIndex, endIndex; - - m_shared.getNextBlocksToCopy(startIndex, endIndex); - while (startIndex < endIndex) { - for (size_t i = startIndex; i < endIndex; i++) - blocksToCopy[i]->forEachLiveCell(functor); - m_shared.getNextBlocksToCopy(startIndex, endIndex); + size_t next, end; + m_shared.getNextBlocksToCopy(next, end); + while (next < end) { + for (; next < end; ++next) { + CopiedBlock* block = m_shared.m_blocksToCopy[next]; + if (!block->hasWorkList()) + continue; + + CopyWorkList& workList = block->workList(); + for (CopyWorkList::iterator it = workList.begin(); it != workList.end(); ++it) + visitCell(*it); + + ASSERT(!block->liveBytes()); + m_shared.m_copiedSpace->recycleEvacuatedBlock(block); + } + m_shared.getNextBlocksToCopy(next, end); } - ASSERT(startIndex == endIndex); + ASSERT(next == end); } } // namespace JSC diff --git a/Source/JavaScriptCore/heap/CopyVisitor.h b/Source/JavaScriptCore/heap/CopyVisitor.h index 45a2e0ad9..c5f7272a9 100644 --- a/Source/JavaScriptCore/heap/CopyVisitor.h +++ b/Source/JavaScriptCore/heap/CopyVisitor.h @@ -31,6 +31,7 @@ namespace JSC { class GCThreadSharedData; +class JSCell; class CopyVisitor { public: @@ -50,6 +51,7 @@ public: private: void* allocateNewSpaceSlow(size_t); + void visitCell(JSCell*); GCThreadSharedData& m_shared; CopiedAllocator m_copiedAllocator; diff --git a/Source/JavaScriptCore/heap/CopyVisitorInlines.h b/Source/JavaScriptCore/heap/CopyVisitorInlines.h index bd7879429..1557af93d 100644 --- a/Source/JavaScriptCore/heap/CopyVisitorInlines.h +++ b/Source/JavaScriptCore/heap/CopyVisitorInlines.h @@ -34,25 +34,11 @@ namespace JSC { -class GCCopyPhaseFunctor : public MarkedBlock::VoidFunctor { -public: - GCCopyPhaseFunctor(CopyVisitor& visitor) - : m_visitor(visitor) - { - } - - void operator()(JSCell* cell) - { - Structure* structure = cell->structure(); - if (!structure->outOfLineCapacity() && !hasIndexedProperties(structure->indexingType())) - return; - ASSERT(structure->classInfo()->methodTable.copyBackingStore == JSObject::copyBackingStore); - JSObject::copyBackingStore(cell, m_visitor); - } - -private: - CopyVisitor& m_visitor; -}; +inline void CopyVisitor::visitCell(JSCell* cell) +{ + ASSERT(cell->structure()->classInfo()->methodTable.copyBackingStore == JSObject::copyBackingStore); + JSObject::copyBackingStore(cell, *this); +} inline bool CopyVisitor::checkIfShouldCopy(void* oldPtr, size_t bytes) { @@ -110,8 +96,8 @@ inline void CopyVisitor::didCopy(void* ptr, size_t bytes) CopiedBlock* block = CopiedSpace::blockFor(ptr); ASSERT(!block->isPinned()); - if (block->didEvacuateBytes(bytes)) - m_shared.m_copiedSpace->recycleEvacuatedBlock(block); + block->didEvacuateBytes(bytes); + } } // namespace JSC diff --git a/Source/JavaScriptCore/heap/CopyWorkList.h b/Source/JavaScriptCore/heap/CopyWorkList.h new file mode 100644 index 000000000..164e2ddce --- /dev/null +++ b/Source/JavaScriptCore/heap/CopyWorkList.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2012 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 CopyWorkList_h +#define CopyWorkList_h + +#include <wtf/Vector.h> + +namespace JSC { + +class JSCell; + +class CopyWorkListSegment : public HeapBlock<CopyWorkListSegment> { +public: + static CopyWorkListSegment* create(DeadBlock* block) + { + return new (NotNull, block) CopyWorkListSegment(block->region()); + } + + size_t size() { return m_size; } + bool isFull() { return reinterpret_cast<char*>(&data()[size()]) >= endOfBlock(); } + JSCell* get(size_t index) { return data()[index]; } + + void append(JSCell* cell) + { + ASSERT(!isFull()); + data()[m_size] = cell; + m_size += 1; + } + + static const size_t blockSize = 512; + +private: + CopyWorkListSegment(Region* region) + : HeapBlock<CopyWorkListSegment>(region) + , m_size(0) + { + } + + JSCell** data() { return reinterpret_cast<JSCell**>(this + 1); } + char* endOfBlock() { return reinterpret_cast<char*>(this) + blockSize; } + + size_t m_size; +}; + +class CopyWorkListIterator { + friend class CopyWorkList; +public: + JSCell* get() { return m_currentSegment->get(m_currentIndex); } + JSCell* operator*() { return get(); } + JSCell* operator->() { return get(); } + + CopyWorkListIterator& operator++() + { + m_currentIndex++; + + if (m_currentIndex >= m_currentSegment->size()) { + m_currentIndex = 0; + m_currentSegment = m_currentSegment->next(); + + ASSERT(!m_currentSegment || m_currentSegment->size()); + } + + return *this; + } + + bool operator==(const CopyWorkListIterator& other) const + { + return m_currentSegment == other.m_currentSegment && m_currentIndex == other.m_currentIndex; + } + + bool operator!=(const CopyWorkListIterator& other) const + { + return !(*this == other); + } + + CopyWorkListIterator() + : m_currentSegment(0) + , m_currentIndex(0) + { + } + +private: + CopyWorkListIterator(CopyWorkListSegment* startSegment, size_t startIndex) + : m_currentSegment(startSegment) + , m_currentIndex(startIndex) + { + } + + CopyWorkListSegment* m_currentSegment; + size_t m_currentIndex; +}; + +class CopyWorkList { +public: + typedef CopyWorkListIterator iterator; + + CopyWorkList(BlockAllocator&); + ~CopyWorkList(); + + void append(JSCell*); + iterator begin(); + iterator end(); + +private: + DoublyLinkedList<CopyWorkListSegment> m_segments; + BlockAllocator& m_blockAllocator; +}; + +inline CopyWorkList::CopyWorkList(BlockAllocator& blockAllocator) + : m_blockAllocator(blockAllocator) +{ +} + +inline CopyWorkList::~CopyWorkList() +{ + while (!m_segments.isEmpty()) + m_blockAllocator.deallocate(CopyWorkListSegment::destroy(m_segments.removeHead())); +} + +inline void CopyWorkList::append(JSCell* cell) +{ + if (m_segments.isEmpty() || m_segments.tail()->isFull()) + m_segments.append(CopyWorkListSegment::create(m_blockAllocator.allocate<CopyWorkListSegment>())); + + ASSERT(!m_segments.tail()->isFull()); + + m_segments.tail()->append(cell); +} + +inline CopyWorkList::iterator CopyWorkList::begin() +{ + return CopyWorkListIterator(m_segments.head(), 0); +} + +inline CopyWorkList::iterator CopyWorkList::end() +{ + return CopyWorkListIterator(); +} + +} // namespace JSC + +#endif // CopyWorkList_h diff --git a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp index f513fafab..5d2e908f1 100644 --- a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp +++ b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp @@ -59,7 +59,6 @@ GCThreadSharedData::GCThreadSharedData(JSGlobalData* globalData) , m_sharedMarkStack(globalData->heap.blockAllocator()) , m_numberOfActiveParallelMarkers(0) , m_parallelMarkersShouldExit(false) - , m_blocksToCopy(globalData->heap.m_blockSnapshot) , m_copyIndex(0) , m_numberOfActiveGCThreads(0) , m_gcThreadsShouldWait(false) @@ -166,7 +165,7 @@ void GCThreadSharedData::didStartCopying() { { SpinLockHolder locker(&m_copyLock); - m_blocksToCopy = m_globalData->heap.m_blockSnapshot; + WTF::copyToVector(m_copiedSpace->m_blockSet, m_blocksToCopy); m_copyIndex = 0; } diff --git a/Source/JavaScriptCore/heap/GCThreadSharedData.h b/Source/JavaScriptCore/heap/GCThreadSharedData.h index b80cc5af2..dbc11b552 100644 --- a/Source/JavaScriptCore/heap/GCThreadSharedData.h +++ b/Source/JavaScriptCore/heap/GCThreadSharedData.h @@ -94,7 +94,7 @@ private: HashSet<void*> m_opaqueRoots; SpinLock m_copyLock; - Vector<MarkedBlock*>& m_blocksToCopy; + Vector<CopiedBlock*> m_blocksToCopy; size_t m_copyIndex; static const size_t s_blockFragmentLength = 32; diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h index 90c9f2ab1..2df365643 100644 --- a/Source/JavaScriptCore/heap/Heap.h +++ b/Source/JavaScriptCore/heap/Heap.h @@ -179,6 +179,7 @@ namespace JSC { private: friend class CodeBlock; + friend class CopiedBlock; friend class GCAwareJITStubRoutine; friend class JITStubRoutine; friend class LLIntOffsetsExtractor; diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h index 53c7de64f..7d16dc2ed 100644 --- a/Source/JavaScriptCore/heap/SlotVisitor.h +++ b/Source/JavaScriptCore/heap/SlotVisitor.h @@ -82,7 +82,7 @@ public: void harvestWeakReferences(); void finalizeUnconditionalFinalizers(); - void copyLater(void*, size_t); + void copyLater(JSCell*, void*, size_t); #if ENABLE(SIMPLE_HEAP_PROFILING) VTableSpectrum m_visitedTypeCounts; diff --git a/Source/JavaScriptCore/heap/SlotVisitorInlines.h b/Source/JavaScriptCore/heap/SlotVisitorInlines.h index ea8126f87..d76ac552a 100644 --- a/Source/JavaScriptCore/heap/SlotVisitorInlines.h +++ b/Source/JavaScriptCore/heap/SlotVisitorInlines.h @@ -26,6 +26,7 @@ #ifndef SlotVisitorInlines_h #define SlotVisitorInlines_h +#include "CopiedBlockInlines.h" #include "CopiedSpaceInlines.h" #include "Options.h" #include "SlotVisitor.h" @@ -160,7 +161,7 @@ inline void SlotVisitor::donateAndDrain() drain(); } -inline void SlotVisitor::copyLater(void* ptr, size_t bytes) +inline void SlotVisitor::copyLater(JSCell* owner, void* ptr, size_t bytes) { if (CopiedSpace::isOversize(bytes)) { m_shared.m_copiedSpace->pin(CopiedSpace::oversizeBlockFor(ptr)); @@ -171,10 +172,7 @@ inline void SlotVisitor::copyLater(void* ptr, size_t bytes) if (block->isPinned()) return; - block->reportLiveBytes(bytes); - - if (!block->shouldEvacuate()) - m_shared.m_copiedSpace->pin(block); + block->reportLiveBytes(owner, bytes); } } // namespace JSC diff --git a/Source/JavaScriptCore/jit/JITDisassembler.cpp b/Source/JavaScriptCore/jit/JITDisassembler.cpp index 35b939913..0ec72e205 100644 --- a/Source/JavaScriptCore/jit/JITDisassembler.cpp +++ b/Source/JavaScriptCore/jit/JITDisassembler.cpp @@ -44,11 +44,11 @@ JITDisassembler::~JITDisassembler() { } -void JITDisassembler::dump(LinkBuffer& linkBuffer) +void JITDisassembler::dump(PrintStream& out, LinkBuffer& linkBuffer) { - dataLogF("Baseline JIT code for CodeBlock %p, instruction count = %u:\n", m_codeBlock, m_codeBlock->instructionCount()); - dataLogF(" Code at [%p, %p):\n", linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()); - dumpDisassembly(linkBuffer, m_startOfCode, m_labelForBytecodeIndexInMainPath[0]); + out.print("Baseline JIT code for CodeBlock ", RawPointer(m_codeBlock), ", instruction count = ", m_codeBlock->instructionCount(), "\n"); + out.print(" Code at [", RawPointer(linkBuffer.debugAddress()), ", ", RawPointer(static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()), "):\n"); + dumpDisassembly(out, linkBuffer, m_startOfCode, m_labelForBytecodeIndexInMainPath[0]); MacroAssembler::Label firstSlowLabel; for (unsigned i = 0; i < m_labelForBytecodeIndexInSlowPath.size(); ++i) { @@ -57,30 +57,35 @@ void JITDisassembler::dump(LinkBuffer& linkBuffer) break; } } - dumpForInstructions(linkBuffer, " ", m_labelForBytecodeIndexInMainPath, firstSlowLabel.isSet() ? firstSlowLabel : m_endOfSlowPath); - dataLogF(" (End Of Main Path)\n"); - dumpForInstructions(linkBuffer, " (S) ", m_labelForBytecodeIndexInSlowPath, m_endOfSlowPath); - dataLogF(" (End Of Slow Path)\n"); + dumpForInstructions(out, linkBuffer, " ", m_labelForBytecodeIndexInMainPath, firstSlowLabel.isSet() ? firstSlowLabel : m_endOfSlowPath); + out.print(" (End Of Main Path)\n"); + dumpForInstructions(out, linkBuffer, " (S) ", m_labelForBytecodeIndexInSlowPath, m_endOfSlowPath); + out.print(" (End Of Slow Path)\n"); + + dumpDisassembly(out, linkBuffer, m_endOfSlowPath, m_endOfCode); +} - dumpDisassembly(linkBuffer, m_endOfSlowPath, m_endOfCode); +void JITDisassembler::dump(LinkBuffer& linkBuffer) +{ + dump(WTF::dataFile(), linkBuffer); } -void JITDisassembler::dumpForInstructions(LinkBuffer& linkBuffer, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel) +void JITDisassembler::dumpForInstructions(PrintStream& out, LinkBuffer& linkBuffer, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel) { for (unsigned i = 0 ; i < labels.size();) { if (!labels[i].isSet()) { i++; continue; } - dataLogF("%s", prefix); + out.print(prefix); m_codeBlock->dump(i); for (unsigned nextIndex = i + 1; ; nextIndex++) { if (nextIndex >= labels.size()) { - dumpDisassembly(linkBuffer, labels[i], endLabel); + dumpDisassembly(out, linkBuffer, labels[i], endLabel); return; } if (labels[nextIndex].isSet()) { - dumpDisassembly(linkBuffer, labels[i], labels[nextIndex]); + dumpDisassembly(out, linkBuffer, labels[i], labels[nextIndex]); i = nextIndex; break; } @@ -88,11 +93,11 @@ void JITDisassembler::dumpForInstructions(LinkBuffer& linkBuffer, const char* pr } } -void JITDisassembler::dumpDisassembly(LinkBuffer& linkBuffer, MacroAssembler::Label from, MacroAssembler::Label to) +void JITDisassembler::dumpDisassembly(PrintStream& out, LinkBuffer& linkBuffer, MacroAssembler::Label from, MacroAssembler::Label to) { CodeLocationLabel fromLocation = linkBuffer.locationOf(from); CodeLocationLabel toLocation = linkBuffer.locationOf(to); - disassemble(fromLocation, bitwise_cast<uintptr_t>(toLocation.executableAddress()) - bitwise_cast<uintptr_t>(fromLocation.executableAddress()), " ", WTF::dataFile()); + disassemble(fromLocation, bitwise_cast<uintptr_t>(toLocation.executableAddress()) - bitwise_cast<uintptr_t>(fromLocation.executableAddress()), " ", out); } } // namespace JSC diff --git a/Source/JavaScriptCore/jit/JITDisassembler.h b/Source/JavaScriptCore/jit/JITDisassembler.h index f8e917d98..ca914748c 100644 --- a/Source/JavaScriptCore/jit/JITDisassembler.h +++ b/Source/JavaScriptCore/jit/JITDisassembler.h @@ -57,10 +57,11 @@ public: void setEndOfCode(MacroAssembler::Label label) { m_endOfCode = label; } void dump(LinkBuffer&); + void dump(PrintStream&, LinkBuffer&); private: - void dumpForInstructions(LinkBuffer&, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel); - void dumpDisassembly(LinkBuffer&, MacroAssembler::Label from, MacroAssembler::Label to); + void dumpForInstructions(PrintStream&, LinkBuffer&, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel); + void dumpDisassembly(PrintStream&, LinkBuffer&, MacroAssembler::Label from, MacroAssembler::Label to); CodeBlock* m_codeBlock; MacroAssembler::Label m_startOfCode; diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp index 07a05b0c9..9db4eba86 100644 --- a/Source/JavaScriptCore/jsc.cpp +++ b/Source/JavaScriptCore/jsc.cpp @@ -540,7 +540,7 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scr Vector<char> scriptBuffer; if (dump) - BytecodeGenerator::setDumpsGeneratedCode(true); + JSC::Options::dumpGeneratedBytecodes() = true; JSGlobalData& globalData = globalObject->globalData(); diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp index 049a51939..cf3cb4e4f 100644 --- a/Source/JavaScriptCore/parser/Parser.cpp +++ b/Source/JavaScriptCore/parser/Parser.cpp @@ -812,6 +812,7 @@ template <FunctionRequirements requirements, bool nameIsInContainingScope, class { AutoPopScopeRef functionScope(this, pushScope()); functionScope->setIsFunction(); + int functionStart = m_token.m_location.startOffset; if (match(IDENT)) { name = m_token.m_data.ident; next(); @@ -865,7 +866,7 @@ template <FunctionRequirements requirements, bool nameIsInContainingScope, class OwnPtr<SourceProviderCacheItem> newInfo; int functionLength = closeBracePos - openBracePos; if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) { - newInfo = adoptPtr(new SourceProviderCacheItem(m_token.m_location.line, closeBracePos)); + newInfo = adoptPtr(new SourceProviderCacheItem(functionStart, m_token.m_location.line, closeBracePos)); functionScope->saveFunctionInfo(newInfo.get()); } diff --git a/Source/JavaScriptCore/parser/SourceProviderCacheItem.h b/Source/JavaScriptCore/parser/SourceProviderCacheItem.h index 9ca121e2a..ec3890560 100644 --- a/Source/JavaScriptCore/parser/SourceProviderCacheItem.h +++ b/Source/JavaScriptCore/parser/SourceProviderCacheItem.h @@ -35,8 +35,9 @@ namespace JSC { class SourceProviderCacheItem { WTF_MAKE_FAST_ALLOCATED; public: - SourceProviderCacheItem(int closeBraceLine, int closeBracePos) - : closeBraceLine(closeBraceLine) + SourceProviderCacheItem(unsigned functionStart, unsigned closeBraceLine, unsigned closeBracePos) + : functionStart(functionStart) + , closeBraceLine(closeBraceLine) , closeBracePos(closeBracePos) { } @@ -59,12 +60,16 @@ public: token.m_location.line = closeBraceLine; return token; } + + unsigned functionStart : 31; + bool needsFullActivation : 1; - int closeBraceLine; - int closeBracePos; - bool usesEval; - bool strictMode; - bool needsFullActivation; + unsigned closeBraceLine : 31; + bool usesEval : 1; + + unsigned closeBracePos : 31; + bool strictMode : 1; + Vector<RefPtr<StringImpl> > usedVariables; Vector<RefPtr<StringImpl> > writtenVariables; }; diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index 564093e33..dc73e04b0 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -129,13 +129,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt size_t count; switch (structure->indexingType()) { - case ALL_UNDECIDED_INDEXING_TYPES: { - currentTarget = 0; - currentSource = 0; - count = 0; - break; - } - + case ALL_UNDECIDED_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_INT32_INDEXING_TYPES: case ALL_DOUBLE_INDEXING_TYPES: { @@ -190,7 +184,7 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but // Mark the properties. visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize); - visitor.copyLater(butterfly->base(preCapacity, propertyCapacity), capacityInBytes); + visitor.copyLater(this, butterfly->base(preCapacity, propertyCapacity), capacityInBytes); // Mark the array if appropriate. switch (structure->indexingType()) { diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h index bd9b90466..f6447d0bd 100644 --- a/Source/JavaScriptCore/runtime/JSValue.h +++ b/Source/JavaScriptCore/runtime/JSValue.h @@ -39,458 +39,458 @@ namespace JSC { // values as being missing, so it is useful to have it abbreviated. #define QNaN (std::numeric_limits<double>::quiet_NaN()) - class ExecState; - class JSCell; - class JSGlobalData; - class JSGlobalObject; - class JSObject; - class JSString; - class PropertyName; - class PropertySlot; - class PutPropertySlot; +class ExecState; +class JSCell; +class JSGlobalData; +class JSGlobalObject; +class JSObject; +class JSString; +class PropertyName; +class PropertySlot; +class PutPropertySlot; #if ENABLE(DFG_JIT) - namespace DFG { - class AssemblyHelpers; - class JITCompiler; - class JITCodeGenerator; - class JSValueSource; - class OSRExitCompiler; - class SpeculativeJIT; - } +namespace DFG { +class AssemblyHelpers; +class JITCompiler; +class JITCodeGenerator; +class JSValueSource; +class OSRExitCompiler; +class SpeculativeJIT; +} #endif #if ENABLE(LLINT_C_LOOP) - namespace LLInt { - class CLoop; - } +namespace LLInt { +class CLoop; +} #endif - struct ClassInfo; - struct Instruction; - struct MethodTable; +struct ClassInfo; +struct Instruction; +struct MethodTable; - template <class T> class WriteBarrierBase; +template <class T> class WriteBarrierBase; - enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString }; +enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString }; - typedef int64_t EncodedJSValue; +typedef int64_t EncodedJSValue; - union EncodedValueDescriptor { - int64_t asInt64; +union EncodedValueDescriptor { + int64_t asInt64; #if USE(JSVALUE32_64) - double asDouble; + double asDouble; #elif USE(JSVALUE64) - JSCell* ptr; + JSCell* ptr; #endif #if CPU(BIG_ENDIAN) - struct { - int32_t tag; - int32_t payload; - } asBits; + struct { + int32_t tag; + int32_t payload; + } asBits; #else - struct { - int32_t payload; - int32_t tag; - } asBits; + struct { + int32_t payload; + int32_t tag; + } asBits; #endif - }; - - // This implements ToInt32, defined in ECMA-262 9.5. - JS_EXPORT_PRIVATE int32_t toInt32(double); - - // This implements ToUInt32, defined in ECMA-262 9.6. - inline uint32_t toUInt32(double number) - { - // As commented in the spec, the operation of ToInt32 and ToUint32 only differ - // in how the result is interpreted; see NOTEs in sections 9.5 and 9.6. - return toInt32(number); - } - - class JSValue { - friend struct EncodedJSValueHashTraits; - friend class JIT; - friend class JITStubs; - friend class JITStubCall; - friend class JSInterfaceJIT; - friend class SpecializedThunkJIT; +}; + +// This implements ToInt32, defined in ECMA-262 9.5. +JS_EXPORT_PRIVATE int32_t toInt32(double); + +// This implements ToUInt32, defined in ECMA-262 9.6. +inline uint32_t toUInt32(double number) +{ + // As commented in the spec, the operation of ToInt32 and ToUint32 only differ + // in how the result is interpreted; see NOTEs in sections 9.5 and 9.6. + return toInt32(number); +} + +class JSValue { + friend struct EncodedJSValueHashTraits; + friend class JIT; + friend class JITStubs; + friend class JITStubCall; + friend class JSInterfaceJIT; + friend class SpecializedThunkJIT; #if ENABLE(DFG_JIT) - friend class DFG::AssemblyHelpers; - friend class DFG::JITCompiler; - friend class DFG::JITCodeGenerator; - friend class DFG::JSValueSource; - friend class DFG::OSRExitCompiler; - friend class DFG::SpeculativeJIT; + friend class DFG::AssemblyHelpers; + friend class DFG::JITCompiler; + friend class DFG::JITCodeGenerator; + friend class DFG::JSValueSource; + friend class DFG::OSRExitCompiler; + friend class DFG::SpeculativeJIT; #endif #if ENABLE(LLINT_C_LOOP) - friend class LLInt::CLoop; + friend class LLInt::CLoop; #endif - public: +public: #if USE(JSVALUE32_64) - enum { Int32Tag = 0xffffffff }; - enum { BooleanTag = 0xfffffffe }; - enum { NullTag = 0xfffffffd }; - enum { UndefinedTag = 0xfffffffc }; - enum { CellTag = 0xfffffffb }; - enum { EmptyValueTag = 0xfffffffa }; - enum { DeletedValueTag = 0xfffffff9 }; - - enum { LowestTag = DeletedValueTag }; + enum { Int32Tag = 0xffffffff }; + enum { BooleanTag = 0xfffffffe }; + enum { NullTag = 0xfffffffd }; + enum { UndefinedTag = 0xfffffffc }; + enum { CellTag = 0xfffffffb }; + enum { EmptyValueTag = 0xfffffffa }; + enum { DeletedValueTag = 0xfffffff9 }; + + enum { LowestTag = DeletedValueTag }; #endif - static EncodedJSValue encode(JSValue); - static JSValue decode(EncodedJSValue); - - enum JSNullTag { JSNull }; - enum JSUndefinedTag { JSUndefined }; - enum JSTrueTag { JSTrue }; - enum JSFalseTag { JSFalse }; - enum EncodeAsDoubleTag { EncodeAsDouble }; - - JSValue(); - JSValue(JSNullTag); - JSValue(JSUndefinedTag); - JSValue(JSTrueTag); - JSValue(JSFalseTag); - JSValue(JSCell* ptr); - JSValue(const JSCell* ptr); - - // Numbers - JSValue(EncodeAsDoubleTag, double); - explicit JSValue(double); - explicit JSValue(char); - explicit JSValue(unsigned char); - explicit JSValue(short); - explicit JSValue(unsigned short); - explicit JSValue(int); - explicit JSValue(unsigned); - explicit JSValue(long); - explicit JSValue(unsigned long); - explicit JSValue(long long); - explicit JSValue(unsigned long long); - - operator bool() const; - bool operator==(const JSValue& other) const; - bool operator!=(const JSValue& other) const; - - bool isInt32() const; - bool isUInt32() const; - bool isDouble() const; - bool isTrue() const; - bool isFalse() const; - - int32_t asInt32() const; - uint32_t asUInt32() const; - double asDouble() const; - bool asBoolean() const; - double asNumber() const; - - // Querying the type. - bool isEmpty() const; - bool isFunction() const; - bool isUndefined() const; - bool isNull() const; - bool isUndefinedOrNull() const; - bool isBoolean() const; - bool isNumber() const; - bool isString() const; - bool isPrimitive() const; - bool isGetterSetter() const; - bool isObject() const; - bool inherits(const ClassInfo*) const; + static EncodedJSValue encode(JSValue); + static JSValue decode(EncodedJSValue); + + enum JSNullTag { JSNull }; + enum JSUndefinedTag { JSUndefined }; + enum JSTrueTag { JSTrue }; + enum JSFalseTag { JSFalse }; + enum EncodeAsDoubleTag { EncodeAsDouble }; + + JSValue(); + JSValue(JSNullTag); + JSValue(JSUndefinedTag); + JSValue(JSTrueTag); + JSValue(JSFalseTag); + JSValue(JSCell* ptr); + JSValue(const JSCell* ptr); + + // Numbers + JSValue(EncodeAsDoubleTag, double); + explicit JSValue(double); + explicit JSValue(char); + explicit JSValue(unsigned char); + explicit JSValue(short); + explicit JSValue(unsigned short); + explicit JSValue(int); + explicit JSValue(unsigned); + explicit JSValue(long); + explicit JSValue(unsigned long); + explicit JSValue(long long); + explicit JSValue(unsigned long long); + + operator bool() const; + bool operator==(const JSValue& other) const; + bool operator!=(const JSValue& other) const; + + bool isInt32() const; + bool isUInt32() const; + bool isDouble() const; + bool isTrue() const; + bool isFalse() const; + + int32_t asInt32() const; + uint32_t asUInt32() const; + double asDouble() const; + bool asBoolean() const; + double asNumber() const; + + // Querying the type. + bool isEmpty() const; + bool isFunction() const; + bool isUndefined() const; + bool isNull() const; + bool isUndefinedOrNull() const; + bool isBoolean() const; + bool isNumber() const; + bool isString() const; + bool isPrimitive() const; + bool isGetterSetter() const; + bool isObject() const; + bool inherits(const ClassInfo*) const; - // Extracting the value. - bool getString(ExecState*, WTF::String&) const; - WTF::String getString(ExecState*) const; // null string if not a string - JSObject* getObject() const; // 0 if not an object + // Extracting the value. + bool getString(ExecState*, WTF::String&) const; + WTF::String getString(ExecState*) const; // null string if not a string + JSObject* getObject() const; // 0 if not an object - // Extracting integer values. - bool getUInt32(uint32_t&) const; + // Extracting integer values. + bool getUInt32(uint32_t&) const; - // Basic conversions. - JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; - bool getPrimitiveNumber(ExecState*, double& number, JSValue&); - - bool toBoolean(ExecState*) const; - - // toNumber conversion is expected to be side effect free if an exception has - // been set in the ExecState already. - double toNumber(ExecState*) const; - JSString* toString(ExecState*) const; - WTF::String toWTFString(ExecState*) const; - WTF::String toWTFStringInline(ExecState*) const; - JSObject* toObject(ExecState*) const; - JSObject* toObject(ExecState*, JSGlobalObject*) const; - - // Integer conversions. - JS_EXPORT_PRIVATE double toInteger(ExecState*) const; - double toIntegerPreserveNaN(ExecState*) const; - int32_t toInt32(ExecState*) const; - uint32_t toUInt32(ExecState*) const; - - // Floating point conversions (this is a convenience method for webcore; - // signle precision float is not a representation used in JS or JSC). - float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); } - - // Object operations, with the toObject operation included. - JSValue get(ExecState*, PropertyName) const; - JSValue get(ExecState*, PropertyName, PropertySlot&) const; - JSValue get(ExecState*, unsigned propertyName) const; - JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const; - void put(ExecState*, PropertyName, JSValue, PutPropertySlot&); - void putToPrimitive(ExecState*, PropertyName, JSValue, PutPropertySlot&); - void putToPrimitiveByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - void putByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - - JSObject* toThisObject(ExecState*) const; - - static bool equal(ExecState* exec, JSValue v1, JSValue v2); - static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2); - static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); - static bool strictEqual(ExecState* exec, JSValue v1, JSValue v2); - static bool strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2); - static bool strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); - - bool isCell() const; - JSCell* asCell() const; - JS_EXPORT_PRIVATE bool isValidCallee(); + // Basic conversions. + JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; + bool getPrimitiveNumber(ExecState*, double& number, JSValue&); + + bool toBoolean(ExecState*) const; + + // toNumber conversion is expected to be side effect free if an exception has + // been set in the ExecState already. + double toNumber(ExecState*) const; + JSString* toString(ExecState*) const; + WTF::String toWTFString(ExecState*) const; + WTF::String toWTFStringInline(ExecState*) const; + JSObject* toObject(ExecState*) const; + JSObject* toObject(ExecState*, JSGlobalObject*) const; + + // Integer conversions. + JS_EXPORT_PRIVATE double toInteger(ExecState*) const; + double toIntegerPreserveNaN(ExecState*) const; + int32_t toInt32(ExecState*) const; + uint32_t toUInt32(ExecState*) const; + + // Floating point conversions (this is a convenience method for webcore; + // signle precision float is not a representation used in JS or JSC). + float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); } + + // Object operations, with the toObject operation included. + JSValue get(ExecState*, PropertyName) const; + JSValue get(ExecState*, PropertyName, PropertySlot&) const; + JSValue get(ExecState*, unsigned propertyName) const; + JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const; + void put(ExecState*, PropertyName, JSValue, PutPropertySlot&); + void putToPrimitive(ExecState*, PropertyName, JSValue, PutPropertySlot&); + void putToPrimitiveByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + void putByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + + JSObject* toThisObject(ExecState*) const; + + static bool equal(ExecState* exec, JSValue v1, JSValue v2); + static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2); + static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); + static bool strictEqual(ExecState* exec, JSValue v1, JSValue v2); + static bool strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2); + static bool strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); + + bool isCell() const; + JSCell* asCell() const; + JS_EXPORT_PRIVATE bool isValidCallee(); - JSValue structureOrUndefined() const; + JSValue structureOrUndefined() const; - JS_EXPORT_PRIVATE char* description() const; + JS_EXPORT_PRIVATE char* description() const; - JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const; + JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const; - private: - template <class T> JSValue(WriteBarrierBase<T>); +private: + template <class T> JSValue(WriteBarrierBase<T>); - enum HashTableDeletedValueTag { HashTableDeletedValue }; - JSValue(HashTableDeletedValueTag); + enum HashTableDeletedValueTag { HashTableDeletedValue }; + JSValue(HashTableDeletedValueTag); - inline const JSValue asValue() const { return *this; } - JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const; - JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*) const; - JS_EXPORT_PRIVATE WTF::String toWTFStringSlowCase(ExecState*) const; - JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const; - JS_EXPORT_PRIVATE JSObject* toThisObjectSlowCase(ExecState*) const; + inline const JSValue asValue() const { return *this; } + JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const; + JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*) const; + JS_EXPORT_PRIVATE WTF::String toWTFStringSlowCase(ExecState*) const; + JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const; + JS_EXPORT_PRIVATE JSObject* toThisObjectSlowCase(ExecState*) const; #if USE(JSVALUE32_64) - /* - * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded - * form for immediates. - * - * The encoding makes use of unused NaN space in the IEEE754 representation. Any value - * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values - * can encode a 51-bit payload. Hardware produced and C-library payloads typically - * have a payload of zero. We assume that non-zero payloads are available to encode - * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are - * all set represents a NaN with a non-zero payload, we can use this space in the NaN - * ranges to encode other values (however there are also other ranges of NaN space that - * could have been selected). - * - * For JSValues that do not contain a double value, the high 32 bits contain the tag - * values listed in the enums below, which all correspond to NaN-space. In the case of - * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer - * integer or boolean value; in the case of all other tags the payload is 0. - */ - uint32_t tag() const; - int32_t payload() const; + /* + * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded + * form for immediates. + * + * The encoding makes use of unused NaN space in the IEEE754 representation. Any value + * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values + * can encode a 51-bit payload. Hardware produced and C-library payloads typically + * have a payload of zero. We assume that non-zero payloads are available to encode + * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are + * all set represents a NaN with a non-zero payload, we can use this space in the NaN + * ranges to encode other values (however there are also other ranges of NaN space that + * could have been selected). + * + * For JSValues that do not contain a double value, the high 32 bits contain the tag + * values listed in the enums below, which all correspond to NaN-space. In the case of + * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer + * integer or boolean value; in the case of all other tags the payload is 0. + */ + uint32_t tag() const; + int32_t payload() const; #if ENABLE(LLINT_C_LOOP) - // This should only be used by the LLInt C Loop interpreter who needs - // synthesize JSValue from its "register"s holding tag and payload - // values. - explicit JSValue(int32_t tag, int32_t payload); + // This should only be used by the LLInt C Loop interpreter who needs + // synthesize JSValue from its "register"s holding tag and payload + // values. + explicit JSValue(int32_t tag, int32_t payload); #endif #elif USE(JSVALUE64) - /* - * On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded - * form for immediates. - * - * The encoding makes use of unused NaN space in the IEEE754 representation. Any value - * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values - * can encode a 51-bit payload. Hardware produced and C-library payloads typically - * have a payload of zero. We assume that non-zero payloads are available to encode - * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are - * all set represents a NaN with a non-zero payload, we can use this space in the NaN - * ranges to encode other values (however there are also other ranges of NaN space that - * could have been selected). - * - * This range of NaN space is represented by 64-bit numbers begining with the 16-bit - * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision - * numbers will begin fall in these ranges. - * - * The top 16-bits denote the type of the encoded JSValue: - * - * Pointer { 0000:PPPP:PPPP:PPPP - * / 0001:****:****:**** - * Double { ... - * \ FFFE:****:****:**** - * Integer { FFFF:0000:IIII:IIII - * - * The scheme we have implemented encodes double precision values by performing a - * 64-bit integer addition of the value 2^48 to the number. After this manipulation - * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF. - * Values must be decoded by reversing this operation before subsequent floating point - * operations my be peformed. - * - * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. - * - * The tag 0x0000 denotes a pointer, or another form of tagged immediate. Boolean, - * null and undefined values are represented by specific, invalid pointer values: - * - * False: 0x06 - * True: 0x07 - * Undefined: 0x0a - * Null: 0x02 - * - * These values have the following properties: - * - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be - * quickly distinguished from all immediate values, including these invalid pointers. - * - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the - * same value, allowing null & undefined to be quickly detected. - * - * No valid JSValue will have the bit pattern 0x0, this is used to represent array - * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0). - */ - - // These values are #defines since using static const integers here is a ~1% regression! - - // This value is 2^48, used to encode doubles such that the encoded value will begin - // with a 16-bit pattern within the range 0x0001..0xFFFE. - #define DoubleEncodeOffset 0x1000000000000ll - // If all bits in the mask are set, this indicates an integer number, - // if any but not all are set this value is a double precision number. - #define TagTypeNumber 0xffff000000000000ll - - // All non-numeric (bool, null, undefined) immediates have bit 2 set. - #define TagBitTypeOther 0x2ll - #define TagBitBool 0x4ll - #define TagBitUndefined 0x8ll - // Combined integer value for non-numeric immediates. - #define ValueFalse (TagBitTypeOther | TagBitBool | false) - #define ValueTrue (TagBitTypeOther | TagBitBool | true) - #define ValueUndefined (TagBitTypeOther | TagBitUndefined) - #define ValueNull (TagBitTypeOther) - - // TagMask is used to check for all types of immediate values (either number or 'other'). - #define TagMask (TagTypeNumber | TagBitTypeOther) - - // These special values are never visible to JavaScript code; Empty is used to represent - // Array holes, and for uninitialized JSValues. Deleted is used in hash table code. - // These values would map to cell types in the JSValue encoding, but not valid GC cell - // pointer should have either of these values (Empty is null, deleted is at an invalid - // alignment for a GC cell, and in the zero page). - #define ValueEmpty 0x0ll - #define ValueDeleted 0x4ll + /* + * On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded + * form for immediates. + * + * The encoding makes use of unused NaN space in the IEEE754 representation. Any value + * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values + * can encode a 51-bit payload. Hardware produced and C-library payloads typically + * have a payload of zero. We assume that non-zero payloads are available to encode + * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are + * all set represents a NaN with a non-zero payload, we can use this space in the NaN + * ranges to encode other values (however there are also other ranges of NaN space that + * could have been selected). + * + * This range of NaN space is represented by 64-bit numbers begining with the 16-bit + * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision + * numbers will begin fall in these ranges. + * + * The top 16-bits denote the type of the encoded JSValue: + * + * Pointer { 0000:PPPP:PPPP:PPPP + * / 0001:****:****:**** + * Double { ... + * \ FFFE:****:****:**** + * Integer { FFFF:0000:IIII:IIII + * + * The scheme we have implemented encodes double precision values by performing a + * 64-bit integer addition of the value 2^48 to the number. After this manipulation + * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF. + * Values must be decoded by reversing this operation before subsequent floating point + * operations my be peformed. + * + * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. + * + * The tag 0x0000 denotes a pointer, or another form of tagged immediate. Boolean, + * null and undefined values are represented by specific, invalid pointer values: + * + * False: 0x06 + * True: 0x07 + * Undefined: 0x0a + * Null: 0x02 + * + * These values have the following properties: + * - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be + * quickly distinguished from all immediate values, including these invalid pointers. + * - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the + * same value, allowing null & undefined to be quickly detected. + * + * No valid JSValue will have the bit pattern 0x0, this is used to represent array + * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0). + */ + + // These values are #defines since using static const integers here is a ~1% regression! + + // This value is 2^48, used to encode doubles such that the encoded value will begin + // with a 16-bit pattern within the range 0x0001..0xFFFE. + #define DoubleEncodeOffset 0x1000000000000ll + // If all bits in the mask are set, this indicates an integer number, + // if any but not all are set this value is a double precision number. + #define TagTypeNumber 0xffff000000000000ll + + // All non-numeric (bool, null, undefined) immediates have bit 2 set. + #define TagBitTypeOther 0x2ll + #define TagBitBool 0x4ll + #define TagBitUndefined 0x8ll + // Combined integer value for non-numeric immediates. + #define ValueFalse (TagBitTypeOther | TagBitBool | false) + #define ValueTrue (TagBitTypeOther | TagBitBool | true) + #define ValueUndefined (TagBitTypeOther | TagBitUndefined) + #define ValueNull (TagBitTypeOther) + + // TagMask is used to check for all types of immediate values (either number or 'other'). + #define TagMask (TagTypeNumber | TagBitTypeOther) + + // These special values are never visible to JavaScript code; Empty is used to represent + // Array holes, and for uninitialized JSValues. Deleted is used in hash table code. + // These values would map to cell types in the JSValue encoding, but not valid GC cell + // pointer should have either of these values (Empty is null, deleted is at an invalid + // alignment for a GC cell, and in the zero page). + #define ValueEmpty 0x0ll + #define ValueDeleted 0x4ll #endif - EncodedValueDescriptor u; - }; + EncodedValueDescriptor u; +}; - typedef IntHash<EncodedJSValue> EncodedJSValueHash; +typedef IntHash<EncodedJSValue> EncodedJSValueHash; #if USE(JSVALUE32_64) - struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { - static const bool emptyValueIsZero = false; - static EncodedJSValue emptyValue() { return JSValue::encode(JSValue()); } - static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } - static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } - }; +struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { + static const bool emptyValueIsZero = false; + static EncodedJSValue emptyValue() { return JSValue::encode(JSValue()); } + static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } + static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } +}; #else - struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { - static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } - static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } - }; +struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { + static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } + static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } +}; #endif - typedef HashMap<EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits> JSValueMap; - - // Stand-alone helper functions. - inline JSValue jsNull() - { - return JSValue(JSValue::JSNull); - } - - inline JSValue jsUndefined() - { - return JSValue(JSValue::JSUndefined); - } - - inline JSValue jsBoolean(bool b) - { - return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse); - } - - ALWAYS_INLINE JSValue jsDoubleNumber(double d) - { - ASSERT(JSValue(JSValue::EncodeAsDouble, d).isNumber()); - return JSValue(JSValue::EncodeAsDouble, d); - } - - ALWAYS_INLINE JSValue jsNumber(double d) - { - ASSERT(JSValue(d).isNumber()); - return JSValue(d); - } - - ALWAYS_INLINE JSValue jsNumber(char i) - { - return JSValue(i); - } - - ALWAYS_INLINE JSValue jsNumber(unsigned char i) - { - return JSValue(i); - } - - ALWAYS_INLINE JSValue jsNumber(short i) - { - return JSValue(i); - } - - ALWAYS_INLINE JSValue jsNumber(unsigned short i) - { - return JSValue(i); - } - - ALWAYS_INLINE JSValue jsNumber(int i) - { - return JSValue(i); - } - - ALWAYS_INLINE JSValue jsNumber(unsigned i) - { - return JSValue(i); - } - - ALWAYS_INLINE JSValue jsNumber(long i) - { - return JSValue(i); - } - - ALWAYS_INLINE JSValue jsNumber(unsigned long i) - { - return JSValue(i); - } - - ALWAYS_INLINE JSValue jsNumber(long long i) - { - return JSValue(i); - } - - ALWAYS_INLINE JSValue jsNumber(unsigned long long i) - { - return JSValue(i); - } - - inline bool operator==(const JSValue a, const JSCell* b) { return a == JSValue(b); } - inline bool operator==(const JSCell* a, const JSValue b) { return JSValue(a) == b; } - - inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); } - inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; } +typedef HashMap<EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits> JSValueMap; + +// Stand-alone helper functions. +inline JSValue jsNull() +{ + return JSValue(JSValue::JSNull); +} + +inline JSValue jsUndefined() +{ + return JSValue(JSValue::JSUndefined); +} + +inline JSValue jsBoolean(bool b) +{ + return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse); +} + +ALWAYS_INLINE JSValue jsDoubleNumber(double d) +{ + ASSERT(JSValue(JSValue::EncodeAsDouble, d).isNumber()); + return JSValue(JSValue::EncodeAsDouble, d); +} + +ALWAYS_INLINE JSValue jsNumber(double d) +{ + ASSERT(JSValue(d).isNumber()); + return JSValue(d); +} + +ALWAYS_INLINE JSValue jsNumber(char i) +{ + return JSValue(i); +} + +ALWAYS_INLINE JSValue jsNumber(unsigned char i) +{ + return JSValue(i); +} + +ALWAYS_INLINE JSValue jsNumber(short i) +{ + return JSValue(i); +} + +ALWAYS_INLINE JSValue jsNumber(unsigned short i) +{ + return JSValue(i); +} + +ALWAYS_INLINE JSValue jsNumber(int i) +{ + return JSValue(i); +} + +ALWAYS_INLINE JSValue jsNumber(unsigned i) +{ + return JSValue(i); +} + +ALWAYS_INLINE JSValue jsNumber(long i) +{ + return JSValue(i); +} + +ALWAYS_INLINE JSValue jsNumber(unsigned long i) +{ + return JSValue(i); +} + +ALWAYS_INLINE JSValue jsNumber(long long i) +{ + return JSValue(i); +} + +ALWAYS_INLINE JSValue jsNumber(unsigned long long i) +{ + return JSValue(i); +} + +inline bool operator==(const JSValue a, const JSCell* b) { return a == JSValue(b); } +inline bool operator==(const JSCell* a, const JSValue b) { return JSValue(a) == b; } + +inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); } +inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h index 99a5f85a2..5ad30bde3 100644 --- a/Source/JavaScriptCore/runtime/Options.h +++ b/Source/JavaScriptCore/runtime/Options.h @@ -68,9 +68,12 @@ namespace JSC { \ v(bool, forceDFGCodeBlockLiveness, false) \ \ + v(bool, dumpGeneratedBytecodes, false) \ + \ /* showDisassembly implies showDFGDisassembly. */ \ v(bool, showDisassembly, false) \ v(bool, showDFGDisassembly, false) \ + v(bool, showAllDFGNodes, false) \ \ v(unsigned, maximumOptimizationCandidateInstructionCount, 10000) \ \ diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp index 93009d806..25f989776 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -338,24 +338,26 @@ static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, J return jsString(exec, StringImpl::create(source.impl(), std::max(0, position), std::min(sourceSize, length))); } - int totalLength = 0; - bool allSeperators8Bit = true; + Checked<int, RecordOverflow> totalLength = 0; + bool allSeparators8Bit = true; for (int i = 0; i < rangeCount; i++) totalLength += substringRanges[i].length; for (int i = 0; i < separatorCount; i++) { totalLength += separators[i].length(); if (separators[i].length() && !separators[i].is8Bit()) - allSeperators8Bit = false; + allSeparators8Bit = false; } + if (totalLength.hasOverflowed()) + return throwOutOfMemoryError(exec); if (!totalLength) return jsEmptyString(exec); - if (source.is8Bit() && allSeperators8Bit) { + if (source.is8Bit() && allSeparators8Bit) { LChar* buffer; const LChar* sourceData = source.characters8(); - RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer); + RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength.unsafeGet(), buffer); if (!impl) return throwOutOfMemoryError(exec); @@ -380,7 +382,7 @@ static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, J } UChar* buffer; - RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer); + RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength.unsafeGet(), buffer); if (!impl) return throwOutOfMemoryError(exec); |