com.google.devtools.build.lib.syntax.compiler.Jump.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.build.lib.syntax.compiler.Jump.java

Source

// 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.
     *
     * <p>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;
    }
}