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;
026
027/**
028 * Super class for the INVOKExxx family of instructions.
029 *
030 * @version $Id: InvokeInstruction.java 1752106 2016-07-10 20:02:39Z britter $
031 */
032public abstract class InvokeInstruction extends FieldOrMethod implements ExceptionThrower,
033        StackConsumer, StackProducer {
034
035    /**
036     * Empty constructor needed for the Class.newInstance() statement in
037     * Instruction.readInstruction(). Not to be used otherwise.
038     */
039    InvokeInstruction() {
040    }
041
042
043    /**
044     * @param index to constant pool
045     */
046    protected InvokeInstruction(final short opcode, final int index) {
047        super(opcode, index);
048    }
049
050
051    /**
052     * @return mnemonic for instruction with symbolic references resolved
053     */
054    @Override
055    public String toString( final ConstantPool cp ) {
056        final Constant c = cp.getConstant(super.getIndex());
057        final StringTokenizer tok = new StringTokenizer(cp.constantToString(c));
058        return Const.getOpcodeName(super.getOpcode()) + " " + tok.nextToken().replace('.', '/')
059                + tok.nextToken();
060    }
061
062
063    /**
064     * Also works for instructions whose stack effect depends on the
065     * constant pool entry they reference.
066     * @return Number of words consumed from stack by this instruction
067     */
068    @Override
069    public int consumeStack( final ConstantPoolGen cpg ) {
070        int sum;
071        if ((super.getOpcode() == Const.INVOKESTATIC) || (super.getOpcode() == Const.INVOKEDYNAMIC)) {
072            sum = 0;
073        } else {
074            sum = 1; // this reference
075        }
076
077        final String signature = getSignature(cpg);
078        sum += Type.getArgumentTypesSize(signature);
079        return sum;
080    }
081
082
083    /**
084     * Also works for instructions whose stack effect depends on the
085     * constant pool entry they reference.
086     * @return Number of words produced onto stack by this instruction
087     */
088    @Override
089    public int produceStack( final ConstantPoolGen cpg ) {
090        final String signature = getSignature(cpg);
091        return Type.getReturnTypeSize(signature);
092    }
093
094    /**
095     * This overrides the deprecated version as we know here that the referenced class
096     * may legally be an array.
097     *
098     * @return name of the referenced class/interface
099     * @throws IllegalArgumentException if the referenced class is an array (this should not happen)
100     */ 
101    @Override
102    public String getClassName( final ConstantPoolGen cpg ) {
103        final ConstantPool cp = cpg.getConstantPool();
104        final ConstantCP cmr = (ConstantCP) cp.getConstant(super.getIndex());
105        final String className = cp.getConstantString(cmr.getClassIndex(), Const.CONSTANT_Class);
106        return className.replace('/', '.');
107    }
108
109    /** @return return type of referenced method.
110     */
111    @Override
112    public Type getType( final ConstantPoolGen cpg ) {
113        return getReturnType(cpg);
114    }
115
116
117    /** @return name of referenced method.
118     */
119    public String getMethodName( final ConstantPoolGen cpg ) {
120        return getName(cpg);
121    }
122
123
124    /** @return return type of referenced method.
125     */
126    public Type getReturnType( final ConstantPoolGen cpg ) {
127        return Type.getReturnType(getSignature(cpg));
128    }
129
130
131    /** @return argument types of referenced method.
132     */
133    public Type[] getArgumentTypes( final ConstantPoolGen cpg ) {
134        return Type.getArgumentTypes(getSignature(cpg));
135    }
136
137}