示例#1
0
文件: stmt.c 项目: BouKiCHi/husic_git
/*
 *	"switch" statement
 */
void doswitch (void )
{
	INTPTR_T	ws[7];
	INTPTR_T	*ptr;

	ws[WSSYM] = (INTPTR_T)locptr;
	ws[WSSP] = stkp;
	ws[WSTYP] = WSSWITCH;
	ws[WSCASEP] = swstp;
	ws[WSTAB] = getlabel ();
	ws[WSDEF] = ws[WSEXIT] = getlabel ();
	addwhile (ws);
	immed (T_LABEL, ws[WSTAB]);
	gpush ();
	needbrack ("(");
	expression (YES);
	needbrack (")");
	stkp = stkp + INTSIZE;  /* '?case' will adjust the stack */
	gjcase ();
	statement (NO);
	ptr = readswitch ();
	jump (ptr[WSEXIT]);
	dumpsw (ptr);
	gnlabel (ptr[WSEXIT]);
	locptr = (char*)ptr[WSSYM];
	stkp = modstk (ptr[WSSP]);
	swstp = ptr[WSCASEP];
	delwhile ();
}
示例#2
0
void cgKillClsRef(IRLS& env, const IRInstruction* inst) {
  if (!debug) return;

  auto& v = vmain(env);
  auto const fp = srcLoc(env, inst, 0).reg();
  auto const off = frame_clsref_offset(
    funcFromFp(inst->src(0)),
    inst->extra<ClsRefSlotData>()->slot
  );

  LowPtr<Class> trash;
  memset(&trash, kTrashClsRef, sizeof(trash));
  Immed64 immed(trash.get());

  if (sizeof(trash) == 4) {
    v << storeli{immed.l(), fp[off]};
  } else if (sizeof(trash) == 8) {
    if (immed.fits(sz::dword)) {
      v << storeqi{immed.l(), fp[off]};
    } else {
      v << store{v.cns(immed.q()), fp[off]};
    }
  } else {
    not_implemented();
  }
}
inline void Assembler::ldub(  Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(ldub_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::ldxfsr( Register s1, int simm13a) { v9_only();  emit_data( op(ldst_op) | rd(G1)    | op3(ldfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d, RelocationHolder const& rspec) { emit_data( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec); }
inline void Assembler::jmpl( Register s1, int simm13a, Register d, RelocationHolder const& rspec ) { insert_nop_after_cbcond(); cti();  emit_data( op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec);  has_delay_slot(); }
inline void Assembler::flush( Register s1, int simm13a) { emit_data( op(arith_op) | op3(flush_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::cbcond(Condition c, CC cc, Register s1, int simm5, Label& L)   { cti();  no_cbcond_before();  emit_data(op(branch_op) | cond_cbcond(c) | op2(bpr_op2) | branchcc(cc) | wdisp10(intptr_t(target(L)), intptr_t(pc())) | rs1(s1) | immed(true) | simm(simm5, 5)); }
inline void Assembler::swap(    Register s1, int simm13a, Register d) { v9_dep();  emit_data( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::std(  Register d, Register s1, int simm13a) { v9_dep(); assert(d->is_even(), "not even"); emit_data( op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::stx(  Register d, Register s1, int simm13a) { v9_only();  emit_data( op(ldst_op) | rd(d) | op3(stx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::stf(    FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a) { emit_data( op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::rett( Register s1, int simm13a, relocInfo::relocType rt) { cti();  emit_data( op(arith_op) | op3(rett_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rt);  has_delay_slot(); }
示例#14
0
namespace HPHP {  namespace JIT { namespace NativeCalls {


namespace {

constexpr SyncOptions SNone = SyncOptions::kNoSyncPoint;
constexpr SyncOptions SSync = SyncOptions::kSyncPoint;
constexpr SyncOptions SSyncAdj1 = SyncOptions::kSyncPointAdjustOne;

constexpr DestType DSSA  = DestType::SSA;
constexpr DestType DSSA2 = DestType::SSA2;
constexpr DestType DTV   = DestType::TV;
constexpr DestType DNone = DestType::None;

template<class EDType, class MemberType>
Arg extra(MemberType EDType::*ptr) {
  auto fun = [ptr] (const IRInstruction* inst) {
    auto const extra = inst->extra<EDType>();
    return Type::cns(extra->*ptr).rawVal();
  };
  return Arg(fun);
}

Arg immed(intptr_t imm) { return Arg(ArgType::Imm, imm); }

FuncPtr fssa(uint64_t i) { return FuncPtr { FuncType::SSA, i }; }

template<class Ret, class T, class... Args>
FuncPtr method(Ret (T::*fp)(Args...) const) {
  return FuncPtr(reinterpret_cast<TCA>(getMethodPtr(fp)));
}

template<class Ret, class T, class... Args>
FuncPtr method(Ret (T::*fp)(Args...)) {
  return FuncPtr(reinterpret_cast<TCA>(getMethodPtr(fp)));
}

auto constexpr SSA      = ArgType::SSA;
auto constexpr TV       = ArgType::TV;
auto constexpr MemberKeyS  = ArgType::MemberKeyS;
auto constexpr MemberKeyIS = ArgType::MemberKeyIS;

using IFaceSupportFn = bool (*)(const StringData*);

}

//////////////////////////////////////////////////////////////////////

/*
 * The table passed to s_callMap's constructor describes helpers calls
 * used by translated code. Each row consists of the following values:
 *
 * Opcode
 *   The opcode that uses the call
 *
 * Func
 *   A value describing the function to call:
 *     <function pointer>          - Raw function pointer
 *     method(<pointer to member>) - Dispatch to a C++ member function---the
 *                                   function must be non-virtual.
 *     fssa(idx)                   - Use a const TCA from inst->src(idx)
 *
 * Dest
 *   DSSA  - The helper returns a single-register value
 *   DSSA2 - The helper returns a two-register value
 *   DTV   - The helper returns a TypedValue in two registers
 *   DNone - The helper does not return a value
 *
 * SyncPoint
 *   SNone - The helper does not need a sync point
 *   SSync - The helper needs a normal sync point
 *   SSyncAdj1 - The helper needs a sync point that skips top of stack on unwind
 *
 * Args
 *   A list of tuples describing the arguments to pass to the helper
 *     {SSA, idx}               - Pass the value in inst->src(idx)
 *     {TV, idx}                - Pass the value in inst->src(idx) as a
 *                                TypedValue, in two registers
 *     {MemberKeyS, idx}           - Like TV, but Str values are passed as a raw
 *                                StringData*, in a single register
 *     {MemberKeyIS, idx}          - Like MemberKeyS, including Int
 *     extra(&EDStruct::member) - extract an immediate from extra data
 *     immed(int64_t)           - constant immediate
 */
static CallMap s_callMap {
    /* Opcode, Func, Dest, SyncPoint, Args */
    {TypeProfileFunc,    profileOneArgument, DNone, SNone,
                           {{TV,0}, extra(&TypeProfileData::param), {SSA, 1}}},
    {ConvBoolToArr,      convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvDblToArr,       convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvIntToArr,       convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvObjToArr,       convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvStrToArr,       convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvCellToArr,      convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},

    {ConvStrToBool,      method(&StringData::toBoolean), DSSA, SNone,
                           {{SSA, 0}}},
    {ConvCellToBool,     cellToBool, DSSA, SNone,
                           {{TV, 0}}},

    {ConvArrToDbl,       convArrToDblHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvObjToDbl,       convCellToDblHelper, DSSA, SSync,
                           {{TV, 0}}},
    {ConvStrToDbl,       convStrToDblHelper, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvCellToDbl,       convCellToDblHelper, DSSA, SSync,
                           {{TV, 0}}},

    {ConvArrToInt,       convArrToIntHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvObjToInt,       cellToInt, DSSA, SSync,
                           {{TV, 0}}},
    {ConvStrToInt,       method(&StringData::toInt64), DSSA, SNone,
                           {{SSA, 0}, immed(10)}},
    {ConvCellToInt,      cellToInt, DSSA, SSync,
                           {{TV, 0}}},

    {ConvCellToObj,      convCellToObjHelper, DSSA, SSync,
                           {{TV, 0}}},

    {ConvDblToStr,       convDblToStrHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvIntToStr,       convIntToStrHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvObjToStr,       convObjToStrHelper, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvResToStr,       convResToStrHelper, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvCellToStr,      convCellToStrHelper, DSSA, SSync,
                           {{TV, 0}}},

    {ConcatStrStr,       concat_ss, DSSA, SNone, {{SSA, 0}, {SSA, 1}}},
    {ConcatStrInt,       concat_si, DSSA, SNone, {{SSA, 0}, {SSA, 1}}},
    {ConcatIntStr,       concat_is, DSSA, SNone, {{SSA, 0}, {SSA, 1}}},

    {AddElemStrKey,      addElemStringKeyHelper, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}, {TV, 2}}},
    {AddElemIntKey,      addElemIntKeyHelper, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}, {TV, 2}}},
    {AddNewElem,         &HphpArray::AddNewElemC, DSSA, SNone,
                           {{SSA, 0}, {TV, 1}}},
    {ArrayAdd,           arrayAdd, DSSA, SNone, {{SSA, 0}, {SSA, 1}}},
    {Box,                boxValue, DSSA, SNone, {{TV, 0}}},
    {NewArray,           HphpArray::MakeReserve, DSSA, SNone, {{SSA, 0}}},
    {Clone,              method(&ObjectData::clone), DSSA, SSync,
                           {{SSA, 0}}},
    {NewPackedArray,     HphpArray::MakePacked, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}}},
    {NewCol,             newColHelper, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {ColAddNewElemC,     colAddNewElemCHelper, DSSA, SSync,
                           {{SSA, 0}, {TV, 1}}},
    {ColAddElemC,        colAddElemCHelper, DSSA, SSync,
                           {{SSA, 0}, {TV, 1}, {TV, 2}}},
    {AllocObj,           newInstance, DSSA, SSync,
                           {{SSA, 0}}},
    {CustomInstanceInit, method(&ObjectData::callCustomInstanceInit),
                           DSSA, SSync, {{SSA, 0}}},
    {LdClsCtor,          loadClassCtor, DSSA, SSync,
                           {{SSA, 0}}},
    {LookupClsRDSHandle, lookupClsRDSHandle, DSSA, SNone, {{SSA, 0}}},
    {LookupClsMethod,    lookupClsMethodHelper, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}}},
    {LdArrFuncCtx,       loadArrayFunctionContext, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdArrFPushCuf,      fpushCufHelperArray, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdStrFPushCuf,      fpushCufHelperString, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {PrintStr,           print_string, DNone, SNone, {{SSA, 0}}},
    {PrintInt,           print_int, DNone, SNone, {{SSA, 0}}},
    {PrintBool,          print_boolean, DNone, SNone, {{SSA, 0}}},
    {VerifyParamCls,     VerifyParamTypeSlow, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}}},
    {VerifyParamCallable, VerifyParamTypeCallable, DNone, SSync,
                           {{TV, 0}, {SSA, 1}}},
    {VerifyParamFail,    VerifyParamTypeFail, DNone, SSync, {{SSA, 0}}},
    {VerifyRetCls,       VerifyRetTypeSlow, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {TV, 3}}},
    {VerifyRetCallable,  VerifyRetTypeCallable, DNone, SSync, {{TV, 0}}},
    {VerifyRetFail,      VerifyRetTypeFail, DNone, SSync, {{TV, 0}}},
    {RaiseUninitLoc,     raiseUndefVariable, DNone, SSync, {{SSA, 0}}},
    {RaiseWarning,       raiseWarning, DNone, SSync, {{SSA, 0}}},
    {RaiseNotice,        raiseNotice, DNone, SSync, {{SSA, 0}}},
    {RaiseArrayIndexNotice,
                         raiseArrayIndexNotice, DNone, SSync, {{SSA, 0}}},
    {WarnNonObjProp,     raisePropertyOnNonObject, DNone, SSync, {}},
    {ThrowNonObjProp,    throw_null_object_prop, DNone, SSync, {}},
    {RaiseUndefProp,     raiseUndefProp, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}}},
    {RaiseError,         raise_error_sd, DNone, SSync, {{SSA, 0}}},
    {IncStatGrouped,     Stats::incStatGrouped, DNone, SNone,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {ClosureStaticLocInit,
                         closureStaticLocInit, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}, {TV, 2}}},
    {ArrayIdx,           fssa(0), DTV, SSync,
                           {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {GenericIdx,         genericIdx, DTV, SSync,
                          {{TV, 0}, {TV, 1}, {TV, 2}}},
    {LdGblAddrDef,       ldGblAddrDefHelper, DSSA, SNone,
                           {{SSA, 0}}},

    /* Switch helpers */
    {LdSwitchDblIndex,   switchDoubleHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdSwitchStrIndex,   switchStringHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdSwitchObjIndex,   switchObjHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},

    /* Continuation support helpers */
    {CreateContFunc,     &c_Continuation::CreateFunc, DSSA, SNone,
                          { extra(&CreateContData::func),
                            {SSA, 0} }},
    {CreateContMeth,     &c_Continuation::CreateMeth, DSSA, SNone,
                          { extra(&CreateContData::func),
                            {SSA, 0}, {SSA, 1} }},

    /* Async function support helpers */
    {CreateAFWHFunc,     &c_AsyncFunctionWaitHandle::CreateFunc, DSSA, SSync,
                          { extra(&CreateContData::func),
                            {SSA, 0}, {SSA, 1} }},
    {CreateAFWHMeth,     &c_AsyncFunctionWaitHandle::CreateMeth, DSSA, SSync,
                          { extra(&CreateContData::func),
                            {SSA, 0}, {SSA, 1}, {SSA, 2} }},
    {CreateSRWH,         &c_StaticResultWaitHandle::CreateFromVM, DSSA, SNone,
                          { {TV, 0} }},

    /* MInstrTranslator helpers */
    {BaseG,    fssa(0), DSSA, SSync, {{TV, 1}, {SSA, 2}}},
    {PropX,    fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}}},
    {PropDX,   fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}}},
    {CGetProp, fssa(0), DTV, SSync,
                 {{SSA, 1}, {SSA, 2}, {MemberKeyS, 3}, {SSA, 4}}},
    {VGetProp, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {MemberKeyS, 3}, {SSA, 4}}},
    {BindProp, fssa(0), DNone, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}, {SSA, 5}}},
    {SetProp,  fssa(0), DNone, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {TV, 4}}},
    {UnsetProp, fssa(0), DNone, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {SetOpProp, fssa(0), DTV, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {TV, 4}, {SSA, 5}, {SSA, 6}}},
    {IncDecProp, fssa(0), DTV, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}, {SSA, 5}}},
    {EmptyProp, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {IssetProp, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {ElemX,    fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {ElemArray, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}}},
    {ElemDX,   fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {ElemUX,   fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {ArrayGet, fssa(0), DTV, SSync,
                 {{SSA, 1}, {SSA, 2}}},
    {StringGet, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}}},
    {MapGet,   fssa(0), DTV, SSync,
                 {{SSA, 1}, {SSA, 2}}},
    {CGetElem, fssa(0), DTV, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {VGetElem, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {BindElem, fssa(0), DNone, SSync,
                 {{SSA, 1}, {TV, 2}, {SSA, 3}, {SSA, 4}}},
    {SetWithRefElem, fssa(0), DNone, SSync,
                 {{SSA, 1}, {TV, 2}, {SSA, 3}, {SSA, 4}}},
    {ArraySet, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {MapSet,   fssa(0), DNone, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {ArraySetRef, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}}},
    {SetElem,  fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {TV, 3}}},
    {UnsetElem, fssa(0), DNone, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}}},
    {SetOpElem, setOpElem, DTV, SSync,
                 {{SSA, 0}, {TV, 1}, {TV, 2}, {SSA, 3}, {SSA, 4}}},
    {IncDecElem, incDecElem, DTV, SSync,
                 {{SSA, 0}, {TV, 1}, {SSA, 2}, {SSA, 3}}},
    {SetNewElem, setNewElem, DNone, SSync, {{SSA, 0}, {TV, 1}}},
    {SetNewElemArray, setNewElemArray, DNone, SSync, {{SSA, 0}, {TV, 1}}},
    {SetWithRefNewElem, fssa(0), DNone, SSync,
                 {{SSA, 1}, {SSA, 2}, {SSA, 3}}},
    {BindNewElem, bindNewElemIR, DNone, SSync,
                 {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {ArrayIsset, fssa(0), DSSA, SSync, {{SSA, 1}, {SSA, 2}}},
    {VectorIsset, fssa(0), DSSA, SSync, {{SSA, 1}, {SSA, 2}}},
    {PairIsset, fssa(0), DSSA, SSync, {{SSA, 1}, {SSA, 2}}},
    {MapIsset,  fssa(0), DSSA, SSync, {{SSA, 1}, {SSA, 2}}},
    {IssetElem, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {EmptyElem, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},

    /* instanceof checks */
    {InstanceOf, method(&Class::classof), DSSA, SNone, {{SSA, 0}, {SSA, 1}}},
    {InstanceOfIface, method(&Class::ifaceofDirect), DSSA,
                      SNone, {{SSA, 0}, {SSA, 1}}},
    {InterfaceSupportsArr, IFaceSupportFn{interface_supports_array},
                             DSSA, SNone, {{SSA, 0}}},
    {InterfaceSupportsStr, IFaceSupportFn{interface_supports_string},
                             DSSA, SNone, {{SSA, 0}}},
    {InterfaceSupportsInt, IFaceSupportFn{interface_supports_int},
                             DSSA, SNone, {{SSA, 0}}},
    {InterfaceSupportsDbl, IFaceSupportFn{interface_supports_double},
                             DSSA, SNone, {{SSA, 0}}},

    /* debug assert helpers */
    {DbgAssertPtr, assertTv, DNone, SNone, {{SSA, 0}}},

    /* surprise flag support */
    {SurpriseHook, &EventHook::CheckSurprise, DNone, SSync, {}},
    {FunctionExitSurpriseHook, &EventHook::onFunctionExit, DNone, SSync,
                               {{SSA, 0}}},
};

ArgGroup CallInfo::toArgGroup(const RegAllocInfo& regs,
                              const IRInstruction* inst) const {
  ArgGroup argGroup{inst, regs[inst]};
  for (auto const& arg : args) {
    switch (arg.type) {
    case ArgType::SSA:
      argGroup.ssa(arg.ival);
      break;
    case ArgType::TV:
      argGroup.typedValue(arg.ival);
      break;
    case ArgType::MemberKeyS:
      argGroup.memberKeyS(arg.ival);
      break;
    case ArgType::MemberKeyIS:
      argGroup.memberKeyIS(arg.ival);
      break;
    case ArgType::ExtraImm:
      argGroup.imm(arg.extraFunc(inst));
      break;
    case ArgType::Imm:
      argGroup.imm(arg.ival);
      break;
    }
  }
  return argGroup;
}

CallMap::CallMap(CallInfoList infos) {
  for (auto const& info : infos) {
    m_map[info.op] = info;

    // Check for opcodes that have a version which modifies the stack,
    // and add an entry to the table for that one.
    if (opcodeHasFlags(info.op, HasStackVersion)) {
      Opcode stkOp = getStackModifyingOpcode(info.op);
      assert(opcodeHasFlags(stkOp, ModifiesStack));
      auto& slot = m_map[stkOp];
      slot = info;
      slot.op = stkOp;
    }
  }
}

bool CallMap::hasInfo(Opcode op) {
  return s_callMap.m_map.count(op) != 0;
}

const CallInfo& CallMap::info(Opcode op) {
  auto it = s_callMap.m_map.find(op);
  assert(it != s_callMap.m_map.end());
  return it->second;
}

} } }
示例#15
0
namespace HPHP { namespace jit { namespace NativeCalls {

namespace {

constexpr SyncOptions SNone = SyncOptions::kNoSyncPoint;
constexpr SyncOptions SSync = SyncOptions::kSyncPoint;

constexpr DestType DSSA  = DestType::SSA;
constexpr DestType DTV   = DestType::TV;
constexpr DestType DNone = DestType::None;

template<class EDType, class MemberType>
Arg extra(MemberType EDType::*ptr) {
  auto fun = [ptr] (const IRInstruction* inst) {
    auto const extra = inst->extra<EDType>();
    return Type::cns(extra->*ptr).rawVal();
  };
  return Arg(fun);
}

Arg immed(intptr_t imm) { return Arg(ArgType::Imm, imm); }

FuncPtr fssa(uint64_t i) { return FuncPtr { FuncType::SSA, i }; }

auto constexpr SSA      = ArgType::SSA;
auto constexpr TV       = ArgType::TV;
auto constexpr MemberKeyS  = ArgType::MemberKeyS;
auto constexpr MemberKeyIS = ArgType::MemberKeyIS;

using IFaceSupportFn = bool (*)(const StringData*);

}

//////////////////////////////////////////////////////////////////////

/*
 * The table passed to s_callMap's constructor describes helpers calls
 * used by translated code. Each row consists of the following values:
 *
 * Opcode
 *   The opcode that uses the call
 *
 * Func
 *   A value describing the function to call:
 *     <function pointer>          - Raw function pointer
 *     <pointer to member>         - Dispatch to a C++ member function---the
 *                                   function must be non-virtual.
 *     fssa(idx)                   - Use a const TCA from inst->src(idx)
 *
 * Dest
 *   DSSA  - The helper returns a single-register value
 *   DTV   - The helper returns a TypedValue in two registers
 *   DNone - The helper does not return a value
 *
 * SyncPoint
 *   SNone - The helper does not need a sync point
 *   SSync - The helper needs a normal sync point
 *   SSyncAdj1 - The helper needs a sync point that skips top of stack on unwind
 *
 * Args
 *   A list of tuples describing the arguments to pass to the helper
 *     {SSA, idx}               - Pass the value in inst->src(idx)
 *     {TV, idx}                - Pass the value in inst->src(idx) as a
 *                                TypedValue, in two registers
 *     {MemberKeyS, idx}           - Like TV, but Str values are passed as a raw
 *                                StringData*, in a single register
 *     {MemberKeyIS, idx}          - Like MemberKeyS, including Int
 *     extra(&EDStruct::member) - extract an immediate from extra data
 *     immed(int64_t)           - constant immediate
 */
static CallMap s_callMap {
    /* Opcode, Func, Dest, SyncPoint, Args */
    {TypeProfileFunc,    profileOneArgument, DNone, SNone,
                           {{TV,0}, extra(&TypeProfileData::param), {SSA, 1}}},
    {ConvBoolToArr,      convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvDblToArr,       convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvIntToArr,       convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvObjToArr,       convCellToArrHelper, DSSA, SSync,
                           {{TV, 0}}},
    {ConvStrToArr,       convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvCellToArr,      convCellToArrHelper, DSSA, SSync,
                           {{TV, 0}}},

    {ConvStrToBool,      &StringData::toBoolean, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvCellToBool,     cellToBool, DSSA, SNone,
                           {{TV, 0}}},

    {ConvArrToDbl,       convArrToDblHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvObjToDbl,       convCellToDblHelper, DSSA, SSync,
                           {{TV, 0}}},
    {ConvStrToDbl,       convStrToDblHelper, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvCellToDbl,       convCellToDblHelper, DSSA, SSync,
                           {{TV, 0}}},

    {ConvArrToInt,       convArrToIntHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvObjToInt,       cellToInt, DSSA, SSync,
                           {{TV, 0}}},
    {ConvStrToInt,       &StringData::toInt64, DSSA, SNone,
                           {{SSA, 0}, immed(10)}},
    {ConvCellToInt,      cellToInt, DSSA, SSync,
                           {{TV, 0}}},

    {ConvCellToObj,      convCellToObjHelper, DSSA, SSync,
                           {{TV, 0}}},

    {ConvDblToStr,       convDblToStrHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvIntToStr,       convIntToStrHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvObjToStr,       convObjToStrHelper, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvResToStr,       convResToStrHelper, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvCellToStr,      convCellToStrHelper, DSSA, SSync,
                           {{TV, 0}}},

    {CoerceStrToInt,     coerceStrToIntHelper, DSSA, SSync,
                           {{SSA, 0}, extra(&CoerceData::argNum),
                            extra(&CoerceData::callee)}},
    {CoerceStrToDbl,     coerceStrToDblHelper, DSSA, SSync,
                           {{SSA, 0}, extra(&CoerceData::argNum),
                            extra(&CoerceData::callee)}},

    {CoerceCellToInt,    coerceCellToIntHelper, DSSA, SSync,
                           {{TV, 0}, extra(&CoerceData::argNum),
                            extra(&CoerceData::callee)}},
    {CoerceCellToDbl,    coerceCellToDblHelper, DSSA, SSync,
                           {{TV, 0}, extra(&CoerceData::argNum),
                            extra(&CoerceData::callee)}},
    {CoerceCellToBool,   coerceCellToBoolHelper, DSSA, SSync,
                           {{TV, 0}, extra(&CoerceData::argNum),
                            extra(&CoerceData::callee)}},

    {ConcatStrStr,       concat_ss, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {ConcatStrInt,       concat_si, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {ConcatIntStr,       concat_is, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {ConcatStr3,         concat_s3, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {ConcatStr4,         concat_s4, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}}},

    {AddElemStrKey,      addElemStringKeyHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {TV, 2}}},
    {AddElemIntKey,      addElemIntKeyHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {TV, 2}}},
    {AddNewElem,         addNewElemHelper, DSSA, SSync,
                           {{SSA, 0}, {TV, 1}}},
    {ArrayAdd,           arrayAdd, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {Box,                boxValue, DSSA, SNone, {{TV, 0}}},
    {Clone,              &ObjectData::clone, DSSA, SSync, {{SSA, 0}}},
    {NewArray,           MixedArray::MakeReserve, DSSA, SNone, {{SSA, 0}}},
    {NewMixedArray,      MixedArray::MakeReserveMixed, DSSA, SNone, {{SSA, 0}}},
    {NewVArray,         MixedArray::MakeReserveVArray, DSSA, SNone, {{SSA, 0}}},
    {NewMIArray,        MixedArray::MakeReserveIntMap, DSSA, SNone, {{SSA, 0}}},
    {NewMSArray,        MixedArray::MakeReserveStrMap, DSSA, SNone, {{SSA, 0}}},
    {NewLikeArray,       MixedArray::MakeReserveLike, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}}},
    {NewPackedArray,     MixedArray::MakePacked, DSSA, SNone,
                           {{extra(&PackedArrayData::size)}, {SSA, 1}}},
    {AllocPackedArray,   MixedArray::MakePackedUninitialized, DSSA, SNone,
                           {{extra(&PackedArrayData::size)}}},
    {NewCol,             newColHelper, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {ColAddNewElemC,     colAddNewElemCHelper, DSSA, SSync,
                           {{SSA, 0}, {TV, 1}}},
    {ColAddElemC,        colAddElemCHelper, DSSA, SSync,
                           {{SSA, 0}, {TV, 1}, {TV, 2}}},
    {AllocObj,           newInstance, DSSA, SSync,
                           {{SSA, 0}}},
    {CustomInstanceInit, &ObjectData::callCustomInstanceInit,
                           DSSA, SSync, {{SSA, 0}}},
    {InitProps,          &Class::initProps, DNone, SSync,
                           {{extra(&ClassData::cls)}}},
    {InitSProps,         &Class::initSProps, DNone, SSync,
                           {{extra(&ClassData::cls)}}},
    {RegisterLiveObj,    registerLiveObj, DNone, SNone, {{SSA, 0}}},
    {LdClsCtor,          loadClassCtor, DSSA, SSync,
                           {{SSA, 0}}},
    {LookupClsRDSHandle, lookupClsRDSHandle, DSSA, SNone, {{SSA, 0}}},
    {LookupClsMethod,    lookupClsMethodHelper, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}}},
    {LdArrFuncCtx,       loadArrayFunctionContext, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdArrFPushCuf,      fpushCufHelperArray, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdStrFPushCuf,      fpushCufHelperString, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {PrintStr,           print_string, DNone, SSync, {{SSA, 0}}},
    {PrintInt,           print_int, DNone, SSync, {{SSA, 0}}},
    {PrintBool,          print_boolean, DNone, SSync, {{SSA, 0}}},
    {VerifyParamCls,     VerifyParamTypeSlow, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}}},
    {VerifyParamCallable, VerifyParamTypeCallable, DNone, SSync,
                           {{TV, 0}, {SSA, 1}}},
    {VerifyParamFail,    VerifyParamTypeFail, DNone, SSync, {{SSA, 0}}},
    {VerifyRetCls,       VerifyRetTypeSlow, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {TV, 3}}},
    {VerifyRetCallable,  VerifyRetTypeCallable, DNone, SSync, {{TV, 0}}},
    {VerifyRetFail,      VerifyRetTypeFail, DNone, SSync, {{TV, 0}}},
    {RaiseUninitLoc,     raiseUndefVariable, DNone, SSync, {{SSA, 0}}},
    {RaiseWarning,       raiseWarning, DNone, SSync, {{SSA, 0}}},
    {RaiseNotice,        raiseNotice, DNone, SSync, {{SSA, 0}}},
    {RaiseArrayIndexNotice,
                         raiseArrayIndexNotice, DNone, SSync, {{SSA, 0}}},
    {WarnNonObjProp,     raisePropertyOnNonObject, DNone, SSync, {}},
    {ThrowNonObjProp,    throw_null_object_prop, DNone, SSync, {}},
    {RaiseUndefProp,     raiseUndefProp, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}}},
    {RaiseError,         raise_error_sd, DNone, SSync, {{SSA, 0}}},
    {IncStatGrouped,     Stats::incStatGrouped, DNone, SNone,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {ClosureStaticLocInit,
                         closureStaticLocInit, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}, {TV, 2}}},
    {ArrayIdx,           fssa(0), DTV, SSync,
                           {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {GenericIdx,         genericIdx, DTV, SSync,
                          {{TV, 0}, {TV, 1}, {TV, 2}}},

    /* Static prop helpers */
    {LdClsPropAddrOrNull,
                         getSPropOrNull, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdClsPropAddrOrRaise,
                         getSPropOrRaise, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},

    /* Global helpers */
    {LdGblAddrDef,       ldGblAddrDefHelper, DSSA, SNone,
                           {{SSA, 0}}},

    /* Switch helpers */
    {LdSwitchDblIndex,   switchDoubleHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdSwitchStrIndex,   switchStringHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdSwitchObjIndex,   switchObjHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},

    /* Generator support helpers */
    {CreateCont,         &c_Generator::Create<false>, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}}},

    /* Async function support helpers */
    {CreateAFWH,         &c_AsyncFunctionWaitHandle::Create, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}, {SSA, 4}}},
    {CreateSSWH,         &c_StaticWaitHandle::CreateSucceededVM, DSSA, SNone,
                           {{TV, 0}}},
    {AFWHPrepareChild,   &c_AsyncFunctionWaitHandle::PrepareChild, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}}},
    {ABCUnblock,         &AsioBlockableChain::Unblock, DSSA, SNone,
                           {{SSA, 0}}},

    /* MInstrTranslator helpers */
    {BaseG,    fssa(0), DSSA, SSync, {{TV, 1}}},
    {PropX,    fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}}},
    {PropDX,   fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}}},
    {CGetProp, fssa(0), DTV, SSync,
                 {{SSA, 1}, {SSA, 2}, {MemberKeyS, 3}, {SSA, 4}}},
    {VGetProp, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {MemberKeyS, 3}, {SSA, 4}}},
    {BindProp, fssa(0), DNone, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}, {SSA, 5}}},
    {SetProp,  fssa(0), DNone, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {TV, 4}}},
    {UnsetProp, fssa(0), DNone, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {SetOpProp, fssa(0), DTV, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {TV, 4}, {SSA, 5}, {SSA, 6}}},
    {IncDecProp, fssa(0), DTV, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}, {SSA, 5}}},
    {EmptyProp, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {IssetProp, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {ElemX,    fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {ElemArray, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}}},
    {ElemDX,   fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {ElemUX,   fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {ArrayGet, fssa(0), DTV, SSync,
                 {{SSA, 1}, {SSA, 2}}},
    {StringGet, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}}},
    {MapGet,   fssa(0), DTV, SSync,
                 {{SSA, 1}, {SSA, 2}}},
    {CGetElem, fssa(0), DTV, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {VGetElem, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {BindElem, fssa(0), DNone, SSync,
                 {{SSA, 1}, {TV, 2}, {SSA, 3}, {SSA, 4}}},
    {SetWithRefElem, fssa(0), DNone, SSync,
                 {{SSA, 1}, {TV, 2}, {SSA, 3}, {SSA, 4}}},
    {ArraySet, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {MapSet,   fssa(0), DNone, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}}},
    {ArraySetRef, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}}},
    {SetElem,  fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {TV, 3}}},
    {UnsetElem, fssa(0), DNone, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}}},
    {SetOpElem, setOpElem, DTV, SSync,
                 {{SSA, 0}, {TV, 1}, {TV, 2}, {SSA, 3}, {SSA, 4}}},
    {IncDecElem, incDecElem, DTV, SSync,
                 {{SSA, 0}, {TV, 1}, {SSA, 2}, {SSA, 3}}},
    {SetNewElem, setNewElem, DNone, SSync, {{SSA, 0}, {TV, 1}}},
    {SetNewElemArray, setNewElemArray, DNone, SSync, {{SSA, 0}, {TV, 1}}},
    {SetWithRefNewElem, fssa(0), DNone, SSync,
                 {{SSA, 1}, {SSA, 2}, {SSA, 3}}},
    {BindNewElem, bindNewElemIR, DNone, SSync,
                 {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {ArrayIsset, fssa(0), DSSA, SSync, {{SSA, 1}, {SSA, 2}}},
    {VectorIsset, fssa(0), DSSA, SSync, {{SSA, 1}, {SSA, 2}}},
    {PairIsset, fssa(0), DSSA, SSync, {{SSA, 1}, {SSA, 2}}},
    {MapIsset,  fssa(0), DSSA, SSync, {{SSA, 1}, {SSA, 2}}},
    {IssetElem, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},
    {EmptyElem, fssa(0), DSSA, SSync,
                 {{SSA, 1}, {MemberKeyIS, 2}, {SSA, 3}}},

    /* instanceof checks */
    {InstanceOf, &Class::classof, DSSA, SNone, {{SSA, 0}, {SSA, 1}}},
    {InstanceOfIface, &Class::ifaceofDirect, DSSA,
                      SNone, {{SSA, 0}, {SSA, 1}}},
    {InterfaceSupportsArr, IFaceSupportFn{interface_supports_array},
                             DSSA, SNone, {{SSA, 0}}},
    {InterfaceSupportsStr, IFaceSupportFn{interface_supports_string},
                             DSSA, SNone, {{SSA, 0}}},
    {InterfaceSupportsInt, IFaceSupportFn{interface_supports_int},
                             DSSA, SNone, {{SSA, 0}}},
    {InterfaceSupportsDbl, IFaceSupportFn{interface_supports_double},
                             DSSA, SNone, {{SSA, 0}}},
    {OODeclExists, &Unit::classExists, DSSA, SSync,
                     {{SSA, 0}, {SSA, 1}, extra(&ClassKindData::kind)}},

    /* debug assert helpers */
    {DbgAssertPtr, assertTv, DNone, SNone, {{SSA, 0}}},

    /* surprise flag support */
    {SurpriseHook,        &EventHook::CheckSurprise, DNone, SSync, {}},
    {FunctionSuspendHook, &EventHook::onFunctionSuspend, DNone, SSync,
                            {{SSA, 0}, {SSA, 1}}},
    {FunctionReturnHook,  &EventHook::onFunctionReturnJit, DNone, SSync,
                            {{SSA, 0}, {TV, 1}}},

    /* silence operator support */
    {ZeroErrorLevel, &zero_error_level, DSSA, SNone, {}},
    {RestoreErrorLevel, &restore_error_level, DNone, SNone, {{SSA, 0}}},

    // count($mixed)
    {Count, &countHelper, DSSA, SSync, {{TV, 0}}},

    // count($array)
    {CountArray, &ArrayData::size, DSSA, SNone, {{SSA, 0}}},
};

CallMap::CallMap(CallInfoList infos) {
  for (auto const& info : infos) {
    m_map[info.op] = info;

    // Check for opcodes that have a version which modifies the stack,
    // and add an entry to the table for that one.
    if (opcodeHasFlags(info.op, HasStackVersion)) {
      Opcode stkOp = getStackModifyingOpcode(info.op);
      assert(opcodeHasFlags(stkOp, ModifiesStack));
      auto& slot = m_map[stkOp];
      slot = info;
      slot.op = stkOp;
    }
  }
}

bool CallMap::hasInfo(Opcode op) {
  return s_callMap.m_map.count(op) != 0;
}

const CallInfo& CallMap::info(Opcode op) {
  auto it = s_callMap.m_map.find(op);
  assert(it != s_callMap.m_map.end());
  return it->second;
}

} // NativeCalls
示例#16
0
namespace NativeCalls {

///////////////////////////////////////////////////////////////////////////////

namespace {

constexpr irlower::SyncOptions SNone = irlower::SyncOptions::None;
constexpr irlower::SyncOptions SSync = irlower::SyncOptions::Sync;

constexpr DestType DSSA  = DestType::SSA;
constexpr DestType DTV   = DestType::TV;
constexpr DestType DNone = DestType::None;

template<class EDType, class MemberType>
Arg extra(MemberType EDType::*ptr) {
  auto fun = [ptr] (const IRInstruction* inst) {
    auto const extra = inst->extra<EDType>();
    return Type::cns(extra->*ptr).rawVal();
  };
  return Arg(fun);
}

Arg immed(intptr_t imm) { return Arg(ArgType::Imm, imm); }

auto constexpr SSA      = ArgType::SSA;
auto constexpr TV       = ArgType::TV;

using IFaceSupportFn = bool (*)(const StringData*);

using StrCmpFn = bool (*)(const StringData*, const StringData*);
using ObjCmpFn = bool (*)(const ObjectData*, const ObjectData*);
using ArrCmpFn = bool (*)(const ArrayData*, const ArrayData*);
using ResCmpFn = bool (*)(const ResourceHdr*, const ResourceHdr*);
using StrIntCmpFn = bool (*)(const StringData*, int64_t);

using StrCmpFnInt = int64_t (*)(const StringData*, const StringData*);
using ObjCmpFnInt = int64_t (*)(const ObjectData*, const ObjectData*);
using ArrCmpFnInt = int64_t (*)(const ArrayData*, const ArrayData*);
using ResCmpFnInt = int64_t (*)(const ResourceHdr*, const ResourceHdr*);
using StrIntCmpFnInt = int64_t (*)(const StringData*, int64_t);

}

//////////////////////////////////////////////////////////////////////

/*
 * The table passed to s_callMap's constructor describes helpers calls
 * used by translated code. Each row consists of the following values:
 *
 * Opcode
 *   The opcode that uses the call
 *
 * Func
 *   A value describing the function to call:
 *     <function pointer>          - Raw function pointer
 *     <pointer to member>         - Dispatch to a C++ member function---the
 *                                   function must be non-virtual.
 *
 * Dest
 *   DSSA  - The helper returns a single-register value
 *   DTV   - The helper returns a TypedValue in two registers
 *   DNone - The helper does not return a value
 *
 * SyncPoint
 *   SNone - The helper does not need a sync point
 *   SSync - The helper needs a normal sync point
 *   SSyncAdj1 - The helper needs a sync point that skips top of stack on unwind
 *
 * Args
 *   A list of tuples describing the arguments to pass to the helper
 *     {SSA, idx}               - Pass the value in inst->src(idx)
 *     {TV, idx}                - Pass the value in inst->src(idx) as a
 *                                TypedValue, in two registers
 *     extra(&EDStruct::member) - extract an immediate from extra data
 *     immed(int64_t)           - constant immediate
 */
static CallMap s_callMap {
    /* Opcode, Func, Dest, SyncPoint, Args */
    {ConvBoolToArr,      convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvDblToArr,       convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvIntToArr,       convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvObjToArr,       convCellToArrHelper, DSSA, SSync,
                           {{TV, 0}}},
    {ConvStrToArr,       convCellToArrHelper, DSSA, SNone,
                           {{TV, 0}}},
    {ConvCellToArr,      convCellToArrHelper, DSSA, SSync,
                           {{TV, 0}}},

    {ConvStrToBool,      &StringData::toBoolean, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvCellToBool,     cellToBool, DSSA, SNone,
                           {{TV, 0}}},

    {ConvArrToDbl,       convArrToDblHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvObjToDbl,       convObjToDblHelper, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvStrToDbl,       convStrToDblHelper, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvResToDbl,       convResToDblHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvCellToDbl,      convCellToDblHelper, DSSA, SSync,
                           {{TV, 0}}},

    {ConvArrToInt,       convArrToIntHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvObjToInt,       &ObjectData::toInt64, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvStrToInt,       &StringData::toInt64, DSSA, SNone,
                           {{SSA, 0}, immed(10)}},
    {ConvResToInt,       &ResourceHdr::getId, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvCellToInt,      cellToInt, DSSA, SSync,
                           {{TV, 0}}},

    {ConvCellToObj,      convCellToObjHelper, DSSA, SSync,
                           {{TV, 0}}},

    {ConvDblToStr,       convDblToStrHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvIntToStr,       convIntToStrHelper, DSSA, SNone,
                           {{SSA, 0}}},
    {ConvObjToStr,       convObjToStrHelper, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvResToStr,       convResToStrHelper, DSSA, SSync,
                           {{SSA, 0}}},
    {ConvCellToStr,      convCellToStrHelper, DSSA, SSync,
                           {{TV, 0}}},

    {CoerceStrToInt,     coerceStrToIntHelper, DSSA, SSync,
                           {{SSA, 0}, extra(&FuncArgData::argNum),
                            extra(&FuncArgData::func)}},
    {CoerceStrToDbl,     coerceStrToDblHelper, DSSA, SSync,
                           {{SSA, 0}, extra(&FuncArgData::argNum),
                            extra(&FuncArgData::func)}},

    {CoerceCellToInt,    coerceCellToIntHelper, DSSA, SSync,
                           {{TV, 0}, extra(&FuncArgData::argNum),
                            extra(&FuncArgData::func)}},
    {CoerceCellToDbl,    coerceCellToDblHelper, DSSA, SSync,
                           {{TV, 0}, extra(&FuncArgData::argNum),
                            extra(&FuncArgData::func)}},
    {CoerceCellToBool,   coerceCellToBoolHelper, DSSA, SSync,
                           {{TV, 0}, extra(&FuncArgData::argNum),
                            extra(&FuncArgData::func)}},

    {ConcatStrStr,       concat_ss, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {ConcatStrInt,       concat_si, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {ConcatIntStr,       concat_is, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {ConcatStr3,         concat_s3, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {ConcatStr4,         concat_s4, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}}},

    {AddElemStrKey,      addElemStringKeyHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {TV, 2}}},
    {AddElemIntKey,      addElemIntKeyHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {TV, 2}}},
    {AddNewElem,         addNewElemHelper, DSSA, SSync,
                           {{SSA, 0}, {TV, 1}}},
    {ArrayAdd,           arrayAdd, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {Box,                boxValue, DSSA, SNone, {{TV, 0}}},
    {Clone,              &ObjectData::clone, DSSA, SSync, {{SSA, 0}}},
    {NewArray,           MixedArray::MakeReserve, DSSA, SNone, {{SSA, 0}}},
    {NewMixedArray,      MixedArray::MakeReserveMixed, DSSA, SNone, {{SSA, 0}}},
    {NewLikeArray,       MixedArray::MakeReserveLike, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}}},
    {AllocPackedArray,   MixedArray::MakePackedUninitialized, DSSA, SNone,
                           {{extra(&PackedArrayData::size)}}},
    {ColAddNewElemC,     colAddNewElemCHelper, DSSA, SSync,
                           {{SSA, 0}, {TV, 1}}},
    {MapAddElemC,        colAddElemCHelper, DSSA, SSync,
                           {{SSA, 0}, {TV, 1}, {TV, 2}}},
    {AllocObj,           newInstance, DSSA, SSync,
                           {{SSA, 0}}},
    {InitProps,          &Class::initProps, DNone, SSync,
                           {{extra(&ClassData::cls)}}},
    {InitSProps,         &Class::initSProps, DNone, SSync,
                           {{extra(&ClassData::cls)}}},
    {RegisterLiveObj,    registerLiveObj, DNone, SNone, {{SSA, 0}}},
    {LdClsCtor,          loadClassCtor, DSSA, SSync,
                           {{SSA, 0}}},
    {LookupClsRDSHandle, lookupClsRDSHandle, DSSA, SNone, {{SSA, 0}}},
    {PrintStr,           print_string, DNone, SSync, {{SSA, 0}}},
    {PrintInt,           print_int, DNone, SSync, {{SSA, 0}}},
    {PrintBool,          print_boolean, DNone, SSync, {{SSA, 0}}},
    {VerifyParamCls,     VerifyParamTypeSlow, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}}},
    {VerifyParamCallable, VerifyParamTypeCallable, DNone, SSync,
                           {{TV, 0}, {SSA, 1}}},
    {VerifyParamFail,    VerifyParamTypeFail, DNone, SSync, {{SSA, 0}}},
    {VerifyRetCls,       VerifyRetTypeSlow, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {TV, 3}}},
    {VerifyRetCallable,  VerifyRetTypeCallable, DNone, SSync, {{TV, 0}}},
    {VerifyRetFail,      VerifyRetTypeFail, DNone, SSync, {{TV, 0}}},
    {RaiseUninitLoc,     raiseUndefVariable, DNone, SSync, {{SSA, 0}}},
    {RaiseError,         raise_error_sd, DNone, SSync, {{SSA, 0}}},
    {RaiseWarning,       raiseWarning, DNone, SSync, {{SSA, 0}}},
    {RaiseNotice,        raiseNotice, DNone, SSync, {{SSA, 0}}},
    {RaiseArrayIndexNotice,
                         raiseArrayIndexNotice, DNone, SSync, {{SSA, 0}}},
    {RaiseArrayKeyNotice,
                         raiseArrayKeyNotice, DNone, SSync, {{SSA, 0}}},
    {RaiseUndefProp,     raiseUndefProp, DNone, SSync,
                           {{SSA, 0}, {SSA, 1}}},
    {RaiseMissingArg,    raiseMissingArgument, DNone, SSync,
                           {extra(&FuncArgData::func),
                            extra(&FuncArgData::argNum)}},
    {IncStatGrouped,     Stats::incStatGrouped, DNone, SNone,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {ClosureStaticLocInit,
                         closureStaticLocInit, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}, {TV, 2}}},
    {GenericIdx,         genericIdx, DTV, SSync,
                          {{TV, 0}, {TV, 1}, {TV, 2}}},
    {MapIdx,             mapIdx, DTV, SSync,
                          {{SSA, 0}, {SSA, 1}, {TV, 2}}},
    {ThrowInvalidOperation, throw_invalid_operation_exception,
                          DNone, SSync, {{SSA, 0}}},
    {HasToString,        &ObjectData::hasToString, DSSA, SSync,
                          {{SSA, 0}}},

    /* Type specialized comparison operators */
    {GtStr,              static_cast<StrCmpFn>(more), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {GteStr,             static_cast<StrCmpFn>(moreEqual), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {LtStr,              static_cast<StrCmpFn>(less), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {LteStr,             static_cast<StrCmpFn>(lessEqual), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {EqStr,              static_cast<StrCmpFn>(equal), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {NeqStr,             static_cast<StrCmpFn>(nequal), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {SameStr,            static_cast<StrCmpFn>(same), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {NSameStr,           static_cast<StrCmpFn>(nsame), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {CmpStr,             static_cast<StrCmpFnInt>(compare), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {GtStrInt,           static_cast<StrIntCmpFn>(more), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {GteStrInt,          static_cast<StrIntCmpFn>(moreEqual), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {LtStrInt,           static_cast<StrIntCmpFn>(less), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {LteStrInt,          static_cast<StrIntCmpFn>(lessEqual), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {EqStrInt,           static_cast<StrIntCmpFn>(equal), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {NeqStrInt,          static_cast<StrIntCmpFn>(nequal), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {CmpStrInt,          static_cast<StrIntCmpFnInt>(compare), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {GtObj,              static_cast<ObjCmpFn>(more), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {GteObj,             static_cast<ObjCmpFn>(moreEqual), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {LtObj,              static_cast<ObjCmpFn>(less), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {LteObj,             static_cast<ObjCmpFn>(lessEqual), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {EqObj,              static_cast<ObjCmpFn>(equal), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {NeqObj,             static_cast<ObjCmpFn>(nequal), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {CmpObj,             static_cast<ObjCmpFnInt>(compare), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {GtArr,              static_cast<ArrCmpFn>(more), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {GteArr,             static_cast<ArrCmpFn>(moreEqual), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {LtArr,              static_cast<ArrCmpFn>(less), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {LteArr,             static_cast<ArrCmpFn>(lessEqual), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {EqArr,              static_cast<ArrCmpFn>(equal), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {NeqArr,             static_cast<ArrCmpFn>(nequal), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {SameArr,            static_cast<ArrCmpFn>(same), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {NSameArr,           static_cast<ArrCmpFn>(nsame), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {CmpArr,             static_cast<ArrCmpFnInt>(compare), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {GtRes,              static_cast<ResCmpFn>(more), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {GteRes,             static_cast<ResCmpFn>(moreEqual), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {LtRes,              static_cast<ResCmpFn>(less), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {LteRes,             static_cast<ResCmpFn>(lessEqual), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},
    {CmpRes,             static_cast<ResCmpFnInt>(compare), DSSA, SSync,
                          {{SSA, 0}, {SSA, 1}}},

    /* Static prop helpers */
    {LdClsPropAddrOrNull,
                         getSPropOrNull, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdClsPropAddrOrRaise,
                         getSPropOrRaise, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},

    /* Global helpers */
    {LdGblAddrDef,       ldGblAddrDefHelper, DSSA, SNone,
                           {{SSA, 0}}},

    /* Switch helpers */
    {LdSwitchDblIndex,   switchDoubleHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdSwitchStrIndex,   switchStringHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {LdSwitchObjIndex,   switchObjHelper, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}}},

    /* Generator support helpers */
    {CreateCont,         &Generator::Create<false>, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}}},

    /* Async function support helpers */
    {CreateAFWH,         &c_AsyncFunctionWaitHandle::Create<true>, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}, {SSA, 4}}},
    {CreateAFWHNoVV,     &c_AsyncFunctionWaitHandle::Create<false>, DSSA, SNone,
                           {{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}, {SSA, 4}}},
    {CreateSSWH,         &c_StaticWaitHandle::CreateSucceeded, DSSA, SNone,
                           {{TV, 0}}},
    {AFWHPrepareChild,   &c_AsyncFunctionWaitHandle::PrepareChild, DSSA, SSync,
                           {{SSA, 0}, {SSA, 1}}},
    {ABCUnblock,         &AsioBlockableChain::Unblock, DSSA, SNone,
                           {{SSA, 0}}},

    /* MInstrTranslator helpers */
    {SetOpElem, setOpElem, DTV, SSync,
                 {{SSA, 0}, {TV, 1}, {TV, 2}, {SSA, 3},
                  extra(&SetOpData::op)}},
    {IncDecElem, incDecElem, DTV, SSync,
                 {{SSA, 0}, {TV, 1}, {SSA, 2},
                  extra(&IncDecData::op)}},
    {SetNewElem, setNewElem, DNone, SSync, {{SSA, 0}, {TV, 1}}},
    {SetNewElemArray, setNewElemArray, DNone, SSync, {{SSA, 0}, {TV, 1}}},
    {BindNewElem, bindNewElemIR, DNone, SSync,
                 {{SSA, 0}, {SSA, 1}, {SSA, 2}}},
    {StringGet, MInstrHelpers::stringGetI, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},

    {PairIsset, MInstrHelpers::pairIsset, DSSA, SSync, {{SSA, 0}, {SSA, 1}}},
    {VectorIsset, MInstrHelpers::vectorIsset, DSSA, SSync,
                  {{SSA, 0}, {SSA, 1}}},
    {BindElem, MInstrHelpers::bindElemC, DNone, SSync,
                 {{SSA, 0}, {TV, 1}, {SSA, 2}, {SSA, 3}}},
    {SetWithRefElem, MInstrHelpers::setWithRefElemC, DNone, SSync,
                 {{SSA, 0}, {TV, 1}, {TV, 2}, {SSA, 3}}},
    {SetWithRefNewElem, MInstrHelpers::setWithRefNewElem, DNone, SSync,
                 {{SSA, 0}, {TV, 1}, {SSA, 2}}},
    {ThrowOutOfBounds, throwOOB, DNone, SSync, {{SSA, 0}}},

    /* instanceof checks */
    {InstanceOf, &Class::classof, DSSA, SNone, {{SSA, 0}, {SSA, 1}}},
    {InstanceOfIface, &Class::ifaceofDirect, DSSA,
                      SNone, {{SSA, 0}, {SSA, 1}}},
    {InterfaceSupportsArr, IFaceSupportFn{interface_supports_array},
                             DSSA, SNone, {{SSA, 0}}},
    {InterfaceSupportsStr, IFaceSupportFn{interface_supports_string},
                             DSSA, SNone, {{SSA, 0}}},
    {InterfaceSupportsInt, IFaceSupportFn{interface_supports_int},
                             DSSA, SNone, {{SSA, 0}}},
    {InterfaceSupportsDbl, IFaceSupportFn{interface_supports_double},
                             DSSA, SNone, {{SSA, 0}}},
    {OODeclExists, &Unit::classExists, DSSA, SSync,
                     {{SSA, 0}, {SSA, 1}, extra(&ClassKindData::kind)}},

    /* debug assert helpers */
    {DbgAssertPtr, assertTv, DNone, SNone, {{SSA, 0}}},

    /* surprise flag support */
    {SuspendHookE, &EventHook::onFunctionSuspendE, DNone, SSync,
                            {{SSA, 0}, {SSA, 1}}},
    {SuspendHookR, &EventHook::onFunctionSuspendR, DNone, SSync,
                            {{SSA, 0}, {SSA, 1}}},
    {ReturnHook,  &EventHook::onFunctionReturn, DNone, SSync,
                            {{SSA, 0}, {TV, 1}}},

    /* silence operator support */
    {ZeroErrorLevel, &zero_error_level, DSSA, SNone, {}},
    {RestoreErrorLevel, &restore_error_level, DNone, SNone, {{SSA, 0}}},

    // count($mixed)
    {Count, &countHelper, DSSA, SSync, {{TV, 0}}},

    {GetMemoKey, getMemoKeyHelper, DTV, SSync, {{TV, 0}}},
};

CallMap::CallMap(CallInfoList infos) {
  for (auto const& info : infos) {
    m_map[info.op] = info;
  }
}

bool CallMap::hasInfo(Opcode op) {
  return s_callMap.m_map.count(op) != 0;
}

const CallInfo& CallMap::info(Opcode op) {
  auto it = s_callMap.m_map.find(op);
  assertx(it != s_callMap.m_map.end());
  return it->second;
}

///////////////////////////////////////////////////////////////////////////////

} // NativeCalls
inline void Assembler::add(Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }