diff options
author | Sven Gothel <[email protected]> | 2010-11-06 06:26:56 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-11-06 06:26:56 +0100 |
commit | d1a03d19398960d6e34232f29a30f1d569fba2a7 (patch) | |
tree | 92f90bb3c3c7587910272ff1235c3980b097cfcd | |
parent | eab5a8ded0b3ee13cdc66bddb369439e0871bae7 (diff) |
Fix buffer size: 64bit GLBufferSizeTracker, hash over addr+size, save fail-fast hash cache, ..
Relates to GlueGen 6b6b9b3b81cdc85b7260664ebec547756a6be5d7, branch sgothel_wip_fixes01.
Memory object size is ptrdiff_t, hence long (64bit).
The hash value must include size as well, otherwise boundaries cannot be verified. (security)
Double check hash collisions while adding a new MemoryObject.
-rw-r--r-- | make/config/jogl/gl-impl-CustomCCode-gl4bc.c | 6 | ||||
-rw-r--r-- | make/config/jogl/gl-impl-CustomCCode-gles1.c | 6 | ||||
-rw-r--r-- | make/config/jogl/gl-impl-CustomCCode-gles2.c | 6 | ||||
-rw-r--r-- | make/config/jogl/gl-impl-CustomJavaCode-gl4bc.java | 92 | ||||
-rw-r--r-- | make/config/jogl/gl-impl-CustomJavaCode-gles1.java | 63 | ||||
-rw-r--r-- | make/config/jogl/gl-impl-CustomJavaCode-gles2.java | 63 | ||||
-rw-r--r-- | src/jogl/classes/com/jogamp/opengl/impl/GLBufferSizeTracker.java | 27 | ||||
-rw-r--r-- | src/jogl/classes/com/jogamp/opengl/impl/MemoryObject.java | 142 |
8 files changed, 259 insertions, 146 deletions
diff --git a/make/config/jogl/gl-impl-CustomCCode-gl4bc.c b/make/config/jogl/gl-impl-CustomCCode-gl4bc.c index 0bd8b68da..778559eba 100644 --- a/make/config/jogl/gl-impl-CustomCCode-gl4bc.c +++ b/make/config/jogl/gl-impl-CustomCCode-gl4bc.c @@ -30,10 +30,10 @@ Java_com_jogamp_opengl_impl_gl4_GL4bcImpl_dispatch_1glMapNamedBufferEXT(JNIEnv * /* Java->C glue code: * Java package: com.jogamp.opengl.impl.gl4.GL4bcImpl - * Java method: ByteBuffer newDirectByteBuffer(long addr, int capacity); - * C function: jobject newDirectByteBuffer(jlong addr, jint capacity); + * Java method: ByteBuffer newDirectByteBuffer(long addr, long capacity); + * C function: jobject newDirectByteBuffer(jlong addr, jlong capacity); */ JNIEXPORT jobject JNICALL -Java_com_jogamp_opengl_impl_gl4_GL4bcImpl_newDirectByteBuffer(JNIEnv *env, jobject _unused, jlong addr, jint capacity) { +Java_com_jogamp_opengl_impl_gl4_GL4bcImpl_newDirectByteBuffer(JNIEnv *env, jobject _unused, jlong addr, jlong capacity) { return (*env)->NewDirectByteBuffer(env, (void*) (intptr_t) addr, capacity); } diff --git a/make/config/jogl/gl-impl-CustomCCode-gles1.c b/make/config/jogl/gl-impl-CustomCCode-gles1.c index a71ca4aae..422935ba7 100644 --- a/make/config/jogl/gl-impl-CustomCCode-gles1.c +++ b/make/config/jogl/gl-impl-CustomCCode-gles1.c @@ -16,10 +16,10 @@ Java_com_jogamp_opengl_impl_es1_GLES1Impl_dispatch_1glMapBuffer(JNIEnv *env, job /* Java->C glue code: * Java package: com.jogamp.opengl.impl.es1.GLES1Impl - * Java method: ByteBuffer newDirectByteBuffer(long addr, int capacity); - * C function: jobject newDirectByteBuffer(jlong addr, jint capacity); + * Java method: ByteBuffer newDirectByteBuffer(long addr, long capacity); + * C function: jobject newDirectByteBuffer(jlong addr, jlong capacity); */ JNIEXPORT jobject JNICALL -Java_com_jogamp_opengl_impl_es1_GLES1Impl_newDirectByteBuffer(JNIEnv *env, jobject _unused, jlong addr, jint capacity) { +Java_com_jogamp_opengl_impl_es1_GLES1Impl_newDirectByteBuffer(JNIEnv *env, jobject _unused, jlong addr, jlong capacity) { return (*env)->NewDirectByteBuffer(env, (void*) (intptr_t) addr, capacity); } diff --git a/make/config/jogl/gl-impl-CustomCCode-gles2.c b/make/config/jogl/gl-impl-CustomCCode-gles2.c index f99822d65..86fc47b4b 100644 --- a/make/config/jogl/gl-impl-CustomCCode-gles2.c +++ b/make/config/jogl/gl-impl-CustomCCode-gles2.c @@ -16,10 +16,10 @@ Java_com_jogamp_opengl_impl_es2_GLES2Impl_dispatch_1glMapBuffer(JNIEnv *env, job /* Java->C glue code: * Java package: com.jogamp.opengl.impl.es2.GLES2Impl - * Java method: ByteBuffer newDirectByteBuffer(long addr, int capacity); - * C function: jobject newDirectByteBuffer(jlong addr, jint capacity); + * Java method: ByteBuffer newDirectByteBuffer(long addr, long capacity); + * C function: jobject newDirectByteBuffer(jlong addr, jlong capacity); */ JNIEXPORT jobject JNICALL -Java_com_jogamp_opengl_impl_es2_GLES2Impl_newDirectByteBuffer(JNIEnv *env, jobject _unused, jlong addr, jint capacity) { +Java_com_jogamp_opengl_impl_es2_GLES2Impl_newDirectByteBuffer(JNIEnv *env, jobject _unused, jlong addr, jlong capacity) { return (*env)->NewDirectByteBuffer(env, (void*) (intptr_t) addr, capacity); } diff --git a/make/config/jogl/gl-impl-CustomJavaCode-gl4bc.java b/make/config/jogl/gl-impl-CustomJavaCode-gl4bc.java index ff177ec94..6776feeb7 100644 --- a/make/config/jogl/gl-impl-CustomJavaCode-gl4bc.java +++ b/make/config/jogl/gl-impl-CustomJavaCode-gl4bc.java @@ -274,32 +274,7 @@ public boolean glIsPBOUnpackEnabled() { return checkUnpackPBOEnabled(false); } -// Attempt to return the same ByteBuffer object from glMapBuffer if -// the vertex buffer object's base address and size haven't changed -private static class ARBVBOKey { - private long addr; - private int capacity; - - ARBVBOKey(long addr, int capacity) { - this.addr = addr; - this.capacity = capacity; - } - - public int hashCode() { - return (int) addr; - } - - public boolean equals(Object o) { - if ((o == null) || (!(o instanceof ARBVBOKey))) { - return false; - } - - ARBVBOKey other = (ARBVBOKey) o; - return ((addr == other.addr) && (capacity == other.capacity)); - } -} - -private Map/*<ARBVBOKey, ByteBuffer>*/ arbVBOCache = new HashMap(); +private HashMap/*<MemoryObject>*/ arbMemCache = new HashMap(); /** Entry point to C language function: <br> <code> LPVOID glMapBuffer(GLenum target, GLenum access); </code> */ public java.nio.ByteBuffer glMapBuffer(int target, int access) { @@ -307,53 +282,78 @@ public java.nio.ByteBuffer glMapBuffer(int target, int access) { if (__addr_ == 0) { throw new GLException("Method \"glMapBuffer\" not available"); } - int sz = bufferSizeTracker.getBufferSize(bufferStateTracker, target, this); + final long sz = bufferSizeTracker.getBufferSize(bufferStateTracker, target, this); if (0 == sz) { return null; } - long addr; - addr = dispatch_glMapBuffer(target, access, __addr_); + final long addr = dispatch_glMapBuffer(target, access, __addr_); if (0 == addr) { return null; } - ARBVBOKey key = new ARBVBOKey(addr, sz); - ByteBuffer _res = (ByteBuffer) arbVBOCache.get(key); - if (_res == null) { - _res = newDirectByteBuffer(addr, sz); - Buffers.nativeOrder(_res); - arbVBOCache.put(key, _res); + ByteBuffer buffer; + MemoryObject memObj0 = new MemoryObject(addr, sz); // object and key + MemoryObject memObj1 = MemoryObject.getOrAddSafe(arbMemCache, memObj0); + if(memObj0 == memObj1) { + // just added .. + if(null != memObj0.getBuffer()) { + throw new InternalError(); + } + buffer = newDirectByteBuffer(addr, sz); + Buffers.nativeOrder(buffer); + memObj0.setBuffer(buffer); + } else { + // already mapped + buffer = memObj1.getBuffer(); + if(null == buffer) { + throw new InternalError(); + } } - _res.position(0); - return _res; + buffer.position(0); + return buffer; } /** Encapsulates function pointer for OpenGL function <br>: <code> LPVOID glMapBuffer(GLenum target, GLenum access); </code> */ native private long dispatch_glMapBuffer(int target, int access, long glProcAddress); /** Entry point to C language function: <code> GLvoid * {@native glMapNamedBufferEXT}(GLuint buffer, GLenum access); </code> <br>Part of <code>GL_EXT_direct_state_access</code> */ -public java.nio.ByteBuffer glMapNamedBufferEXT(int buffer, int access) { +public java.nio.ByteBuffer glMapNamedBufferEXT(int bufferName, int access) { final long __addr_ = ((GL4bcProcAddressTable)_context.getGLProcAddressTable())._addressof_glMapNamedBufferEXT; if (__addr_ == 0) { throw new GLException("Method \"glMapNamedBufferEXT\" not available"); } - int sz = bufferSizeTracker.getDirectStateBufferSize(buffer, this); + final long sz = bufferSizeTracker.getDirectStateBufferSize(bufferName, this); if (0 == sz) { return null; } - long addr; - addr = dispatch_glMapNamedBufferEXT(buffer, access, __addr_); + final long addr = dispatch_glMapNamedBufferEXT(bufferName, access, __addr_); if (0 == addr) { return null; } - ByteBuffer _res = newDirectByteBuffer(addr, sz); - Buffers.nativeOrder(_res); - _res.position(0); - return _res; + ByteBuffer buffer; + MemoryObject memObj0 = new MemoryObject(addr, sz); // object and key + MemoryObject memObj1 = MemoryObject.getOrAddSafe(arbMemCache, memObj0); + if(memObj0 == memObj1) { + // just added .. + if(null != memObj0.getBuffer()) { + throw new InternalError(); + } + buffer = newDirectByteBuffer(addr, sz); + Buffers.nativeOrder(buffer); + memObj0.setBuffer(buffer); + } else { + // already mapped + buffer = memObj1.getBuffer(); + if(null == buffer) { + throw new InternalError(); + } + } + buffer.position(0); + return buffer; } private native long dispatch_glMapNamedBufferEXT(int buffer, int access, long procAddress); -native private ByteBuffer newDirectByteBuffer(long addr, int capacity); +native private ByteBuffer newDirectByteBuffer(long addr, long capacity); public void glVertexPointer(GLArrayData array) { if(array.getComponentNumber()==0) return; diff --git a/make/config/jogl/gl-impl-CustomJavaCode-gles1.java b/make/config/jogl/gl-impl-CustomJavaCode-gles1.java index d29fe1645..faff8b89f 100644 --- a/make/config/jogl/gl-impl-CustomJavaCode-gles1.java +++ b/make/config/jogl/gl-impl-CustomJavaCode-gles1.java @@ -249,32 +249,7 @@ private boolean checkPackPBOEnabled(boolean throwException) { return false; } -// Attempt to return the same ByteBuffer object from glMapBufferARB if -// the vertex buffer object's base address and size haven't changed -private static class ARBVBOKey { - private long addr; - private int capacity; - - ARBVBOKey(long addr, int capacity) { - this.addr = addr; - this.capacity = capacity; - } - - public int hashCode() { - return (int) addr; - } - - public boolean equals(Object o) { - if ((o == null) || (!(o instanceof ARBVBOKey))) { - return false; - } - - ARBVBOKey other = (ARBVBOKey) o; - return ((addr == other.addr) && (capacity == other.capacity)); - } -} - -private Map/*<ARBVBOKey, ByteBuffer>*/ arbVBOCache = new HashMap(); +private HashMap/*<MemoryObject>*/ arbMemCache = new HashMap(); /** Entry point to C language function: <br> <code> LPVOID glMapBuffer(GLenum target, GLenum access); </code> */ public java.nio.ByteBuffer glMapBuffer(int target, int access) { @@ -282,32 +257,40 @@ public java.nio.ByteBuffer glMapBuffer(int target, int access) { if (__addr_ == 0) { throw new GLException("Method \"glMapBuffer\" not available"); } - int sz = bufferSizeTracker.getBufferSize(bufferStateTracker, - target, - this); + final long sz = bufferSizeTracker.getBufferSize(bufferStateTracker, target, this); if (0 == sz) { return null; } - long addr; - addr = dispatch_glMapBuffer(target, access, __addr_); + final long addr = dispatch_glMapBuffer(target, access, __addr_); if (0 == addr) { return null; } - ARBVBOKey key = new ARBVBOKey(addr, sz); - java.nio.ByteBuffer _res = (java.nio.ByteBuffer) arbVBOCache.get(key); - if (_res == null) { - _res = newDirectByteBuffer(addr, sz); - Buffers.nativeOrder(_res); - arbVBOCache.put(key, _res); + ByteBuffer buffer; + MemoryObject memObj0 = new MemoryObject(addr, sz); // object and key + MemoryObject memObj1 = MemoryObject.getOrAddSafe(arbMemCache, memObj0); + if(memObj0 == memObj1) { + // just added .. + if(null != memObj0.getBuffer()) { + throw new InternalError(); + } + buffer = newDirectByteBuffer(addr, sz); + Buffers.nativeOrder(buffer); + memObj0.setBuffer(buffer); + } else { + // already mapped + buffer = memObj1.getBuffer(); + if(null == buffer) { + throw new InternalError(); + } } - _res.position(0); - return _res; + buffer.position(0); + return buffer; } /** Encapsulates function pointer for OpenGL function <br>: <code> LPVOID glMapBuffer(GLenum target, GLenum access); </code> */ native private long dispatch_glMapBuffer(int target, int access, long glProcAddress); -native private ByteBuffer newDirectByteBuffer(long addr, int capacity); +native private ByteBuffer newDirectByteBuffer(long addr, long capacity); public void glVertexPointer(GLArrayData array) { if(array.getComponentNumber()==0) return; diff --git a/make/config/jogl/gl-impl-CustomJavaCode-gles2.java b/make/config/jogl/gl-impl-CustomJavaCode-gles2.java index e65c491a2..e096d2185 100644 --- a/make/config/jogl/gl-impl-CustomJavaCode-gles2.java +++ b/make/config/jogl/gl-impl-CustomJavaCode-gles2.java @@ -259,32 +259,7 @@ private boolean checkPackPBOEnabled(boolean throwException) { return false; } -// Attempt to return the same ByteBuffer object from glMapBufferARB if -// the vertex buffer object's base address and size haven't changed -private static class ARBVBOKey { - private long addr; - private int capacity; - - ARBVBOKey(long addr, int capacity) { - this.addr = addr; - this.capacity = capacity; - } - - public int hashCode() { - return (int) addr; - } - - public boolean equals(Object o) { - if ((o == null) || (!(o instanceof ARBVBOKey))) { - return false; - } - - ARBVBOKey other = (ARBVBOKey) o; - return ((addr == other.addr) && (capacity == other.capacity)); - } -} - -private Map/*<ARBVBOKey, ByteBuffer>*/ arbVBOCache = new HashMap(); +private HashMap/*<MemoryObject>*/ arbMemCache = new HashMap(); /** Entry point to C language function: <br> <code> LPVOID glMapBuffer(GLenum target, GLenum access); </code> */ public java.nio.ByteBuffer glMapBuffer(int target, int access) { @@ -292,32 +267,40 @@ public java.nio.ByteBuffer glMapBuffer(int target, int access) { if (__addr_ == 0) { throw new GLException("Method \"glMapBuffer\" not available"); } - int sz = bufferSizeTracker.getBufferSize(bufferStateTracker, - target, - this); + final long sz = bufferSizeTracker.getBufferSize(bufferStateTracker, target, this); if (0 == sz) { return null; } - long addr; - addr = dispatch_glMapBuffer(target, access, __addr_); + final long addr = dispatch_glMapBuffer(target, access, __addr_); if (0 == addr) { return null; } - ARBVBOKey key = new ARBVBOKey(addr, sz); - java.nio.ByteBuffer _res = (java.nio.ByteBuffer) arbVBOCache.get(key); - if (_res == null) { - _res = newDirectByteBuffer(addr, sz); - Buffers.nativeOrder(_res); - arbVBOCache.put(key, _res); + ByteBuffer buffer; + MemoryObject memObj0 = new MemoryObject(addr, sz); // object and key + MemoryObject memObj1 = MemoryObject.getOrAddSafe(arbMemCache, memObj0); + if(memObj0 == memObj1) { + // just added .. + if(null != memObj0.getBuffer()) { + throw new InternalError(); + } + buffer = newDirectByteBuffer(addr, sz); + Buffers.nativeOrder(buffer); + memObj0.setBuffer(buffer); + } else { + // already mapped + buffer = memObj1.getBuffer(); + if(null == buffer) { + throw new InternalError(); + } } - _res.position(0); - return _res; + buffer.position(0); + return buffer; } /** Encapsulates function pointer for OpenGL function <br>: <code> LPVOID glMapBuffer(GLenum target, GLenum access); </code> */ native private long dispatch_glMapBuffer(int target, int access, long glProcAddress); -native private ByteBuffer newDirectByteBuffer(long addr, int capacity); +native private ByteBuffer newDirectByteBuffer(long addr, long capacity); public void glClearDepth(double depth) { glClearDepthf((float)depth); diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLBufferSizeTracker.java b/src/jogl/classes/com/jogamp/opengl/impl/GLBufferSizeTracker.java index ceabd3910..6ebda222b 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/GLBufferSizeTracker.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/GLBufferSizeTracker.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -40,7 +41,7 @@ package com.jogamp.opengl.impl; import javax.media.opengl.*; -import com.jogamp.common.util.IntIntHashMap; +import com.jogamp.common.util.IntLongHashMap; /** * Tracks as closely as possible the sizes of allocated OpenGL buffer @@ -93,17 +94,17 @@ public class GLBufferSizeTracker { // objects, which is probably sub-optimal. The expected usage // pattern of buffer objects indicates that the fact that this map // never shrinks is probably not that bad. - private IntIntHashMap bufferSizeMap; + private IntLongHashMap bufferSizeMap; protected static final boolean DEBUG = Debug.debug("GLStatusTracker"); public GLBufferSizeTracker() { - bufferSizeMap = new IntIntHashMap(); + bufferSizeMap = new IntLongHashMap(); bufferSizeMap.setKeyNotFoundValue(-1); } public void setBufferSize(GLBufferStateTracker bufferStateTracker, - int target, GL caller, int size) { + int target, GL caller, long size) { // Need to do some similar queries to getBufferSize below int buffer = bufferStateTracker.getBoundBufferObject(target, caller); boolean valid = bufferStateTracker.isBoundBufferObjectKnown(target); @@ -125,11 +126,11 @@ public class GLBufferSizeTracker { // left to do except drop this piece of information on the floor. } - public void setDirectStateBufferSize(int buffer, GL caller, int size) { + public void setDirectStateBufferSize(int buffer, GL caller, long size) { bufferSizeMap.put(buffer, size); } - public int getBufferSize(GLBufferStateTracker bufferStateTracker, + public long getBufferSize(GLBufferStateTracker bufferStateTracker, int target, GL caller) { // See whether we know what buffer is currently bound to the given @@ -149,25 +150,29 @@ public class GLBufferSizeTracker { return getBufferSizeImpl(target, buffer, caller); } // We don't know what's going on in this case; query the GL for an answer + // FIXME: both functions return 'int' types, which is not suitable, + // since buffer lenght is 64bit ? int[] tmp = new int[1]; caller.glGetBufferParameteriv(target, GL.GL_BUFFER_SIZE, tmp, 0); if (DEBUG) { System.err.println("GLBufferSizeTracker.getBufferSize(): no cached buffer information"); } - return tmp[0]; + return (long) tmp[0]; } - public int getDirectStateBufferSize(int buffer, GL caller) { + public long getDirectStateBufferSize(int buffer, GL caller) { return getBufferSizeImpl(0, buffer, caller); } - private int getBufferSizeImpl(int target, int buffer, GL caller) { + private long getBufferSizeImpl(int target, int buffer, GL caller) { // See whether we know the size of this buffer object; at this // point we almost certainly should if the application is // written correctly - int sz = bufferSizeMap.get(buffer); + long sz = bufferSizeMap.get(buffer); if (0 > sz) { // For robustness, try to query this value from the GL as we used to + // FIXME: both functions return 'int' types, which is not suitable, + // since buffer lenght is 64bit ? int[] tmp = new int[1]; if(0==target) { // DirectState .. @@ -186,7 +191,7 @@ public class GLBufferSizeTracker { " was zero; probably application error"); } // Assume we just don't know what's happening - sz = tmp[0]; + sz = (long) tmp[0]; bufferSizeMap.put(buffer, sz); if (DEBUG) { System.err.println("GLBufferSizeTracker.getBufferSize(): made slow query to cache size " + diff --git a/src/jogl/classes/com/jogamp/opengl/impl/MemoryObject.java b/src/jogl/classes/com/jogamp/opengl/impl/MemoryObject.java new file mode 100644 index 000000000..a691a6156 --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/impl/MemoryObject.java @@ -0,0 +1,142 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.impl; + +import java.nio.ByteBuffer; +import java.util.HashMap; + +/** + * + */ +public class MemoryObject { + private long addr; + private long size; + private int hash32; + private ByteBuffer buffer=null; + + public MemoryObject(long addr, long size) { + this.addr = addr; + this.size = size; + this.hash32 = getHash32(addr, size); + } + + public void setBuffer(ByteBuffer buffer) { + this.buffer = buffer; + } + + public ByteBuffer getBuffer() { + return this.buffer; + } + + /** + * @return the 32bit hash value generated via {@link #getHash32(long, long)} + */ + public int hashCode() { + return hash32; + } + + /** + * Ignores the optional attached <code>ByteBuffer</code> intentionally.<br> + * + * @return true of reference is equal or <code>obj</code> is of type <code>MemoryObject</code> + * and <code>addr</code> and <code>size</code> is equal.<br> + */ + public boolean equals(Object obj) { + if(this == obj) { return true; } + if(obj instanceof MemoryObject) { + MemoryObject m = (MemoryObject) obj; + return addr == m.addr && size == m.size ; + } + return false; + } + + /** + * Generates a 32bit hash value by <code>addr</code> and <code>size</code>.<br> + * Ignores the optional attached <code>ByteBuffer</code> intentionally.<br> + */ + public static int getHash32(long addr, long size) { + // avoid xor collisions of eg low/high parts + // 31 * x == (x << 5) - x + int hash = 31 + (int) addr ; // lo addr + hash = ((hash << 5) - hash) + (int) ( addr >>> 32 ) ; // hi addr + hash = ((hash << 5) - hash) + (int) size ; // lo size + hash = ((hash << 5) - hash) + (int) ( size >>> 32 ) ; // hi size + + return hash; + } + + /** + * Generates a 64bit hash value by <code>addr</code> and <code>size</code>.<br> + * Ignores the optional attached <code>ByteBuffer</code> intentionally.<br> + */ + public static long getHash64(long addr, long size) { + // 31 * x == (x << 5) - x + final long hash = 31 + addr; + return ((hash << 5) - hash) + size; + } + + public String toString() { + return "MemoryObject[addr 0x"+Long.toHexString(addr)+", size 0x"+Long.toHexString(size)+", hash32: 0x"+Integer.toHexString(hash32)+"]"; + } + + /** + * Verifies the hash map operation, ie + * <ul> + * <li>slow add: if !map.contains(obj0), the values are verified (slow)</li> + * <li>fast get: if map.contains(obj0), the mapped value is compared with equals (fast) </li> + * </ul> + * In case the above verification fails, a RuntimeException is thrown.<br> + * In such case the calculation of the hash value should either be tuned,<br> + * or we just cannot use hash mapping.<br> + * + * @param map the identity HashMap mapping MemoryObject to MemoryObject + * @param obj0 the MemoryObject to get or add in the map + * @return either the already mapped one where <code>obj0</code> != <code>return</code>, + * or the added <code>obj0</code> == <code>return</code>. + * @throws RuntimeException if hash collision occurs + */ + public static MemoryObject getOrAddSafe(HashMap/*<MemoryObject,MemoryObject>*/ map, MemoryObject obj0) { + MemoryObject obj1 = (MemoryObject) map.get(obj0); // get identity (fast) + if(null == obj1) { + // verify hash collision (slow) + if( map.values().contains(obj0) ) { + throw new RuntimeException("Hash collision, hash !exist, but in values: "+obj0); + } + map.put(obj0, obj0); + obj1 = obj0; + } else { + // verify hash collision (ok) + if( !obj1.equals(obj0) ) { + throw new RuntimeException("Hash collision, hash equals, but objects not: query "+obj0+" != contained "+obj1); + } + } + return obj1; + } + +}
\ No newline at end of file |