Skip to content

Commit

Permalink
Add AUnused section
Browse files Browse the repository at this point in the history
Summary: Add new AUnused section for code that is almost never called, or code
that will become dead. Use AUnused for stubs of profiling translations
and catch blocks. This should improve locality of live code in astubs.

Reviewed By: @ottoni

Differential Revision: D1327507
  • Loading branch information
aravind authored and JoelMarcey committed May 23, 2014
1 parent 9dac5e1 commit 0ca62fb
Show file tree
Hide file tree
Showing 28 changed files with 229 additions and 125 deletions.
2 changes: 2 additions & 0 deletions hphp/runtime/base/runtime-option.h
Expand Up @@ -384,6 +384,8 @@ class RuntimeOption {
F(uint64_t, JitAMaxUsage, maxUsageDef()) \
F(uint64_t, JitAProfSize, 64 << 20) \
F(uint64_t, JitAStubsSize, 64 << 20) \
F(uint64_t, JitAColdSize, 24 << 20) \
F(uint64_t, JitAFrozenSize, 40 << 20) \
F(uint64_t, JitGlobalDataSize, kJitGlobalDataDef) \
F(bool, AllowHhas, false) \
/* CheckReturnTypeHints:
Expand Down
10 changes: 7 additions & 3 deletions hphp/runtime/vm/jit/back-end-arm.cpp
Expand Up @@ -156,10 +156,14 @@ struct BackEnd : public JIT::BackEnd {
info.stubAddr = reinterpret_cast<TCA>(sim.xreg(ARM::rAsm.code()));
}

JIT::CodeGenerator* newCodeGenerator(const IRUnit& unit, CodeBlock& mainCode,
CodeBlock& stubsCode, MCGenerator* mcg,
JIT::CodeGenerator* newCodeGenerator(const IRUnit& unit,
CodeBlock& mainCode,
CodeBlock& stubsCode,
CodeBlock& unusedCode,
MCGenerator* mcg,
CodegenState& state) override {
return new ARM::CodeGenerator(unit, mainCode, stubsCode, mcg, state);
return new ARM::CodeGenerator(unit, mainCode, stubsCode,
unusedCode, mcg, state);
}

void moveToAlign(CodeBlock& cb,
Expand Down
10 changes: 7 additions & 3 deletions hphp/runtime/vm/jit/back-end-x64.cpp
Expand Up @@ -110,10 +110,14 @@ struct BackEnd : public JIT::BackEnd {
CALLEE_SAVED_BARRIER();
}

JIT::CodeGenerator* newCodeGenerator(const IRUnit& unit, CodeBlock& mainCode,
CodeBlock& stubsCode, MCGenerator* mcg,
JIT::CodeGenerator* newCodeGenerator(const IRUnit& unit,
CodeBlock& mainCode,
CodeBlock& stubsCode,
CodeBlock& unusedCode,
MCGenerator* mcg,
CodegenState& state) override {
return new X64::CodeGenerator(unit, mainCode, stubsCode, mcg, state);
return new X64::CodeGenerator(unit, mainCode, stubsCode,
unusedCode, mcg, state);
}

void moveToAlign(CodeBlock& cb,
Expand Down
1 change: 1 addition & 0 deletions hphp/runtime/vm/jit/back-end.h
Expand Up @@ -97,6 +97,7 @@ class BackEnd {
virtual CodeGenerator* newCodeGenerator(const IRUnit& unit,
CodeBlock& mainCode,
CodeBlock& stubsCode,
CodeBlock& unusedCode,
MCGenerator* mcg,
CodegenState& state) = 0;
virtual void moveToAlign(CodeBlock& cb,
Expand Down
26 changes: 24 additions & 2 deletions hphp/runtime/vm/jit/block.h
Expand Up @@ -41,8 +41,30 @@ struct Block : boost::noncopyable {
typedef InstructionList::reference reference;
typedef InstructionList::const_reference const_reference;

// Execution frequency hint; codegen will put Unlikely blocks in astubs.
enum class Hint { Neither, Likely, Unlikely };
/*
* Execution frequency hint; codegen will put Unlikely blocks in astubs,
* and Unused blocks in aunused.
*
* 'Main' code, or code that executes most frequently, should have either
* the 'Likely' or 'Neither' Block::Hint. Code for these blocks is
* emitted into the 'a' section.
*
* Code that handles infrequent cases should have the 'Unlikely'
* Block::Hint. Example of such code are decref helpers that free objects
* when the ref-count goes to zero. Code for these blocks is emitted into
* the 'astubs' section.
*
* Code that is either executed once, or is highly unlikely to be ever
* executed, or code that will become dead in the future should have
* the 'Unlikely' Hint. Examples of these include Service Request stubs
* (executed once), Catch blocks (highly unlikely), and stubs code
* emitted in profiling mode (which become dead after optimized code is
* emitted). Code for these blocks is emitted into the 'aunused' section.
*
* See also util/code-cache.h for comment on the 'ahot' and 'aprof' sections.
*/

enum class Hint { Neither, Likely, Unlikely, Unused };

explicit Block(unsigned id)
: m_id(id)
Expand Down
5 changes: 4 additions & 1 deletion hphp/runtime/vm/jit/cfg.h
Expand Up @@ -136,7 +136,10 @@ namespace detail {
m_visitor(block);
}
private:
static bool cold(Block* b) { return b->hint() == Block::Hint::Unlikely; }
static bool cold(Block* b) {
return b->hint() == Block::Hint::Unlikely ||
b->hint() == Block::Hint::Unused;
}
private:
boost::dynamic_bitset<> m_visited;
Visitor &m_visitor;
Expand Down
5 changes: 3 additions & 2 deletions hphp/runtime/vm/jit/code-gen-arm.cpp
Expand Up @@ -1415,7 +1415,7 @@ void CodeGenerator::cgSideExitGuardStk(IRInstruction* inst) {
sp[cellsToBytes(extra->checkedSlot) + TVOFF(m_data)],
[&] (ConditionCode cc) {
auto const sk = SrcKey(curFunc(), extra->taken, resumed());
emitBindSideExit(this->m_mainCode, this->m_stubsCode, sk, ccNegate(cc));
emitBindSideExit(this->m_mainCode, this->m_unusedCode, sk, ccNegate(cc));
}
);
}
Expand Down Expand Up @@ -1530,7 +1530,7 @@ void CodeGenerator::cgSyncABIRegs(IRInstruction* inst) {
void CodeGenerator::cgReqBindJmp(IRInstruction* inst) {
emitBindJmp(
m_mainCode,
m_stubsCode,
m_unusedCode,
SrcKey(curFunc(), inst->extra<ReqBindJmp>()->offset, resumed())
);
}
Expand Down Expand Up @@ -1703,6 +1703,7 @@ void CodeGenerator::cgCall(IRInstruction* inst) {
auto const srcKey = m_curInst->marker().sk();
auto const adjust = emitBindCall(m_mainCode,
m_stubsCode,
m_unusedCode,
srcKey,
extra->callee,
extra->numParams);
Expand Down
5 changes: 4 additions & 1 deletion hphp/runtime/vm/jit/code-gen-arm.h
Expand Up @@ -31,10 +31,12 @@ namespace HPHP { namespace JIT { namespace ARM {
struct CodeGenerator : public JIT::CodeGenerator {

CodeGenerator(const IRUnit& unit, CodeBlock& mainCode, CodeBlock& stubsCode,
JIT::MCGenerator* mcg, CodegenState& state)
CodeBlock& unusedCode, JIT::MCGenerator* mcg,
CodegenState& state)
: m_unit(unit)
, m_mainCode(mainCode)
, m_stubsCode(stubsCode)
, m_unusedCode(unusedCode)
, m_as(mainCode)
, m_astubs(stubsCode)
, m_mcg(mcg)
Expand Down Expand Up @@ -139,6 +141,7 @@ struct CodeGenerator : public JIT::CodeGenerator {
const IRUnit& m_unit;
CodeBlock& m_mainCode;
CodeBlock& m_stubsCode;
CodeBlock& m_unusedCode;
vixl::MacroAssembler m_as;
vixl::MacroAssembler m_astubs;
MCGenerator* m_mcg;
Expand Down
31 changes: 16 additions & 15 deletions hphp/runtime/vm/jit/code-gen-x64.cpp
Expand Up @@ -478,8 +478,8 @@ void CodeGenerator::emitReqBindJcc(ConditionCode cc,
TestAndSmashFlags::kAlignJccAndJmp);
auto const patchAddr = a.frontier();
auto const jccStub =
emitEphemeralServiceReq(m_stubsCode,
mcg->getFreeStub(m_stubsCode),
emitEphemeralServiceReq(m_unusedCode,
mcg->getFreeStub(m_unusedCode),
REQ_BIND_JMPCC_FIRST,
patchAddr,
extra->taken,
Expand Down Expand Up @@ -2045,7 +2045,7 @@ void CodeGenerator::cgSideExitJmpInstanceOfBitmask(IRInstruction* inst) {
auto const sk = SrcKey(curFunc(), inst->extra<SideExitJccData>()->taken,
resumed());
emitInstanceBitmaskCheck(inst);
emitBindSideExit(m_mainCode, m_stubsCode,
emitBindSideExit(m_mainCode, m_unusedCode,
opToConditionCode(inst->op()),
sk);
}
Expand All @@ -2054,7 +2054,7 @@ void CodeGenerator::cgSideExitJmpNInstanceOfBitmask(IRInstruction* inst) {
auto const sk = SrcKey(curFunc(), inst->extra<SideExitJccData>()->taken,
resumed());
emitInstanceBitmaskCheck(inst);
emitBindSideExit(m_mainCode, m_stubsCode,
emitBindSideExit(m_mainCode, m_unusedCode,
opToConditionCode(inst->op()),
sk);
}
Expand Down Expand Up @@ -2585,7 +2585,7 @@ void CodeGenerator::emitReqBindAddr(TCA& dest,
SrcKey sk) {
mcg->setJmpTransID((TCA)&dest);

dest = emitServiceReq(m_stubsCode, REQ_BIND_ADDR,
dest = emitServiceReq(m_unusedCode, REQ_BIND_ADDR,
&dest, sk.toAtomicInt());
}

Expand Down Expand Up @@ -2627,8 +2627,8 @@ void CodeGenerator::cgJmpSwitchDest(IRInstruction* inst) {
m_as. cmpq(data->cases - 2, indexReg);
mcg->backEnd().prepareForSmash(m_mainCode, kJmpccLen);
TCA def = emitEphemeralServiceReq(
m_stubsCode,
mcg->getFreeStub(m_stubsCode),
m_unusedCode,
mcg->getFreeStub(m_unusedCode),
REQ_BIND_JMPCC_SECOND,
m_as.frontier(),
data->defaultOff,
Expand All @@ -2652,12 +2652,12 @@ void CodeGenerator::cgJmpSwitchDest(IRInstruction* inst) {
if (data->bounded) {
indexVal -= data->base;
if (indexVal >= data->cases - 2 || indexVal < 0) {
emitBindJmp(m_mainCode, m_stubsCode,
emitBindJmp(m_mainCode, m_unusedCode,
SrcKey(curFunc(), data->defaultOff, resumed()));
return;
}
}
emitBindJmp(m_mainCode, m_stubsCode,
emitBindJmp(m_mainCode, m_unusedCode,
SrcKey(curFunc(), data->targets[indexVal], resumed()));
}
}
Expand Down Expand Up @@ -2960,7 +2960,7 @@ void CodeGenerator::cgEagerSyncVMRegs(IRInstruction* inst) {
void CodeGenerator::cgReqBindJmp(IRInstruction* inst) {
emitBindJmp(
m_mainCode,
m_stubsCode,
m_unusedCode,
SrcKey(curFunc(), inst->extra<ReqBindJmp>()->offset, resumed())
);
}
Expand Down Expand Up @@ -3709,6 +3709,7 @@ void CodeGenerator::cgCall(IRInstruction* inst) {
auto const srcKey = m_curInst->marker().sk();
auto const adjust = emitBindCall(m_mainCode,
m_stubsCode,
m_unusedCode,
srcKey,
extra->callee,
extra->numParams);
Expand Down Expand Up @@ -4572,7 +4573,7 @@ void CodeGenerator::emitSideExitGuard(Type type,
type, typeSrc, dataSrc,
[&](ConditionCode cc) {
auto const sk = SrcKey(curFunc(), taken, resumed());
emitBindSideExit(m_mainCode, m_stubsCode, ccNegate(cc), sk);
emitBindSideExit(m_mainCode, m_unusedCode, ccNegate(cc), sk);
});
}

Expand All @@ -4599,7 +4600,7 @@ void CodeGenerator::cgExitJcc(IRInstruction* inst) {
auto const sk = SrcKey(curFunc(), inst->extra<SideExitJccData>()->taken,
resumed());
emitCompare(inst);
emitBindSideExit(m_mainCode, m_stubsCode,
emitBindSideExit(m_mainCode, m_unusedCode,
opToConditionCode(inst->op()),
sk);
}
Expand All @@ -4608,7 +4609,7 @@ void CodeGenerator::cgExitJccInt(IRInstruction* inst) {
auto const sk = SrcKey(curFunc(), inst->extra<SideExitJccData>()->taken,
resumed());
emitCompareInt(inst);
emitBindSideExit(m_mainCode, m_stubsCode,
emitBindSideExit(m_mainCode, m_unusedCode,
opToConditionCode(inst->op()),
sk);
}
Expand Down Expand Up @@ -5325,7 +5326,7 @@ void CodeGenerator::cgSideExitJmpZero(IRInstruction* inst) {
auto const sk = SrcKey(curFunc(), inst->extra<SideExitJccData>()->taken,
resumed());
emitTestZero(inst->src(0), srcLoc(0));
emitBindSideExit(m_mainCode, m_stubsCode,
emitBindSideExit(m_mainCode, m_unusedCode,
opToConditionCode(inst->op()),
sk);
}
Expand All @@ -5334,7 +5335,7 @@ void CodeGenerator::cgSideExitJmpNZero(IRInstruction* inst) {
auto const sk = SrcKey(curFunc(), inst->extra<SideExitJccData>()->taken,
resumed());
emitTestZero(inst->src(0), srcLoc(0));
emitBindSideExit(m_mainCode, m_stubsCode,
emitBindSideExit(m_mainCode, m_unusedCode,
opToConditionCode(inst->op()),
sk);
}
Expand Down
5 changes: 4 additions & 1 deletion hphp/runtime/vm/jit/code-gen-x64.h
Expand Up @@ -33,10 +33,12 @@ struct CodeGenerator : public JIT::CodeGenerator {
typedef JIT::X64Assembler Asm;

CodeGenerator(const IRUnit& unit, CodeBlock& mainCode, CodeBlock& stubsCode,
JIT::MCGenerator* mcg, CodegenState& state)
CodeBlock& unusedCode, JIT::MCGenerator* mcg,
CodegenState& state)
: m_unit(unit)
, m_mainCode(mainCode)
, m_stubsCode(stubsCode)
, m_unusedCode(unusedCode)
, m_as(mainCode)
, m_astubs(stubsCode)
, m_mcg(mcg)
Expand Down Expand Up @@ -339,6 +341,7 @@ struct CodeGenerator : public JIT::CodeGenerator {
const IRUnit& m_unit;
CodeBlock& m_mainCode;
CodeBlock& m_stubsCode;
CodeBlock& m_unusedCode;
Asm m_as; // current "main" assembler
Asm m_astubs; // for stubs and other cold code
MCGenerator* m_mcg;
Expand Down
29 changes: 18 additions & 11 deletions hphp/runtime/vm/jit/code-gen.cpp
Expand Up @@ -76,11 +76,13 @@ LiveRegs computeLiveRegs(const IRUnit& unit, const RegAllocInfo& regs) {
}

static void genBlock(IRUnit& unit, CodeBlock& cb, CodeBlock& stubsCode,
MCGenerator* mcg, CodegenState& state, Block* block,
CodeBlock& unusedCode, MCGenerator* mcg,
CodegenState& state, Block* block,
std::vector<TransBCMapping>* bcMap) {
FTRACE(6, "genBlock: {}\n", block->id());
std::unique_ptr<CodeGenerator> cg(mcg->backEnd().newCodeGenerator(unit, cb,
stubsCode,
unusedCode,
mcg,
state));

Expand All @@ -105,9 +107,7 @@ static void genBlock(IRUnit& unit, CodeBlock& cb, CodeBlock& stubsCode,
}
}

void genCodeImpl(CodeBlock& mainCode,
CodeBlock& stubsCode,
IRUnit& unit,
void genCodeImpl(IRUnit& unit,
std::vector<TransBCMapping>* bcMap,
JIT::MCGenerator* mcg,
const RegAllocInfo& regs,
Expand All @@ -120,6 +120,9 @@ void genCodeImpl(CodeBlock& mainCode,
return state.addresses[block];
};

CodeBlock& mainCode = mcg->code.main();
CodeBlock& stubsCode = mcg->code.stubs();
CodeBlock& unusedCode = mcg->code.unused();
mcg->code.lock();
SCOPE_EXIT { mcg->code.unlock(); };

Expand Down Expand Up @@ -149,7 +152,7 @@ void genCodeImpl(CodeBlock& mainCode,
state.asmInfo->asmRanges[block] = TcaRange(aStart, cb.frontier());
}

genBlock(unit, cb, stubsCode, mcg, state, block, bcMap);
genBlock(unit, cb, stubsCode, unusedCode, mcg, state, block, bcMap);
auto nextFlow = block->next();
if (nextFlow && nextFlow != nextLinear) {
mcg->backEnd().emitFwdJmp(cb, nextFlow, state);
Expand All @@ -175,11 +178,16 @@ void genCodeImpl(CodeBlock& mainCode,
? *boost::next(it) : nullptr;
emitBlock(mainCode, *it, nextLinear);
}
for (auto it = linfo.astubsIt; it != linfo.blocks.end(); ++it) {
Block* nextLinear = boost::next(it) != linfo.blocks.end()
for (auto it = linfo.astubsIt; it != linfo.aunusedIt; ++it) {
Block* nextLinear = boost::next(it) != linfo.aunusedIt
? *boost::next(it) : nullptr;
emitBlock(stubsCode, *it, nextLinear);
}
for (auto it = linfo.aunusedIt; it != linfo.blocks.end(); ++it) {
Block* nextLinear = boost::next(it) != linfo.blocks.end()
? *boost::next(it) : nullptr;
emitBlock(unusedCode, *it, nextLinear);
}

if (debug) {
for (Block* UNUSED block : linfo.blocks) {
Expand All @@ -188,18 +196,17 @@ void genCodeImpl(CodeBlock& mainCode,
}
}

void genCode(CodeBlock& main, CodeBlock& stubs, IRUnit& unit,
std::vector<TransBCMapping>* bcMap,
void genCode(IRUnit& unit, std::vector<TransBCMapping>* bcMap,
JIT::MCGenerator* mcg,
const RegAllocInfo& regs) {
Timer _t(Timer::codeGen);

if (dumpIREnabled()) {
AsmInfo ai(unit);
genCodeImpl(main, stubs, unit, bcMap, mcg, regs, &ai);
genCodeImpl(unit, bcMap, mcg, regs, &ai);
printUnit(kCodeGenLevel, unit, " after code gen ", &regs, &ai);
} else {
genCodeImpl(main, stubs, unit, bcMap, mcg, regs, nullptr);
genCodeImpl(unit, bcMap, mcg, regs, nullptr);
}
}

Expand Down
5 changes: 2 additions & 3 deletions hphp/runtime/vm/jit/code-gen.h
Expand Up @@ -20,6 +20,7 @@
#include "hphp/runtime/vm/jit/types.h"
#include "hphp/runtime/vm/jit/state-vector.h"
#include "hphp/runtime/vm/jit/translator.h"
#include "hphp/util/code-cache.h"

namespace HPHP { namespace JIT {

Expand Down Expand Up @@ -97,9 +98,7 @@ const Func* loadClassCtor(Class* cls);

LiveRegs computeLiveRegs(const IRUnit& unit, const RegAllocInfo& regs);

void genCode(CodeBlock& mainCode,
CodeBlock& stubsCode,
IRUnit& unit,
void genCode(IRUnit& unit,
std::vector<TransBCMapping>* bcMap,
MCGenerator* mcg,
const RegAllocInfo& regs);
Expand Down

0 comments on commit 0ca62fb

Please sign in to comment.