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