Commit 1a72409c authored by fpizlo@apple.com's avatar fpizlo@apple.com

Infer one-time scopes

https://bugs.webkit.org/show_bug.cgi?id=124812

Source/JavaScriptCore: 

Reviewed by Oliver Hunt.
        
This detects JSActivations that are created only once. The JSActivation pointer is then
baked into the machine code.
        
This takes advantage of the one-time scope inference to reduce the number of
indirections needed to get to a closure variable in case where the scope is only
allocated once. This isn't really a speed-up since in the common case the total number
of instruction bytes needed to load the scope from the stack is about equal to the
number of instruction bytes needed to materialize the absolute address of a scoped
variable. But, this is a necessary prerequisite to
https://bugs.webkit.org/show_bug.cgi?id=124630, so it's probably a good idea anyway.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecode/Instruction.h:
* bytecode/Opcode.h:
(JSC::padOpcodeName):
* bytecode/Watchpoint.h:
(JSC::WatchpointSet::notifyWrite):
(JSC::InlineWatchpointSet::notifyWrite):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitResolveScope):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::scopedVarLoadElimination):
(JSC::DFG::CSEPhase::scopedVarStoreElimination):
(JSC::DFG::CSEPhase::getLocalLoadElimination):
(JSC::DFG::CSEPhase::setLocalStoreElimination):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::tryGetRegisters):
* dfg/DFGGraph.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::varNumber):
(JSC::DFG::Node::hasSymbolTable):
(JSC::DFG::Node::symbolTable):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGWatchpointCollectionPhase.cpp:
(JSC::DFG::WatchpointCollectionPhase::handle):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileGetClosureRegisters):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/JSActivation.h:
(JSC::JSActivation::create):
* runtime/JSScope.cpp:
(JSC::abstractAccess):
(JSC::JSScope::abstractResolve):
* runtime/JSScope.h:
(JSC::ResolveOp::ResolveOp):
* runtime/JSVariableObject.h:
(JSC::JSVariableObject::registers):
* runtime/SymbolTable.cpp:
(JSC::SymbolTable::SymbolTable):
* runtime/SymbolTable.h:

LayoutTests: 

Reviewed by Oliver Hunt.

* js/regress/infer-one-time-closure-expected.txt: Added.
* js/regress/infer-one-time-closure-ten-vars-expected.txt: Added.
* js/regress/infer-one-time-closure-ten-vars.html: Added.
* js/regress/infer-one-time-closure-two-vars-expected.txt: Added.
* js/regress/infer-one-time-closure-two-vars.html: Added.
* js/regress/infer-one-time-closure.html: Added.
* js/regress/infer-one-time-deep-closure-expected.txt: Added.
* js/regress/infer-one-time-deep-closure.html: Added.
* js/regress/script-tests/infer-one-time-closure-ten-vars.js: Added.
* js/regress/script-tests/infer-one-time-closure-two-vars.js: Added.
* js/regress/script-tests/infer-one-time-closure.js: Added.
* js/regress/script-tests/infer-one-time-deep-closure.js: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@159834 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 1b53aa12
2013-11-27 Filip Pizlo <fpizlo@apple.com>
Infer one-time scopes
https://bugs.webkit.org/show_bug.cgi?id=124812
Reviewed by Oliver Hunt.
* js/regress/infer-one-time-closure-expected.txt: Added.
* js/regress/infer-one-time-closure-ten-vars-expected.txt: Added.
* js/regress/infer-one-time-closure-ten-vars.html: Added.
* js/regress/infer-one-time-closure-two-vars-expected.txt: Added.
* js/regress/infer-one-time-closure-two-vars.html: Added.
* js/regress/infer-one-time-closure.html: Added.
* js/regress/infer-one-time-deep-closure-expected.txt: Added.
* js/regress/infer-one-time-deep-closure.html: Added.
* js/regress/script-tests/infer-one-time-closure-ten-vars.js: Added.
* js/regress/script-tests/infer-one-time-closure-two-vars.js: Added.
* js/regress/script-tests/infer-one-time-closure.js: Added.
* js/regress/script-tests/infer-one-time-deep-closure.js: Added.
2013-11-27 Eric Carlson <eric.carlson@apple.com>
Allow the QuickTime plug-in to be replaced by script in an isolated word
......
JSRegress/infer-one-time-closure
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
JSRegress/infer-one-time-closure-ten-vars
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/infer-one-time-closure-ten-vars.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/infer-one-time-closure-two-vars
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/infer-one-time-closure-two-vars.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/infer-one-time-closure.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/infer-one-time-deep-closure
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/infer-one-time-deep-closure.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
function fooMaker(xParam) {
var x = xParam;
var x2 = xParam + 1;
var x3 = xParam + 2;
var x4 = xParam + 3;
var x5 = xParam + 4;
var x6 = xParam + 5;
var x7 = xParam + 6;
var x8 = xParam + 7;
var x9 = xParam + 8;
var x10 = xParam + 9;
return function (y) {
for (var i = 0; i < 1000; ++i)
y += x + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;
return y;
}
}
var foo = fooMaker(42);
noInline(foo);
for (var i = 0; i < 10000; ++i) {
var result = foo(5);
if (result != 465005)
throw "Error: bad result: " + result;
}
var result = fooMaker(23)(5);
if (result != 275005)
throw "Error: bad result: " + result;
function fooMaker(xParam) {
var x = xParam;
var x2 = xParam + 1;
return function (y) {
for (var i = 0; i < 1000; ++i)
y += x + x2;
return y;
}
}
var foo = fooMaker(42);
noInline(foo);
for (var i = 0; i < 10000; ++i) {
var result = foo(5);
if (result != (42 + 43) * 1000 + 5)
throw "Error: bad result: " + result;
}
var result = fooMaker(23)(5);
if (result != (23 + 24) * 1000 + 5)
throw "Error: bad result: " + result;
function fooMaker(xParam) {
var x = xParam;
return function (y) {
for (var i = 0; i < 1000; ++i)
y += x;
return y;
}
}
var foo = fooMaker(42);
noInline(foo);
for (var i = 0; i < 10000; ++i) {
var result = foo(5);
if (result != 42 * 1000 + 5)
throw "Error: bad result: " + result;
}
var result = fooMaker(23)(5);
if (result != 23 * 1000 + 5)
throw "Error: bad result: " + result;
function fooMaker(aParam) {
var a = aParam;
return function(bParam) {
var b = bParam;
return function(cParam) {
var c = cParam;
return function(dParam) {
var d = dParam;
return function(eParam) {
var e = eParam;
return function (fParam) {
var f = a + b + c + d + e + fParam;
for (var i = 0; i < 1000; ++i)
f += a;
return f;
};
};
};
};
};
}
var foo = fooMaker(42)(1)(2)(3)(4);
noInline(foo);
for (var i = 0; i < 20000; ++i) {
var result = foo(5);
if (result != 42057)
throw "Error: bad result: " + result;
}
var result = fooMaker(23)(2)(3)(4)(5)(5);
if (result != 23042)
throw "Error: bad result: " + result;
2013-11-27 Filip Pizlo <fpizlo@apple.com>
Infer one-time scopes
https://bugs.webkit.org/show_bug.cgi?id=124812
Reviewed by Oliver Hunt.
This detects JSActivations that are created only once. The JSActivation pointer is then
baked into the machine code.
This takes advantage of the one-time scope inference to reduce the number of
indirections needed to get to a closure variable in case where the scope is only
allocated once. This isn't really a speed-up since in the common case the total number
of instruction bytes needed to load the scope from the stack is about equal to the
number of instruction bytes needed to materialize the absolute address of a scoped
variable. But, this is a necessary prerequisite to
https://bugs.webkit.org/show_bug.cgi?id=124630, so it's probably a good idea anyway.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecode/Instruction.h:
* bytecode/Opcode.h:
(JSC::padOpcodeName):
* bytecode/Watchpoint.h:
(JSC::WatchpointSet::notifyWrite):
(JSC::InlineWatchpointSet::notifyWrite):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitResolveScope):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::scopedVarLoadElimination):
(JSC::DFG::CSEPhase::scopedVarStoreElimination):
(JSC::DFG::CSEPhase::getLocalLoadElimination):
(JSC::DFG::CSEPhase::setLocalStoreElimination):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::tryGetRegisters):
* dfg/DFGGraph.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::varNumber):
(JSC::DFG::Node::hasSymbolTable):
(JSC::DFG::Node::symbolTable):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGWatchpointCollectionPhase.cpp:
(JSC::DFG::WatchpointCollectionPhase::handle):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileGetClosureRegisters):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/JSActivation.h:
(JSC::JSActivation::create):
* runtime/JSScope.cpp:
(JSC::abstractAccess):
(JSC::JSScope::abstractResolve):
* runtime/JSScope.h:
(JSC::ResolveOp::ResolveOp):
* runtime/JSVariableObject.h:
(JSC::JSVariableObject::registers):
* runtime/SymbolTable.cpp:
(JSC::SymbolTable::SymbolTable):
* runtime/SymbolTable.h:
2013-11-27 Filip Pizlo <fpizlo@apple.com>
Finally fix some obvious Bartlett bugs
......
......@@ -1365,6 +1365,7 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
++it; // depth
printLocationAndOp(out, exec, location, it, "resolve_scope");
out.printf("%s, %s, %d", registerName(r0).data(), idName(id0, identifier(id0)).data(), resolveModeAndType);
++it;
break;
}
case op_get_from_scope: {
......@@ -1764,6 +1765,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), scope, ident, Get, type);
instructions[i + 3].u.operand = op.type;
instructions[i + 4].u.operand = op.depth;
if (op.activation)
instructions[i + 5].u.activation.set(*vm(), ownerExecutable, op.activation);
break;
}
......@@ -1781,7 +1784,9 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), scope, ident, Get, modeAndType.type());
instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand();
if (op.structure)
if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks)
instructions[i + 5].u.watchpointSet = op.watchpointSet;
else if (op.structure)
instructions[i + 5].u.structure.set(*vm(), ownerExecutable, op.structure);
instructions[i + 6].u.pointer = reinterpret_cast<void*>(op.operand);
break;
......@@ -1794,10 +1799,9 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), scope, ident, Put, modeAndType.type());
instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand();
if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks) {
ASSERT(!op.structure);
if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks)
instructions[i + 5].u.watchpointSet = op.watchpointSet;
} else if (op.structure)
else if (op.structure)
instructions[i + 5].u.structure.set(*vm(), ownerExecutable, op.structure);
instructions[i + 6].u.pointer = reinterpret_cast<void*>(op.operand);
break;
......@@ -2183,6 +2187,15 @@ void CodeBlock::finalizeUnconditionally()
dataLogF("Clearing LLInt get callee with function %p.\n", curInstruction[2].u.jsCell.get());
curInstruction[2].u.jsCell.clear();
break;
case op_resolve_scope: {
WriteBarrierBase<JSActivation>& activation = curInstruction[5].u.activation;
if (!activation || Heap::isMarked(activation.get()))
break;
if (Options::verboseOSR())
dataLogF("Clearing dead activation %p.\n", activation.get());
activation.clear();
break;
}
case op_get_from_scope:
case op_put_to_scope: {
ResolveModeAndType modeAndType =
......@@ -2193,7 +2206,7 @@ void CodeBlock::finalizeUnconditionally()
if (!structure || Heap::isMarked(structure.get()))
break;
if (Options::verboseOSR())
dataLogF("Clearing LLInt scope access with structure %p.\n", structure.get());
dataLogF("Clearing scope access with structure %p.\n", structure.get());
structure.clear();
break;
}
......
......@@ -117,6 +117,7 @@ struct Instruction {
ArrayAllocationProfile* arrayAllocationProfile;
ObjectAllocationProfile* objectAllocationProfile;
VariableWatchpointSet* watchpointSet;
WriteBarrierBase<JSActivation> activation;
void* pointer;
bool* predicatePointer;
} u;
......
......@@ -169,7 +169,7 @@ namespace JSC {
macro(op_get_pnames, 6) \
macro(op_next_pname, 7) \
\
macro(op_resolve_scope, 5) \
macro(op_resolve_scope, 6) \
macro(op_get_from_scope, 8) /* has value profiling */ \
macro(op_put_to_scope, 7) \
\
......
......@@ -108,6 +108,14 @@ public:
fireAllSlow();
}
void notifyWrite()
{
if (state() == ClearWatchpoint)
startWatching();
else
fireAll();
}
int8_t* addressOfState() { return &m_state; }
int8_t* addressOfSetIsNotEmpty() { return &m_setIsNotEmpty; }
......@@ -201,6 +209,19 @@ public:
WTF::storeStoreFence();
}
void notifyWrite()
{
if (isFat()) {
fat()->notifyWrite();
return;
}
if (decodeState(m_data) == ClearWatchpoint)
m_data = encodeState(IsWatched);
else
m_data = encodeState(IsInvalidated);
WTF::storeStoreFence();
}
private:
static const uintptr_t IsThinFlag = 1;
static const uintptr_t StateMask = 6;
......
......@@ -1212,6 +1212,8 @@ ResolveType BytecodeGenerator::resolveType()
RegisterID* BytecodeGenerator::emitResolveScope(RegisterID* dst, const Identifier& identifier)
{
m_codeBlock->addPropertyAccessInstruction(instructions().size());
ASSERT(!m_symbolTable || !m_symbolTable->contains(identifier.impl()) || resolveType() == Dynamic);
// resolve_scope dst, id, ResolveType, depth
......@@ -1220,6 +1222,7 @@ RegisterID* BytecodeGenerator::emitResolveScope(RegisterID* dst, const Identifie
instructions().append(addConstant(identifier));
instructions().append(resolveType());
instructions().append(0);
instructions().append(0);
return dst;
}
......
......@@ -1145,6 +1145,9 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
m_graph, m_codeBlock->globalObjectFor(node->codeOrigin)->activationStructure());
m_state.setHaveStructures(true);
break;
case ActivationAllocationWatchpoint:
break;
case CreateArguments:
forNode(node).setType(SpecArguments);
......
......@@ -36,6 +36,7 @@
#include "DFGCapabilities.h"
#include "DFGJITCode.h"
#include "GetByIdStatus.h"
#include "JSActivation.h"
#include "Operations.h"
#include "PreciseJumpTargets.h"
#include "PutByIdStatus.h"
......@@ -3046,9 +3047,18 @@ bool ByteCodeParser::parseBlock(unsigned limit)
set(VirtualRegister(dst), cellConstant(m_inlineStackTop->m_codeBlock->globalObject()));
break;
case ClosureVar:
case ClosureVarWithVarInjectionChecks:
set(VirtualRegister(dst), getScope(m_inlineStackTop->m_codeBlock->needsActivation(), depth));
case ClosureVarWithVarInjectionChecks: {
JSActivation* activation = currentInstruction[5].u.activation.get();
if (activation
&& activation->symbolTable()->m_activationAllocatedOnce.isStillValid()) {
addToGraph(ActivationAllocationWatchpoint, OpInfo(activation->symbolTable()));
set(VirtualRegister(dst), cellConstant(activation));
break;
}
set(VirtualRegister(dst),
getScope(m_inlineStackTop->m_codeBlock->needsActivation(), depth));
break;
}
case Dynamic:
RELEASE_ASSERT_NOT_REACHED();
break;
......@@ -3063,14 +3073,20 @@ bool ByteCodeParser::parseBlock(unsigned limit)
StringImpl* uid = m_graph.identifiers()[identifierNumber];
ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
Structure* structure;
Structure* structure = 0;
WatchpointSet* watchpoints = 0;
uintptr_t operand;
{
ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
structure = currentInstruction[5].u.structure.get();
if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks)
watchpoints = currentInstruction[5].u.watchpointSet;
else
structure = currentInstruction[5].u.structure.get();
operand = reinterpret_cast<uintptr_t>(currentInstruction[6].u.pointer);
}
UNUSED_PARAM(watchpoints); // We will use this in the future. For now we set it as a way of documenting the fact that that's what index 5 is in GlobalVar mode.
SpeculatedType prediction = getPrediction();
JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
......@@ -3101,7 +3117,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction)));
break;
}
addToGraph(VariableWatchpoint, OpInfo(watchpointSet));
if (specificValue.isCell())
set(VirtualRegister(dst), cellConstant(specificValue.asCell()));
......@@ -3110,11 +3126,13 @@ bool ByteCodeParser::parseBlock(unsigned limit)
break;
}
case ClosureVar:
case ClosureVarWithVarInjectionChecks:
case ClosureVarWithVarInjectionChecks: {
Node* scopeNode = get(VirtualRegister(scope));
set(VirtualRegister(dst),
addToGraph(GetClosureVar, OpInfo(operand), OpInfo(prediction),
addToGraph(GetClosureRegisters, get(VirtualRegister(scope)))));
addToGraph(GetClosureRegisters, scopeNode)));
break;
}
case Dynamic:
RELEASE_ASSERT_NOT_REACHED();
break;
......
......@@ -227,7 +227,7 @@ private:
return 0;
}
Node* scopedVarLoadElimination(Node* registers, unsigned varNumber)
Node* scopedVarLoadElimination(Node* registers, int varNumber)
{
for (unsigned i = m_indexInBlock; i--;) {
Node* node = m_currentBlock->at(i);
......@@ -296,7 +296,7 @@ private:
return 0;
}
Node* scopedVarStoreElimination(Node* scope, Node* registers, unsigned varNumber)
Node* scopedVarStoreElimination(Node* scope, Node* registers, int varNumber)
{
for (unsigned i = m_indexInBlock; i--;) {
Node* node = m_currentBlock->at(i);
......@@ -316,7 +316,8 @@ private:
break;
}
case GetLocal: {
case GetLocal:
case SetLocal: {
VariableAccessData* variableAccessData = node->variableAccessData();
if (variableAccessData->isCaptured()
&& variableAccessData->local() == static_cast<VirtualRegister>(varNumber))
......@@ -829,6 +830,7 @@ private:
}
break;
case GetClosureVar:
case PutClosureVar:
if (static_cast<VirtualRegister>(node->varNumber()) == local)
return 0;
......@@ -882,6 +884,7 @@ private:
}
case GetClosureVar:
case PutClosureVar:
if (static_cast<VirtualRegister>(node->varNumber()) == local)
result.mayBeAccessed = true;
break;
......
......@@ -155,9 +155,14 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
case CreateActivation:
case CreateArguments:
write(SideState);
write(Watchpoint_fire);
read(GCState);
write(GCState);
return;
case ActivationAllocationWatchpoint:
read(Watchpoint_fire);
return;
// These are forward-exiting nodes that assume that the subsequent instruction
// is a MovHint, and they try to roll forward over this MovHint in their
......
......@@ -954,6 +954,7 @@ private:
case Unreachable:
case ExtractOSREntryLocal:
case LoopHint:
case ActivationAllocationWatchpoint:
break;
#else
default:
......
......@@ -35,6 +35,7 @@
#include "FullBytecodeLiveness.h"
#include "FunctionExecutableDump.h"
#include "JIT.h"
#include "JSActivation.h"
#include "OperandsInlines.h"
#include "Operations.h"
#include <wtf/CommaPrinter.h>
......@@ -722,6 +723,18 @@ unsigned Graph::requiredRegisterCountForExecutionAndExit()
return std::max(frameRegisterCount(), requiredRegisterCountForExit());
}
WriteBarrierBase<Unknown>* Graph::tryGetRegisters(Node* node)
{
if (!node->hasConstant())
return 0;
JSActivation* activation = jsDynamicCast<JSActivation*>(valueOfJSConstant(node));
if (!activation)
return 0;
if (!activation->isTornOff())
return 0;
return activation->registers();
}
} } // namespace JSC::DFG
#endif
......@@ -791,6 +791,8 @@ public:
unsigned requiredRegisterCountForExit();
unsigned requiredRegisterCountForExecutionAndExit();
WriteBarrierBase<Unknown>* tryGetRegisters(Node*);
VM& m_vm;
Plan& m_plan;