// Copyright 2015 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.lib.syntax.compiler; import com.google.devtools.build.lib.syntax.Operator; import net.bytebuddy.implementation.Implementation.Context; import net.bytebuddy.implementation.bytecode.StackManipulation; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * Implements byte code for gotos and conditional jumps. */ public class Jump implements StackManipulation { protected final int opCode; protected final Label target; protected final Size stackSizeChange; private Jump(int opCode, Label target, Size stackSizeChange) { this.opCode = opCode; this.target = target; this.stackSizeChange = stackSizeChange; } @Override public boolean isValid() { return true; } @Override public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitJumpInsn(opCode, target); return stackSizeChange; } @Override public String toString() { return "Jump(" + opCode + ", " + target + ")"; } /** * Builds a conditional jump for two int operands on the stack. */ public static JumpWithoutTarget ifIntOperands(PrimitiveComparison comparison) { return new JumpWithoutTarget(Opcodes.IF_ICMPEQ + comparison.ordinal(), new Size(-2, 0)); } /** * Builds a conditional jump for one int operand from the stack compared to zero. */ public static JumpWithoutTarget ifIntOperandToZero(PrimitiveComparison comparison) { return new JumpWithoutTarget(Opcodes.IFEQ + comparison.ordinal(), new Size(-1, 0)); } /** * Builds a conditional jump for two reference type operands from the stack. */ public static JumpWithoutTarget ifReferenceOperands(ReferenceComparison comparison) { return new JumpWithoutTarget(Opcodes.IF_ACMPEQ + comparison.ordinal(), new Size(-2, 0)); } /** * Builds a conditional jump for one reference type operand from the stack compared to null. */ public static JumpWithoutTarget ifReferenceOperandToNull(ReferenceComparison comparison) { return new JumpWithoutTarget(Opcodes.IFNULL + comparison.ordinal(), new Size(-1, 0)); } /** * Builds an unconditional jump to the target label. */ public static Jump to(Label target) { return new Jump(Opcodes.GOTO, target, new Size(0, 0)); } /** * Builds an unconditional jump to the label added by the given {@link LabelAdder}. */ public static Jump to(LabelAdder target) { return to(target.getLabel()); } /** * Builder helper class for partially built jumps from conditionals. * *

Allows adding a jump target label. */ public static final class JumpWithoutTarget { protected final int opCode; protected final Size stackSizeChange; private JumpWithoutTarget(int opCode, Size stackSizeChange) { this.opCode = opCode; this.stackSizeChange = stackSizeChange; } /** * Builds a jump to the given target and the previously initialized conditional. */ public Jump to(LabelAdder target) { return new Jump(opCode, target.getLabel(), stackSizeChange); } } /** * All primitive comparisons for which there are byte code equivalents. */ public enum PrimitiveComparison { EQUAL, NOT_EQUAL, LESS, GREATER_EQUAL, GREATER, LESS_EQUAL; public static PrimitiveComparison forOperator(Operator operator) { switch (operator) { case LESS: return LESS; case LESS_EQUALS: return PrimitiveComparison.LESS_EQUAL; case GREATER: return GREATER; case GREATER_EQUALS: return GREATER_EQUAL; default: throw new Error("unreachable code"); } } } /** * All reference comparisons for which there are byte code equivalents. */ public enum ReferenceComparison { EQUAL, NOT_EQUAL; } }