Пример #1
0
void emitStaticLocInit(HTS& env, int32_t locId, const StringData* name) {
  if (curFunc(env)->isPseudoMain()) PUNT(StaticLocInit);

  auto const ldPMExit = makePseudoMainExit(env);
  auto const value = popC(env);

  // Closures and generators from closures don't satisfy the "one static per
  // source location" rule that the inline fastpath requires
  auto const box = [&]{
    if (curFunc(env)->isClosureBody()) {
      return gen(env, ClosureStaticLocInit, cns(env, name), fp(env), value);
    }

    auto const cachedBox =
      gen(env, LdStaticLocCached, StaticLocName { curFunc(env), name });
    ifThen(
      env,
      [&] (Block* taken) {
        gen(env, CheckStaticLocInit, taken, cachedBox);
      },
      [&] {
        hint(env, Block::Hint::Unlikely);
        gen(env, StaticLocInitCached, cachedBox, value);
      }
    );
    return cachedBox;
  }();
  gen(env, IncRef, box);
  auto const oldValue = ldLoc(env, locId, ldPMExit, DataTypeSpecific);
  stLocRaw(env, locId, fp(env), box);
  gen(env, DecRef, oldValue);
  // We don't need to decref value---it's a bytecode invariant that
  // our Cell was not ref-counted.
}
Пример #2
0
void emitCGetL(HTS& env, int32_t id) {
  auto const ldrefExit = makeExit(env);
  auto const ldPMExit = makePseudoMainExit(env);
  // Mimic hhbc guard relaxation for now.
  auto cat = curSrcKey(env).op() == OpFPassL ? DataTypeSpecific
                                             : DataTypeCountnessInit;
  pushIncRef(env, ldLocInnerWarn(env, id, ldrefExit, ldPMExit, cat));
}
Пример #3
0
void emitEmptyL(IRGS& env, int32_t id) {
  auto const ldrefExit = makeExit(env);
  auto const ldPMExit = makePseudoMainExit(env);
  auto const ld = ldLocInner(env, id, ldrefExit, ldPMExit, DataTypeSpecific);
  push(
    env,
    gen(env, XorBool, gen(env, ConvCellToBool, ld), cns(env, true))
  );
}
Пример #4
0
void emitAGetL(HTS& env, int32_t id) {
  auto const ldrefExit = makeExit(env);
  auto const ldPMExit = makePseudoMainExit(env);
  auto const src = ldLocInner(env, id, ldrefExit, ldPMExit, DataTypeSpecific);
  if (src->type().subtypeOfAny(Type::Obj, Type::Str)) {
    implAGet(env, src);
  } else {
    PUNT(AGetL);
  }
}
Пример #5
0
void emitSetL(HTS& env, int32_t id) {
  auto const ldrefExit = makeExit(env);
  auto const ldPMExit = makePseudoMainExit(env);

  // since we're just storing the value in a local, this function doesn't care
  // about the type of the value. stLoc needs to IncRef the value so it may
  // constrain it further.
  auto const src = popC(env, DataTypeGeneric);
  pushStLoc(env, id, ldrefExit, ldPMExit, src);
}
Пример #6
0
void emitIsTypeL(IRGS& env, int32_t id, IsTypeOp subop) {
  if (subop == IsTypeOp::Scalar) return implIsScalarL(env, id);
  auto const t = typeOpToDataType(subop);
  auto const ldrefExit = makeExit(env);
  auto const ldPMExit = makePseudoMainExit(env);
  auto const val =
    ldLocInnerWarn(env, id, ldrefExit, ldPMExit, DataTypeSpecific);
  if (t == KindOfObject) {
    push(env, optimizedCallIsObject(env, val));
  } else {
    push(env, gen(env, IsType, Type(t), val));
  }
}
Пример #7
0
void emitCGetL2(HTS& env, int32_t id) {
  auto const ldrefExit = makeExit(env);
  auto const ldPMExit = makePseudoMainExit(env);
  auto const oldTop = pop(env, Type::StkElem);
  auto const val = ldLocInnerWarn(
    env,
    id,
    ldrefExit,
    ldPMExit,
    DataTypeCountnessInit
  );
  pushIncRef(env, val);
  push(env, oldTop);
}
Пример #8
0
void emitBindL(HTS& env, int32_t id) {
  if (curFunc(env)->isPseudoMain()) {
    interpOne(env, Type::BoxedInitCell, 1);
    return;
  }

  auto const ldPMExit = makePseudoMainExit(env);
  auto const newValue = popV(env);
  // Note that the IncRef must happen first, for correctness in a
  // pseudo-main: the destructor could decref the value again after
  // we've stored it into the local.
  pushIncRef(env, newValue);
  auto const oldValue = ldLoc(env, id, ldPMExit, DataTypeSpecific);
  stLocRaw(env, id, fp(env), newValue);
  gen(env, DecRef, oldValue);
}
Пример #9
0
void checkTypeLocal(IRGS& env, uint32_t locId, Type type, Offset dest,
                    bool outerOnly) {
  assertx(type <= TCell || type <= TBoxedInitCell);

  auto exit = env.irb->guardFailBlock();
  if (exit == nullptr) exit = makeExit(env, dest);

  if (type <= TCell) {
    profiledGuard(env, type, ProfGuard::CheckLoc, locId, exit);
    return;
  }

  profiledGuard(env, TBoxedInitCell, ProfGuard::CheckLoc, locId, exit);
  gen(env, HintLocInner, type, LocalId { locId }, fp(env));

  if (!outerOnly && type.inner() < TInitCell) {
    auto const exit = makeExit(env);
    auto const ldPMExit = makePseudoMainExit(env);
    auto const val = ldLoc(env, locId, ldPMExit, DataTypeSpecific);
    gen(env, CheckRefInner, env.irb->predictedInnerType(locId), exit, val);
  }
}
Пример #10
0
void emitStaticLoc(HTS& env, int32_t locId, const StringData* name) {
  if (curFunc(env)->isPseudoMain()) PUNT(StaticLoc);

  auto const ldPMExit = makePseudoMainExit(env);

  auto const box = curFunc(env)->isClosureBody() ?
    gen(env, ClosureStaticLocInit,
             cns(env, name), fp(env), cns(env, Type::Uninit)) :
    gen(env, LdStaticLocCached, StaticLocName { curFunc(env), name });

  auto const res = cond(
    env,
    0,
    [&] (Block* taken) {
      gen(env, CheckStaticLocInit, taken, box);
    },
    [&] { // Next: the static local is already initialized
      return cns(env, true);
    },
    [&] { // Taken: need to initialize the static local
      /*
       * Even though this path is "cold", we're not marking it
       * unlikely because the size of the instructions this will
       * generate is about 10 bytes, which is not much larger than the
       * 5 byte jump to acold would be.
       *
       * One note about StaticLoc: we're literally always going to
       * generate a fallthrough trace here that is cold (the code that
       * initializes the static local).  TODO(#2894612).
       */
      gen(env, StaticLocInitCached, box, cns(env, Type::InitNull));
      return cns(env, false);
    });
  gen(env, IncRef, box);
  auto const oldValue = ldLoc(env, locId, ldPMExit, DataTypeGeneric);
  stLocRaw(env, locId, fp(env), box);
  gen(env, DecRef, oldValue);
  push(env, res);
}
Пример #11
0
void emitIssetL(IRGS& env, int32_t id) {
  auto const ldrefExit = makeExit(env);
  auto const ldPMExit = makePseudoMainExit(env);
  auto const ld = ldLocInner(env, id, ldrefExit, ldPMExit, DataTypeSpecific);
  push(env, gen(env, IsNType, TNull, ld));
}