From: Markus Koschany <apo@debian.org>
Date: Sat, 9 Apr 2016 20:28:48 +0200
Subject: no asm support
We don't support the optional asm.jar because LWJGL is not compatible with
libasm-java.
Forwarded: not-needed
---
.../org/lwjgl/test/mapped/TestMappedObject.java | 87 --
.../test/opengl/sprites/SpriteShootoutMapped.java | 838 -------------
.../lwjgl/util/mapped/MappedObjectClassLoader.java | 193 ---
.../lwjgl/util/mapped/MappedObjectTransformer.java | 1319 --------------------
4 files changed, 2437 deletions(-)
delete mode 100644 src/java/org/lwjgl/test/mapped/TestMappedObject.java
delete mode 100644 src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java
delete mode 100644 src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java
delete mode 100644 src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java
diff --git a/src/java/org/lwjgl/test/mapped/TestMappedObject.java b/src/java/org/lwjgl/test/mapped/TestMappedObject.java
deleted file mode 100644
index 0ae560e..0000000
--- a/src/java/org/lwjgl/test/mapped/TestMappedObject.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2002-2011 LWJGL Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * 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.
- *
- * * Neither the name of 'LWJGL' nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT OWNER 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.
- */
-package org.lwjgl.test.mapped;
-
-import org.lwjgl.util.mapped.MappedObjectClassLoader;
-import org.lwjgl.util.mapped.MappedObjectTransformer;
-
-/** @author Riven */
-@SuppressWarnings("static-access")
-public class TestMappedObject {
-
- static {
- boolean assertsEnabled = false;
- assert assertsEnabled = true; // Intentional side effect!!!
- if ( !assertsEnabled )
- throw new RuntimeException("Asserts must be enabled for this test.");
- }
-
- public static void main(String[] args) throws Exception {
- MappedObjectTransformer.register(MappedFloat.class);
- MappedObjectTransformer.register(MappedVec2.class);
- MappedObjectTransformer.register(MappedVec3.class);
- MappedObjectTransformer.register(MappedSomething.class);
- MappedObjectTransformer.register(MappedObjectTests3.Xyz.class);
- MappedObjectTransformer.register(MappedObjectTests4.MappedPointer.class);
- MappedObjectTransformer.register(MappedObjectTests4.MappedCacheLinePadded.class);
- MappedObjectTransformer.register(MappedObjectTests4.MappedFieldCacheLinePadded.class);
-
- if ( MappedObjectClassLoader.fork(TestMappedObject.class, args) ) {
- return;
- }
-
- MappedObjectTests1.testViewField();
-
- MappedObjectTests2.testFields();
-
- // MappedObjectBench.benchmarkMapped();
- // MappedObjectBench.benchmarkInstances();
- // MappedObjectBench.benchmarkIndirectArray();
- // MappedObjectBench.benchmarkDirectArray();
- // MappedObjectBench.benchmarkUnsafe();
-
- MappedObjectTests3.testMappedBuffer();
- MappedObjectTests3.testForeach();
- MappedObjectTests3.testConstructor();
- MappedObjectTests3.testMappedSet();
-
- MappedObjectTests4.testLocalView();
- //MappedObjectTests4.testLWJGL();
- MappedObjectTests4.testPointer();
- MappedObjectTests4.testCacheLineAlignment();
- MappedObjectTests4.testCacheLinePadding();
- MappedObjectTests4.testCacheLinePaddingPOJO();
-
- System.out.println("done");
- }
-
-}
\ No newline at end of file
diff --git a/src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java b/src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java
deleted file mode 100644
index 83805d1..0000000
--- a/src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java
+++ /dev/null
@@ -1,838 +0,0 @@
-/*
- * Copyright (c) 2002-2011 LWJGL Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * 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.
- *
- * * Neither the name of 'LWJGL' nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT OWNER 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.
- */
-package org.lwjgl.test.opengl.sprites;
-
-import org.lwjgl.BufferUtils;
-import org.lwjgl.LWJGLException;
-import org.lwjgl.Sys;
-import org.lwjgl.input.Keyboard;
-import org.lwjgl.input.Mouse;
-import org.lwjgl.opengl.*;
-import org.lwjgl.util.mapped.MappedObject;
-import org.lwjgl.util.mapped.MappedObjectClassLoader;
-import org.lwjgl.util.mapped.MappedObjectTransformer;
-import org.lwjgl.util.mapped.MappedType;
-
-import java.awt.image.BufferedImage;
-import java.awt.image.Raster;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Random;
-import javax.imageio.ImageIO;
-
-import static org.lwjgl.opengl.EXTTransformFeedback.*;
-import static org.lwjgl.opengl.GL11.*;
-import static org.lwjgl.opengl.GL12.*;
-import static org.lwjgl.opengl.GL15.*;
-import static org.lwjgl.opengl.GL20.*;
-import static org.lwjgl.opengl.GL30.*;
-
-/**
- * Sprite rendering demo. Three implementations are supported:
- * a) CPU animation + BufferData VBO update.
- * b) CPU animation + MapBufferRange VBO update.
- * c) GPU animation using transform feedback with a vertex shader.
- *
- * @author Spasi
- * @since 18/3/2011
- */
-public final class SpriteShootoutMapped {
-
- static final int SCREEN_WIDTH = 800;
- static final int SCREEN_HEIGHT = 600;
-
- private static final int ANIMATION_TICKS = 60;
-
- private boolean run = true;
- private boolean render = true;
- private boolean colorMask = true;
- private boolean animate = true;
- private boolean smooth;
- private boolean vsync;
-
- int ballSize = 42;
- int ballCount = 100 * 1000;
-
- private SpriteRenderer renderer;
-
- // OpenGL stuff
- private int texID;
- private int texBigID;
- private int texSmallID;
-
- long animateTime;
-
- private SpriteShootoutMapped() {
- }
-
- public static void main(String[] args) {
- MappedObjectTransformer.register(Pixel4b.class);
- MappedObjectTransformer.register(Pixel3b.class);
- MappedObjectTransformer.register(Sprite.class);
- MappedObjectTransformer.register(SpriteRender.class);
-
- if ( MappedObjectClassLoader.fork(SpriteShootoutMapped.class, args) )
- return;
-
- try {
- new SpriteShootoutMapped().start();
- } catch (LWJGLException e) {
- e.printStackTrace();
- }
- }
-
- private void start() throws LWJGLException {
- try {
- initGL();
-
- final ContextCapabilities caps = GLContext.getCapabilities();
- if ( !true && (caps.OpenGL30 || caps.GL_EXT_transform_feedback) )
- renderer = new SpriteRendererTF();
- else if ( true && caps.GL_ARB_map_buffer_range )
- renderer = new SpriteRendererMapped();
- else
- renderer = new SpriteRendererPlain();
-
- updateBalls(ballCount);
- run();
- } catch (Throwable t) {
- t.printStackTrace();
- } finally {
- destroy();
- }
- }
-
- private void initGL() throws LWJGLException {
- Display.setLocation((Display.getDisplayMode().getWidth() - SCREEN_WIDTH) / 2,
- (Display.getDisplayMode().getHeight() - SCREEN_HEIGHT) / 2);
- Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT));
- Display.setTitle("Sprite Shootout");
- Display.create();
- //Display.create(new PixelFormat(), new ContextAttribs(4, 1).withProfileCompatibility(true).withDebug(true));
- //AMDDebugOutput.glDebugMessageCallbackAMD(new AMDDebugOutputCallback());
-
- if ( !GLContext.getCapabilities().OpenGL20 )
- throw new RuntimeException("OpenGL 2.0 is required for this demo.");
-
- // Setup viewport
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT, -1.0, 1.0);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-
- glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
-
- // Create textures
-
- try {
- texSmallID = createTexture("res/ball_sm.png");
- texBigID = createTexture("res/ball.png");
- } catch (IOException e) {
- e.printStackTrace();
- System.exit(-1);
- }
- texID = texBigID;
-
- // Setup rendering state
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
- glEnable(GL_ALPHA_TEST);
- glAlphaFunc(GL_GREATER, 0.0f);
-
- glColorMask(colorMask, colorMask, colorMask, false);
- glDepthMask(false);
- glDisable(GL_DEPTH_TEST);
-
- // Setup geometry
-
- glEnableClientState(GL_VERTEX_ARRAY);
-
- Util.checkGLError();
- }
-
- private static int createTexture(final String path) throws IOException {
- final BufferedImage img = ImageIO.read(SpriteShootoutMapped.class.getClassLoader().getResource(path));
-
- final int w = img.getWidth();
- final int h = img.getHeight();
-
- final ByteBuffer buffer = readImage(img);
-
- final int texID = glGenTextures();
-
- glBindTexture(GL_TEXTURE_2D, texID);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer);
-
- return texID;
- }
-
- public static class Pixel4b extends MappedObject {
-
- public byte r, g, b, a;
-
- }
-
- @MappedType(align = 3)
- public static class Pixel3b extends MappedObject {
-
- public byte r, g, b;
-
- }
-
- private static ByteBuffer readImage(final BufferedImage img) throws IOException {
- final Raster raster = img.getRaster();
-
- final int bands = raster.getNumBands();
-
- final int w = img.getWidth();
- final int h = img.getHeight();
-
- final int count = w * h;
-
- final byte[] pixels = new byte[count * bands];
- raster.getDataElements(0, 0, w, h, pixels);
-
- if ( bands == 4 ) {
- Pixel4b p = Pixel4b.malloc(count);
-
- int b = 0;
- for ( int i = 0; i < count; i++, b += 4 ) {
- // Pre-multiply alpha
- final float a = unpackUByte01(pixels[b + 3]);
-
- p.view = i;
- p.r = packUByte01(unpackUByte01(pixels[b + 2]) * a);
- p.g = packUByte01(unpackUByte01(pixels[b + 1]) * a);
- p.b = packUByte01(unpackUByte01(pixels[b + 0]) * a);
- p.a = pixels[b + 3];
- }
-
- return p.backingByteBuffer();
- } else if ( bands == 3 ) {
- Pixel3b p = Pixel3b.malloc(count);
-
- int b = 0;
- for ( int i = 0; i < count; i++, b += 3 ) {
- p.view = i;
- p.r = pixels[b + 2];
- p.g = pixels[b + 1];
- p.b = pixels[b + 0];
- }
-
- return p.backingByteBuffer();
- } else {
- ByteBuffer p = BufferUtils.createByteBuffer(count * bands);
- p.put(pixels, 0, p.capacity());
- p.flip();
- return p;
- }
-
- }
-
- private static float unpackUByte01(final byte x) {
- return (x & 0xFF) / 255.0f;
- }
-
- private static byte packUByte01(final float x) {
- return (byte)(x * 255.0f);
- }
-
- private void updateBalls(final int count) {
- System.out.println("NUMBER OF BALLS: " + count);
- renderer.updateBalls(ballCount);
- }
-
- private void run() {
- long startTime = System.currentTimeMillis() + 5000;
- long fps = 0;
-
- long time = Sys.getTime();
- final int ticksPerUpdate = (int)(Sys.getTimerResolution() / ANIMATION_TICKS);
-
- renderer.render(false, true, 0);
-
- while ( run ) {
- Display.processMessages();
- handleInput();
-
- glClear(GL_COLOR_BUFFER_BIT);
-
- final long currTime = Sys.getTime();
- final int delta = (int)(currTime - time);
- if ( smooth || delta >= ticksPerUpdate ) {
- renderer.render(render, animate, delta);
- time = currTime;
- } else
- renderer.render(render, false, 0);
-
- Display.update(false);
- //Display.sync(60);
-
- if ( startTime > System.currentTimeMillis() ) {
- fps++;
- } else {
- long timeUsed = 5000 + (startTime - System.currentTimeMillis());
- startTime = System.currentTimeMillis() + 5000;
- System.out.println("FPS: " + (Math.round(fps / (timeUsed / 1000.0) * 10) / 10.0) + ", Balls: " + ballCount);
- System.out.println("Animation: " + animateTime / fps);
- animateTime = 0;
- fps = 0;
- }
- }
- }
-
- private void handleInput() {
- if ( Display.isCloseRequested() )
- run = false;
-
- while ( Keyboard.next() ) {
- if ( Keyboard.getEventKeyState() )
- continue;
-
- switch ( Keyboard.getEventKey() ) {
- case Keyboard.KEY_1:
- case Keyboard.KEY_2:
- case Keyboard.KEY_3:
- case Keyboard.KEY_4:
- case Keyboard.KEY_5:
- case Keyboard.KEY_6:
- case Keyboard.KEY_7:
- case Keyboard.KEY_8:
- case Keyboard.KEY_9:
- case Keyboard.KEY_0:
- ballCount = 1 << (Keyboard.getEventKey() - Keyboard.KEY_1);
- updateBalls(ballCount);
- break;
- case Keyboard.KEY_ADD:
- case Keyboard.KEY_SUBTRACT:
- int mult;
- if ( Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT) )
- mult = 1000;
- else if ( Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU) )
- mult = 100;
- else if ( Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL) )
- mult = 10;
- else
- mult = 1;
- if ( Keyboard.getEventKey() == Keyboard.KEY_SUBTRACT )
- mult = -mult;
- ballCount += mult * 100;
- if ( ballCount <= 0 )
- ballCount = 1;
- updateBalls(ballCount);
- break;
- case Keyboard.KEY_ESCAPE:
- run = false;
- break;
- case Keyboard.KEY_A:
- animate = !animate;
- System.out.println("Animation is now " + (animate ? "on" : "off") + ".");
- break;
- case Keyboard.KEY_C:
- colorMask = !colorMask;
- glColorMask(colorMask, colorMask, colorMask, false);
- System.out.println("Color mask is now " + (colorMask ? "on" : "off") + ".");
- // Disable alpha test when color mask is off, else we get no benefit.
- if ( colorMask ) {
- glEnable(GL_BLEND);
- glEnable(GL_ALPHA_TEST);
- } else {
- glDisable(GL_BLEND);
- glDisable(GL_ALPHA_TEST);
- }
- break;
- case Keyboard.KEY_R:
- render = !render;
- System.out.println("Rendering is now " + (render ? "on" : "off") + ".");
- break;
- case Keyboard.KEY_S:
- smooth = !smooth;
- System.out.println("Smooth animation is now " + (smooth ? "on" : "off") + ".");
- break;
- case Keyboard.KEY_T:
- if ( texID == texBigID ) {
- texID = texSmallID;
- ballSize = 16;
- } else {
- texID = texBigID;
- ballSize = 42;
- }
- renderer.updateBallSize();
- glBindTexture(GL_TEXTURE_2D, texID);
- System.out.println("Now using the " + (texID == texBigID ? "big" : "small") + " texture.");
- break;
- case Keyboard.KEY_V:
- vsync = !vsync;
- Display.setVSyncEnabled(vsync);
- System.out.println("VSYNC is now " + (vsync ? "enabled" : "disabled") + ".");
- break;
- }
- }
-
- while ( Mouse.next() ) ;
- }
-
- private void destroy() {
- Display.destroy();
- }
-
- public static class Sprite extends MappedObject {
-
- public float dx, x;
- public float dy, y;
-
- }
-
- public static class SpriteRender extends MappedObject {
-
- public float x, y;
-
- }
-
- private abstract class SpriteRenderer {
-
- protected Sprite sprites;
-
- protected int spriteCount;
-
- protected int vshID;
- protected int progID;
-
- protected void createProgram() {
- final int fshID = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(fshID, "uniform sampler2D COLOR_MAP;\n" +
- "void main(void) {\n" +
- " gl_FragColor = texture2D(COLOR_MAP, gl_PointCoord);\n" +
- "}");
- glCompileShader(fshID);
- if ( glGetShaderi(fshID, GL_COMPILE_STATUS) == GL_FALSE ) {
- System.out.println(glGetShaderInfoLog(fshID, glGetShaderi(fshID, GL_INFO_LOG_LENGTH)));
- throw new RuntimeException("Failed to compile fragment shader.");
- }
-
- progID = glCreateProgram();
- glAttachShader(progID, vshID);
- glAttachShader(progID, fshID);
- glLinkProgram(progID);
- if ( glGetProgrami(progID, GL_LINK_STATUS) == GL_FALSE ) {
- System.out.println(glGetProgramInfoLog(progID, glGetProgrami(progID, GL_INFO_LOG_LENGTH)));
- throw new RuntimeException("Failed to link shader program.");
- }
-
- glUseProgram(progID);
- glUniform1i(glGetUniformLocation(progID, "COLOR_MAP"), 0);
-
- updateBallSize();
-
- glEnableClientState(GL_VERTEX_ARRAY);
- }
-
- public void updateBallSize() {
- glPointSize(ballSize);
- }
-
- public abstract void updateBalls(int count);
-
- protected abstract void render(boolean render, boolean animate, int delta);
-
- }
-
- private abstract class SpriteRendererBatched extends SpriteRenderer {
-
- protected static final int BALLS_PER_BATCH = 10 * 1000;
-
- SpriteRendererBatched() {
- vshID = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(vshID, "void main(void) {\n" +
- " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" +
- "}");
- glCompileShader(vshID);
- if ( glGetShaderi(vshID, GL_COMPILE_STATUS) == GL_FALSE ) {
- System.out.println(glGetShaderInfoLog(vshID, glGetShaderi(vshID, GL_INFO_LOG_LENGTH)));
- throw new RuntimeException("Failed to compile vertex shader.");
- }
-
- createProgram();
- }
-
- public void updateBalls(final int count) {
- final Random random = new Random();
-
- final Sprite newSprites = Sprite.malloc(count);
- if ( sprites != null ) {
- sprites.view = 0;
- sprites.copyRange(newSprites, Math.min(count, spriteCount));
- }
-
- if ( count > spriteCount ) {
- for ( int i = spriteCount; i < count; i++ ) {
- newSprites.view = i;
-
- newSprites.x = (int)(random.nextFloat() * (SCREEN_WIDTH - ballSize) + ballSize * 0.5f);
- newSprites.y = (int)(random.nextFloat() * (SCREEN_HEIGHT - ballSize) + ballSize * 0.5f);
- newSprites.dx = random.nextFloat() * 0.4f - 0.2f;
- newSprites.dy = random.nextFloat() * 0.4f - 0.2f;
- }
- }
-
- sprites = newSprites;
- spriteCount = count;
- }
-
- protected void animate(
- final Sprite sprite,
- final SpriteRender spriteRender,
- final int ballSize, final int ballIndex, final int batchSize, final int delta
- ) {
- final float ballRadius = ballSize * 0.5f;
- final float boundW = SCREEN_WIDTH - ballRadius;
- final float boundH = SCREEN_HEIGHT - ballRadius;
-
- final Sprite[] sprites = sprite.asArray();
- final SpriteRender[] spritesRender = spriteRender.asArray();
- for ( int b = ballIndex, r = 0, len = (ballIndex + batchSize); b < len; b++, r++ ) {
- float dx = sprites[b].dx;
- float x = sprites[b].x;
-
- x += dx * delta;
- if ( x < ballRadius ) {
- x = ballRadius;
- dx = -dx;
- } else if ( x > boundW ) {
- x = boundW;
- dx = -dx;
- }
-
- sprites[b].dx = dx;
- sprites[b].x = x;
- spritesRender[r].x = x;
-
- float dy = sprites[b].dy;
- float y = sprites[b].y;
-
- y += dy * delta;
- if ( y < ballRadius ) {
- y = ballRadius;
- dy = -dy;
- } else if ( y > boundH ) {
- y = boundH;
- dy = -dy;
- }
-
- sprites[b].dy = dy;
- sprites[b].y = y;
- spritesRender[r].y = y;
- }
- }
-
- }
-
- private class SpriteRendererPlain extends SpriteRendererBatched {
-
- private final int DATA_PER_BATCH = BALLS_PER_BATCH * 2 * 4; // balls * 2 floats * 4 bytes
-
- protected int[] animVBO;
-
- private SpriteRender spritesRender;
-
- SpriteRendererPlain() {
- System.out.println("Shootout Implementation: CPU animation & BufferData");
- spritesRender = SpriteRender.malloc(BALLS_PER_BATCH);
- }
-
- public void updateBalls(final int count) {
- super.updateBalls(count);
-
- final int batchCount = count / BALLS_PER_BATCH + (count % BALLS_PER_BATCH == 0 ? 0 : 1);
- if ( animVBO != null && batchCount == animVBO.length )
- return;
-
- final int[] newAnimVBO = new int[batchCount];
- if ( animVBO != null ) {
- System.arraycopy(animVBO, 0, newAnimVBO, 0, Math.min(animVBO.length, newAnimVBO.length));
- for ( int i = newAnimVBO.length; i < animVBO.length; i++ )
- glDeleteBuffers(animVBO[i]);
- }
- for ( int i = animVBO == null ? 0 : animVBO.length; i < newAnimVBO.length; i++ ) {
- newAnimVBO[i] = glGenBuffers();
- glBindBuffer(GL_ARRAY_BUFFER, newAnimVBO[i]);
- }
-
- animVBO = newAnimVBO;
- }
-
- public void render(final boolean render, final boolean animate, final int delta) {
- int batchSize = Math.min(ballCount, BALLS_PER_BATCH);
- int ballIndex = 0;
- int batchIndex = 0;
- while ( ballIndex < ballCount ) {
- glBindBuffer(GL_ARRAY_BUFFER, animVBO[batchIndex]);
-
- if ( animate )
- animate(ballIndex, batchSize, delta);
-
- if ( render ) {
- glVertexPointer(2, GL_FLOAT, 0, 0);
- glDrawArrays(GL_POINTS, 0, batchSize);
- }
-
- ballIndex += batchSize;
- batchSize = Math.min(ballCount - ballIndex, BALLS_PER_BATCH);
- batchIndex++;
- }
- }
-
- private void animate(final int ballIndex, final int batchSize, final int delta) {
- animate(
- sprites, spritesRender,
- ballSize, ballIndex, batchSize, delta
- );
-
- glBufferData(GL_ARRAY_BUFFER, DATA_PER_BATCH, GL_STREAM_DRAW);
- glBufferSubData(GL_ARRAY_BUFFER, 0, spritesRender.backingByteBuffer());
- }
-
- }
-
- private class SpriteRendererMapped extends SpriteRendererBatched {
-
- private StreamVBO animVBO;
-
- SpriteRendererMapped() {
- System.out.println("Shootout Implementation: CPU animation & MapBufferRange");
- }
-
- public void updateBalls(final int count) {
- super.updateBalls(count);
-
- if ( animVBO != null )
- animVBO.destroy();
-
- animVBO = new StreamVBO(GL_ARRAY_BUFFER, ballCount * (2 * 4));
- }
-
- public void render(final boolean render, final boolean animate, final int delta) {
- int batchSize = Math.min(ballCount, BALLS_PER_BATCH);
- int ballIndex = 0;
- while ( ballIndex < ballCount ) {
- if ( animate ) {
- final ByteBuffer buffer = animVBO.map(batchSize * (2 * 4));
-
- long t0 = System.nanoTime();
- animate(sprites, SpriteRender.<SpriteRender>map(buffer), ballSize, ballIndex, batchSize, delta);
- long t1 = System.nanoTime();
-
- animateTime += t1 - t0;
-
- animVBO.unmap();
- }
-
- if ( render ) {
- glVertexPointer(2, GL_FLOAT, 0, ballIndex * (2 * 4));
- glDrawArrays(GL_POINTS, 0, batchSize);
- }
-
- ballIndex += batchSize;
- batchSize = Math.min(ballCount - ballIndex, BALLS_PER_BATCH);
- }
- }
-
- }
-
- private class SpriteRendererTF extends SpriteRenderer {
-
- private int progIDTF;
- private int ballSizeLoc;
- private int deltaLoc;
-
- private int[] tfVBO = new int[2];
- private int currVBO;
-
- SpriteRendererTF() {
- System.out.println("Shootout Implementation: TF GPU animation");
-
- // Transform-feedback program
-
- final int vshID = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(vshID, "#version 130\n" +
- "const float WIDTH = " + SCREEN_WIDTH + ";\n" +
- "const float HEIGHT = " + SCREEN_HEIGHT + ";\n" +
- "uniform float ballSize;\n" + // ballSize / 2
- "uniform float delta;\n" +
- "void main(void) {\n" +
- " vec4 anim = gl_Vertex;\n" +
- " anim.xy = anim.xy + anim.zw * delta;\n" +
- " vec2 animC = clamp(anim.xy, vec2(ballSize), vec2(WIDTH - ballSize, HEIGHT - ballSize));\n" +
- " if ( anim.x != animC.x ) anim.z = -anim.z;\n" +
- " if ( anim.y != animC.y ) anim.w = -anim.w;\n" +
- " gl_Position = vec4(animC, anim.zw);\n" +
- "}");
- glCompileShader(vshID);
- if ( glGetShaderi(vshID, GL_COMPILE_STATUS) == GL_FALSE ) {
- System.out.println(glGetShaderInfoLog(vshID, glGetShaderi(vshID, GL_INFO_LOG_LENGTH)));
- throw new RuntimeException("Failed to compile vertex shader.");
- }
-
- progIDTF = glCreateProgram();
- glAttachShader(progIDTF, vshID);
- glTransformFeedbackVaryings(progIDTF, new CharSequence[] { "gl_Position" }, GL_SEPARATE_ATTRIBS);
- glLinkProgram(progIDTF);
- if ( glGetProgrami(progIDTF, GL_LINK_STATUS) == GL_FALSE ) {
- System.out.println(glGetProgramInfoLog(progIDTF, glGetProgrami(progIDTF, GL_INFO_LOG_LENGTH)));
- throw new RuntimeException("Failed to link shader program.");
- }
-
- glUseProgram(progIDTF);
-
- ballSizeLoc = glGetUniformLocation(progIDTF, "ballSize");
- deltaLoc = glGetUniformLocation(progIDTF, "delta");
-
- glUniform1f(ballSizeLoc, ballSize * 0.5f);
-
- // -----------------
-
- this.vshID = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(this.vshID, "void main(void) {\n" +
- " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" +
- "}");
- glCompileShader(this.vshID);
- if ( glGetShaderi(this.vshID, GL_COMPILE_STATUS) == GL_FALSE ) {
- System.out.println(glGetShaderInfoLog(this.vshID, glGetShaderi(this.vshID, GL_INFO_LOG_LENGTH)));
- throw new RuntimeException("Failed to compile vertex shader.");
- }
-
- createProgram();
- }
-
- public void updateBallSize() {
- glUseProgram(progIDTF);
- glUniform1f(ballSizeLoc, ballSize * 0.5f);
-
- glUseProgram(progID);
- super.updateBallSize();
- }
-
- private void doUpdateBalls(final int count) {
- final Random random = new Random();
-
- final Sprite newSprites = Sprite.malloc(count);
- if ( sprites != null ) {
- sprites.view = 0;
- sprites.copyRange(newSprites, Math.min(count, spriteCount));
- }
-
- if ( count > spriteCount ) {
- for ( int i = spriteCount; i < count; i++ ) {
- newSprites.view = i;
-
- newSprites.x = (int)(random.nextFloat() * (SCREEN_WIDTH - ballSize) + ballSize * 0.5f);
- newSprites.y = (int)(random.nextFloat() * (SCREEN_HEIGHT - ballSize) + ballSize * 0.5f);
- newSprites.dx = random.nextFloat() * 0.4f - 0.2f;
- newSprites.dy = random.nextFloat() * 0.4f - 0.2f;
- }
- }
-
- sprites = newSprites;
- spriteCount = count;
- }
-
- public void updateBalls(final int count) {
- if ( tfVBO[0] != 0 ) {
- // Fetch current animation state
- glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sprites.backingByteBuffer());
- }
-
- doUpdateBalls(count);
-
- if ( tfVBO[0] != 0 ) {
- for ( int i = 0; i < tfVBO.length; i++ )
- glDeleteBuffers(tfVBO[i]);
- }
-
- for ( int i = 0; i < tfVBO.length; i++ ) {
- tfVBO[i] = glGenBuffers();
- glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tfVBO[i]);
- glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sprites.backingByteBuffer(), GL_STATIC_DRAW);
- }
-
- glBindBuffer(GL_ARRAY_BUFFER, tfVBO[0]);
- glVertexPointer(2, GL_FLOAT, (4 * 4), 0);
- }
-
- public void render(final boolean render, final boolean animate, final int delta) {
- if ( animate ) {
- glUseProgram(progIDTF);
- glUniform1f(deltaLoc, delta);
-
- final int vbo = currVBO;
- currVBO = 1 - currVBO;
-
- glBindBuffer(GL_ARRAY_BUFFER, tfVBO[vbo]);
- glVertexPointer(4, GL_FLOAT, 0, 0);
-
- glEnable(GL_RASTERIZER_DISCARD);
- if ( GLContext.getCapabilities().OpenGL30 ) {
- glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfVBO[1 - vbo]);
-
- glBeginTransformFeedback(GL_POINTS);
- glDrawArrays(GL_POINTS, 0, ballCount);
- glEndTransformFeedback();
- } else {
- glBindBufferBaseEXT(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0, tfVBO[1 - vbo]);
-
- glBeginTransformFeedbackEXT(GL_POINTS);
- glDrawArrays(GL_POINTS, 0, ballCount);
- glEndTransformFeedbackEXT();
- }
- glDisable(GL_RASTERIZER_DISCARD);
-
- glUseProgram(progID);
- glVertexPointer(2, GL_FLOAT, (4 * 4), 0);
- }
-
- if ( render )
- glDrawArrays(GL_POINTS, 0, ballCount);
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java b/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java
deleted file mode 100644
index 463823f..0000000
--- a/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2002-2011 LWJGL Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * 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.
- *
- * * Neither the name of 'LWJGL' nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT OWNER 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.
- */
-package org.lwjgl.util.mapped;
-
-import org.lwjgl.LWJGLUtil;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.URLClassLoader;
-
-/**
- * This classloader is responsible for applying the bytecode transformation to mapped objects.
- * The transformation can either be applied using a Java agent, or with the convenient {@link #fork} method.
- *
- * @author Riven
- */
-public class MappedObjectClassLoader extends URLClassLoader {
-
- static final String MAPPEDOBJECT_PACKAGE_PREFIX = MappedObjectClassLoader.class.getPackage().getName() + ".";
-
- static boolean FORKED;
-
- /**
- * Forks the specified class containing a main method, passing the specified arguments. See
- * {@link org.lwjgl.test.mapped.TestMappedObject} for example usage.
- *
- * @param mainClass the class containing the main method
- * @param args the arguments to pass
- *
- * @return true if the fork was successful.
- */
- public static boolean fork(Class<?> mainClass, String[] args) {
- if ( FORKED ) {
- return false;
- }
-
- FORKED = true;
-
- try {
- MappedObjectClassLoader loader = new MappedObjectClassLoader(mainClass);
- loader.loadMappedObject();
-
- Class<?> replacedMainClass = loader.loadClass(mainClass.getName());
- Method mainMethod = replacedMainClass.getMethod("main", String[].class);
- mainMethod.invoke(null, new Object[] { args });
- } catch (InvocationTargetException exc) {
- Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), exc.getCause());
- } catch (Throwable cause) {
- throw new Error("failed to fork", cause);
- }
-
- return true;
- }
-
- private MappedObjectClassLoader(Class<?> mainClass) {
- super(((URLClassLoader)mainClass.getClassLoader()).getURLs());
- }
-
- protected synchronized Class<?> loadMappedObject() throws ClassNotFoundException {
- final String name = MappedObject.class.getName();
- String className = name.replace('.', '/');
-
- 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_ACTIVITY )
- printActivity(className, t0, t1);
-
- Class<?> clazz = super.defineClass(name, bytecode, 0, bytecode.length);
- resolveClass(clazz);
- return clazz;
- }
-
- private static long total_time_transforming;
-
- @Override
- protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- if ( name.startsWith("java.")
- || name.startsWith("javax.")
- || name.startsWith("sun.")
- || name.startsWith("sunw.")
- || name.startsWith("org.objectweb.asm.")
- )
- return super.loadClass(name, resolve);
-
- final String className = name.replace('.', '/');
- final boolean inThisPackage = name.startsWith(MAPPEDOBJECT_PACKAGE_PREFIX);
-
- if ( inThisPackage && (
- name.equals(MappedObjectClassLoader.class.getName())
- || name.equals((MappedObjectTransformer.class.getName()))
- || name.equals((CacheUtil.class.getName()))
- ) )
- return super.loadClass(name, resolve);
-
- 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 ( !(inThisPackage && name.substring(MAPPEDOBJECT_PACKAGE_PREFIX.length()).indexOf('.') == -1) ) {
- long t0 = System.nanoTime();
- final byte[] newBytecode = MappedObjectTransformer.transformMappedAPI(className, bytecode);
- long t1 = System.nanoTime();
-
- total_time_transforming += (t1 - t0);
-
- if ( bytecode != newBytecode ) {
- bytecode = newBytecode;
- if ( MappedObjectTransformer.PRINT_ACTIVITY )
- printActivity(className, t0, t1);
- }
- }
-
- Class<?> clazz = super.defineClass(name, bytecode, 0, bytecode.length);
- if ( resolve )
- resolveClass(clazz);
- return clazz;
- }
-
- private static void printActivity(final String className, final long t0, final long t1) {
- final StringBuilder msg = new StringBuilder(MappedObjectClassLoader.class.getSimpleName() + ": " + className);
-
- if ( MappedObjectTransformer.PRINT_TIMING )
- msg.append("\n\ttransforming took " + (t1 - t0) / 1000 + " micros (total: " + (total_time_transforming / 1000 / 1000) + "ms)");
-
- LWJGLUtil.log(msg);
- }
-
- private static byte[] readStream(InputStream in) {
- byte[] bytecode = new byte[256];
- int len = 0;
- try {
- while ( true ) {
- if ( bytecode.length == len )
- bytecode = copyOf(bytecode, len * 2);
- int got = in.read(bytecode, len, bytecode.length - len);
- if ( got == -1 )
- break;
- len += got;
- }
- } catch (IOException exc) {
- // stop!
- } finally {
- try {
- in.close();
- } catch (IOException exc) {
- // ignore...
- }
- }
- return copyOf(bytecode, len);
- }
-
- private static byte[] copyOf(byte[] original, int newLength) {
- byte[] copy = new byte[newLength];
- System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
- return copy;
- }
-
-}
\ No newline at end of file
diff --git a/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java b/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java
deleted file mode 100644
index c34c14e..0000000
--- a/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java
+++ /dev/null
@@ -1,1319 +0,0 @@
-/*
- * Copyright (c) 2002-2011 LWJGL Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * 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.
- *
- * * Neither the name of 'LWJGL' nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT OWNER 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.
- */
-package org.lwjgl.util.mapped;
-
-import org.lwjgl.BufferUtils;
-import org.lwjgl.LWJGLUtil;
-import org.lwjgl.MemoryUtil;
-import org.objectweb.asm.*;
-import org.objectweb.asm.tree.*;
-import org.objectweb.asm.tree.analysis.*;
-import org.objectweb.asm.tree.analysis.Frame;
-import org.objectweb.asm.util.TraceClassVisitor;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.objectweb.asm.ClassWriter.*;
-import static org.objectweb.asm.Opcodes.*;
-
-/**
- * This class implements the bytecode transformation that mapped object go through.
- * Mapped object classes need to first be registered with the transformer, see {@link #register(Class)}.
- * <p/>
- * The transformer supports some debugging tools, enabled through JVM system properties:<br/>
- * org.lwjgl.util.mapped.PrintTiming=true, prints timing information for the transformation step.<br/>
- * org.lwjgl.util.mapped.PrintActivity=true, prints activity information.<br/>
- * org.lwjgl.util.mapped.PrintBytecode=true, prints the transformed bytecode.<br/>
- * org.lwjgl.util.Debug must also be set to true for the above to work.
- *
- * @author Riven
- */
-public class MappedObjectTransformer {
-
- static final boolean PRINT_ACTIVITY = LWJGLUtil.DEBUG && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintActivity");
- static final boolean PRINT_TIMING = PRINT_ACTIVITY && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintTiming");
- static final boolean PRINT_BYTECODE = LWJGLUtil.DEBUG && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintBytecode");
-
- 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 final String MAPPEDSET_PREFIX = jvmClassName(MappedSet.class);
- static final String MAPPED_SET2_JVM = jvmClassName(MappedSet2.class);
- static final String MAPPED_SET3_JVM = jvmClassName(MappedSet3.class);
- static final String MAPPED_SET4_JVM = jvmClassName(MappedSet4.class);
-
- static final String CACHE_LINE_PAD_JVM = "L" + jvmClassName(CacheLinePad.class) + ";";
-
- // Public methods
- static final String VIEWADDRESS_METHOD_NAME = "getViewAddress";
- static final String NEXT_METHOD_NAME = "next";
- static final String ALIGN_METHOD_NAME = "getAlign";
- static final String SIZEOF_METHOD_NAME = "getSizeof";
- static final String CAPACITY_METHOD_NAME = "capacity"; // Used for .asArray().length
-
- // Internal methods
- static final String VIEW_CONSTRUCTOR_NAME = "constructView$LWJGL"; // Used by runViewConstructor
-
- static final Map<Integer, String> OPCODE_TO_NAME = new HashMap<Integer, String>();
- static final Map<Integer, String> INSNTYPE_TO_NAME = new HashMap<Integer, String>();
-
- static boolean is_currently_computing_frames;
-
- static {
- getClassEnums(Opcodes.class, OPCODE_TO_NAME, "V1_", "ACC_", "T_", "F_", "MH_");
- getClassEnums(AbstractInsnNode.class, INSNTYPE_TO_NAME);
-
- className_to_subtype = new HashMap<String, MappedSubtypeInfo>();
-
- {
- // HACK: required for mapped.view++
- //
- // because the compiler generates:
- // => GETFIELD MappedObject.view
- // => ICONST_1
- // => IADD
- // => PUTFIELD MyMappedType.view
- //
- // instead of:
- // => GETFIELD MyMappedType.view
- // => ICONST_1
- // => IADD
- // => PUTFIELD MyMappedType.view
- //
- className_to_subtype.put(MAPPED_OBJECT_JVM, new MappedSubtypeInfo(MAPPED_OBJECT_JVM, null, -1, -1, -1, false));
- }
-
- final String vmName = System.getProperty("java.vm.name");
- if ( vmName != null && !vmName.contains("Server") ) {
- System.err.println("Warning: " + MappedObject.class.getSimpleName() + "s have inferiour performance on Client VMs, please consider switching to a Server VM.");
- }
- }
-
- /**
- * Registers a class as a mapped object.
- * The class must extend {@link org.lwjgl.util.mapped.MappedObject} and be annotated with {@link org.lwjgl.util.mapped.MappedField}.
- *
- * @param type the mapped object class.
- */
- public static void register(Class<? extends MappedObject> type) {
- if ( MappedObjectClassLoader.FORKED )
- return;
-
- final MappedType mapped = type.getAnnotation(MappedType.class);
-
- if ( mapped != null && mapped.padding() < 0 )
- throw new ClassFormatError("Invalid mapped type padding: " + mapped.padding());
-
- if ( type.getEnclosingClass() != null && !Modifier.isStatic(type.getModifiers()) )
- throw new InternalError("only top-level or static inner classes are allowed");
-
- final String className = jvmClassName(type);
- final Map<String, FieldInfo> fields = new HashMap<String, FieldInfo>();
-
- long sizeof = 0;
- for ( Field field : type.getDeclaredFields() ) {
- FieldInfo fieldInfo = registerField(mapped == null || mapped.autoGenerateOffsets(), className, sizeof, field);
- if ( fieldInfo == null )
- continue;
-
- fields.put(field.getName(), fieldInfo);
-
- sizeof = Math.max(sizeof, fieldInfo.offset + fieldInfo.lengthPadded);
- }
-
- int align = 4;
- int padding = 0;
- boolean cacheLinePadded = false;
-
- if ( mapped != null ) {
- align = mapped.align();
- if ( mapped.cacheLinePadding() ) {
- if ( mapped.padding() != 0 )
- throw new ClassFormatError("Mapped type padding cannot be specified together with cacheLinePadding.");
-
- final int cacheLineMod = (int)(sizeof % CacheUtil.getCacheLineSize());
- if ( cacheLineMod != 0 )
- padding = CacheUtil.getCacheLineSize() - cacheLineMod;
-
- cacheLinePadded = true;
- } else
- padding = mapped.padding();
- }
-
- sizeof += padding;
-
- final MappedSubtypeInfo mappedType = new MappedSubtypeInfo(className, fields, (int)sizeof, align, padding, cacheLinePadded);
- if ( className_to_subtype.put(className, mappedType) != null )
- throw new InternalError("duplicate mapped type: " + mappedType.className);
- }
-
- private static FieldInfo registerField(final boolean autoGenerateOffsets, final String className, long advancingOffset, final Field field) {
- if ( Modifier.isStatic(field.getModifiers()) ) // static fields are never mapped
- return null;
-
- // we only support primitives and ByteBuffers
- if ( !field.getType().isPrimitive() && field.getType() != ByteBuffer.class )
- throw new ClassFormatError("field '" + className + "." + field.getName() + "' not supported: " + field.getType());
-
- MappedField meta = field.getAnnotation(MappedField.class);
- if ( meta == null && !autoGenerateOffsets )
- throw new ClassFormatError("field '" + className + "." + field.getName() + "' missing annotation " + MappedField.class.getName() + ": " + className);
-
- Pointer pointer = field.getAnnotation(Pointer.class);
- if ( pointer != null && field.getType() != long.class )
- throw new ClassFormatError("The @Pointer annotation can only be used on long fields. @Pointer field found: " + className + "." + field.getName() + ": " + field.getType());
-
- if ( Modifier.isVolatile(field.getModifiers()) && (pointer != null || field.getType() == ByteBuffer.class) )
- throw new ClassFormatError("The volatile keyword is not supported for @Pointer or ByteBuffer fields. Volatile field found: " + className + "." + field.getName() + ": " + field.getType());
-
- // quick hack
- long byteLength;
- if ( field.getType() == long.class || field.getType() == double.class ) {
- if ( pointer == null )
- byteLength = 8;
- else
- byteLength = MappedObjectUnsafe.INSTANCE.addressSize();
- } else if ( field.getType() == double.class )
- byteLength = 8;
- else if ( field.getType() == int.class || field.getType() == float.class )
- byteLength = 4;
- else if ( field.getType() == char.class || field.getType() == short.class )
- byteLength = 2;
- else if ( field.getType() == byte.class )
- byteLength = 1;
- else if ( field.getType() == ByteBuffer.class ) {
- byteLength = meta.byteLength();
- if ( byteLength < 0 )
- throw new IllegalStateException("invalid byte length for mapped ByteBuffer field: " + className + "." + field.getName() + " [length=" + byteLength + "]");
- } else
- throw new ClassFormatError(field.getType().getName());
-
- if ( field.getType() != ByteBuffer.class && (advancingOffset % byteLength) != 0 )
- throw new IllegalStateException("misaligned mapped type: " + className + "." + field.getName());
-
- CacheLinePad pad = field.getAnnotation(CacheLinePad.class);
-
- long byteOffset = advancingOffset;
- if ( meta != null && meta.byteOffset() != -1 ) {
- if ( meta.byteOffset() < 0 )
- throw new ClassFormatError("Invalid field byte offset: " + className + "." + field.getName() + " [byteOffset=" + meta.byteOffset() + "]");
- if ( pad != null )
- throw new ClassFormatError("A field byte offset cannot be specified together with cache-line padding: " + className + "." + field.getName());
-
- byteOffset = meta.byteOffset();
- }
-
- long byteLengthPadded = byteLength;
- if ( pad != null ) {
- // Pad before
- if ( pad.before() && byteOffset % CacheUtil.getCacheLineSize() != 0 )
- byteOffset += CacheUtil.getCacheLineSize() - (byteOffset & (CacheUtil.getCacheLineSize() - 1));
-
- // Pad after
- if ( pad.after() && (byteOffset + byteLength) % CacheUtil.getCacheLineSize() != 0 )
- byteLengthPadded += CacheUtil.getCacheLineSize() - (byteOffset + byteLength) % CacheUtil.getCacheLineSize();
-
- assert !pad.before() || (byteOffset % CacheUtil.getCacheLineSize() == 0);
- assert !pad.after() || ((byteOffset + byteLengthPadded) % CacheUtil.getCacheLineSize() == 0);
- }
-
- if ( PRINT_ACTIVITY )
- LWJGLUtil.log(MappedObjectTransformer.class.getSimpleName() + ": " + className + "." + field.getName() + " [type=" + field.getType().getSimpleName() + ", offset=" + byteOffset + "]");
-
- return new FieldInfo(byteOffset, byteLength, byteLengthPadded, Type.getType(field.getType()), Modifier.isVolatile(field.getModifiers()), pointer != null);
- }
-
- /** 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,
- CAPACITY_METHOD_NAME,
- };
-
- public MethodVisitor visitMethod(int access, final String name, final String desc, final String signature, final String[] exceptions) {
- for ( String method : DEFINALIZE_LIST ) {
- if ( name.equals(method) ) {
- access &= ~ACC_FINAL;
- break;
- }
- }
- return super.visitMethod(access, name, desc, signature, exceptions);
- }
- };
-
- new ClassReader(bytecode).accept(cv, 0);
- return cw.toByteArray();
- }
-
- static byte[] transformMappedAPI(final String className, byte[] bytecode) {
- final ClassWriter cw = new ClassWriter(COMPUTE_FRAMES) {
-
- @Override
- protected String getCommonSuperClass(String a, String b) {
- // HACK: prevent user-code static-initialization-blocks to be executed
- if ( is_currently_computing_frames && !a.startsWith("java/") || !b.startsWith("java/") )
- return "java/lang/Object";
-
- return super.getCommonSuperClass(a, b);
- }
-
- };
-
- final TransformationAdapter ta = new TransformationAdapter(cw, className);
-
- ClassVisitor cv = ta;
- if ( className_to_subtype.containsKey(className) ) // Do a first pass to generate address getters
- cv = getMethodGenAdapter(className, cv);
-
- new ClassReader(bytecode).accept(cv, ClassReader.SKIP_FRAMES);
-
- if ( !ta.transformed )
- return bytecode;
-
- bytecode = cw.toByteArray();
- if ( PRINT_BYTECODE )
- printBytecode(bytecode);
-
- return bytecode;
- }
-
- private static ClassAdapter getMethodGenAdapter(final String className, final ClassVisitor cv) {
- return new ClassAdapter(cv) {
-
- @Override
- public void visitEnd() {
- final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
-
- generateViewAddressGetter();
- generateCapacity();
- generateAlignGetter(mappedSubtype);
- generateSizeofGetter();
- generateNext();
-
- for ( String fieldName : mappedSubtype.fields.keySet() ) {
- final FieldInfo field = mappedSubtype.fields.get(fieldName);
-
- if ( field.type.getDescriptor().length() > 1 ) { // ByteBuffer, getter only
- generateByteBufferGetter(fieldName, field);
- } else {
- generateFieldGetter(fieldName, field);
- generateFieldSetter(fieldName, field);
- }
- }
-
- super.visitEnd();
- }
-
- private void generateViewAddressGetter() {
- MethodVisitor mv = super.visitMethod(ACC_PUBLIC, VIEWADDRESS_METHOD_NAME, "(I)J", null, null);
- mv.visitCode();
- mv.visitVarInsn(ALOAD, 0);
- mv.visitFieldInsn(GETFIELD, MAPPED_OBJECT_JVM, "baseAddress", "J");
- mv.visitVarInsn(ILOAD, 1);
- mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
- mv.visitInsn(IMUL);
- mv.visitInsn(I2L);
- mv.visitInsn(LADD);
- if ( MappedObject.CHECKS ) {
- mv.visitInsn(DUP2);
- mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "checkAddress", "(JL" + MAPPED_OBJECT_JVM + ";)V");
- }
- mv.visitInsn(LRETURN);
- mv.visitMaxs(3, 2);
- mv.visitEnd();
- }
-
- private void generateCapacity() {
- // return (backingByteBuffer().capacity() + (int)(MemoryUtil.getAddress0(backingByteBuffer()) - baseAddress)) / SIZEOF;
- MethodVisitor mv = super.visitMethod(ACC_PUBLIC, CAPACITY_METHOD_NAME, "()I", null, null);
- mv.visitCode();
- mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKEVIRTUAL, MAPPED_OBJECT_JVM, "backingByteBuffer", "()L" + jvmClassName(ByteBuffer.class) + ";");
- mv.visitInsn(DUP);
- mv.visitMethodInsn(INVOKEVIRTUAL, jvmClassName(ByteBuffer.class), "capacity", "()I");
- mv.visitInsn(SWAP);
- mv.visitMethodInsn(INVOKESTATIC, jvmClassName(MemoryUtil.class), "getAddress0", "(L" + jvmClassName(Buffer.class) + ";)J");
- mv.visitVarInsn(ALOAD, 0);
- mv.visitFieldInsn(GETFIELD, MAPPED_OBJECT_JVM, "baseAddress", "J");
- mv.visitInsn(LSUB);
- mv.visitInsn(L2I);
- mv.visitInsn(IADD);
- mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
- mv.visitInsn(IDIV);
- mv.visitInsn(IRETURN);
- mv.visitMaxs(3, 1);
- 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 String fieldName, final FieldInfo field) {
- MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, getterName(fieldName), "(L" + className + ";I)" + field.type.getDescriptor(), null, null);
- mv.visitCode();
- mv.visitVarInsn(ALOAD, 0);
- mv.visitVarInsn(ILOAD, 1);
- mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
- visitIntNode(mv, (int)field.offset);
- mv.visitInsn(I2L);
- mv.visitInsn(LADD);
- visitIntNode(mv, (int)field.length);
- mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";");
- mv.visitInsn(ARETURN);
- mv.visitMaxs(3, 2);
- mv.visitEnd();
- }
-
- private void generateFieldGetter(final String fieldName, final FieldInfo field) {
- MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, getterName(fieldName), "(L" + className + ";I)" + field.type.getDescriptor(), null, null);
- mv.visitCode();
- mv.visitVarInsn(ALOAD, 0);
- mv.visitVarInsn(ILOAD, 1);
- mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
- visitIntNode(mv, (int)field.offset);
- mv.visitInsn(I2L);
- mv.visitInsn(LADD);
- mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, field.getAccessType() + "get", "(J)" + field.type.getDescriptor());
- mv.visitInsn(field.type.getOpcode(IRETURN));
- mv.visitMaxs(3, 2);
- mv.visitEnd();
- }
-
- private void generateFieldSetter(final String fieldName, final FieldInfo field) {
- MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, setterName(fieldName), "(L" + className + ";I" + field.type.getDescriptor() + ")V", null, null);
- mv.visitCode();
- int load = 0;
- switch ( field.type.getSort() ) {
- case Type.BOOLEAN:
- case Type.CHAR:
- case Type.BYTE:
- case Type.SHORT:
- case Type.INT:
- load = ILOAD;
- break;
- case Type.FLOAT:
- load = FLOAD;
- break;
- case Type.LONG:
- load = LLOAD;
- break;
- case Type.DOUBLE:
- load = DLOAD;
- break;
- }
- mv.visitVarInsn(load, 2);
- mv.visitVarInsn(ALOAD, 0);
- mv.visitVarInsn(ILOAD, 1);
- mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
- visitIntNode(mv, (int)field.offset);
- mv.visitInsn(I2L);
- mv.visitInsn(LADD);
- mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, field.getAccessType() + "put", "(" + field.type.getDescriptor() + "J)V");
- mv.visitInsn(RETURN);
- mv.visitMaxs(4, 4);
- mv.visitEnd();
- }
-
- };
- }
-
- private static class TransformationAdapter extends ClassAdapter {
-
- final String className;
-
- boolean transformed;
-
- TransformationAdapter(final ClassVisitor cv, final String className) {
- super(cv);
- this.className = className;
- }
-
- @Override
- public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) {
- // remove redirected fields
- final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
- if ( mappedSubtype != null && mappedSubtype.fields.containsKey(name) ) {
- if ( PRINT_ACTIVITY )
- LWJGLUtil.log(MappedObjectTransformer.class.getSimpleName() + ": discarding field: " + className + "." + name + ":" + desc);
- return null;
- }
-
- if ( (access & ACC_STATIC) == 0 ) {
- return new FieldNode(access, name, desc, signature, value) {
- public void visitEnd() {
- if ( visibleAnnotations == null ) { // early-out
- accept(cv);
- return;
- }
-
- boolean before = false;
- boolean after = false;
- int byteLength = 0;
- for ( AnnotationNode pad : visibleAnnotations ) {
- if ( CACHE_LINE_PAD_JVM.equals(pad.desc) ) {
- if ( "J".equals(desc) || "D".equals(desc) )
- byteLength = 8;
- else if ( "I".equals(desc) || "F".equals(desc) )
- byteLength = 4;
- else if ( "S".equals(desc) || "C".equals(desc) )
- byteLength = 2;
- else if ( "B".equals(desc) || "Z".equals(desc) )
- byteLength = 1;
- else
- throw new ClassFormatError("The @CacheLinePad annotation cannot be used on non-primitive fields: " + className + "." + name);
-
- transformed = true;
-
- after = true;
- if ( pad.values != null ) {
- for ( int i = 0; i < pad.values.size(); i += 2 ) {
- final boolean value = pad.values.get(i + 1).equals(Boolean.TRUE);
- if ( "before".equals(pad.values.get(i)) )
- before = value;
- else
- after = value;
- }
- }
- break;
- }
- }
-
- /*
- We make the fields public to force the JVM to keep the fields in the object.
- Instead of using only longs or integers, we use the same type as the original
- field. That's because modern JVMs usually reorder fields by type:
- longs, then doubles, then integers, then booleans, etc. This way it's more
- likely that the padding will work as expected.
- */
-
- if ( before ) {
- final int count = CacheUtil.getCacheLineSize() / byteLength - 1;
- for ( int i = count; i >= 1; i-- )
- cv.visitField(access | ACC_PUBLIC | ACC_SYNTHETIC, name + "$PAD_" + i, desc, signature, null);
- }
-
- accept(cv);
-
- if ( after ) {
- final int count = CacheUtil.getCacheLineSize() / byteLength - 1;
- for ( int i = 1; i <= count; i++ )
- cv.visitField(access | ACC_PUBLIC | ACC_SYNTHETIC, name + "$PAD" + i, desc, signature, null);
- }
- }
- };
- } else
- return super.visitField(access, name, desc, signature, value);
- }
-
- @Override
- public MethodVisitor visitMethod(final int access, String name, final String desc, final String signature, final String[] exceptions) {
- // Move MappedSubtype constructors to another method
- if ( "<init>".equals(name) ) {
- final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
- if ( mappedSubtype != null ) {
- if ( !"()V".equals(desc) )
- throw new ClassFormatError(className + " can only have a default constructor, found: " + desc);
-
- final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
- mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKESPECIAL, MAPPED_OBJECT_JVM, "<init>", "()V");
- mv.visitInsn(RETURN);
- mv.visitMaxs(0, 0);
-
- // put the method body in another method
- name = VIEW_CONSTRUCTOR_NAME;
- }
- }
-
- final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
- return new MethodNode(access, name, desc, signature, exceptions) {
-
- /** When true, the method has touched a mapped object and needs to be transformed. We track this
- * so we can skip the expensive frame analysis and tree API usage. */
- boolean needsTransformation;
-
- @Override
- public void visitMaxs(int a, int b) {
- try {
- is_currently_computing_frames = true;
- super.visitMaxs(a, b);
- } finally {
- is_currently_computing_frames = false;
- }
- }
-
- @Override
- public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
- if ( className_to_subtype.containsKey(owner) || owner.startsWith(MAPPEDSET_PREFIX) )
- needsTransformation = true;
-
- super.visitFieldInsn(opcode, owner, name, desc);
- }
-
- @Override
- public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
- if ( className_to_subtype.containsKey(owner) )
- needsTransformation = true;
-
- super.visitMethodInsn(opcode, owner, name, desc);
- }
-
- @Override
- public void visitEnd() {
- if ( needsTransformation ) { // Early-out for methods that do not touch a mapped object.
- //System.err.println("\nTRANSFORMING: " + className + "." + name + desc);
- transformed = true;
- try {
- transformMethod(analyse());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- // Pass the instruction stream to the adapter's MethodVisitor
- accept(mv);
- }
-
- private Frame<BasicValue>[] analyse() throws AnalyzerException {
- final Analyzer<BasicValue> a = new Analyzer<BasicValue>(new SimpleVerifier());
- a.analyze(className, this);
- return a.getFrames();
- }
-
- private void transformMethod(final Frame<BasicValue>[] frames) {
- final InsnList instructions = this.instructions;
-
- final Map<Integer, MappedSubtypeInfo> arrayVars = new HashMap<Integer, MappedSubtypeInfo>();
-
- /*
- We need this map because we insert/remove instructions from the stream and we need a way
- to match each original instruction with the corresponding frame.
- TODO: Can we keep track of everything more efficiently without a map?
- */
- final Map<AbstractInsnNode, Frame<BasicValue>> frameMap = new HashMap<AbstractInsnNode, Frame<BasicValue>>();
- for ( int i = 0; i < frames.length; i++ )
- frameMap.put(instructions.get(i), frames[i]);
-
- for ( int i = 0; i < instructions.size(); i++ ) { // f is a separate cursor for frames
- final AbstractInsnNode instruction = instructions.get(i);
-
- //System.out.println("MAIN LOOP #" + i + " - " + getOpcodeName(instruction));
-
- switch ( instruction.getType() ) {
- case AbstractInsnNode.VAR_INSN:
- if ( instruction.getOpcode() == ALOAD ) {
- VarInsnNode varInsn = (VarInsnNode)instruction;
- final MappedSubtypeInfo mappedSubtype = arrayVars.get(varInsn.var);
- if ( mappedSubtype != null )
- i = transformArrayAccess(instructions, i, frameMap, varInsn, mappedSubtype, varInsn.var);
- }
- break;
- case AbstractInsnNode.FIELD_INSN:
- FieldInsnNode fieldInsn = (FieldInsnNode)instruction;
-
- final InsnList list = transformFieldAccess(fieldInsn);
- if ( list != null )
- i = replace(instructions, i, instruction, list);
-
- break;
- case AbstractInsnNode.METHOD_INSN:
- MethodInsnNode methodInsn = (MethodInsnNode)instruction;
- final MappedSubtypeInfo mappedType = className_to_subtype.get(methodInsn.owner);
- if ( mappedType != null )
- i = transformMethodCall(instructions, i, frameMap, methodInsn, mappedType, arrayVars);
- break;
- }
- }
- }
- };
- }
- }
-
- static int transformMethodCall(final InsnList instructions, int i, final Map<AbstractInsnNode, Frame<BasicValue>> frameMap, final MethodInsnNode methodInsn, final MappedSubtypeInfo mappedType, final Map<Integer, MappedSubtypeInfo> arrayVars) {
- switch ( methodInsn.getOpcode() ) {
- case INVOKEVIRTUAL:
- if ( "asArray".equals(methodInsn.name) && methodInsn.desc.equals("()[L" + MAPPED_OBJECT_JVM + ";") ) {
- // Go forward and store the local variable index.
- // We only allow this pattern: INVOKEVIRTUAL -> CHECKCAST -> ASTORE.
- // We remove the first two and store the target MappedSubtype in the ASTORE variable
- AbstractInsnNode nextInstruction;
- checkInsnAfterIsArray(nextInstruction = methodInsn.getNext(), CHECKCAST);
- checkInsnAfterIsArray(nextInstruction = nextInstruction.getNext(), ASTORE);
-
- final Frame<BasicValue> frame = frameMap.get(nextInstruction);
- final String targetType = frame.getStack(frame.getStackSize() - 1).getType().getElementType().getInternalName();
- if ( !methodInsn.owner.equals(targetType) ) {
- /*
- This may happen with the current API, like so:
- MappedA foo = MappedA.malloc(...);
- MappedB[] cursor = foo.asArray();
- We have to parameterize MappedObject to avoid this.
- */
- throw new ClassCastException("Source: " + methodInsn.owner + " - Target: " + targetType);
- }
-
- final VarInsnNode varInstruction = (VarInsnNode)nextInstruction;
-
- arrayVars.put(varInstruction.var, mappedType);
-
- instructions.remove(methodInsn.getNext()); // Remove CHECKCAST
- instructions.remove(methodInsn); // Remove INVOKEVIRTUAL
- }
-
- if ( "dup".equals(methodInsn.name) && methodInsn.desc.equals("()L" + MAPPED_OBJECT_JVM + ";") ) {
- i = replace(instructions, i, methodInsn, generateDupInstructions(methodInsn));
- break;
- }
-
- if ( "slice".equals(methodInsn.name) && methodInsn.desc.equals("()L" + MAPPED_OBJECT_JVM + ";") ) {
- i = replace(instructions, i, methodInsn, generateSliceInstructions(methodInsn));
- break;
- }
-
- if ( "runViewConstructor".equals(methodInsn.name) && "()V".equals(methodInsn.desc) ) {
- i = replace(instructions, i, methodInsn, generateRunViewConstructorInstructions(methodInsn));
- break;
- }
-
- if ( "copyTo".equals(methodInsn.name) && methodInsn.desc.equals("(L" + MAPPED_OBJECT_JVM + ";)V") ) {
- i = replace(instructions, i, methodInsn, generateCopyToInstructions(mappedType));
- break;
- }
-
- if ( "copyRange".equals(methodInsn.name) && methodInsn.desc.equals("(L" + MAPPED_OBJECT_JVM + ";I)V") ) {
- i = replace(instructions, i, methodInsn, generateCopyRangeInstructions(mappedType));
- break;
- }
-
- break;
- case INVOKESPECIAL:
- // super() in VIEW_CONSTRUCTOR_NAME, remove
- if ( methodInsn.owner.equals(MAPPED_OBJECT_JVM) && "<init>".equals(methodInsn.name) && "()V".equals(methodInsn.desc) ) {
- instructions.remove(methodInsn.getPrevious()); // ALOAD
- instructions.remove(methodInsn); // INVOKESPECIAL
-
- i -= 2;
- }
- break;
- case INVOKESTATIC:
- boolean isMapDirectMethod = "map".equals(methodInsn.name) && methodInsn.desc.equals("(JI)L" + MAPPED_OBJECT_JVM + ";");
- boolean isMapBufferMethod = "map".equals(methodInsn.name) && methodInsn.desc.equals("(Ljava/nio/ByteBuffer;)L" + MAPPED_OBJECT_JVM + ";");
- boolean isMallocMethod = "malloc".equals(methodInsn.name) && methodInsn.desc.equals("(I)L" + MAPPED_OBJECT_JVM + ";");
-
- if ( (isMapDirectMethod || isMapBufferMethod) || isMallocMethod )
- i = replace(instructions, i, methodInsn, generateMapInstructions(mappedType, methodInsn.owner, isMapDirectMethod, isMallocMethod));
- break;
- }
-
- return i;
- }
-
- private static InsnList generateCopyRangeInstructions(final MappedSubtypeInfo mappedType) {
- final InsnList list = new InsnList();
-
- // stack: instances, target, this
- list.add(getIntNode(mappedType.sizeof));
- // stack: sizeof, instances, target, this
- list.add(new InsnNode(IMUL));
- // stack: bytes, target, this
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "copy", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";I)V"));
- // stack: -
-
- return list;
- }
-
- private static InsnList generateCopyToInstructions(final MappedSubtypeInfo mappedType) {
- final InsnList list = new InsnList();
-
- // stack: target, this
- list.add(getIntNode(mappedType.sizeof - mappedType.padding));
- // stack: sizeof, target, this
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "copy", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";I)V"));
- // stack: -
-
- return list;
- }
-
- private static InsnList generateRunViewConstructorInstructions(final MethodInsnNode methodInsn) {
- final InsnList list = new InsnList();
-
- // stack: this
- list.add(new InsnNode(DUP));
- // stack: this, this
- list.add(new MethodInsnNode(INVOKEVIRTUAL, methodInsn.owner, VIEW_CONSTRUCTOR_NAME, "()V"));
- // stack: this
-
- return list;
- }
-
- private static InsnList generateSliceInstructions(final MethodInsnNode methodInsn) {
- final InsnList list = new InsnList();
-
- // stack: this
- list.add(new TypeInsnNode(NEW, methodInsn.owner));
- // stack: new, this
- list.add(new InsnNode(DUP));
- // stack: new, new, this
- list.add(new MethodInsnNode(INVOKESPECIAL, methodInsn.owner, "<init>", "()V"));
- // stack: new, this
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "slice", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";)L" + MAPPED_OBJECT_JVM + ";"));
- // stack: new
-
- return list;
- }
-
- private static InsnList generateDupInstructions(final MethodInsnNode methodInsn) {
- final InsnList list = new InsnList();
-
- // stack: this
- list.add(new TypeInsnNode(NEW, methodInsn.owner));
- // stack: new, this
- list.add(new InsnNode(DUP));
- // stack: new, new, this
- list.add(new MethodInsnNode(INVOKESPECIAL, methodInsn.owner, "<init>", "()V"));
- // stack: new, this
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "dup", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";)L" + MAPPED_OBJECT_JVM + ";"));
- // stack: new
-
- return list;
- }
-
- private static InsnList generateMapInstructions(final MappedSubtypeInfo mappedType, final String className, final boolean mapDirectMethod, final boolean mallocMethod) {
- final InsnList trg = new InsnList();
-
- if ( mallocMethod ) {
- // stack: count
- trg.add(getIntNode(mappedType.sizeof));
- // stack: sizeof, count
- trg.add(new InsnNode(IMUL));
- // stack: bytes
- trg.add(new MethodInsnNode(INVOKESTATIC, mappedType.cacheLinePadded ? jvmClassName(CacheUtil.class) : jvmClassName(BufferUtils.class), "createByteBuffer", "(I)L" + jvmClassName(ByteBuffer.class) + ";"));
- // stack: buffer
- } else if ( mapDirectMethod ) {
- // stack: capacity, address
- trg.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";"));
- // stack: buffer
- }
-
- // stack: buffer
- trg.add(new TypeInsnNode(NEW, className));
- // stack: new, buffer
- trg.add(new InsnNode(DUP));
- // stack: new, new, buffer
- trg.add(new MethodInsnNode(INVOKESPECIAL, className, "<init>", "()V"));
- // stack: new, buffer
- trg.add(new InsnNode(DUP_X1));
- // stack: new, buffer, new
- trg.add(new InsnNode(SWAP));
- // stack: buffer, new, new
- trg.add(getIntNode(mappedType.align));
- // stack: int, buffer, new, new
- trg.add(getIntNode(mappedType.sizeof));
- // stack: int, int, buffer, new, new
- trg.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "setup", "(L" + MAPPED_OBJECT_JVM + ";Ljava/nio/ByteBuffer;II)V"));
- // stack: new
-
- return trg;
- }
-
- static InsnList transformFieldAccess(final FieldInsnNode fieldInsn) {
- final MappedSubtypeInfo mappedSubtype;
- mappedSubtype = className_to_subtype.get(fieldInsn.owner);
- if ( mappedSubtype == null ) { // early out
- // MappedSet.view
- outer:
- if ( "view".equals(fieldInsn.name) && fieldInsn.owner.startsWith(MAPPEDSET_PREFIX) )
- return generateSetViewInstructions(fieldInsn);
-
- return null; // early out
- }
-
- if ( "SIZEOF".equals(fieldInsn.name) )
- return generateSIZEOFInstructions(fieldInsn, mappedSubtype);
-
- if ( "view".equals(fieldInsn.name) )
- return generateViewInstructions(fieldInsn, mappedSubtype);
-
- if ( "baseAddress".equals(fieldInsn.name) || "viewAddress".equals(fieldInsn.name) ) {
- return generateAddressInstructions(fieldInsn);
- }
-
- final FieldInfo field = mappedSubtype.fields.get(fieldInsn.name);
- if ( field == null ) // early out
- return null;
-
- // now we're going to transform ByteBuffer-typed field access
- if ( fieldInsn.desc.equals("L" + jvmClassName(ByteBuffer.class) + ";") )
- return generateByteBufferInstructions(fieldInsn, mappedSubtype, field.offset);
-
- // we're now going to transform the field access
- return generateFieldInstructions(fieldInsn, field);
- }
-
- private static InsnList generateSetViewInstructions(final FieldInsnNode fieldInsn) {
- if ( fieldInsn.getOpcode() == GETFIELD )
- throwAccessErrorOnReadOnlyField(fieldInsn.owner, fieldInsn.name);
- if ( fieldInsn.getOpcode() != PUTFIELD )
- throw new InternalError();
-
- final InsnList list = new InsnList();
-
- // stack: index, this
- if ( MAPPED_SET2_JVM.equals(fieldInsn.owner) )
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_views", "(L" + MAPPED_SET2_JVM + ";I)V"));
- else if ( MAPPED_SET3_JVM.equals(fieldInsn.owner) )
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_views", "(L" + MAPPED_SET3_JVM + ";I)V"));
- else if ( MAPPED_SET4_JVM.equals(fieldInsn.owner) )
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_views", "(L" + MAPPED_SET4_JVM + ";I)V"));
- else
- throw new InternalError();
- // stack: -
-
- return list;
- }
-
- private static InsnList generateSIZEOFInstructions(final FieldInsnNode fieldInsn, final MappedSubtypeInfo mappedSubtype) {
- if ( !"I".equals(fieldInsn.desc) )
- throw new InternalError();
-
- final InsnList list = new InsnList();
-
- if ( fieldInsn.getOpcode() == GETSTATIC ) {
- list.add(getIntNode(mappedSubtype.sizeof));
- return list;
- }
-
- if ( fieldInsn.getOpcode() == PUTSTATIC )
- throwAccessErrorOnReadOnlyField(fieldInsn.owner, fieldInsn.name);
-
- throw new InternalError();
- }
-
- private static InsnList generateViewInstructions(final FieldInsnNode fieldInsn, final MappedSubtypeInfo mappedSubtype) {
- if ( !"I".equals(fieldInsn.desc) )
- throw new InternalError();
-
- final InsnList list = new InsnList();
-
- if ( fieldInsn.getOpcode() == GETFIELD ) {
- if ( mappedSubtype.sizeof_shift != 0 ) {
- // stack: instance
- list.add(getIntNode(mappedSubtype.sizeof_shift));
- // stack: sizeof, instance
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "get_view_shift", "(L" + MAPPED_OBJECT_JVM + ";I)I"));
- // stack: view
- } else {
- // stack: instance
- list.add(getIntNode(mappedSubtype.sizeof));
- // stack: sizeof, instance
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "get_view", "(L" + MAPPED_OBJECT_JVM + ";I)I"));
- // stack: view
- }
- return list;
- }
-
- if ( fieldInsn.getOpcode() == PUTFIELD ) {
- if ( mappedSubtype.sizeof_shift != 0 ) {
- // stack: view, instance
- list.add(getIntNode(mappedSubtype.sizeof_shift));
- // stack: sizeof, view, instance
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_view_shift", "(L" + MAPPED_OBJECT_JVM + ";II)V"));
- // stack: -
- } else {
- // stack: view, instance
- list.add(getIntNode(mappedSubtype.sizeof));
- // stack: sizeof, view, instance
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_view", "(L" + MAPPED_OBJECT_JVM + ";II)V"));
- // stack: -
- }
- return list;
- }
-
- throw new InternalError();
- }
-
- private static InsnList generateAddressInstructions(final FieldInsnNode fieldInsn) {
- if ( !"J".equals(fieldInsn.desc) )
- throw new IllegalStateException();
-
- if ( fieldInsn.getOpcode() == GETFIELD ) // do not change a thing
- return null;
-
- if ( fieldInsn.getOpcode() == PUTFIELD )
- throwAccessErrorOnReadOnlyField(fieldInsn.owner, fieldInsn.name);
-
- throw new InternalError();
- }
-
- private static InsnList generateByteBufferInstructions(final FieldInsnNode fieldInsn, final MappedSubtypeInfo mappedSubtype, final long fieldOffset) {
- if ( fieldInsn.getOpcode() == PUTFIELD )
- throwAccessErrorOnReadOnlyField(fieldInsn.owner, fieldInsn.name);
-
- if ( fieldInsn.getOpcode() == GETFIELD ) {
- final InsnList list = new InsnList();
-
- // stack: ref
- list.add(new FieldInsnNode(GETFIELD, mappedSubtype.className, "viewAddress", "J"));
- // stack: long
- list.add(new LdcInsnNode(fieldOffset));
- // stack: long, long
- list.add(new InsnNode(LADD));
- // stack: long
- list.add(new LdcInsnNode(mappedSubtype.fields.get(fieldInsn.name).length));
- // stack: long, long
- list.add(new InsnNode(L2I));
- // stack: int, long
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";"));
- // stack: buffer
-
- return list;
- }
-
- throw new InternalError();
- }
-
- private static InsnList generateFieldInstructions(final FieldInsnNode fieldInsn, final FieldInfo field) {
- final InsnList list = new InsnList();
-
- if ( fieldInsn.getOpcode() == PUTFIELD ) {
- // stack: value, ref
- list.add(getIntNode((int)field.offset));
- // stack: fieldOffset, value, ref
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, field.getAccessType() + "put", "(L" + MAPPED_OBJECT_JVM + ";" + fieldInsn.desc + "I)V"));
- // stack -
- return list;
- }
-
- if ( fieldInsn.getOpcode() == GETFIELD ) {
- // stack: ref
- list.add(getIntNode((int)field.offset));
- // stack: fieldOffset, ref
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, field.getAccessType() + "get", "(L" + MAPPED_OBJECT_JVM + ";I)" + fieldInsn.desc));
- // stack: -
- return list;
- }
-
- throw new InternalError();
- }
-
- static int transformArrayAccess(final InsnList instructions, int i, final Map<AbstractInsnNode, Frame<BasicValue>> frameMap, final VarInsnNode loadInsn, final MappedSubtypeInfo mappedSubtype, final int var) {
- // We need to go forward in time to find how we use the array var
- final int loadStackSize = frameMap.get(loadInsn).getStackSize() + 1;
-
- AbstractInsnNode nextInsn = loadInsn;
-
- while ( true ) {
- nextInsn = nextInsn.getNext();
- if ( nextInsn == null )
- throw new InternalError();
-
- Frame<BasicValue> frame = frameMap.get(nextInsn);
- if ( frame == null )
- continue;
-
- int stackSize = frame.getStackSize();
-
- if ( stackSize == loadStackSize + 1 && nextInsn.getOpcode() == AALOAD ) {
- final AbstractInsnNode aaLoadInsn = nextInsn;
-
- while ( true ) {
- nextInsn = nextInsn.getNext();
- if ( nextInsn == null )
- break;
-
- frame = frameMap.get(nextInsn);
- if ( frame == null )
- continue;
- stackSize = frame.getStackSize();
-
- if ( stackSize == loadStackSize + 1 && nextInsn.getOpcode() == PUTFIELD ) {
- final FieldInsnNode fieldInsn = (FieldInsnNode)nextInsn;
-
- // stack: value, view, ref
- instructions.insert(nextInsn, new MethodInsnNode(INVOKESTATIC, mappedSubtype.className, setterName(fieldInsn.name), "(L" + mappedSubtype.className + ";I" + fieldInsn.desc + ")V"));
- // stack: -
- instructions.remove(nextInsn);
-
- break;
- } else if ( stackSize == loadStackSize && nextInsn.getOpcode() == GETFIELD ) {
- final FieldInsnNode fieldInsn = (FieldInsnNode)nextInsn;
-
- // stack: view, ref
- instructions.insert(nextInsn, new MethodInsnNode(INVOKESTATIC, mappedSubtype.className, getterName(fieldInsn.name), "(L" + mappedSubtype.className + ";I)" + fieldInsn.desc));
- // stack: value
- instructions.remove(nextInsn);
-
- break;
- } else if ( stackSize == loadStackSize && nextInsn.getOpcode() == DUP && nextInsn.getNext().getOpcode() == GETFIELD ) {
- // May happen with operator+assignment (e.g. cursor[i].value += 10)
- final FieldInsnNode fieldInsn = (FieldInsnNode)nextInsn.getNext();
-
- final MethodInsnNode getter = new MethodInsnNode(INVOKESTATIC, mappedSubtype.className, getterName(fieldInsn.name), "(L" + mappedSubtype.className + ";I)" + fieldInsn.desc);
-
- // stack: view, ref
- instructions.insert(nextInsn, new InsnNode(DUP2));
- // stack: view, ref, view, ref
- instructions.insert(nextInsn.getNext(), getter);
- // stack: value, view, ref
-
- instructions.remove(nextInsn);
- instructions.remove(fieldInsn);
-
- nextInsn = getter;
- continue;
- } else if ( stackSize < loadStackSize )
- throw new ClassFormatError("Invalid " + mappedSubtype.className + " view array usage detected: " + getOpcodeName(nextInsn));
- }
-
- instructions.remove(aaLoadInsn);
-
- return i;
- } else if ( stackSize == loadStackSize && nextInsn.getOpcode() == ARRAYLENGTH ) {
- if ( LWJGLUtil.DEBUG && loadInsn.getNext() != nextInsn )
- throw new InternalError();
-
- instructions.remove(nextInsn);
- loadInsn.var = var;
- instructions.insert(loadInsn, new MethodInsnNode(INVOKEVIRTUAL, mappedSubtype.className, CAPACITY_METHOD_NAME, "()I"));
-
- return i + 1;
- } else if ( stackSize < loadStackSize ) // Consumed by something other than AALOAD or ARRAYLENGTH
- throw new ClassFormatError("Invalid " + mappedSubtype.className + " view array usage detected: " + getOpcodeName(nextInsn));
- }
- }
-
- private static class FieldInfo {
-
- final long offset;
- final long length;
- final long lengthPadded;
- final Type type;
- final boolean isVolatile;
- final boolean isPointer;
-
- FieldInfo(final long offset, final long length, final long lengthPadded, final Type type, final boolean isVolatile, final boolean isPointer) {
- this.offset = offset;
- this.length = length;
- this.lengthPadded = lengthPadded;
- this.type = type;
- this.isVolatile = isVolatile;
- this.isPointer = isPointer;
- }
-
- String getAccessType() {
- return isPointer ? "a" : type.getDescriptor().toLowerCase() + (isVolatile ? "v" : "");
- }
-
- }
-
- private static class MappedSubtypeInfo {
-
- final String className;
-
- final int sizeof;
- final int sizeof_shift;
- final int align;
- final int padding;
- final boolean cacheLinePadded;
-
- final Map<String, FieldInfo> fields;
-
- MappedSubtypeInfo(String className, Map<String, FieldInfo> fields, int sizeof, int align, int padding, final boolean cacheLinePadded) {
- this.className = className;
-
- this.sizeof = sizeof;
- if ( ((sizeof - 1) & sizeof) == 0 )
- this.sizeof_shift = getPoT(sizeof);
- else
- this.sizeof_shift = 0;
- this.align = align;
- this.padding = padding;
- this.cacheLinePadded = cacheLinePadded;
-
- this.fields = fields;
- }
-
- private static int getPoT(int value) {
- int pot = -1;
- while ( value > 0 ) {
- pot++;
- value >>= 1;
- }
- return pot;
- }
-
- }
-
- // -------------------------------------------------------
- // -------------------[ MACROS & UTILS ]------------------
- // -------------------------------------------------------
-
- private static void getClassEnums(final Class clazz, final Map<Integer, String> map, final String... prefixFilters) {
- try {
- OUTER:
- for ( Field field : clazz.getFields() ) {
- if ( !Modifier.isStatic(field.getModifiers()) || field.getType() != int.class )
- continue;
-
- for ( String filter : prefixFilters ) {
- if ( field.getName().startsWith(filter) )
- continue OUTER;
- }
-
- if ( map.put((Integer)field.get(null), field.getName()) != null )
- throw new IllegalStateException();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- static String getOpcodeName(final AbstractInsnNode insn) {
- final String op = OPCODE_TO_NAME.get(insn.getOpcode());
- return INSNTYPE_TO_NAME.get(insn.getType()) + ": " + insn.getOpcode() + (op == null ? "" : " [" + OPCODE_TO_NAME.get(insn.getOpcode()) + "]");
- }
-
- static String jvmClassName(Class<?> type) {
- return type.getName().replace('.', '/');
- }
-
- static String getterName(final String fieldName) {
- return "get$" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1) + "$LWJGL";
- }
-
- static String setterName(final String fieldName) {
- return "set$" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1) + "$LWJGL";
- }
-
- private static void checkInsnAfterIsArray(final AbstractInsnNode instruction, final int opcode) {
- if ( instruction == null )
- throw new ClassFormatError("Unexpected end of instructions after .asArray() method.");
-
- if ( instruction.getOpcode() != opcode )
- throw new ClassFormatError("The result of .asArray() must be stored to a local variable. Found: " + getOpcodeName(instruction));
- }
-
- static AbstractInsnNode getIntNode(final int value) {
- if ( value <= 5 && -1 <= value )
- return new InsnNode(ICONST_M1 + value + 1);
-
- if ( value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE )
- return new IntInsnNode(BIPUSH, value);
-
- if ( value >= Short.MIN_VALUE && value <= Short.MAX_VALUE )
- return new IntInsnNode(SIPUSH, value);
-
- return new LdcInsnNode(value);
- }
-
- static void visitIntNode(final MethodVisitor mv, final int value) {
- if ( value <= 5 && -1 <= value )
- mv.visitInsn(ICONST_M1 + value + 1);
- else if ( value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE )
- mv.visitIntInsn(BIPUSH, value);
- else if ( value >= Short.MIN_VALUE && value <= Short.MAX_VALUE )
- mv.visitIntInsn(SIPUSH, value);
- else
- mv.visitLdcInsn(value);
- }
-
- /** Replace an instruction with a list of instructions. */
- static int replace(final InsnList instructions, final int i, final AbstractInsnNode location, final InsnList list) {
- final int size = list.size();
-
- instructions.insert(location, list);
- instructions.remove(location);
-
- return i + (size - 1);
- }
-
- private static void throwAccessErrorOnReadOnlyField(String className, String fieldName) {
- throw new IllegalAccessError("The " + className + "." + fieldName + " field is final.");
- }
-
- private static void printBytecode(byte[] bytecode) {
- StringWriter sw = new StringWriter();
- ClassVisitor tracer = new TraceClassVisitor(new ClassWriter(0), new PrintWriter(sw));
- new ClassReader(bytecode).accept(tracer, 0);
- String dump = sw.toString();
-
- LWJGLUtil.log(dump);
- }
-
-}
\ No newline at end of file