List of usage examples for org.objectweb.asm Label Label
public Label()
From source file:com.google.template.soy.jbcsrc.restricted.SoyExpression.java
License:Apache License
/** Returns a SoyExpression that evaluates to a subtype of {@link SoyValue}. */ public SoyExpression box() { if (isBoxed()) { return this; }/*from www. j a va 2 s . c o m*/ if (soyType().equals(NullType.getInstance())) { if (delegate == NULL) { return NULL_BOXED; } return asBoxed(toStatement().then(NULL_BOXED)); } // since we aren't boxed and these must be primitives so we don't need to worry about // nullability if (soyRuntimeType.isKnownBool()) { return asBoxed(MethodRef.BOOLEAN_DATA_FOR_VALUE.invoke(delegate)); } if (soyRuntimeType.isKnownInt()) { return asBoxed(MethodRef.INTEGER_DATA_FOR_VALUE.invoke(delegate)); } if (soyRuntimeType.isKnownFloat()) { return asBoxed(MethodRef.FLOAT_DATA_FOR_VALUE.invoke(delegate)); } // If null is expected and it is a reference type we want to propagate null through the boxing // operation final boolean isNonNullable = delegate.isNonNullable(); return asBoxed(new Expression(soyRuntimeType.box().runtimeType(), features()) { @Override protected void doGen(CodeBuilder adapter) { Label end = null; delegate.gen(adapter); if (!isNonNullable) { end = new Label(); BytecodeUtils.nullCoalesce(adapter, end); } doBox(adapter, soyRuntimeType.asNonNullable()); if (end != null) { adapter.mark(end); } } }); }
From source file:com.google.template.soy.jbcsrc.restricted.SoyExpression.java
License:Apache License
/** Coerce this expression to a boolean value. */ public SoyExpression coerceToBoolean() { // First deal with primitives which don't have to care about null. if (BytecodeUtils.isPrimitive(resultType())) { return coercePrimitiveToBoolean(); }/*from w w w .jav a 2 s . c o m*/ if (soyType().equals(NullType.getInstance())) { return FALSE; } if (delegate.isNonNullable()) { return coerceNonNullableReferenceTypeToBoolean(); } else { // If we are potentially nullable, then map null to false and run the normal logic recursively // for the non-nullable branch. final Label end = new Label(); return withSource(new Expression(delegate.resultType(), delegate.features()) { @Override protected void doGen(CodeBuilder adapter) { delegate.gen(adapter); adapter.dup(); Label nonNull = new Label(); adapter.ifNonNull(nonNull); adapter.pop(); adapter.pushBoolean(false); adapter.goTo(end); adapter.mark(nonNull); } }).asNonNullable().coerceToBoolean().labelEnd(end); } }
From source file:com.google.template.soy.jbcsrc.restricted.SoyExpression.java
License:Apache License
/** * Unboxes this to a {@link SoyExpression} with a runtime type of {@code asType}. * * <p>This method is appropriate when you know (likely via inspection of the {@link #soyType()}, * or other means) that the value does have the appropriate type but you prefer to interact with * it as its unboxed representation. If you simply want to 'coerce' the given value to a new type * consider {@link #coerceToBoolean()} {@link #coerceToDouble()} or {@link #coerceToString()} * which are designed for that use case. *//*from w w w . j a v a2s . co m*/ public SoyExpression unboxAs(Class<?> asType) { checkArgument(!SoyValue.class.isAssignableFrom(asType), "Cannot use unboxAs() to convert to a SoyValue: %s, use .box() instead", asType); // No-op conversion, always allow. // SoyExpressions that are already unboxed fall into this case. if (BytecodeUtils.isDefinitelyAssignableFrom(Type.getType(asType), soyRuntimeType.runtimeType())) { return this; } // Attempting to unbox an unboxed proto if (asType.equals(Message.class) && soyRuntimeType.isKnownProtoOrUnionOfProtos() && !isBoxed()) { return this; } if (!isBoxed()) { throw new IllegalStateException("Trying to unbox an unboxed value (" + soyRuntimeType + ") into " + asType + " doesn't make sense. Should you be using a type coercion? e.g. coerceToBoolean()"); } if (asType.equals(boolean.class)) { return forBool(delegate.invoke(MethodRef.SOY_VALUE_BOOLEAN_VALUE)); } if (asType.equals(long.class)) { return forInt(delegate.invoke(MethodRef.SOY_VALUE_LONG_VALUE)); } if (asType.equals(double.class)) { return forFloat(delegate.invoke(MethodRef.SOY_VALUE_FLOAT_VALUE)); } if (delegate.isNonNullable()) { if (asType.equals(String.class)) { Expression unboxedString = delegate.invoke(MethodRef.SOY_VALUE_STRING_VALUE); // We need to ensure that santized types don't lose their content kinds return soyRuntimeType.isKnownSanitizedContent() ? forSanitizedString(unboxedString, ((SanitizedType) soyType()).getContentKind()) : forString(unboxedString); } if (asType.equals(List.class)) { return unboxAsList(); } if (asType.equals(Message.class)) { SoyRuntimeType runtimeType = getUnboxedType(soyType()); return forProto(runtimeType, delegate.invoke(MethodRef.SOY_PROTO_VALUE_GET_PROTO) .checkedCast(runtimeType.runtimeType())); } } else { // else it must be a List/Proto/String all of which must preserve null through the unboxing // operation // TODO(lukes): this violates the expression contract since we jump to a label outside the // scope of the expression final Label end = new Label(); Expression nonNullDelegate = new Expression(resultType(), features()) { @Override protected void doGen(CodeBuilder adapter) { delegate.gen(adapter); BytecodeUtils.nullCoalesce(adapter, end); } }; return withSource(nonNullDelegate).asNonNullable().unboxAs(asType).asNullable().labelEnd(end); } throw new UnsupportedOperationException("Can't unbox " + soyRuntimeType + " as " + asType); }
From source file:com.google.template.soy.jbcsrc.restricted.testing.ExpressionEvaluator.java
License:Apache License
public static ClassData createClass(Class<? extends Invoker> targetInterface, Expression expr) { java.lang.reflect.Method invokeMethod; try {/*from w w w . j a v a2 s .c o m*/ 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(Names.CLASS_PREFIX + 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 protected 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.SoyExpression.java
License:Apache License
/** Returns a SoyExpression that evaluates to a subtype of {@link SoyValue}. */ SoyExpression box() {/*from w w w. j ava2 s . c o m*/ if (isBoxed()) { return this; } if (soyType.equals(NullType.getInstance())) { return this; } // If null is expected and it is a reference type we want to propagate null through the boxing // operation if (!delegate.isNonNullable()) { // now prefix with a null check and then box so null is preserved via 'boxing' final Label end = new Label(); return withSource(new Expression(resultType(), features()) { @Override void doGen(CodeBuilder adapter) { delegate.gen(adapter); adapter.dup(); adapter.ifNull(end); } }).asNonNullable().box().asNullable().labelEnd(end); } if (isKnownBool()) { return asBoxed(MethodRef.BOOLEAN_DATA_FOR_VALUE.invoke(delegate)); } if (isKnownInt()) { return asBoxed(MethodRef.INTEGER_DATA_FOR_VALUE.invoke(delegate)); } if (isKnownFloat()) { return asBoxed(MethodRef.FLOAT_DATA_FOR_VALUE.invoke(delegate)); } if (isKnownSanitizedContent()) { return asBoxed(MethodRef.ORDAIN_AS_SAFE.invoke(delegate, FieldRef.enumReference(((SanitizedType) soyType).getContentKind()).accessor())); } if (isKnownString()) { return asBoxed(MethodRef.STRING_DATA_FOR_VALUE.invoke(delegate)); } if (isKnownList()) { return asBoxed(MethodRef.LIST_IMPL_FOR_PROVIDER_LIST.invoke(delegate)); } throw new IllegalStateException( "cannot box soy expression of type " + soyType + " with runtime type " + clazz); }
From source file:com.google.template.soy.jbcsrc.SoyExpression.java
License:Apache License
/** Coerce this expression to a boolean value. */ SoyExpression coerceToBoolean() {//from www . ja va2 s. co m // First deal with primitives which don't have to care about null. if (BytecodeUtils.isPrimitive(resultType())) { return coercePrimitiveToBoolean(); } if (soyType.equals(NullType.getInstance())) { return FALSE; } if (delegate.isNonNullable()) { return coerceNonNullableReferenceTypeToBoolean(); } else { // If we are potentially nullable, then map null to false and run the normal logic recursively // for the non-nullable branch. final Label end = new Label(); return withSource(new Expression(delegate.resultType(), delegate.features()) { @Override void doGen(CodeBuilder adapter) { delegate.gen(adapter); adapter.dup(); Label nonNull = new Label(); adapter.ifNonNull(nonNull); adapter.pop(); adapter.pushBoolean(false); adapter.goTo(end); adapter.mark(nonNull); } }).asNonNullable().coerceToBoolean().labelEnd(end); } }
From source file:com.google.template.soy.jbcsrc.SoyExpression.java
License:Apache License
/** * Unboxes this to a {@link SoyExpression} with a runtime type of {@code asType}. * * <p>This method is appropriate when you know (likely via inspection of the {@link #soyType()}, * or other means) that the value does have the appropriate type but you prefer to interact with * it as its unboxed representation. If you simply want to 'coerce' the given value to a new type * consider {@link #coerceToBoolean()} {@link #coerceToDouble()} or {@link #coerceToString()} * which are designed for that use case. *///from www . j a va2 s .com SoyExpression unboxAs(Class<?> asType) { checkArgument(!SoyValue.class.isAssignableFrom(asType), "Cannot use convert() to convert to a SoyValue: %s, use .box() instead", asType); // no op conversion, always allow. if (asType.equals(clazz)) { return this; } if (!isBoxed()) { throw new IllegalStateException("Trying to unbox an unboxed value (" + clazz + ") doesn't make sense, " + "should you be using a type coercion? e.g. .coerceToBoolean()"); } if (asType.equals(boolean.class)) { return forBool(delegate.invoke(MethodRef.SOY_VALUE_BOOLEAN_VALUE)); } if (asType.equals(long.class)) { return forInt(delegate.invoke(MethodRef.SOY_VALUE_LONG_VALUE)); } if (asType.equals(double.class)) { return forFloat(delegate.invoke(MethodRef.SOY_VALUE_FLOAT_VALUE)); } if (delegate.isNonNullable()) { if (asType.equals(String.class)) { Expression unboxedString = delegate.invoke(MethodRef.SOY_VALUE_STRING_VALUE); // We need to ensure that santized types don't lose their content kinds return isKnownSanitizedContent() ? forSanitizedString(unboxedString, ((SanitizedType) soyType).getContentKind()) : forString(unboxedString); } if (asType.equals(List.class)) { return unboxAsList(); } } else { // else it must be a List/Proto/String all of which must preserve null through the unboxing // operation final Label ifNull = new Label(); Expression nonNullDelegate = new Expression(resultType(), features()) { @Override void doGen(CodeBuilder adapter) { delegate.gen(adapter); adapter.dup(); adapter.ifNull(ifNull); } }; final SoyExpression unboxAs = withSource(nonNullDelegate).asNonNullable().unboxAs(asType); return unboxAs.withSource(new Expression(unboxAs.resultType(), features()) { @Override void doGen(CodeBuilder adapter) { unboxAs.gen(adapter); adapter.mark(ifNull); adapter.checkCast(unboxAs.resultType()); // insert a cast to force type agreement } }); } throw new UnsupportedOperationException("Can't unbox " + clazz + " as " + asType); }
From source file:com.google.template.soy.jbcsrc.SoyNodeCompiler.java
License:Apache License
@Override protected Statement visitSwitchNode(SwitchNode node) { // A few special cases: // 1. only a {default} block. In this case we can skip all the switch logic and temporaries // 2. no children. Just return the empty statement // Note that in both of these cases we do not evalutate (or generate code) for the switch // expression. List<SoyNode> children = node.getChildren(); if (children.isEmpty()) { return Statement.NULL_STATEMENT; }/*from w ww .j a v a 2 s .c o m*/ if (children.size() == 1 && children.get(0) instanceof SwitchDefaultNode) { return visitChildrenInNewScope((SwitchDefaultNode) children.get(0)); } // otherwise we need to evaluate the predicate and generate dispatching logic. SoyExpression expression = exprCompiler.compile(node.getExpr()); Statement init; List<IfBlock> cases = new ArrayList<>(); Optional<Statement> defaultBlock = Optional.absent(); Scope scope = variables.enterScope(); Variable variable = scope.createSynthetic(SyntheticVarName.forSwitch(node), expression, STORE); init = variable.initializer(); expression = expression.withSource(variable.local()); for (SoyNode child : children) { if (child instanceof SwitchCaseNode) { SwitchCaseNode caseNode = (SwitchCaseNode) child; Label reattachPoint = new Label(); List<Expression> comparisons = new ArrayList<>(); for (ExprRootNode caseExpr : caseNode.getExprList()) { comparisons.add(compareSoyEquals(expression, exprCompiler.compile(caseExpr, reattachPoint))); } Expression condition = BytecodeUtils.logicalOr(comparisons).labelStart(reattachPoint); Statement block = visitChildrenInNewScope(caseNode); cases.add(IfBlock.create(condition, block)); } else { SwitchDefaultNode defaultNode = (SwitchDefaultNode) child; defaultBlock = Optional.of(visitChildrenInNewScope(defaultNode)); } } Statement exitScope = scope.exitScope(); // Soy allows arbitrary expressions to appear in {case} statements within a {switch}. // Java/C, by contrast, only allow some constant expressions in cases. // TODO(lukes): in practice the case statements are often constant strings/ints. If everything // is typed to int/string we should consider implementing via the tableswitch/lookupswitch // instruction which would be way way way faster. cglib has some helpers for string switch // generation that we could maybe use return Statement.concat(init, ControlFlow.ifElseChain(cases, defaultBlock), exitScope) .withSourceLocation(node.getSourceLocation()); }
From source file:com.google.template.soy.jbcsrc.SoyNodeCompiler.java
License:Apache License
@Override protected Statement visitForNode(ForNode node) { // Despite appearances, range() is not a soy function, it is essentially a keyword that only // works in for loops, there are 3 forms. // {for $i in range(3)}{$i}{/for} -> 0 1 2 // {for $i in range(2, 5)} ... {/for} -> 2 3 4 // {for $i in range(2, 8, 2)} ... {/for} -> 2 4 6 Scope scope = variables.enterScope(); final CompiledRangeArgs rangeArgs = calculateRangeArgs(node, scope); final Statement loopBody = visitChildrenInNewScope(node); // Note it is important that exitScope is called _after_ the children are visited. // TODO(lukes): this is somewhat error-prone... we could maybe manage it by have the scope // maintain a sequence of statements and then all statements would be added to Scope which would // return a statement for the whole thing at the end... would that be clearer? final Statement exitScope = scope.exitScope(); return new Statement(node.getSourceLocation()) { @Override// ww w .java 2s . c o m void doGen(CodeBuilder adapter) { for (Statement initializer : rangeArgs.initStatements()) { initializer.gen(adapter); } // We need to check for an empty loop by doing an entry test Label loopStart = adapter.mark(); // If current >= limit we are done rangeArgs.currentIndex().gen(adapter); rangeArgs.limit().gen(adapter); Label end = new Label(); adapter.ifCmp(Type.INT_TYPE, Opcodes.IFGE, end); loopBody.gen(adapter); // at the end of the loop we need to increment and jump back. rangeArgs.increment().gen(adapter); adapter.goTo(loopStart); adapter.mark(end); exitScope.gen(adapter); } }; }
From source file:com.google.template.soy.jbcsrc.SoyNodeCompiler.java
License:Apache License
/** * Interprets the given expressions as the arguments of a {@code range(...)} expression in a * {@code for} loop./*from www. j a va2s. c o m*/ */ private CompiledRangeArgs calculateRangeArgs(ForNode forNode, Scope scope) { RangeArgs rangeArgs = forNode.getRangeArgs(); final ImmutableList.Builder<Statement> initStatements = ImmutableList.builder(); final Variable currentIndex; if (rangeArgs.start().isPresent()) { Label startDetachPoint = new Label(); Expression startIndex = MethodRef.INTS_CHECKED_CAST .invoke(exprCompiler.compile(rangeArgs.start().get(), startDetachPoint).unboxAs(long.class)); currentIndex = scope.create(forNode.getVarName(), startIndex, STORE); initStatements.add(currentIndex.initializer().labelStart(startDetachPoint)); } else { currentIndex = scope.create(forNode.getVarName(), constant(0), STORE); initStatements.add(currentIndex.initializer()); } final Statement incrementCurrentIndex; if (rangeArgs.increment().isPresent()) { Label detachPoint = new Label(); Expression increment = MethodRef.INTS_CHECKED_CAST .invoke(exprCompiler.compile(rangeArgs.increment().get(), detachPoint).unboxAs(long.class)); // If the expression is non-trivial, make sure to save it to a field. final Variable incrementVariable = scope.createSynthetic(SyntheticVarName.forLoopIncrement(forNode), increment, increment.isCheap() ? DERIVED : STORE); initStatements.add(incrementVariable.initializer().labelStart(detachPoint)); incrementVariable.local(); incrementCurrentIndex = new Statement() { @Override void doGen(CodeBuilder adapter) { currentIndex.local().gen(adapter); incrementVariable.local().gen(adapter); adapter.visitInsn(Opcodes.IADD); adapter.visitVarInsn(Opcodes.ISTORE, currentIndex.local().index()); } }; } else { incrementCurrentIndex = new Statement() { @Override void doGen(CodeBuilder adapter) { adapter.iinc(currentIndex.local().index(), 1); } }; } Label detachPoint = new Label(); Expression limit = MethodRef.INTS_CHECKED_CAST .invoke(exprCompiler.compile(rangeArgs.limit(), detachPoint).unboxAs(long.class)); // If the expression is non-trivial we should cache it in a local variable Variable variable = scope.createSynthetic(SyntheticVarName.forLoopLimit(forNode), limit, limit.isCheap() ? DERIVED : STORE); initStatements.add(variable.initializer().labelStart(detachPoint)); limit = variable.local(); return new AutoValue_SoyNodeCompiler_CompiledRangeArgs(currentIndex.local(), limit, incrementCurrentIndex, initStatements.build()); }