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