void DataFlowWalker::processAccessChain(ExpressionPtr e) { if (!e) return; if (!e->is(Expression::KindOfObjectPropertyExpression) && !e->is(Expression::KindOfArrayElementExpression)) { return; } for (int i = 0, n = e->getKidCount(); i < n; ++i) { ExpressionPtr kid(e->getNthExpr(i)); if (kid && kid->hasContext(Expression::AccessContext)) { processAccessChain(kid); process(kid, true); break; } } }
/** * Traverses the expression tree rooted at e and returns true if * any node in the tree is a simple variable that references a * name in m_boundVars. */ bool CaptureExtractor::dependsOnQueryOnlyState(ExpressionPtr e) { assert(e != nullptr); if (e->getKindOf() == Expression::KindOfSimpleVariable) { auto sv = static_pointer_cast<SimpleVariable>(e); auto varName = sv->getName(); for (auto &boundVar : m_boundVars) { if (varName == boundVar) return true; } return false; } auto numKids = e->getKidCount(); for (int i = 0; i < numKids; i++) { auto ei = e->getNthExpr(i); if (ei == nullptr) return false; //Default param if (dependsOnQueryOnlyState(ei)) return true; } return false; }
void DataFlowWalker::process(ExpressionPtr e, bool doAccessChains) { if (e->getContext() & (Expression::AssignmentLHS|Expression::OprLValue) || !doAccessChains && e->hasContext(Expression::AccessContext)) { return; } switch (e->getKindOf()) { case Expression::KindOfListAssignment: processAccessChainLA(static_pointer_cast<ListAssignment>(e)); processAccess(e); break; case Expression::KindOfArrayElementExpression: case Expression::KindOfObjectPropertyExpression: if (!e->hasContext(Expression::AccessContext)) { processAccessChain(e); } // fall through case Expression::KindOfObjectMethodExpression: case Expression::KindOfDynamicFunctionCall: case Expression::KindOfSimpleFunctionCall: case Expression::KindOfNewObjectExpression: case Expression::KindOfIncludeExpression: case Expression::KindOfSimpleVariable: case Expression::KindOfDynamicVariable: case Expression::KindOfStaticMemberExpression: case Expression::KindOfConstantExpression: processAccess(e); break; case Expression::KindOfAssignmentExpression: case Expression::KindOfBinaryOpExpression: case Expression::KindOfUnaryOpExpression: { ExpressionPtr var = e->getNthExpr(0); if (var && var->getContext() & (Expression::AssignmentLHS| Expression::OprLValue)) { processAccessChain(var); processAccess(var); } } default: processAccess(e); break; } }
static inline std::string ExtractDocComment(ExpressionPtr e) { if (!e) return ""; switch (e->getKindOf()) { case Expression::KindOfAssignmentExpression: return ExtractDocComment(e->getNthExpr(0)); case Expression::KindOfSimpleVariable: { SimpleVariablePtr sv( static_pointer_cast<SimpleVariable>(e)); return sv->getDocComment(); } case Expression::KindOfConstantExpression: { ConstantExpressionPtr ce( static_pointer_cast<ConstantExpression>(e)); return ce->getDocComment(); } default: return ""; } return ""; }
static ExpressionPtr cloneForInlineRecur(InlineCloneInfo &info, ExpressionPtr exp, const std::string &prefix, AnalysisResultConstPtr ar, FunctionScopePtr scope) { exp->getOriginalScope(); // make sure to cache the original scope exp->setBlockScope(scope); for (int i = 0, n = exp->getKidCount(); i < n; i++) { if (ExpressionPtr k = exp->getNthExpr(i)) { exp->setNthKid(i, cloneForInlineRecur(info, k, prefix, ar, scope)); } } StaticClassName *scn = dynamic_cast<StaticClassName*>(exp.get()); if (scn && scn->isStatic() && !info.staticClass.empty()) { scn->resolveStatic(info.staticClass); } switch (exp->getKindOf()) { case Expression::KindOfSimpleVariable: { SimpleVariablePtr sv(dynamic_pointer_cast<SimpleVariable>(exp)); if (sv->isSuperGlobal()) break; string name; if (sv->isThis()) { if (!info.callWithThis) { if (!sv->hasContext(Expression::ObjectContext)) { exp = sv->makeConstant(ar, "null"); } else { // This will produce the wrong error // we really want a "throw_fatal" ast node. exp = sv->makeConstant(ar, "null"); } break; } if (info.localThis.empty()) break; name = info.localThis; } else { name = prefix + sv->getName(); } SimpleVariablePtr rep(new SimpleVariable( exp->getScope(), exp->getLocation(), name)); rep->copyContext(sv); rep->updateSymbol(SimpleVariablePtr()); rep->getSymbol()->setHidden(); // Conservatively set flags to prevent // the alias manager from getting confused. // On the next pass, it will correct the values, // and optimize appropriately. rep->getSymbol()->setUsed(); rep->getSymbol()->setReferenced(); if (exp->getContext() & (Expression::LValue| Expression::RefValue| Expression::RefParameter)) { info.sepm[name] = rep; } exp = rep; } break; case Expression::KindOfObjectMethodExpression: { FunctionCallPtr call( static_pointer_cast<FunctionCall>(exp)); if (call->getFuncScope() == info.func) { call->setNoInline(); } break; } case Expression::KindOfSimpleFunctionCall: { SimpleFunctionCallPtr call(static_pointer_cast<SimpleFunctionCall>(exp)); call->addLateDependencies(ar); call->setLocalThis(info.localThis); if (call->getFuncScope() == info.func) { call->setNoInline(); } } default: break; } return exp; }
void ExprDict::updateAccess(ExpressionPtr e) { int cls = e->getExprClass(); int eid = e->getCanonID(); e->clearAnticipated(); e->clearAvailable(); // bail on non-canonical expressions if (!isCanonicalStructure(eid)) { // but record we saw a type assertion belonging to this block m_avlTypeAsserts.push_back(eid); return; } if (m_anticipated && (cls & Expression::Update ? !BitOps::get_bit(eid, m_altered) : !e->getLocalEffects())) { /* Anticipated can be computed bottom up as we go. But note that we only know altered for Load/Store expressions. */ int i = e->getKidCount(); while (true) { if (!i--) { e->setAnticipated(); if (!e->hasContext(Expression::AssignmentLHS)) { setStructureOps(eid, m_anticipated, true); } break; } if (ExpressionPtr k = e->getNthExpr(i)) { if (!isCanonicalStructure(k->getCanonID())) continue; if (!k->isAnticipated()) { break; } } } } if (m_available) { /* Available has to be computed optimistically, because we dont yet know what is going to be altered between here and the end of the block So keep a list of the potentially-available accesses (avlAccess), and for each id, the last potentially-available expression (avlExpr). For each modifying expression that we process, we remove expressions from avlAccess, and at the end, we build up the available expressions bottom up. */ if ((cls & (Expression::Store|Expression::Call)) || (cls & Expression::Load && e->getContext() & (Expression::LValue| Expression::RefValue| Expression::UnsetContext| Expression::DeepReference))) { bool isLoad; int depth = 0, effects = 0; for (int i = 0, n = m_avlAccess.size(); i < n; ) { ExpressionRawPtr a = m_avlAccess[i]; if (m_am.checkAnyInterf(e, a, isLoad, depth, effects) != AliasManager::DisjointAccess) { int aid = a->getCanonID(); assert(isCanonicalStructure(aid)); if (eid != aid || cls == Expression::Load) { BitOps::set_bit(aid, m_altered, true); } if (!(cls & Expression::Store) || a != e->getStoreVariable()) { a->clearAvailable(); m_avlAccess[i] = m_avlAccess[--n]; m_avlAccess.resize(n); continue; } } i++; } } if (cls & Expression::Update || !e->getContainedEffects()) { int i = e->getKidCount(); while (true) { if (!i--) { e->setAvailable(); if (cls & Expression::Update) { m_avlAccess.push_back(e); } m_avlExpr[eid] = e; break; } if (ExpressionPtr k = e->getNthExpr(i)) { if (!isCanonicalStructure(k->getCanonID())) continue; if (!k->isAvailable()) { break; } } } } } if ((cls & (Expression::Store|Expression::Call)) || (cls & Expression::Load && e->getContext() & (Expression::LValue| Expression::RefValue| Expression::UnsetContext| Expression::DeepReference))) { ExpressionPtr cur = m_active, prev; bool isLoad; int depth = 0, effects = 0; while (cur) { ExpressionPtr next = cur->getCanonLVal(); int cid = cur->getCanonID(); assert(isCanonicalStructure(cid)); if ((cid != eid || cls == Expression::Load) && (BitOps::get_bit(cid, m_altered) || m_am.checkAnyInterf(e, cur, isLoad, depth, effects) != AliasManager::DisjointAccess)) { BitOps::set_bit(cid, m_altered, true); if (!prev) { m_active = next; } else { prev->setCanonPtr(next); } } else { prev = cur; } cur = next; } } }