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}