From b09625557d11a11fb4f953b3630f1c83e938e8f2 Mon Sep 17 00:00:00 2001 From: Ioannis Tsakpinis Date: Thu, 14 Jul 2011 16:54:25 +0000 Subject: [PATCH] Implemented .next() with bytecode transformation, 4x faster now. Made method transformation a bit faster. --- .../lwjgl/test/mapped/MappedObjectTests1.java | 9 ++ .../org/lwjgl/util/mapped/MappedHelper.java | 4 + .../org/lwjgl/util/mapped/MappedObject.java | 18 ++-- .../util/mapped/MappedObjectTransformer.java | 92 +++++++++++-------- 4 files changed, 79 insertions(+), 44 deletions(-) diff --git a/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java b/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java index 51f06e19..cb402522 100644 --- a/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java +++ b/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java @@ -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); diff --git a/src/java/org/lwjgl/util/mapped/MappedHelper.java b/src/java/org/lwjgl/util/mapped/MappedHelper.java index a4f2cff0..2b9b5ada 100644 --- a/src/java/org/lwjgl/util/mapped/MappedHelper.java +++ b/src/java/org/lwjgl/util/mapped/MappedHelper.java @@ -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; diff --git a/src/java/org/lwjgl/util/mapped/MappedObject.java b/src/java/org/lwjgl/util/mapped/MappedObject.java index 8605b1f5..9d3a93b0 100644 --- a/src/java/org/lwjgl/util/mapped/MappedObject.java +++ b/src/java/org/lwjgl/util/mapped/MappedObject.java @@ -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 SIZEOF bytes, from the current * mapped object, to the specified mapped object. diff --git a/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java b/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java index c20eda5c..ea987002 100644 --- a/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java +++ b/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java @@ -38,6 +38,9 @@ public class MappedObjectTransformer { static final Map 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(); @@ -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 ( "".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), "", "()V"); + mv.visitMethodInsn(INVOKESPECIAL, MAPPED_OBJECT_JVM, "", "()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)) && "".equals(methodName) && "()V".equals(signature) ) { + if ( opcode == INVOKESPECIAL && className.equals(MAPPED_OBJECT_JVM) && "".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, "", "()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, "", "()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;