Commit 5f079f65 authored by barraclough@apple.com's avatar barraclough@apple.com

Bug 56284 - Add a dataflow intermediate representation for use in JIT generation.

Reviewed by Geoffrey Garen & Oliver Hunt.

The JSC JIT presently generates code directly from the bytecode used by the interpreter.
This is not an optimal intermediate representation for JIT code generation, since it does
not capture liveness information of values, and provides little opportunity to perform
any static analysis for even primitive types. The JIT currently generates two code paths,
a fast path handling common cases, and a slower path handling less common operand types.
However the slow path jumps back into the fast path, meaning that information arising
from the earlier type checks cannot be propagated to later operations.

This patch adds:
    * a dataflow intermediate representation capable of describing a single basic block
      of operations,
    * a mechanism to convert a simple, single-block bytecode functions to the new IR,
    * and a JIT code generator capable of generating code from this representation.

The JIT generates two code paths, with the slower path not reentering the fast path
mid-block, allowing speculative optimizations to be made on the hot path, with type
information arising from these speculative decisions able to be propagated through the
dataflow. Code generation of both speculative and non-speculative paths exploits the type
and liveness information represented in the dataflow graph to attempt to avoid redundant
boxing and type-checking of values, and to remove unnecessary spills of temporary values
to the RegisterFile.

The dataflow JIT currently can only support a subset of bytecode operations, limited to
arithmetic, bit-ops, and basic property access. Functions that cannot be compiled by the
dataflow JIT will be run using the existing JIT. The coverage of the dataflow JIT will be
expanded to include, control-flow, function calls, and then the long-tail of remaining
bytecode instructions. The JIT presently only support JSVALUE64, and as a consequence of
this only supports x86-64.

The status of the dataflow JIT is currently work-in-progress. Limitations of the present
JIT code generation may cause performance regressions, particularly:
    * the policy to only generate arithmetic code on the speculative path using integer
      instructions, never using floating point.
    * the policy to only generate arithmetic code on the non-speculative path using
      floating point instructions, never using integer.
    * always generating JSValue adds on the non-speculative path as a call out to a
      C-function, never handling this in JIT code.
    * always assuming by-Value property accesses on the speculative path to be array
      accesses.
    * generating all by-Value property accesses from the non-speculative path as a call
      out to a C-function.
    * generating all by-Indentifer property accesses as a call out to a C-function.
Due to these regressions, the code is landed in a state where it is disabled in most
cases by the ENABLE_DFG_JIT_RESTRICTIONS guard in Platform.h. As these regressions are
addressed, the JIT will be allowed to trigger in more cases.

* JavaScriptCore.xcodeproj/project.pbxproj:
    - Added new files to Xcode project.
* dfg: Added.
    - Added directory for new code.
* dfg/DFGByteCodeParser.cpp: Added.
* dfg/DFGByteCodeParser.h: Added.
    - Contruct a DFG::Graph representation from a bytecode CodeBlock.
* dfg/DFGGenerationInfo.h: Added.
    - Track type & register information for VirtualRegisters during JIT code generation.
* dfg/DFGGraph.cpp: Added.
* dfg/DFGGraph.h: Added.
    - Dataflow graph intermediate representation for code generation.
* dfg/DFGJITCodeGenerator.cpp: Added.
* dfg/DFGJITCodeGenerator.h: Added.
    - Base class for SpeculativeJIT & NonSpeculativeJIT to share common functionality.
* dfg/DFGJITCompiler.cpp: Added.
* dfg/DFGJITCompiler.h: Added.
    - Class responsible for driving code generation of speculativeJIT & non-speculative
      code paths from the dataflow graph.
* dfg/DFGNonSpeculativeJIT.cpp: Added.
* dfg/DFGNonSpeculativeJIT.h: Added.
    - Used to generate the non-speculative code path, this make no assumptions
      about operand types.
* dfg/DFGOperations.cpp: Added.
* dfg/DFGOperations.h: Added.
    - Helper functions called from the JIT generated code.
* dfg/DFGRegisterBank.h: Added.
    - Used to track contents of physical registers during JIT code generation.
* dfg/DFGSpeculativeJIT.cpp: Added.
* dfg/DFGSpeculativeJIT.h: Added.
    - Used to generate the speculative code path, this make assumptions about
      operand types to enable optimization.
* runtime/Executable.cpp:
    - Add code to attempt to use the DFG JIT to compile a function, with fallback
      to the existing JIT.
* wtf/Platform.h:
    - Added compile guards to enable the DFG JIT.



git-svn-id: svn://svn.chromium.org/blink/trunk@81079 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 2b78f3d5
2011-03-14 Gavin Barraclough <barraclough@apple.com>
Reviewed by Geoffrey Garen & Oliver Hunt.
Bug 56284 - Add a dataflow intermediate representation for use in JIT generation.
The JSC JIT presently generates code directly from the bytecode used by the interpreter.
This is not an optimal intermediate representation for JIT code generation, since it does
not capture liveness information of values, and provides little opportunity to perform
any static analysis for even primitive types. The JIT currently generates two code paths,
a fast path handling common cases, and a slower path handling less common operand types.
However the slow path jumps back into the fast path, meaning that information arising
from the earlier type checks cannot be propagated to later operations.
This patch adds:
* a dataflow intermediate representation capable of describing a single basic block
of operations,
* a mechanism to convert a simple, single-block bytecode functions to the new IR,
* and a JIT code generator capable of generating code from this representation.
The JIT generates two code paths, with the slower path not reentering the fast path
mid-block, allowing speculative optimizations to be made on the hot path, with type
information arising from these speculative decisions able to be propagated through the
dataflow. Code generation of both speculative and non-speculative paths exploits the type
and liveness information represented in the dataflow graph to attempt to avoid redundant
boxing and type-checking of values, and to remove unnecessary spills of temporary values
to the RegisterFile.
The dataflow JIT currently can only support a subset of bytecode operations, limited to
arithmetic, bit-ops, and basic property access. Functions that cannot be compiled by the
dataflow JIT will be run using the existing JIT. The coverage of the dataflow JIT will be
expanded to include, control-flow, function calls, and then the long-tail of remaining
bytecode instructions. The JIT presently only support JSVALUE64, and as a consequence of
this only supports x86-64.
The status of the dataflow JIT is currently work-in-progress. Limitations of the present
JIT code generation may cause performance regressions, particularly:
* the policy to only generate arithmetic code on the speculative path using integer
instructions, never using floating point.
* the policy to only generate arithmetic code on the non-speculative path using
floating point instructions, never using integer.
* always generating JSValue adds on the non-speculative path as a call out to a
C-function, never handling this in JIT code.
* always assuming by-Value property accesses on the speculative path to be array
accesses.
* generating all by-Value property accesses from the non-speculative path as a call
out to a C-function.
* generating all by-Indentifer property accesses as a call out to a C-function.
Due to these regressions, the code is landed in a state where it is disabled in most
cases by the ENABLE_DFG_JIT_RESTRICTIONS guard in Platform.h. As these regressions are
addressed, the JIT will be allowed to trigger in more cases.
* JavaScriptCore.xcodeproj/project.pbxproj:
- Added new files to Xcode project.
* dfg: Added.
- Added directory for new code.
* dfg/DFGByteCodeParser.cpp: Added.
* dfg/DFGByteCodeParser.h: Added.
- Contruct a DFG::Graph representation from a bytecode CodeBlock.
* dfg/DFGGenerationInfo.h: Added.
- Track type & register information for VirtualRegisters during JIT code generation.
* dfg/DFGGraph.cpp: Added.
* dfg/DFGGraph.h: Added.
- Dataflow graph intermediate representation for code generation.
* dfg/DFGJITCodeGenerator.cpp: Added.
* dfg/DFGJITCodeGenerator.h: Added.
- Base class for SpeculativeJIT & NonSpeculativeJIT to share common functionality.
* dfg/DFGJITCompiler.cpp: Added.
* dfg/DFGJITCompiler.h: Added.
- Class responsible for driving code generation of speculativeJIT & non-speculative
code paths from the dataflow graph.
* dfg/DFGNonSpeculativeJIT.cpp: Added.
* dfg/DFGNonSpeculativeJIT.h: Added.
- Used to generate the non-speculative code path, this make no assumptions
about operand types.
* dfg/DFGOperations.cpp: Added.
* dfg/DFGOperations.h: Added.
- Helper functions called from the JIT generated code.
* dfg/DFGRegisterBank.h: Added.
- Used to track contents of physical registers during JIT code generation.
* dfg/DFGSpeculativeJIT.cpp: Added.
* dfg/DFGSpeculativeJIT.h: Added.
- Used to generate the speculative code path, this make assumptions about
operand types to enable optimization.
* runtime/Executable.cpp:
- Add code to attempt to use the DFG JIT to compile a function, with fallback
to the existing JIT.
* wtf/Platform.h:
- Added compile guards to enable the DFG JIT.
2011-03-14 Geoffrey Garen <ggaren@apple.com>
Reviewed by Oliver Hunt.
......
......@@ -434,6 +434,8 @@ namespace JSC {
bool hasExpressionInfo() { return m_rareData && m_rareData->m_expressionInfo.size(); }
bool hasLineInfo() { return m_rareData && m_rareData->m_lineInfo.size(); }
// We only generate exception handling info if the user is debugging
// (and may want line number info), or if the function contains exception handler.
bool needsCallReturnIndices()
{
return m_rareData &&
......
/*
* Copyright (C) 2011 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 DFGAliasTracker_h
#define DFGAliasTracker_h
#if ENABLE(DFG_JIT)
#include <dfg/DFGGraph.h>
#include <wtf/Vector.h>
namespace JSC { namespace DFG {
// === AliasTracker ===
//
// This class id used to detect aliasing property accesses, which we may
// be able to speculatively optimize (for example removing redundant loads
// where we know a getter will not be called, or optimizing puts to arrays
// where we know the value being written to in within length and is not a
// hole value). In time, this should be more than a 1-deep buffer!
class AliasTracker {
public:
AliasTracker(Graph& graph)
: m_graph(graph)
, m_candidateAliasGetByVal(NoNode)
{
}
NodeIndex lookupGetByVal(NodeIndex base, NodeIndex property)
{
// Try to detect situations where a GetByVal follows another GetByVal to the same
// property; in these cases, we may be able to omit the subsequent get on the
// speculative path, where we know conditions hold to make this safe (for example,
// on the speculative path we will not have allowed getter access).
if (m_candidateAliasGetByVal != NoNode) {
Node& possibleAlias = m_graph[m_candidateAliasGetByVal];
ASSERT(possibleAlias.op == GetByVal);
// This check ensures the accesses alias, provided that the subscript is an
// integer index (this is good enough; the speculative path will only generate
// optimized accesses to handle integer subscripts).
if (possibleAlias.child1 == base && equalIgnoringLaterNumericConversion(possibleAlias.child2, property))
return m_candidateAliasGetByVal;
}
return NoNode;
}
void recordGetByVal(NodeIndex getByVal)
{
m_candidateAliasGetByVal = getByVal;
}
void recordPutByVal(NodeIndex putByVal)
{
ASSERT_UNUSED(putByVal, m_graph[putByVal].op == PutByVal);
m_candidateAliasGetByVal = NoNode;
}
void recordGetById(NodeIndex getById)
{
ASSERT_UNUSED(getById, m_graph[getById].op == GetById);
m_candidateAliasGetByVal = NoNode;
}
void recordPutById(NodeIndex putById)
{
ASSERT_UNUSED(putById, m_graph[putById].op == PutById);
m_candidateAliasGetByVal = NoNode;
}
void recordPutByIdDirect(NodeIndex putByVal)
{
ASSERT_UNUSED(putByVal, m_graph[putByVal].op == PutByIdDirect);
m_candidateAliasGetByVal = NoNode;
}
private:
// This method returns true for arguments:
// - (X, X)
// - (X, ValueToNumber(X))
// - (X, ValueToInt32(X))
// - (X, NumberToInt32(X))
bool equalIgnoringLaterNumericConversion(NodeIndex op1, NodeIndex op2)
{
if (op1 == op2)
return true;
Node& node2 = m_graph[op2];
return (node2.op == ValueToNumber || node2.op == ValueToInt32 || node2.op == NumberToInt32) && op1 == node2.child1;
}
// The graph, to look up potentially aliasing nodes.
Graph& m_graph;
// Currently a 1-deep buffer!
NodeIndex m_candidateAliasGetByVal;
};
} } // namespace JSC::DFG
#endif
#endif
/*
* Copyright (C) 2011 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 DFGByteCodeParser_h
#define DFGByteCodeParser_h
#if ENABLE(DFG_JIT)
#include <dfg/DFGGraph.h>
namespace JSC {
class CodeBlock;
class JSGlobalData;
namespace DFG {
// Populate the Graph with a basic block of code from the CodeBlock,
// starting at the provided bytecode index.
bool parse(Graph&, JSGlobalData*, CodeBlock*, unsigned startIndex);
} } // namespace JSC::DFG
#endif
#endif
/*
* Copyright (C) 2011 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 DFGGenerationInfo_h
#define DFGGenerationInfo_h
#if ENABLE(DFG_JIT)
#include <dfg/DFGJITCompiler.h>
namespace JSC { namespace DFG {
// === DataFormat ===
//
// This enum tracks the current representation in which a value is being held.
// Values may be unboxed primitives (int32, double, or cell), or boxed as a JSValue.
// For boxed values, we may know the type of boxing that has taken place.
// (May also need bool, array, object, string types!)
enum DataFormat {
DataFormatNone = 0,
DataFormatInteger = 1,
DataFormatDouble = 2,
DataFormatCell = 3,
DataFormatJS = 8,
DataFormatJSInteger = DataFormatJS | DataFormatInteger,
DataFormatJSDouble = DataFormatJS | DataFormatDouble,
DataFormatJSCell = DataFormatJS | DataFormatCell,
};
// === GenerationInfo ===
//
// This class is used to track the current status of a live values during code generation.
// Can provide information as to whether a value is in machine registers, and if so which,
// whether a value has been spilled to the RegsiterFile, and if so may be able to provide
// details of the format in memory (all values are spilled in a boxed form, but we may be
// able to track the type of box), and tracks how many outstanding uses of a value remain,
// so that we know when the value is dead and the machine registers associated with it
// may be released.
class GenerationInfo {
public:
GenerationInfo()
: m_nodeIndex(NoNode)
, m_useCount(0)
, m_registerFormat(DataFormatNone)
, m_spillFormat(DataFormatNone)
, m_canFill(false)
{
}
// Used to set the generation info according the the result
// of various operations.
void initArgument(NodeIndex nodeIndex, uint32_t useCount)
{
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = DataFormatNone;
m_spillFormat = DataFormatNone;
m_canFill = true;
}
void initConstant(NodeIndex nodeIndex, uint32_t useCount)
{
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = DataFormatNone;
m_spillFormat = DataFormatNone;
m_canFill = true;
}
void initInteger(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
{
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = DataFormatInteger;
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
}
void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
{
ASSERT(format & DataFormatJS);
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = format;
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
}
void initCell(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
{
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = DataFormatCell;
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
}
void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr)
{
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = DataFormatDouble;
m_spillFormat = DataFormatNone;
m_canFill = false;
u.fpr = fpr;
}
void initNone(NodeIndex nodeIndex, uint32_t useCount)
{
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = DataFormatNone;
m_spillFormat = DataFormatNone;
m_canFill = false;
}
// Get the index of the node that produced this value.
NodeIndex nodeIndex() { return m_nodeIndex; }
// Mark the value as having been used (decrement the useCount).
// Returns true if this was the last use of the value, and any
// associated machine registers may be freed.
bool use()
{
return !--m_useCount;
}
// Used to check the operands of operations to see if they are on
// their last use; in some cases it may be safe to reuse the same
// machine register for the result of the operation.
bool canReuse()
{
ASSERT(m_useCount);
return m_useCount == 1;
}
// Get the format of the value in machine registers (or 'none').
DataFormat registerFormat() { return m_registerFormat; }
// Get the format of the value as it is spilled in the RegisterFile (or 'none').
DataFormat spillFormat() { return m_spillFormat; }
// Get the machine resister currently holding the value.
GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
// Check whether a value needs spilling in order to free up any associated machine registers.
bool needsSpill()
{
// This should only be called on values that are currently in a register.
ASSERT(m_registerFormat != DataFormatNone);
// Constants and arguments do not need spilling, nor do values
// that have already been spilled to the RegisterFile.
return !m_canFill;
}
// Called when a VirtualRegister is being spilled †o the RegisterFile for the first time.
void spill(DataFormat spillFormat)
{
// We shouldn't be spill values that don't need spilling.
ASSERT(!m_canFill);
ASSERT(m_spillFormat == DataFormatNone);
// We should only be spilling values that are currently in machine registers.
ASSERT(m_registerFormat != DataFormatNone);
// We only spill values that have been boxed as a JSValue; otherwise the GC
// would need a way to distinguish cell pointers from numeric primitives.
ASSERT(spillFormat & DataFormatJS);
m_registerFormat = DataFormatNone;
m_spillFormat = spillFormat;
m_canFill = true;
}
// Called on values that don't need spilling (constants, arguments,
// values that have already been spilled), to mark them as no longer
// being in machine registers.
void setSpilled()
{
// Should only be called on values that don't need spillling, and are currently in registers.
ASSERT(m_canFill && m_registerFormat != DataFormatNone);
m_registerFormat = DataFormatNone;
}
// Record that this value is filled into machine registers,
// tracking which registers, and what format the value has.
void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS)
{
ASSERT(format & DataFormatJS);
m_registerFormat = format;
u.gpr = gpr;
}
void fillInteger(GPRReg gpr)
{
m_registerFormat = DataFormatInteger;
u.gpr = gpr;
}
void fillDouble(FPRReg fpr)
{
m_registerFormat = DataFormatDouble;
u.fpr = fpr;
}
#ifndef NDEBUG
bool alive()
{
return m_useCount;
}
#endif
private:
// The index of the node whose result is stored in this virtual register.
// FIXME: Can we remove this? - this is currently only used when collecting
// snapshots of the RegisterBank for SpeculationCheck/EntryLocation. Could
// investigate storing NodeIndex as the name in RegsiterBank, instead of
// VirtualRegister.
NodeIndex m_nodeIndex;
uint32_t m_useCount;
DataFormat m_registerFormat;
DataFormat m_spillFormat;
bool m_canFill;
union {
GPRReg gpr;
FPRReg fpr;
} u;
};
} } // namespace JSC::DFG
#endif
#endif
/*
* Copyright (C) 2011 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 "DFGGraph.h"
#include "CodeBlock.h"
#if ENABLE(DFG_JIT)
namespace JSC { namespace DFG {
#ifndef NDEBUG
void Graph::dump(CodeBlock* codeBlock)
{
// Creates an array of stringized names.
#define STRINGIZE_DFG_OP_ENUM(opcode, flags) #opcode ,
const char* dfgOpNames[] = {
FOR_EACH_DFG_OP(STRINGIZE_DFG_OP_ENUM)
};
#undef STRINGIZE_DFG_OP_ENUM
Node* nodes = this->begin();
size_t size = this->size();
for (size_t i = 0; i < size; ++i) {
Node& node = nodes[i];
NodeType op = node.op;
unsigned refCount = node.refCount;
if (!refCount)
continue;
bool mustGenerate = node.mustGenerate();
if (mustGenerate)
--refCount;
// Example/explanation of dataflow dump output
//
// 14: <!2:7> GetByVal(@3, @13)
// ^1 ^2 ^3 ^4 ^5
//
// (1) The nodeIndex of this operation.
// (2) The reference count. The number printed is the 'real' count,
// not including the 'mustGenerate' ref. If the node is
// 'mustGenerate' then the count it prefixed with '!'.
// (3) The virtual register slot assigned to this node.
// (4) The name of the operation.
// (5) The arguments to the operation. The may be of the form:
// @# - a NodeIndex referencing a prior node in the graph.
// arg# - an argument number.
// $# - the index in the CodeBlock of a constant { for numeric constants the value is displayed | for integers, in both decimal and hex }.
// id# - the index in the CodeBlock of an identifer { if codeBlock is passed to dump(), the string representation is displayed }.
// var# - the index of a var on the global object, used by GetGlobalVar/PutGlobalVar operations.
printf("% 4d:\t<%c%u:%u>\t%s(", (int)i, mustGenerate ? '!' : ' ', refCount, node.virtualRegister, dfgOpNames[op & NodeIdMask]);
if (node.child1 != NoNode)
printf("@%u", node.child1);
if (node.child2 != NoNode)
printf(", @%u", node.child2);
if (node.child3 != NoNode)
printf(", @%u", node.child3);
bool hasChildren = node.child1 != NoNode;
if (node.hasVarNumber())
printf("%svar%u", hasChildren ? ", " : "", node.varNumber());
if (node.hasIdentifier()) {
if (codeBlock)
printf("%sid%u{%s}", hasChildren ? ", " : "", node.identifierNumber(), codeBlock->identifier(node.identifierNumber()).ustring().utf8().data());
else
printf("%sid%u", hasChildren ? ", " : "", node.identifierNumber());
}
if (node.isArgument())
printf("%sarg%u", hasChildren ? ", " : "", node.argumentNumber());
if (op == Int32Constant)
printf("%s$%u{%d|0x%08x}", hasChildren ? ", " : "", node.constantNumber(), node.int32Constant(), node.int32Constant());
if (op == DoubleConstant)
printf("%s$%u{%f})", hasChildren ? ", " : "", node.constantNumber(), node.numericConstant());
if (op == JSConstant)
printf("%s$%u", hasChildren ? ", " : "", node.constantNumber());
printf(")\n");
}
}
#endif
// FIXME: Convert this method to be iterative, not recursive.
void Graph::refChildren(NodeIndex op)
{
Node& node = at(op);
if (node.child1 == NoNode) {
ASSERT(node.child2 == NoNode && node.child3 == NoNode);
return;
}
ref(node.child1);
if (node.child2 == NoNode) {
ASSERT(node.child3 == NoNode);
return;
}
ref(node.child2);
if (node.child3 == NoNode)
return;
ref(node.child3);
}
} } // namespace JSC::DFG
#endif
/*
* Copyright (C) 2011 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 DFGGraph_h
#define DFGGraph_h
#if ENABLE(DFG_JIT)
#include <dfg/DFGNode.h>
#include <wtf/Vector.h>
namespace JSC {
class CodeBlock;
namespace DFG {
//
// === Graph ===
//
// The dataflow graph is an ordered vector of nodes.
// The order may be significant for nodes with side-effects (property accesses, value conversions).
// Nodes that are 'dead' remain in the vector with refCount 0.
class Graph : public Vector<Node, 64> {
public:
// Mark a node as being referenced.
void ref(NodeIndex nodeIndex)
{
// If the value (before incrementing) was at reCount zero then we need to ref its children.
if (!at(nodeIndex).refCount++)
refChildren(nodeIndex);
}
#ifndef NDEBUG
// CodeBlock is optional, but may allow additional inforamtion to be dumped (e.g. Identifier names).
void dump(CodeBlock* = 0);
#endif
private:
// When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children.
void refChildren(NodeIndex);
};
} } // namespace JSC::DFG
#endif
#endif
This diff is collapsed.
/*
* Copyright (C) 2011 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 DFGNode_h
#define DFGNode_h
#if ENABLE(DFG_JIT)
#include <wtf/Vector.h>
// Emit various logging information for debugging, including dumping the dataflow graphs.
#define DFG_DEBUG_VERBOSE 0
// Enable generation of dynamic checks into the instruction stream.
#define DFG_JIT_ASSERT 0
// Consistency check contents compiler data structures.
#define DFG_CONSISTENCY_CHECK 0
// Emit a brekpoint into the head of every generated function, to aid debugging in GDB.
#define DFG_JIT_BREAK_ON_ENTRY 0
namespace JSC { namespace DFG {
// Type for a virtual register number (spill location).
// Using an enum to make this type-checked at compile time, to avert programmer errors.
enum VirtualRegister { InvalidVirtualRegister = -1 };
COMPILE_ASSERT(sizeof(VirtualRegister) == sizeof(int), VirtualRegister_is_32bit);
// Type for a reference to another node in the graph.
typedef uint32_t NodeIndex;
static const NodeIndex NoNode = UINT_MAX;
// Information used to map back from an exception to any handler/source information.
// (Presently implemented as a bytecode index).
typedef uint32_t ExceptionInfo;
// Entries in the NodeType enum (below) are composed of an id, a result type (possibly none)
// and some additional informative flags (must generate, is constant, etc).
#define NodeIdMask 0xFFF
#define NodeResultMask 0xF000
#define NodeMustGenerate 0x10000 // set on nodes that have side effects, and may not trivially be removed by DCE.
#define NodeIsConstant 0x20000
// These values record the result type of the node (as checked by NodeResultMask, above), 0 for no result.
#define NodeResultJS 0x1000
#define NodeResultDouble 0x2000
#define NodeResultInt32 0x3000
// This macro defines a set of information about all known node types, used to populate NodeId, NodeType below.
#define FOR_EACH_DFG_OP(macro) \
/* Nodes for consatnts. */\
macro(JSConstant, NodeResultJS | NodeIsConstant) \
macro(Int32Constant, NodeResultJS | NodeIsConstant) \
macro(DoubleConstant, NodeResultJS | NodeIsConstant) \
macro(Argument, NodeResultJS) \
macro(ConvertThis, NodeResultJS) \
\
/* Nodes for bitwise operations. */\
macro(BitAnd, NodeResultInt32) \
macro(BitOr, NodeResultInt32) \
macro(BitXor, NodeResultInt32) \
macro(BitLShift, NodeResultInt32) \
macro(BitRShift, NodeResultInt32) \
macro(BitURShift, NodeResultInt32) \
/* Bitwise operators call ToInt32 on their operands. */\
macro(NumberToInt32, NodeResultInt32) \
macro(ValueToInt32, NodeResultInt32 | NodeMustGenerate) \
/* Used to box the result of URShift nodes (result has range 0..2^32-1). */\
macro(UInt32ToNumber, NodeResultDouble) \
\
/* Nodes for arithmetic operations. */\
macro(ArithAdd, NodeResultDouble) \
macro(ArithSub, NodeResultDouble) \
macro(ArithMul, NodeResultDouble) \
macro(ArithDiv, NodeResultDouble) \
macro(ArithMod, NodeResultDouble) \
/* Arithmetic operators call ToNumber on their operands. */\
macro(Int32ToNumber, NodeResultDouble) \
macro(ValueToNumber, NodeResultDouble | NodeMustGenerate) \
\
/* Add of values may either be arithmetic, or result in string concatenation. */\
macro(ValueAdd, NodeResultJS | NodeMustGenerate) \
\
/* Property access. */\
/* PutByValAlias indicates a 'put' aliases a prior write to the same property. */\
/* Since a put to 'length' may invalidate optimizations here, */\
/* this must be the directly subsequent property put. */\
macro(GetByVal, NodeResultJS | NodeMustGenerate) \
macro(PutByVal, NodeMustGenerate) \
macro(PutByValAlias, NodeMustGenerate) \
macro(GetById, NodeResultJS | NodeMustGenerate) \
macro(PutById, NodeMustGenerate) \
macro(PutByIdDirect, NodeMustGenerate) \
macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
macro(PutGlobalVar, NodeMustGenerate) \
\
macro(Return, NodeMustGenerate)
// This enum generates a monotonically increasing id for all Node types,
// and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask).
enum NodeId {
#define DFG_OP_ENUM(opcode, flags) opcode##_id,
FOR_EACH_DFG_OP(DFG_OP_ENUM)
#undef DFG_OP_ENUM
};
// Entries in this enum describe all Node types.
// The enum value contains a monotonically increasing id, a result type, and additional flags.
enum NodeType {
#define DFG_OP_ENUM(opcode, flags) opcode = opcode##_id | (flags),
FOR_EACH_DFG_OP(DFG_OP_ENUM)
#undef DFG_OP_ENUM
};
// This type used in passing an immediate argument to Node constructor;
// distinguishes an immediate value (typically an index into a CodeBlock data structure -
// a constant index, argument, or identifier) from a NodeIndex.
struct OpInfo {
explicit OpInfo(unsigned value) : m_value(value) {}
unsigned m_value;
};
// === Node ===
//
// Node represents a single operation in the data flow graph.
struct Node {
// Construct a node with up to 3 children, no immediate value.
Node(NodeType op, ExceptionInfo exceptionInfo, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
: op(op)
, exceptionInfo(exceptionInfo)
, child1(child1)
, child2(child2)
, child3(child3)
, virtualRegister(InvalidVirtualRegister)
, refCount(0)
{
}
// Construct a node with up to 3 children and an immediate value.
Node(NodeType op, ExceptionInfo exceptionInfo, OpInfo imm, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
: op(op)
, exceptionInfo(exceptionInfo)
, child1(child1)
, child2(child2)
, child3(child3)
, virtualRegister(InvalidVirtualRegister)
, refCount(0)
, m_opInfo(imm.m_value)
{
}
bool mustGenerate()
{
return op & NodeMustGenerate;
}
bool isConstant()
{
return op & NodeIsConstant;
}
unsigned constantNumber()
{
ASSERT(isConstant());
return m_opInfo;
}
bool isArgument()
{
return op == Argument;
}
unsigned argumentNumber()
{
ASSERT(isArgument());
return m_opInfo;
}
bool hasIdentifier()
{
return op == GetById || op == PutById || op == PutByIdDirect;
}
unsigned identifierNumber()
{
ASSERT(hasIdentifier());
return m_opInfo;
}
bool hasVarNumber()
{
return op == GetGlobalVar || op == PutGlobalVar;
}
unsigned varNumber()
{
ASSERT(hasVarNumber());
return m_opInfo;
}
bool hasInt32Result()
{
return (op & NodeResultMask) == NodeResultInt32;
}
bool hasDoubleResult()
{
return (op & NodeResultMask) == NodeResultDouble;
}
bool hasJSResult()
{
return (op & NodeResultMask) == NodeResultJS;
}
// Check for integers or doubles.
bool hasNumericResult()
{
// This check will need updating if more result types are added.
ASSERT((hasInt32Result() || hasDoubleResult()) == !hasJSResult());
return !hasJSResult();
}
int32_t int32Constant()
{
ASSERT(op == Int32Constant);
return m_constantValue.asInt32;
}
void setInt32Constant(int32_t value)
{
ASSERT(op == Int32Constant);
m_constantValue.asInt32 = value;
}
double numericConstant()
{
ASSERT(op == DoubleConstant);
return m_constantValue.asDouble;
}
void setDoubleConstant(double value)
{
ASSERT(op == DoubleConstant);
m_constantValue.asDouble = value;
}
// This enum value describes the type of the ndoe.
NodeType op;
// Used to look up exception handling information (currently implemented as a bytecode index).
ExceptionInfo exceptionInfo;
// References to up to 3 children (0 for no child).
NodeIndex child1, child2, child3;
// The virtual register number (spill location) associated with this .
VirtualRegister virtualRegister;
// The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects).
unsigned refCount;
private:
// An immediate value, accesses type-checked via accessors above.
unsigned m_opInfo;
// The value of an int32/double constant.
union {
int32_t asInt32;
double asDouble;
} m_constantValue;
};
} } // namespace JSC::DFG
#endif
#endif
/*
* Copyright (C) 2011 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 DFGNonSpeculativeJIT_h
#define DFGNonSpeculativeJIT_h
#if ENABLE(DFG_JIT)
#include <dfg/DFGJITCodeGenerator.h>
namespace JSC { namespace DFG {
class SpeculationCheckIndexIterator;
// === EntryLocation ===
//
// This structure describes an entry point into the non-speculative
// code path. This is used in linking bail-outs from the speculative path.
struct EntryLocation {
EntryLocation(MacroAssembler::Label, NonSpeculativeJIT*);
// The node this entry point corresponds to, and the label
// marking the start of code for the given node.
MacroAssembler::Label m_entry;
NodeIndex m_nodeIndex;
// For every entry point we record a map recording for every
// machine register which, if any, values it contains. For
// GPR registers we must also record the format of the value.
struct RegisterInfo {
NodeIndex nodeIndex;
DataFormat format;
};
RegisterInfo m_gprInfo[numberOfGPRs];
NodeIndex m_fprInfo[numberOfFPRs];
};
// === NonSpeculativeJIT ===
//
// This class is used to generate code for the non-speculative path.
// Code generation will take advantage of static information avaialble
// in the dataflow to perform safe optimizations - for example, avoiding
// boxing numeric values between arithmetic operations, but will not
// perform any unsafe optimizations that would render the code unable
// to produce the correct results for any possible input.
class NonSpeculativeJIT : public JITCodeGenerator {
friend struct EntryLocation;
public:
NonSpeculativeJIT(JITCompiler& jit)
: JITCodeGenerator(jit, false)
{
}
void compile(SpeculationCheckIndexIterator&);
typedef SegmentedVector<EntryLocation, 16> EntryLocationVector;
EntryLocationVector& entryLocations() { return m_entryLocations; }
private:
// These methods are used when generating 'unexpected'
// calls out from JIT code to C++ helper routines -
// they spill all live values to the appropriate
// slots in the RegisterFile without changing any state
// in the GenerationInfo.
void silentSpill(VirtualRegister spillMe, GPRReg canTrample)
{
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.registerFormat() != DataFormatNone);
if (info.needsSpill()) {
DataFormat spillFormat = info.registerFormat();
if (spillFormat == DataFormatDouble) {
boxDouble(info.fpr(), canTrample);
m_jit.storePtr(JITCompiler::gprToRegisterID(canTrample), JITCompiler::addressFor(spillMe));
} else {
JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
if (spillFormat == DataFormatInteger) {
m_jit.orPtr(JITCompiler::tagTypeNumberRegister, reg);
m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
} else {
ASSERT(spillFormat & DataFormatJS || spillFormat == DataFormatCell);
m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
}
}
}
}
void silentFill(VirtualRegister spillMe, GPRReg canTrample)
{
GenerationInfo& info = m_generationInfo[spillMe];
NodeIndex nodeIndex = info.nodeIndex();
Node& node = m_jit.graph()[nodeIndex];
ASSERT(info.registerFormat() != DataFormatNone);
DataFormat spillFormat = info.registerFormat();
if (node.isConstant()) {
JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
} else if (node.isArgument()) {
JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
m_jit.loadPtr(m_jit.addressForArgument(m_jit.graph()[nodeIndex].argumentNumber()), reg);
} else if (spillFormat == DataFormatDouble) {
m_jit.loadPtr(JITCompiler::addressFor(spillMe), JITCompiler::gprToRegisterID(canTrample));
unboxDouble(canTrample, info.fpr());
} else if (spillFormat == DataFormatInteger) {
JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
m_jit.load32(JITCompiler::addressFor(spillMe), reg);
} else {
ASSERT(spillFormat & DataFormatJS || spillFormat == DataFormatCell);
JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
m_jit.loadPtr(JITCompiler::addressFor(spillMe), reg);
}
}
void silentSpillAllRegisters(GPRReg dontTrample)
{
GPRReg canTrample = (dontTrample == gpr0) ? gpr1 : gpr0;
for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
VirtualRegister name = m_gprs.name(gpr);
if (name != InvalidVirtualRegister)
silentSpill(name, canTrample);
}
for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
VirtualRegister name = m_fprs.name(fpr);
if (name != InvalidVirtualRegister)
silentSpill(name, canTrample);
}
}
void silentFillAllRegisters(GPRReg dontTrample)
{
GPRReg canTrample = (dontTrample == gpr0) ? gpr1 : gpr0;
for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
VirtualRegister name = m_fprs.name(fpr);
if (name != InvalidVirtualRegister)
silentFill(name, canTrample);
}
for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
VirtualRegister name = m_gprs.name(gpr);
if (name != InvalidVirtualRegister)
silentFill(name, canTrample);
}
}
void silentFillAllRegisters(FPRReg dontTrample)
{
GPRReg canTrample = gpr0;
for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
VirtualRegister name = m_fprs.name(fpr);
if (name != InvalidVirtualRegister) {
#ifndef NDEBUG
ASSERT(fpr != dontTrample);
#else
UNUSED_PARAM(dontTrample);
#endif
silentFill(name, canTrample);
}
}
for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
VirtualRegister name = m_gprs.name(gpr);
if (name != InvalidVirtualRegister)
silentFill(name, canTrample);
}
}
// These methods are used to plant calls out to C++
// helper routines to convert between types.
void valueToNumber(JSValueOperand&, FPRReg result);
void valueToInt32(JSValueOperand&, GPRReg result);
void numberToInt32(FPRReg, GPRReg result);
// Record an entry location into the non-speculative code path;
// for every bail-out on the speculative path we record information
// to be able to re-enter into the non-speculative one.
void trackEntry(MacroAssembler::Label entry)
{
m_entryLocations.append(EntryLocation(entry, this));
}
EntryLocationVector m_entryLocations;
};
} } // namespace JSC::DFG
#endif
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -1016,6 +1016,13 @@
#define ENABLE_JIT 1
#endif
/* Currently only implemented for JSVALUE64, only tested on PLATFORM(MAC) */
#if ENABLE(JIT) && USE(JSVALUE64) && PLATFORM(MAC)
#define ENABLE_DFG_JIT 1
/* Enabled with restrictions to circumvent known performance regressions. */
#define ENABLE_DFG_JIT_RESTRICTIONS 1
#endif
/* Ensure that either the JIT or the interpreter has been enabled. */
#if !defined(ENABLE_INTERPRETER) && !ENABLE(JIT)
#define ENABLE_INTERPRETER 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment