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