Search in sources :

Example 1 with SaveRestoreState

use of com.google.template.soy.jbcsrc.TemplateVariableManager.SaveRestoreState in project closure-templates by google.

the class DetachState method createExpressionDetacher.

/**
 * Returns a {@link ExpressionDetacher} that can be used to instrument an expression with detach
 * reattach logic.
 */
@Override
public ExpressionDetacher createExpressionDetacher(Label reattachPoint) {
    SaveRestoreState saveRestoreState = variables.saveRestoreState();
    Statement restore = saveRestoreState.restore();
    int state = addState(reattachPoint, restore);
    Statement saveState = stateField.putInstanceField(thisExpr, BytecodeUtils.constant(state));
    return new ExpressionDetacher.BasicDetacher(Statement.concat(saveRestoreState.save(), saveState));
}
Also used : SaveRestoreState(com.google.template.soy.jbcsrc.TemplateVariableManager.SaveRestoreState) Statement(com.google.template.soy.jbcsrc.restricted.Statement)

Example 2 with SaveRestoreState

use of com.google.template.soy.jbcsrc.TemplateVariableManager.SaveRestoreState in project closure-templates by google.

the class DetachState method detachLimited.

/**
 * Returns a Statement that will conditionally detach if the given {@link AdvisingAppendable} has
 * been {@link AdvisingAppendable#softLimitReached() output limited}.
 */
Statement detachLimited(AppendableExpression appendable) {
    if (!appendable.supportsSoftLimiting()) {
        return appendable.toStatement();
    }
    final Label reattachPoint = new Label();
    final SaveRestoreState saveRestoreState = variables.saveRestoreState();
    Statement restore = saveRestoreState.restore();
    int state = addState(reattachPoint, restore);
    final Expression isSoftLimited = appendable.softLimitReached();
    final Statement returnLimited = returnExpression(MethodRef.RENDER_RESULT_LIMITED.invoke());
    final Statement saveState = stateField.putInstanceField(thisExpr, BytecodeUtils.constant(state));
    return new Statement() {

        @Override
        protected void doGen(CodeBuilder adapter) {
            isSoftLimited.gen(adapter);
            // if !softLimited
            adapter.ifZCmp(Opcodes.IFEQ, reattachPoint);
            // ok we were limited, save state and return
            // save locals
            saveRestoreState.save().gen(adapter);
            // save the state field
            saveState.gen(adapter);
            returnLimited.gen(adapter);
            // Note, the reattach point for 'limited' is _after_ the check.  That means we do not
            // recheck the limit state.  So if a caller calls us back without freeing any buffer we
            // will print more before checking again.  This is fine, because our caller is breaking the
            // contract.
            adapter.mark(reattachPoint);
        }
    };
}
Also used : Expression(com.google.template.soy.jbcsrc.restricted.Expression) Statement.returnExpression(com.google.template.soy.jbcsrc.restricted.Statement.returnExpression) 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 3 with SaveRestoreState

use of com.google.template.soy.jbcsrc.TemplateVariableManager.SaveRestoreState 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)

Aggregations

SaveRestoreState (com.google.template.soy.jbcsrc.TemplateVariableManager.SaveRestoreState)3 Statement (com.google.template.soy.jbcsrc.restricted.Statement)3 CodeBuilder (com.google.template.soy.jbcsrc.restricted.CodeBuilder)2 Label (org.objectweb.asm.Label)2 Expression (com.google.template.soy.jbcsrc.restricted.Expression)1 Statement.returnExpression (com.google.template.soy.jbcsrc.restricted.Statement.returnExpression)1