Beispiel #1
0
bool UnitRepoProxy::GetUnitStmt
                  ::get(UnitEmitter& ue, const MD5& md5) {
  try {
    RepoTxn txn(m_repo);
    if (!prepared()) {
      std::stringstream ssSelect;
      ssSelect << "SELECT unitSn,preload,bc,data FROM "
               << m_repo.table(m_repoId, "Unit")
               << " WHERE md5 == @md5;";
      txn.prepare(*this, ssSelect.str());
    }
    RepoTxnQuery query(txn, *this);
    query.bindMd5("@md5", md5);
    query.step();
    if (!query.row()) {
      return true;
    }
    int64_t unitSn;                     /**/ query.getInt64(0, unitSn);
    int preloadPriority;                /**/ query.getInt(1, preloadPriority);
    const void* bc; size_t bclen;       /**/ query.getBlob(2, bc, bclen);
    BlobDecoder dataBlob =              /**/ query.getBlob(3);

    ue.m_repoId = m_repoId;
    ue.m_sn = unitSn;
    ue.m_preloadPriority = preloadPriority;
    ue.setBc(static_cast<const unsigned char*>(bc), bclen);
    ue.serdeMetaData(dataBlob);

    txn.commit();
  } catch (RepoExc& re) {
    return true;
  }
  return false;
}
RepoAuthType decodeRAT(const UnitEmitter& ue, const unsigned char*& pc) {
  return decodeRATImpl(
    pc,
    [&](uint32_t id) { return ue.lookupLitstr(id); },
    [&](uint32_t id) { return ue.lookupArrayType(id); }
  );
}
Beispiel #3
0
void UnitRepoProxy::GetUnitArraysStmt
                  ::get(UnitEmitter& ue) {
  RepoTxn txn(m_repo);
  if (!prepared()) {
    std::stringstream ssSelect;
    ssSelect << "SELECT arrayId,array FROM "
             << m_repo.table(m_repoId, "UnitArray")
             << " WHERE unitSn == @unitSn ORDER BY arrayId ASC;";
    txn.prepare(*this, ssSelect.str());
  }
  RepoTxnQuery query(txn, *this);
  query.bindInt64("@unitSn", ue.sn());
  do {
    query.step();
    if (query.row()) {
      Id arrayId;        /**/ query.getId(0, arrayId);
      StringData* array; /**/ query.getStaticString(1, array);
      String s(array);
      Variant v = f_unserialize(s);
      Id id UNUSED = ue.mergeArray(v.asArrRef().get(), array);
      ASSERT(id == arrayId);
    }
  } while (!query.done());
  txn.commit();
}
Beispiel #4
0
void PreClassRepoProxy::GetPreClassesStmt
                      ::get(UnitEmitter& ue) {
  RepoTxn txn(m_repo);
  if (!prepared()) {
    std::stringstream ssSelect;
    ssSelect << "SELECT preClassId,name,hoistable,extraData FROM "
             << m_repo.table(m_repoId, "PreClass")
             << " WHERE unitSn == @unitSn ORDER BY preClassId ASC;";
    txn.prepare(*this, ssSelect.str());
  }
  RepoTxnQuery query(txn, *this);
  query.bindInt64("@unitSn", ue.sn());
  do {
    query.step();
    if (query.row()) {
      Id preClassId;          /**/ query.getId(0, preClassId);
      StringData* name;       /**/ query.getStaticString(1, name);
      int hoistable;          /**/ query.getInt(2, hoistable);
      BlobDecoder extraBlob = /**/ query.getBlob(3);
      PreClassEmitter* pce = ue.newPreClassEmitter(
        name, (PreClass::Hoistable)hoistable);
      pce->serdeMetaData(extraBlob);
      if (!SystemLib::s_inited) {
        assert(pce->attrs() & AttrPersistent);
        assert(pce->attrs() & AttrUnique);
      }
      assert(pce->id() == preClassId);
    }
  } while (!query.done());
  txn.commit();
}
Beispiel #5
0
void UnitRepoProxy::GetUnitMergeablesStmt
                  ::get(UnitEmitter& ue) {
  RepoTxn txn(m_repo);
  if (!prepared()) {
    std::stringstream ssSelect;
    ssSelect << "SELECT mergeableIx,mergeableKind,mergeableId,mergeableValue"
                " FROM "
             << m_repo.table(m_repoId, "UnitMergeables")
             << " WHERE unitSn == @unitSn ORDER BY mergeableIx ASC;";
    txn.prepare(*this, ssSelect.str());
  }
  RepoTxnQuery query(txn, *this);
  query.bindInt64("@unitSn", ue.m_sn);
  do {
    query.step();
    if (query.row()) {
      int mergeableIx;           /**/ query.getInt(0, mergeableIx);
      int mergeableKind;         /**/ query.getInt(1, mergeableKind);
      Id mergeableId;            /**/ query.getInt(2, mergeableId);

      auto k = MergeKind(mergeableKind);

      if (UNLIKELY(!RuntimeOption::RepoAuthoritative)) {
        /*
         * We're using a repo generated in WholeProgram mode,
         * but we're not using it in RepoAuthoritative mode
         * (this is dodgy to start with). We're not going to
         * deal with requires at merge time, so drop them
         * here, and clear the mergeOnly flag for the unit.
         * The two exceptions are persistent constants and
         * TypeAliases which are allowed in systemlib.
         */
        if ((k != MergeKind::PersistentDefine && k != MergeKind::TypeAlias)
            || SystemLib::s_inited) {
          ue.m_mergeOnly = false;
        }
      }
      switch (k) {
        case MergeKind::TypeAlias:
          ue.insertMergeableTypeAlias(mergeableIx, k, mergeableId);
          break;
        case MergeKind::ReqDoc:
          ue.insertMergeableInclude(mergeableIx, k, mergeableId);
          break;
        case MergeKind::PersistentDefine:
        case MergeKind::Define:
        case MergeKind::Global: {
          TypedValue mergeableValue; /**/ query.getTypedValue(3,
                                                              mergeableValue);
          ue.insertMergeableDef(mergeableIx, k, mergeableId, mergeableValue);
          break;
        }
        default: break;
      }
    }
  } while (!query.done());
  txn.commit();
}
Beispiel #6
0
void emit_pseudomain(EmitUnitState& state,
                     UnitEmitter& ue,
                     const php::Unit& unit) {
  FTRACE(2,  "    pseudomain\n");
  auto& pm = *unit.pseudomain;
  ue.initMain(std::get<0>(pm.srcInfo.loc),
              std::get<1>(pm.srcInfo.loc));
  auto const fe = ue.getMain();
  auto const info = emit_bytecode(state, ue, pm);
  emit_finish_func(pm, *fe, info);
}
Beispiel #7
0
void emit_class(EmitUnitState& state,
                UnitEmitter& ue,
                const php::Class& cls) {
  FTRACE(2, "    class: {}\n", cls.name->data());
  auto const pce = ue.newPreClassEmitter(
    cls.name,
    cls.hoistability
  );
  pce->init(
    std::get<0>(cls.srcInfo.loc),
    std::get<1>(cls.srcInfo.loc),
    ue.bcPos(),
    cls.attrs,
    cls.parentName ? cls.parentName : s_empty.get(),
    cls.srcInfo.docComment
  );
  pce->setUserAttributes(cls.userAttributes);

  for (auto& i : cls.interfaceNames)   pce->addInterface(i);
  for (auto& ut : cls.usedTraitNames)  pce->addUsedTrait(ut);
  for (auto& req : cls.traitRequirements) pce->addTraitRequirement(req);
  for (auto& tp : cls.traitPrecRules)  pce->addTraitPrecRule(tp);
  for (auto& ta : cls.traitAliasRules) pce->addTraitAliasRule(ta);

  for (auto& m : cls.methods) {
    FTRACE(2, "    method: {}\n", m->name->data());
    auto const fe = ue.newMethodEmitter(m->name, pce);
    emit_init_func(*fe, *m);
    pce->addMethod(fe);
    auto const info = emit_bytecode(state, ue, *m);
    emit_finish_func(*m, *fe, info);
  }

  for (auto& prop : cls.properties) {
    pce->addProperty(
      prop.name,
      prop.attrs,
      prop.typeConstraint,
      prop.docComment,
      &prop.val,
      KindOfInvalid // hphpcType
    );
  }

  for (auto& cconst : cls.constants) {
    pce->addConstant(
      cconst.name,
      cconst.typeConstraint,
      &cconst.val,
      cconst.phpCode
    );
  }
}
Beispiel #8
0
void FuncRepoProxy::GetFuncsStmt
                  ::get(UnitEmitter& ue) {
  RepoTxn txn(m_repo);
  if (!prepared()) {
    std::stringstream ssSelect;
    ssSelect << "SELECT funcSn,preClassId,name,top,extraData "
                "FROM "
             << m_repo.table(m_repoId, "Func")
             << " WHERE unitSn == @unitSn ORDER BY funcSn ASC;";
    txn.prepare(*this, ssSelect.str());
  }
  RepoTxnQuery query(txn, *this);
  query.bindInt64("@unitSn", ue.m_sn);
  do {
    query.step();
    if (query.row()) {
      int funcSn;               /**/ query.getInt(0, funcSn);
      Id preClassId;            /**/ query.getId(1, preClassId);
      StringData* name;         /**/ query.getStaticString(2, name);
      bool top;                 /**/ query.getBool(3, top);
      BlobDecoder extraBlob =   /**/ query.getBlob(4);

      FuncEmitter* fe;
      if (preClassId < 0) {
        fe = ue.newFuncEmitter(name);
      } else {
        PreClassEmitter* pce = ue.pce(preClassId);
        fe = ue.newMethodEmitter(name, pce);
        bool added UNUSED = pce->addMethod(fe);
        assert(added);
      }
      assert(fe->sn() == funcSn);
      fe->top = top;
      fe->serdeMetaData(extraBlob);
      if (!SystemLib::s_inited && !fe->isPseudoMain()) {
        assert(fe->attrs & AttrBuiltin);
        if (preClassId < 0) {
          assert(fe->attrs & AttrPersistent);
          assert(fe->attrs & AttrUnique);
          assert(fe->attrs & AttrSkipFrame);
        }
      }
      fe->setEHTabIsSorted();
      fe->finish(fe->past, true);
      ue.recordFunction(fe);
    }
  } while (!query.done());
  txn.commit();
}
Beispiel #9
0
void emit_func(EmitUnitState& state, UnitEmitter& ue, const php::Func& func) {
  FTRACE(2,  "    func {}\n", func.name->data());
  auto const fe = ue.newFuncEmitter(func.name);
  emit_init_func(*fe, func);
  auto const info = emit_bytecode(state, ue, func);
  emit_finish_func(func, *fe, info);
}
Beispiel #10
0
void UnitRepoProxy::GetUnitArraysStmt
                  ::get(UnitEmitter& ue) {
  RepoTxn txn(m_repo);
  if (!prepared()) {
    std::stringstream ssSelect;
    ssSelect << "SELECT arrayId,array FROM "
             << m_repo.table(m_repoId, "UnitArray")
             << " WHERE unitSn == @unitSn ORDER BY arrayId ASC;";
    txn.prepare(*this, ssSelect.str());
  }
  RepoTxnQuery query(txn, *this);
  query.bindInt64("@unitSn", ue.m_sn);
  do {
    query.step();
    if (query.row()) {
      Id arrayId;        /**/ query.getId(0, arrayId);
      std::string key;   /**/ query.getStdString(1, key);
      Variant v = unserialize_from_buffer(key.data(), key.size());
      Id id UNUSED = ue.mergeArray(
        v.asArrRef().get(),
        ArrayData::GetScalarArrayKey(key.c_str(), key.size()));
      assert(id == arrayId);
    }
  } while (!query.done());
  txn.commit();
}
Beispiel #11
0
void encode_member_key(MemberKey mk, UnitEmitter& ue) {
  ue.emitByte(mk.mcode);

  switch (mk.mcode) {
    case MEC: case MEL: case MPC: case MPL:
      ue.emitIVA(mk.iva);
      break;

    case MEI:
      ue.emitInt64(mk.int64);
      break;

    case MET: case MPT: case MQT:
      ue.emitInt32(ue.mergeLitstr(mk.litstr));
      break;

    case MW:
      // No immediate
      break;
  }
}
Beispiel #12
0
void UnitRepoProxy::GetUnitLitstrsStmt
                  ::get(UnitEmitter& ue) {
  RepoTxn txn(m_repo);
  if (!prepared()) {
    std::stringstream ssSelect;
    ssSelect << "SELECT litstrId,litstr FROM "
             << m_repo.table(m_repoId, "UnitLitstr")
             << " WHERE unitSn == @unitSn ORDER BY litstrId ASC;";
    txn.prepare(*this, ssSelect.str());
  }
  RepoTxnQuery query(txn, *this);
  query.bindInt64("@unitSn", ue.sn());
  do {
    query.step();
    if (query.row()) {
      Id litstrId;        /**/ query.getId(0, litstrId);
      StringData* litstr; /**/ query.getStaticString(1, litstr);
      Id id UNUSED = ue.mergeLitstr(litstr);
      ASSERT(id == litstrId);
    }
  } while (!query.done());
  txn.commit();
}
Beispiel #13
0
void UnitRepoProxy::GetUnitPreConstsStmt
                  ::get(UnitEmitter& ue) {
  RepoTxn txn(m_repo);
  if (!prepared()) {
    std::stringstream ssSelect;
    ssSelect << "SELECT name,value,preconstId FROM "
             << m_repo.table(m_repoId, "UnitPreConst")
             << " WHERE unitSn == @unitSn ORDER BY preConstId ASC;";
    txn.prepare(*this, ssSelect.str());
  }
  RepoTxnQuery query(txn, *this);
  query.bindInt64("@unitSn", ue.sn());
  do {
    query.step();
    if (query.row()) {
      StringData* name; /**/ query.getStaticString(0, name);
      TypedValue value; /**/ query.getTypedValue(1, value);
      Id id;            /**/ query.getId(2, id);
      UNUSED Id addedId = ue.addPreConst(name, value);
      ASSERT(id == addedId);
    }
  } while (!query.done());
  txn.commit();
}
Beispiel #14
0
void merge_repo_auth_type(UnitEmitter& ue, RepoAuthType rat) {
  using T = RepoAuthType::Tag;

  switch (rat.tag()) {
  case T::OptBool:
  case T::OptInt:
  case T::OptSStr:
  case T::OptStr:
  case T::OptDbl:
  case T::OptRes:
  case T::OptObj:
  case T::Null:
  case T::Cell:
  case T::Ref:
  case T::InitUnc:
  case T::Unc:
  case T::InitCell:
  case T::InitGen:
  case T::Gen:
  case T::Uninit:
  case T::InitNull:
  case T::Bool:
  case T::Int:
  case T::Dbl:
  case T::Res:
  case T::SStr:
  case T::Str:
  case T::Obj:
    return;

  case T::OptSArr:
  case T::OptArr:
  case T::SArr:
  case T::Arr:
    // We don't need to merge the litstrs in the array, because rats
    // in arrays in the array type table must be using global litstr
    // ids.  (As the array type table itself is not associated with
    // any unit.)
    return;

  case T::OptSubObj:
  case T::OptExactObj:
  case T::SubObj:
  case T::ExactObj:
    ue.mergeLitstr(rat.clsName());
    return;
  }
}
Beispiel #15
0
Datei: emit.cpp Projekt: 2bj/hhvm
RepoAuthType make_repo_type(UnitEmitter& ue, const Type& t) {
  using T = RepoAuthType::Tag;

  if (t.strictSubtypeOf(TObj) || (is_opt(t) && t.strictSubtypeOf(TOptObj))) {
    auto const dobj = dobj_of(t);
    auto const tag =
      is_opt(t)
        ? (dobj.type == DObj::Exact ? T::OptExactObj : T::OptSubObj)
        : (dobj.type == DObj::Exact ? T::ExactObj    : T::SubObj);
    ue.mergeLitstr(dobj.cls.name());
    return RepoAuthType { tag, dobj.cls.name() };
  }

#define ASSERTT_OP(x) if (t.subtypeOf(T##x)) return RepoAuthType{T::x};
  ASSERTT_OPS
#undef ASSERTT_OP
  return RepoAuthType{};
}
Beispiel #16
0
bool UnitRepoProxy::GetUnitStmt
                  ::get(UnitEmitter& ue, const MD5& md5) {
  try {
    RepoTxn txn(m_repo);
    if (!prepared()) {
      std::stringstream ssSelect;
      ssSelect << "SELECT unitSn,bc,bc_meta,mainReturn,mergeable,lines FROM "
               << m_repo.table(m_repoId, "Unit")
               << " WHERE md5 == @md5;";
      txn.prepare(*this, ssSelect.str());
    }
    RepoTxnQuery query(txn, *this);
    query.bindMd5("@md5", md5);
    query.step();
    if (!query.row()) {
      return true;
    }
    int64 unitSn;                            /**/ query.getInt64(0, unitSn);
    const void* bc; size_t bclen;            /**/ query.getBlob(1, bc, bclen);
    const void* bc_meta; size_t bc_meta_len; /**/ query.getBlob(2, bc_meta,
                                                                bc_meta_len);
    TypedValue value;                        /**/ query.getTypedValue(3, value);
    bool mergeable;                          /**/ query.getBool(4, mergeable);
    BlobDecoder linesBlob =                  /**/ query.getBlob(5);
    ue.setRepoId(m_repoId);
    ue.setSn(unitSn);
    ue.setBc((const uchar*)bc, bclen);
    ue.setBcMeta((const uchar*)bc_meta, bc_meta_len);
    value._count = mergeable;
    ue.setMainReturn(&value);

    LineTable lines;
    linesBlob(lines);
    ue.setLines(lines);

    txn.commit();
  } catch (RepoExc& re) {
    return true;
  }
  return false;
}
Beispiel #17
0
void RepoAuthType::resolveArray(const UnitEmitter& ue) {
  auto fn = [&](const uint32_t id) {
    return ue.lookupArrayType(id);
  };
  doResolve(fn);
}
Beispiel #18
0
void emit_class(EmitUnitState& state,
                UnitEmitter& ue,
                const php::Class& cls) {
  FTRACE(2, "    class: {}\n", cls.name->data());
  auto const pce = ue.newPreClassEmitter(
    cls.name,
    cls.hoistability
  );
  pce->init(
    std::get<0>(cls.srcInfo.loc),
    std::get<1>(cls.srcInfo.loc),
    ue.bcPos(),
    cls.attrs,
    cls.parentName ? cls.parentName : s_empty.get(),
    cls.srcInfo.docComment
  );
  pce->setUserAttributes(cls.userAttributes);

  for (auto& x : cls.interfaceNames)     pce->addInterface(x);
  for (auto& x : cls.usedTraitNames)     pce->addUsedTrait(x);
  for (auto& x : cls.requirements)       pce->addClassRequirement(x);
  for (auto& x : cls.traitPrecRules)     pce->addTraitPrecRule(x);
  for (auto& x : cls.traitAliasRules)    pce->addTraitAliasRule(x);

  for (auto& m : cls.methods) {
    FTRACE(2, "    method: {}\n", m->name->data());
    auto const fe = ue.newMethodEmitter(m->name, pce);
    emit_init_func(*fe, *m);
    pce->addMethod(fe);
    auto const info = emit_bytecode(state, ue, *m);
    emit_finish_func(*m, *fe, info);
  }

  auto const privateProps   = state.index.lookup_private_props(&cls);
  auto const privateStatics = state.index.lookup_private_statics(&cls);
  for (auto& prop : cls.properties) {
    auto const repoTy = [&] (const PropState& ps) -> RepoAuthType {
      // TODO(#3599292): we don't currently infer closure use var types.
      if (is_closure(cls)) return RepoAuthType{};
      auto it = ps.find(prop.name);
      if (it == end(ps)) return RepoAuthType{};
      auto const rat = make_repo_type(*state.index.array_table_builder(),
                                      it->second);
      merge_repo_auth_type(ue, rat);
      return rat;
    };

    pce->addProperty(
      prop.name,
      prop.attrs,
      prop.typeConstraint,
      prop.docComment,
      &prop.val,
      (prop.attrs & AttrStatic) ? repoTy(privateStatics) : repoTy(privateProps)
    );
  }

  for (auto& cconst : cls.constants) {
    pce->addConstant(
      cconst.name,
      cconst.typeConstraint,
      &cconst.val,
      cconst.phpCode
    );
  }
}
Beispiel #19
0
void emit_class(EmitUnitState& state,
                UnitEmitter& ue,
                const php::Class& cls) {
  FTRACE(2, "    class: {}\n", cls.name->data());
  auto const pce = ue.newPreClassEmitter(
    cls.name,
    cls.hoistability
  );
  pce->init(
    std::get<0>(cls.srcInfo.loc),
    std::get<1>(cls.srcInfo.loc),
    ue.bcPos(),
    cls.attrs,
    cls.parentName ? cls.parentName : s_empty.get(),
    cls.srcInfo.docComment
  );
  pce->setUserAttributes(cls.userAttributes);

  for (auto& x : cls.interfaceNames)     pce->addInterface(x);
  for (auto& x : cls.usedTraitNames)     pce->addUsedTrait(x);
  for (auto& x : cls.requirements)       pce->addClassRequirement(x);
  for (auto& x : cls.traitPrecRules)     pce->addTraitPrecRule(x);
  for (auto& x : cls.traitAliasRules)    pce->addTraitAliasRule(x);
  pce->setNumDeclMethods(cls.numDeclMethods);

  pce->setIfaceVtableSlot(state.index.lookup_iface_vtable_slot(&cls));

  for (auto& m : cls.methods) {
    FTRACE(2, "    method: {}\n", m->name->data());
    auto const fe = ue.newMethodEmitter(m->name, pce);
    emit_init_func(*fe, *m);
    pce->addMethod(fe);
    auto const info = emit_bytecode(state, ue, *m);
    emit_finish_func(*m, *fe, info);
  }

  std::vector<Type> useVars;
  if (is_closure(cls)) {
    auto f = find_method(&cls, s_invoke.get());
    useVars = state.index.lookup_closure_use_vars(f);
  }
  auto uvIt = useVars.begin();

  auto const privateProps   = state.index.lookup_private_props(&cls);
  auto const privateStatics = state.index.lookup_private_statics(&cls);
  for (auto& prop : cls.properties) {
    auto const makeRat = [&] (const Type& ty) -> RepoAuthType {
      if (ty.couldBe(TCls)) {
        return RepoAuthType{};
      }
      auto const rat = make_repo_type(*state.index.array_table_builder(), ty);
      merge_repo_auth_type(ue, rat);
      return rat;
    };

    auto const privPropTy = [&] (const PropState& ps) -> Type {
      if (is_closure(cls)) {
        // For closures use variables will be the first properties of the
        // closure object, in declaration order
        if (uvIt != useVars.end()) return *uvIt++;
        return Type{};
      }

      auto it = ps.find(prop.name);
      if (it == end(ps)) return Type{};
      return it->second;
    };

    Type propTy;
    auto const attrs = prop.attrs;
    if (attrs & AttrPrivate) {
      propTy = privPropTy((attrs & AttrStatic) ? privateStatics : privateProps);
    } else if ((attrs & AttrPublic) && (attrs & AttrStatic)) {
      propTy = state.index.lookup_public_static(&cls, prop.name);
    }

    pce->addProperty(
      prop.name,
      prop.attrs,
      prop.typeConstraint,
      prop.docComment,
      &prop.val,
      makeRat(propTy)
    );
  }
  assert(uvIt == useVars.end());

  for (auto& cconst : cls.constants) {
    if (!cconst.val.hasValue()) {
      pce->addAbstractConstant(
        cconst.name,
        cconst.typeConstraint,
        cconst.isTypeconst
      );
    } else {
      pce->addConstant(
        cconst.name,
        cconst.typeConstraint,
        &cconst.val.value(),
        cconst.phpCode,
        cconst.isTypeconst
      );
    }
  }

  pce->setEnumBaseTy(cls.enumBaseTy);
}
void encodeRAT(UnitEmitter& ue, RepoAuthType rat) {
  using T = RepoAuthType::Tag;
  switch (rat.tag()) {
  case T::Uninit:
  case T::InitNull:
  case T::Null:
  case T::Int:
  case T::OptInt:
  case T::Dbl:
  case T::OptDbl:
  case T::Res:
  case T::OptRes:
  case T::Bool:
  case T::OptBool:
  case T::SStr:
  case T::OptSStr:
  case T::Str:
  case T::OptStr:
  case T::SVec:
  case T::OptSVec:
  case T::Vec:
  case T::OptVec:
  case T::SDict:
  case T::OptSDict:
  case T::Dict:
  case T::OptDict:
  case T::SKeyset:
  case T::OptSKeyset:
  case T::Keyset:
  case T::OptKeyset:
  case T::Obj:
  case T::OptObj:
  case T::UncArrKey:
  case T::ArrKey:
  case T::OptUncArrKey:
  case T::OptArrKey:
  case T::InitUnc:
  case T::Unc:
  case T::InitCell:
  case T::Cell:
  case T::Ref:
  case T::InitGen:
  case T::Gen:
    ue.emitByte(static_cast<uint8_t>(rat.tag()));
    break;

  case T::SArr:
  case T::OptSArr:
  case T::Arr:
  case T::OptArr:
  case T::SVArr:
  case T::OptSVArr:
  case T::VArr:
  case T::OptVArr:
  case T::SDArr:
  case T::OptSDArr:
  case T::DArr:
  case T::OptDArr:
    {
      auto tagByte = static_cast<uint8_t>(rat.tag());
      if (rat.hasArrData()) tagByte |= kRATArrayDataBit;
      ue.emitByte(tagByte);
      if (rat.hasArrData()) {
        ue.emitInt32(rat.arrayId());
      }
      break;
    }

  case T::ExactObj:
  case T::SubObj:
  case T::OptExactObj:
  case T::OptSubObj:
    ue.emitByte(static_cast<uint8_t>(rat.tag()));
    ue.emitInt32(ue.mergeLitstr(rat.clsName()));
    break;
  }
}
Beispiel #21
0
void emit_class(EmitUnitState& state,
                UnitEmitter& ue,
                const php::Class& cls) {
  FTRACE(2, "    class: {}\n", cls.name->data());
  auto const pce = ue.newPreClassEmitter(
    cls.name,
    cls.hoistability
  );
  pce->init(
    std::get<0>(cls.srcInfo.loc),
    std::get<1>(cls.srcInfo.loc),
    ue.bcPos(),
    cls.attrs,
    cls.parentName ? cls.parentName : s_empty.get(),
    cls.srcInfo.docComment
  );
  pce->setUserAttributes(cls.userAttributes);

  for (auto& x : cls.interfaceNames)     pce->addInterface(x);
  for (auto& x : cls.usedTraitNames)     pce->addUsedTrait(x);
  for (auto& x : cls.requirements)       pce->addClassRequirement(x);
  for (auto& x : cls.traitPrecRules)     pce->addTraitPrecRule(x);
  for (auto& x : cls.traitAliasRules)    pce->addTraitAliasRule(x);
  pce->setNumDeclMethods(cls.numDeclMethods);

  pce->setIfaceVtableSlot(state.index.lookup_iface_vtable_slot(&cls));

  for (auto& m : cls.methods) {
    FTRACE(2, "    method: {}\n", m->name->data());
    auto const fe = ue.newMethodEmitter(m->name, pce);
    emit_init_func(*fe, *m);
    pce->addMethod(fe);
    auto const info = emit_bytecode(state, ue, *m);
    emit_finish_func(*m, *fe, info);
  }

  auto const privateProps   = state.index.lookup_private_props(&cls);
  auto const privateStatics = state.index.lookup_private_statics(&cls);
  for (auto& prop : cls.properties) {
    auto const makeRat = [&] (const Type& ty) -> RepoAuthType {
      if (ty.couldBe(TCls)) {
        return RepoAuthType{};
      }
      auto const rat = make_repo_type(*state.index.array_table_builder(), ty);
      merge_repo_auth_type(ue, rat);
      return rat;
    };

    auto const privPropTy = [&] (const PropState& ps) -> Type {
      /*
       * Skip closures, because the types of their used vars can be
       * communicated via assert opcodes right now.  At the time of this
       * writing there was nothing to gain by including RAT's for the
       * properties, since closure properties are only used internally by the
       * runtime, not directly via opcodes like CGetM.
       */
      if (is_closure(cls)) return Type{};

      auto it = ps.find(prop.name);
      if (it == end(ps)) return Type{};
      return it->second;
    };

    Type propTy;
    auto const attrs = prop.attrs;
    if (attrs & AttrPrivate) {
      propTy = privPropTy((attrs & AttrStatic) ? privateStatics : privateProps);
    } else if ((attrs & AttrPublic) && (attrs & AttrStatic)) {
      propTy = state.index.lookup_public_static(&cls, prop.name);
    }

    pce->addProperty(
      prop.name,
      prop.attrs,
      prop.typeConstraint,
      prop.docComment,
      &prop.val,
      makeRat(propTy)
    );
  }

  for (auto& cconst : cls.constants) {
    if (!cconst.val.hasValue()) {
      pce->addAbstractConstant(
        cconst.name,
        cconst.typeConstraint,
        cconst.isTypeconst
      );
    } else {
      pce->addConstant(
        cconst.name,
        cconst.typeConstraint,
        &cconst.val.value(),
        cconst.phpCode,
        cconst.isTypeconst
      );
    }
  }

  pce->setEnumBaseTy(cls.enumBaseTy);
}
Beispiel #22
0
void emit_typealias(UnitEmitter& ue, const php::TypeAlias& alias) {
  auto const id = ue.addTypeAlias(alias);
  ue.pushMergeableTypeAlias(HPHP::Unit::MergeKind::TypeAlias, id);
}