Beispiel #1
0
void emitContEnter(IRGS& env) {
  auto const returnOffset = nextBcOff(env);
  assertx(curClass(env));
  assertx(curClass(env)->classof(c_AsyncGenerator::classof()) ||
          curClass(env)->classof(c_Generator::classof()));
  assertx(curFunc(env)->contains(returnOffset));

  auto isAsync = curClass(env)->classof(c_AsyncGenerator::classof());
  // Load generator's FP and resume address.
  auto const genObj = ldThis(env);
  auto const genFp  = gen(env, LdContActRec, IsAsyncData(isAsync), genObj);
  auto resumeAddr   = gen(env, LdContResumeAddr, IsAsyncData(isAsync), genObj);

  // Make sure function enter hook is called if needed.
  auto const exitSlow = makeExitSlow(env);
  gen(env, CheckSurpriseFlags, exitSlow, fp(env));

  // Exit to interpreter if resume address is not known.
  resumeAddr = gen(env, CheckNonNull, exitSlow, resumeAddr);

  spillStack(env);
  env.irb->exceptionStackBoundary();
  auto returnBcOffset = returnOffset - curFunc(env)->base();
  gen(
    env,
    ContEnter,
    ContEnterData { offsetFromIRSP(env, BCSPOffset{0}), returnBcOffset },
    sp(env),
    fp(env),
    genFp,
    resumeAddr
  );
}
Beispiel #2
0
void emitContEnter(HTS& env) {
  auto const returnOffset = nextBcOff(env);
  assert(curClass(env));
  assert(curClass(env)->classof(c_AsyncGenerator::classof()) ||
         curClass(env)->classof(c_Generator::classof()));
  assert(curFunc(env)->contains(returnOffset));

  // Load generator's FP and resume address.
  auto const genObj = ldThis(env);
  auto const genFp  = gen(env, LdContActRec, genObj);
  auto resumeAddr   = gen(env, LdContResumeAddr, genObj);

  // Make sure function enter hook is called if needed.
  auto const exitSlow = makeExitSlow(env);
  gen(env, CheckSurpriseFlags, exitSlow);

  // Exit to interpreter if resume address is not known.
  resumeAddr = gen(env, CheckNonNull, exitSlow, resumeAddr);

  // Sync stack.
  auto const stack = spillStack(env);

  // Enter generator.
  auto returnBcOffset = returnOffset - curFunc(env)->base();
  gen(env, ContEnter, stack, fp(env), genFp, resumeAddr,
    cns(env, returnBcOffset));
}
Beispiel #3
0
SSATmp* ldClsPropAddr(IRGS& env, SSATmp* ssaCls, SSATmp* ssaName, bool raise) {
  /*
   * We can use ldClsPropAddrKnown if either we know which property it is and
   * that it is visible && accessible, or we know it is a property on this
   * class itself.
   */
  bool const sPropKnown = [&] {
    if (!ssaName->hasConstVal()) return false;
    auto const propName = ssaName->strVal();

    if (!ssaCls->hasConstVal()) return false;
    auto const cls = ssaCls->clsVal();
    if (!classIsPersistentOrCtxParent(env, cls)) return false;

    auto const lookup = cls->findSProp(curClass(env), propName);
    return lookup.prop != kInvalidSlot && lookup.accessible;
  }();

  if (sPropKnown) {
    return ldClsPropAddrKnown(env, ssaCls->clsVal(), ssaName->strVal());
  }

  return gen(
    env,
    raise ? LdClsPropAddrOrRaise : LdClsPropAddrOrNull,
    ssaCls,
    ssaName,
    cns(env, curClass(env))
  );
}
Beispiel #4
0
void emitContValid(IRGS& env) {
  assertx(curClass(env));
  assertx(curClass(env)->classof(c_AsyncGenerator::classof()) ||
          curClass(env)->classof(c_Generator::classof()));
  auto const cont = ldThis(env);
  push(env, gen(env, ContValid,
    IsAsyncData(curClass(env)->classof(c_AsyncGenerator::classof())), cont));
}
Beispiel #5
0
void emitContCheck(HTS& env, int32_t checkStarted) {
  assert(curClass(env));
  assert(curClass(env)->classof(c_AsyncGenerator::classof()) ||
         curClass(env)->classof(c_Generator::classof()));
  auto const cont = ldThis(env);
  gen(env, ContPreNext, makeExitSlow(env), cont,
    cns(env, static_cast<bool>(checkStarted)));
}
Beispiel #6
0
/*
 * The CreateCl opcode is specified as not being allowed before the
 * class it creates exists, and closure classes are always unique.
 *
 * This means even if we're not in RepoAuthoritative mode, as long as
 * this code is reachable it will always use the same closure Class*,
 * so we can just burn it into the TC without using RDS.
 */
void emitCreateCl(HTS& env, int32_t numParams, const StringData* clsName) {
  auto const cls = Unit::lookupClassOrUniqueClass(clsName);
  auto const invokeFunc = cls->lookupMethod(s_uuinvoke.get());
  auto const clonedFunc = invokeFunc->cloneAndSetClass(
    const_cast<Class*>(curClass(env))
  );
  assert(cls && (cls->attrs() & AttrUnique));

  auto const closure = allocObjFast(env, cls);
  gen(env, IncRef, closure);

  auto const ctx = [&]{
    if (!curClass(env)) return cns(env, nullptr);
    auto const ldctx = gen(env, LdCtx, fp(env));
    if (invokeFunc->attrs() & AttrStatic) {
      return gen(env, ConvClsToCctx, gen(env, LdClsCtx, ldctx));
    }
    gen(env, IncRefCtx, ldctx);
    return ldctx;
  }();
  gen(env, StClosureCtx, closure, ctx);
  gen(env, StClosureFunc, FuncData(clonedFunc), closure);

  SSATmp* args[numParams];
  for (int32_t i = 0; i < numParams; ++i) {
    args[numParams - i - 1] = popF(env);
  }

  int32_t propId = 0;
  for (; propId < numParams; ++propId) {
    gen(
      env,
      StClosureArg,
      PropByteOffset(cls->declPropOffset(propId)),
      closure,
      args[propId]
    );
  }

  // Closure static variables are per instance, and need to start
  // uninitialized.  After numParams use vars, the remaining instance
  // properties hold any static locals.
  assert(cls->numDeclProperties() ==
         clonedFunc->numStaticLocals() + numParams);
  for (int32_t numDeclProperties = cls->numDeclProperties();
      propId < numDeclProperties;
      ++propId) {
    gen(
      env,
      StClosureArg,
      PropByteOffset(cls->declPropOffset(propId)),
      closure,
      cns(env, Type::Uninit)
    );
  }

  push(env, closure);
}
void Injection::execute() const {
    if (m_builtin) {
        assert(m_callback);
        // Execute function in runtime
        m_callback(m_arg);
        return;
    }
    // Execute php code piece
    TypedValue retval;
    VarEnv *varEnv = nullptr;
    ActRec *cfpSave = nullptr;
    ObjectData *this_ = nullptr;
    Class *cls = nullptr;
    ActRec *fp = g_vmContext->getFP();
    if (fp) {
        if (!fp->hasVarEnv()) {
            fp->m_varEnv = VarEnv::createLazyAttach(fp);
        }
        varEnv = fp->m_varEnv;
        cfpSave = varEnv->getCfp();
        if (fp->hasThis()) {
            this_ = fp->getThis();
        } else if (fp->hasClass()) {
            cls = fp->getClass();
        }
    }
    // Note: For now we don't merge analysis code's class and function.
    // Later we might decide to do so
    g_vmContext->invokeFunc(&retval, m_unit->getMain(curClass()),
                            null_array, this_, cls, varEnv);
    if (varEnv) {
        varEnv->setCfp(cfpSave);
    }
}
Beispiel #8
0
void emitInitProp(IRGS& env, const StringData* propName, InitPropOp op) {
  auto const val = popC(env);
  auto const ctx = curClass(env);

  SSATmp* base;
  Slot idx = 0;
  switch (op) {
  case InitPropOp::Static:
    {
      // For sinit, the context class is always the same as the late-bound
      // class, so we can just use curClass().
      auto const handle = ctx->sPropHandle(ctx->lookupSProp(propName));
      base = gen(
        env,
        LdRDSAddr,
        RDSHandleData { handle },
        TPtrToSPropCell
      );
    }
    break;

  case InitPropOp::NonStatic:
    {
      // The above is not the case for pinit, so we need to load.
      auto const cctx = gen(env, LdCctx, fp(env));
      auto const cls = gen(env, LdClsCtx, cctx);

      base = gen(env, LdClsInitData, cls);
      idx = ctx->lookupDeclProp(propName);
    }
    break;
  }

  gen(env, StElem, base, cns(env, idx * sizeof(TypedValue)), val);
}
Beispiel #9
0
void emitContCurrent(HTS& env) {
  assert(curClass(env));
  auto const cont = ldThis(env);
  gen(env, ContStartedCheck, makeExitSlow(env), cont);
  auto const offset = cns(env, offsetof(c_Generator, m_value));
  auto const value = gen(env, LdContField, Type::Cell, cont, offset);
  pushIncRef(env, value);
}
Beispiel #10
0
void emitParent(HTS& env) {
  auto const clss = curClass(env);
  if (clss == nullptr || clss->parent() == nullptr) {
    interpOne(env, Type::Cls, 0);
  } else {
    push(env, cns(env, clss->parent()));
  }
}
Beispiel #11
0
void emitSelf(HTS& env) {
  auto const clss = curClass(env);
  if (clss == nullptr) {
    interpOne(env, Type::Cls, 0);
  } else {
    push(env, cns(env, clss));
  }
}
Beispiel #12
0
void emitContCurrent(IRGS& env) {
  assertx(curClass(env));
  auto const cont = ldThis(env);
  gen(env, ContStartedCheck, IsAsyncData(false), makeExitSlow(env), cont);
  auto const offset = cns(env,
    offsetof(Generator, m_value) - Generator::objectOff());
  auto const value = gen(env, LdContField, TCell, cont, offset);
  pushIncRef(env, value);
}
Beispiel #13
0
void emitLateBoundCls(HTS& env) {
  auto const clss = curClass(env);
  if (!clss) {
    // no static context class, so this will raise an error
    interpOne(env, Type::Cls, 0);
    return;
  }
  auto const ctx = ldCtx(env);
  push(env, gen(env, LdClsCtx, ctx));
}
Beispiel #14
0
void emitCheckProp(IRGS& env, const StringData* propName) {
  auto const cctx = gen(env, LdCctx, fp(env));
  auto const cls = gen(env, LdClsCtx, cctx);
  auto const propInitVec = gen(env, LdClsInitData, cls);

  auto const ctx = curClass(env);
  auto const idx = ctx->lookupDeclProp(propName);

  auto const curVal = gen(env, LdElem, propInitVec,
    cns(env, idx * sizeof(TypedValue)));
  push(env, gen(env, IsNType, TUninit, curVal));
}
Beispiel #15
0
void emitBareThis(HTS& env, BareThisOp subop) {
  if (!curClass(env)) {
    interpOne(env, Type::InitNull, 0); // will raise notice and push null
    return;
  }
  auto const ctx = gen(env, LdCtx, fp(env));
  if (subop == BareThisOp::NeverNull) {
    env.irb->setThisAvailable();
  } else {
    gen(env, CheckCtxThis, makeExitSlow(env), ctx);
  }
  pushIncRef(env, gen(env, CastCtxThis, ctx));
}
Beispiel #16
0
void emitInitThisLoc(HTS& env, int32_t id) {
  if (!curClass(env)) {
    // Do nothing if this is null
    return;
  }
  auto const ldrefExit = makeExit(env);
  auto const oldLoc    = ldLoc(env, id, ldrefExit, DataTypeCountness);
  auto const ctx       = gen(env, LdCtx, fp(env));
  gen(env, CheckCtxThis, makeExitSlow(env), ctx);
  auto const this_     = gen(env, CastCtxThis, ctx);
  gen(env, IncRef, this_);
  stLocRaw(env, id, fp(env), this_);
  gen(env, DecRef, oldLoc);
}
Beispiel #17
0
void emitContValid(HTS& env) {
  assert(curClass(env));
  auto const cont = ldThis(env);
  push(env, gen(env, ContValid, cont));
}