Fixed stackmap and classloading bugs.
This commit is contained in:
parent
c8c2c670d4
commit
bad616d4cb
|
@ -51,7 +51,7 @@ import java.nio.ByteBuffer;
|
||||||
*/
|
*/
|
||||||
public class MappedObject {
|
public class MappedObject {
|
||||||
|
|
||||||
static final boolean CHECKS = false;//LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.Checks");
|
static final boolean CHECKS = LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.Checks");
|
||||||
|
|
||||||
public MappedObject() {
|
public MappedObject() {
|
||||||
//
|
//
|
||||||
|
|
|
@ -8,13 +8,13 @@ import org.lwjgl.LWJGLUtil;
|
||||||
import org.objectweb.asm.*;
|
import org.objectweb.asm.*;
|
||||||
import org.objectweb.asm.util.TraceClassVisitor;
|
import org.objectweb.asm.util.TraceClassVisitor;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.*;
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import static org.objectweb.asm.Opcodes.*;
|
import static org.objectweb.asm.Opcodes.*;
|
||||||
|
|
||||||
|
@ -32,8 +32,8 @@ import static org.objectweb.asm.Opcodes.*;
|
||||||
*/
|
*/
|
||||||
public class MappedObjectTransformer {
|
public class MappedObjectTransformer {
|
||||||
|
|
||||||
static final boolean PRINT_TIMING = false;//LWJGLUtil.DEBUG && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintTiming");
|
static final boolean PRINT_TIMING = LWJGLUtil.DEBUG && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintTiming");
|
||||||
static final boolean PRINT_ACTIVITY = false;//LWJGLUtil.DEBUG && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintActivity");
|
static final boolean PRINT_ACTIVITY = LWJGLUtil.DEBUG && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintActivity");
|
||||||
static final boolean PRINT_BYTECODE = false; //LWJGLUtil.DEBUG && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintBytecode");
|
static final boolean PRINT_BYTECODE = false; //LWJGLUtil.DEBUG && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintBytecode");
|
||||||
|
|
||||||
static final Map<String, MappedSubtypeInfo> className_to_subtype;
|
static final Map<String, MappedSubtypeInfo> className_to_subtype;
|
||||||
|
@ -138,12 +138,23 @@ public class MappedObjectTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean is_currently_computing_frames = false;
|
||||||
static final String view_constructor_method = "_construct_view_";
|
static final String view_constructor_method = "_construct_view_";
|
||||||
|
|
||||||
static byte[] transformFieldAccess(final String className, byte[] bytecode) {
|
static byte[] transformFieldAccess(final String className, byte[] bytecode) {
|
||||||
int flags = 0;//ClassWriter.COMPUTE_FRAMES;
|
int flags = ClassWriter.COMPUTE_FRAMES;
|
||||||
|
|
||||||
ClassWriter writer = new ClassWriter(flags);
|
ClassWriter writer = new ClassWriter(flags) {
|
||||||
|
// HACK: prevent user-code static-initialization-blocks to be executed
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getCommonSuperClass(String a, String b) {
|
||||||
|
if ( is_currently_computing_frames )
|
||||||
|
if ( !a.startsWith("java/") || !b.startsWith("java/") )
|
||||||
|
return "java/lang/Object";
|
||||||
|
return super.getCommonSuperClass(a, b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ClassAdapter adapter = new ClassAdapter(writer) {
|
ClassAdapter adapter = new ClassAdapter(writer) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -192,14 +203,14 @@ public class MappedObjectTransformer {
|
||||||
bytecode = writer.toByteArray();
|
bytecode = writer.toByteArray();
|
||||||
|
|
||||||
if ( PRINT_BYTECODE )
|
if ( PRINT_BYTECODE )
|
||||||
printBytecode(bytecode, adapter);
|
printBytecode(bytecode);
|
||||||
|
|
||||||
return bytecode;
|
return bytecode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printBytecode(byte[] bytecode, ClassAdapter adapter) {
|
private static void printBytecode(byte[] bytecode) {
|
||||||
StringWriter sw = new StringWriter();
|
StringWriter sw = new StringWriter();
|
||||||
ClassVisitor tracer = new TraceClassVisitor(adapter, new PrintWriter(sw));
|
ClassVisitor tracer = new TraceClassVisitor(new ClassWriter(0), new PrintWriter(sw));
|
||||||
new ClassReader(bytecode).accept(tracer, 0);
|
new ClassReader(bytecode).accept(tracer, 0);
|
||||||
String dump = sw.toString();
|
String dump = sw.toString();
|
||||||
|
|
||||||
|
@ -228,12 +239,15 @@ public class MappedObjectTransformer {
|
||||||
super.visitTypeInsn(opcode, typeName);
|
super.visitTypeInsn(opcode, typeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int requireExtraStack = 0;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMaxs(int maxStack, int maxLocals)
|
public void visitMaxs(int a, int b) {
|
||||||
{
|
try {
|
||||||
super.visitMaxs(maxStack+this.requireExtraStack, maxLocals);
|
is_currently_computing_frames = true;
|
||||||
|
|
||||||
|
super.visitMaxs(a, b);
|
||||||
|
} finally {
|
||||||
|
is_currently_computing_frames = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -282,7 +296,6 @@ public class MappedObjectTransformer {
|
||||||
// stack: int, int, buffer, new, new
|
// stack: int, int, buffer, new, new
|
||||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "setup", "(L" + jvmClassName(MappedObject.class) + ";Ljava/nio/ByteBuffer;II)V");
|
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "setup", "(L" + jvmClassName(MappedObject.class) + ";Ljava/nio/ByteBuffer;II)V");
|
||||||
// stack: new
|
// stack: new
|
||||||
this.requireExtraStack = 5;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,7 +309,6 @@ public class MappedObjectTransformer {
|
||||||
// stack: new, this
|
// stack: new, this
|
||||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "dup", "(L" + jvmClassName(MappedObject.class) + ";L" + jvmClassName(MappedObject.class) + ";)L" + jvmClassName(MappedObject.class) + ";");
|
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "dup", "(L" + jvmClassName(MappedObject.class) + ";L" + jvmClassName(MappedObject.class) + ";)L" + jvmClassName(MappedObject.class) + ";");
|
||||||
// stack: new
|
// stack: new
|
||||||
this.requireExtraStack = 3;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,7 +322,6 @@ public class MappedObjectTransformer {
|
||||||
// stack: new, this
|
// stack: new, this
|
||||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "slice", "(L" + jvmClassName(MappedObject.class) + ";L" + jvmClassName(MappedObject.class) + ";)L" + jvmClassName(MappedObject.class) + ";");
|
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "slice", "(L" + jvmClassName(MappedObject.class) + ";L" + jvmClassName(MappedObject.class) + ";)L" + jvmClassName(MappedObject.class) + ";");
|
||||||
// stack: new
|
// stack: new
|
||||||
this.requireExtraStack = 3;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +333,6 @@ public class MappedObjectTransformer {
|
||||||
// stack: this, this
|
// stack: this, this
|
||||||
super.visitMethodInsn(INVOKEVIRTUAL, className, view_constructor_method, "()V");
|
super.visitMethodInsn(INVOKEVIRTUAL, className, view_constructor_method, "()V");
|
||||||
// stack: this
|
// stack: this
|
||||||
this.requireExtraStack = 2;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +344,6 @@ public class MappedObjectTransformer {
|
||||||
// stack: sizeof, target, this
|
// stack: sizeof, target, this
|
||||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "copy", "(L" + jvmClassName(MappedObject.class) + ";L" + jvmClassName(MappedObject.class) + ";I)V");
|
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "copy", "(L" + jvmClassName(MappedObject.class) + ";L" + jvmClassName(MappedObject.class) + ";I)V");
|
||||||
// stack: -
|
// stack: -
|
||||||
this.requireExtraStack = 3;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +355,6 @@ public class MappedObjectTransformer {
|
||||||
// stack: bytes, target, this
|
// stack: bytes, target, this
|
||||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "copy", "(L" + jvmClassName(MappedObject.class) + ";L" + jvmClassName(MappedObject.class) + ";I)V");
|
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "copy", "(L" + jvmClassName(MappedObject.class) + ";L" + jvmClassName(MappedObject.class) + ";I)V");
|
||||||
// stack: -
|
// stack: -
|
||||||
this.requireExtraStack = 4;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -488,7 +496,6 @@ public class MappedObjectTransformer {
|
||||||
// stack: int, long
|
// stack: int, long
|
||||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";");
|
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";");
|
||||||
// stack: buffer
|
// stack: buffer
|
||||||
this.requireExtraStack = 4;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,7 +512,6 @@ public class MappedObjectTransformer {
|
||||||
// stack: long, value
|
// stack: long, value
|
||||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), typeName.toLowerCase() + "put", "(" + typeName + "J)V");
|
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), typeName.toLowerCase() + "put", "(" + typeName + "J)V");
|
||||||
// stack -
|
// stack -
|
||||||
this.requireExtraStack = 4+(int)(mappedSubtype.fieldToLength.get(fieldName).longValue()>>2);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( opcode == GETFIELD ) {
|
if ( opcode == GETFIELD ) {
|
||||||
|
@ -518,7 +524,6 @@ public class MappedObjectTransformer {
|
||||||
// stack: long
|
// stack: long
|
||||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), typeName.toLowerCase() + "get", "(J)" + typeName);
|
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), typeName.toLowerCase() + "get", "(J)" + typeName);
|
||||||
// stack: value
|
// stack: value
|
||||||
this.requireExtraStack = 4;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,4 +581,59 @@ public class MappedObjectTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String exportConfiguration() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
for ( MappedSubtypeInfo info : className_to_subtype.values() ) {
|
||||||
|
sb.append("class\t" + info.className + "\t" + info.sizeof + "\t" + info.align + "\r\n");
|
||||||
|
|
||||||
|
for ( String fieldName : info.fieldToOffset.keySet() ) {
|
||||||
|
sb.append("field\t" + info.className + "\t" + fieldName + "\t" + info.fieldToOffset.get(fieldName) + "\t" + info.fieldToLength.get(fieldName) + "\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
className_to_subtype.clear();
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void importConfigation(String input) {
|
||||||
|
className_to_subtype.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
BufferedReader br = new BufferedReader(new StringReader(input));
|
||||||
|
|
||||||
|
while ( true ) {
|
||||||
|
String line = br.readLine();
|
||||||
|
if ( line == null )
|
||||||
|
break;
|
||||||
|
if ( (line = line.trim()).isEmpty() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
StringTokenizer st = new StringTokenizer(line, "\t");
|
||||||
|
|
||||||
|
String type = st.nextToken();
|
||||||
|
if ( type.equals("class") ) {
|
||||||
|
String className = st.nextToken();
|
||||||
|
int sizeof = Integer.parseInt(st.nextToken());
|
||||||
|
int align = Integer.parseInt(st.nextToken());
|
||||||
|
|
||||||
|
className_to_subtype.put(className, new MappedSubtypeInfo(className, sizeof, align));
|
||||||
|
} else if ( type.equals("field") ) {
|
||||||
|
MappedObjectTransformer.MappedSubtypeInfo info = className_to_subtype.get(st.nextToken());
|
||||||
|
String methodName = st.nextToken();
|
||||||
|
int off = Integer.parseInt(st.nextToken());
|
||||||
|
int len = Integer.parseInt(st.nextToken());
|
||||||
|
|
||||||
|
info.fieldToOffset.put(methodName, Long.valueOf(off));
|
||||||
|
info.fieldToLength.put(methodName, Long.valueOf(len));
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException exc) {
|
||||||
|
throw new IllegalStateException("never happens");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue