-
Notifications
You must be signed in to change notification settings - Fork 1
/
CodeGenUtils.java
171 lines (156 loc) · 5.22 KB
/
CodeGenUtils.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package simjava;
import java.io.OutputStream;
import java.io.PrintStream;
/**
* This class contains several static methods useful when developing
* the code generation part of our compiler.
*
*/
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.util.TraceClassVisitor;
import simjava.AST.Type.TypeName;
public class CodeGenUtils{
/**
* Converts the provided classfile, generally created by asm,
* in a human readable format and returns as a String.
*
* @param bytecode
*/
public static String bytecodeToString(byte[] bytecode) {
int flags = ClassReader.SKIP_DEBUG;
ClassReader cr;
cr = new ClassReader(bytecode);
StringWriter out = new StringWriter();
cr.accept(new TraceClassVisitor(new PrintWriter(out)), flags);
return out.toString();
}
/**
* Prints the provided classfile, generally created by asm,
* in a human readable format
*
* @param bytecode
*/
public static void dumpBytecode(byte[] bytecode) {
int flags = ClassReader.SKIP_DEBUG;
ClassReader cr;
cr = new ClassReader(bytecode);
PrintStream out = System.out;
cr.accept(new TraceClassVisitor(new PrintWriter(out)), flags);
}
/**
* Loader for dynamically generated classes.
* Instantiated by getInstance.
*
*/
public static class DynamicClassLoader extends ClassLoader {
public DynamicClassLoader(ClassLoader parent) {
super(parent);
}
public Class<?> define(String className, byte[] bytecode) {
return super.defineClass(className, bytecode, 0, bytecode.length);
}
};
/**
* Creates an instance of the indicated class from the provided byteCode.
* args is passed as a parameter to the constructor, and in order to
* be the correct type for generated code, should be String[]
*
*
* @param name
* @param byteCode
* @param args
* @return
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
*/
public static Runnable getInstance(String name, byte[] byteCode, Object args)
throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
DynamicClassLoader loader = new DynamicClassLoader(Thread.currentThread().getContextClassLoader());
Class<?> testClass = loader.define(name, byteCode);
Constructor<?> constructor = testClass.getConstructor(args.getClass());
return (Runnable) constructor.newInstance(args);
}
// /**
// * Generates code to print the given String.
// * IF !GEN, does not generate code.
// * Used to allow observation of execution of generated program
// * during development and grading.
// *
// * @param mv
// * @param message
// */
// public static void genPrint(boolean GEN, MethodVisitor mv, String message) {
// if(GEN){
// mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
// mv.visitLdcInsn(message);
// mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V", false);
// }
// }
/**
* Generates code to print the given String.
* IF !GEN, does not generate code.
* Used to allow observation of execution of generated program
* during development and grading.
*
* @param mv
* @param message
*/
public static void genPrint(boolean GEN, MethodVisitor mv, String message) {
if(GEN){
// mv.visitFieldInsn(Opcodes.GETSTATIC, "simjava/PLPRuntimeLog", "globalLog", "Lcop5556sp17/PLPRuntimeLog;");
mv.visitLdcInsn(message);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "simjava/PLPRuntimeLog", "globalLogAddEntry", "(Ljava/lang/String;)V", false);
}
}
/**
* Generates code to print the value on top of the stack without consuming it.
* If !GEN, does not generate code.
*
* GEN Requires stack is not empty, and type matches the given type.
*
* Currently implemented only for integer and boolean.
*
* @param GEN
* @param mv
* @param type
*/
public static void genPrintTOS(boolean GEN, MethodVisitor mv, TypeName type) {
if (GEN) {
// mv.visitInsn(Opcodes.DUP);
// mv.visitFieldInsn(Opcodes.GETSTATIC, "simjava/PLPRuntimeLog", "globalLog", "Lcop5556sp17/PLPRuntimeLog;");
// mv.visitInsn(Opcodes.SWAP);
switch (type) {
case INTEGER: {
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer","toString","(I)Ljava/lang/String;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "simjava/PLPRuntimeLog", "globalLogAddEntry", "(Ljava/lang/String;)V", false);
}
break;
case BOOLEAN: {
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean","toString","(Z)Ljava/lang/String;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "simjava/PLPRuntimeLog", "globalLogAddEntry", "(Ljava/lang/String;)V", false);
}
break;
case IMAGE:
case FRAME:{
/* ignore */
} break;
default: {
throw new RuntimeException("genPrintTOS called unimplemented type " + type);
}
}
}
}
}