use of com.google.template.soy.jbcsrc.restricted.LocalVariable in project closure-templates by google.
the class PrintDirectives method applyStreamingPrintDirectivesTo.
private static AppendableAndOptions applyStreamingPrintDirectivesTo(List<DirectiveWithArgs> directivesToApply, Expression appendable, JbcSrcPluginContext context, TemplateVariableManager variableManager) {
final List<LocalVariable> closeables = new ArrayList<>();
final List<Variable> appendableVars = new ArrayList<>();
Scope scope = variableManager.enterScope();
AppendableAndOptions prev = AppendableAndOptions.create(appendable);
Variable prevVar = scope.createTemporary("tmp_appendable", appendable);
appendableVars.add(prevVar);
// appendable with the last directive first. so iterate in reverse order.
for (DirectiveWithArgs directiveToApply : Lists.reverse(directivesToApply)) {
AppendableAndOptions curr = directiveToApply.apply(context, prevVar.local());
Variable currVar = scope.createTemporary("tmp_appendable", curr.appendable());
appendableVars.add(currVar);
if (curr.closeable()) {
closeables.add(currVar.local());
}
prev = curr;
prevVar = currVar;
}
// Check if we need to apply a wrapper to make sure close propagates to all the right places
// this is necessary if there are multiple closeable wrappers.
final Expression appendableExpression;
final boolean closeable;
if (closeables.isEmpty()) {
appendableExpression = prev.appendable();
closeable = false;
} else if (closeables.size() == 1 && prev.closeable()) {
// there is exactly one closeable and it is first, we don't need a wrapper
appendableExpression = prev.appendable();
closeable = true;
} else {
// there is either more than one closeable, or it is not the first one, so we need a wrapper
// We need to reverse the list of closeables so that we close them in the correct order. for
// example, given '|foo|bar' we will first wrap the delegate with bar and then with foo but we
// need to close foo first.
appendableExpression = RUNTIME_PROPAGATE_CLOSE.invoke(Iterables.getLast(appendableVars).local(), BytecodeUtils.asImmutableList(Lists.reverse(closeables)));
closeable = true;
}
final Statement exitScope = scope.exitScope();
Expression result = new Expression(appendableExpression.resultType()) {
@Override
protected void doGen(CodeBuilder adapter) {
for (Variable var : appendableVars) {
var.initializer().gen(adapter);
}
appendableExpression.gen(adapter);
exitScope.gen(adapter);
}
};
if (closeable) {
return AppendableAndOptions.createCloseable(result);
} else {
return AppendableAndOptions.create(result);
}
}
use of com.google.template.soy.jbcsrc.restricted.LocalVariable in project closure-templates by google.
the class TemplateCompiler method generateConstructor.
/**
* Generate a public constructor that assigns our final field and checks for missing required
* params.
*
* <p>This constructor is called by the generate factory classes.
*
* @param fieldInitializers additional statements to initialize fields (other than params)
*/
private void generateConstructor(Statement fieldInitializers) {
final Label start = new Label();
final Label end = new Label();
final LocalVariable thisVar = createThisVar(template.typeInfo(), start, end);
final LocalVariable paramsVar = createLocal("params", 1, SOY_RECORD_TYPE, start, end);
final LocalVariable ijVar = createLocal("ij", 2, SOY_RECORD_TYPE, start, end);
final List<Statement> assignments = new ArrayList<>();
// for other fields needed by the compiler.
assignments.add(fieldInitializers);
assignments.add(paramsField.putInstanceField(thisVar, paramsVar));
assignments.add(ijField.putInstanceField(thisVar, ijVar));
for (TemplateParam param : template.node().getAllParams()) {
Expression paramProvider = getParam(paramsVar, ijVar, param);
assignments.add(paramFields.get(param.name()).putInstanceField(thisVar, paramProvider));
}
Statement constructorBody = new Statement() {
@Override
protected void doGen(CodeBuilder ga) {
ga.mark(start);
// call super()
thisVar.gen(ga);
ga.invokeConstructor(OBJECT.type(), NULLARY_INIT);
for (Statement assignment : assignments) {
assignment.gen(ga);
}
ga.visitInsn(Opcodes.RETURN);
ga.visitLabel(end);
thisVar.tableEntry(ga);
paramsVar.tableEntry(ga);
ijVar.tableEntry(ga);
}
};
constructorBody.writeMethod(Opcodes.ACC_PUBLIC, template.constructor().method(), writer);
}
use of com.google.template.soy.jbcsrc.restricted.LocalVariable in project closure-templates by google.
the class TemplateCompiler method generateRenderMethod.
private Statement generateRenderMethod() {
final Label start = new Label();
final Label end = new Label();
final LocalVariable thisVar = createThisVar(template.typeInfo(), start, end);
final LocalVariable appendableVar = createLocal("appendable", 1, LOGGING_ADVISING_APPENDABLE_TYPE, start, end).asNonNullable();
final LocalVariable contextVar = createLocal("context", 2, RENDER_CONTEXT_TYPE, start, end).asNonNullable();
final TemplateVariableManager variableSet = new TemplateVariableManager(fieldNames, template.typeInfo(), thisVar, template.renderMethod().method());
TemplateNode node = template.node();
TemplateVariables variables = new TemplateVariables(variableSet, thisVar, new RenderContextExpression(contextVar));
final CompiledMethodBody methodBody = SoyNodeCompiler.create(registry, innerClasses, stateField, thisVar, AppendableExpression.forLocal(appendableVar), variableSet, variables).compile(node);
final Statement returnDone = Statement.returnExpression(MethodRef.RENDER_RESULT_DONE.invoke());
new Statement() {
@Override
protected void doGen(CodeBuilder adapter) {
adapter.mark(start);
methodBody.body().gen(adapter);
adapter.mark(end);
returnDone.gen(adapter);
thisVar.tableEntry(adapter);
appendableVar.tableEntry(adapter);
contextVar.tableEntry(adapter);
variableSet.generateTableEntries(adapter);
}
}.writeIOExceptionMethod(Opcodes.ACC_PUBLIC, template.renderMethod().method(), writer);
writer.setNumDetachStates(methodBody.numberOfDetachStates());
variableSet.defineStaticFields(writer);
return variableSet.defineFields(writer);
}
use of com.google.template.soy.jbcsrc.restricted.LocalVariable in project closure-templates by google.
the class TemplateFactoryCompiler method generateCreateMethod.
/**
* Writes the {@link CompiledTemplate.Factory#create} method, which directly delegates to the
* constructor of the {@link #template}.
*/
private void generateCreateMethod(ClassVisitor cv, TypeInfo factoryType) {
final Label start = new Label();
final Label end = new Label();
final LocalVariable thisVar = createThisVar(factoryType, start, end);
final LocalVariable paramsVar = createLocal("params", 1, SOY_RECORD_TYPE, start, end);
final LocalVariable ijVar = createLocal("ij", 2, SOY_RECORD_TYPE, start, end);
final Statement returnTemplate = Statement.returnExpression(template.constructor().construct(paramsVar, ijVar));
new Statement() {
@Override
protected void doGen(CodeBuilder ga) {
ga.mark(start);
returnTemplate.gen(ga);
ga.mark(end);
thisVar.tableEntry(ga);
paramsVar.tableEntry(ga);
ijVar.tableEntry(ga);
}
}.writeMethod(Opcodes.ACC_PUBLIC, CREATE_METHOD, cv);
}
use of com.google.template.soy.jbcsrc.restricted.LocalVariable in project closure-templates by google.
the class TemplateVariableManager method enterScope.
/**
* Enters a new scope. Variables may only be defined within a scope.
*/
Scope enterScope() {
final Map<VarKey, Variable> currentFrame = new LinkedHashMap<>();
final Label scopeExit = new Label();
frames.push(currentFrame);
return new Scope() {
boolean exited;
@Override
Variable createSynthetic(SyntheticVarName varName, Expression initExpr, SaveStrategy strategy) {
checkState(!exited, "Scope already exited");
VarKey key = VarKey.create(Kind.SYNTHETIC, varName.name());
// synthetics are prefixed by $ by convention
String name = fieldNames.generateName("$" + varName.name());
return doCreate(name, new Label(), scopeExit, initExpr, key, strategy);
}
@Override
Variable createTemporary(String name, Expression initExpr) {
checkState(!exited, "Scope already exited");
VarKey key = VarKey.create(Kind.TEMPORARY, name);
name = fieldNames.generateName("$$" + name);
return doCreate(name, new Label(), scopeExit, initExpr, key, SaveStrategy.NEVER);
}
@Override
Variable create(String name, Expression initExpr, SaveStrategy strategy) {
checkState(!exited, "Scope already exited");
VarKey key = VarKey.create(Kind.USER_DEFINED, name);
name = fieldNames.generateName(name);
return doCreate(name, new Label(), scopeExit, initExpr, key, strategy);
}
@Override
Statement exitScope() {
checkState(!exited, "Scope already exited");
exited = true;
frames.pop();
// Use identity semantics to make sure we visit each label at most once. visiting a label
// more than once tends to corrupt internal asm state.
final Set<Label> endLabels = Sets.newIdentityHashSet();
for (Variable var : currentFrame.values()) {
endLabels.add(var.local.end());
availableSlots.clear(var.local.index(), var.local.index() + var.local.resultType().getSize());
}
return new Statement() {
// TODO(lukes): we could generate null writes for when object typed fields go out of
// scope. This would potentially allow intermediate results to be collected sooner.
@Override
protected void doGen(CodeBuilder adapter) {
for (Label label : endLabels) {
adapter.visitLabel(label);
}
}
};
}
private Variable doCreate(String name, Label start, Label end, Expression initExpr, VarKey key, SaveStrategy strategy) {
int index = reserveSlotFor(initExpr.resultType());
LocalVariable local = LocalVariable.createLocal(name, index, initExpr.resultType(), start, end);
Variable var;
switch(strategy) {
case DERIVED:
var = new DerivedVariable(initExpr, local);
break;
case NEVER:
var = new TemporaryVariable(initExpr, local);
break;
case STORE:
var = new FieldSavedVariable(initExpr, local);
break;
default:
throw new AssertionError();
}
currentFrame.put(key, var);
allVariables.add(var);
return var;
}
};
}
Aggregations