147b983f2b
Global constants pushed directly into the global constants table:
static const StaticString s_mpi("M_PI");
virtual moduleLoad(Hdf config) {
Native::RegisterConstantDouble(s_mpi.get(), 3.1415926535);
}
While Class constants are queued into a temporary table,
then picked up during PCE emit as Systemlib is parsed:
static const StaticString s_math("Math");
static const StaticString s_pi("PI");
virtual moduleLoad(Hdf config) {
Native::RegisterClassConstantDouble(s_math.get(), s_pi.get(),
3.1415926535);
}
.
<?php
class Math {
// PI will be injected here at emit time
}
Reviewed By: @jdelong
Differential Revision: D963642
349 linhas
11 KiB
C++
349 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 "folly/Memory.h"
|
|
|
|
#include "hphp/runtime/vm/repo.h"
|
|
#include "hphp/runtime/vm/blob-helper.h"
|
|
#include "hphp/runtime/vm/native.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);
|
|
}
|
|
|
|
auto pc = folly::make_unique<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.get());
|
|
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.get(),
|
|
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.get(),
|
|
const_.name(),
|
|
const_.typeConstraint(),
|
|
const_.val(),
|
|
const_.phpCode()));
|
|
}
|
|
if (auto nativeConsts = Native::getClassConstants(m_name)) {
|
|
for (auto cnsMap : *nativeConsts) {
|
|
auto tv = cnsMap.second;
|
|
constBuild.add(cnsMap.first, PreClass::Const(pc.get(),
|
|
cnsMap.first,
|
|
empty_string.get(),
|
|
tv,
|
|
empty_string.get()));
|
|
}
|
|
}
|
|
|
|
pc->m_constants.create(constBuild);
|
|
return pc.release();
|
|
}
|
|
|
|
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
|