Search in sources :

Example 11 with Statement

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

the class DetachState method generateReattachTable.

/**
 * Returns a statement that generates the reattach jump table.
 *
 * <p>Note: This statement should be the <em>first</em> statement in any detachable method.
 */
Statement generateReattachTable() {
    final Expression readField = stateField.accessor(thisExpr);
    final Statement defaultCase = Statement.throwExpression(MethodRef.RUNTIME_UNEXPECTED_STATE_ERROR.invoke(readField));
    return new Statement() {

        @Override
        protected void doGen(final CodeBuilder adapter) {
            int[] keys = new int[reattaches.size()];
            for (int i = 0; i < keys.length; i++) {
                keys[i] = i;
            }
            readField.gen(adapter);
            // Generate a switch table.  Note, while it might be preferable to just 'goto state', Java
            // doesn't allow computable gotos (probably because it makes verification impossible).  So
            // instead we emulate that with a jump table.  And anyway we still need to execute 'restore'
            // logic to repopulate the local variable tables, so the 'case' statements are a natural
            // place for that logic to live.
            adapter.tableSwitch(keys, new TableSwitchGenerator() {

                @Override
                public void generateCase(int key, Label end) {
                    if (key == 0) {
                        // State 0 is special, it means initial state, so we just jump to the very end
                        adapter.goTo(end);
                        return;
                    }
                    ReattachState reattachState = reattaches.get(key);
                    // restore and jump!
                    reattachState.restoreStatement().gen(adapter);
                    adapter.goTo(reattachState.reattachPoint());
                }

                @Override
                public void generateDefault() {
                    defaultCase.gen(adapter);
                }
            }, // there are no 'holes' meaning that it is compact in the bytecode.
            true);
        }
    };
}
Also used : Expression(com.google.template.soy.jbcsrc.restricted.Expression) Statement.returnExpression(com.google.template.soy.jbcsrc.restricted.Statement.returnExpression) TableSwitchGenerator(org.objectweb.asm.commons.TableSwitchGenerator) Statement(com.google.template.soy.jbcsrc.restricted.Statement) Label(org.objectweb.asm.Label) CodeBuilder(com.google.template.soy.jbcsrc.restricted.CodeBuilder)

Example 12 with Statement

use of com.google.template.soy.jbcsrc.restricted.Statement 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 13 with Statement

use of com.google.template.soy.jbcsrc.restricted.Statement 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 14 with Statement

use of com.google.template.soy.jbcsrc.restricted.Statement 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 15 with Statement

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

the class MsgCompiler method compileMessage.

/**
 * Compiles the given {@link MsgNode} to a statement with the given escaping directives applied.
 *
 * <p>The returned statement must be written to a location with a stack depth of zero, since
 * placeholder formatting may require detach logic.
 *
 * @param partsAndId The computed msg id
 * @param msg The msg node
 * @param escapingDirectives The set of escaping directives to apply.
 */
Statement compileMessage(MsgPartsAndIds partsAndId, MsgNode msg, ImmutableList<SoyPrintDirective> escapingDirectives) {
    Expression soyMsgDefaultParts = compileDefaultMessagePartsConstant(partsAndId);
    Expression soyMsgParts = parameterLookup.getRenderContext().getSoyMsgParts(partsAndId.id, soyMsgDefaultParts);
    Statement printMsg;
    if (msg.isRawTextMsg()) {
        // Simplest case, just a static string translation
        printMsg = handleBasicTranslation(escapingDirectives, soyMsgParts);
    } else {
        // String translation + placeholders
        printMsg = handleTranslationWithPlaceholders(msg, escapingDirectives, soyMsgParts, parameterLookup.getRenderContext().getULocale(), partsAndId.parts);
    }
    return Statement.concat(printMsg.withSourceLocation(msg.getSourceLocation()), detachState.detachLimited(appendableExpression));
}
Also used : SoyExpression(com.google.template.soy.jbcsrc.restricted.SoyExpression) Expression(com.google.template.soy.jbcsrc.restricted.Expression) Statement(com.google.template.soy.jbcsrc.restricted.Statement)

Aggregations

Statement (com.google.template.soy.jbcsrc.restricted.Statement)30 Expression (com.google.template.soy.jbcsrc.restricted.Expression)15 Label (org.objectweb.asm.Label)14 CodeBuilder (com.google.template.soy.jbcsrc.restricted.CodeBuilder)13 SoyExpression (com.google.template.soy.jbcsrc.restricted.SoyExpression)11 ArrayList (java.util.ArrayList)8 LocalVariable (com.google.template.soy.jbcsrc.restricted.LocalVariable)7 Scope (com.google.template.soy.jbcsrc.TemplateVariableManager.Scope)5 Variable (com.google.template.soy.jbcsrc.TemplateVariableManager.Variable)4 AppendableAndOptions (com.google.template.soy.jbcsrc.restricted.SoyJbcSrcPrintDirective.Streamable.AppendableAndOptions)4 IfBlock (com.google.template.soy.jbcsrc.ControlFlow.IfBlock)3 SaveRestoreState (com.google.template.soy.jbcsrc.TemplateVariableManager.SaveRestoreState)3 FieldRef (com.google.template.soy.jbcsrc.restricted.FieldRef)3 LinkedHashMap (java.util.LinkedHashMap)3 ExprRootNode (com.google.template.soy.exprtree.ExprRootNode)2 ClassData (com.google.template.soy.jbcsrc.internal.ClassData)2 Statement.returnExpression (com.google.template.soy.jbcsrc.restricted.Statement.returnExpression)2 RangeArgs (com.google.template.soy.shared.RangeArgs)2 SoyPrintDirective (com.google.template.soy.shared.restricted.SoyPrintDirective)2 ForNonemptyNode (com.google.template.soy.soytree.ForNonemptyNode)2