diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg')
20 files changed, 567 insertions, 104 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 317a08504..75611972e 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -28,6 +28,7 @@ #if ENABLE(DFG_JIT) +#include "ArrayConstructor.h" #include "CallLinkStatus.h" #include "CodeBlock.h" #include "DFGByteCodeCache.h" @@ -35,6 +36,7 @@ #include "GetByIdStatus.h" #include "MethodCallLinkStatus.h" #include "PutByIdStatus.h" +#include "ResolveGlobalStatus.h" #include <wtf/HashMap.h> #include <wtf/MathExtras.h> @@ -94,6 +96,10 @@ private: void setIntrinsicResult(bool usesResult, int resultOperand, NodeIndex); // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call. bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction); + bool handleConstantInternalFunction(bool usesResult, int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind); + void handleGetByOffset( + int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber, + bool useInlineStorage, size_t offset); void handleGetById( int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber, const GetByIdStatus&); @@ -1124,7 +1130,12 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); NodeIndex callTarget = get(currentInstruction[1].u.operand); - enum { ConstantFunction, LinkedFunction, UnknownFunction } callType; + enum { + ConstantFunction, + ConstantInternalFunction, + LinkedFunction, + UnknownFunction + } callType; CallLinkStatus callLinkStatus = CallLinkStatus::computeFor( m_inlineStackTop->m_profiledBlock, m_currentIndex); @@ -1147,6 +1158,13 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn m_graph.valueOfFunctionConstant(callTarget), m_graph.valueOfFunctionConstant(callTarget)->executable()); #endif + } else if (m_graph.isInternalFunctionConstant(callTarget)) { + callType = ConstantInternalFunction; +#if DFG_ENABLE(DEBUG_VERBOSE) + dataLog("Call at [@%lu, bc#%u] has an internal function constant: %p.\n", + m_graph.size(), m_currentIndex, + m_graph.valueOfInternalFunctionConstant(callTarget)); +#endif } else if (callLinkStatus.isSet() && !callLinkStatus.couldTakeSlowPath() && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { callType = LinkedFunction; @@ -1179,6 +1197,16 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn prediction = getPrediction(); nextOffset += OPCODE_LENGTH(op_call_put_result); } + + if (callType == ConstantInternalFunction) { + if (handleConstantInternalFunction(usesResult, resultOperand, m_graph.valueOfInternalFunctionConstant(callTarget), registerOffset, argumentCountIncludingThis, prediction, kind)) + return; + + // Can only handle this using the generic call handler. + addCall(interpreter, currentInstruction, op); + return; + } + JSFunction* expectedFunction; Intrinsic intrinsic; bool certainAboutExpectedFunction; @@ -1210,7 +1238,7 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn } else if (handleInlining(usesResult, currentInstruction[1].u.operand, callTarget, resultOperand, certainAboutExpectedFunction, expectedFunction, registerOffset, argumentCountIncludingThis, nextOffset, kind)) return; } - + addCall(interpreter, currentInstruction, op); } @@ -1567,6 +1595,60 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins } } +bool ByteCodeParser::handleConstantInternalFunction( + bool usesResult, int resultOperand, InternalFunction* function, int registerOffset, + int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind kind) +{ + // If we ever find that we have a lot of internal functions that we specialize for, + // then we should probably have some sort of hashtable dispatch, or maybe even + // dispatch straight through the MethodTable of the InternalFunction. But for now, + // it seems that this case is hit infrequently enough, and the number of functions + // we know about is small enough, that having just a linear cascade of if statements + // is good enough. + + UNUSED_PARAM(registerOffset); // Remove this once we do more things to the arguments. + UNUSED_PARAM(prediction); // Remove this once we do more things. + UNUSED_PARAM(kind); // Remove this once we do more things. + + if (function->classInfo() == &ArrayConstructor::s_info) { + // We could handle this but don't for now. + if (argumentCountIncludingThis != 1) + return false; + + setIntrinsicResult( + usesResult, resultOperand, + addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0))); + return true; + } + + return false; +} + +void ByteCodeParser::handleGetByOffset( + int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber, + bool useInlineStorage, size_t offset) +{ + NodeIndex propertyStorage; + size_t offsetOffset; + if (useInlineStorage) { + propertyStorage = base; + ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue))); + offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue); + } else { + propertyStorage = addToGraph(GetPropertyStorage, base); + offsetOffset = 0; + } + set(destinationOperand, + addToGraph( + GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), + propertyStorage)); + + StorageAccessData storageAccessData; + storageAccessData.offset = offset + offsetOffset; + storageAccessData.identifierNumber = identifierNumber; + m_graph.m_storageAccessData.append(storageAccessData); +} + void ByteCodeParser::handleGetById( int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber, const GetByIdStatus& getByIdStatus) @@ -1620,25 +1702,9 @@ void ByteCodeParser::handleGetById( return; } - NodeIndex propertyStorage; - size_t offsetOffset; - if (useInlineStorage) { - propertyStorage = base; - ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue))); - offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue); - } else { - propertyStorage = addToGraph(GetPropertyStorage, base); - offsetOffset = 0; - } - set(destinationOperand, - addToGraph( - GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), - propertyStorage)); - - StorageAccessData storageAccessData; - storageAccessData.offset = getByIdStatus.offset() + offsetOffset; - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); + handleGetByOffset( + destinationOperand, prediction, base, identifierNumber, useInlineStorage, + getByIdStatus.offset()); } void ByteCodeParser::prepareToParseBlock() @@ -2648,10 +2714,39 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_resolve_global: { SpeculatedType prediction = getPrediction(); + unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[ + currentInstruction[2].u.operand]; + + ResolveGlobalStatus status = ResolveGlobalStatus::computeFor( + m_inlineStackTop->m_profiledBlock, m_currentIndex, + m_codeBlock->identifier(identifierNumber)); + if (status.isSimple()) { + ASSERT(status.structure()); + + NodeIndex globalObject = addStructureTransitionCheck( + m_inlineStackTop->m_codeBlock->globalObject(), status.structure()); + + if (status.specificValue()) { + ASSERT(status.specificValue().isCell()); + + set(currentInstruction[1].u.operand, + cellConstant(status.specificValue().asCell())); + } else { + handleGetByOffset( + currentInstruction[1].u.operand, prediction, globalObject, + identifierNumber, status.structure()->isUsingInlineStorage(), + status.offset()); + } + + m_globalResolveNumber++; // Skip over the unused global resolve info. + + NEXT_OPCODE(op_resolve_global); + } + NodeIndex resolve = addToGraph(ResolveGlobal, OpInfo(m_graph.m_resolveGlobalData.size()), OpInfo(prediction)); m_graph.m_resolveGlobalData.append(ResolveGlobalData()); ResolveGlobalData& data = m_graph.m_resolveGlobalData.last(); - data.identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; + data.identifierNumber = identifierNumber; data.resolveInfoIndex = m_globalResolveNumber++; set(currentInstruction[1].u.operand, resolve); @@ -3077,6 +3172,8 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry( } m_constantRemap[i] = result.iterator->second; } + for (unsigned i = 0; i < codeBlock->numberOfGlobalResolveInfos(); ++i) + byteCodeParser->m_codeBlock->addGlobalResolveInfo(std::numeric_limits<unsigned>::max()); m_callsiteBlockHeadNeedsLinking = true; } else { @@ -3160,6 +3257,9 @@ void ByteCodeParser::parseCodeBlock() ASSERT(m_inlineStackTop->m_unlinkedBlocks.isEmpty() || m_graph.m_blocks[m_inlineStackTop->m_unlinkedBlocks.last().m_blockIndex]->bytecodeBegin < m_currentIndex); m_inlineStackTop->m_unlinkedBlocks.append(UnlinkedBlock(m_graph.m_blocks.size())); m_inlineStackTop->m_blockLinkingTargets.append(m_graph.m_blocks.size()); + // The first block is definitely an OSR target. + if (!m_graph.m_blocks.size()) + block->isOSRTarget = true; m_graph.m_blocks.append(block.release()); prepareToParseBlock(); } diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.h b/Source/JavaScriptCore/dfg/DFGCapabilities.h index 027b0f78b..1aec0bca1 100644 --- a/Source/JavaScriptCore/dfg/DFGCapabilities.h +++ b/Source/JavaScriptCore/dfg/DFGCapabilities.h @@ -193,7 +193,6 @@ inline bool canInlineOpcode(OpcodeID opcodeID, CodeBlock* codeBlock, Instruction case op_put_scoped_var: case op_resolve: case op_resolve_base: - case op_resolve_global: // Constant buffers aren't copied correctly. This is easy to fix, but for // now we just disable inlining for functions that use them. diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h index fce76c68c..c9d3cbc32 100644 --- a/Source/JavaScriptCore/dfg/DFGCommon.h +++ b/Source/JavaScriptCore/dfg/DFGCommon.h @@ -134,6 +134,11 @@ enum NoResultTag { NoResult }; enum OptimizationFixpointState { FixpointConverged, FixpointNotConverged }; +inline bool shouldShowDisassembly() +{ + return Options::showDisassembly || Options::showDFGDisassembly; +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/Source/JavaScriptCore/dfg/DFGDisassembler.cpp b/Source/JavaScriptCore/dfg/DFGDisassembler.cpp new file mode 100644 index 000000000..1dde37cf2 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGDisassembler.cpp @@ -0,0 +1,115 @@ +/* + * 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 "DFGDisassembler.h" + +#if ENABLE(DFG_JIT) + +#include "DFGGraph.h" + +namespace JSC { namespace DFG { + +Disassembler::Disassembler(Graph& graph) + : m_graph(graph) +{ + m_labelForBlockIndex.resize(graph.m_blocks.size()); + m_labelForNodeIndex.resize(graph.size()); +} + +void Disassembler::dump(LinkBuffer& linkBuffer) +{ + m_graph.m_dominators.computeIfNecessary(m_graph); + + dataLog("Generated JIT code for DFG CodeBlock %p:\n", m_graph.m_codeBlock); + dataLog(" Code at [%p, %p):\n", linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()); + + const char* prefix = " "; + const char* disassemblyPrefix = " "; + + NodeIndex lastNodeIndex = NoNode; + MacroAssembler::Label previousLabel = m_startOfCode; + for (size_t blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { + 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); + NodeIndex lastNodeIndexForDisassembly = block->at(0); + for (size_t i = 0; i < block->size(); ++i) { + if (!m_graph[block->at(i)].willHaveCodeGen()) + continue; + MacroAssembler::Label currentLabel; + if (m_labelForNodeIndex[block->at(i)].isSet()) + currentLabel = m_labelForNodeIndex[block->at(i)]; + else { + // Dump the last instruction by using the first label of the next block + // as the end point. This case is hit either during peephole compare + // optimizations (the Branch won't have its own label) or if we have a + // forced OSR exit. + if (blockIndex + 1 < m_graph.m_blocks.size()) + currentLabel = m_labelForBlockIndex[blockIndex + 1]; + 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)); + lastNodeIndex = block->at(i); + lastNodeIndexForDisassembly = block->at(i); + } + } + dumpDisassembly(disassemblyPrefix, linkBuffer, previousLabel, m_endOfMainPath, lastNodeIndex); + dataLog("%s(End Of Main Path)\n", prefix); + dumpDisassembly(disassemblyPrefix, linkBuffer, previousLabel, m_endOfCode, NoNode); +} + +void Disassembler::dumpDisassembly(const char* prefix, LinkBuffer& linkBuffer, MacroAssembler::Label& previousLabel, MacroAssembler::Label currentLabel, NodeIndex context) +{ + size_t prefixLength = strlen(prefix); + int amountOfNodeWhiteSpace; + if (context == NoNode) + amountOfNodeWhiteSpace = 0; + else + amountOfNodeWhiteSpace = Graph::amountOfNodeWhiteSpace(m_graph[context]); + OwnArrayPtr<char> prefixBuffer = adoptArrayPtr(new char[prefixLength + amountOfNodeWhiteSpace + 1]); + strcpy(prefixBuffer.get(), prefix); + for (int i = 0; i < amountOfNodeWhiteSpace; ++i) + prefixBuffer[i + prefixLength] = ' '; + prefixBuffer[prefixLength + amountOfNodeWhiteSpace] = 0; + + CodeLocationLabel start = linkBuffer.locationOf(previousLabel); + CodeLocationLabel end = linkBuffer.locationOf(currentLabel); + previousLabel = currentLabel; + ASSERT(bitwise_cast<uintptr_t>(end.executableAddress()) >= bitwise_cast<uintptr_t>(start.executableAddress())); + if (tryToDisassemble(start, bitwise_cast<uintptr_t>(end.executableAddress()) - bitwise_cast<uintptr_t>(start.executableAddress()), prefixBuffer.get(), WTF::dataFile())) + return; + + dataLog("%s disassembly not available for range %p...%p\n", prefixBuffer.get(), start.executableAddress(), end.executableAddress()); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) diff --git a/Source/JavaScriptCore/dfg/DFGDisassembler.h b/Source/JavaScriptCore/dfg/DFGDisassembler.h new file mode 100644 index 000000000..470a989ef --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGDisassembler.h @@ -0,0 +1,82 @@ +/* + * 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 DFGDisassembler_h +#define DFGDisassembler_h + +#include <wtf/Platform.h> + +#if ENABLE(DFG_JIT) + +#include "DFGCommon.h" +#include "LinkBuffer.h" +#include "MacroAssembler.h" +#include <wtf/Vector.h> + +namespace JSC { namespace DFG { + +class Graph; + +class Disassembler { + WTF_MAKE_FAST_ALLOCATED; +public: + Disassembler(Graph&); + + void setStartOfCode(MacroAssembler::Label label) { m_startOfCode = label; } + void setForBlock(BlockIndex blockIndex, MacroAssembler::Label label) + { + m_labelForBlockIndex[blockIndex] = label; + } + void setForNode(NodeIndex nodeIndex, MacroAssembler::Label label) + { + m_labelForNodeIndex[nodeIndex] = label; + } + void setEndOfMainPath(MacroAssembler::Label label) + { + m_endOfMainPath = label; + } + void setEndOfCode(MacroAssembler::Label label) + { + m_endOfCode = label; + } + + void dump(LinkBuffer&); + +private: + void dumpDisassembly(const char* prefix, LinkBuffer&, MacroAssembler::Label& previousLabel, MacroAssembler::Label currentLabel, NodeIndex context); + + Graph& m_graph; + MacroAssembler::Label m_startOfCode; + Vector<MacroAssembler::Label> m_labelForBlockIndex; + Vector<MacroAssembler::Label> m_labelForNodeIndex; + MacroAssembler::Label m_endOfMainPath; + MacroAssembler::Label m_endOfCode; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGDisassembler_h diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp index e932792df..5033aa2c0 100644 --- a/Source/JavaScriptCore/dfg/DFGDriver.cpp +++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp @@ -43,11 +43,20 @@ namespace JSC { namespace DFG { +static unsigned numCompilations; + +unsigned getNumCompilations() +{ + return numCompilations; +} + enum CompileMode { CompileFunction, CompileOther }; inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr* jitCodeWithArityCheck) { SamplingRegion samplingRegion("DFG Compilation (Driver)"); + numCompilations++; + ASSERT(codeBlock); ASSERT(codeBlock->alternative()); ASSERT(codeBlock->alternative()->getJITType() == JITCode::BaselineJIT); @@ -92,7 +101,6 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("DFG optimization fixpoint converged in %u iterations.\n", cnt); #endif - dfg.m_dominators.compute(dfg); performVirtualRegisterAllocation(dfg); GraphDumpMode modeForFinalValidate = DumpGraph; diff --git a/Source/JavaScriptCore/dfg/DFGDriver.h b/Source/JavaScriptCore/dfg/DFGDriver.h index ce798d0a6..a6e82fef5 100644 --- a/Source/JavaScriptCore/dfg/DFGDriver.h +++ b/Source/JavaScriptCore/dfg/DFGDriver.h @@ -38,6 +38,8 @@ class MacroAssemblerCodePtr; namespace DFG { +JS_EXPORT_PRIVATE unsigned getNumCompilations(); + #if ENABLE(DFG_JIT) bool tryCompile(ExecState*, CodeBlock*, JITCode&); bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr& jitCodeWithArityCheck); diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index 93de024d7..4689470c8 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -89,7 +89,7 @@ static void printWhiteSpace(unsigned amount) dataLog(" "); } -void Graph::dumpCodeOrigin(NodeIndex prevNodeIndex, NodeIndex nodeIndex) +void Graph::dumpCodeOrigin(const char* prefix, NodeIndex prevNodeIndex, NodeIndex nodeIndex) { if (prevNodeIndex == NoNode) return; @@ -112,18 +112,30 @@ void Graph::dumpCodeOrigin(NodeIndex prevNodeIndex, NodeIndex nodeIndex) // Print the pops. for (unsigned i = previousInlineStack.size(); i-- > indexOfDivergence;) { + dataLog("%s", prefix); printWhiteSpace(i * 2); dataLog("<-- %p\n", previousInlineStack[i].inlineCallFrame->executable.get()); } // Print the pushes. for (unsigned i = indexOfDivergence; i < currentInlineStack.size(); ++i) { + dataLog("%s", prefix); printWhiteSpace(i * 2); dataLog("--> %p\n", currentInlineStack[i].inlineCallFrame->executable.get()); } } -void Graph::dump(NodeIndex nodeIndex) +int Graph::amountOfNodeWhiteSpace(Node& node) +{ + return (node.codeOrigin.inlineDepth() - 1) * 2; +} + +void Graph::printNodeWhiteSpace(Node& node) +{ + printWhiteSpace(amountOfNodeWhiteSpace(node)); +} + +void Graph::dump(const char* prefix, NodeIndex nodeIndex) { Node& node = at(nodeIndex); NodeType op = node.op(); @@ -134,7 +146,8 @@ void Graph::dump(NodeIndex nodeIndex) if (mustGenerate) --refCount; - printWhiteSpace((node.codeOrigin.inlineDepth() - 1) * 2); + dataLog("%s", prefix); + printNodeWhiteSpace(node); // Example/explanation of dataflow dump output // @@ -288,6 +301,54 @@ void Graph::dump(NodeIndex nodeIndex) dataLog("\n"); } +void Graph::dumpBlockHeader(const char* prefix, BlockIndex blockIndex, PhiNodeDumpMode phiNodeDumpMode) +{ + BasicBlock* block = m_blocks[blockIndex].get(); + + dataLog("%sBlock #%u (bc#%u): %s%s\n", prefix, (int)blockIndex, block->bytecodeBegin, block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : ""); + dataLog("%s Predecessors:", prefix); + for (size_t i = 0; i < block->m_predecessors.size(); ++i) + dataLog(" #%u", block->m_predecessors[i]); + dataLog("\n"); + if (m_dominators.isValid()) { + dataLog("%s Dominated by:", prefix); + for (size_t i = 0; i < m_blocks.size(); ++i) { + if (!m_dominators.dominates(i, blockIndex)) + continue; + dataLog(" #%lu", static_cast<unsigned long>(i)); + } + dataLog("\n"); + dataLog("%s Dominates:", prefix); + for (size_t i = 0; i < m_blocks.size(); ++i) { + if (!m_dominators.dominates(blockIndex, i)) + continue; + dataLog(" #%lu", static_cast<unsigned long>(i)); + } + dataLog("\n"); + } + dataLog("%s Phi Nodes:", prefix); + unsigned count = 0; + 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; + if (!((++count) % 4)) + dataLog("\n%s ", prefix); + dataLog(" @%u->(", phiNodeIndex); + if (phiNode.child1()) { + dataLog("@%u", phiNode.child1().index()); + if (phiNode.child2()) { + dataLog(", @%u", phiNode.child2().index()); + if (phiNode.child3()) + dataLog(", @%u", phiNode.child3().index()); + } + } + dataLog(")%s", i + 1 < block->phis.size() ? "," : ""); + } + dataLog("\n"); +} + void Graph::dump() { NodeIndex lastNodeIndex = NoNode; @@ -295,33 +356,7 @@ void Graph::dump() BasicBlock* block = m_blocks[b].get(); if (!block) continue; - dataLog("Block #%u (bc#%u): %s%s\n", (int)b, block->bytecodeBegin, block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : ""); - dataLog(" Predecessors:"); - for (size_t i = 0; i < block->m_predecessors.size(); ++i) - dataLog(" #%u", block->m_predecessors[i]); - dataLog("\n"); - if (m_dominators.isValid()) { - dataLog(" Dominated by:"); - for (size_t i = 0; i < m_blocks.size(); ++i) { - if (!m_dominators.dominates(i, b)) - continue; - dataLog(" #%lu", static_cast<unsigned long>(i)); - } - dataLog("\n"); - dataLog(" Dominates:"); - for (size_t i = 0; i < m_blocks.size(); ++i) { - if (!m_dominators.dominates(b, i)) - continue; - dataLog(" #%lu", static_cast<unsigned long>(i)); - } - dataLog("\n"); - } - dataLog(" Phi Nodes:\n"); - for (size_t i = 0; i < block->phis.size(); ++i) { - dumpCodeOrigin(lastNodeIndex, block->phis[i]); - dump(block->phis[i]); - lastNodeIndex = block->phis[i]; - } + dumpBlockHeader("", b, DumpAllPhis); dataLog(" vars before: "); if (block->cfaHasVisited) dumpOperands(block->valuesAtHead, WTF::dataFile()); @@ -332,8 +367,8 @@ void Graph::dump() dumpOperands(block->variablesAtHead, WTF::dataFile()); dataLog("\n"); for (size_t i = 0; i < block->size(); ++i) { - dumpCodeOrigin(lastNodeIndex, block->at(i)); - dump(block->at(i)); + dumpCodeOrigin("", lastNodeIndex, block->at(i)); + dump("", block->at(i)); lastNodeIndex = block->at(i); } dataLog(" vars after: "); diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index acc9ff472..9e4a28fc3 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -179,11 +179,15 @@ public: // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names). void dump(); - void dump(NodeIndex); + enum PhiNodeDumpMode { DumpLivePhisOnly, DumpAllPhis }; + void dumpBlockHeader(const char* prefix, BlockIndex, PhiNodeDumpMode); + void dump(const char* prefix, NodeIndex); + static int amountOfNodeWhiteSpace(Node&); + static void printNodeWhiteSpace(Node&); // Dump the code origin of the given node as a diff from the code origin of the // preceding node. - void dumpCodeOrigin(NodeIndex, NodeIndex); + void dumpCodeOrigin(const char* prefix, NodeIndex, NodeIndex); BlockIndex blockIndexForBytecodeOffset(Vector<BlockIndex>& blocks, unsigned bytecodeBegin); @@ -273,6 +277,18 @@ public: return false; return true; } + bool isInternalFunctionConstant(NodeIndex nodeIndex) + { + if (!isJSConstant(nodeIndex)) + return false; + JSValue value = valueOfJSConstant(nodeIndex); + if (!value.isCell() || !value) + return false; + JSCell* cell = value.asCell(); + if (!cell->inherits(&InternalFunction::s_info)) + return false; + return true; + } // Helper methods get constant values from nodes. JSValue valueOfJSConstant(NodeIndex nodeIndex) { @@ -296,6 +312,10 @@ public: ASSERT(function); return jsCast<JSFunction*>(function); } + InternalFunction* valueOfInternalFunctionConstant(NodeIndex nodeIndex) + { + return jsCast<InternalFunction*>(valueOfJSConstant(nodeIndex).asCell()); + } static const char *opName(NodeType); diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp index 561f51615..3c85cc77c 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp @@ -40,6 +40,15 @@ namespace JSC { namespace DFG { +JITCompiler::JITCompiler(Graph& dfg) + : CCallHelpers(&dfg.m_globalData, dfg.m_codeBlock) + , m_graph(dfg) + , m_currentCodeOriginIndex(0) +{ + if (shouldShowDisassembly()) + m_disassembler = adoptPtr(new Disassembler(dfg)); +} + void JITCompiler::linkOSRExits() { for (unsigned i = 0; i < codeBlock()->numberOfOSRExits(); ++i) { @@ -201,9 +210,11 @@ void JITCompiler::link(LinkBuffer& linkBuffer) bool JITCompiler::compile(JITCode& entry) { + setStartOfCode(); compileEntry(); SpeculativeJIT speculative(*this); compileBody(speculative); + setEndOfMainPath(); // Generate slow path code. speculative.runSlowPathGenerators(); @@ -213,6 +224,7 @@ bool JITCompiler::compile(JITCode& entry) // Create OSR entry trampolines if necessary. speculative.createOSREntries(); + setEndOfCode(); LinkBuffer linkBuffer(*m_globalData, this, m_codeBlock, JITCompilationCanFail); if (linkBuffer.didFailToAllocate()) @@ -220,14 +232,18 @@ bool JITCompiler::compile(JITCode& entry) link(linkBuffer); speculative.linkOSREntries(linkBuffer); + if (m_disassembler) + m_disassembler->dump(linkBuffer); + entry = JITCode( - FINALIZE_CODE(linkBuffer, ("DFG program/eval CodeBlock %p", m_codeBlock)), + linkBuffer.finalizeCodeWithoutDisassembly(), JITCode::DFGJIT); return true; } bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck) { + setStartOfCode(); compileEntry(); // === Function header code generation === @@ -246,6 +262,7 @@ bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi // === Function body code generation === SpeculativeJIT speculative(*this); compileBody(speculative); + setEndOfMainPath(); // === Function footer code generation === // @@ -290,7 +307,7 @@ bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi // Create OSR entry trampolines if necessary. speculative.createOSREntries(); - + setEndOfCode(); // === Link === LinkBuffer linkBuffer(*m_globalData, this, m_codeBlock, JITCompilationCanFail); @@ -302,10 +319,13 @@ bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi // FIXME: switch the register file check & arity check over to DFGOpertaion style calls, not JIT stubs. linkBuffer.link(callRegisterFileCheck, cti_register_file_check); linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck); + + if (m_disassembler) + m_disassembler->dump(linkBuffer); entryWithArityCheck = linkBuffer.locationOf(arityCheck); entry = JITCode( - FINALIZE_CODE(linkBuffer, ("DFG function CodeBlock %p", m_codeBlock)), + linkBuffer.finalizeCodeWithoutDisassembly(), JITCode::DFGJIT); return true; } diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h index 9d69ec9f3..ed16459cc 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h @@ -30,6 +30,7 @@ #include "CodeBlock.h" #include "DFGCCallHelpers.h" +#include "DFGDisassembler.h" #include "DFGFPRInfo.h" #include "DFGGPRInfo.h" #include "DFGGraph.h" @@ -208,12 +209,7 @@ struct PropertyAccessRecord { // call to be linked). class JITCompiler : public CCallHelpers { public: - JITCompiler(Graph& dfg) - : CCallHelpers(&dfg.m_globalData, dfg.m_codeBlock) - , m_graph(dfg) - , m_currentCodeOriginIndex(0) - { - } + JITCompiler(Graph& dfg); bool compile(JITCode& entry); bool compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck); @@ -221,6 +217,42 @@ public: // Accessors for properties. Graph& graph() { return m_graph; } + // Methods to set labels for the disassembler. + void setStartOfCode() + { + if (LIKELY(!m_disassembler)) + return; + m_disassembler->setStartOfCode(labelIgnoringWatchpoints()); + } + + void setForBlock(BlockIndex blockIndex) + { + if (LIKELY(!m_disassembler)) + return; + m_disassembler->setForBlock(blockIndex, labelIgnoringWatchpoints()); + } + + void setForNode(NodeIndex nodeIndex) + { + if (LIKELY(!m_disassembler)) + return; + m_disassembler->setForNode(nodeIndex, labelIgnoringWatchpoints()); + } + + void setEndOfMainPath() + { + if (LIKELY(!m_disassembler)) + return; + m_disassembler->setEndOfMainPath(labelIgnoringWatchpoints()); + } + + void setEndOfCode() + { + if (LIKELY(!m_disassembler)) + return; + m_disassembler->setEndOfCode(labelIgnoringWatchpoints()); + } + // Get a token for beginning a call, and set the current code origin index in // the call frame. CallBeginToken beginCall() @@ -353,6 +385,8 @@ private: // The dataflow graph currently being generated. Graph& m_graph; + OwnPtr<Disassembler> m_disassembler; + // Vector of calls out from JIT code, including exception handler information. // Count of the number of CallRecords with exception handlers. Vector<CallLinkRecord> m_calls; diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index 64e6fe097..40701c3bd 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -730,6 +730,11 @@ struct Node { { return m_refCount; } + + bool willHaveCodeGen() + { + return shouldGenerate() && op() != Phantom && op() != Nop; + } unsigned refCount() { diff --git a/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp b/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp index ca6257401..480a7dab9 100644 --- a/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp +++ b/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp @@ -46,19 +46,19 @@ const char* nodeFlagsAsString(NodeFlags flags) if (flags & NodeResultMask) { switch (flags & NodeResultMask) { case NodeResultJS: - ptr.strcat("ResultJS"); + ptr.strcat("JS"); break; case NodeResultNumber: - ptr.strcat("ResultNumber"); + ptr.strcat("Number"); break; case NodeResultInt32: - ptr.strcat("ResultInt32"); + ptr.strcat("Int32"); break; case NodeResultBoolean: - ptr.strcat("ResultBoolean"); + ptr.strcat("Boolean"); break; case NodeResultStorage: - ptr.strcat("ResultStorage"); + ptr.strcat("Storage"); break; default: ASSERT_NOT_REACHED(); @@ -70,21 +70,21 @@ const char* nodeFlagsAsString(NodeFlags flags) if (flags & NodeMustGenerate) { if (hasPrinted) ptr.strcat("|"); - ptr.strcat("MustGenerate"); + ptr.strcat("MustGen"); hasPrinted = true; } if (flags & NodeHasVarArgs) { if (hasPrinted) ptr.strcat("|"); - ptr.strcat("HasVarArgs"); + ptr.strcat("VarArgs"); hasPrinted = true; } if (flags & NodeClobbersWorld) { if (hasPrinted) ptr.strcat("|"); - ptr.strcat("ClobbersWorld"); + ptr.strcat("Clobbers"); hasPrinted = true; } @@ -95,18 +95,23 @@ const char* nodeFlagsAsString(NodeFlags flags) hasPrinted = true; } - if (flags & NodeUsedAsNumber) { - if (hasPrinted) - ptr.strcat("|"); - ptr.strcat("UsedAsNum"); - hasPrinted = true; - } - - if (flags & NodeNeedsNegZero) { - if (hasPrinted) - ptr.strcat("|"); - ptr.strcat("NeedsNegZero"); - hasPrinted = true; + if (flags & NodeResultMask) { + if (!(flags & NodeUsedAsNumber) && !(flags & NodeNeedsNegZero)) { + if (hasPrinted) + ptr.strcat("|"); + ptr.strcat("PureInt"); + hasPrinted = true; + } else if (!(flags & NodeUsedAsNumber)) { + if (hasPrinted) + ptr.strcat("|"); + ptr.strcat("PureInt(w/ neg zero)"); + hasPrinted = true; + } else if (!(flags & NodeNeedsNegZero)) { + if (hasPrinted) + ptr.strcat("|"); + ptr.strcat("PureNum"); + hasPrinted = true; + } } if (flags & NodeMayOverflow) { @@ -126,7 +131,7 @@ const char* nodeFlagsAsString(NodeFlags flags) if (flags & NodeUsedAsInt) { if (hasPrinted) ptr.strcat("|"); - ptr.strcat("UsedAsInt"); + ptr.strcat("UseAsInt"); hasPrinted = true; } diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp index d46d59650..e617b5479 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp @@ -115,7 +115,10 @@ void OSRExitCompiler::handleExitCounts(const OSRExit& exit) m_jit.store32(GPRInfo::regT2, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfForcedOSRExitCounter())); m_jit.store32(GPRInfo::regT1, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfSpeculativeSuccessCounter())); + m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), GPRInfo::regT0); + tooFewFails.append(m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, AssemblyHelpers::TrustedImm32(Options::forcedOSRExitCountForReoptimization))); + } else { // Proceed based on the assumption that we can handle these exits so long as they // don't get too frequent. @@ -136,8 +139,14 @@ void OSRExitCompiler::handleExitCounts(const OSRExit& exit) } // Reoptimize as soon as possible. - m_jit.store32(AssemblyHelpers::TrustedImm32(0), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter())); - m_jit.store32(AssemblyHelpers::TrustedImm32(0), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionActiveThreshold())); +#if !NUMBER_OF_ARGUMENT_REGISTERS + m_jit.poke(GPRInfo::regT0); +#else + m_jit.move(GPRInfo::regT0, GPRInfo::argumentGPR0); + ASSERT(GPRInfo::argumentGPR0 != GPRInfo::regT1); +#endif + m_jit.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast<void*>(triggerReoptimizationNow)), GPRInfo::regT1); + m_jit.call(GPRInfo::regT1); AssemblyHelpers::Jump doneAdjusting = m_jit.jump(); tooFewFails.link(&m_jit); diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index 06a1cf883..b056a3c6d 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -32,14 +32,15 @@ #include "DFGRepatch.h" #include "HostCallReturnValue.h" #include "GetterSetter.h" -#include <wtf/InlineASM.h> #include "Interpreter.h" +#include "JIT.h" #include "JITExceptions.h" #include "JSActivation.h" #include "JSGlobalData.h" #include "JSStaticScopeObject.h" #include "NameInstance.h" #include "Operations.h" +#include <wtf/InlineASM.h> #if ENABLE(DFG_JIT) @@ -968,13 +969,11 @@ EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Iden return JSValue::encode(base); } -EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, GlobalResolveInfo* resolveInfo, Identifier* propertyName) +EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, GlobalResolveInfo* resolveInfo, JSGlobalObject* globalObject, Identifier* propertyName) { JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - PropertySlot slot(globalObject); if (globalObject->getPropertySlot(exec, *propertyName, slot)) { JSValue result = slot.getValue(exec, *propertyName); @@ -1253,6 +1252,27 @@ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* } #endif +extern "C" void DFG_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock) +{ +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("%p: Entered reoptimize\n", codeBlock); +#endif + // We must be called with the baseline code block. + ASSERT(JITCode::isBaselineCode(codeBlock->getJITType())); + + // If I am my own replacement, then reoptimization has already been triggered. + // This can happen in recursive functions. + if (codeBlock->replacement() == codeBlock) + return; + + // Otherwise, the replacement must be optimized code. Use this as an opportunity + // to check our logic. + ASSERT(codeBlock->hasOptimizedReplacement()); + ASSERT(codeBlock->replacement()->getJITType() == JITCode::DFGJIT); + + codeBlock->reoptimize(); +} + } // extern "C" } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h index 38166a83f..7477ab2fc 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.h +++ b/Source/JavaScriptCore/dfg/DFGOperations.h @@ -65,7 +65,7 @@ typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EA)(ExecState*, JSArray*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECI)(ExecState*, JSCell*, Identifier*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue); -typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EGI)(ExecState*, GlobalResolveInfo*, Identifier*); +typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EGriJsgI)(ExecState*, GlobalResolveInfo*, JSGlobalObject*, Identifier*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EI)(ExecState*, Identifier*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJ)(ExecState*, EncodedJSValue); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJA)(ExecState*, EncodedJSValue, JSArray*); @@ -121,7 +121,7 @@ void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet) W EncodedJSValue DFG_OPERATION operationResolve(ExecState*, Identifier*) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationResolveBase(ExecState*, Identifier*) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState*, Identifier*) WTF_INTERNAL; -EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, GlobalResolveInfo*, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, GlobalResolveInfo*, JSGlobalObject*, Identifier*) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationStrCat(ExecState*, void*, size_t) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, void*, size_t) WTF_INTERNAL; @@ -227,6 +227,8 @@ size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState*, EncodedJSValue) WTF_ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void*) WTF_INTERNAL; #endif +void DFG_OPERATION triggerReoptimizationNow(CodeBlock*) WTF_INTERNAL; + } // extern "C" } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 852f74387..d9a79f13a 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -1026,6 +1026,7 @@ void SpeculativeJIT::compile(BasicBlock& block) for (m_indexInBlock = 0; m_indexInBlock < block.size(); ++m_indexInBlock) { m_compileIndex = block[m_indexInBlock]; + m_jit.setForNode(m_compileIndex); Node& node = at(m_compileIndex); m_codeOriginForOSR = node.codeOrigin; if (!node.shouldGenerate()) { @@ -1321,6 +1322,7 @@ bool SpeculativeJIT::compile() ASSERT(!m_compileIndex); for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block) { + m_jit.setForBlock(m_block); BasicBlock* block = m_jit.graph().m_blocks[m_block].get(); if (block) compile(*block); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 933784685..6c6948b90 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -1229,9 +1229,9 @@ public: m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, result); return call; } - JITCompiler::Call callOperation(J_DFGOperation_EGI operation, GPRReg result, GPRReg arg1, Identifier* identifier) + JITCompiler::Call callOperation(J_DFGOperation_EGriJsgI operation, GPRReg result, GPRReg arg1, GPRReg arg2, Identifier* identifier) { - m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, result); } JITCompiler::Call callOperation(J_DFGOperation_EI operation, GPRReg result, Identifier* identifier) @@ -1482,9 +1482,9 @@ public: m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(pointer)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } - JITCompiler::Call callOperation(J_DFGOperation_EGI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, Identifier* identifier) + JITCompiler::Call callOperation(J_DFGOperation_EGriJsgI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2, Identifier* identifier) { - m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier)); + m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(identifier)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1) @@ -2369,7 +2369,7 @@ public: Vector<SlowPathGenerator*, 8> m_slowPathGenerators; // doesn't use OwnPtr<> because I don't want to include DFGSlowPathGenerator.h Vector<SilentRegisterSavePlan> m_plans; - + ValueRecovery computeValueRecoveryFor(const ValueSource&); ValueRecovery computeValueRecoveryFor(int operand) diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 0c33e0748..21d94e9e8 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -3840,7 +3840,7 @@ void SpeculativeJIT::compile(Node& node) addSlowPathGenerator( slowPathCall( structuresNotMatch, this, operationResolveGlobal, - JSValueRegs(resultTagGPR, resultPayloadGPR), resolveInfoGPR, + JSValueRegs(resultTagGPR, resultPayloadGPR), resolveInfoGPR, globalObjectGPR, &m_jit.codeBlock()->identifier(data.identifierNumber))); jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index 0b7606b2c..a6c283584 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -3843,11 +3843,11 @@ void SpeculativeJIT::compile(Node& node) m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfPropertyStorage()), resultGPR); m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR); m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr), resultGPR); - + addSlowPathGenerator( slowPathCall( structuresDontMatch, this, operationResolveGlobal, - resultGPR, resolveInfoGPR, + resultGPR, resolveInfoGPR, globalObjectGPR, &m_jit.codeBlock()->identifier(data.identifierNumber))); jsValueResult(resultGPR, m_compileIndex); |
