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