1+ /*
2+ * CodeAPI-BytecodeWriter - Framework to generate Java code and Bytecode code. <https://github.com/JonathanxD/CodeAPI-BytecodeWriter>
3+ *
4+ * The MIT License (MIT)
5+ *
6+ * Copyright (c) 2017 TheRealBuggy/JonathanxD (https://github.com/JonathanxD/ & https://github.com/TheRealBuggy/) <[email protected] > 7+ * Copyright (c) contributors
8+ *
9+ *
10+ * Permission is hereby granted, free of charge, to any person obtaining a copy
11+ * of this software and associated documentation files (the "Software"), to deal
12+ * in the Software without restriction, including without limitation the rights
13+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14+ * copies of the Software, and to permit persons to whom the Software is
15+ * furnished to do so, subject to the following conditions:
16+ *
17+ * The above copyright notice and this permission notice shall be included in
18+ * all copies or substantial portions of the Software.
19+ *
20+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26+ * THE SOFTWARE.
27+ */
28+ package com.github.jonathanxd.codeapi.bytecode.common
29+
30+ import com.github.jonathanxd.codeapi.type.CodeType
31+ import org.objectweb.asm.Label
32+ import java.util.*
33+
34+ /* *
35+ * Jvm Frame, this frame contains all variables of parent frame and store variables of current frame.
36+ */
37+ internal class Frame (val parent : Frame ? = null , variables : List <Variable > = emptyList(), val endLabel : Label ? = null ) {
38+
39+ private val variables: MutableList <Variable > = (parent?.immutableVariableList.orEmpty() + variables).toMutableList()
40+ val immutableVariableList: List <Variable > = Collections .unmodifiableList(this .variables)
41+
42+ /* *
43+ * Get variable at stack pos `i`.
44+ *
45+ * @param i Index in the stack.
46+ * @return Variable or [Optional.empty] if not present.
47+ */
48+ fun getVar (i : Int ): Variable ? {
49+ if (i < 0 || i >= this .variables.size)
50+ return null
51+
52+ return this .variables[i]
53+ }
54+
55+ /* *
56+ * Get a variable by name.
57+ *
58+ * @param name Name of the variable.
59+ * @return Variable or `null` if not present.
60+ */
61+ fun getVarByName (name : String ): Variable ? {
62+ return this .variables.find { `var ` -> `var `.name == name }
63+ }
64+
65+ /* *
66+ * Get a variable by name and type.
67+ *
68+ * @param name Name of the variable.
69+ * @param type Type of the variable.
70+ * @return Variable or `null` if not present.
71+ */
72+ fun getVar (name : String , type : CodeType ? ): Variable ? {
73+ if (type == null ) {
74+ return this .getVarByName(name)
75+ }
76+
77+ return this .variables.find { `var ` -> `var `.name == name && `var `.type.compareTo(type) == 0 }
78+ }
79+
80+ /* *
81+ * Gets the position of a variable instance
82+ *
83+ * @param variable Variable instance
84+ * @return Position of variable if exists, or [OptionalInt.empty] otherwise.
85+ */
86+ fun getVarPos (variable : Variable ): OptionalInt {
87+ for (i in this .variables.indices.reversed()) {
88+ if (this .variables[i] == variable)
89+ return OptionalInt .of(i)
90+ }
91+
92+ return OptionalInt .empty()
93+ }
94+
95+ /* *
96+ * Add variable
97+ */
98+ fun add (variable : Variable ) {
99+ this .variables.add(variable)
100+ }
101+
102+ /* *
103+ * Store a variable in stack "table".
104+ *
105+ * @param name Name of variable
106+ * @param type Type of variable
107+ * @param startLabel Start label (first occurrence of variable).
108+ * @param endLabel End label (last usage of variable).
109+ * @return [OptionalInt] holding the position, or empty if failed to store.
110+ * @throws RuntimeException if variable is already defined.
111+ */
112+ fun storeVar (name : String , type : CodeType , startLabel : Label , endLabel : Label ? ): OptionalInt {
113+ val variable = Variable (name, type, startLabel, endLabel ? : this .endLabel)
114+
115+ for (i in this .variables.indices.reversed()) {
116+ val variable1 = this .variables[i]
117+
118+ if (variable1 == variable) {
119+ if (variable1.isTemp) {
120+ throw RuntimeException (" Cannot store variable named '$name '. Variable already stored!" )
121+ }
122+
123+ return OptionalInt .of(i)
124+ }
125+ }
126+
127+ this .variables.add(variable)
128+ // ? Last index with synchronized method is good!!!
129+ return this .getVarPos(variable)
130+ }
131+
132+ /* *
133+ * Store a internal variable. (internal variables doesn't have their names generated in
134+ * LocalVariableTable).
135+ *
136+ * Name generation could also be avoided using '#' symbol in the variable name.
137+ *
138+ * Position of internal variables couldn't be getted by [.storeVar].
139+ *
140+ * Internal variables could be freely redefined and has no restrictions about the redefinition.
141+ *
142+ * @param name Name of variable
143+ * @param type Type of variable
144+ * @param startLabel Start label (first occurrence of variable).
145+ * @param endLabel End label (last usage of variable).
146+ * @return [OptionalInt] holding the position, or empty if failed to store.
147+ */
148+ fun storeInternalVar (name : String , type : CodeType , startLabel : Label , endLabel : Label ? ): OptionalInt {
149+ val variable = Variable (name, type, startLabel, endLabel ? : this .endLabel, true )
150+
151+ for (i in variables.indices.reversed()) {
152+ if (this .variables[i] == variable) {
153+ return OptionalInt .of(i)
154+ }
155+ }
156+
157+ this .variables.add(variable)
158+ // ? Last index with synchronized method is good!!!
159+ return this .getVarPos(variable)
160+ }
161+
162+ /* *
163+ * Redefine a variable in a `position`.
164+ *
165+ * @param pos Position of variable in stack map.
166+ * @param name Name of variable
167+ * @param type Type of variable
168+ * @param startLabel Start label (first occurrence of variable).
169+ * @param endLabel End label (last usage of variable).
170+ */
171+ fun redefineVar (pos : Int , name : String , type : CodeType , startLabel : Label , endLabel : Label ? ) {
172+ val variable = Variable (name, type, startLabel, endLabel)
173+
174+ if (pos >= this .variables.size) {
175+ this .variables.add(pos, variable)
176+ } else {
177+ if (this .variables[pos].isTemp) {
178+ throw RuntimeException (" Cannot store variable named '$name '. Variable already stored!" )
179+ }
180+
181+ this .variables[pos] = variable
182+ }
183+ }
184+
185+ /* *
186+ * Return last position in stack map.
187+ *
188+ * @return Last position in stack map.
189+ */
190+ fun currentPos (): Int {
191+ return this .variables.size - 1
192+ }
193+
194+ /* *
195+ * Create a unique name of variable based on [base] name.
196+ */
197+ fun getUniqueVariableName (base : String ): String {
198+ if (! hasVar(base))
199+ return base
200+
201+ var finalName = base
202+ var i = 0
203+
204+ do {
205+ finalName + = i
206+ ++ i
207+ } while (hasVar(finalName))
208+
209+ return finalName
210+ }
211+
212+ fun hasVar (varName : String ) = this .variables.any { it.name == varName }
213+ }
0 commit comments