Skip to content

Commit dc0b191

Browse files
authored
Merge pull request #7 from JonathanxD/feature/reuse-locals
Added ability to reuse local variables, fixes #6#
2 parents 044e122 + 2d59cfb commit dc0b191

File tree

54 files changed

+1113
-629
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1113
-629
lines changed

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ buildscript {
1818
}
1919

2020
group 'com.github.jonathanxd'
21-
version '3.0.2-e'
21+
version '3.0.3'
2222

2323
apply from: project(":CodeAPI").file("gradle/common.gradle")
2424

2525
dependencies {
2626
compile project(":CodeAPI")
27-
compile 'com.github.JonathanxD:BytecodeDisassembler:2.0.2'
27+
compile 'com.github.JonathanxD:BytecodeDisassembler:2.0.3-c2'
2828
compile group: 'org.ow2.asm', name: 'asm-all', version: '5.1'
2929
testCompile project(path: ':CodeAPI', configuration: 'tests')
3030
}

src/main/kotlin/com/github/jonathanxd/codeapi/bytecode/BytecodeClass.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ package com.github.jonathanxd.codeapi.bytecode
3030
import com.github.jonathanxd.bytecodedisassembler.Disassembler
3131
import com.github.jonathanxd.codeapi.base.TypeDeclaration
3232

33-
class BytecodeClass(val type: TypeDeclaration, private val bytecode_: ByteArray) {
33+
class BytecodeClass constructor(val type: TypeDeclaration, private val bytecode_: ByteArray) {
3434

3535
val disassembledCode: String by lazy {
3636
Disassembler.disassemble(bytes = this.bytecode, hash = true)
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
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

Comments
 (0)