void annotate(NormalizedInstruction* i) { switch(i->op()) { case OpFPushObjMethodD: case OpFPushClsMethodD: case OpFPushClsMethodF: case OpFPushFuncD: { // When we push predictable action records, we can use a simpler // translation for their corresponding FCall. SrcKey next(i->source); next.advance(curUnit()); const StringData* className = NULL; const StringData* funcName = NULL; if (i->op() == OpFPushFuncD) { funcName = curUnit()->lookupLitstrId(i->imm[1].u_SA); } else if (i->op() == OpFPushObjMethodD) { if (i->inputs[0]->valueType() != KindOfObject) break; const Class* cls = i->inputs[0]->rtt.valueClass(); if (!cls) break; funcName = curUnit()->lookupLitstrId(i->imm[1].u_SA); className = cls->name(); } else if (i->op() == OpFPushClsMethodF) { if (i->inputs[1]->rtt.valueString() == NULL || i->inputs[0]->valueType() != KindOfClass) { break; } const Class* cls = i->inputs[0]->rtt.valueClass(); if (!cls) break; funcName = i->inputs[1]->rtt.valueString(); className = cls->name(); } else { ASSERT(i->op() == OpFPushClsMethodD); funcName = curUnit()->lookupLitstrId(i->imm[1].u_SA); className = curUnit()->lookupLitstrId(i->imm[2].u_SA); } ASSERT(funcName->isStatic()); const FPIEnt *fe = curFunc()->findFPI(next.m_offset); ASSERT(fe); recordActRecPush(i->source, curUnit(), fe, funcName, className, i->op() == OpFPushClsMethodD || i->op() == OpFPushClsMethodF); } break; case OpFCall: { CallRecord callRec; if (mapGet(s_callDB, i->source, &callRec)) { if (callRec.m_type == Function) { i->funcd = callRec.m_func; } else { ASSERT(callRec.m_type == EncodedNameAndArgs); i->funcName = callRec.m_encodedName; } } else { i->funcName = NULL; } } break; default: break; } }
void annotate(NormalizedInstruction* i) { switch(i->op()) { case OpFPushObjMethodD: case OpFPushClsMethodD: case OpFPushClsMethodF: case OpFPushFuncD: { // When we push predictable action records, we can use a simpler // translation for their corresponding FCall. const StringData* className = nullptr; const StringData* funcName = nullptr; if (i->op() == OpFPushFuncD) { funcName = curUnit()->lookupLitstrId(i->imm[1].u_SA); } else if (i->op() == OpFPushObjMethodD) { if (i->inputs[0]->valueType() != KindOfObject) break; const Class* cls = i->inputs[0]->rtt.valueClass(); if (!cls) break; funcName = curUnit()->lookupLitstrId(i->imm[1].u_SA); className = cls->name(); } else if (i->op() == OpFPushClsMethodF) { if (!i->inputs[1]->isString() || i->inputs[1]->rtt.valueString() == nullptr || i->inputs[0]->valueType() != KindOfClass) { break; } const Class* cls = i->inputs[0]->rtt.valueClass(); if (!cls) break; funcName = i->inputs[1]->rtt.valueString(); className = cls->name(); } else { assert(i->op() == OpFPushClsMethodD); funcName = curUnit()->lookupLitstrId(i->imm[1].u_SA); className = curUnit()->lookupLitstrId(i->imm[2].u_SA); } assert(funcName->isStatic()); recordActRecPush(*i, curUnit(), funcName, className, i->op() == OpFPushClsMethodD || i->op() == OpFPushClsMethodF); } break; case OpFCall: case OpFCallArray: { CallRecord callRec; if (mapGet(s_callDB, i->source, &callRec)) { if (callRec.m_type == Function) { i->funcd = callRec.m_func; } else { assert(callRec.m_type == EncodedNameAndArgs); i->funcName = callRec.m_encodedName; } } else { i->funcName = nullptr; } } break; default: break; } }
void annotate(NormalizedInstruction* i) { switch(i->op()) { case OpFPushObjMethodD: case OpFPushClsMethodD: case OpFPushClsMethodF: case OpFPushCtorD: case OpFPushCtor: case OpFPushFuncD: { if (RuntimeOption::RepoAuthoritative && Repo::global().UsedHHBBC) { break; } // When we push predictable activation records, we can use a simpler // translation for their corresponding FCall. const StringData* className = nullptr; const StringData* funcName = nullptr; if (i->op() == OpFPushFuncD) { funcName = i->m_unit->lookupLitstrId(i->imm[1].u_SA); } else if (i->op() == OpFPushObjMethodD) { if (i->inputs[0]->valueType() != KindOfObject) break; const Class* cls = i->inputs[0]->rtt.valueClass(); if (!cls) break; funcName = i->m_unit->lookupLitstrId(i->imm[1].u_SA); className = cls->name(); } else if (i->op() == OpFPushClsMethodF) { if (!i->inputs[1]->isString() || i->inputs[1]->rtt.valueString() == nullptr || i->inputs[0]->valueType() != KindOfClass) { break; } const Class* cls = i->inputs[0]->rtt.valueClass(); if (!cls) break; funcName = i->inputs[1]->rtt.valueString(); className = cls->name(); } else if (i->op() == OpFPushClsMethodD) { funcName = i->m_unit->lookupLitstrId(i->imm[1].u_SA); className = i->m_unit->lookupLitstrId(i->imm[2].u_SA); } else if (i->op() == OpFPushCtorD) { className = i->m_unit->lookupLitstrId(i->imm[1].u_SA); const Class* cls = Unit::lookupUniqueClass(className); if (!cls) break; auto const ctor = cls->getCtor(); funcName = ctor->name(); className = ctor->cls()->name(); } else { assert(i->op() == OpFPushCtor); const Class* cls = i->inputs[0]->rtt.valueClass(); if (!cls) break; auto const ctor = cls->getCtor(); funcName = ctor->name(); className = ctor->cls()->name(); } assert(funcName->isStatic()); recordActRecPush(i->source, funcName, className, i->op() == OpFPushClsMethodD || i->op() == OpFPushClsMethodF); } break; case OpFCall: case OpFCallArray: { if (RuntimeOption::RepoAuthoritative && Repo::global().UsedHHBBC) { break; } if (auto const func = folly::get_ptr(s_callDB, i->source)) { i->funcd = *func; } } break; default: break; case Op::FCallD: { auto const fpi = i->func()->findFPI(i->source.offset()); auto const pushOp = i->m_unit->getOpcode(fpi->m_fpushOff); auto const clsName = i->m_unit->lookupLitstrId(i->imm[1].u_SA); auto const funcName = i->m_unit->lookupLitstrId(i->imm[2].u_SA); auto const isStatic = pushOp == Op::FPushClsMethodD || pushOp == Op::FPushClsMethodF || pushOp == Op::FPushClsMethod; /* * Currently we don't attempt any of this for FPushClsMethod * because lookupImmutableMethod is only for situations that * don't involve LSB. */ auto const func = pushOp == Op::FPushClsMethod ? nullptr : lookupDirectFunc(i->source, funcName, clsName, isStatic); if (func) { FTRACE(1, "found direct func (%s) for FCallD\n", func->fullName()->data()); i->funcd = func; } break; } } }