Implemented .next() with bytecode transformation, 4x faster now.
Made method transformation a bit faster.
This commit is contained in:
parent
5949d57bb1
commit
b09625557d
|
@ -89,6 +89,15 @@ public class MappedObjectTests1 {
|
|||
vecs.view = 0;
|
||||
}
|
||||
|
||||
// manipulate 'view' with next()
|
||||
{
|
||||
assert (vecs.view == 0);
|
||||
vecs.next();
|
||||
assert (vecs.view == 1);
|
||||
assert (vecs.value != 1.1f); // old view
|
||||
vecs.view = 0;
|
||||
}
|
||||
|
||||
// test bounds checking
|
||||
{
|
||||
assert (vecs.view == 0);
|
||||
|
|
|
@ -87,6 +87,10 @@ public class MappedHelper {
|
|||
return (int)(mapped.viewAddress - mapped.baseAddress) / sizeof;
|
||||
}
|
||||
|
||||
public static void put_view_next(MappedObject mapped, int sizeof) {
|
||||
mapped.setViewAddress(mapped.viewAddress + sizeof);
|
||||
}
|
||||
|
||||
public static MappedObject dup(MappedObject src, MappedObject dst) {
|
||||
dst.baseAddress = src.baseAddress;
|
||||
dst.viewAddress = src.viewAddress;
|
||||
|
|
|
@ -86,12 +86,7 @@ public class MappedObject {
|
|||
*/
|
||||
public int view;
|
||||
|
||||
/** Moves the current view to the next element. */
|
||||
public final void next() {
|
||||
setViewAddress(this.viewAddress + this.sizeof);
|
||||
}
|
||||
|
||||
final void setViewAddress(final long address) {
|
||||
public final void setViewAddress(final long address) {
|
||||
if ( CHECKS )
|
||||
checkAddress(address);
|
||||
this.viewAddress = address;
|
||||
|
@ -99,8 +94,9 @@ public class MappedObject {
|
|||
|
||||
final void checkAddress(final long address) {
|
||||
final long base = MappedObjectUnsafe.getBufferBaseAddress(preventGC);
|
||||
if ( address < base || preventGC.capacity() < (address - base + this.sizeof) )
|
||||
throw new IndexOutOfBoundsException();
|
||||
final int offset = (int)(address - base);
|
||||
if ( address < base || preventGC.capacity() < (offset + this.sizeof) )
|
||||
throw new IndexOutOfBoundsException(Integer.toString(offset / sizeof));
|
||||
}
|
||||
|
||||
final void checkRange(final int bytes) {
|
||||
|
@ -186,6 +182,12 @@ public class MappedObject {
|
|||
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
|
||||
throw new InternalError("type not registered");
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies and amount of <code>SIZEOF</code> bytes, from the current
|
||||
* mapped object, to the specified mapped object.
|
||||
|
|
|
@ -38,6 +38,9 @@ public class MappedObjectTransformer {
|
|||
|
||||
static final Map<String, MappedSubtypeInfo> className_to_subtype;
|
||||
|
||||
static final String MAPPED_OBJECT_JVM = jvmClassName(MappedObject.class);
|
||||
static final String MAPPED_HELPER_JVM = jvmClassName(MappedHelper.class);
|
||||
|
||||
static {
|
||||
className_to_subtype = new HashMap<String, MappedSubtypeInfo>();
|
||||
|
||||
|
@ -56,7 +59,7 @@ public class MappedObjectTransformer {
|
|||
// => IADD
|
||||
// => PUTFIELD MyMappedType.view
|
||||
//
|
||||
MappedSubtypeInfo info = new MappedSubtypeInfo(jvmClassName(MappedObject.class), -1, -1);
|
||||
MappedSubtypeInfo info = new MappedSubtypeInfo(MAPPED_OBJECT_JVM, -1, -1);
|
||||
className_to_subtype.put(info.className, info);
|
||||
}
|
||||
|
||||
|
@ -162,7 +165,7 @@ public class MappedObjectTransformer {
|
|||
{
|
||||
MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
|
||||
|
||||
if ( mappedSubtype != null && !mappedSubtype.className.equals(jvmClassName(MappedObject.class)) ) {
|
||||
if ( mappedSubtype != null && !mappedSubtype.className.equals(MAPPED_OBJECT_JVM) ) {
|
||||
if ( "<init>".equals(name) ) {
|
||||
if ( !"()V".equals(desc) )
|
||||
throw new IllegalStateException(className + " can only have a default constructor, found: " + desc);
|
||||
|
@ -170,7 +173,7 @@ public class MappedObjectTransformer {
|
|||
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, jvmClassName(MappedObject.class), "<init>", "()V");
|
||||
mv.visitMethodInsn(INVOKESPECIAL, MAPPED_OBJECT_JVM, "<init>", "()V");
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
|
@ -181,7 +184,7 @@ public class MappedObjectTransformer {
|
|||
}
|
||||
}
|
||||
|
||||
return new MappedInstanceMethodAdapter(className, name, desc, super.visitMethod(access, name, desc, signature, exceptions));
|
||||
return new MappedInstanceMethodAdapter(access, className, name, desc, super.visitMethod(access, name, desc, signature, exceptions));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -252,17 +255,25 @@ public class MappedObjectTransformer {
|
|||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String className, String methodName, String signature) {
|
||||
if ( opcode == INVOKESPECIAL && className.equals(jvmClassName(MappedObject.class)) && "<init>".equals(methodName) && "()V".equals(signature) ) {
|
||||
if ( opcode == INVOKESPECIAL && className.equals(MAPPED_OBJECT_JVM) && "<init>".equals(methodName) && "()V".equals(signature) ) {
|
||||
// stack: instance
|
||||
visitInsn(POP);
|
||||
// stack: -
|
||||
return;
|
||||
}
|
||||
|
||||
for ( MappedSubtypeInfo mappedType : className_to_subtype.values() ) {
|
||||
boolean isMapDirectMethod = (opcode == INVOKESTATIC && "map".equals(methodName) && className.equals(mappedType.className) && signature.equals("(JI)L" + jvmClassName(MappedObject.class) + ";"));
|
||||
boolean isMapBufferMethod = (opcode == INVOKESTATIC && "map".equals(methodName) && className.equals(mappedType.className) && signature.equals("(Ljava/nio/ByteBuffer;)L" + jvmClassName(MappedObject.class) + ";"));
|
||||
boolean isMallocMethod = (opcode == INVOKESTATIC && "malloc".equals(methodName) && className.equals(mappedType.className) && signature.equals("(I)L" + jvmClassName(MappedObject.class) + ";"));
|
||||
MappedSubtypeInfo mappedType = className_to_subtype.get(className);
|
||||
if ( mappedType != null && visitMappedMethod(opcode, className, methodName, signature, mappedType) )
|
||||
return;
|
||||
|
||||
super.visitMethodInsn(opcode, className, methodName, signature);
|
||||
}
|
||||
|
||||
private boolean visitMappedMethod(final int opcode, final String className, final String methodName, final String signature, final MappedSubtypeInfo mappedType) {
|
||||
if ( opcode == INVOKESTATIC ) {
|
||||
boolean isMapDirectMethod = "map".equals(methodName) && signature.equals("(JI)L" + MAPPED_OBJECT_JVM + ";");
|
||||
boolean isMapBufferMethod = "map".equals(methodName) && signature.equals("(Ljava/nio/ByteBuffer;)L" + MAPPED_OBJECT_JVM + ";");
|
||||
boolean isMallocMethod = "malloc".equals(methodName) && signature.equals("(I)L" + MAPPED_OBJECT_JVM + ";");
|
||||
|
||||
if ( (isMapDirectMethod || isMapBufferMethod) || isMallocMethod ) {
|
||||
if ( isMallocMethod ) {
|
||||
|
@ -275,7 +286,7 @@ public class MappedObjectTransformer {
|
|||
// stack: buffer
|
||||
} else if ( isMapDirectMethod ) {
|
||||
// stack: capacity, address
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";");
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";");
|
||||
// stack: buffer
|
||||
}
|
||||
|
||||
|
@ -294,12 +305,12 @@ public class MappedObjectTransformer {
|
|||
// stack: int, buffer, new, new
|
||||
pushInt(super.mv, mappedType.sizeof);
|
||||
// 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, MAPPED_HELPER_JVM, "setup", "(L" + MAPPED_OBJECT_JVM + ";Ljava/nio/ByteBuffer;II)V");
|
||||
// stack: new
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( opcode == INVOKEVIRTUAL && "dup".equals(methodName) && className.equals(mappedType.className) && signature.equals("()L" + jvmClassName(MappedObject.class) + ";") ) {
|
||||
} else if ( opcode == INVOKEVIRTUAL ) {
|
||||
if ( "dup".equals(methodName) && signature.equals("()L" + MAPPED_OBJECT_JVM + ";") ) {
|
||||
// stack: this
|
||||
super.visitTypeInsn(NEW, className);
|
||||
// stack: new, this
|
||||
|
@ -307,12 +318,12 @@ public class MappedObjectTransformer {
|
|||
// stack: new, new, this
|
||||
super.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V");
|
||||
// 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, MAPPED_HELPER_JVM, "dup", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";)L" + MAPPED_OBJECT_JVM + ";");
|
||||
// stack: new
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( opcode == INVOKEVIRTUAL && "slice".equals(methodName) && className.equals(mappedType.className) && signature.equals("()L" + jvmClassName(MappedObject.class) + ";") ) {
|
||||
if ( "slice".equals(methodName) && signature.equals("()L" + MAPPED_OBJECT_JVM + ";") ) {
|
||||
// stack: this
|
||||
super.visitTypeInsn(NEW, className);
|
||||
// stack: new, this
|
||||
|
@ -320,46 +331,55 @@ public class MappedObjectTransformer {
|
|||
// stack: new, new, this
|
||||
super.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V");
|
||||
// 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, MAPPED_HELPER_JVM, "slice", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";)L" + MAPPED_OBJECT_JVM + ";");
|
||||
// stack: new
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
if ( opcode == INVOKEVIRTUAL && "runViewConstructor".equals(methodName) && className.equals(mappedType.className) && "()V".equals(signature) ) {
|
||||
if ( "runViewConstructor".equals(methodName) && "()V".equals(signature) ) {
|
||||
// stack: this
|
||||
super.visitInsn(DUP);
|
||||
// stack: this, this
|
||||
super.visitMethodInsn(INVOKEVIRTUAL, className, view_constructor_method, "()V");
|
||||
// stack: this
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
if ( opcode == INVOKEVIRTUAL && "copyTo".equals(methodName) && className.equals(mappedType.className) && signature.equals("(L" + jvmClassName(MappedObject.class) + ";)V") ) {
|
||||
if ( "copyTo".equals(methodName) && signature.equals("(L" + MAPPED_OBJECT_JVM + ";)V") ) {
|
||||
// stack: target, this
|
||||
pushInt(super.mv, mappedType.sizeof);
|
||||
// stack: sizeof, target, this
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "copy", "(L" + jvmClassName(MappedObject.class) + ";L" + jvmClassName(MappedObject.class) + ";I)V");
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "copy", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";I)V");
|
||||
// stack: -
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( opcode == INVOKEVIRTUAL && "copyRange".equals(methodName) && className.equals(mappedType.className) && signature.equals("(L" + jvmClassName(MappedObject.class) + ";I)V") ) {
|
||||
if ( "copyRange".equals(methodName) && signature.equals("(L" + MAPPED_OBJECT_JVM + ";I)V") ) {
|
||||
// stack: instances, target, this
|
||||
pushInt(super.mv, mappedType.sizeof);
|
||||
// stack: sizeof, instances, target, this
|
||||
super.visitInsn(IMUL);
|
||||
// stack: bytes, target, this
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "copy", "(L" + jvmClassName(MappedObject.class) + ";L" + jvmClassName(MappedObject.class) + ";I)V");
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "copy", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";I)V");
|
||||
// stack: -
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( "next".equals(methodName) && "()V".equals(signature) ) {
|
||||
// stack: this
|
||||
pushInt(super.mv, mappedType.sizeof);
|
||||
// stack: sizeof, this
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "put_view_next", "(L" + MAPPED_OBJECT_JVM + ";I)V");
|
||||
// stack: -
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
super.visitMethodInsn(opcode, className, methodName, signature);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void throwAccessErrorOnReadOnlyField(String className, String fieldName) {
|
||||
|
@ -384,11 +404,11 @@ public class MappedObjectTransformer {
|
|||
if ( false )
|
||||
break outer;
|
||||
else if ( className.equals(jvmClassName(MappedSet2.class)) )
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "put_views", "(L" + jvmClassName(MappedSet2.class) + ";I)V");
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "put_views", "(L" + jvmClassName(MappedSet2.class) + ";I)V");
|
||||
else if ( className.equals(jvmClassName(MappedSet3.class)) )
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "put_views", "(L" + jvmClassName(MappedSet3.class) + ";I)V");
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "put_views", "(L" + jvmClassName(MappedSet3.class) + ";I)V");
|
||||
else if ( className.equals(jvmClassName(MappedSet4.class)) )
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "put_views", "(L" + jvmClassName(MappedSet4.class) + ";I)V");
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "put_views", "(L" + jvmClassName(MappedSet4.class) + ";I)V");
|
||||
else
|
||||
break outer;
|
||||
// stack: -
|
||||
|
@ -421,7 +441,7 @@ public class MappedObjectTransformer {
|
|||
// stack: instance
|
||||
pushInt(super.mv, mappedSubtype.sizeof);
|
||||
// stack: sizeof, instance
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "get_view", "(L" + jvmClassName(MappedObject.class) + ";I)I");
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "get_view", "(L" + MAPPED_OBJECT_JVM + ";I)I");
|
||||
// stack: view
|
||||
return;
|
||||
}
|
||||
|
@ -429,7 +449,7 @@ public class MappedObjectTransformer {
|
|||
// stack: view, instance
|
||||
pushInt(super.mv, mappedSubtype.sizeof);
|
||||
// stack: sizeof, view, instance
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "put_view", "(L" + jvmClassName(MappedObject.class) + ";II)V");
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "put_view", "(L" + MAPPED_OBJECT_JVM + ";II)V");
|
||||
// stack: -
|
||||
return;
|
||||
}
|
||||
|
@ -494,7 +514,7 @@ public class MappedObjectTransformer {
|
|||
// stack: long, long
|
||||
super.visitInsn(L2I);
|
||||
// stack: int, long
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";");
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";");
|
||||
// stack: buffer
|
||||
return;
|
||||
}
|
||||
|
@ -512,7 +532,7 @@ public class MappedObjectTransformer {
|
|||
// stack: offset, viewAddr, value
|
||||
super.visitInsn(LADD);
|
||||
// stack: fieldAddr, value
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), typeName.toLowerCase() + "put", "(" + typeName + "J)V");
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, typeName.toLowerCase() + "put", "(" + typeName + "J)V");
|
||||
// stack -
|
||||
|
||||
return;
|
||||
|
@ -525,7 +545,7 @@ public class MappedObjectTransformer {
|
|||
// stack: fieldOffset, viewAddr
|
||||
super.visitInsn(LADD);
|
||||
// stack: fieldAddr
|
||||
super.visitMethodInsn(INVOKESTATIC, jvmClassName(MappedHelper.class), typeName.toLowerCase() + "get", "(J)" + typeName);
|
||||
super.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, typeName.toLowerCase() + "get", "(J)" + typeName);
|
||||
// stack: value
|
||||
|
||||
return;
|
||||
|
|
Loading…
Reference in New Issue