Converted sizeof and align to methods.
Override more methods in MappedObject subclasses, foreach is now 4 times faster.
This commit is contained in:
parent
20b9d3f89f
commit
896e363979
|
@ -60,8 +60,8 @@ public class MappedObjectTests1 {
|
|||
{
|
||||
MappedFloat vecs1 = MappedFloat.malloc(1234);
|
||||
|
||||
assert (vecs1.sizeof == MappedFloat.SIZEOF);
|
||||
assert (vecs1.sizeof * 1234 == vecs1.backingByteBuffer().capacity());
|
||||
assert (vecs1.getSizeof() == MappedFloat.SIZEOF);
|
||||
assert (vecs1.getSizeof() * 1234 == vecs1.backingByteBuffer().capacity());
|
||||
assert (MappedFloat.SIZEOF * 1234 == vecs1.backingByteBuffer().capacity());
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public class MappedObjectTests2 {
|
|||
|
||||
System.out.println(vecs.viewAddress); // test read-access
|
||||
|
||||
System.out.println(vecs.align); // test read-access
|
||||
System.out.println(vecs.getAlign()); // test read-access
|
||||
|
||||
System.out.println(MappedVec3.SIZEOF); // test read-access
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ public class MappedObjectTests2 {
|
|||
vecs.view = 1;
|
||||
long a2 = vecs.viewAddress;
|
||||
assert (a2 - a1 == MappedVec3.SIZEOF);
|
||||
assert (a2 - a1 == vecs.sizeof);
|
||||
assert (a2 - a1 == vecs.getSizeof());
|
||||
vecs.view = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ final class MappedForeach<T extends MappedObject> implements Iterable<T> {
|
|||
}
|
||||
|
||||
public T next() {
|
||||
MappedHelper.put_view(mapped, this.index++, mapped.sizeof);
|
||||
mapped.setViewAddress(mapped.getViewAddress(this.index++));
|
||||
return mapped;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,11 +55,9 @@ public class MappedHelper {
|
|||
|
||||
if ( LWJGLUtil.CHECKS && align <= 0 )
|
||||
throw new IllegalArgumentException("invalid alignment");
|
||||
mo.align = align;
|
||||
|
||||
if ( LWJGLUtil.CHECKS && (sizeof <= 0 || sizeof % align != 0) )
|
||||
throw new IllegalStateException("sizeof not a multiple of alignment");
|
||||
mo.sizeof = sizeof;
|
||||
|
||||
long addr = MemoryUtil.getAddress(buffer);
|
||||
if ( LWJGLUtil.CHECKS && addr % align != 0 )
|
||||
|
@ -107,8 +105,6 @@ public class MappedHelper {
|
|||
public static MappedObject dup(MappedObject src, MappedObject dst) {
|
||||
dst.baseAddress = src.baseAddress;
|
||||
dst.viewAddress = src.viewAddress;
|
||||
dst.align = src.align;
|
||||
dst.sizeof = src.sizeof;
|
||||
dst.preventGC = src.preventGC;
|
||||
return dst;
|
||||
}
|
||||
|
@ -116,8 +112,6 @@ public class MappedHelper {
|
|||
public static MappedObject slice(MappedObject src, MappedObject dst) {
|
||||
dst.baseAddress = src.viewAddress; // !
|
||||
dst.viewAddress = src.viewAddress;
|
||||
dst.align = src.align;
|
||||
dst.sizeof = src.sizeof;
|
||||
dst.preventGC = src.preventGC;
|
||||
return dst;
|
||||
}
|
||||
|
|
|
@ -50,11 +50,11 @@ import java.nio.ByteBuffer;
|
|||
*
|
||||
* @author Riven
|
||||
*/
|
||||
public class MappedObject {
|
||||
public abstract class MappedObject {
|
||||
|
||||
static final boolean CHECKS = LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.Checks");
|
||||
|
||||
public MappedObject() {
|
||||
protected MappedObject() {
|
||||
//
|
||||
}
|
||||
|
||||
|
@ -64,11 +64,8 @@ public class MappedObject {
|
|||
/** The mapped object view memory address, in bytes. Read-only. */
|
||||
public long viewAddress;
|
||||
|
||||
/** The mapped object memory alignment, in bytes. Read-only. */
|
||||
public int align;
|
||||
|
||||
/** The mapped object memory sizeof, in bytes. Read-only. */
|
||||
public int sizeof;
|
||||
/** The mapped buffer. */
|
||||
ByteBuffer preventGC;
|
||||
|
||||
/**
|
||||
* Holds the value of sizeof of the sub-type of this MappedObject<br>
|
||||
|
@ -87,6 +84,12 @@ public class MappedObject {
|
|||
*/
|
||||
public int view;
|
||||
|
||||
protected final long getViewAddress(final int view) {
|
||||
// No call-site modification for this, we override in every subclass instead,
|
||||
// so that we can use it in MappedForeach.
|
||||
throw new InternalError("type not registered");
|
||||
}
|
||||
|
||||
public final void setViewAddress(final long address) {
|
||||
if ( CHECKS )
|
||||
checkAddress(address);
|
||||
|
@ -96,8 +99,8 @@ public class MappedObject {
|
|||
final void checkAddress(final long address) {
|
||||
final long base = MemoryUtil.getAddress0(preventGC);
|
||||
final int offset = (int)(address - base);
|
||||
if ( address < base || preventGC.capacity() < (offset + this.sizeof) )
|
||||
throw new IndexOutOfBoundsException(Integer.toString(offset / sizeof));
|
||||
if ( address < base || preventGC.capacity() < (offset + getSizeof()) )
|
||||
throw new IndexOutOfBoundsException(Integer.toString(offset / getSizeof()));
|
||||
}
|
||||
|
||||
final void checkRange(final int bytes) {
|
||||
|
@ -108,6 +111,27 @@ public class MappedObject {
|
|||
throw new BufferOverflowException();
|
||||
}
|
||||
|
||||
/** The mapped object memory alignment, in bytes. Read-only. */
|
||||
/**
|
||||
* Returns the mapped object memory alignment, in bytes.
|
||||
*
|
||||
* @return the memory alignment
|
||||
*/
|
||||
public final int getAlign() {
|
||||
// No call-site modification for this, we override in every subclass instead.
|
||||
throw new InternalError("type not registered");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapped object memory sizeof, in bytes.
|
||||
*
|
||||
* @return the sizeof value
|
||||
*/
|
||||
public final int getSizeof() {
|
||||
// No call-site modification for this, we override in every subclass instead.
|
||||
throw new InternalError("type not registered");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MappedObject instance, mapping the memory region of the specified direct ByteBuffer.
|
||||
* <p/>
|
||||
|
@ -178,22 +202,18 @@ public class MappedObject {
|
|||
* Any code in the default constructor will not run automatically. This method
|
||||
* can be used to run execute that code on the current view.
|
||||
*/
|
||||
public final <T extends MappedObject> void runViewConstructor() {
|
||||
public final void runViewConstructor() {
|
||||
// any method that calls this method will have its call-site modified
|
||||
throw new InternalError("type not registered");
|
||||
}
|
||||
|
||||
/** Moves the current view to the next element. */
|
||||
public final void next() {
|
||||
// any method that calls this method will have its call-site modified
|
||||
// No call-site modification for this, we override in every subclass instead,
|
||||
// so that we can use it in MappedSetX.
|
||||
throw new InternalError("type not registered");
|
||||
}
|
||||
|
||||
/** Moves the current view to the next element. Non-transformed implementation for MappedSets. */
|
||||
final void nextSet() {
|
||||
setViewAddress(viewAddress + sizeof);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies and amount of <code>SIZEOF</code> bytes, from the current
|
||||
* mapped object, to the specified mapped object.
|
||||
|
@ -232,14 +252,12 @@ public class MappedObject {
|
|||
throw new InternalError("type not registered");
|
||||
}
|
||||
|
||||
ByteBuffer preventGC;
|
||||
|
||||
/**
|
||||
* Returns the {@link java.nio.ByteBuffer} that backs this mapped object.
|
||||
*
|
||||
* @return the backing buffer
|
||||
*/
|
||||
public ByteBuffer backingByteBuffer() {
|
||||
public final ByteBuffer backingByteBuffer() {
|
||||
return this.preventGC;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,9 @@ public class MappedObjectClassLoader extends URLClassLoader {
|
|||
FORKED = true;
|
||||
|
||||
try {
|
||||
URLClassLoader loader = new MappedObjectClassLoader(mainClass);
|
||||
MappedObjectClassLoader loader = new MappedObjectClassLoader(mainClass);
|
||||
loader.loadMappedObject();
|
||||
|
||||
Class<?> replacedMainClass = loader.loadClass(mainClass.getName());
|
||||
Method mainMethod = replacedMainClass.getMethod("main", String[].class);
|
||||
mainMethod.invoke(null, new Object[] { args });
|
||||
|
@ -90,6 +92,28 @@ public class MappedObjectClassLoader extends URLClassLoader {
|
|||
super(((URLClassLoader)mainClass.getClassLoader()).getURLs());
|
||||
}
|
||||
|
||||
protected synchronized Class<?> loadMappedObject() throws ClassNotFoundException {
|
||||
final String name = MappedObject.class.getName();
|
||||
String className = name.replace('.', '/');
|
||||
|
||||
if ( MappedObjectTransformer.PRINT_ACTIVITY )
|
||||
LWJGLUtil.log(MappedObjectClassLoader.class.getSimpleName() + ": " + className);
|
||||
|
||||
byte[] bytecode = readStream(this.getResourceAsStream(className.concat(".class")));
|
||||
|
||||
long t0 = System.nanoTime();
|
||||
bytecode = MappedObjectTransformer.transformMappedObject(bytecode);
|
||||
long t1 = System.nanoTime();
|
||||
total_time_transforming += (t1 - t0);
|
||||
|
||||
if ( MappedObjectTransformer.PRINT_TIMING )
|
||||
LWJGLUtil.log("transforming " + className + " took " + (t1 - t0) / 1000 + " micros (total: " + (total_time_transforming / 1000 / 1000) + "ms)");
|
||||
|
||||
Class<?> clazz = super.defineClass(name, bytecode, 0, bytecode.length);
|
||||
resolveClass(clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
private static long total_time_transforming;
|
||||
|
||||
@Override
|
||||
|
@ -104,10 +128,8 @@ public class MappedObjectClassLoader extends URLClassLoader {
|
|||
if ( name.startsWith("sunw.") )
|
||||
return super.loadClass(name, resolve);
|
||||
|
||||
// never transform classes in this very package, sub-packages should be transformed
|
||||
if ( name.startsWith(MAPPEDOBJECT_PACKAGE_PREFIX) )
|
||||
if ( name.substring(MAPPEDOBJECT_PACKAGE_PREFIX.length()).indexOf('.') == -1 )
|
||||
return super.loadClass(name, resolve);
|
||||
if ( name.equals(MappedObjectClassLoader.class.getName()) )
|
||||
return super.loadClass(name, resolve);
|
||||
|
||||
String className = name.replace('.', '/');
|
||||
|
||||
|
@ -116,13 +138,16 @@ public class MappedObjectClassLoader extends URLClassLoader {
|
|||
|
||||
byte[] bytecode = readStream(this.getResourceAsStream(className.concat(".class")));
|
||||
|
||||
long t0 = System.nanoTime();
|
||||
bytecode = MappedObjectTransformer.transformMappedAPI(className, bytecode);
|
||||
long t1 = System.nanoTime();
|
||||
total_time_transforming += (t1 - t0);
|
||||
// Classes in this package do not get transformed, but need to go through here because we have transformed MappedObject.
|
||||
if ( !(name.startsWith(MAPPEDOBJECT_PACKAGE_PREFIX) && name.substring(MAPPEDOBJECT_PACKAGE_PREFIX.length()).indexOf('.') == -1) ) {
|
||||
long t0 = System.nanoTime();
|
||||
bytecode = MappedObjectTransformer.transformMappedAPI(className, bytecode);
|
||||
long t1 = System.nanoTime();
|
||||
|
||||
if ( MappedObjectTransformer.PRINT_TIMING )
|
||||
LWJGLUtil.log("transforming " + className + " took " + (t1 - t0) / 1000 + " micros (total: " + (total_time_transforming / 1000 / 1000) + "ms)");
|
||||
total_time_transforming += (t1 - t0);
|
||||
if ( MappedObjectTransformer.PRINT_TIMING )
|
||||
LWJGLUtil.log("transforming " + className + " took " + (t1 - t0) / 1000 + " micros (total: " + (total_time_transforming / 1000 / 1000) + "ms)");
|
||||
}
|
||||
|
||||
Class<?> clazz = super.defineClass(name, bytecode, 0, bytecode.length);
|
||||
if ( resolve )
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.lwjgl.LWJGLUtil;
|
|||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.tree.*;
|
||||
import org.objectweb.asm.tree.analysis.*;
|
||||
import org.objectweb.asm.tree.analysis.Frame;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
@ -76,9 +77,15 @@ public class MappedObjectTransformer {
|
|||
static final String MAPPED_SET3_JVM = jvmClassName(MappedSet3.class);
|
||||
static final String MAPPED_SET4_JVM = jvmClassName(MappedSet4.class);
|
||||
|
||||
static final String LENGTH_METHOD_NAME = "length$LWJGL";
|
||||
static final String VIEWADDRESS_METHOD_NAME = "getViewAddress$LWJGL";
|
||||
static final String VIEW_CONSTRUCTOR_NAME = "constructView$LWJGL";
|
||||
// Public methods
|
||||
static final String VIEWADDRESS_METHOD_NAME = "getViewAddress";
|
||||
static final String NEXT_METHOD_NAME = "next";
|
||||
static final String ALIGN_METHOD_NAME = "getAlign";
|
||||
static final String SIZEOF_METHOD_NAME = "getSizeof";
|
||||
|
||||
// Internal methods
|
||||
static final String LENGTH_METHOD_NAME = "length$LWJGL"; // Used for .asArray().length
|
||||
static final String VIEW_CONSTRUCTOR_NAME = "constructView$LWJGL"; // Used by runViewConstructor
|
||||
|
||||
static final Map<Integer, String> OPCODE_TO_NAME = new HashMap<Integer, String>();
|
||||
static final Map<Integer, String> INSNTYPE_TO_NAME = new HashMap<Integer, String>();
|
||||
|
@ -122,9 +129,6 @@ public class MappedObjectTransformer {
|
|||
* @param type the mapped object class.
|
||||
*/
|
||||
public static void register(Class<?> type) {
|
||||
if ( MappedObjectClassLoader.FORKED )
|
||||
return;
|
||||
|
||||
final MappedType mapped = type.getAnnotation(MappedType.class);
|
||||
if ( mapped == null )
|
||||
throw new InternalError("missing " + MappedType.class.getName() + " annotation");
|
||||
|
@ -185,6 +189,34 @@ public class MappedObjectTransformer {
|
|||
return (int)byteLength;
|
||||
}
|
||||
|
||||
/** Removes final from methods that will be overriden by subclasses. */
|
||||
static byte[] transformMappedObject(byte[] bytecode) {
|
||||
final ClassWriter cw = new ClassWriter(0);
|
||||
|
||||
ClassVisitor cv = new ClassAdapter(cw) {
|
||||
|
||||
private final String[] DEFINALIZE_LIST = {
|
||||
VIEWADDRESS_METHOD_NAME,
|
||||
NEXT_METHOD_NAME,
|
||||
ALIGN_METHOD_NAME,
|
||||
SIZEOF_METHOD_NAME,
|
||||
};
|
||||
|
||||
public MethodVisitor visitMethod(int access, final String name, final String desc, final String signature, final String[] exceptions) {
|
||||
for ( String method : DEFINALIZE_LIST ) {
|
||||
if ( name.equals(method) ) {
|
||||
access &= ~ACC_FINAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
};
|
||||
|
||||
new ClassReader(bytecode).accept(cv, 0);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
static byte[] transformMappedAPI(final String className, byte[] bytecode) {
|
||||
final ClassWriter cw = new ClassWriter(COMPUTE_FRAMES) {
|
||||
|
||||
|
@ -203,8 +235,7 @@ public class MappedObjectTransformer {
|
|||
if ( className_to_subtype.containsKey(className) ) // Do a first pass to generate address getters
|
||||
cv = getMethodGenAdapter(className, cv);
|
||||
|
||||
//cr.accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
new ClassReader(bytecode).accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
new ClassReader(bytecode).accept(cv, ClassReader.SKIP_FRAMES);
|
||||
bytecode = cw.toByteArray();
|
||||
|
||||
if ( PRINT_BYTECODE )
|
||||
|
@ -218,10 +249,13 @@ public class MappedObjectTransformer {
|
|||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
|
||||
|
||||
generateViewAddressGetter();
|
||||
generateLengthGetter();
|
||||
|
||||
final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
|
||||
generateAlignGetter(mappedSubtype);
|
||||
generateSizeofGetter();
|
||||
generateNext();
|
||||
|
||||
for ( String fieldName : mappedSubtype.fieldToOffset.keySet() ) {
|
||||
final Type type = mappedSubtype.fieldToType.get(fieldName);
|
||||
|
@ -238,7 +272,7 @@ public class MappedObjectTransformer {
|
|||
}
|
||||
|
||||
private void generateViewAddressGetter() {
|
||||
MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, VIEWADDRESS_METHOD_NAME, "(L" + className + ";I)J", null, null);
|
||||
MethodVisitor mv = super.visitMethod(ACC_PUBLIC, VIEWADDRESS_METHOD_NAME, "(I)J", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, MAPPED_OBJECT_JVM, "baseAddress", "J");
|
||||
|
@ -266,7 +300,7 @@ public class MappedObjectTransformer {
|
|||
MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, LENGTH_METHOD_NAME, "(L" + className + ";)I", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, className, "backingByteBuffer", "()L" + jvmClassName(ByteBuffer.class) + ";");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, MAPPED_OBJECT_JVM, "backingByteBuffer", "()L" + jvmClassName(ByteBuffer.class) + ";");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, jvmClassName(ByteBuffer.class), "capacity", "()I");
|
||||
mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
|
||||
mv.visitInsn(IDIV);
|
||||
|
@ -275,12 +309,45 @@ public class MappedObjectTransformer {
|
|||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private void generateAlignGetter(final MappedSubtypeInfo mappedSubtype) {
|
||||
MethodVisitor mv = super.visitMethod(ACC_PUBLIC, ALIGN_METHOD_NAME, "()I", null, null);
|
||||
mv.visitCode();
|
||||
visitIntNode(mv, mappedSubtype.sizeof);
|
||||
mv.visitInsn(IRETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private void generateSizeofGetter() {
|
||||
MethodVisitor mv = super.visitMethod(ACC_PUBLIC, SIZEOF_METHOD_NAME, "()I", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
|
||||
mv.visitInsn(IRETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private void generateNext() {
|
||||
MethodVisitor mv = super.visitMethod(ACC_PUBLIC, NEXT_METHOD_NAME, "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitFieldInsn(GETFIELD, MAPPED_OBJECT_JVM, "viewAddress", "J");
|
||||
mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
|
||||
mv.visitInsn(I2L);
|
||||
mv.visitInsn(LADD);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, className, "setViewAddress", "(J)V");
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private void generateByteBufferGetter(final MappedSubtypeInfo mappedSubtype, final String fieldName, final Type type) {
|
||||
MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, getterName(fieldName), "(L" + className + ";I)" + type.getDescriptor(), null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ILOAD, 1);
|
||||
mv.visitMethodInsn(INVOKESTATIC, className, VIEWADDRESS_METHOD_NAME, "(L" + className + ";I)J");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
|
||||
visitIntNode(mv, mappedSubtype.fieldToOffset.get(fieldName).intValue());
|
||||
mv.visitInsn(I2L);
|
||||
mv.visitInsn(LADD);
|
||||
|
@ -296,13 +363,13 @@ public class MappedObjectTransformer {
|
|||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ILOAD, 1);
|
||||
mv.visitMethodInsn(INVOKESTATIC, className, VIEWADDRESS_METHOD_NAME, "(L" + className + ";I)J");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
|
||||
visitIntNode(mv, mappedSubtype.fieldToOffset.get(fieldName).intValue());
|
||||
mv.visitInsn(I2L);
|
||||
mv.visitInsn(LADD);
|
||||
mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, type.getDescriptor().toLowerCase() + "get", "(J)" + type.getDescriptor());
|
||||
mv.visitInsn(type.getOpcode(IRETURN));
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitMaxs(3, 2);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
|
@ -331,13 +398,13 @@ public class MappedObjectTransformer {
|
|||
mv.visitVarInsn(load, 2);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ILOAD, 1);
|
||||
mv.visitMethodInsn(INVOKESTATIC, className, VIEWADDRESS_METHOD_NAME, "(L" + className + ";I)J");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
|
||||
visitIntNode(mv, mappedSubtype.fieldToOffset.get(fieldName).intValue());
|
||||
mv.visitInsn(I2L);
|
||||
mv.visitInsn(LADD);
|
||||
mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, type.getDescriptor().toLowerCase() + "put", "(" + type.getDescriptor() + "J)V");
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitMaxs(4, 3);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
|
@ -415,12 +482,14 @@ public class MappedObjectTransformer {
|
|||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if ( needsTransformation ) // Early-out for methods that do not touch a mapped object.
|
||||
if ( needsTransformation ) { // Early-out for methods that do not touch a mapped object.
|
||||
//System.err.println("\nTRANSFORMING: " + className + "." + name + desc);
|
||||
try {
|
||||
transformMethod(analyse());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass the instruction stream to the adapter's MethodVisitor
|
||||
accept(mv);
|
||||
|
@ -433,8 +502,6 @@ public class MappedObjectTransformer {
|
|||
}
|
||||
|
||||
private void transformMethod(final Frame<BasicValue>[] frames) {
|
||||
//System.err.println("\nTRANSFORMING: " + className + " - " + name + desc);
|
||||
|
||||
final InsnList instructions = this.instructions;
|
||||
|
||||
final Map<Integer, MappedSubtypeInfo> arrayVars = new HashMap<Integer, MappedSubtypeInfo>();
|
||||
|
@ -540,10 +607,6 @@ public class MappedObjectTransformer {
|
|||
break;
|
||||
}
|
||||
|
||||
if ( "next".equals(methodInsn.name) && "()V".equals(methodInsn.desc) ) {
|
||||
i = replace(instructions, i, methodInsn, generateNextInstructions(mappedType));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case INVOKESPECIAL:
|
||||
// super() in VIEW_CONSTRUCTOR_NAME, remove
|
||||
|
@ -567,18 +630,6 @@ public class MappedObjectTransformer {
|
|||
return i;
|
||||
}
|
||||
|
||||
private static InsnList generateNextInstructions(final MappedSubtypeInfo mappedType) {
|
||||
final InsnList list = new InsnList();
|
||||
|
||||
// stack: this
|
||||
list.add(getIntNode(mappedType.sizeof));
|
||||
// stack: sizeof, this
|
||||
list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_view_next", "(L" + MAPPED_OBJECT_JVM + ";I)V"));
|
||||
// stack: -
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static InsnList generateCopyRangeInstructions(final MappedSubtypeInfo mappedType) {
|
||||
final InsnList list = new InsnList();
|
||||
|
||||
|
@ -705,9 +756,6 @@ public class MappedObjectTransformer {
|
|||
if ( "view".equals(fieldInsn.name) )
|
||||
return generateViewInstructions(fieldInsn, mappedSubtype);
|
||||
|
||||
if ( "align".equals(fieldInsn.name) || "sizeof".equals(fieldInsn.name) )
|
||||
return generateAlignSizeofInstructions(fieldInsn, mappedSubtype);
|
||||
|
||||
if ( "baseAddress".equals(fieldInsn.name) || "viewAddress".equals(fieldInsn.name) ) {
|
||||
return generateAddressInstructions(fieldInsn);
|
||||
}
|
||||
|
@ -806,29 +854,6 @@ public class MappedObjectTransformer {
|
|||
throw new InternalError();
|
||||
}
|
||||
|
||||
private static InsnList generateAlignSizeofInstructions(final FieldInsnNode fieldInsn, final MappedSubtypeInfo mappedSubtype) {
|
||||
if ( !"I".equals(fieldInsn.desc) )
|
||||
throw new InternalError();
|
||||
|
||||
if ( fieldInsn.getOpcode() == GETFIELD ) {
|
||||
final InsnList list = new InsnList();
|
||||
|
||||
// stack: instance
|
||||
list.add(new InsnNode(POP));
|
||||
// stack: -
|
||||
if ( "sizeof".equals(fieldInsn.name) )
|
||||
list.add(getIntNode(mappedSubtype.sizeof));
|
||||
else if ( "align".equals(fieldInsn.name) )
|
||||
list.add(getIntNode(mappedSubtype.align));
|
||||
// stack: int
|
||||
return list;
|
||||
}
|
||||
|
||||
if ( fieldInsn.getOpcode() == PUTFIELD )
|
||||
throwAccessErrorOnReadOnlyField(fieldInsn.owner, fieldInsn.name);
|
||||
throw new InternalError();
|
||||
}
|
||||
|
||||
private static InsnList generateAddressInstructions(final FieldInsnNode fieldInsn) {
|
||||
if ( !"J".equals(fieldInsn.desc) )
|
||||
throw new IllegalStateException();
|
||||
|
@ -961,7 +986,7 @@ public class MappedObjectTransformer {
|
|||
nextInsn = getter;
|
||||
continue;
|
||||
} else if ( stackSize < loadStackSize )
|
||||
throw new ClassFormatError("Invalid .asArray() usage detected: " + getOpcodeName(nextInsn));
|
||||
throw new ClassFormatError("Invalid " + mappedSubtype.className + " view array usage detected: " + getOpcodeName(nextInsn));
|
||||
}
|
||||
|
||||
instructions.remove(aaLoadInsn);
|
||||
|
|
|
@ -44,13 +44,13 @@ public class MappedSet2 {
|
|||
public int view;
|
||||
|
||||
void view(int view) {
|
||||
MappedHelper.put_view(this.a, view, this.a.sizeof);
|
||||
MappedHelper.put_view(this.b, view, this.b.sizeof);
|
||||
a.setViewAddress(a.getViewAddress(view));
|
||||
b.setViewAddress(b.getViewAddress(view));
|
||||
}
|
||||
|
||||
public void next() {
|
||||
this.a.nextSet();
|
||||
this.b.nextSet();
|
||||
this.a.next();
|
||||
this.b.next();
|
||||
}
|
||||
|
||||
}
|
|
@ -45,15 +45,15 @@ public class MappedSet3 {
|
|||
public int view;
|
||||
|
||||
void view(int view) {
|
||||
MappedHelper.put_view(this.a, view, this.a.sizeof);
|
||||
MappedHelper.put_view(this.b, view, this.b.sizeof);
|
||||
MappedHelper.put_view(this.c, view, this.c.sizeof);
|
||||
a.setViewAddress(a.getViewAddress(view));
|
||||
b.setViewAddress(b.getViewAddress(view));
|
||||
c.setViewAddress(c.getViewAddress(view));
|
||||
}
|
||||
|
||||
public void next() {
|
||||
this.a.nextSet();
|
||||
this.b.nextSet();
|
||||
this.c.nextSet();
|
||||
this.a.next();
|
||||
this.b.next();
|
||||
this.c.next();
|
||||
}
|
||||
|
||||
}
|
|
@ -46,16 +46,16 @@ public class MappedSet4 {
|
|||
public int view;
|
||||
|
||||
void view(int view) {
|
||||
MappedHelper.put_view(this.a, view, this.a.sizeof);
|
||||
MappedHelper.put_view(this.b, view, this.b.sizeof);
|
||||
MappedHelper.put_view(this.c, view, this.c.sizeof);
|
||||
MappedHelper.put_view(this.d, view, this.d.sizeof);
|
||||
a.setViewAddress(a.getViewAddress(view));
|
||||
b.setViewAddress(b.getViewAddress(view));
|
||||
c.setViewAddress(c.getViewAddress(view));
|
||||
d.setViewAddress(d.getViewAddress(view));
|
||||
}
|
||||
|
||||
public void next() {
|
||||
this.a.nextSet();
|
||||
this.b.nextSet();
|
||||
this.c.nextSet();
|
||||
this.d.nextSet();
|
||||
this.a.next();
|
||||
this.b.next();
|
||||
this.c.next();
|
||||
this.d.next();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue