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