Esempio n. 1
0
void cgLdRDSAddr(IRLS& env, const IRInstruction* inst) {
  ldRDSAddrImpl(
    vmain(env),
    inst->extra<LdRDSAddr>()->handle,
    dstLoc(env, inst, 0).reg()
  );
}
void cgLookupClsMethodCache(IRLS& env, const IRInstruction* inst) {
  auto const extra = inst->extra<ClsMethodData>();
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const fp = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  auto const ch = StaticMethodCache::alloc(
    extra->clsName,
    extra->methodName,
    ctxName(inst->marker())
  );

  if (false) { // typecheck
    UNUSED TypedValue* fake_fp = nullptr;
    const UNUSED Func* f = StaticMethodCache::lookup(
      ch,
      extra->namedEntity,
      extra->clsName,
      extra->methodName,
      fake_fp
    );
  }

  auto const args = argGroup(env, inst)
    .imm(ch)
    .immPtr(extra->namedEntity)
    .immPtr(extra->clsName)
    .immPtr(extra->methodName)
    .reg(fp);

  // May raise an error if the class is undefined.
  cgCallHelper(v, env, CallSpec::direct(StaticMethodCache::lookup),
               callDest(dst), SyncOptions::Sync, args);
}
Esempio n. 3
0
void cgCallArray(IRLS& env, const IRInstruction* inst) {
  auto const extra = inst->extra<CallArray>();
  auto const sp = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  auto const syncSP = v.makeReg();
  v << lea{sp[cellsToBytes(extra->spOffset.offset)], syncSP};
  v << syncvmsp{syncSP};

  auto const target = extra->numParams == 0
    ? mcg->ustubs().fcallArrayHelper
    : mcg->ustubs().fcallUnpackHelper;

  auto const pc = v.cns(extra->pc);
  auto const after = v.cns(extra->after);
  auto const args = extra->numParams == 0
    ? v.makeTuple({pc, after})
    : v.makeTuple({pc, after, v.cns(extra->numParams)});

  auto const done = v.makeBlock();
  v << vcallarray{target, fcall_array_regs(), args,
                  {done, label(env, inst->taken())}};
  env.catch_calls[inst->taken()] = CatchCall::PHP;
  v = done;

  auto const dst = dstLoc(env, inst, 0);
  v << defvmret{dst.reg(0), dst.reg(1)};
}
Esempio n. 4
0
void cgOrdStrIdx(IRLS& env, const IRInstruction* inst) {
  auto const sd = srcLoc(env, inst, 0).reg();
  auto const idx = srcLoc(env, inst, 1).reg();
  auto& v = vmain(env);

  auto const sf = v.makeReg();
  auto const length = v.makeReg();

  v << loadzlq{sd[StringData::sizeOff()], length};
  v << cmpq{idx, length, sf};

  unlikelyCond(v, vcold(env), CC_B, sf, dstLoc(env, inst, 0).reg(),
    [&] (Vout& v) {
      auto const args = argGroup(env, inst).ssa(0).ssa(1);
      cgCallHelper(v, env, CallSpec::direct(MInstrHelpers::stringGetI),
                   kVoidDest, SyncOptions::Sync, args);
      return v.cns(0);
    },
    [&] (Vout& v) {
      auto const dst = v.makeReg();
      auto const data = v.makeReg();
#ifdef NO_M_DATA
      v << lea{sd[sizeof(StringData)], data};
#else
      v << load{sd[StringData::dataOff()], data};
#endif
      v << loadzbq{data[idx], dst};
      return dst;
    }
  );
}
void cgLookupClsMethodFCache(IRLS& env, const IRInstruction* inst) {
  auto const extra = inst->extra<ClsMethodData>();
  auto const dst = dstLoc(env, inst, 0).reg(0);
  auto const cls = inst->src(0)->clsVal();
  auto const fp = srcLoc(env, inst, 1).reg();
  auto& v = vmain(env);

  auto const ch = StaticMethodFCache::alloc(
    cls->name(),
    extra->methodName,
    ctxName(inst->marker())
  );
  assertx(rds::isNormalHandle(ch));

  const Func* (*lookup)(rds::Handle, const Class*,
                        const StringData*, TypedValue*) =
    StaticMethodFCache::lookup;

  auto const args = argGroup(env, inst)
   .imm(ch)
   .immPtr(cls)
   .immPtr(extra->methodName)
   .reg(fp);

  cgCallHelper(v, env, CallSpec::direct(lookup),
               callDest(dst), SyncOptions::Sync, args);
}
Esempio n. 6
0
void cgInstanceOfIfaceVtable(IRLS& env, const IRInstruction* inst) {
  auto const iface = inst->extra<InstanceOfIfaceVtable>()->cls;
  auto const slot = iface->preClass()->ifaceVtableSlot();

  auto const dst = dstLoc(env, inst, 0).reg();
  auto const rcls = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  auto const sf = v.makeReg();
  emitCmpVecLen(v, sf, static_cast<int32_t>(slot),
                rcls[Class::vtableVecLenOff()]);
  cond(
    v, CC_A, sf, dst,
    [&] (Vout& v) {
      auto const vtableVec = v.makeReg();
      emitLdLowPtr(v, rcls[Class::vtableVecOff()], vtableVec,
                   sizeof(LowPtr<Class::VtableVecSlot>));

      auto const ifaceOff = slot * sizeof(Class::VtableVecSlot) +
                            offsetof(Class::VtableVecSlot, iface);
      auto const sf = v.makeReg();
      emitCmpLowPtr<Class>(v, sf, iface, vtableVec[ifaceOff]);

      auto tmp = v.makeReg();
      v << setcc{CC_E, sf, tmp};
      return tmp;
    },
    [&] (Vout& v) { return v.cns(false); }
  );
}
void cgFwdCtxStaticCall(IRLS& env, const IRInstruction* inst) {
  auto const dstCtx = dstLoc(env, inst, 0).reg();
  auto const srcCtx = srcLoc(env, inst, 0).reg();
  auto const ty = inst->src(0)->type();

  auto& v = vmain(env);

  auto ctx_from_this =  [] (Vout& v, Vreg rthis, Vreg dst) {
    // Load (this->m_cls | 0x1) into `dst'.
    auto const cls = emitLdObjClass(v, rthis, v.makeReg());
    v << orqi{ActRec::kHasClassBit, cls, dst, v.makeReg()};
    return dst;
  };

  if (ty <= TCctx) {
    v << copy{srcCtx, dstCtx};
  } else if (ty <= TObj) {
    ctx_from_this(v, srcCtx, dstCtx);
  } else {
    // If we don't know whether we have a $this, we need to check dynamically.
    auto const sf = v.makeReg();
    v << testqi{ActRec::kHasClassBit, srcCtx, sf};
    unlikelyCond(v, vcold(env), CC_NZ, sf, dstCtx,
         [&] (Vout& v) { return srcCtx; },
         [&] (Vout& v) { return ctx_from_this(v, srcCtx, v.makeReg()); }
        );
  }
}
Esempio n. 8
0
void cgLdContActRec(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const cont = srcLoc(env, inst, 0).reg();
  auto const isAsync = inst->extra<IsAsyncData>()->isAsync;
  auto const arOff = BaseGenerator::arOff() - genOffset(isAsync);
  vmain(env) << lea{cont[arOff], dst};
}
Esempio n. 9
0
void cgLdStaticLoc(IRLS& env, const IRInstruction* inst) {
  auto const extra = inst->extra<LdStaticLoc>();
  auto const link = rds::bindStaticLocal(extra->func, extra->name);
  auto const dst = dstLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  v << lea{rvmtl()[link.handle() + rds::StaticLocalData::ref_offset()], dst};
}
Esempio n. 10
0
void cgConstructInstance(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const cls = inst->extra<ConstructInstance>()->cls;

  auto const args = argGroup(env, inst).immPtr(cls);
  cgCallHelper(vmain(env), env, CallSpec::direct(cls->instanceCtor().get()),
               callDest(dst), SyncOptions::Sync, args);
}
Esempio n. 11
0
void cgMod(IRLS& env, const IRInstruction* inst) {
  auto const d = dstLoc(env, inst, 0).reg();
  auto const dividend = srcLoc(env, inst, 0).reg();
  auto const divisor  = srcLoc(env, inst, 1).reg();
  auto& v = vmain(env);

  v << srem{dividend, divisor, d};
}
Esempio n. 12
0
void printDsts(std::ostream& os, const IRInstruction* inst,
               const RegAllocInfo* regs) {
  const char* sep = "";
  for (unsigned i = 0, n = inst->numDsts(); i < n; i++) {
    os << punc(sep);
    print(os, inst->dst(i), dstLoc(regs, inst, i));
    sep = ", ";
  }
}
Esempio n. 13
0
void cgLdLocPseudoMain(IRLS& env, const IRInstruction* inst) {
  auto const fp = srcLoc(env, inst, 0).reg();
  auto const off = localOffset(inst->extra<LdLocPseudoMain>()->locId);
  auto& v = vmain(env);

  irlower::emitTypeCheck(v, env, inst->typeParam(), fp[off + TVOFF(m_type)],
                         fp[off + TVOFF(m_data)], inst->taken());
  loadTV(v, inst->dst(), dstLoc(env, inst, 0), fp[off]);
}
Esempio n. 14
0
void cgLdClsRef(IRLS& env, const IRInstruction* inst) {
  auto const fp = srcLoc(env, inst, 0).reg();
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const off = frame_clsref_offset(
    funcFromFp(inst->src(0)),
    inst->extra<ClsRefSlotData>()->slot
  );
  emitLdLowPtr(vmain(env), fp[off], dst, sizeof(LowPtr<Class>));
}
Esempio n. 15
0
void cgLdWHState(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const obj = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  auto const state = v.makeReg();
  v << loadzbq{obj[WH::stateOff()], state};
  v << andqi{0x0F, state, dst, v.makeReg()};
}
Esempio n. 16
0
void cgLdClsCns(IRLS& env, const IRInstruction* inst) {
  auto const extra = inst->extra<LdClsCns>();
  auto const link = rds::bindClassConstant(extra->clsName, extra->cnsName);
  auto const dst = dstLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  auto const sf = checkRDSHandleInitialized(v, link.handle());
  fwdJcc(v, env, CC_NE, sf, inst->taken());
  v << lea{rvmtl()[link.handle()], dst};
}
Esempio n. 17
0
void cgLdClsName(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const src = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  auto const preclass = v.makeReg();
  v << load{src[Class::preClassOff()], preclass};
  emitLdLowPtr(v, preclass[PreClass::nameOffset()],
               dst, sizeof(LowStringPtr));
}
Esempio n. 18
0
void cgLdFuncNumParams(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const func = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  auto const tmp = v.makeReg();
  // See Func::finishedEmittingParams and Func::numParams.
  v << loadzlq{func[Func::paramCountsOff()], tmp};
  v << shrqi{1, tmp, dst, v.makeReg()};
}
Esempio n. 19
0
void cgConjure(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0);
  auto& v = vmain(env);
  if (dst.hasReg(0)) {
    v << conjure{dst.reg(0)};
  }
  if (dst.hasReg(1)) {
    v << conjure{dst.reg(1)};
  }
}
Esempio n. 20
0
void cgLdSubClsCns(IRLS& env, const IRInstruction* inst) {
  auto const extra = inst->extra<LdSubClsCns>();
  auto const dst = dstLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  auto const slot = extra->slot;
  auto const tmp = v.makeReg();
  v << load{srcLoc(env, inst, 0).reg()[Class::constantsVecOff()], tmp};
  v << lea{tmp[slot * sizeof(Class::Const) + offsetof(Class::Const, val)], dst};
}
Esempio n. 21
0
void cgLdInitRDSAddr(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  ldRDSAddrImpl(v, inst->extra<LdInitRDSAddr>()->handle, dst);

  auto const sf = v.makeReg();
  emitCmpTVType(v, sf, KindOfUninit, dst[TVOFF(m_type)]);
  v << jcc{CC_Z, sf, {label(env, inst->next()), label(env, inst->taken())}};
}
Esempio n. 22
0
void cgLdBindAddr(IRLS& env, const IRInstruction* inst) {
  auto const extra = inst->extra<LdBindAddr>();
  auto const dst = dstLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  // Emit service request to smash address of SrcKey into 'addr'.
  auto const addrPtr = v.allocData<TCA>();
  v << bindaddr{addrPtr, extra->sk, extra->bcSPOff};
  v << loadqd{reinterpret_cast<uint64_t*>(addrPtr), dst};
}
Esempio n. 23
0
void cgLdFuncVecLen(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const cls = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  // A Cctx is a Cls with the bottom bit set; subtract one from the offset to
  // handle that case.
  auto const off = Class::funcVecLenOff() - (inst->src(0)->isA(TCctx) ? 1 : 0);
  v << loadzlq{cls[off], dst};
}
Esempio n. 24
0
void cgContArIncIdx(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const contAR = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  auto const tmp = v.makeReg();
  auto const idxOff = GENDATAOFF(m_index) - Generator::arOff();
  v << load{contAR[idxOff], tmp};
  v << incq{tmp, dst, v.makeReg()};
  v << store{dst, contAR[idxOff]};
}
Esempio n. 25
0
void cgLdObjInvoke(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const cls = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  emitLdLowPtr(v, cls[Class::invokeOff()], dst, sizeof(LowPtr<Func>));

  auto const sf = v.makeReg();
  v << testq{dst, dst, sf};
  v << jcc{CC_Z, sf, {label(env, inst->next()), label(env, inst->taken())}};
}
Esempio n. 26
0
void cgCheckNonNull(IRLS& env, const IRInstruction* inst) {
  auto dst = dstLoc(env, inst, 0).reg();
  auto src = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);
  assertx(inst->taken());

  auto const sf = v.makeReg();
  v << testq{src, src, sf};
  fwdJcc(v, env, CC_Z, sf, inst->taken());
  v << copy{src, dst};
}
Esempio n. 27
0
void cgLdGblAddr(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  cgCallHelper(v, env, CallSpec::direct(ldGblAddrHelper), callDest(dst),
               SyncOptions::None, argGroup(env, inst).ssa(0));

  auto const sf = v.makeReg();
  v << testq{dst, dst, sf};
  v << jcc{CC_Z, sf, {label(env, inst->next()), label(env, inst->taken())}};
}
Esempio n. 28
0
void cgContValid(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const cont = srcLoc(env, inst, 0).reg();
  auto const isAsync = inst->extra<IsAsyncData>()->isAsync;
  auto& v = vmain(env);

  // Return true if generator state is not Done.
  auto const sf = v.makeReg();
  auto const stateOff = BaseGenerator::stateOff() - genOffset(isAsync);
  v << cmpbim{int8_t(BaseGenerator::State::Done), cont[stateOff], sf};
  v << setcc{CC_NE, sf, dst};
}
Esempio n. 29
0
void cgContStarted(IRLS& env, const IRInstruction* inst) {
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const cont = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  // Return true if generator state is not in the Created state.
  auto const sf = v.makeReg();
  auto const stateOff = BaseGenerator::stateOff() -
                        genOffset(false /* isAsync */);
  v << cmpbim{int8_t(BaseGenerator::State::Created), cont[stateOff], sf};
  v << setcc{CC_NE, sf, dst};
}
Esempio n. 30
0
void cgAssertNonNull(IRLS& env, const IRInstruction* inst) {
  auto dst = dstLoc(env, inst, 0).reg();
  auto src = srcLoc(env, inst, 0).reg();
  auto& v = vmain(env);

  if (RuntimeOption::EvalHHIRGenerateAsserts) {
    auto const sf = v.makeReg();
    v << testq{src, src, sf};
    ifThen(v, CC_Z, sf, [&](Vout& v) { v << ud2{}; });
  }
  v << copy{src, dst};
}