    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     * @param cp Constant pool
    032     * @param value to be pushed
    033     */
    034    public PUSH(final ConstantPoolGen cp, final boolean value) {
    035        Objects.requireNonNull(cp, "cp");
    036        instruction = InstructionConst.getInstruction(Const.ICONST_0 + (value ? 1 : 0));
    037    }
    038
    039    /**
    040     * @param cp Constant pool
    041     * @param value to be pushed
    042     */
    043    public PUSH(final ConstantPoolGen cp, final Boolean value) {
    044        this(cp, value.booleanValue());
    045    }
    046
    047    /**
    048     * creates a push object from a Character value. Warning: Make sure not to attempt to allow autoboxing to create this
    049     * value parameter, as an alternative constructor will be called
    050     *
    051     * @param cp Constant pool
    052     * @param value to be pushed
    053     */
    054    public PUSH(final ConstantPoolGen cp, final Character value) {
    055        this(cp, value.charValue());
    056    }
    057
    058    /**
    059     * @param cp Constant pool
    060     * @param value to be pushed
    061     */
    062    public PUSH(final ConstantPoolGen cp, final double value) {
    063        if (value == 0.0) {
    064            instruction = InstructionConst.DCONST_0;
    065        } else if (value == 1.0) {
    066            instruction = InstructionConst.DCONST_1;
    067        } else {
    068            instruction = new LDC2_W(cp.addDouble(value));
    069        }
    070    }
    071
    072    /**
    073     * @param cp Constant pool
    074     * @param value to be pushed
    075     */
    076    public PUSH(final ConstantPoolGen cp, final float value) {
    077        if (value == 0.0) {
    078            instruction = InstructionConst.FCONST_0;
    079        } else if (value == 1.0) {
    080            instruction = InstructionConst.FCONST_1;
    081        } else if (value == 2.0) {
    082            instruction = InstructionConst.FCONST_2;
    083        } else {
    084            instruction = new LDC(cp.addFloat(value));
    085        }
    086    }
    087
    088    /**
    089     * This constructor also applies for values of type short, char, byte
    090     *
    091     * @param cp Constant pool
    092     * @param value to be pushed
    093     */
    094    public PUSH(final ConstantPoolGen cp, final int value) {
    095        if (value >= -1 && value <= 5) {
    096            instruction = InstructionConst.getInstruction(Const.ICONST_0 + value);
    097        } else if (Instruction.isValidByte(value)) {
    098            instruction = new BIPUSH((byte) value);
    099        } else if (Instruction.isValidShort(value)) {
    100            instruction = new SIPUSH((short) value);
    101        } else {
    102            instruction = new LDC(cp.addInteger(value));
    103        }
    104    }
    105
    106    /**
    107     * @param cp Constant pool
    108     * @param value to be pushed
    109     */
    110    public PUSH(final ConstantPoolGen cp, final long value) {
    111        if (value == 0) {
    112            instruction = InstructionConst.LCONST_0;
    113        } else if (value == 1) {
    114            instruction = InstructionConst.LCONST_1;
    115        } else {
    116            instruction = new LDC2_W(cp.addLong(value));
    117        }
    118    }
    119
    120    /**
    121     * @param cp Constant pool
    122     * @param value to be pushed
    123     */
    124    public PUSH(final ConstantPoolGen cp, final Number value) {
    125        if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
    126            instruction = new PUSH(cp, value.intValue()).instruction;
    127        } else if (value instanceof Double) {
    128            instruction = new PUSH(cp, value.doubleValue()).instruction;
    129        } else if (value instanceof Float) {
    130            instruction = new PUSH(cp, value.floatValue()).instruction;
    131        } else if (value instanceof Long) {
    132            instruction = new PUSH(cp, value.longValue()).instruction;
    133        } else {
    134            throw new ClassGenException("What's this: " + value);
    135        }
    136    }
    137
    138    /**
    139     *
    140     * @param cp
    141     * @param value
    142     * @since 6.0
    143     */
    144    public PUSH(final ConstantPoolGen cp, final ObjectType value) {
    145        if (value == null) {
    146            instruction = InstructionConst.ACONST_NULL;
    147        } else {
    148            instruction = new LDC(cp.addClass(value));
    149        }
    150    }
    151
    152    /**
    153     * @param cp Constant pool
    154     * @param value to be pushed
    155     */
    156    public PUSH(final ConstantPoolGen cp, final String value) {
    157        if (value == null) {
    158            instruction = InstructionConst.ACONST_NULL;
    159        } else {
    160            instruction = new LDC(cp.addString(value));
    161        }
    162    }
    163
    164    public Instruction getInstruction() {
    165        return instruction;
    166    }
    167
    168    @Override
    169    public InstructionList getInstructionList() {
    170        return new InstructionList(instruction);
    171    }
    172
    173    /**
    174     * @return mnemonic for instruction
    175     */
    176    @Override
    177    public String toString() {
    178        return instruction + " (PUSH)";
    179    }
    180}