Commit b3e5acbf authored by oliver@apple.com's avatar oliver@apple.com

fourthTier: DFG should support op_in and it should use patching to make it fast

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

Source/JavaScriptCore:

Reviewed by Geoffrey Garen.

Implement op_in in the DFG and give it patching. The code we generate is just
a jump on the hot path, and the slow paths generate stubs and link the jump to
them. I didn't want to bother with patching structures and load offsets and
the like, although I probably could have.

This is a ginormous speed-up on microbenchmarks for "in", obviously.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpAssumingJITType):
(JSC::CodeBlock::resetStubInternal):
(JSC::structureStubInfoLessThan):
(JSC):
(JSC::CodeBlock::sortStructureStubInfos):
* bytecode/CodeBlock.h:
(CodeBlock):
* bytecode/StructureStubInfo.cpp:
(JSC::StructureStubInfo::deref):
(JSC::StructureStubInfo::visitWeakReferences):
* bytecode/StructureStubInfo.h:
(JSC::isInAccess):
(JSC):
(StructureStubInfo):
(JSC::StructureStubInfo::initInList):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCCallHelpers.h:
(JSC::DFG::CCallHelpers::setupResults):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGPRInfo.h:
(JSC::DFG::JSValueRegs::payloadOnly):
(JSValueRegs):
(JSC::DFG::JSValueRegs::JSValueRegs):
(JSC::DFG::JSValueRegs::operator!):
(JSC::DFG::JSValueSource::operator!):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
* dfg/DFGJITCompiler.h:
(JSC::DFG::InRecord::InRecord):
(InRecord):
(DFG):
(JITCompiler):
(JSC::DFG::JITCompiler::addIn):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryRepatchIn):
(DFG):
(JSC::DFG::dfgRepatchIn):
(JSC::DFG::dfgResetIn):
* dfg/DFGRepatch.h:
(DFG):
(JSC::DFG::dfgResetIn):
* dfg/DFGSlowPathGenerator.h:
(JSC::DFG::CallSlowPathGenerator::CallSlowPathGenerator):
(JSC::DFG::CallSlowPathGenerator::tearDown):
(JSC::DFG::CallResultAndNoArgumentsSlowPathGenerator::generateInternal):
(JSC::DFG::CallResultAndOneArgumentSlowPathGenerator::generateInternal):
(JSC::DFG::CallResultAndTwoArgumentsSlowPathGenerator::generateInternal):
(JSC::DFG::CallResultAndThreeArgumentsSlowPathGenerator::generateInternal):
(JSC::DFG::CallResultAndFourArgumentsSlowPathGenerator::generateInternal):
(JSC::DFG::CallResultAndFiveArgumentsSlowPathGenerator::generateInternal):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileIn):
(DFG):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::extractResult):
(DFG):
(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::callOperation):
(JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheckSetResult):
(JSC::DFG::SpeculativeJIT::appendCallSetResult):
(JSC::DFG::JSValueOperand::tagGPR):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* runtime/JSCJSValue.cpp:
(JSC::JSValue::dump):
* runtime/JSString.h:
(JSString):
(JSC::JSString::tryGetValueImpl):
(JSC):
* runtime/Operations.h:
(JSC::normalizePrototypeChainForChainAccess):

Source/WTF:

Reviewed by Geoffrey Garen.

Now if you pass a null StringImpl* then something will still get printed instead
of crashing. I figure that this is broadly useful for debug code, and I make use
of it in the JSC portion of this patch.

* wtf/PrintStream.cpp:
(WTF::printInternal):

LayoutTests:

Reviewed by Geoffrey Garen.

Test coverage for op_in performance.

* fast/js/regress/in-four-cases-expected.txt: Added.
* fast/js/regress/in-four-cases.html: Added.
* fast/js/regress/in-one-case-false-expected.txt: Added.
* fast/js/regress/in-one-case-false.html: Added.
* fast/js/regress/in-one-case-true-expected.txt: Added.
* fast/js/regress/in-one-case-true.html: Added.
* fast/js/regress/in-two-cases-expected.txt: Added.
* fast/js/regress/in-two-cases.html: Added.
* fast/js/regress/script-tests/in-four-cases.js: Added.
(foo):
(bar):
* fast/js/regress/script-tests/in-one-case-false.js: Added.
(foo):
(bar):
* fast/js/regress/script-tests/in-one-case-true.js: Added.
(foo):
(bar):
* fast/js/regress/script-tests/in-two-cases.js: Added.
(foo):
(bar):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153225 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 336e13ce
2013-06-11 Filip Pizlo <fpizlo@apple.com>
fourthTier: DFG should support op_in and it should use patching to make it fast
https://bugs.webkit.org/show_bug.cgi?id=117385
Reviewed by Geoffrey Garen.
Test coverage for op_in performance.
* fast/js/regress/in-four-cases-expected.txt: Added.
* fast/js/regress/in-four-cases.html: Added.
* fast/js/regress/in-one-case-false-expected.txt: Added.
* fast/js/regress/in-one-case-false.html: Added.
* fast/js/regress/in-one-case-true-expected.txt: Added.
* fast/js/regress/in-one-case-true.html: Added.
* fast/js/regress/in-two-cases-expected.txt: Added.
* fast/js/regress/in-two-cases.html: Added.
* fast/js/regress/script-tests/in-four-cases.js: Added.
(foo):
(bar):
* fast/js/regress/script-tests/in-one-case-false.js: Added.
(foo):
(bar):
* fast/js/regress/script-tests/in-one-case-true.js: Added.
(foo):
(bar):
* fast/js/regress/script-tests/in-two-cases.js: Added.
(foo):
(bar):
2013-06-11 Geoffrey Garen <ggaren@apple.com>
Rolled back in <http://trac.webkit.org/changeset/151363>.
JSRegress/in-four-cases
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/in-four-cases.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/in-one-case-false
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/in-one-case-false.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/in-one-case-true
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/in-one-case-true.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/in-two-cases
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/in-two-cases.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../resources/js-test-post.js"></script>
</body>
</html>
function foo(a) {
var result = 0;
for (var i = 0; i < a.length; ++i) {
result <<= 1;
result ^= "foo" in a[i];
}
return result;
}
function bar() {
var array = [{foo:42}, {bar:42}, {fuzz:41, foo:43}, {baz: 47}];
var result = 0;
for (var i = 0; i < 1000000; ++i)
result += foo(array);
return result;
}
var result = bar();
if (result != 10000000)
throw "Bad result: " + result;
function foo(a) {
var result = 0;
for (var i = 0; i < a.length; ++i) {
result <<= 1;
result ^= "foo" in a[i];
}
return result;
}
function bar() {
var array = [{bar:42}, {bar:42}];
var result = 0;
for (var i = 0; i < 1000000; ++i)
result += foo(array);
return result;
}
var result = bar();
if (result != 0)
throw "Bad result: " + result;
function foo(a) {
var result = 0;
for (var i = 0; i < a.length; ++i) {
result <<= 1;
result ^= "foo" in a[i];
}
return result;
}
function bar() {
var array = [{foo:42}, {foo:42}];
var result = 0;
for (var i = 0; i < 1000000; ++i)
result += foo(array);
return result;
}
var result = bar();
if (result != 3000000)
throw "Bad result: " + result;
function foo(a) {
var result = 0;
for (var i = 0; i < a.length; ++i) {
result <<= 1;
result ^= "foo" in a[i];
}
return result;
}
function bar() {
var array = [{foo:42}, {bar:42}];
var result = 0;
for (var i = 0; i < 1000000; ++i)
result += foo(array);
return result;
}
var result = bar();
if (result != 2000000)
throw "Bad result: " + result;
2013-06-11 Filip Pizlo <fpizlo@apple.com>
fourthTier: DFG should support op_in and it should use patching to make it fast
https://bugs.webkit.org/show_bug.cgi?id=117385
Reviewed by Geoffrey Garen.
Implement op_in in the DFG and give it patching. The code we generate is just
a jump on the hot path, and the slow paths generate stubs and link the jump to
them. I didn't want to bother with patching structures and load offsets and
the like, although I probably could have.
This is a ginormous speed-up on microbenchmarks for "in", obviously.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpAssumingJITType):
(JSC::CodeBlock::resetStubInternal):
(JSC::structureStubInfoLessThan):
(JSC):
(JSC::CodeBlock::sortStructureStubInfos):
* bytecode/CodeBlock.h:
(CodeBlock):
* bytecode/StructureStubInfo.cpp:
(JSC::StructureStubInfo::deref):
(JSC::StructureStubInfo::visitWeakReferences):
* bytecode/StructureStubInfo.h:
(JSC::isInAccess):
(JSC):
(StructureStubInfo):
(JSC::StructureStubInfo::initInList):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCCallHelpers.h:
(JSC::DFG::CCallHelpers::setupResults):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGPRInfo.h:
(JSC::DFG::JSValueRegs::payloadOnly):
(JSValueRegs):
(JSC::DFG::JSValueRegs::JSValueRegs):
(JSC::DFG::JSValueRegs::operator!):
(JSC::DFG::JSValueSource::operator!):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
* dfg/DFGJITCompiler.h:
(JSC::DFG::InRecord::InRecord):
(InRecord):
(DFG):
(JITCompiler):
(JSC::DFG::JITCompiler::addIn):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryRepatchIn):
(DFG):
(JSC::DFG::dfgRepatchIn):
(JSC::DFG::dfgResetIn):
* dfg/DFGRepatch.h:
(DFG):
(JSC::DFG::dfgResetIn):
* dfg/DFGSlowPathGenerator.h:
(JSC::DFG::CallSlowPathGenerator::CallSlowPathGenerator):
(JSC::DFG::CallSlowPathGenerator::tearDown):
(JSC::DFG::CallResultAndNoArgumentsSlowPathGenerator::generateInternal):
(JSC::DFG::CallResultAndOneArgumentSlowPathGenerator::generateInternal):
(JSC::DFG::CallResultAndTwoArgumentsSlowPathGenerator::generateInternal):
(JSC::DFG::CallResultAndThreeArgumentsSlowPathGenerator::generateInternal):
(JSC::DFG::CallResultAndFourArgumentsSlowPathGenerator::generateInternal):
(JSC::DFG::CallResultAndFiveArgumentsSlowPathGenerator::generateInternal):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileIn):
(DFG):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::extractResult):
(DFG):
(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::callOperation):
(JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheckSetResult):
(JSC::DFG::SpeculativeJIT::appendCallSetResult):
(JSC::DFG::JSValueOperand::tagGPR):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* runtime/JSCJSValue.cpp:
(JSC::JSValue::dump):
* runtime/JSString.h:
(JSString):
(JSC::JSString::tryGetValueImpl):
(JSC):
* runtime/Operations.h:
(JSC::normalizePrototypeChainForChainAccess):
2013-06-12 Geoffrey Garen <ggaren@apple.com>
The Math object should not be polymorphic
......
......@@ -113,7 +113,7 @@ void CodeBlock::dumpAssumingJITType(PrintStream& out, JITCode::JITType jitType)
out.print(inferredName(), "#", hash(), ":[", RawPointer(this), "->", RawPointer(ownerExecutable()), ", ", jitType, codeType());
if (codeType() == FunctionCode)
out.print(specializationKind());
if (m_shouldAlwaysBeInlined)
if (this->jitType() == JITCode::BaselineJIT && m_shouldAlwaysBeInlined)
out.print(" (SABI)");
if (ownerExecutable()->neverInline())
out.print(" (NeverInline)");
......@@ -2282,14 +2282,20 @@ void CodeBlock::resetStubInternal(RepatchBuffer& repatchBuffer, StructureStubInf
case JITCode::BaselineJIT:
if (isGetByIdAccess(accessType))
JIT::resetPatchGetById(repatchBuffer, &stubInfo);
else
else {
RELEASE_ASSERT(isPutByIdAccess(accessType));
JIT::resetPatchPutById(repatchBuffer, &stubInfo);
}
break;
case JITCode::DFGJIT:
if (isGetByIdAccess(accessType))
DFG::dfgResetGetByID(repatchBuffer, stubInfo);
else
else if (isPutByIdAccess(accessType))
DFG::dfgResetPutByID(repatchBuffer, stubInfo);
else {
RELEASE_ASSERT(isInAccess(accessType));
DFG::dfgResetIn(repatchBuffer, stubInfo);
}
break;
default:
RELEASE_ASSERT_NOT_REACHED();
......@@ -3108,6 +3114,16 @@ void CodeBlock::setOptimizationThresholdBasedOnCompilationResult(CompilationResu
}
}
static bool structureStubInfoLessThan(const StructureStubInfo& a, const StructureStubInfo& b)
{
return a.callReturnLocation.executableAddress() < b.callReturnLocation.executableAddress();
}
void CodeBlock::sortStructureStubInfos()
{
std::sort(m_structureStubInfos.begin(), m_structureStubInfos.end(), structureStubInfoLessThan);
}
uint32_t CodeBlock::adjustedExitCountThreshold(uint32_t desiredThreshold)
{
ASSERT(JITCode::isOptimizingJIT(jitType()));
......
......@@ -411,6 +411,7 @@ public:
#if ENABLE(JIT)
void setNumberOfStructureStubInfos(size_t size) { m_structureStubInfos.grow(size); }
void sortStructureStubInfos();
size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); }
StructureStubInfo& structureStubInfo(int index) { return m_structureStubInfos[index]; }
......
......@@ -49,6 +49,11 @@ void StructureStubInfo::deref()
case access_put_by_id_list:
delete u.putByIdList.list;
return;
case access_in_list: {
PolymorphicAccessStructureList* polymorphicStructures = u.inList.structureList;
delete polymorphicStructures;
return;
}
case access_get_by_id_self:
case access_get_by_id_proto:
case access_get_by_id_chain:
......@@ -111,6 +116,12 @@ bool StructureStubInfo::visitWeakReferences()
if (!u.putByIdList.list->visitWeak())
return false;
break;
case access_in_list: {
PolymorphicAccessStructureList* polymorphicStructures = u.inList.structureList;
if (!polymorphicStructures->visitWeak(u.inList.listSize))
return false;
break;
}
default:
// The rest of the instructions don't require references, so there is no need to
// do anything.
......
......@@ -60,6 +60,7 @@ enum AccessType {
access_put_by_id_generic,
access_get_array_length,
access_get_string_length,
access_in_list
};
inline bool isGetByIdAccess(AccessType accessType)
......@@ -93,6 +94,16 @@ inline bool isPutByIdAccess(AccessType accessType)
}
}
inline bool isInAccess(AccessType accessType)
{
switch (accessType) {
case access_in_list:
return true;
default:
return false;
}
}
struct StructureStubInfo {
StructureStubInfo()
: accessType(access_unset)
......@@ -170,6 +181,13 @@ struct StructureStubInfo {
accessType = access_put_by_id_list;
u.putByIdList.list = list;
}
void initInList(PolymorphicAccessStructureList* list, int listSize)
{
accessType = access_in_list;
u.inList.structureList = list;
u.inList.listSize = listSize;
}
void reset()
{
......@@ -296,6 +314,10 @@ struct StructureStubInfo {
struct {
PolymorphicPutByIdList* list;
} putByIdList;
struct {
PolymorphicAccessStructureList* structureList;
int listSize;
} inList;
} u;
RefPtr<JITStubRoutine> stubRoutine;
......
......@@ -1540,6 +1540,13 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
}
clobberWorld(node->codeOrigin, indexInBlock);
break;
case In:
// FIXME: We can determine when the property definitely exists based on abstract
// value information.
clobberWorld(node->codeOrigin, indexInBlock);
forNode(node).setType(SpecBoolean);
break;
case GetGlobalVar:
forNode(node).makeTop();
......
......@@ -3083,6 +3083,12 @@ bool ByteCodeParser::parseBlock(unsigned limit)
addToGraph(Identity, Edge(get(currentInstruction[2].u.operand), NumberUse)));
NEXT_OPCODE(op_to_number);
}
case op_in: {
set(currentInstruction[1].u.operand,
addToGraph(In, get(currentInstruction[2].u.operand), get(currentInstruction[3].u.operand)));
NEXT_OPCODE(op_in);
}
default:
// Parse failed! This should not happen because the capabilities checker
......
......@@ -976,7 +976,11 @@ public:
GPRReg srcA = GPRInfo::returnValueGPR;
GPRReg srcB = GPRInfo::returnValueGPR2;
if (srcB != destA) {
if (destA == InvalidGPRReg)
move(srcB, destB);
else if (destB == InvalidGPRReg)
move(srcA, destA);
else if (srcB != destA) {
// Handle the easy cases - two simple moves.
move(srcA, destA);
move(srcB, destB);
......
......@@ -166,6 +166,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
case op_jneq_ptr:
case op_typeof:
case op_to_number:
case op_in:
case op_get_from_scope:
case op_put_to_scope:
return CanCompileAndInline;
......
......@@ -801,6 +801,14 @@ private:
setUseKindAndUnboxIfProfitable<CellUse>(node->child2());
break;
}
case In: {
// FIXME: We should at some point have array profiling on op_in, in which
// case we would be able to turn this into a kind of GetByVal.
setUseKindAndUnboxIfProfitable<CellUse>(node->child2());
break;
}
case Phantom:
case Identity: {
......
......@@ -51,6 +51,11 @@ public:
{
}
static JSValueRegs payloadOnly(GPRReg gpr)
{
return JSValueRegs(gpr);
}
bool operator!() const { return m_gpr == InvalidGPRReg; }
GPRReg gpr() const { return m_gpr; }
......@@ -137,10 +142,18 @@ public:
: m_tagGPR(tagGPR)
, m_payloadGPR(payloadGPR)
{
ASSERT((static_cast<GPRReg>(m_tagGPR) == InvalidGPRReg) == (static_cast<GPRReg>(payloadGPR) == InvalidGPRReg));
}
bool operator!() const { return static_cast<GPRReg>(m_tagGPR) == InvalidGPRReg; }
static JSValueRegs payloadOnly(GPRReg gpr)
{
return JSValueRegs(InvalidGPRReg, gpr);
}
bool operator!() const
{
return static_cast<GPRReg>(m_tagGPR) == InvalidGPRReg
&& static_cast<GPRReg>(m_payloadGPR) == InvalidGPRReg;
}
GPRReg tagGPR() const { return static_cast<GPRReg>(m_tagGPR); }
GPRReg payloadGPR() const { return static_cast<GPRReg>(m_payloadGPR); }
......@@ -196,7 +209,11 @@ public:
return result;
}
bool operator!() const { return static_cast<GPRReg>(m_baseOrTag) == InvalidGPRReg && static_cast<GPRReg>(m_payload) == InvalidGPRReg; }
bool operator!() const
{
return static_cast<GPRReg>(m_baseOrTag) == InvalidGPRReg
&& static_cast<GPRReg>(m_payload) == InvalidGPRReg;
}
bool isAddress() const
{
......
......@@ -178,7 +178,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
codeOrigins[i] = record.m_codeOrigin;
}
m_codeBlock->setNumberOfStructureStubInfos(m_propertyAccesses.size());
m_codeBlock->setNumberOfStructureStubInfos(m_propertyAccesses.size() + m_ins.size());
for (unsigned i = 0; i < m_propertyAccesses.size(); ++i) {
StructureStubInfo& info = m_codeBlock->structureStubInfo(i);
CodeLocationCall callReturnLocation = linkBuffer.locationOf(m_propertyAccesses[i].m_slowPathGenerator->call());
......@@ -205,6 +205,20 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
m_propertyAccesses[i].m_usedRegisters.copyInfo(info.patch.dfg.usedRegisters);
info.patch.dfg.registersFlushed = m_propertyAccesses[i].m_registerMode == PropertyAccessRecord::RegistersFlushed;
}
for (unsigned i = 0; i < m_ins.size(); ++i) {
StructureStubInfo& info = m_codeBlock->structureStubInfo(m_propertyAccesses.size() + i);
CodeLocationLabel jump = linkBuffer.locationOf(m_ins[i].m_jump);
CodeLocationCall callReturnLocation = linkBuffer.locationOf(m_ins[i].m_slowPathGenerator->call());
info.codeOrigin = m_ins[i].m_codeOrigin;
info.hotPathBegin = jump;
info.callReturnLocation = callReturnLocation;
info.patch.dfg.deltaCallToSlowCase = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_ins[i].m_slowPathGenerator->label()));
info.patch.dfg.baseGPR = m_ins[i].m_baseGPR;
info.patch.dfg.valueGPR = m_ins[i].m_resultGPR;
m_ins[i].m_usedRegisters.copyInfo(info.patch.dfg.usedRegisters);
info.patch.dfg.registersFlushed = false;
}
m_codeBlock->sortStructureStubInfos();
m_codeBlock->setNumberOfCallLinkInfos(m_jsCalls.size());
for (unsigned i = 0; i < m_jsCalls.size(); ++i) {
......
......@@ -235,6 +235,28 @@ struct PropertyAccessRecord {
RegisterMode m_registerMode;
};
struct InRecord {
InRecord(
CodeOrigin codeOrigin, MacroAssembler::PatchableJump jump,
SlowPathGenerator* slowPathGenerator, int8_t baseGPR, int8_t resultGPR,
const RegisterSet& usedRegisters)
: m_codeOrigin(codeOrigin)
, m_jump(jump)
, m_slowPathGenerator(slowPathGenerator)
, m_baseGPR(baseGPR)
, m_resultGPR(resultGPR)
, m_usedRegisters(usedRegisters)