List of usage examples for org.objectweb.asm Label Label
public Label()
From source file:com.google.template.soy.jbcsrc.BytecodeUtils.java
License:Apache License
/** * Returns an expression that evaluates to {@code left} if left is non null, and evaluates to * {@code right} otherwise. /* ww w . j a v a 2 s.c o m*/ */ static Expression firstNonNull(final Expression left, final Expression right) { checkArgument(left.resultType().getSort() == Type.OBJECT); checkArgument(right.resultType().getSort() == Type.OBJECT); Features features = Features.of(); if (Expression.areAllCheap(left, right)) { features = features.plus(Feature.CHEAP); } if (right.isNonNullable()) { features = features.plus(Feature.NON_NULLABLE); } return new Expression(left.resultType(), features) { @Override void doGen(CodeBuilder cb) { Label leftIsNonNull = new Label(); left.gen(cb); // Stack: L cb.dup(); // Stack: L, L cb.ifNonNull(leftIsNonNull); // Stack: L // pop the extra copy of left cb.pop(); // Stack: right.gen(cb); // Stack: R cb.mark(leftIsNonNull); // At this point the stack has an instance of L or R } }; }
From source file:com.google.template.soy.jbcsrc.BytecodeUtils.java
License:Apache License
/** * Returns an expression that evaluates equivalently to a java ternary expression: * {@code condition ? left : right}/*w w w. ja v a 2 s. com*/ */ static Expression ternary(final Expression condition, final Expression trueBranch, final Expression falseBranch) { checkArgument(condition.resultType().equals(Type.BOOLEAN_TYPE)); checkArgument(trueBranch.resultType().getSort() == falseBranch.resultType().getSort()); Features features = Features.of(); if (Expression.areAllCheap(condition, trueBranch, falseBranch)) { features = features.plus(Feature.CHEAP); } if (trueBranch.isNonNullable() && falseBranch.isNonNullable()) { features = features.plus(Feature.NON_NULLABLE); } return new Expression(trueBranch.resultType(), features) { @Override void doGen(CodeBuilder mv) { condition.gen(mv); Label ifFalse = new Label(); Label end = new Label(); mv.visitJumpInsn(Opcodes.IFEQ, ifFalse); // if 0 goto ifFalse trueBranch.gen(mv); // eval true branch mv.visitJumpInsn(Opcodes.GOTO, end); // jump to the end mv.visitLabel(ifFalse); falseBranch.gen(mv); // eval false branch mv.visitLabel(end); } }; }
From source file:com.google.template.soy.jbcsrc.BytecodeUtils.java
License:Apache License
private static Expression doShortCircuitingLogicalOperator( final ImmutableList<? extends Expression> expressions, final boolean isOrOperator) { checkArgument(!expressions.isEmpty()); for (Expression expr : expressions) { expr.checkAssignableTo(Type.BOOLEAN_TYPE); }/* w w w .ja va2 s.c om*/ if (expressions.size() == 1) { return expressions.get(0); } return new Expression(Type.BOOLEAN_TYPE, Expression.areAllCheap(expressions) ? Features.of(Feature.CHEAP) : Features.of()) { @Override void doGen(CodeBuilder adapter) { Label end = new Label(); Label shortCircuit = new Label(); for (int i = 0; i < expressions.size(); i++) { Expression expr = expressions.get(i); expr.gen(adapter); if (i == expressions.size() - 1) { // if we are the last one, just goto end. Whatever the result of the last expression is // determines the result of the whole expression (when all prior tests fail). adapter.goTo(end); } else { adapter.ifZCmp(isOrOperator ? Opcodes.IFNE : Opcodes.IFEQ, shortCircuit); } } adapter.mark(shortCircuit); adapter.pushBoolean(isOrOperator); // default for || is true && is false adapter.mark(end); } }; }
From source file:com.google.template.soy.jbcsrc.ControlFlow.java
License:Apache License
/** * Returns a statement that encodes the given sequence of {@link IfBlock if blocks} as an * if-elseif-else chain.// www . ja v a 2s. c o m */ static Statement ifElseChain(final List<IfBlock> ifs, final Optional<Statement> elseBlock) { checkArgument(!ifs.isEmpty()); return new Statement() { @Override void doGen(CodeBuilder adapter) { Label end = new Label(); Label next; for (int i = 0; i < ifs.size(); i++) { IfBlock curr = ifs.get(i); boolean isLastIfBlock = i == ifs.size() - 1; if (isLastIfBlock && !elseBlock.isPresent()) { next = end; } else { next = new Label(); } curr.condition().gen(adapter); adapter.ifZCmp(Opcodes.IFEQ, next); curr.block().gen(adapter); if (end != next) { adapter.goTo(end); } adapter.mark(next); } if (elseBlock.isPresent()) { elseBlock.get().gen(adapter); adapter.mark(end); } } }; }
From source file:com.google.template.soy.jbcsrc.DetachState.java
License:Apache License
/** * Returns a Statement that will conditionally detach if the given {@link AdvisingAppendable} has * been {@link AdvisingAppendable#softLimitReached() output limited}. *//* ww w. j a v a 2 s . c om*/ 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 void doGen(CodeBuilder adapter) { isSoftLimited.gen(adapter); adapter.ifZCmp(Opcodes.IFEQ, reattachPoint); // if !softLimited // ok we were limited, save state and return saveRestoreState.save().gen(adapter); // save locals saveState.gen(adapter); // save the state field 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); } }; }
From source file:com.google.template.soy.jbcsrc.DetachState.java
License:Apache License
/** * Generate detach logic for calls.//from ww w . j ava 2s. c om * * <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 void doGen(CodeBuilder adapter) { // Legend: RR = RenderResult, Z = boolean callRender.gen(adapter); // Stack: RR adapter.dup(); // Stack: RR, RR MethodRef.RENDER_RESULT_IS_DONE.invokeUnchecked(adapter); // Stack: RR, Z // if isDone goto Done Label end = new Label(); adapter.ifZCmp(Opcodes.IFNE, end); // Stack: RR saveRestoreState.save().gen(adapter); saveState.gen(adapter); adapter.returnValue(); adapter.mark(reattachRender); callRender.gen(adapter); // Stack: RR adapter.dup(); // Stack: RR, RR MethodRef.RENDER_RESULT_IS_DONE.invokeUnchecked(adapter); // Stack: RR, Z // if isDone goto restore Label restore = new Label(); adapter.ifZCmp(Opcodes.IFNE, restore); // Stack: RR // no need to save or restore anything adapter.returnValue(); adapter.mark(restore); // Stack: RR saveRestoreState.restore().gen(adapter); adapter.mark(end); // Stack: RR adapter.pop(); // Stack: } }; }
From source file:com.google.template.soy.jbcsrc.ExpressionCompiler.java
License:Apache License
/** * Compiles the given expression tree to a sequence of bytecode in the current method visitor. * * <p>The generated bytecode expects that the evaluation stack is empty when this method is * called and it will generate code such that the stack contains a single SoyValue when it * returns. The SoyValue object will have a runtime type equal to * {@code node.getType().javaType()}.// w w w . ja v a 2 s . com */ SoyExpression compile(ExprNode node) { Label reattachPoint = new Label(); final SoyExpression exec = compile(node, reattachPoint); return exec.withSource(exec.labelStart(reattachPoint)); }
From source file:com.google.template.soy.jbcsrc.ExpressionTester.java
License:Apache License
private static ClassData createClass(Class<? extends Invoker> targetInterface, Expression expr) { java.lang.reflect.Method invokeMethod; try {/* w w w . java 2 s .com*/ invokeMethod = targetInterface.getMethod("invoke"); } catch (NoSuchMethodException | SecurityException e) { throw new RuntimeException(e); } Class<?> returnType = invokeMethod.getReturnType(); if (!Type.getType(returnType).equals(expr.resultType())) { if (!returnType.equals(Object.class) || expr.resultType().getSort() != Type.OBJECT) { throw new IllegalArgumentException(targetInterface + " is not appropriate for this expression"); } } TypeInfo generatedType = TypeInfo.create( ExpressionTester.class.getPackage().getName() + "." + targetInterface.getSimpleName() + "Impl"); SoyClassWriter cw = SoyClassWriter.builder(generatedType) .setAccess(Opcodes.ACC_FINAL | Opcodes.ACC_SUPER | Opcodes.ACC_PUBLIC) .implementing(TypeInfo.create(targetInterface)).build(); BytecodeUtils.defineDefaultConstructor(cw, generatedType); Method invoke = Method.getMethod(invokeMethod); Statement.returnExpression(expr).writeMethod(Opcodes.ACC_PUBLIC, invoke, cw); Method voidInvoke; try { voidInvoke = Method.getMethod(Invoker.class.getMethod("voidInvoke")); } catch (NoSuchMethodException | SecurityException e) { throw new RuntimeException(e); // this method definitely exists } Statement.concat(LocalVariable.createThisVar(generatedType, new Label(), new Label()) .invoke(MethodRef.create(invokeMethod)).toStatement(), new Statement() { @Override void doGen(CodeBuilder adapter) { adapter.visitInsn(Opcodes.RETURN); } }).writeMethod(Opcodes.ACC_PUBLIC, voidInvoke, cw); ClassData data = cw.toClassData(); checkClassData(data); return data; }
From source file:com.google.template.soy.jbcsrc.MsgCompiler.java
License:Apache License
private void putSelectPartIntoMap(Expression mapExpression, MsgNode originalMsg, Map<String, Statement> placeholderNameToPutStatement, SoyMsgSelectPart select) { MsgSelectNode repSelectNode = originalMsg.getRepSelectNode(select.getSelectVarName()); if (!placeholderNameToPutStatement.containsKey(select.getSelectVarName())) { Label reattachPoint = new Label(); Expression value = soyNodeCompiler.compileToString(repSelectNode.getExpr(), reattachPoint); placeholderNameToPutStatement.put(select.getSelectVarName(), putToMap(mapExpression, select.getSelectVarName(), value).labelStart(reattachPoint)); }//from w w w. j a v a2s .co m // Recursively visit select cases for (Case<String> caseOrDefault : select.getCases()) { putPlaceholdersIntoMap(mapExpression, originalMsg, caseOrDefault.parts(), placeholderNameToPutStatement); } }
From source file:com.google.template.soy.jbcsrc.MsgCompiler.java
License:Apache License
private void putPluralPartIntoMap(Expression mapExpression, MsgNode originalMsg, Map<String, Statement> placeholderNameToPutStatement, SoyMsgPluralPart plural) { MsgPluralNode repPluralNode = originalMsg.getRepPluralNode(plural.getPluralVarName()); if (!placeholderNameToPutStatement.containsKey(plural.getPluralVarName())) { Label reattachPoint = new Label(); Expression value = soyNodeCompiler.compileToInt(repPluralNode.getExpr(), reattachPoint); placeholderNameToPutStatement.put(plural.getPluralVarName(), putToMap(mapExpression, plural.getPluralVarName(), value).labelStart(reattachPoint)); }//ww w .j a v a 2s . com // Recursively visit plural cases for (Case<SoyMsgPluralCaseSpec> caseOrDefault : plural.getCases()) { putPlaceholdersIntoMap(mapExpression, originalMsg, caseOrDefault.parts(), placeholderNameToPutStatement); } }