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