    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 */
    017package org.apache.bcel.generic;
    018
    019import java.util.Objects;
    020
    021import org.apache.bcel.Const;
    022
    023/**
    024 * Wrapper class for push operations, which are implemented either as BIPUSH, LDC or xCONST_n instructions.
    025 */
    026public final class PUSH implements CompoundInstruction, VariableLengthInstruction, InstructionConstants {
    027
    028    private final Instruction instruction;
    029
    030    /**
    031     * Pushes an array type constant, for example {@code int[].class}, {@code String[].class}, and so on.
    032     *
    033     * @param cp generated constant pool.
    034     * @param value to be pushed.
    035     * @since 6.7.0
    036     */
    037    public PUSH(final ConstantPoolGen cp, final ArrayType value) {
    038        if (value == null) {
    039            instruction = InstructionConst.ACONST_NULL;
    040        } else {
    041            instruction = new LDC(cp.addArrayClass(value));
    042        }
    043    }
    044
    045   /**
    046     * @param cp Constant pool
    047     * @param value to be pushed
    048     */
    049    public PUSH(final ConstantPoolGen cp, final boolean value) {
    050        Objects.requireNonNull(cp, "cp");
    051        instruction = InstructionConst.getInstruction(Const.ICONST_0 + (value ? 1 : 0));
    052    }
    053
    054    /**
    055     * @param cp Constant pool
    056     * @param value to be pushed
    057     */
    058    public PUSH(final ConstantPoolGen cp, final Boolean value) {
    059        this(cp, value.booleanValue());
    060    }
    061
    062    /**
    063     * creates a push object from a Character value. Warning: Make sure not to attempt to allow autoboxing to create this
    064     * value parameter, as an alternative constructor will be called
    065     *
    066     * @param cp Constant pool
    067     * @param value to be pushed
    068     */
    069    public PUSH(final ConstantPoolGen cp, final Character value) {
    070        this(cp, value.charValue());
    071    }
    072
    073    /**
    074     * @param cp Constant pool
    075     * @param value to be pushed
    076     */
    077    public PUSH(final ConstantPoolGen cp, final double value) {
    078        if (value == 0.0) {
    079            instruction = InstructionConst.DCONST_0;
    080        } else if (value == 1.0) {
    081            instruction = InstructionConst.DCONST_1;
    082        } else {
    083            instruction = new LDC2_W(cp.addDouble(value));
    084        }
    085    }
    086
    087    /**
    088     * @param cp Constant pool
    089     * @param value to be pushed
    090     */
    091    public PUSH(final ConstantPoolGen cp, final float value) {
    092        if (value == 0.0) {
    093            instruction = InstructionConst.FCONST_0;
    094        } else if (value == 1.0) {
    095            instruction = InstructionConst.FCONST_1;
    096        } else if (value == 2.0) {
    097            instruction = InstructionConst.FCONST_2;
    098        } else {
    099            instruction = new LDC(cp.addFloat(value));
    100        }
    101    }
    102
    103    /**
    104     * This constructor also applies for values of type short, char, byte
    105     *
    106     * @param cp Constant pool
    107     * @param value to be pushed
    108     */
    109    public PUSH(final ConstantPoolGen cp, final int value) {
    110        if (value >= -1 && value <= 5) {
    111            instruction = InstructionConst.getInstruction(Const.ICONST_0 + value);
    112        } else if (Instruction.isValidByte(value)) {
    113            instruction = new BIPUSH((byte) value);
    114        } else if (Instruction.isValidShort(value)) {
    115            instruction = new SIPUSH((short) value);
    116        } else {
    117            instruction = new LDC(cp.addInteger(value));
    118        }
    119    }
    120
    121    /**
    122     * @param cp Constant pool
    123     * @param value to be pushed
    124     */
    125    public PUSH(final ConstantPoolGen cp, final long value) {
    126        if (value == 0) {
    127            instruction = InstructionConst.LCONST_0;
    128        } else if (value == 1) {
    129            instruction = InstructionConst.LCONST_1;
    130        } else {
    131            instruction = new LDC2_W(cp.addLong(value));
    132        }
    133    }
    134
    135    /**
    136     * @param cp Constant pool
    137     * @param value to be pushed
    138     */
    139    public PUSH(final ConstantPoolGen cp, final Number value) {
    140        if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
    141            instruction = new PUSH(cp, value.intValue()).instruction;
    142        } else if (value instanceof Double) {
    143            instruction = new PUSH(cp, value.doubleValue()).instruction;
    144        } else if (value instanceof Float) {
    145            instruction = new PUSH(cp, value.floatValue()).instruction;
    146        } else if (value instanceof Long) {
    147            instruction = new PUSH(cp, value.longValue()).instruction;
    148        } else {
    149            throw new ClassGenException("What's this: " + value);
    150        }
    151    }
    152
    153    /**
    154     *
    155     * @param cp
    156     * @param value
    157     * @since 6.0
    158     */
    159    public PUSH(final ConstantPoolGen cp, final ObjectType value) {
    160        if (value == null) {
    161            instruction = InstructionConst.ACONST_NULL;
    162        } else {
    163            instruction = new LDC(cp.addClass(value));
    164        }
    165    }
    166
    167    /**
    168     * @param cp Constant pool
    169     * @param value to be pushed
    170     */
    171    public PUSH(final ConstantPoolGen cp, final String value) {
    172        if (value == null) {
    173            instruction = InstructionConst.ACONST_NULL;
    174        } else {
    175            instruction = new LDC(cp.addString(value));
    176        }
    177    }
    178
    179    public Instruction getInstruction() {
    180        return instruction;
    181    }
    182
    183    @Override
    184    public InstructionList getInstructionList() {
    185        return new InstructionList(instruction);
    186    }
    187
    188    /**
    189     * @return mnemonic for instruction
    190     */
    191    @Override
    192    public String toString() {
    193        return instruction + " (PUSH)";
    194    }
    195}