1 /*
2 * Copyright 2014 - 2020 Rafael Winterhalter
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.bytebuddy.implementation.bytecode;
17
18 import net.bytebuddy.description.type.TypeDefinition;
19
20 import java.util.Arrays;
21 import java.util.Collection;
22
23 /**
24 * Represents the size of a Java type on the operand stack.
25 */
26 public enum StackSize {
27
28 /**
29 * An empty stack size.
30 */
31 ZERO(0),
32
33 /**
34 * A single slot stack size.
35 */
36 SINGLE(1),
37
38 /**
39 * A double slot stack size which is required by {@code long} and {@code double} values.
40 */
41 DOUBLE(2);
42
43 /**
44 * The size of the stack this instance represents.
45 */
46 private final int size;
47
48 /**
49 * Creates a new stack size.
50 *
51 * @param size The size of the stack this instance represents.
52 */
53 StackSize(int size) {
54 this.size = size;
55 }
56
57 /**
58 * Finds the operand stack size of a given Java type.
59 *
60 * @param type The type of interest.
61 * @return The given type's operand stack size.
62 */
63 public static StackSize of(Class<?> type) {
64 if (type == void.class) {
65 return ZERO;
66 } else if (type == double.class || type == long.class) {
67 return DOUBLE;
68 } else {
69 return SINGLE;
70 }
71 }
72
73 /**
74 * Represents a numeric size as a {@link StackSize}.
75 *
76 * @param size The size to represent. Must be {@code 0}, {@code 1} or {@code 2}.
77 * @return A stack size representation for the given value.
78 */
79 public static StackSize of(int size) {
80 switch (size) {
81 case 0:
82 return ZERO;
83 case 1:
84 return SINGLE;
85 case 2:
86 return DOUBLE;
87 default:
88 throw new IllegalArgumentException("Unexpected stack size value: " + size);
89 }
90 }
91
92 /**
93 * Computes the stack size of all supplied types.
94 *
95 * @param typeDefinition The types for which to compute the size.
96 * @return The total size of all types.
97 */
98 public static int of(TypeDefinition... typeDefinition) {
99 return of(Arrays.asList(typeDefinition));
100 }
101
102 /**
103 * Computes the stack size of all supplied types.
104 *
105 * @param typeDefinitions The types for which to compute the size.
106 * @return The total size of all types.
107 */
108 public static int of(Collection<? extends TypeDefinition> typeDefinitions) {
109 int size = 0;
110 for (TypeDefinition typeDefinition : typeDefinitions) {
111 size += typeDefinition.getStackSize().getSize();
112 }
113 return size;
114 }
115
116 /**
117 * The numeric value of this stack size representation.
118 *
119 * @return An integer representing the operand stack size.
120 */
121 public int getSize() {
122 return size;
123 }
124
125 /**
126 * Creates an instance of a
127 * {@link StackManipulation.Size}
128 * that describes a stack growth of this size.
129 *
130 * @return A stack size growth by the size represented by this stack size.
131 */
132 public StackManipulation.Size toIncreasingSize() {
133 return new StackManipulation.Size(getSize(), getSize());
134 }
135
136 /**
137 * Creates an instance of a
138 * {@link StackManipulation.Size}
139 * that describes a stack decrease of this size.
140 *
141 * @return A stack size decrease by the size represented by this stack size.
142 */
143 public StackManipulation.Size toDecreasingSize() {
144 return new StackManipulation.Size(-1 * getSize(), 0);
145 }
146
147 /**
148 * Determines the maximum of two stack size representations.
149 *
150 * @param stackSize The other stack size representation.
151 * @return The maximum of this and the other stack size.
152 */
153 public StackSize maximum(StackSize stackSize) {
154 switch (this) {
155 case ZERO:
156 return stackSize;
157 case SINGLE:
158 switch (stackSize) {
159 case DOUBLE:
160 return stackSize;
161 case SINGLE:
162 case ZERO:
163 return this;
164 default:
165 throw new AssertionError();
166 }
167 case DOUBLE:
168 return this;
169 default:
170 throw new AssertionError();
171 }
172 }
173 }
174