    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 * Super class 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     * This overrides the deprecated version as we know here that the referenced class may legally be an array.
    081     *
    082     * @return name of the referenced class/interface.
    083     * @throws IllegalArgumentException if the referenced class is an array (this should not happen)
    084     */
    085    @Override
    086    public String getClassName(final ConstantPoolGen cpg) {
    087        final ConstantPool cp = cpg.getConstantPool();
    088        final ConstantCP cmr = (ConstantCP) cp.getConstant(super.getIndex());
    089        final String className = cp.getConstantString(cmr.getClassIndex(), Const.CONSTANT_Class);
    090        return Utility.pathToPackage(className);
    091    }
    092
    093    /**
    094     * Gets the name of referenced method.
    095     *
    096     * @param cpg the constant pool generator.
    097     * @return name of referenced method.
    098     */
    099    public String getMethodName(final ConstantPoolGen cpg) {
    100        return getName(cpg);
    101    }
    102
    103    /**
    104     * Gets the return type of referenced method.
    105     *
    106     * @param cpg the constant pool generator.
    107     * @return return type of referenced method.
    108     */
    109    public Type getReturnType(final ConstantPoolGen cpg) {
    110        return Type.getReturnType(getSignature(cpg));
    111    }
    112
    113    /**
    114     * Gets the return type of referenced method.
    115     *
    116     * @param cpg the constant pool generator.
    117     * @return return type of referenced method.
    118     */
    119    @Override
    120    public Type getType(final ConstantPoolGen cpg) {
    121        return getReturnType(cpg);
    122    }
    123
    124    /**
    125     * Also works for instructions whose stack effect depends on the constant pool entry they reference.
    126     *
    127     * @return Number of words produced onto stack by this instruction.
    128     */
    129    @Override
    130    public int produceStack(final ConstantPoolGen cpg) {
    131        final String signature = getSignature(cpg);
    132        return Type.getReturnTypeSize(signature);
    133    }
    134
    135    /**
    136     * @return mnemonic for instruction with symbolic references resolved.
    137     */
    138    @Override
    139    public String toString(final ConstantPool cp) {
    140        final Constant c = cp.getConstant(super.getIndex());
    141        final StringTokenizer tok = new StringTokenizer(cp.constantToString(c));
    142
    143        final String opcodeName = Const.getOpcodeName(super.getOpcode());
    144
    145        final StringBuilder sb = new StringBuilder(opcodeName);
    146        if (tok.hasMoreTokens()) {
    147            sb.append(" ");
    148            sb.append(Utility.packageToPath(tok.nextToken()));
    149            if (tok.hasMoreTokens()) {
    150                sb.append(tok.nextToken());
    151            }
    152        }
    153
    154        return sb.toString();
    155    }
    156
    157}
    158