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