Search in sources :

Example 6 with CodeBuilder

use of com.google.template.soy.jbcsrc.restricted.CodeBuilder in project closure-templates by google.

the class DetachState method detachForRender.

/**
 * Generate detach logic for calls.
 *
 * <p>Calls are a little different due to a desire to minimize the cost of detaches. We assume
 * that if a given call site detaches once, it is more likely to detach multiple times. So we
 * generate code that looks like:
 *
 * <pre>{@code
 * RenderResult initialResult = template.render(appendable, renderContext);
 * if (!initialResult.isDone()) {
 *   // save all fields
 *   state = REATTACH_RENDER;
 *   return initialResult;
 * } else {
 *   goto END;
 * }
 * REATTACH_RENDER:
 * // restore nothing!
 * RenderResult secondResult = template.render(appendable, renderContext);
 * if (!secondResult.isDone()) {
 *   // saveFields
 *   state = REATTACH_RENDER;
 *   return secondResult;
 * } else {
 *   // restore all fields
 *   goto END;
 * }
 * END:
 * }</pre>
 *
 * <p>With this technique we save re-running the save-restore logic for multiple detaches from the
 * same call site. This should be especially useful for top level templates.
 *
 * @param callRender an Expression that can generate code to call the render method, should be
 *     safe to generate more than once.
 */
Statement detachForRender(final Expression callRender) {
    checkArgument(callRender.resultType().equals(RENDER_RESULT_TYPE));
    final Label reattachRender = new Label();
    final SaveRestoreState saveRestoreState = variables.saveRestoreState();
    // We pass NULL statement for the restore logic since we handle that ourselves below
    int state = addState(reattachRender, Statement.NULL_STATEMENT);
    final Statement saveState = stateField.putInstanceField(thisExpr, BytecodeUtils.constant(state));
    return new Statement() {

        @Override
        protected void doGen(CodeBuilder adapter) {
            // Legend: RR = RenderResult, Z = boolean
            // Stack: RR
            callRender.gen(adapter);
            // Stack: RR, RR
            adapter.dup();
            // Stack: RR, Z
            MethodRef.RENDER_RESULT_IS_DONE.invokeUnchecked(adapter);
            // if isDone goto Done
            Label end = new Label();
            // Stack: RR
            adapter.ifZCmp(Opcodes.IFNE, end);
            saveRestoreState.save().gen(adapter);
            saveState.gen(adapter);
            adapter.returnValue();
            adapter.mark(reattachRender);
            // Stack: RR
            callRender.gen(adapter);
            // Stack: RR, RR
            adapter.dup();
            // Stack: RR, Z
            MethodRef.RENDER_RESULT_IS_DONE.invokeUnchecked(adapter);
            // if isDone goto restore
            Label restore = new Label();
            // Stack: RR
            adapter.ifZCmp(Opcodes.IFNE, restore);
            // no need to save or restore anything
            adapter.returnValue();
            // Stack: RR
            adapter.mark(restore);
            saveRestoreState.restore().gen(adapter);
            // Stack: RR
            adapter.mark(end);
            // Stack:
            adapter.pop();
        }
    };
}
Also used : SaveRestoreState(com.google.template.soy.jbcsrc.TemplateVariableManager.SaveRestoreState) Statement(com.google.template.soy.jbcsrc.restricted.Statement) Label(org.objectweb.asm.Label) CodeBuilder(com.google.template.soy.jbcsrc.restricted.CodeBuilder)

Example 7 with CodeBuilder

use of com.google.template.soy.jbcsrc.restricted.CodeBuilder in project closure-templates by google.

the class TemplateVariableManager method defineFields.

// TODO(lukes): consider moving all these optional 'one per template' fields to a different object
// for management.
/**
 * Defines all the fields necessary for the registered variables.
 *
 * @return a statement to initialize the fields
 */
@CheckReturnValue
Statement defineFields(ClassVisitor writer) {
    List<Statement> initializers = new ArrayList<>();
    for (Variable var : allVariables) {
        var.maybeDefineField(writer);
    }
    if (currentCalleeField != null) {
        currentCalleeField.defineField(writer);
    }
    if (currentRendereeField != null) {
        currentRendereeField.defineField(writer);
    }
    if (currentAppendable != null) {
        currentAppendable.defineField(writer);
    }
    if (tempBufferField != null) {
        tempBufferField.defineField(writer);
        // If a template needs a temp buffer then we initialize it eagerly in the template constructor
        // this may be wasteful in the case that the buffer is only used on certain call paths, but
        // if it turns out to be expensive, this could always be solved by an author by refactoring
        // their templates (e.g. extract the conditional logic into another template)
        final Expression newStringBuilder = MethodRef.LOGGING_ADVISING_APPENDABLE_BUFFERING.invoke();
        initializers.add(new Statement() {

            @Override
            protected void doGen(CodeBuilder adapter) {
                adapter.loadThis();
                newStringBuilder.gen(adapter);
                tempBufferField.putUnchecked(adapter);
            }
        });
    }
    if (msgPlaceholderMapField != null) {
        msgPlaceholderMapField.defineField(writer);
        // same comment as above about eager initialization.
        final Expression newHashMap = ConstructorRef.LINKED_HASH_MAP_SIZE.construct(constant(msgPlaceholderMapInitialSize));
        initializers.add(new Statement() {

            @Override
            protected void doGen(CodeBuilder adapter) {
                adapter.loadThis();
                newHashMap.gen(adapter);
                msgPlaceholderMapField.putUnchecked(adapter);
            }
        });
    }
    return Statement.concat(initializers);
}
Also used : LocalVariable(com.google.template.soy.jbcsrc.restricted.LocalVariable) Expression(com.google.template.soy.jbcsrc.restricted.Expression) Statement(com.google.template.soy.jbcsrc.restricted.Statement) ArrayList(java.util.ArrayList) CodeBuilder(com.google.template.soy.jbcsrc.restricted.CodeBuilder) CheckReturnValue(javax.annotation.CheckReturnValue)

Example 8 with CodeBuilder

use of com.google.template.soy.jbcsrc.restricted.CodeBuilder 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);
    }
}
Also used : Variable(com.google.template.soy.jbcsrc.TemplateVariableManager.Variable) LocalVariable(com.google.template.soy.jbcsrc.restricted.LocalVariable) Scope(com.google.template.soy.jbcsrc.TemplateVariableManager.Scope) SoyExpression(com.google.template.soy.jbcsrc.restricted.SoyExpression) Expression(com.google.template.soy.jbcsrc.restricted.Expression) Statement(com.google.template.soy.jbcsrc.restricted.Statement) AppendableAndOptions(com.google.template.soy.jbcsrc.restricted.SoyJbcSrcPrintDirective.Streamable.AppendableAndOptions) LocalVariable(com.google.template.soy.jbcsrc.restricted.LocalVariable) ArrayList(java.util.ArrayList) CodeBuilder(com.google.template.soy.jbcsrc.restricted.CodeBuilder)

Example 9 with CodeBuilder

use of com.google.template.soy.jbcsrc.restricted.CodeBuilder 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);
}
Also used : Expression(com.google.template.soy.jbcsrc.restricted.Expression) Statement(com.google.template.soy.jbcsrc.restricted.Statement) Label(org.objectweb.asm.Label) LocalVariable(com.google.template.soy.jbcsrc.restricted.LocalVariable) ArrayList(java.util.ArrayList) TemplateParam(com.google.template.soy.soytree.defn.TemplateParam) CodeBuilder(com.google.template.soy.jbcsrc.restricted.CodeBuilder)

Example 10 with CodeBuilder

use of com.google.template.soy.jbcsrc.restricted.CodeBuilder 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);
}
Also used : TemplateNode(com.google.template.soy.soytree.TemplateNode) Statement(com.google.template.soy.jbcsrc.restricted.Statement) Label(org.objectweb.asm.Label) LocalVariable(com.google.template.soy.jbcsrc.restricted.LocalVariable) CompiledMethodBody(com.google.template.soy.jbcsrc.SoyNodeCompiler.CompiledMethodBody) CodeBuilder(com.google.template.soy.jbcsrc.restricted.CodeBuilder)

Aggregations

CodeBuilder (com.google.template.soy.jbcsrc.restricted.CodeBuilder)13 Statement (com.google.template.soy.jbcsrc.restricted.Statement)13 Label (org.objectweb.asm.Label)11 Expression (com.google.template.soy.jbcsrc.restricted.Expression)8 LocalVariable (com.google.template.soy.jbcsrc.restricted.LocalVariable)6 ArrayList (java.util.ArrayList)4 SoyExpression (com.google.template.soy.jbcsrc.restricted.SoyExpression)3 SaveRestoreState (com.google.template.soy.jbcsrc.TemplateVariableManager.SaveRestoreState)2 Scope (com.google.template.soy.jbcsrc.TemplateVariableManager.Scope)2 Variable (com.google.template.soy.jbcsrc.TemplateVariableManager.Variable)2 Statement.returnExpression (com.google.template.soy.jbcsrc.restricted.Statement.returnExpression)2 CompiledMethodBody (com.google.template.soy.jbcsrc.SoyNodeCompiler.CompiledMethodBody)1 ClassData (com.google.template.soy.jbcsrc.internal.ClassData)1 SoyClassWriter (com.google.template.soy.jbcsrc.internal.SoyClassWriter)1 AppendableAndOptions (com.google.template.soy.jbcsrc.restricted.SoyJbcSrcPrintDirective.Streamable.AppendableAndOptions)1 TypeInfo (com.google.template.soy.jbcsrc.restricted.TypeInfo)1 RangeArgs (com.google.template.soy.shared.RangeArgs)1 ForNonemptyNode (com.google.template.soy.soytree.ForNonemptyNode)1 TemplateNode (com.google.template.soy.soytree.TemplateNode)1 TemplateParam (com.google.template.soy.soytree.defn.TemplateParam)1