summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-11-29 12:18:48 +0100
committerSimon Hausmann <simon.hausmann@digia.com>2012-11-29 12:18:57 +0100
commit4c01d0526ba4dd8cff0c0ff22a6f0ab5eb973064 (patch)
treebed2fe914fe0f7ec70abfb47d2d84af8a3604d09 /Source/JavaScriptCore
parent01485457c9a5da3f1121015afd25bb53af77662e (diff)
downloadqtwebkit-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')
-rw-r--r--Source/JavaScriptCore/CMakeLists.txt1
-rw-r--r--Source/JavaScriptCore/ChangeLog417
-rw-r--r--Source/JavaScriptCore/DerivedSources.pri16
-rw-r--r--Source/JavaScriptCore/GNUmakefile.list.am2
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.pro10
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj16
-rw-r--r--Source/JavaScriptCore/Target.pri1
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssembler.h41
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerARM.h23
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerSH4.h23
-rw-r--r--Source/JavaScriptCore/assembler/SH4Assembler.h17
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.cpp4
-rw-r--r--Source/JavaScriptCore/bytecode/SpeculatedType.cpp80
-rw-r--r--Source/JavaScriptCore/bytecode/SpeculatedType.h7
-rw-r--r--Source/JavaScriptCore/bytecode/ValueProfile.h20
-rw-r--r--Source/JavaScriptCore/bytecode/ValueRecovery.h42
-rw-r--r--Source/JavaScriptCore/bytecode/VirtualRegister.h10
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp13
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h3
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractValue.h11
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp60
-rw-r--r--Source/JavaScriptCore/dfg/DFGDisassembler.cpp33
-rw-r--r--Source/JavaScriptCore/dfg/DFGDisassembler.h3
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.cpp258
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h14
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h8
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp2
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp34
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h44
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp96
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp103
-rw-r--r--Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h8
-rw-r--r--Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.cpp74
-rw-r--r--Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.h56
-rw-r--r--Source/JavaScriptCore/heap/BlockAllocator.cpp2
-rw-r--r--Source/JavaScriptCore/heap/BlockAllocator.h14
-rw-r--r--Source/JavaScriptCore/heap/CopiedBlock.h64
-rw-r--r--Source/JavaScriptCore/heap/CopiedBlockInlines.h54
-rw-r--r--Source/JavaScriptCore/heap/CopiedSpace.h1
-rw-r--r--Source/JavaScriptCore/heap/CopiedSpaceInlines.h2
-rw-r--r--Source/JavaScriptCore/heap/CopyVisitor.cpp28
-rw-r--r--Source/JavaScriptCore/heap/CopyVisitor.h2
-rw-r--r--Source/JavaScriptCore/heap/CopyVisitorInlines.h28
-rw-r--r--Source/JavaScriptCore/heap/CopyWorkList.h165
-rw-r--r--Source/JavaScriptCore/heap/GCThreadSharedData.cpp3
-rw-r--r--Source/JavaScriptCore/heap/GCThreadSharedData.h2
-rw-r--r--Source/JavaScriptCore/heap/Heap.h1
-rw-r--r--Source/JavaScriptCore/heap/SlotVisitor.h2
-rw-r--r--Source/JavaScriptCore/heap/SlotVisitorInlines.h8
-rw-r--r--Source/JavaScriptCore/jit/JITDisassembler.cpp35
-rw-r--r--Source/JavaScriptCore/jit/JITDisassembler.h5
-rw-r--r--Source/JavaScriptCore/jsc.cpp2
-rw-r--r--Source/JavaScriptCore/parser/Parser.cpp3
-rw-r--r--Source/JavaScriptCore/parser/SourceProviderCacheItem.h19
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp10
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.h806
-rw-r--r--Source/JavaScriptCore/runtime/Options.h3
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.cpp14
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);