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.StringTokenizer;
022
023import org.apache.bcel.Const;
024import org.apache.bcel.classfile.Constant;
025import org.apache.bcel.classfile.ConstantCP;
026import org.apache.bcel.classfile.ConstantPool;
027import org.apache.bcel.classfile.Utility;
028
029/**
030 * Superclass for the INVOKExxx family of instructions.
031 */
032public abstract class InvokeInstruction extends FieldOrMethod implements ExceptionThrower, StackConsumer, StackProducer {
033
034    /**
035     * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise.
036     */
037    InvokeInstruction() {
038    }
039
040    /**
041     * Constructs an InvokeInstruction.
042     *
043     * @param opcode The opcode.
044     * @param index to constant pool.
045     */
046    protected InvokeInstruction(final short opcode, final int index) {
047        super(opcode, index);
048    }
049
050    /**
051     * Also works for instructions whose stack effect depends on the constant pool entry they reference.
052     *
053     * @return Number of words consumed from stack by this instruction.
054     */
055    @Override
056    public int consumeStack(final ConstantPoolGen cpg) {
057        int sum;
058        if (super.getOpcode() == Const.INVOKESTATIC || super.getOpcode() == Const.INVOKEDYNAMIC) {
059            sum = 0;
060        } else {
061            sum = 1; // this reference
062        }
063
064        final String signature = getSignature(cpg);
065        sum += Type.getArgumentTypesSize(signature);
066        return sum;
067    }
068
069    /**
070     * Gets the argument types of referenced method.
071     *
072     * @param cpg The constant pool generator.
073     * @return argument types of referenced method.
074     */
075    public Type[] getArgumentTypes(final ConstantPoolGen cpg) {
076        return Type.getArgumentTypes(getSignature(cpg));
077    }
078
079    /**
080     * Gets the name of the referenced class or interface.
081     * <p>
082     * This overrides the deprecated version as we know here that the referenced class may legally be an array.
083     * </p>
084     *
085     * @return name of the referenced class/interface.
086     * @throws IllegalArgumentException Thrown if the referenced class is an array (this should not happen)
087     */
088    @Override
089    public String getClassName(final ConstantPoolGen cpg) {
090        final ConstantPool cp = cpg.getConstantPool();
091        final ConstantCP cmr = (ConstantCP) cp.getConstant(super.getIndex());
092        final String className = cp.getConstantString(cmr.getClassIndex(), Const.CONSTANT_Class);
093        return Utility.pathToPackage(className);
094    }
095
096    /**
097     * Gets the name of referenced method.
098     *
099     * @param cpg The constant pool generator.
100     * @return name of referenced method.
101     */
102    public String getMethodName(final ConstantPoolGen cpg) {
103        return getName(cpg);
104    }
105
106    /**
107     * Gets the return type of referenced method.
108     *
109     * @param cpg The constant pool generator.
110     * @return return type of referenced method.
111     */
112    public Type getReturnType(final ConstantPoolGen cpg) {
113        return Type.getReturnType(getSignature(cpg));
114    }
115
116    /**
117     * Gets the return type of referenced method.
118     *
119     * @param cpg The constant pool generator.
120     * @return return type of referenced method.
121     */
122    @Override
123    public Type getType(final ConstantPoolGen cpg) {
124        return getReturnType(cpg);
125    }
126
127    /**
128     * Also works for instructions whose stack effect depends on the constant pool entry they reference.
129     *
130     * @return Number of words produced onto stack by this instruction.
131     */
132    @Override
133    public int produceStack(final ConstantPoolGen cpg) {
134        final String signature = getSignature(cpg);
135        return Type.getReturnTypeSize(signature);
136    }
137
138    /**
139     * @return mnemonic for instruction with symbolic references resolved.
140     */
141    @Override
142    public String toString(final ConstantPool cp) {
143        final Constant c = cp.getConstant(super.getIndex());
144        final StringTokenizer tok = new StringTokenizer(cp.constantToString(c));
145
146        final String opcodeName = Const.getOpcodeName(super.getOpcode());
147
148        final StringBuilder sb = new StringBuilder(opcodeName);
149        if (tok.hasMoreTokens()) {
150            sb.append(" ");
151            sb.append(Utility.packageToPath(tok.nextToken()));
152            if (tok.hasMoreTokens()) {
153                sb.append(tok.nextToken());
154            }
155        }
156
157        return sb.toString();
158    }
159
160}
161