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}