bool ObjectMethodExpression::preOutputCPP(CodeGenerator &cg,
    AnalysisResultPtr ar, int state) {
  if (!m_name.empty() && m_valid && m_object->getType()->isSpecificObject()) {
    return FunctionCall::preOutputCPP(cg, ar, state);
  }
  // Short circuit out if inExpression() returns false
  if (!ar->inExpression()) return true;
  m_ciTemp = cg.createNewId(shared_from_this());

  ar->wrapExpressionBegin(cg);
  bool isThis = m_object->isThis();
  if (!isThis) {
    m_object->preOutputCPP(cg, ar, state);
  }
  if (m_name.empty()) {
    m_nameExp->preOutputCPP(cg, ar, state);
  }
  const MethodSlot *ms = NULL;
  if (!m_name.empty()) {
    ConstructPtr self = shared_from_this();
    ms = ar->getOrAddMethodSlot(m_name, self);
  }
  cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
  if (ms) {
    cg_printf("mcp%d.methodCallWithIndex((", m_ciTemp);
  } else {
    cg_printf("mcp%d.methodCall((", m_ciTemp);
  }
  if (isThis) {
    cg_printf("GET_THIS()");
  } else {
    outputCPPObject(cg, ar);
  }
  cg_printf("), ");
  if (!m_name.empty()) {
    uint64 hash = hash_string_i(m_name.c_str());
    cg_printString(m_origName, ar, shared_from_this());
    if (ms) {
      cg_printf(", %s", ms->runObjParam().c_str());
    }
    cg_printf(", 0x%016llXLL);\n", hash);
  } else {
    m_nameExp->outputCPP(cg, ar);
    cg_printf(", -1);\n");
  }
  cg_printf("const CallInfo *cit%d  __attribute__((__unused__)) ="
      " mcp%d.ci;\n", m_ciTemp, m_ciTemp);

  if (m_params && m_params->getCount() > 0) {
    ar->pushCallInfo(m_ciTemp);
    m_params->preOutputCPP(cg, ar, state);
    ar->popCallInfo();
  }

  if (state & FixOrder) {
    ar->pushCallInfo(m_ciTemp);
    preOutputStash(cg, ar, state);
    ar->popCallInfo();
  }
  if (hasCPPTemp() && !(state & FixOrder)) {
    cg_printf("id(%s);\n", cppTemp().c_str());
  }
  return true;
}
bool ObjectMethodExpression::preOutputCPP(CodeGenerator &cg,
                                          AnalysisResultPtr ar, int state) {
  if (!m_name.empty() && m_valid && m_object->getType()->isSpecificObject()) {
    if (m_object->hasEffect()) {
      if (cg.inExpression()) {
        m_object->preOutputCPP(cg, ar, FixOrder);
        if (m_params) m_params->preOutputCPP(cg, ar, 0);
        if (state & FixOrder) {
          preOutputStash(cg, ar, state);
        }
      }
      return true;
    }
    return FunctionCall::preOutputCPP(cg, ar, state);
  }
  // Short circuit out if inExpression() returns false
  if (!cg.inExpression()) return true;
  cg.wrapExpressionBegin();
  m_ciTemp = cg.createNewLocalId(shared_from_this());

  if (outputLineMap(cg, ar)) cg_printf("0);\n");

  bool isThis = m_object->isThis();
  if (!isThis) {
    int s = 0;
    if (m_name.empty() &&
        m_nameExp->hasEffect() && !m_object->isScalar()) {
      s = FixOrder;
    }
    m_object->preOutputCPP(cg, ar, s);
  }
  if (m_name.empty()) {
    m_nameExp->preOutputCPP(cg, ar, 0);
  }
  const MethodSlot *ms = NULL;
  if (!m_name.empty()) {
    ConstructPtr self = shared_from_this();
    ms = ar->getOrAddMethodSlot(m_name, self);
  }
  cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);

  if (!isThis) {
    TypePtr t = m_object->getType();
    if (t && t->is(Type::KindOfObject)) {
      cg_printf("CObjRef obj%d = ", m_ciTemp);
    } else {
      cg_printf("CVarRef obj%d = ", m_ciTemp);
    }
    outputCPPObject(cg, ar);
    cg_printf(";\n");
  }
  if (m_name.empty()) {
    cg_printf("CStrRef mth%d = ", m_ciTemp);
    m_nameExp->outputCPP(cg, ar);
    cg_printf(";\n");
  }

  if (ms) {
    cg_printf("mcp%d.methodCallWithIndex((", m_ciTemp);
  } else {
    cg_printf("mcp%d.methodCall((", m_ciTemp);
  }
  if (isThis) {
    if (!getClassScope() || getClassScope()->derivedByDynamic() ||
        !static_pointer_cast<SimpleVariable>(m_object)->isGuardedThis()) {
      cg_printf("GET_THIS_VALID()");
    } else {
      cg_printf("this");
    }
  } else {
    cg_printf("obj%d", m_ciTemp);
  }
  cg_printf("), ");
  if (!m_name.empty()) {
    uint64 hash = hash_string_i(m_name.c_str());
    cg_printString(m_origName, ar, shared_from_this());
    if (ms) {
      cg_printf(", %s", ms->runObjParam().c_str());
    }
    cg_printf(", 0x%016llXLL);\n", hash);
  } else {
    cg_printf("mth%d, -1);\n", m_ciTemp);
  }
  cg_printf("const CallInfo *cit%d ATTRIBUTE_UNUSED = mcp%d.ci;\n",
            m_ciTemp, m_ciTemp);

  if (m_params && m_params->getCount() > 0) {
    cg.pushCallInfo(m_ciTemp);
    m_params->preOutputCPP(cg, ar, 0);
    cg.popCallInfo();
  }

  if (state & FixOrder) {
    cg.pushCallInfo(m_ciTemp);
    preOutputStash(cg, ar, state);
    cg.popCallInfo();
  }

  return true;
}