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