summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp144
-rw-r--r--Source/JavaScriptCore/dfg/DFGCapabilities.h1
-rw-r--r--Source/JavaScriptCore/dfg/DFGCommon.h5
-rw-r--r--Source/JavaScriptCore/dfg/DFGDisassembler.cpp115
-rw-r--r--Source/JavaScriptCore/dfg/DFGDisassembler.h82
-rw-r--r--Source/JavaScriptCore/dfg/DFGDriver.cpp10
-rw-r--r--Source/JavaScriptCore/dfg/DFGDriver.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.cpp99
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h24
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.cpp26
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.h46
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h5
-rw-r--r--Source/JavaScriptCore/dfg/DFGNodeFlags.cpp47
-rw-r--r--Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp13
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp28
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.h6
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp2
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h10
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp2
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp4
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);