Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
inf225.h21
jvm-asm-example
Commits
db69e06c
Commit
db69e06c
authored
Nov 08, 2021
by
Anya Helene Bagge
🦆
Browse files
various
parent
fe195b4d
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/main/java/inf225/examples/Debugger.java
0 → 100644
View file @
db69e06c
package
inf225.examples
;
import
com.sun.jdi.*
;
import
com.sun.jdi.connect.Connector
;
import
com.sun.jdi.connect.LaunchingConnector
;
import
com.sun.jdi.event.*
;
import
com.sun.jdi.request.EventRequest
;
import
com.sun.jdi.request.EventRequestManager
;
import
com.sun.jdi.request.MethodEntryRequest
;
import
com.sun.jdi.request.StepRequest
;
import
java.lang.reflect.Field
;
import
java.util.List
;
import
java.util.Map
;
public
class
Debugger
{
private
Class
debugee
;
public
void
setDebugee
(
Class
debugee
)
{
this
.
debugee
=
debugee
;
}
/**
* Create connector and give it the debuggee's main class, connect this debugger
* to the VM and launch the VM.
*
* @return Virtual Machine for debugging
* @throws Exception
*/
public
VirtualMachine
connectAndLaunchVirtualMachine
()
throws
Exception
{
LaunchingConnector
launchingConnector
=
Bootstrap
.
virtualMachineManager
().
defaultConnector
();
Map
<
String
,
Connector
.
Argument
>
connectorArguments
=
launchingConnector
.
defaultArguments
();
connectorArguments
.
get
(
"main"
).
setValue
(
debugee
.
getName
());
connectorArguments
.
get
(
"options"
).
setValue
(
"-cp "
+
System
.
getProperty
(
"java.class.path"
));
System
.
out
.
println
(
connectorArguments
);
return
launchingConnector
.
launch
(
connectorArguments
);
}
/**
* Enable methodEntryRequest to get notified when a method is entried in the
* debugee class.
*
* @see <a href=
* "https://docs.oracle.com/javase/8/docs/jdk/api/jpda/jdi/com/sun/jdi/event/MethodEntryEvent.html">MethodEntryEvent</a>
*
* @param virtualMachine
*/
public
void
listenToMethodEntryEvents
(
VirtualMachine
virtualMachine
)
{
MethodEntryRequest
methodEntryRequest
=
virtualMachine
.
eventRequestManager
().
createMethodEntryRequest
();
virtualMachine
.
eventRequestManager
().
createExceptionRequest
(
null
,
true
,
true
).
enable
();
methodEntryRequest
.
addClassFilter
(
"*.Test"
);
methodEntryRequest
.
enable
();
}
public
static
void
main
(
String
[]
args
)
throws
NoSuchFieldException
,
SecurityException
{
System
.
out
.
println
(
System
.
getProperties
().
toString
().
replace
(
","
,
",\n"
));
Debugger
debugger
=
new
Debugger
();
debugger
.
setDebugee
(
Test
.
class
);
for
(
java
.
lang
.
reflect
.
Method
m
:
Test
.
class
.
getMethods
())
{
// Field field = Test.class.getField("foo");
System
.
out
.
println
(
m
.
toGenericString
());
}
try
{
VirtualMachine
virtualMachine
=
debugger
.
connectAndLaunchVirtualMachine
();
debugger
.
listenToMethodEntryEvents
(
virtualMachine
);
StepRequest
request
=
virtualMachine
.
eventRequestManager
()
.
createStepRequest
(
virtualMachine
.
allThreads
().
get
(
0
),
StepRequest
.
STEP_MIN
,
StepRequest
.
STEP_INTO
);
request
.
addClassFilter
(
"*.Test"
);
// request.addCountFilter(1);
request
.
enable
();
EventSet
events
;
while
((
events
=
virtualMachine
.
eventQueue
().
remove
())
!=
null
)
{
for
(
Event
event
:
events
)
{
System
.
out
.
println
(
event
);
if
(
event
instanceof
MethodEntryEvent
)
{
Method
enteredMethod
=
((
MethodEntryEvent
)
event
).
method
();
System
.
out
.
println
(
"METHOD: "
+
enteredMethod
.
toString
());
}
else
if
(
event
instanceof
StepEvent
)
{
StepEvent
stepEvent
=
(
StepEvent
)
event
;
Method
method
=
stepEvent
.
location
().
method
();
System
.
out
.
println
(
method
.
name
()
+
":"
+
stepEvent
.
location
().
codeIndex
()
+
": "
+
String
.
format
(
"%02x"
,
method
.
bytecodes
()[(
int
)
stepEvent
.
location
().
codeIndex
()]));
ThreadReference
thread
=
stepEvent
.
thread
();
if
(
thread
.
isSuspended
())
{
StackFrame
frame
=
stepEvent
.
thread
().
frame
(
0
);
List
<
LocalVariable
>
variables
=
frame
.
visibleVariables
();
for
(
LocalVariable
v
:
variables
)
{
System
.
out
.
println
(
v
.
typeName
()
+
" "
+
v
.
name
()
+
" = "
+
frame
.
getValue
(
v
));
}
}
System
.
out
.
println
(
request
+
", "
+
stepEvent
.
thread
().
isSuspended
());
}
virtualMachine
.
resume
();
}
}
}
catch
(
VMDisconnectedException
e
)
{
System
.
out
.
println
(
"Virtual Machine is disconnected."
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
}
src/main/java/inf225/examples/Lambdas.java
View file @
db69e06c
...
...
@@ -42,9 +42,9 @@ public class Lambdas {
}
public
double
foo
(
double
a
,
double
b
)
{
int
[]
s
=
{};
String
t
=
""
;
return
a
+
b
+
s
[
0
]
+
t
.
length
();
return
a
+
b
+
t
.
length
();
}
public
static
void
printByteCode
(
Function
<
Float
,
Float
>
fun
)
throws
Exception
{
...
...
src/main/java/inf225/examples/Test.java
0 → 100644
View file @
db69e06c
package
inf225.examples
;
public
class
Test
{
String
foo
=
""
;
public
static
void
main
(
String
[]
args
)
{
new
Test
().
f
();
throw
new
RuntimeException
();
}
public
void
f
()
{
int
a
=
2
;
int
b
=
3
;
System
.
out
.
println
(
g
(
a
+
b
));
}
public
int
g
(
int
a
)
{
return
a
*
2
;
}
}
src/main/java/inf225/examples/asm/ASTNode.java
View file @
db69e06c
package
inf225.examples.asm
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
import
org.objectweb.asm.Type
;
public
class
ASTNode
{
public
interface
ASTNode
{
public
interface
StatNode
extends
ASTNode
{
}
public
interface
ExprNode
extends
ASTNode
{
public
Type
type
();
}
public
static
class
Const
implements
ExprNode
{
Object
value
;
Type
type
;
public
static
class
Var
extends
ASTNode
{
public
Const
(
Object
value
,
Type
type
)
{
super
();
this
.
value
=
value
;
this
.
type
=
type
;
}
@Override
public
String
toString
()
{
if
(
value
instanceof
String
)
return
String
.
format
(
"\"%s\""
,
value
.
toString
().
replaceAll
(
"[\"\\\\]"
,
"\\$1"
));
else
if
(
value
instanceof
Number
)
return
value
.
toString
();
else
return
value
.
getClass
().
getName
()
+
"("
+
value
+
")"
;
}
@Override
public
Type
type
()
{
return
type
;
}
}
public
static
class
Var
implements
ExprNode
{
int
slot
;
Object
type
;
public
Var
(
int
slot
,
Object
type
)
{
Type
type
;
String
name
;
public
Var
(
int
slot
,
Type
type
)
{
super
();
this
.
slot
=
slot
;
this
.
type
=
type
;
}
@Override
public
String
toString
()
{
return
"Var [slot=
"
+
slot
+
"
, type=
"
+
type
+
"]"
;
return
name
!=
null
?
name
:
"var
"
+
slot
+
"
_
"
+
type
;
}
@Override
public
int
hashCode
()
{
final
int
prime
=
31
;
int
result
=
1
;
result
=
prime
*
result
+
slot
;
result
=
prime
*
result
+
((
type
==
null
)
?
0
:
type
.
hashCode
());
return
result
;
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
this
==
obj
)
return
true
;
if
(
obj
==
null
)
return
false
;
if
(
getClass
()
!=
obj
.
getClass
())
return
false
;
Var
other
=
(
Var
)
obj
;
if
(
slot
!=
other
.
slot
)
return
false
;
if
(
type
==
null
)
{
if
(
other
.
type
!=
null
)
return
false
;
}
else
if
(!
type
.
equals
(
other
.
type
))
return
false
;
return
true
;
}
@Override
public
Type
type
()
{
return
type
;
}
}
public
static
class
Assign
implements
StatNode
{
Var
var
;
ExprNode
value
;
public
Assign
(
Var
var
,
ExprNode
value
)
{
super
();
this
.
var
=
var
;
this
.
value
=
value
;
}
@Override
public
String
toString
()
{
return
var
+
" = "
+
value
+
";"
;
}
}
public
static
class
Operator
extends
ASTNode
{
public
static
class
Declare
implements
StatNode
{
Var
var
;
public
Declare
(
Var
var
)
{
super
();
this
.
var
=
var
;
}
@Override
public
String
toString
()
{
return
var
.
type
.
getClassName
()
+
" "
+
var
+
";"
;
}
}
public
static
class
Return
implements
StatNode
{
ExprNode
value
;
public
Return
(
ExprNode
value
)
{
super
();
this
.
value
=
value
;
}
@Override
public
String
toString
()
{
return
"return "
+
value
+
";"
;
}
}
public
static
class
Operator
implements
ExprNode
{
String
operator
;
List
<
ExprNode
>
args
;
Type
type
;
public
Operator
(
String
operator
,
Type
type
,
ExprNode
...
args
)
{
super
();
this
.
operator
=
operator
;
this
.
args
=
Arrays
.
asList
(
args
);
}
@Override
public
String
toString
()
{
return
operator
+
args
;
}
@Override
public
Type
type
()
{
return
type
;
}
}
public
static
class
Invoke
implements
ExprNode
{
String
operator
;
ASTNode
lhs
,
rhs
;
public
Operator
(
String
operator
,
ASTNode
lhs
,
ASTNode
rhs
)
{
List
<
ExprNode
>
args
;
Type
type
;
ExprNode
obj
;
public
Invoke
(
String
operator
,
Type
type
,
ExprNode
obj
,
ExprNode
...
args
)
{
super
();
this
.
operator
=
operator
;
this
.
lh
s
=
lhs
;
this
.
rhs
=
rhs
;
this
.
arg
s
=
Arrays
.
asList
(
args
)
;
this
.
obj
=
obj
;
}
@Override
public
String
toString
()
{
return
"Operator [operator="
+
operator
+
", lhs="
+
lhs
+
", rhs="
+
rhs
+
"]"
;
return
obj
.
toString
()
+
"."
+
operator
+
args
;
}
@Override
public
Type
type
()
{
return
type
;
}
}
}
src/main/java/inf225/examples/asm/ToExpr.java
View file @
db69e06c
package
inf225.examples.asm
;
import
java.util.ArrayDeque
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Deque
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.stream.Stream
;
import
org.objectweb.asm.ConstantDynamic
;
import
org.objectweb.asm.Handle
;
...
...
@@ -13,9 +18,15 @@ import org.objectweb.asm.Type;
import
org.objectweb.asm.commons.AnalyzerAdapter
;
import
org.objectweb.asm.commons.InstructionAdapter
;
import
inf225.examples.asm.ASTNode.ExprNode
;
import
inf225.examples.asm.ASTNode.Operator
;
import
inf225.examples.asm.ASTNode.StatNode
;
public
class
ToExpr
extends
InstructionAdapter
implements
AnalyzerVisitor
{
protected
AnalyzerAdapter
analyzerAdapter
;
protected
Deque
<
ASTNode
>
stack
=
new
ArrayDeque
<>();
protected
List
<
ASTNode
.
StatNode
>
statements
=
new
ArrayList
<>();
protected
Deque
<
ASTNode
.
ExprNode
>
stack
=
new
ArrayDeque
<>();
protected
Map
<
String
,
ASTNode
.
Var
>
vars
=
new
HashMap
<>();
protected
Type
methodType
;
protected
int
lineNumber
;
private
Label
label
;
...
...
@@ -24,6 +35,15 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
super
(
api
,
methodVisitor
);
}
protected
ASTNode
.
Var
var
(
int
slot
,
Type
type
)
{
String
id
=
String
.
format
(
"%d:%s"
,
slot
,
type
);
ASTNode
.
Var
v
=
vars
.
get
(
id
);
if
(
v
==
null
)
{
v
=
new
ASTNode
.
Var
(
slot
,
type
);
vars
.
put
(
id
,
v
);
}
return
v
;
}
public
void
visitParameter
(
final
String
name
,
final
int
access
)
{
System
.
out
.
printf
(
"visitParameter(%s,%d)%n"
,
name
,
access
);
}
...
...
@@ -34,13 +54,15 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
public
void
aconst
(
Object
value
)
{
System
.
out
.
printf
(
"aconst %s%n"
,
value
);
stack
.
push
(
new
ASTNode
.
Const
(
value
,
Type
.
getType
(
value
.
getClass
())));
}
public
void
add
(
Type
type
)
{
System
.
out
.
printf
(
"add %s%n"
,
type
);
AST
Node
rhs
=
stack
.
pop
();
AST
Node
lhs
=
stack
.
pop
();
stack
.
push
(
new
ASTNode
.
Operator
(
"add"
,
lhs
,
rhs
));
Expr
Node
rhs
=
stack
.
pop
();
Expr
Node
lhs
=
stack
.
pop
();
stack
.
push
(
new
ASTNode
.
Operator
(
type
.
getDescriptor
().
toLowerCase
()
+
"add"
,
type
,
lhs
,
rhs
));
}
public
void
aload
(
Type
type
)
{
...
...
@@ -49,6 +71,9 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
public
void
and
(
Type
type
)
{
System
.
out
.
printf
(
"and %s%n"
,
type
);
ExprNode
rhs
=
stack
.
pop
();
ExprNode
lhs
=
stack
.
pop
();
stack
.
push
(
new
ASTNode
.
Operator
(
type
.
getDescriptor
().
toLowerCase
()
+
"and"
,
type
,
lhs
,
rhs
));
}
public
void
anew
(
Type
type
)
{
...
...
@@ -58,6 +83,7 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
public
void
areturn
(
Type
type
)
{
System
.
out
.
printf
(
"areturn %s%n"
,
type
);
statements
.
add
(
new
ASTNode
.
Return
(
stack
.
pop
()));
}
...
...
@@ -76,10 +102,12 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
public
void
cast
(
Type
from
,
Type
to
)
{
System
.
out
.
printf
(
"cast %s, %s%n"
,
from
,
to
);
stack
.
push
(
new
ASTNode
.
Operator
(
"cast_"
+
from
+
"_"
+
to
,
to
,
stack
.
pop
()));
}
public
void
cconst
(
ConstantDynamic
constantDynamic
)
{
System
.
out
.
printf
(
"cconst %s%n"
,
constantDynamic
);
stack
.
push
(
new
ASTNode
.
Const
(
constantDynamic
,
null
));
}
public
void
checkcast
(
Type
type
)
{
...
...
@@ -89,29 +117,51 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
public
void
cmpg
(
Type
type
)
{
System
.
out
.
printf
(
"cmpg %s%n"
,
type
);
ExprNode
rhs
=
stack
.
pop
();
ExprNode
lhs
=
stack
.
pop
();
stack
.
push
(
new
ASTNode
.
Operator
(
type
.
getDescriptor
().
toLowerCase
()
+
"cmpg"
,
type
,
lhs
,
rhs
));
}
public
void
cmpl
(
Type
type
)
{
System
.
out
.
printf
(
"cmpl %s%n"
,
type
);
ExprNode
rhs
=
stack
.
pop
();
ExprNode
lhs
=
stack
.
pop
();
stack
.
push
(
new
ASTNode
.
Operator
(
type
.
getDescriptor
().
toLowerCase
()
+
"cmpl"
,
type
,
lhs
,
rhs
));
}
public
void
dconst
(
double
doubleValue
)
{
System
.
out
.
printf
(
"dconst %g%n"
,
doubleValue
);
stack
.
push
(
new
ASTNode
.
Const
(
doubleValue
,
Type
.
DOUBLE_TYPE
));
}
public
void
div
(
Type
type
)
{
System
.
out
.
printf
(
"div %s%n"
,
type
);
ExprNode
rhs
=
stack
.
pop
();
ExprNode
lhs
=
stack
.
pop
();
stack
.
push
(
new
ASTNode
.
Operator
(
type
.
getDescriptor
().
toLowerCase
()
+
"div"
,
type
,
lhs
,
rhs
));
}
public
void
dup
()
{
System
.
out
.
println
(
"dup"
);
ExprNode
top
=
stack
.
pop
();
stack
.
push
(
top
);
stack
.
push
(
top
);
}
public
void
dup2
()
{
System
.
out
.
println
(
"dup2"
);
ExprNode
top
=
stack
.
pop
();
Object
type
=
stackGetType
(
0
);
if
(
type
==
Opcodes
.
LONG
||
type
==
Opcodes
.
DOUBLE
)
{
stack
.
push
(
top
);
stack
.
push
(
top
);
}
else
{
ExprNode
top2
=
stack
.
pop
();
stack
.
push
(
top2
);
stack
.
push
(
top
);
stack
.
push
(
top2
);
stack
.
push
(
top
);
}
}
public
void
dup2X1
()
{
...
...
@@ -132,6 +182,7 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
public
void
fconst
(
float
floatValue
)
{
System
.
out
.
printf
(
"dconst %g%n"
,
floatValue
);
stack
.
push
(
new
ASTNode
.
Const
(
floatValue
,
Type
.
FLOAT_TYPE
));
}
public
void
getfield
(
String
owner
,
String
name
,
String
descriptor
)
{
...
...
@@ -149,10 +200,12 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
public
void
hconst
(
Handle
handle
)
{
System
.
out
.
printf
(
"hconst %s%n"
,
handle
);
stack
.
push
(
new
ASTNode
.
Const
(
handle
,
null
));
}
public
void
iconst
(
int
intValue
)
{
System
.
out
.
printf
(
"iconst %d%n"
,
intValue
);
stack
.
push
(
new
ASTNode
.
Const
(
intValue
,
Type
.
INT_TYPE
));
}
public
void
ifacmpeq
(
Label
label
)
{
...
...
@@ -240,16 +293,22 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
Type
methType
=
Type
.
getType
(
descriptor
);
Type
[]
argumentTypes
=
methType
.
getArgumentTypes
();
Type
retType
=
methType
.
getReturnType
();
ExprNode
obj
=
stack
.
pop
();
System
.
out
.
printf
(
"invokeinterface %s, %s, %s %s → %s%n"
,
owner
,
name
,
descriptor
,
//
Arrays
.
toString
(
argumentTypes
),
retType
);
ExprNode
[]
args
=
(
ExprNode
[])
Stream
.
of
(
argumentTypes
).
map
(
t
->
stack
.
pop
()).
toArray
(
n
->
new
ExprNode
[
n
]);
stack
.
push
(
new
ASTNode
.
Invoke
(
name
,
retType
,
obj
,
args
));
}
public
void
invokespecial
(
String
owner
,
String
name
,
String
descriptor
,
boolean
isInterface
)
{
Type
methType
=
Type
.
getType
(
descriptor
);
Type
objType
=
Type
.
getObjectType
(
owner
);
Type
[]
argumentTypes
=
methType
.
getArgumentTypes
();
Type
retType
=
methType
.
getReturnType
();
System
.
out
.
printf
(
"invokespecial %s, %s, %s, %b %s → %s%n"
,
owner
,
name
,
descriptor
,
isInterface
,
//
Arrays
.
toString
(
argumentTypes
),
retType
);
ExprNode
[]
args
=
(
ExprNode
[])
Stream
.
of
(
argumentTypes
).
map
(
t
->
stack
.
pop
()).
toArray
(
n
->
new
ExprNode
[
n
]);
stack
.
push
(
new
ASTNode
.
Operator
(
name
,
retType
,
args
));
}
public
void
invokestatic
(
String
owner
,
String
name
,
String
descriptor
,
boolean
isInterface
)
{
...
...
@@ -258,11 +317,19 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
Type
retType
=
methType
.
getReturnType
();
System
.
out
.
printf
(
"invokestatic %s, %s, %s, %b %s → %s%n"
,
owner
,
name
,
descriptor
,
isInterface
,
//
Arrays
.
toString
(
argumentTypes
),
retType
);
ExprNode
[]
args
=
(
ExprNode
[])
Stream
.
of
(
argumentTypes
).
map
(
t
->
stack
.
pop
()).
toArray
(
n
->
new
ExprNode
[
n
]);
stack
.
push
(
new
ASTNode
.
Operator
(
name
,
retType
,
args
));
}
public
void
invokevirtual
(
String
owner
,
String
name
,
String
descriptor
,
boolean
isInterface
)
{
Type
methType
=
Type
.
getType
(
descriptor
);
Type
objType
=
Type
.
getObjectType
(
owner
);
Type
[]
argumentTypes
=
methType
.
getArgumentTypes
();
Type
retType
=
methType
.
getReturnType
();
ExprNode
obj
=
stack
.
pop
();
System
.
out
.
printf
(
"invokevirtual %s, %s, %s, %b%n"
,
owner
,
name
,
descriptor
,
isInterface
);
ExprNode
[]
args
=
(
ExprNode
[])
Stream
.
of
(
argumentTypes
).
map
(
t
->
stack
.
pop
()).
toArray
(
n
->
new
ExprNode
[
n
]);
stack
.
push
(
new
ASTNode
.
Invoke
(
name
,
retType
,
obj
,
args
));
}
public
void
jsr
(
Label
label
)
{
...
...
@@ -272,16 +339,21 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
public
void
lcmp
()
{
System
.
out
.
printf
(
"lcmp%n"
);
ExprNode
rhs
=
stack
.
pop
();
ExprNode
lhs
=
stack
.
pop
();
stack
.
push
(
new
ASTNode
.
Operator
(
"lcmp"
,
Type
.
LONG_TYPE
,
lhs
,
rhs
));
}
public
void
lconst
(
long
longValue
)
{
System
.
out
.
printf
(
"lconst %l%n"
,
longValue
);
stack
.
push
(
new
ASTNode
.
Const
(
longValue
,
Type
.
LONG_TYPE
));
}
public
void
load
(
int
var
,
Type
type
)
{
// 'type' depends on the load instruction (e.g., iload, aload, dload, etc), and
// will be one of the primitive types, or an object or array type – in the latter cases
// we can get the actual type from the AnalyzerAdapter
// will be one of the primitive types, or an object or array type – in the
// latter cases
// we can get the actual type from the AnalyzerAdapter
Object
localType
=
localGetType
(
var
);
if
(
type
.
getSort
()
==
Type
.
OBJECT
)
type
=
Type
.
getObjectType
((
String
)
localType
);
...
...
@@ -289,7 +361,7 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
type
=
Type
.
getType
((
String
)
localType
);
System
.
out
.
printf
(
"load %d, %s (%s)%n"
,
var
,
type
,
localGetType
(
var
));
stack
.
push
(
new
ASTNode
.
Var
(
var
,
localGetType
(
var
)
));
stack
.
push
(
var
(
var
,
type
));
}
Object
localGetType
(
int
var
)
{
...
...
@@ -392,6 +464,9 @@ public class ToExpr extends InstructionAdapter implements AnalyzerVisitor {
public
void
mul
(
Type
type
)
{
System
.
out
.
printf
(
"mul %s | %s %s ↑%n"
,
type
,
frameTypeToString
(
stackGetType
(
0
)),
frameTypeToString
(
stackGetType
(
1
)));
ExprNode
rhs
=
stack
.
pop
();
ExprNode
lhs
=
stack
.
pop
();
stack
.
push
(
new
ASTNode
.
Operator
(
type
.
getDescriptor
().
toLowerCase
()
+
"mul"
,
type
,
lhs
,
rhs
));
}