EmitterVisitor::emitPostponedMeths refactorization
EmitterVisitor::emitPostponedMeths was terribly long and disorganized. Let's split it into more methods that can be later reused for emitting generator body in FuncEmitter.
Esse commit está contido em:
@@ -1626,6 +1626,9 @@ void EmitterVisitor::visitIfCondition(
|
||||
}
|
||||
}
|
||||
|
||||
// Assigns ids to all of the local variables eagerly. This gives us the
|
||||
// nice property that all named local variables will be assigned ids
|
||||
// 0 through k-1, while any unnamed local variable will have an id >= k.
|
||||
void EmitterVisitor::assignLocalVariableIds(FunctionScopePtr fs) {
|
||||
VariableTablePtr variables = fs->getVariables();
|
||||
std::vector<std::string> localNames;
|
||||
@@ -1644,9 +1647,6 @@ void EmitterVisitor::visit(FileScopePtr file) {
|
||||
if (!func) return;
|
||||
|
||||
m_file = file;
|
||||
// Assign ids to all of the local variables eagerly. This gives us the
|
||||
// nice property that all named local variables will be assigned ids
|
||||
// 0 through k-1, while any unnamed local variable will have an id >= k.
|
||||
assignLocalVariableIds(func);
|
||||
|
||||
AnalysisResultPtr ar(file->getContainingProgram());
|
||||
@@ -5291,6 +5291,69 @@ static Attr buildAttrs(ModifierExpressionPtr mod, bool isRef = false) {
|
||||
return Attr(attrs);
|
||||
}
|
||||
|
||||
static Attr buildMethodAttrs(MethodStatementPtr meth, FuncEmitter* fe,
|
||||
bool top, bool allowOverride) {
|
||||
FunctionScopePtr funcScope = meth->getFunctionScope();
|
||||
ModifierExpressionPtr mod(meth->getModifiers());
|
||||
Attr attrs = buildAttrs(mod, meth->isRef());
|
||||
|
||||
if (allowOverride) {
|
||||
attrs = attrs | AttrAllowOverride;
|
||||
}
|
||||
|
||||
if (funcScope->mayUseVV() || meth->hasCallToGetArgs()) {
|
||||
attrs = attrs | AttrMayUseVV;
|
||||
}
|
||||
|
||||
auto fullName = meth->getOriginalFullName();
|
||||
auto it = Option::FunctionSections.find(fullName);
|
||||
if ((it != Option::FunctionSections.end() && it->second == "hot") ||
|
||||
(RuntimeOption::EvalRandomHotFuncs &&
|
||||
(hash_string_i(fullName.c_str()) & 8))) {
|
||||
attrs = attrs | AttrHot;
|
||||
}
|
||||
|
||||
if (Option::WholeProgram) {
|
||||
if (!funcScope->isRedeclaring()) {
|
||||
attrs = attrs | AttrUnique;
|
||||
if (top &&
|
||||
(!funcScope->isVolatile() ||
|
||||
funcScope->isPersistent() ||
|
||||
funcScope->isGenerator())) {
|
||||
attrs = attrs | AttrPersistent;
|
||||
}
|
||||
}
|
||||
if (ClassScopePtr cls = meth->getClassScope()) {
|
||||
if (meth->getName() == cls->getName() &&
|
||||
!cls->classNameCtor()) {
|
||||
/*
|
||||
In WholeProgram mode, we inline the traits into their
|
||||
classes. If a trait method name matches the class name
|
||||
it is NOT a constructor.
|
||||
We mark the method with AttrTrait so that we can avoid
|
||||
treating it as a constructor even though it looks like
|
||||
one.
|
||||
*/
|
||||
attrs = attrs | AttrTrait;
|
||||
}
|
||||
if (!funcScope->hasOverride()) {
|
||||
attrs = attrs | AttrNoOverride;
|
||||
}
|
||||
}
|
||||
} else if (!SystemLib::s_inited) {
|
||||
// we're building systemlib. everything is unique
|
||||
attrs = attrs | AttrUnique | AttrPersistent;
|
||||
}
|
||||
|
||||
// For closures, the MethodStatement didn't have real attributes; enforce
|
||||
// that the __invoke method is public here
|
||||
if (fe->isClosureBody()) {
|
||||
assert(!(attrs & (AttrProtected | AttrPrivate)));
|
||||
attrs = attrs | AttrPublic;
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
|
||||
static TypeConstraint
|
||||
determine_type_constraint(const ParameterExpressionPtr& par) {
|
||||
if (par->hasTypeHint()) {
|
||||
@@ -5334,9 +5397,16 @@ void EmitterVisitor::emitPostponedMeths() {
|
||||
PostponedMeth& p = m_postponedMeths.front();
|
||||
FunctionScopePtr funcScope = p.m_meth->getFunctionScope();
|
||||
FuncEmitter* fe = p.m_fe;
|
||||
bool allowOverride = false;
|
||||
|
||||
if (!fe) {
|
||||
assert(p.m_top);
|
||||
if (!m_topMethodEmitted.insert(p.m_meth->getOriginalName()).second) {
|
||||
throw IncludeTimeFatalException(
|
||||
p.m_meth,
|
||||
"%s",
|
||||
(string("Function already defined: ") +
|
||||
p.m_meth->getOriginalName()).c_str());
|
||||
}
|
||||
const StringData* methName =
|
||||
StringData::GetStaticString(p.m_meth->getOriginalName());
|
||||
fe = new FuncEmitter(m_ue, -1, -1, methName);
|
||||
@@ -5346,269 +5416,10 @@ void EmitterVisitor::emitPostponedMeths() {
|
||||
p.m_fe = fe;
|
||||
top_fes.push_back(fe);
|
||||
}
|
||||
const FunctionScope::UserAttributeMap& userAttrs =
|
||||
funcScope->userAttributes();
|
||||
for (FunctionScope::UserAttributeMap::const_iterator it = userAttrs.begin();
|
||||
it != userAttrs.end(); ++it) {
|
||||
if (it->first == "__Overridable") {
|
||||
allowOverride = true;
|
||||
continue;
|
||||
}
|
||||
const StringData* uaName = StringData::GetStaticString(it->first);
|
||||
ExpressionPtr uaValue = it->second;
|
||||
assert(uaValue);
|
||||
assert(uaValue->isScalar());
|
||||
TypedValue tv;
|
||||
initScalar(tv, uaValue);
|
||||
fe->addUserAttribute(uaName, tv);
|
||||
}
|
||||
Emitter e(p.m_meth, m_ue, *this);
|
||||
if (p.m_top) {
|
||||
if (!m_topMethodEmitted.insert(p.m_meth->getOriginalName()).second) {
|
||||
throw IncludeTimeFatalException(
|
||||
p.m_meth,
|
||||
"%s",
|
||||
(string("Function already defined: ") +
|
||||
p.m_meth->getOriginalName()).c_str());
|
||||
}
|
||||
}
|
||||
typedef std::pair<Id, ConstructPtr> DVInitializer;
|
||||
std::vector<DVInitializer> dvInitializers;
|
||||
ExpressionListPtr params = p.m_meth->getParams();
|
||||
int numParam = params ? params->getCount() : 0;
|
||||
for (int i = 0; i < numParam; i++) {
|
||||
ParameterExpressionPtr par(
|
||||
static_pointer_cast<ParameterExpression>((*params)[i]));
|
||||
StringData* parName = StringData::GetStaticString(par->getName());
|
||||
if (par->isOptional()) {
|
||||
dvInitializers.push_back(DVInitializer(i, par->defaultValue()));
|
||||
}
|
||||
|
||||
FuncEmitter::ParamInfo pi;
|
||||
auto const typeConstraint = determine_type_constraint(par);
|
||||
if (typeConstraint.hasConstraint()) {
|
||||
pi.setTypeConstraint(typeConstraint);
|
||||
}
|
||||
emitMethodMetadata(p);
|
||||
emitMethodBody(p);
|
||||
|
||||
if (par->hasUserType()) {
|
||||
pi.setUserType(StringData::GetStaticString(par->getUserTypeHint()));
|
||||
}
|
||||
|
||||
// Store info about the default value if there is one.
|
||||
if (par->isOptional()) {
|
||||
const StringData* phpCode;
|
||||
ExpressionPtr vNode = par->defaultValue();
|
||||
if (vNode->isScalar()) {
|
||||
TypedValue dv;
|
||||
initScalar(dv, vNode);
|
||||
pi.setDefaultValue(dv);
|
||||
|
||||
std::string orig = vNode->getComment();
|
||||
if (orig.empty()) {
|
||||
// Simple case: it's a scalar value so we just serialize it
|
||||
VariableSerializer vs(VariableSerializer::Type::PHPOutput);
|
||||
String result = vs.serialize(tvAsCVarRef(&dv), true);
|
||||
phpCode = StringData::GetStaticString(result.get());
|
||||
} else {
|
||||
// This was optimized from a Constant, or ClassConstant
|
||||
// use the original string
|
||||
phpCode = StringData::GetStaticString(orig);
|
||||
}
|
||||
} else {
|
||||
// Non-scalar, so we have to output PHP from the AST node
|
||||
std::ostringstream os;
|
||||
CodeGenerator cg(&os, CodeGenerator::PickledPHP);
|
||||
AnalysisResultPtr ar(new AnalysisResult());
|
||||
vNode->outputPHP(cg, ar);
|
||||
phpCode = StringData::GetStaticString(os.str());
|
||||
}
|
||||
pi.setPhpCode(phpCode);
|
||||
}
|
||||
ExpressionListPtr paramUserAttrs =
|
||||
dynamic_pointer_cast<ExpressionList>(par->userAttributeList());
|
||||
if (paramUserAttrs) {
|
||||
for (int j = 0; j < paramUserAttrs->getCount(); ++j) {
|
||||
UserAttributePtr a = dynamic_pointer_cast<UserAttribute>(
|
||||
(*paramUserAttrs)[j]);
|
||||
StringData* uaName = StringData::GetStaticString(a->getName());
|
||||
ExpressionPtr uaValue = a->getExp();
|
||||
assert(uaValue);
|
||||
assert(uaValue->isScalar());
|
||||
TypedValue tv;
|
||||
initScalar(tv, uaValue);
|
||||
pi.addUserAttribute(uaName, tv);
|
||||
}
|
||||
}
|
||||
|
||||
pi.setRef(par->isRef());
|
||||
fe->appendParam(parName, pi);
|
||||
}
|
||||
// add return type hint
|
||||
fe->setReturnTypeConstraint(
|
||||
StringData::GetStaticString(p.m_meth->getReturnTypeConstraint()));
|
||||
|
||||
// add the original filename for flattened traits
|
||||
auto const originalFilename = p.m_meth->getOriginalFilename();
|
||||
if (!originalFilename.empty()) {
|
||||
fe->setOriginalFilename(StringData::GetStaticString(originalFilename));
|
||||
}
|
||||
|
||||
m_curFunc = fe;
|
||||
|
||||
if (fe->isClosureBody() || fe->isGeneratorFromClosure()) {
|
||||
// We are going to keep the closure as the first local
|
||||
fe->allocVarId(StringData::GetStaticString("0Closure"));
|
||||
|
||||
if (fe->isClosureBody()) {
|
||||
ClosureUseVarVec* useVars = p.m_closureUseVars;
|
||||
for (auto& useVar : *useVars) {
|
||||
// These are all locals. I want them right after the params so I don't
|
||||
// have to keep track of which one goes where at runtime.
|
||||
fe->allocVarId(useVar.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p.m_meth->hasCallToGetArgs()) {
|
||||
fe->allocVarId(s_continuationVarArgsLocal);
|
||||
}
|
||||
|
||||
// Assign ids to all of the local variables eagerly. This gives us the
|
||||
// nice property that all named local variables will be assigned ids
|
||||
// 0 through k-1, while any unnamed local variable will have an id >= k.
|
||||
// Note that the logic above already assigned ids to the parameters, so
|
||||
// we will still uphold the invariant that the n parameters will have
|
||||
// ids 0 through n-1 respectively.
|
||||
assignLocalVariableIds(funcScope);
|
||||
|
||||
// set all the params and metadata etc on fe
|
||||
StringData* methDoc =
|
||||
StringData::GetStaticString(p.m_meth->getDocComment());
|
||||
ModifierExpressionPtr mod(p.m_meth->getModifiers());
|
||||
Attr attrs = buildAttrs(mod, p.m_meth->isRef());
|
||||
|
||||
if (allowOverride) attrs = attrs | AttrAllowOverride;
|
||||
|
||||
if (funcScope->mayUseVV() || p.m_meth->hasCallToGetArgs()) {
|
||||
attrs = attrs | AttrMayUseVV;
|
||||
}
|
||||
|
||||
auto fullName = p.m_meth->getOriginalFullName();
|
||||
auto it = Option::FunctionSections.find(fullName);
|
||||
if ((it != Option::FunctionSections.end() && it->second == "hot") ||
|
||||
(RuntimeOption::EvalRandomHotFuncs &&
|
||||
(hash_string_i(fullName.c_str()) & 8))) {
|
||||
attrs = attrs | AttrHot;
|
||||
}
|
||||
|
||||
if (Option::WholeProgram) {
|
||||
if (!funcScope->isRedeclaring()) {
|
||||
attrs = attrs | AttrUnique;
|
||||
if (p.m_top &&
|
||||
(!funcScope->isVolatile() ||
|
||||
funcScope->isPersistent() ||
|
||||
funcScope->isGenerator())) {
|
||||
attrs = attrs | AttrPersistent;
|
||||
}
|
||||
}
|
||||
if (ClassScopePtr cls = p.m_meth->getClassScope()) {
|
||||
if (p.m_meth->getName() == cls->getName() &&
|
||||
!cls->classNameCtor()) {
|
||||
/*
|
||||
In WholeProgram mode, we inline the traits into their
|
||||
classes. If a trait method name matches the class name
|
||||
it is NOT a constructor.
|
||||
We mark the method with AttrTrait so that we can avoid
|
||||
treating it as a constructor even though it looks like
|
||||
one.
|
||||
*/
|
||||
attrs = attrs | AttrTrait;
|
||||
}
|
||||
if (!funcScope->hasOverride()) {
|
||||
attrs = attrs | AttrNoOverride;
|
||||
}
|
||||
}
|
||||
} else if (!SystemLib::s_inited) {
|
||||
// we're building systemlib. everything is unique
|
||||
attrs = attrs | AttrUnique | AttrPersistent;
|
||||
}
|
||||
|
||||
// For closures, the MethodStatement didn't have real attributes; enforce
|
||||
// that the __invoke method is public here
|
||||
if (fe->isClosureBody()) {
|
||||
assert(!(attrs & (AttrProtected | AttrPrivate)));
|
||||
attrs = attrs | AttrPublic;
|
||||
}
|
||||
|
||||
Label topOfBody(e);
|
||||
const Location* sLoc = p.m_meth->getLocation().get();
|
||||
fe->init(sLoc->line0, sLoc->line1, m_ue.bcPos(), attrs, p.m_top, methDoc);
|
||||
// --Method emission begins--
|
||||
{
|
||||
if (funcScope->needsLocalThis() &&
|
||||
!funcScope->isStatic() &&
|
||||
!funcScope->isGenerator()) {
|
||||
assert(!p.m_top);
|
||||
static const StringData* thisStr = StringData::GetStaticString("this");
|
||||
Id thisId = fe->lookupVarId(thisStr);
|
||||
e.InitThisLoc(thisId);
|
||||
}
|
||||
for (uint i = 0; i < fe->params().size(); i++) {
|
||||
const TypeConstraint& tc = fe->params()[i].typeConstraint();
|
||||
if (!tc.hasConstraint()) continue;
|
||||
e.VerifyParamType(i);
|
||||
}
|
||||
|
||||
if (funcScope->isAbstract()) {
|
||||
StringData* msg =
|
||||
StringData::GetStaticString("Cannot call abstract method ");
|
||||
const StringData* methName =
|
||||
StringData::GetStaticString(p.m_meth->getOriginalFullName());
|
||||
msg = NEW(StringData)(msg, methName->slice());
|
||||
msg = NEW(StringData)(msg, "()");
|
||||
e.String(msg);
|
||||
e.Fatal(1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit body
|
||||
visit(p.m_meth->getStmts());
|
||||
|
||||
// If the current position in the bytecode is reachable, emit code to
|
||||
// return null
|
||||
if (currentPositionIsReachable()) {
|
||||
e.Null();
|
||||
if (p.m_meth->getFunctionScope()->isGenerator()) {
|
||||
assert(m_evalStack.size() == 1);
|
||||
e.ContRetC();
|
||||
} else {
|
||||
if ((p.m_meth->getStmts() && p.m_meth->getStmts()->isGuarded())) {
|
||||
m_metaInfo.add(m_ue.bcPos(), Unit::MetaInfo::Kind::GuardedThis,
|
||||
false, 0, 0);
|
||||
}
|
||||
e.RetC();
|
||||
}
|
||||
} // -- Method emission ends --
|
||||
|
||||
FuncFinisher ff(this, e, p.m_fe);
|
||||
|
||||
// Default value initializers
|
||||
for (uint i = 0; i < dvInitializers.size(); ++i) {
|
||||
Label entryPoint(e);
|
||||
Id paramId = dvInitializers[i].first;
|
||||
ConstructPtr node = dvInitializers[i].second;
|
||||
emitVirtualLocal(paramId, KindOfUninit);
|
||||
visit(node);
|
||||
emitCGet(e);
|
||||
emitSet(e);
|
||||
e.PopC();
|
||||
p.m_fe->setParamFuncletOff(paramId, entryPoint.getAbsoluteOffset());
|
||||
}
|
||||
if (!dvInitializers.empty()) {
|
||||
m_metaInfo.add(m_ue.bcPos(), Unit::MetaInfo::Kind::NoSurprise,
|
||||
false, 0, 0);
|
||||
e.Jmp(topOfBody);
|
||||
}
|
||||
delete p.m_closureUseVars;
|
||||
m_postponedMeths.pop_front();
|
||||
}
|
||||
@@ -5618,6 +5429,224 @@ void EmitterVisitor::emitPostponedMeths() {
|
||||
}
|
||||
}
|
||||
|
||||
void EmitterVisitor::emitMethodMetadata(PostponedMeth& p) {
|
||||
FunctionScopePtr funcScope = p.m_meth->getFunctionScope();
|
||||
FuncEmitter* fe = p.m_fe;
|
||||
|
||||
// user attributes
|
||||
bool allowOverride = false;
|
||||
const FunctionScope::UserAttributeMap& userAttrs =
|
||||
funcScope->userAttributes();
|
||||
for (FunctionScope::UserAttributeMap::const_iterator it = userAttrs.begin();
|
||||
it != userAttrs.end(); ++it) {
|
||||
if (it->first == "__Overridable") {
|
||||
allowOverride = true;
|
||||
continue;
|
||||
}
|
||||
const StringData* uaName = StringData::GetStaticString(it->first);
|
||||
ExpressionPtr uaValue = it->second;
|
||||
assert(uaValue);
|
||||
assert(uaValue->isScalar());
|
||||
TypedValue tv;
|
||||
initScalar(tv, uaValue);
|
||||
fe->addUserAttribute(uaName, tv);
|
||||
}
|
||||
|
||||
// parameters
|
||||
fillFuncEmitterParams(fe, p.m_meth->getParams());
|
||||
|
||||
// add return type hint
|
||||
fe->setReturnTypeConstraint(
|
||||
StringData::GetStaticString(p.m_meth->getReturnTypeConstraint()));
|
||||
|
||||
// add the original filename for flattened traits
|
||||
auto const originalFilename = p.m_meth->getOriginalFilename();
|
||||
if (!originalFilename.empty()) {
|
||||
fe->setOriginalFilename(StringData::GetStaticString(originalFilename));
|
||||
}
|
||||
|
||||
if (fe->isClosureBody() || fe->isGeneratorFromClosure()) {
|
||||
// We are going to keep the closure as the first local
|
||||
fe->allocVarId(StringData::GetStaticString("0Closure"));
|
||||
|
||||
if (fe->isClosureBody()) {
|
||||
ClosureUseVarVec* useVars = p.m_closureUseVars;
|
||||
for (auto& useVar : *useVars) {
|
||||
// These are all locals. I want them right after the params so I don't
|
||||
// have to keep track of which one goes where at runtime.
|
||||
fe->allocVarId(useVar.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p.m_meth->hasCallToGetArgs()) {
|
||||
fe->allocVarId(s_continuationVarArgsLocal);
|
||||
}
|
||||
|
||||
const Location* sLoc = p.m_meth->getLocation().get();
|
||||
fe->init(sLoc->line0,
|
||||
sLoc->line1,
|
||||
m_ue.bcPos(),
|
||||
buildMethodAttrs(p.m_meth, p.m_fe, p.m_top, allowOverride),
|
||||
p.m_top,
|
||||
StringData::GetStaticString(p.m_meth->getDocComment()));
|
||||
}
|
||||
|
||||
void EmitterVisitor::fillFuncEmitterParams(FuncEmitter* fe,
|
||||
ExpressionListPtr params){
|
||||
int numParam = params ? params->getCount() : 0;
|
||||
for (int i = 0; i < numParam; i++) {
|
||||
ParameterExpressionPtr par(
|
||||
static_pointer_cast<ParameterExpression>((*params)[i]));
|
||||
StringData* parName = StringData::GetStaticString(par->getName());
|
||||
|
||||
FuncEmitter::ParamInfo pi;
|
||||
auto const typeConstraint = determine_type_constraint(par);
|
||||
if (typeConstraint.hasConstraint()) {
|
||||
pi.setTypeConstraint(typeConstraint);
|
||||
}
|
||||
|
||||
if (par->hasUserType()) {
|
||||
pi.setUserType(StringData::GetStaticString(par->getUserTypeHint()));
|
||||
}
|
||||
|
||||
// Store info about the default value if there is one.
|
||||
if (par->isOptional()) {
|
||||
const StringData* phpCode;
|
||||
ExpressionPtr vNode = par->defaultValue();
|
||||
if (vNode->isScalar()) {
|
||||
TypedValue dv;
|
||||
initScalar(dv, vNode);
|
||||
pi.setDefaultValue(dv);
|
||||
|
||||
std::string orig = vNode->getComment();
|
||||
if (orig.empty()) {
|
||||
// Simple case: it's a scalar value so we just serialize it
|
||||
VariableSerializer vs(VariableSerializer::Type::PHPOutput);
|
||||
String result = vs.serialize(tvAsCVarRef(&dv), true);
|
||||
phpCode = StringData::GetStaticString(result.get());
|
||||
} else {
|
||||
// This was optimized from a Constant, or ClassConstant
|
||||
// use the original string
|
||||
phpCode = StringData::GetStaticString(orig);
|
||||
}
|
||||
} else {
|
||||
// Non-scalar, so we have to output PHP from the AST node
|
||||
std::ostringstream os;
|
||||
CodeGenerator cg(&os, CodeGenerator::PickledPHP);
|
||||
AnalysisResultPtr ar(new AnalysisResult());
|
||||
vNode->outputPHP(cg, ar);
|
||||
phpCode = StringData::GetStaticString(os.str());
|
||||
}
|
||||
pi.setPhpCode(phpCode);
|
||||
}
|
||||
|
||||
ExpressionListPtr paramUserAttrs =
|
||||
dynamic_pointer_cast<ExpressionList>(par->userAttributeList());
|
||||
if (paramUserAttrs) {
|
||||
for (int j = 0; j < paramUserAttrs->getCount(); ++j) {
|
||||
UserAttributePtr a = dynamic_pointer_cast<UserAttribute>(
|
||||
(*paramUserAttrs)[j]);
|
||||
StringData* uaName = StringData::GetStaticString(a->getName());
|
||||
ExpressionPtr uaValue = a->getExp();
|
||||
assert(uaValue);
|
||||
assert(uaValue->isScalar());
|
||||
TypedValue tv;
|
||||
initScalar(tv, uaValue);
|
||||
pi.addUserAttribute(uaName, tv);
|
||||
}
|
||||
}
|
||||
|
||||
pi.setRef(par->isRef());
|
||||
fe->appendParam(parName, pi);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitterVisitor::emitMethodBody(PostponedMeth& p) {
|
||||
FunctionScopePtr funcScope = p.m_meth->getFunctionScope();
|
||||
FuncEmitter* fe = p.m_fe;
|
||||
m_curFunc = fe;
|
||||
|
||||
// Assign ids to all of the local variables eagerly. Note that parameters
|
||||
// ids are already assigned, so we will still uphold the invariant that
|
||||
// the n parameters will have ids 0 through n-1 respectively.
|
||||
assignLocalVariableIds(funcScope);
|
||||
|
||||
Emitter e(p.m_meth, m_ue, *this);
|
||||
Label topOfBody(e);
|
||||
|
||||
if (funcScope->needsLocalThis() &&
|
||||
!funcScope->isStatic() &&
|
||||
!funcScope->isGenerator()) {
|
||||
assert(!p.m_top);
|
||||
static const StringData* thisStr = StringData::GetStaticString("this");
|
||||
Id thisId = fe->lookupVarId(thisStr);
|
||||
e.InitThisLoc(thisId);
|
||||
}
|
||||
for (uint i = 0; i < fe->params().size(); i++) {
|
||||
const TypeConstraint& tc = fe->params()[i].typeConstraint();
|
||||
if (!tc.hasConstraint()) continue;
|
||||
e.VerifyParamType(i);
|
||||
}
|
||||
|
||||
if (funcScope->isAbstract()) {
|
||||
StringData* msg = StringData::GetStaticString(
|
||||
"Cannot call abstract method " + p.m_meth->getOriginalFullName() + "()");
|
||||
e.String(msg);
|
||||
e.Fatal(1);
|
||||
}
|
||||
|
||||
// emit method body
|
||||
visit(p.m_meth->getStmts());
|
||||
|
||||
// If the current position in the bytecode is reachable, emit code to
|
||||
// return null
|
||||
if (currentPositionIsReachable()) {
|
||||
e.Null();
|
||||
if (p.m_meth->getFunctionScope()->isGenerator()) {
|
||||
assert(m_evalStack.size() == 1);
|
||||
e.ContRetC();
|
||||
} else {
|
||||
if ((p.m_meth->getStmts() && p.m_meth->getStmts()->isGuarded())) {
|
||||
m_metaInfo.add(m_ue.bcPos(), Unit::MetaInfo::Kind::GuardedThis,
|
||||
false, 0, 0);
|
||||
}
|
||||
e.RetC();
|
||||
}
|
||||
}
|
||||
|
||||
FuncFinisher ff(this, e, p.m_fe);
|
||||
|
||||
emitMethodDVInitializers(e, p, topOfBody);
|
||||
}
|
||||
|
||||
void EmitterVisitor::emitMethodDVInitializers(Emitter& e, PostponedMeth& p,
|
||||
Label& topOfBody) {
|
||||
// Default value initializers
|
||||
bool hasOptional = false;
|
||||
ExpressionListPtr params = p.m_meth->getParams();
|
||||
int numParam = params ? params->getCount() : 0;
|
||||
for (int i = 0; i < numParam; i++) {
|
||||
ParameterExpressionPtr par(
|
||||
static_pointer_cast<ParameterExpression>((*params)[i]));
|
||||
if (par->isOptional()) {
|
||||
hasOptional = true;
|
||||
Label entryPoint(e);
|
||||
emitVirtualLocal(i, KindOfUninit);
|
||||
visit(par->defaultValue());
|
||||
emitCGet(e);
|
||||
emitSet(e);
|
||||
e.PopC();
|
||||
p.m_fe->setParamFuncletOff(i, entryPoint.getAbsoluteOffset());
|
||||
}
|
||||
}
|
||||
if (hasOptional) {
|
||||
m_metaInfo.add(m_ue.bcPos(), Unit::MetaInfo::Kind::NoSurprise,
|
||||
false, 0, 0);
|
||||
e.Jmp(topOfBody);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitterVisitor::emitPostponedCtors() {
|
||||
while (!m_postponedCtors.empty()) {
|
||||
PostponedCtor& p = m_postponedCtors.front();
|
||||
|
||||
Arquivo normal → Arquivo executável
+6
@@ -628,6 +628,12 @@ public:
|
||||
void postponeSinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
|
||||
void postponeCinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
|
||||
void emitPostponedMeths();
|
||||
void emitMethodMetadata(PostponedMeth& p);
|
||||
void fillFuncEmitterParams(FuncEmitter* fe,
|
||||
ExpressionListPtr params);
|
||||
void emitMethodBody(PostponedMeth& p);
|
||||
void emitMethodDVInitializers(Emitter& e, PostponedMeth& p,
|
||||
Label& topOfBody);
|
||||
void emitPostponedCtors();
|
||||
void emitPostponedPSinit(PostponedNonScalars& p, bool pinit);
|
||||
void emitPostponedPinits();
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário