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));
}
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);
}
};
}
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();
}
};
}
Aggregations