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}