1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.bcel.generic;
18
19 import java.util.StringTokenizer;
20
21 import org.apache.bcel.Const;
22 import org.apache.bcel.classfile.Constant;
23 import org.apache.bcel.classfile.ConstantCP;
24 import org.apache.bcel.classfile.ConstantPool;
25 import org.apache.bcel.classfile.Utility;
26
27 /**
28 * Super class for the INVOKExxx family of instructions.
29 */
30 public abstract class InvokeInstruction extends FieldOrMethod implements ExceptionThrower, StackConsumer, StackProducer {
31
32 /**
33 * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise.
34 */
35 InvokeInstruction() {
36 }
37
38 /**
39 * @param index to constant pool
40 */
41 protected InvokeInstruction(final short opcode, final int index) {
42 super(opcode, index);
43 }
44
45 /**
46 * Also works for instructions whose stack effect depends on the constant pool entry they reference.
47 *
48 * @return Number of words consumed from stack by this instruction
49 */
50 @Override
51 public int consumeStack(final ConstantPoolGen cpg) {
52 int sum;
53 if (super.getOpcode() == Const.INVOKESTATIC || super.getOpcode() == Const.INVOKEDYNAMIC) {
54 sum = 0;
55 } else {
56 sum = 1; // this reference
57 }
58
59 final String signature = getSignature(cpg);
60 sum += Type.getArgumentTypesSize(signature);
61 return sum;
62 }
63
64 /**
65 * @return argument types of referenced method.
66 */
67 public Type[] getArgumentTypes(final ConstantPoolGen cpg) {
68 return Type.getArgumentTypes(getSignature(cpg));
69 }
70
71 /**
72 * This overrides the deprecated version as we know here that the referenced class may legally be an array.
73 *
74 * @return name of the referenced class/interface
75 * @throws IllegalArgumentException if the referenced class is an array (this should not happen)
76 */
77 @Override
78 public String getClassName(final ConstantPoolGen cpg) {
79 final ConstantPool cp = cpg.getConstantPool();
80 final ConstantCP cmr = (ConstantCP) cp.getConstant(super.getIndex());
81 final String className = cp.getConstantString(cmr.getClassIndex(), Const.CONSTANT_Class);
82 return Utility.pathToPackage(className);
83 }
84
85 /**
86 * @return name of referenced method.
87 */
88 public String getMethodName(final ConstantPoolGen cpg) {
89 return getName(cpg);
90 }
91
92 /**
93 * @return return type of referenced method.
94 */
95 public Type getReturnType(final ConstantPoolGen cpg) {
96 return Type.getReturnType(getSignature(cpg));
97 }
98
99 /**
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 }