{,List}AssignmentExpression: add support for RHS first evaluation order
Add a flag to {,List}AssignmentExpression that changes evaluation order
to RHS before LHS.
This will be used by YieldExpression.
Esse commit está contido em:
@@ -1841,6 +1841,7 @@ ExpressionPtr AliasManager::canonicalizeRecur(ExpressionPtr e) {
|
||||
|
||||
int n = e->getKidCount();
|
||||
if (n < 2) delayVars = false;
|
||||
if (e->is(Expression::KindOfAssignmentExpression)) delayVars = false;
|
||||
|
||||
m_inCall += inCall;
|
||||
for (int j = delayVars ? 0 : 1; j < 2; j++) {
|
||||
|
||||
@@ -2742,11 +2742,26 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
case Expression::KindOfAssignmentExpression: {
|
||||
AssignmentExpressionPtr ae(
|
||||
static_pointer_cast<AssignmentExpression>(node));
|
||||
ExpressionPtr rhs = ae->getValue();
|
||||
Id tempLocal = -1;
|
||||
Offset start = InvalidAbsoluteOffset;
|
||||
|
||||
if (ae->isRhsFirst()) {
|
||||
assert(!rhs->hasContext(Expression::RefValue));
|
||||
tempLocal = emitVisitAndSetUnnamedL(e, rhs);
|
||||
start = m_ue.bcPos();
|
||||
}
|
||||
|
||||
visit(ae->getVariable());
|
||||
emitClsIfSPropBase(e);
|
||||
visit(ae->getValue());
|
||||
if (ae->getValue()->hasContext(Expression::RefValue)) {
|
||||
|
||||
if (ae->isRhsFirst()) {
|
||||
emitPushAndFreeUnnamedL(e, tempLocal, start);
|
||||
} else {
|
||||
visit(rhs);
|
||||
}
|
||||
|
||||
if (rhs->hasContext(Expression::RefValue)) {
|
||||
emitConvertToVar(e);
|
||||
emitBind(e);
|
||||
if (ae->hasAnyContext(Expression::AccessContext|
|
||||
@@ -3259,9 +3274,19 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
ListAssignmentPtr la(static_pointer_cast<ListAssignment>(node));
|
||||
ExpressionPtr rhs = la->getArray();
|
||||
|
||||
if (!rhs) {
|
||||
// visitListAssignmentLHS should have handled this
|
||||
assert(false);
|
||||
// visitListAssignmentLHS should have handled this
|
||||
assert(rhs);
|
||||
|
||||
bool nullRHS = la->getRHSKind() == ListAssignment::Null;
|
||||
// Assign RHS to temp local, unless it's already a simple variable
|
||||
bool simpleRHS = rhs->is(Expression::KindOfSimpleVariable)
|
||||
&& !static_pointer_cast<SimpleVariable>(rhs)->getAlwaysStash();
|
||||
Id tempLocal = -1;
|
||||
Offset start = InvalidAbsoluteOffset;
|
||||
|
||||
if (!simpleRHS && la->isRhsFirst()) {
|
||||
tempLocal = emitVisitAndSetUnnamedL(e, rhs);
|
||||
start = m_ue.bcPos();
|
||||
}
|
||||
|
||||
// We use "index chains" to deal with nested list assignment. We will
|
||||
@@ -3271,19 +3296,10 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
IndexChain workingChain;
|
||||
visitListAssignmentLHS(e, la, workingChain, indexChains);
|
||||
|
||||
bool nullRHS = la->getRHSKind() == ListAssignment::Null;
|
||||
// Assign RHS to temp local, unless it's already a simple variable
|
||||
bool simpleRHS = rhs->is(Expression::KindOfSimpleVariable)
|
||||
&& !static_pointer_cast<SimpleVariable>(rhs)->getAlwaysStash();
|
||||
Id tempLocal = -1;
|
||||
Offset start = InvalidAbsoluteOffset;
|
||||
if (!simpleRHS) {
|
||||
tempLocal = m_curFunc->allocUnnamedLocal();
|
||||
emitVirtualLocal(tempLocal);
|
||||
visit(rhs);
|
||||
emitConvertToCell(e);
|
||||
emitSet(e);
|
||||
emitPop(e);
|
||||
if (!simpleRHS && !la->isRhsFirst()) {
|
||||
assert(tempLocal == -1);
|
||||
assert(start == InvalidAbsoluteOffset);
|
||||
tempLocal = emitVisitAndSetUnnamedL(e, rhs);
|
||||
start = m_ue.bcPos();
|
||||
}
|
||||
|
||||
@@ -3319,20 +3335,9 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
if (simpleRHS) {
|
||||
visit(rhs);
|
||||
} else {
|
||||
emitVirtualLocal(tempLocal);
|
||||
emitCGet(e);
|
||||
emitPushAndFreeUnnamedL(e, tempLocal, start);
|
||||
}
|
||||
|
||||
// Null out and free unnamed local
|
||||
if (!simpleRHS) {
|
||||
assert(tempLocal >= 0);
|
||||
assert(start != InvalidAbsoluteOffset);
|
||||
newFaultRegion(start, m_ue.bcPos(),
|
||||
new UnsetUnnamedLocalThunklet(tempLocal));
|
||||
emitVirtualLocal(tempLocal);
|
||||
emitUnset(e);
|
||||
m_curFunc->freeUnnamedLocal(tempLocal);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4151,6 +4156,27 @@ void EmitterVisitor::emitVGet(Emitter& e) {
|
||||
}
|
||||
}
|
||||
|
||||
Id EmitterVisitor::emitVisitAndSetUnnamedL(Emitter& e, ExpressionPtr exp) {
|
||||
Id tempLocal = m_curFunc->allocUnnamedLocal();
|
||||
emitVirtualLocal(tempLocal);
|
||||
visit(exp);
|
||||
emitConvertToCell(e);
|
||||
emitSet(e);
|
||||
emitPop(e);
|
||||
return tempLocal;
|
||||
}
|
||||
|
||||
void EmitterVisitor::emitPushAndFreeUnnamedL(Emitter& e, Id tempLocal, Offset start) {
|
||||
assert(tempLocal >= 0);
|
||||
assert(start != InvalidAbsoluteOffset);
|
||||
emitVirtualLocal(tempLocal);
|
||||
emitCGet(e);
|
||||
newFaultRegion(start, m_ue.bcPos(), new UnsetUnnamedLocalThunklet(tempLocal));
|
||||
emitVirtualLocal(tempLocal);
|
||||
emitUnset(e);
|
||||
m_curFunc->freeUnnamedLocal(tempLocal);
|
||||
}
|
||||
|
||||
EmitterVisitor::PassByRefKind EmitterVisitor::getPassByRefKind(ExpressionPtr exp) {
|
||||
// The PassByRefKind of a list assignment expression is determined
|
||||
// by the PassByRefKind of the RHS. This loop will repeatedly recurse
|
||||
|
||||
@@ -582,6 +582,8 @@ public:
|
||||
template<class Expr> void emitVirtualClassBase(Emitter&, Expr* node);
|
||||
void emitResolveClsBase(Emitter& e, int pos);
|
||||
void emitClsIfSPropBase(Emitter& e);
|
||||
Id emitVisitAndSetUnnamedL(Emitter& e, ExpressionPtr exp);
|
||||
void emitPushAndFreeUnnamedL(Emitter& e, Id tempLocal, Offset start);
|
||||
Label* getContinuationGotoLabel(StatementPtr s);
|
||||
void emitContinuationSwitch(Emitter& e, SwitchStatementPtr s);
|
||||
DataType analyzeSwitch(SwitchStatementPtr s, SwitchState& state);
|
||||
|
||||
@@ -42,9 +42,11 @@ using namespace HPHP;
|
||||
|
||||
AssignmentExpression::AssignmentExpression
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr variable, ExpressionPtr value, bool ref)
|
||||
ExpressionPtr variable, ExpressionPtr value, bool ref,
|
||||
bool rhsFirst /* = false */)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(AssignmentExpression)),
|
||||
m_variable(variable), m_value(value), m_ref(ref) {
|
||||
m_variable(variable), m_value(value), m_ref(ref), m_rhsFirst(rhsFirst) {
|
||||
assert(!m_ref || !m_rhsFirst);
|
||||
m_variable->setContext(Expression::DeepAssignmentLHS);
|
||||
m_variable->setContext(Expression::AssignmentLHS);
|
||||
m_variable->setContext(Expression::LValue);
|
||||
@@ -135,7 +137,7 @@ void AssignmentExpression::analyzeProgram(AnalysisResultPtr ar) {
|
||||
}
|
||||
|
||||
ConstructPtr AssignmentExpression::getNthKid(int n) const {
|
||||
switch (n) {
|
||||
switch (m_rhsFirst ? 1 - n : n) {
|
||||
case 0:
|
||||
return m_variable;
|
||||
case 1:
|
||||
@@ -152,7 +154,7 @@ int AssignmentExpression::getKidCount() const {
|
||||
}
|
||||
|
||||
void AssignmentExpression::setNthKid(int n, ConstructPtr cp) {
|
||||
switch (n) {
|
||||
switch (m_rhsFirst ? 1 - n : n) {
|
||||
case 0:
|
||||
m_variable = boost::dynamic_pointer_cast<Expression>(cp);
|
||||
break;
|
||||
|
||||
@@ -29,7 +29,7 @@ class AssignmentExpression : public Expression, public IParseHandler {
|
||||
public:
|
||||
AssignmentExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr variable, ExpressionPtr value,
|
||||
bool ref);
|
||||
bool ref, bool rhsFirst = false);
|
||||
|
||||
DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
ExpressionPtr preOptimize(AnalysisResultConstPtr ar);
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
ExpressionPtr getValue() { return m_value;}
|
||||
void setVariable(ExpressionPtr v) { m_variable = v; }
|
||||
void setValue(ExpressionPtr v) { m_value = v; }
|
||||
bool isRhsFirst() { return m_rhsFirst; }
|
||||
int getLocalEffects() const;
|
||||
|
||||
// $GLOBALS[<literal-string>] = <scalar>;
|
||||
@@ -59,6 +60,7 @@ private:
|
||||
ExpressionPtr m_variable;
|
||||
ExpressionPtr m_value;
|
||||
bool m_ref;
|
||||
bool m_rhsFirst;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -147,9 +147,10 @@ static bool AssignmentCouldSet(ExpressionListPtr vars, ExpressionPtr var) {
|
||||
|
||||
ListAssignment::ListAssignment
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionListPtr variables, ExpressionPtr array)
|
||||
ExpressionListPtr variables, ExpressionPtr array, bool rhsFirst /* = false */)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ListAssignment)),
|
||||
m_variables(variables), m_array(array), m_rhsKind(Regular) {
|
||||
m_variables(variables), m_array(array), m_rhsKind(Regular),
|
||||
m_rhsFirst(rhsFirst) {
|
||||
setLValue();
|
||||
|
||||
if (m_array) {
|
||||
@@ -217,7 +218,7 @@ void ListAssignment::analyzeProgram(AnalysisResultPtr ar) {
|
||||
}
|
||||
|
||||
ConstructPtr ListAssignment::getNthKid(int n) const {
|
||||
switch (n) {
|
||||
switch (m_rhsFirst ? 1 - n : n) {
|
||||
case 0:
|
||||
return m_variables;
|
||||
case 1:
|
||||
@@ -234,7 +235,7 @@ int ListAssignment::getKidCount() const {
|
||||
}
|
||||
|
||||
void ListAssignment::setNthKid(int n, ConstructPtr cp) {
|
||||
switch (n) {
|
||||
switch (m_rhsFirst ? 1 - n : n) {
|
||||
case 0:
|
||||
m_variables = boost::dynamic_pointer_cast<ExpressionList>(cp);
|
||||
break;
|
||||
|
||||
@@ -35,7 +35,8 @@ public:
|
||||
Null
|
||||
};
|
||||
ListAssignment(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionListPtr variables, ExpressionPtr array);
|
||||
ExpressionListPtr variables, ExpressionPtr array,
|
||||
bool rhsFirst = false);
|
||||
|
||||
DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
|
||||
@@ -43,10 +44,12 @@ public:
|
||||
|
||||
ExpressionListPtr getVariables() const { return m_variables; }
|
||||
ExpressionPtr getArray() const { return m_array; }
|
||||
bool isRhsFirst() { return m_rhsFirst; }
|
||||
private:
|
||||
ExpressionListPtr m_variables;
|
||||
ExpressionPtr m_array;
|
||||
RHSKind m_rhsKind;
|
||||
bool m_rhsFirst;
|
||||
|
||||
void setLValue();
|
||||
};
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário