9edc07112b
When object support was first added to HHVM, a class named "Instance" was introduced (deriving from ObjectData) to represent instances of user defined classes. Since then, things have evolved and HPHPc and HPHPi have been retired, and now there really is no needed to have ObjectData and Instance be separate classes anymore. As a first step towards merging ObjectData and Instance together, this diff puts their definitions in the same .h file and puts their implementations in the same .cpp file. A few small changes were necessary to fix issues with cyclical includes: (1) Repo/emitter related parts of class.cpp and class.h were moved to class-emit.cpp and class-emit.h; (2) the contents of "vm/core_types.h" was moved to "base/types.h"; and (3) a few functions that didn't appear to be hot were moved from .h files and the corresponding .cpp files.
332 linhas
11 KiB
C++
332 linhas
11 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
#include "hphp/runtime/vm/preclass-emit.h"
|
|
#include "hphp/runtime/vm/repo.h"
|
|
#include "hphp/runtime/vm/blob_helper.h"
|
|
|
|
namespace HPHP {
|
|
|
|
//=============================================================================
|
|
// PreClassEmitter::Prop.
|
|
|
|
PreClassEmitter::Prop::Prop(const PreClassEmitter* pce,
|
|
const StringData* n,
|
|
Attr attrs,
|
|
const StringData* typeConstraint,
|
|
const StringData* docComment,
|
|
TypedValue* val,
|
|
DataType hphpcType)
|
|
: m_name(n)
|
|
, m_attrs(attrs)
|
|
, m_typeConstraint(typeConstraint)
|
|
, m_docComment(docComment)
|
|
, m_hphpcType(hphpcType)
|
|
{
|
|
m_mangledName = PreClass::manglePropName(pce->name(), n, attrs);
|
|
memcpy(&m_val, val, sizeof(TypedValue));
|
|
}
|
|
|
|
PreClassEmitter::Prop::~Prop() {
|
|
}
|
|
|
|
//=============================================================================
|
|
// PreClassEmitter.
|
|
|
|
PreClassEmitter::PreClassEmitter(UnitEmitter& ue,
|
|
Id id,
|
|
const StringData* n,
|
|
PreClass::Hoistable hoistable)
|
|
: m_ue(ue)
|
|
, m_name(n)
|
|
, m_id(id)
|
|
, m_hoistable(hoistable)
|
|
, m_InstanceCtor(nullptr)
|
|
, m_builtinPropSize(0)
|
|
{}
|
|
|
|
void PreClassEmitter::init(int line1, int line2, Offset offset, Attr attrs,
|
|
const StringData* parent,
|
|
const StringData* docComment) {
|
|
m_line1 = line1;
|
|
m_line2 = line2;
|
|
m_offset = offset;
|
|
m_attrs = attrs;
|
|
m_parent = parent;
|
|
m_docComment = docComment;
|
|
}
|
|
|
|
PreClassEmitter::~PreClassEmitter() {
|
|
for (MethodVec::const_iterator it = m_methods.begin();
|
|
it != m_methods.end(); ++it) {
|
|
delete *it;
|
|
}
|
|
}
|
|
|
|
void PreClassEmitter::addInterface(const StringData* n) {
|
|
m_interfaces.push_back(n);
|
|
}
|
|
|
|
bool PreClassEmitter::addMethod(FuncEmitter* method) {
|
|
MethodMap::const_iterator it = m_methodMap.find(method->name());
|
|
if (it != m_methodMap.end()) {
|
|
return false;
|
|
}
|
|
m_methods.push_back(method);
|
|
m_methodMap[method->name()] = method;
|
|
return true;
|
|
}
|
|
|
|
bool PreClassEmitter::addProperty(const StringData* n, Attr attrs,
|
|
const StringData* typeConstraint,
|
|
const StringData* docComment,
|
|
TypedValue* val,
|
|
DataType hphpcType) {
|
|
PropMap::Builder::const_iterator it = m_propMap.find(n);
|
|
if (it != m_propMap.end()) {
|
|
return false;
|
|
}
|
|
PreClassEmitter::Prop prop(this, n, attrs, typeConstraint, docComment, val,
|
|
hphpcType);
|
|
m_propMap.add(prop.name(), prop);
|
|
return true;
|
|
}
|
|
|
|
const PreClassEmitter::Prop&
|
|
PreClassEmitter::lookupProp(const StringData* propName) const {
|
|
PropMap::Builder::const_iterator it = m_propMap.find(propName);
|
|
assert(it != m_propMap.end());
|
|
Slot idx = it->second;
|
|
return m_propMap[idx];
|
|
}
|
|
|
|
bool PreClassEmitter::addConstant(const StringData* n,
|
|
const StringData* typeConstraint,
|
|
TypedValue* val,
|
|
const StringData* phpCode) {
|
|
ConstMap::Builder::const_iterator it = m_constMap.find(n);
|
|
if (it != m_constMap.end()) {
|
|
return false;
|
|
}
|
|
PreClassEmitter::Const const_(n, typeConstraint, val, phpCode);
|
|
m_constMap.add(const_.name(), const_);
|
|
return true;
|
|
}
|
|
|
|
void PreClassEmitter::addUsedTrait(const StringData* traitName) {
|
|
m_usedTraits.push_back(traitName);
|
|
}
|
|
|
|
void PreClassEmitter::addTraitPrecRule(
|
|
const PreClass::TraitPrecRule &rule) {
|
|
m_traitPrecRules.push_back(rule);
|
|
}
|
|
|
|
void PreClassEmitter::addTraitAliasRule(
|
|
const PreClass::TraitAliasRule &rule) {
|
|
m_traitAliasRules.push_back(rule);
|
|
}
|
|
|
|
void PreClassEmitter::addUserAttribute(const StringData* name, TypedValue tv) {
|
|
m_userAttributes[name] = tv;
|
|
}
|
|
|
|
void PreClassEmitter::commit(RepoTxn& txn) const {
|
|
Repo& repo = Repo::get();
|
|
PreClassRepoProxy& pcrp = repo.pcrp();
|
|
int repoId = m_ue.repoId();
|
|
int64_t usn = m_ue.sn();
|
|
pcrp.insertPreClass(repoId)
|
|
.insert(*this, txn, usn, m_id, m_name, m_hoistable);
|
|
|
|
for (MethodVec::const_iterator it = m_methods.begin();
|
|
it != m_methods.end(); ++it) {
|
|
(*it)->commit(txn);
|
|
}
|
|
}
|
|
|
|
void PreClassEmitter::setBuiltinClassInfo(const ClassInfo* info,
|
|
BuiltinCtorFunction ctorFunc,
|
|
int sz) {
|
|
if (info->getAttribute() & ClassInfo::IsFinal) {
|
|
m_attrs = m_attrs | AttrFinal;
|
|
}
|
|
if (info->getAttribute() & ClassInfo::IsAbstract) {
|
|
m_attrs = m_attrs | AttrAbstract;
|
|
}
|
|
if (info->getAttribute() & ClassInfo::IsTrait) {
|
|
m_attrs = m_attrs | AttrTrait;
|
|
}
|
|
m_attrs = m_attrs | AttrUnique;
|
|
m_InstanceCtor = ctorFunc;
|
|
m_builtinPropSize = sz - sizeof(ObjectData);
|
|
}
|
|
|
|
PreClass* PreClassEmitter::create(Unit& unit) const {
|
|
Attr attrs = m_attrs;
|
|
if (attrs & AttrPersistent &&
|
|
!RuntimeOption::RepoAuthoritative && SystemLib::s_inited) {
|
|
attrs = Attr(attrs & ~AttrPersistent);
|
|
}
|
|
PreClass* pc = new PreClass(&unit, m_line1, m_line2, m_offset, m_name,
|
|
attrs, m_parent, m_docComment, m_id,
|
|
m_hoistable);
|
|
pc->m_InstanceCtor = m_InstanceCtor;
|
|
pc->m_builtinPropSize = m_builtinPropSize;
|
|
pc->m_interfaces = m_interfaces;
|
|
pc->m_usedTraits = m_usedTraits;
|
|
pc->m_traitPrecRules = m_traitPrecRules;
|
|
pc->m_traitAliasRules = m_traitAliasRules;
|
|
pc->m_userAttributes = m_userAttributes;
|
|
|
|
PreClass::MethodMap::Builder methodBuild;
|
|
for (MethodVec::const_iterator it = m_methods.begin();
|
|
it != m_methods.end(); ++it) {
|
|
Func* f = (*it)->create(unit, pc);
|
|
methodBuild.add(f->name(), f);
|
|
}
|
|
pc->m_methods.create(methodBuild);
|
|
|
|
PreClass::PropMap::Builder propBuild;
|
|
for (unsigned i = 0; i < m_propMap.size(); ++i) {
|
|
const Prop& prop = m_propMap[i];
|
|
propBuild.add(prop.name(), PreClass::Prop(pc,
|
|
prop.name(),
|
|
prop.attrs(),
|
|
prop.typeConstraint(),
|
|
prop.docComment(),
|
|
prop.val(),
|
|
prop.hphpcType()));
|
|
}
|
|
pc->m_properties.create(propBuild);
|
|
|
|
PreClass::ConstMap::Builder constBuild;
|
|
for (unsigned i = 0; i < m_constMap.size(); ++i) {
|
|
const Const& const_ = m_constMap[i];
|
|
constBuild.add(const_.name(), PreClass::Const(pc,
|
|
const_.name(),
|
|
const_.typeConstraint(),
|
|
const_.val(),
|
|
const_.phpCode()));
|
|
}
|
|
pc->m_constants.create(constBuild);
|
|
return pc;
|
|
}
|
|
|
|
template<class SerDe> void PreClassEmitter::serdeMetaData(SerDe& sd) {
|
|
// NOTE: name, hoistable, and a few other fields currently
|
|
// serialized outside of this.
|
|
sd(m_line1)
|
|
(m_line2)
|
|
(m_offset)
|
|
(m_attrs)
|
|
(m_parent)
|
|
(m_docComment)
|
|
|
|
(m_interfaces)
|
|
(m_usedTraits)
|
|
(m_traitPrecRules)
|
|
(m_traitAliasRules)
|
|
(m_userAttributes)
|
|
(m_propMap)
|
|
(m_constMap)
|
|
;
|
|
}
|
|
|
|
//=============================================================================
|
|
// PreClassRepoProxy.
|
|
|
|
PreClassRepoProxy::PreClassRepoProxy(Repo& repo)
|
|
: RepoProxy(repo)
|
|
#define PCRP_OP(c, o) \
|
|
, m_##o##Local(repo, RepoIdLocal), m_##o##Central(repo, RepoIdCentral)
|
|
PCRP_OPS
|
|
#undef PCRP_OP
|
|
{
|
|
#define PCRP_OP(c, o) \
|
|
m_##o[RepoIdLocal] = &m_##o##Local; \
|
|
m_##o[RepoIdCentral] = &m_##o##Central;
|
|
PCRP_OPS
|
|
#undef PCRP_OP
|
|
}
|
|
|
|
PreClassRepoProxy::~PreClassRepoProxy() {
|
|
}
|
|
|
|
void PreClassRepoProxy::createSchema(int repoId, RepoTxn& txn) {
|
|
{
|
|
std::stringstream ssCreate;
|
|
ssCreate << "CREATE TABLE " << m_repo.table(repoId, "PreClass")
|
|
<< "(unitSn INTEGER, preClassId INTEGER, name TEXT,"
|
|
" hoistable INTEGER, extraData BLOB,"
|
|
" PRIMARY KEY (unitSn, preClassId));";
|
|
txn.exec(ssCreate.str());
|
|
}
|
|
}
|
|
|
|
void PreClassRepoProxy::InsertPreClassStmt
|
|
::insert(const PreClassEmitter& pce, RepoTxn& txn,
|
|
int64_t unitSn, Id preClassId,
|
|
const StringData* name,
|
|
PreClass::Hoistable hoistable) {
|
|
if (!prepared()) {
|
|
std::stringstream ssInsert;
|
|
ssInsert << "INSERT INTO " << m_repo.table(m_repoId, "PreClass")
|
|
<< " VALUES(@unitSn, @preClassId, @name, @hoistable, "
|
|
"@extraData);";
|
|
txn.prepare(*this, ssInsert.str());
|
|
}
|
|
|
|
BlobEncoder extraBlob;
|
|
RepoTxnQuery query(txn, *this);
|
|
query.bindInt64("@unitSn", unitSn);
|
|
query.bindId("@preClassId", preClassId);
|
|
query.bindStaticString("@name", name);
|
|
query.bindInt("@hoistable", hoistable);
|
|
const_cast<PreClassEmitter&>(pce).serdeMetaData(extraBlob);
|
|
query.bindBlob("@extraData", extraBlob, /* static */ true);
|
|
query.exec();
|
|
}
|
|
|
|
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);
|
|
assert(pce->id() == preClassId);
|
|
}
|
|
} while (!query.done());
|
|
txn.commit();
|
|
}
|
|
|
|
} // HPHP
|