Skip to content

Commit

Permalink
Add a vector base location representing $this
Browse files Browse the repository at this point in the history
This diff adds a new location code 'H', representing $this in
the current frame. A new instruction, CheckThis, is used to preserve
the time at which fatals from a null $this occur. While the primary
purpose of the new location code is to further complicate the emitter
and runtime/translator, it also has the nice side effect of avoiding
about half of the increfs/decrefs we used to perform on $this.
  • Loading branch information
swtaarrs authored and sgolemon committed Oct 12, 2012
1 parent 51c10ae commit 14a61b7
Show file tree
Hide file tree
Showing 17 changed files with 239 additions and 99 deletions.
5 changes: 5 additions & 0 deletions doc/bytecode.specification
Expand Up @@ -3402,6 +3402,11 @@ This [] -> [C:Obj]
instruction throws a fatal error. Next, this instruction pushes the current
instance onto the stack.

CheckThis [] -> []

Check existence of this. This instruction checks the current instance, and if
it is null, throws a fatal error.

InitThisLoc <local variable id> [] -> []

Initialize this local variable. This instruction checks the current instance,
Expand Down
31 changes: 23 additions & 8 deletions src/compiler/analysis/emitter.cpp
Expand Up @@ -115,6 +115,7 @@ namespace StackSym {
static const char L = 0x06; // Local symbolic flavor
static const char T = 0x07; // String literal symbolic flavor
static const char I = 0x08; // int literal symbolic flavor
static const char H = 0x09; // $this symbolic flavor

static const char N = 0x10; // Name marker
static const char G = 0x20; // Global name marker
Expand Down Expand Up @@ -151,6 +152,7 @@ namespace StackSym {
case StackSym::L: res = "L"; break;
case StackSym::T: res = "T"; break;
case StackSym::I: res = "I"; break;
case StackSym::H: res = "H"; break;
default: break;
}
char marker = StackSym::GetMarker(sym);
Expand Down Expand Up @@ -620,7 +622,7 @@ std::string SymbolicStack::pretty() const {

void SymbolicStack::push(char sym) {
if (sym != StackSym::W && sym != StackSym::K && sym != StackSym::L &&
sym != StackSym::T && sym != StackSym::I) {
sym != StackSym::T && sym != StackSym::I && sym != StackSym::H) {
m_actualStack.push_back(m_symStack.size());
*m_actualStackHighWaterPtr = MAX(*m_actualStackHighWaterPtr,
(int)m_actualStack.size());
Expand All @@ -634,7 +636,8 @@ void SymbolicStack::pop() {
char sym = m_symStack.back().sym;
char flavor = StackSym::GetSymFlavor(sym);
if (StackSym::GetMarker(sym) != StackSym::W &&
flavor != StackSym::L && flavor != StackSym::T && flavor != StackSym::I) {
flavor != StackSym::L && flavor != StackSym::T && flavor != StackSym::I &&
flavor != StackSym::H) {
ASSERT(!m_actualStack.empty());
m_actualStack.pop_back();
}
Expand Down Expand Up @@ -1181,12 +1184,12 @@ void EmitterVisitor::popEvalStackLMany() {
char symFlavor = StackSym::GetSymFlavor(sym);
m_evalStack.pop();
if (symFlavor != StackSym::C && symFlavor != StackSym::L &&
symFlavor != StackSym::R) {
symFlavor != StackSym::R && symFlavor != StackSym::H) {
InvariantViolation(
"Emitter emitted an instruction that tries to consume a "
"value from the stack when the top of the stack does not "
"match the symbolic flavor that the instruction expects "
"(expected symbolic flavor \"C\", \"L\", or \"R\", actual "
"(expected symbolic flavor \"C\", \"L\", \"R\", or \"H\", actual "
"symbolic flavor \"%s\" at offset %d)",
StackSym::ToString(symFlavor).c_str(),
m_ue.bcPos());
Expand Down Expand Up @@ -3120,7 +3123,18 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
case Expression::KindOfObjectPropertyExpression: {
ObjectPropertyExpressionPtr op(
static_pointer_cast<ObjectPropertyExpression>(node));
visit(op->getObject());
ExpressionPtr obj = op->getObject();
SimpleVariablePtr sv = dynamic_pointer_cast<SimpleVariable>(obj);
if (sv && sv->isThis() && sv->hasContext(Expression::ObjectContext)) {
if (sv->isGuarded()) {
m_metaInfo.add(m_ue.bcPos(), Unit::MetaInfo::GuardedThis,
false, 0, 0);
}
e.CheckThis();
m_evalStack.push(StackSym::H);
} else {
visit(obj);
}
StringData* clsName = getClassName(op->getObject());
if (clsName) {
m_evalStack.setKnownCls(clsName, false);
Expand Down Expand Up @@ -3555,13 +3569,14 @@ void EmitterVisitor::buildVectorImm(std::vector<uchar>& vectorImm,
vectorImm.push_back(LC);
} else if (symFlavor == StackSym::R) {
vectorImm.push_back(LR);
} else if (symFlavor == StackSym::H) {
vectorImm.push_back(LH);
} else {
ASSERT(false);
not_reached();
}
} break;
default: {
ASSERT(false);
break;
not_reached();
}
}
if (symFlavor == StackSym::L) {
Expand Down
37 changes: 30 additions & 7 deletions src/runtime/vm/bytecode.cpp
Expand Up @@ -3095,6 +3095,7 @@ inline void OPTBLD_INLINE VMExecutionContext::getHelperPre(
TypedValue* fr = NULL;
TypedValue* cref;
TypedValue* pname;
tvWriteUninit(&tvScratch);

switch (lcode) {
case LNL:
Expand Down Expand Up @@ -3178,11 +3179,17 @@ inline void OPTBLD_INLINE VMExecutionContext::getHelperPre(
case LR:
loc = m_stack.indTV(depth--);
break;
default: ASSERT(false);
case LH:
ASSERT(m_fp->hasThis());
tvScratch.m_type = KindOfObject;
tvScratch.m_data.pobj = m_fp->getThis();
loc = &tvScratch;
break;

default: not_reached();
}

base = loc;
tvWriteUninit(&tvScratch);
tvWriteUninit(&tvLiteral);
tvWriteUninit(&tvRef);
tvWriteUninit(&tvRef2);
Expand Down Expand Up @@ -3387,6 +3394,7 @@ inline bool OPTBLD_INLINE VMExecutionContext::setHelperPre(
TypedValue* fr = NULL;
TypedValue* cref;
TypedValue* pname;
tvWriteUninit(&tvScratch);

switch (lcode) {
case LNL:
Expand Down Expand Up @@ -3478,11 +3486,17 @@ inline bool OPTBLD_INLINE VMExecutionContext::setHelperPre(
case LR:
loc = m_stack.indTV(depth--);
break;
default: ASSERT(false);
case LH:
ASSERT(m_fp->hasThis());
tvScratch.m_type = KindOfObject;
tvScratch.m_data.pobj = m_fp->getThis();
loc = &tvScratch;
break;

default: not_reached();
}

base = loc;
tvWriteUninit(&tvScratch);
tvWriteUninit(&tvLiteral);
tvWriteUninit(&tvRef);
tvWriteUninit(&tvRef2);
Expand Down Expand Up @@ -6343,15 +6357,24 @@ inline void OPTBLD_INLINE VMExecutionContext::iopDefCls(PC& pc) {
Unit::defClass(c);
}

inline void OPTBLD_INLINE VMExecutionContext::iopThis(PC& pc) {
NEXT();
if (!m_fp->hasThis()) {
static inline void checkThis(ActRec* fp) {
if (!fp->hasThis()) {
raise_error(Strings::FATAL_NULL_THIS);
}
}

inline void OPTBLD_INLINE VMExecutionContext::iopThis(PC& pc) {
NEXT();
checkThis(m_fp);
ObjectData* this_ = m_fp->getThis();
m_stack.pushObject(this_);
}

inline void OPTBLD_INLINE VMExecutionContext::iopCheckThis(PC& pc) {
NEXT();
checkThis(m_fp);
}

inline void OPTBLD_INLINE VMExecutionContext::iopInitThisLoc(PC& pc) {
NEXT();
DECODE_IVA(id);
Expand Down
3 changes: 2 additions & 1 deletion src/runtime/vm/hhbc.cpp
Expand Up @@ -540,7 +540,7 @@ void staticStreamer(const TypedValue* tv, std::stringstream& out) {
}
}

const char* const locationNames[] = { "L", "C",
const char* const locationNames[] = { "L", "C", "H",
"GL", "GC",
"NL", "NC",
"SL", "SC",
Expand All @@ -561,6 +561,7 @@ LocationCode parseLocationCode(const char* s) {
switch (*s) {
case 'L': return LL;
case 'C': return LC;
case 'H': return LH;
case 'R': return LR;
default:
int incr = (s[1] == 'C');
Expand Down
29 changes: 21 additions & 8 deletions src/runtime/vm/hhbc.h
Expand Up @@ -82,9 +82,10 @@ enum InstrFlags {
};

enum LocationCode {
// Base is the object stored in a cell or a local.
// Base is the object stored in a local, a cell, or $this
LL,
LC,
LH,

// Base is the global name referred to by a cell or a local.
LGL,
Expand Down Expand Up @@ -112,16 +113,27 @@ enum LocationCode {
};

inline int numLocationCodeImms(LocationCode lc) {
return
(lc == LL || lc == LGL || lc == LNL || lc == LSL) ? 1 :
0;
switch (lc) {
case LL: case LGL: case LNL: case LSL:
return 1;
case LC: case LH: case LGC: case LNC: case LSC: case LR:
return 0;
default:
not_reached();
}
}

inline int numLocationCodeStackVals(LocationCode lc) {
return
(lc == LR || lc == LC || lc == LGC || lc == LNC || lc == LSL) ? 1 :
(lc == LSC) ? 2 :
0;
switch (lc) {
case LL: case LH: case LGL: case LNL:
return 0;
case LC: case LGC: case LNC: case LSL: case LR:
return 1;
case LSC:
return 2;
default:
not_reached();
}
}

// Returns string representation of `lc'. (Pointer to internal static
Expand Down Expand Up @@ -505,6 +517,7 @@ enum SetOpOp {
O(DefCls, ONE(IVA), NOV, NOV, NF) \
O(DefCns, ONE(SA), ONE(CV), ONE(CV), NF) \
O(This, NA, NOV, ONE(CV), NF) \
O(CheckThis, NA, NOV, NOV, NF) \
O(InitThisLoc, ONE(IVA), NOV, NOV, NF) \
O(StaticLoc, TWO(IVA,SA), NOV, ONE(CV), NF) \
O(StaticLocInit, TWO(IVA,SA), ONE(CV), NOV, NF) \
Expand Down
1 change: 1 addition & 0 deletions src/runtime/vm/member_operations.h
Expand Up @@ -156,6 +156,7 @@ static inline TypedValue* Elem(TypedValue& tvScratch, TypedValue& tvRef,
tvScratch._count = 0;
tvScratch.m_type = KindOfString;
} else {
TV_WRITE_UNINIT(&tvScratch);
tvAsVariant(&tvScratch) = base->m_data.pstr->getChar(x);
}
result = &tvScratch;
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/vm/stats.h
Expand Up @@ -84,6 +84,11 @@ extern __thread uint64_t tl_tcInstrs;
STAT(Tx64_PropGetSlow) \
STAT(Tx64_PropSetFast) \
STAT(Tx64_PropSetSlow) \
STAT(Tx64_CGetMProp) \
STAT(Tx64_CGetMLEE) \
STAT(Tx64_CGetMGE) \
STAT(Tx64_CGetMArray) \
STAT(Tx64_CGetMGeneric) \
STAT(Tx64_CnsFast) \
STAT(Tx64_CnsSlow) \
STAT(Tx64_ContCreateFast) \
Expand Down
10 changes: 10 additions & 0 deletions src/runtime/vm/translator/hopt/irtranslator.cpp
Expand Up @@ -1144,6 +1144,12 @@ TranslatorX64::irTranslateThis(const Tracelet &t,
HHIR_EMIT(This);
}

void
TranslatorX64::irTranslateCheckThis(const Tracelet& t,
const NormalizedInstruction& i) {
HHIR_UNIMPLEMENTED(CheckThis);
}

void
TranslatorX64::irTranslateInitThisLoc(const Tracelet& t,
const NormalizedInstruction& i) {
Expand Down Expand Up @@ -1491,6 +1497,10 @@ void TranslatorX64::irAssertType(const Location& l,
case Location::Litint: // Literal int pseudo-location
HHIR_UNIMPLEMENTED(Litint);
break;

case Location::This:
HHIR_UNIMPLEMENTED(This);
break;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/runtime/vm/translator/regalloc.cpp
Expand Up @@ -939,6 +939,7 @@ void LazyScratchReg::dealloc() {
}

void LazyScratchReg::realloc(PhysReg pr /* = InvalidReg */) {
ASSERT(m_reg != noreg);
dealloc();
alloc(pr);
}
Expand Down
15 changes: 13 additions & 2 deletions src/runtime/vm/translator/runtime-type.h
Expand Up @@ -34,8 +34,14 @@ struct Location {
Iter, // Stack frame's iterators
Litstr, // Literal string pseudo-location
Litint, // Literal int pseudo-location
This, // $this in the current frame
};

Location(Space spc)
: space(spc)
, offset(0)
{ ASSERT(spc == This); }

Location(Space spc, int64 off)
: space(spc)
, offset(off)
Expand Down Expand Up @@ -77,8 +83,9 @@ struct Location {
case Iter: return "Iter";
case Litstr: return "Litstr";
case Litint: return "Litint";
case Invalid:
default: return "*invalid*";
case This: return "This";
case Invalid:return "*invalid*";
default: not_reached();
}
}

Expand Down Expand Up @@ -108,6 +115,10 @@ struct Location {
return space == Litstr || space == Litint;
}

bool isThis() const {
return space == This;
}

public:
Space space;
int64 offset;
Expand Down

0 comments on commit 14a61b7

Please sign in to comment.