    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}