Package list lwjgl / 6bd7f8d
Add no-asm-support.patch Markus Koschany 5 years ago
2 changed file(s) with 2481 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 From: Markus Koschany <apo@debian.org>
1 Date: Sat, 9 Apr 2016 20:28:48 +0200
2 Subject: no asm support
3
4 ---
5 .../org/lwjgl/test/mapped/TestMappedObject.java | 87 --
6 .../test/opengl/sprites/SpriteShootoutMapped.java | 838 -------------
7 .../lwjgl/util/mapped/MappedObjectClassLoader.java | 193 ---
8 .../lwjgl/util/mapped/MappedObjectTransformer.java | 1319 --------------------
9 4 files changed, 2437 deletions(-)
10 delete mode 100644 src/java/org/lwjgl/test/mapped/TestMappedObject.java
11 delete mode 100644 src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java
12 delete mode 100644 src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java
13 delete mode 100644 src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java
14
15 diff --git a/src/java/org/lwjgl/test/mapped/TestMappedObject.java b/src/java/org/lwjgl/test/mapped/TestMappedObject.java
16 deleted file mode 100644
17 index 0ae560e..0000000
18 --- a/src/java/org/lwjgl/test/mapped/TestMappedObject.java
19 +++ /dev/null
20 @@ -1,87 +0,0 @@
21 -/*
22 - * Copyright (c) 2002-2011 LWJGL Project
23 - * All rights reserved.
24 - *
25 - * Redistribution and use in source and binary forms, with or without
26 - * modification, are permitted provided that the following conditions are
27 - * met:
28 - *
29 - * * Redistributions of source code must retain the above copyright
30 - * notice, this list of conditions and the following disclaimer.
31 - *
32 - * * Redistributions in binary form must reproduce the above copyright
33 - * notice, this list of conditions and the following disclaimer in the
34 - * documentation and/or other materials provided with the distribution.
35 - *
36 - * * Neither the name of 'LWJGL' nor the names of
37 - * its contributors may be used to endorse or promote products derived
38 - * from this software without specific prior written permission.
39 - *
40 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
42 - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
44 - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45 - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
46 - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
47 - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
48 - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49 - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50 - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 - */
52 -package org.lwjgl.test.mapped;
53 -
54 -import org.lwjgl.util.mapped.MappedObjectClassLoader;
55 -import org.lwjgl.util.mapped.MappedObjectTransformer;
56 -
57 -/** @author Riven */
58 -@SuppressWarnings("static-access")
59 -public class TestMappedObject {
60 -
61 - static {
62 - boolean assertsEnabled = false;
63 - assert assertsEnabled = true; // Intentional side effect!!!
64 - if ( !assertsEnabled )
65 - throw new RuntimeException("Asserts must be enabled for this test.");
66 - }
67 -
68 - public static void main(String[] args) throws Exception {
69 - MappedObjectTransformer.register(MappedFloat.class);
70 - MappedObjectTransformer.register(MappedVec2.class);
71 - MappedObjectTransformer.register(MappedVec3.class);
72 - MappedObjectTransformer.register(MappedSomething.class);
73 - MappedObjectTransformer.register(MappedObjectTests3.Xyz.class);
74 - MappedObjectTransformer.register(MappedObjectTests4.MappedPointer.class);
75 - MappedObjectTransformer.register(MappedObjectTests4.MappedCacheLinePadded.class);
76 - MappedObjectTransformer.register(MappedObjectTests4.MappedFieldCacheLinePadded.class);
77 -
78 - if ( MappedObjectClassLoader.fork(TestMappedObject.class, args) ) {
79 - return;
80 - }
81 -
82 - MappedObjectTests1.testViewField();
83 -
84 - MappedObjectTests2.testFields();
85 -
86 - // MappedObjectBench.benchmarkMapped();
87 - // MappedObjectBench.benchmarkInstances();
88 - // MappedObjectBench.benchmarkIndirectArray();
89 - // MappedObjectBench.benchmarkDirectArray();
90 - // MappedObjectBench.benchmarkUnsafe();
91 -
92 - MappedObjectTests3.testMappedBuffer();
93 - MappedObjectTests3.testForeach();
94 - MappedObjectTests3.testConstructor();
95 - MappedObjectTests3.testMappedSet();
96 -
97 - MappedObjectTests4.testLocalView();
98 - //MappedObjectTests4.testLWJGL();
99 - MappedObjectTests4.testPointer();
100 - MappedObjectTests4.testCacheLineAlignment();
101 - MappedObjectTests4.testCacheLinePadding();
102 - MappedObjectTests4.testCacheLinePaddingPOJO();
103 -
104 - System.out.println("done");
105 - }
106 -
107 -}
108 \ No newline at end of file
109 diff --git a/src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java b/src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java
110 deleted file mode 100644
111 index 83805d1..0000000
112 --- a/src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java
113 +++ /dev/null
114 @@ -1,838 +0,0 @@
115 -/*
116 - * Copyright (c) 2002-2011 LWJGL Project
117 - * All rights reserved.
118 - *
119 - * Redistribution and use in source and binary forms, with or without
120 - * modification, are permitted provided that the following conditions are
121 - * met:
122 - *
123 - * * Redistributions of source code must retain the above copyright
124 - * notice, this list of conditions and the following disclaimer.
125 - *
126 - * * Redistributions in binary form must reproduce the above copyright
127 - * notice, this list of conditions and the following disclaimer in the
128 - * documentation and/or other materials provided with the distribution.
129 - *
130 - * * Neither the name of 'LWJGL' nor the names of
131 - * its contributors may be used to endorse or promote products derived
132 - * from this software without specific prior written permission.
133 - *
134 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
135 - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
136 - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
137 - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
138 - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
139 - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
140 - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
141 - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
142 - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
143 - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
144 - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
145 - */
146 -package org.lwjgl.test.opengl.sprites;
147 -
148 -import org.lwjgl.BufferUtils;
149 -import org.lwjgl.LWJGLException;
150 -import org.lwjgl.Sys;
151 -import org.lwjgl.input.Keyboard;
152 -import org.lwjgl.input.Mouse;
153 -import org.lwjgl.opengl.*;
154 -import org.lwjgl.util.mapped.MappedObject;
155 -import org.lwjgl.util.mapped.MappedObjectClassLoader;
156 -import org.lwjgl.util.mapped.MappedObjectTransformer;
157 -import org.lwjgl.util.mapped.MappedType;
158 -
159 -import java.awt.image.BufferedImage;
160 -import java.awt.image.Raster;
161 -import java.io.IOException;
162 -import java.nio.ByteBuffer;
163 -import java.util.Random;
164 -import javax.imageio.ImageIO;
165 -
166 -import static org.lwjgl.opengl.EXTTransformFeedback.*;
167 -import static org.lwjgl.opengl.GL11.*;
168 -import static org.lwjgl.opengl.GL12.*;
169 -import static org.lwjgl.opengl.GL15.*;
170 -import static org.lwjgl.opengl.GL20.*;
171 -import static org.lwjgl.opengl.GL30.*;
172 -
173 -/**
174 - * Sprite rendering demo. Three implementations are supported:
175 - * a) CPU animation + BufferData VBO update.
176 - * b) CPU animation + MapBufferRange VBO update.
177 - * c) GPU animation using transform feedback with a vertex shader.
178 - *
179 - * @author Spasi
180 - * @since 18/3/2011
181 - */
182 -public final class SpriteShootoutMapped {
183 -
184 - static final int SCREEN_WIDTH = 800;
185 - static final int SCREEN_HEIGHT = 600;
186 -
187 - private static final int ANIMATION_TICKS = 60;
188 -
189 - private boolean run = true;
190 - private boolean render = true;
191 - private boolean colorMask = true;
192 - private boolean animate = true;
193 - private boolean smooth;
194 - private boolean vsync;
195 -
196 - int ballSize = 42;
197 - int ballCount = 100 * 1000;
198 -
199 - private SpriteRenderer renderer;
200 -
201 - // OpenGL stuff
202 - private int texID;
203 - private int texBigID;
204 - private int texSmallID;
205 -
206 - long animateTime;
207 -
208 - private SpriteShootoutMapped() {
209 - }
210 -
211 - public static void main(String[] args) {
212 - MappedObjectTransformer.register(Pixel4b.class);
213 - MappedObjectTransformer.register(Pixel3b.class);
214 - MappedObjectTransformer.register(Sprite.class);
215 - MappedObjectTransformer.register(SpriteRender.class);
216 -
217 - if ( MappedObjectClassLoader.fork(SpriteShootoutMapped.class, args) )
218 - return;
219 -
220 - try {
221 - new SpriteShootoutMapped().start();
222 - } catch (LWJGLException e) {
223 - e.printStackTrace();
224 - }
225 - }
226 -
227 - private void start() throws LWJGLException {
228 - try {
229 - initGL();
230 -
231 - final ContextCapabilities caps = GLContext.getCapabilities();
232 - if ( !true && (caps.OpenGL30 || caps.GL_EXT_transform_feedback) )
233 - renderer = new SpriteRendererTF();
234 - else if ( true && caps.GL_ARB_map_buffer_range )
235 - renderer = new SpriteRendererMapped();
236 - else
237 - renderer = new SpriteRendererPlain();
238 -
239 - updateBalls(ballCount);
240 - run();
241 - } catch (Throwable t) {
242 - t.printStackTrace();
243 - } finally {
244 - destroy();
245 - }
246 - }
247 -
248 - private void initGL() throws LWJGLException {
249 - Display.setLocation((Display.getDisplayMode().getWidth() - SCREEN_WIDTH) / 2,
250 - (Display.getDisplayMode().getHeight() - SCREEN_HEIGHT) / 2);
251 - Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT));
252 - Display.setTitle("Sprite Shootout");
253 - Display.create();
254 - //Display.create(new PixelFormat(), new ContextAttribs(4, 1).withProfileCompatibility(true).withDebug(true));
255 - //AMDDebugOutput.glDebugMessageCallbackAMD(new AMDDebugOutputCallback());
256 -
257 - if ( !GLContext.getCapabilities().OpenGL20 )
258 - throw new RuntimeException("OpenGL 2.0 is required for this demo.");
259 -
260 - // Setup viewport
261 -
262 - glMatrixMode(GL_PROJECTION);
263 - glLoadIdentity();
264 - glOrtho(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT, -1.0, 1.0);
265 -
266 - glMatrixMode(GL_MODELVIEW);
267 - glLoadIdentity();
268 - glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
269 -
270 - glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
271 -
272 - // Create textures
273 -
274 - try {
275 - texSmallID = createTexture("res/ball_sm.png");
276 - texBigID = createTexture("res/ball.png");
277 - } catch (IOException e) {
278 - e.printStackTrace();
279 - System.exit(-1);
280 - }
281 - texID = texBigID;
282 -
283 - // Setup rendering state
284 -
285 - glEnable(GL_BLEND);
286 - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
287 -
288 - glEnable(GL_ALPHA_TEST);
289 - glAlphaFunc(GL_GREATER, 0.0f);
290 -
291 - glColorMask(colorMask, colorMask, colorMask, false);
292 - glDepthMask(false);
293 - glDisable(GL_DEPTH_TEST);
294 -
295 - // Setup geometry
296 -
297 - glEnableClientState(GL_VERTEX_ARRAY);
298 -
299 - Util.checkGLError();
300 - }
301 -
302 - private static int createTexture(final String path) throws IOException {
303 - final BufferedImage img = ImageIO.read(SpriteShootoutMapped.class.getClassLoader().getResource(path));
304 -
305 - final int w = img.getWidth();
306 - final int h = img.getHeight();
307 -
308 - final ByteBuffer buffer = readImage(img);
309 -
310 - final int texID = glGenTextures();
311 -
312 - glBindTexture(GL_TEXTURE_2D, texID);
313 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
314 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
315 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
316 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
317 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer);
318 -
319 - return texID;
320 - }
321 -
322 - public static class Pixel4b extends MappedObject {
323 -
324 - public byte r, g, b, a;
325 -
326 - }
327 -
328 - @MappedType(align = 3)
329 - public static class Pixel3b extends MappedObject {
330 -
331 - public byte r, g, b;
332 -
333 - }
334 -
335 - private static ByteBuffer readImage(final BufferedImage img) throws IOException {
336 - final Raster raster = img.getRaster();
337 -
338 - final int bands = raster.getNumBands();
339 -
340 - final int w = img.getWidth();
341 - final int h = img.getHeight();
342 -
343 - final int count = w * h;
344 -
345 - final byte[] pixels = new byte[count * bands];
346 - raster.getDataElements(0, 0, w, h, pixels);
347 -
348 - if ( bands == 4 ) {
349 - Pixel4b p = Pixel4b.malloc(count);
350 -
351 - int b = 0;
352 - for ( int i = 0; i < count; i++, b += 4 ) {
353 - // Pre-multiply alpha
354 - final float a = unpackUByte01(pixels[b + 3]);
355 -
356 - p.view = i;
357 - p.r = packUByte01(unpackUByte01(pixels[b + 2]) * a);
358 - p.g = packUByte01(unpackUByte01(pixels[b + 1]) * a);
359 - p.b = packUByte01(unpackUByte01(pixels[b + 0]) * a);
360 - p.a = pixels[b + 3];
361 - }
362 -
363 - return p.backingByteBuffer();
364 - } else if ( bands == 3 ) {
365 - Pixel3b p = Pixel3b.malloc(count);
366 -
367 - int b = 0;
368 - for ( int i = 0; i < count; i++, b += 3 ) {
369 - p.view = i;
370 - p.r = pixels[b + 2];
371 - p.g = pixels[b + 1];
372 - p.b = pixels[b + 0];
373 - }
374 -
375 - return p.backingByteBuffer();
376 - } else {
377 - ByteBuffer p = BufferUtils.createByteBuffer(count * bands);
378 - p.put(pixels, 0, p.capacity());
379 - p.flip();
380 - return p;
381 - }
382 -
383 - }
384 -
385 - private static float unpackUByte01(final byte x) {
386 - return (x & 0xFF) / 255.0f;
387 - }
388 -
389 - private static byte packUByte01(final float x) {
390 - return (byte)(x * 255.0f);
391 - }
392 -
393 - private void updateBalls(final int count) {
394 - System.out.println("NUMBER OF BALLS: " + count);
395 - renderer.updateBalls(ballCount);
396 - }
397 -
398 - private void run() {
399 - long startTime = System.currentTimeMillis() + 5000;
400 - long fps = 0;
401 -
402 - long time = Sys.getTime();
403 - final int ticksPerUpdate = (int)(Sys.getTimerResolution() / ANIMATION_TICKS);
404 -
405 - renderer.render(false, true, 0);
406 -
407 - while ( run ) {
408 - Display.processMessages();
409 - handleInput();
410 -
411 - glClear(GL_COLOR_BUFFER_BIT);
412 -
413 - final long currTime = Sys.getTime();
414 - final int delta = (int)(currTime - time);
415 - if ( smooth || delta >= ticksPerUpdate ) {
416 - renderer.render(render, animate, delta);
417 - time = currTime;
418 - } else
419 - renderer.render(render, false, 0);
420 -
421 - Display.update(false);
422 - //Display.sync(60);
423 -
424 - if ( startTime > System.currentTimeMillis() ) {
425 - fps++;
426 - } else {
427 - long timeUsed = 5000 + (startTime - System.currentTimeMillis());
428 - startTime = System.currentTimeMillis() + 5000;
429 - System.out.println("FPS: " + (Math.round(fps / (timeUsed / 1000.0) * 10) / 10.0) + ", Balls: " + ballCount);
430 - System.out.println("Animation: " + animateTime / fps);
431 - animateTime = 0;
432 - fps = 0;
433 - }
434 - }
435 - }
436 -
437 - private void handleInput() {
438 - if ( Display.isCloseRequested() )
439 - run = false;
440 -
441 - while ( Keyboard.next() ) {
442 - if ( Keyboard.getEventKeyState() )
443 - continue;
444 -
445 - switch ( Keyboard.getEventKey() ) {
446 - case Keyboard.KEY_1:
447 - case Keyboard.KEY_2:
448 - case Keyboard.KEY_3:
449 - case Keyboard.KEY_4:
450 - case Keyboard.KEY_5:
451 - case Keyboard.KEY_6:
452 - case Keyboard.KEY_7:
453 - case Keyboard.KEY_8:
454 - case Keyboard.KEY_9:
455 - case Keyboard.KEY_0:
456 - ballCount = 1 << (Keyboard.getEventKey() - Keyboard.KEY_1);
457 - updateBalls(ballCount);
458 - break;
459 - case Keyboard.KEY_ADD:
460 - case Keyboard.KEY_SUBTRACT:
461 - int mult;
462 - if ( Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT) )
463 - mult = 1000;
464 - else if ( Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU) )
465 - mult = 100;
466 - else if ( Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL) )
467 - mult = 10;
468 - else
469 - mult = 1;
470 - if ( Keyboard.getEventKey() == Keyboard.KEY_SUBTRACT )
471 - mult = -mult;
472 - ballCount += mult * 100;
473 - if ( ballCount <= 0 )
474 - ballCount = 1;
475 - updateBalls(ballCount);
476 - break;
477 - case Keyboard.KEY_ESCAPE:
478 - run = false;
479 - break;
480 - case Keyboard.KEY_A:
481 - animate = !animate;
482 - System.out.println("Animation is now " + (animate ? "on" : "off") + ".");
483 - break;
484 - case Keyboard.KEY_C:
485 - colorMask = !colorMask;
486 - glColorMask(colorMask, colorMask, colorMask, false);
487 - System.out.println("Color mask is now " + (colorMask ? "on" : "off") + ".");
488 - // Disable alpha test when color mask is off, else we get no benefit.
489 - if ( colorMask ) {
490 - glEnable(GL_BLEND);
491 - glEnable(GL_ALPHA_TEST);
492 - } else {
493 - glDisable(GL_BLEND);
494 - glDisable(GL_ALPHA_TEST);
495 - }
496 - break;
497 - case Keyboard.KEY_R:
498 - render = !render;
499 - System.out.println("Rendering is now " + (render ? "on" : "off") + ".");
500 - break;
501 - case Keyboard.KEY_S:
502 - smooth = !smooth;
503 - System.out.println("Smooth animation is now " + (smooth ? "on" : "off") + ".");
504 - break;
505 - case Keyboard.KEY_T:
506 - if ( texID == texBigID ) {
507 - texID = texSmallID;
508 - ballSize = 16;
509 - } else {
510 - texID = texBigID;
511 - ballSize = 42;
512 - }
513 - renderer.updateBallSize();
514 - glBindTexture(GL_TEXTURE_2D, texID);
515 - System.out.println("Now using the " + (texID == texBigID ? "big" : "small") + " texture.");
516 - break;
517 - case Keyboard.KEY_V:
518 - vsync = !vsync;
519 - Display.setVSyncEnabled(vsync);
520 - System.out.println("VSYNC is now " + (vsync ? "enabled" : "disabled") + ".");
521 - break;
522 - }
523 - }
524 -
525 - while ( Mouse.next() ) ;
526 - }
527 -
528 - private void destroy() {
529 - Display.destroy();
530 - }
531 -
532 - public static class Sprite extends MappedObject {
533 -
534 - public float dx, x;
535 - public float dy, y;
536 -
537 - }
538 -
539 - public static class SpriteRender extends MappedObject {
540 -
541 - public float x, y;
542 -
543 - }
544 -
545 - private abstract class SpriteRenderer {
546 -
547 - protected Sprite sprites;
548 -
549 - protected int spriteCount;
550 -
551 - protected int vshID;
552 - protected int progID;
553 -
554 - protected void createProgram() {
555 - final int fshID = glCreateShader(GL_FRAGMENT_SHADER);
556 - glShaderSource(fshID, "uniform sampler2D COLOR_MAP;\n" +
557 - "void main(void) {\n" +
558 - " gl_FragColor = texture2D(COLOR_MAP, gl_PointCoord);\n" +
559 - "}");
560 - glCompileShader(fshID);
561 - if ( glGetShaderi(fshID, GL_COMPILE_STATUS) == GL_FALSE ) {
562 - System.out.println(glGetShaderInfoLog(fshID, glGetShaderi(fshID, GL_INFO_LOG_LENGTH)));
563 - throw new RuntimeException("Failed to compile fragment shader.");
564 - }
565 -
566 - progID = glCreateProgram();
567 - glAttachShader(progID, vshID);
568 - glAttachShader(progID, fshID);
569 - glLinkProgram(progID);
570 - if ( glGetProgrami(progID, GL_LINK_STATUS) == GL_FALSE ) {
571 - System.out.println(glGetProgramInfoLog(progID, glGetProgrami(progID, GL_INFO_LOG_LENGTH)));
572 - throw new RuntimeException("Failed to link shader program.");
573 - }
574 -
575 - glUseProgram(progID);
576 - glUniform1i(glGetUniformLocation(progID, "COLOR_MAP"), 0);
577 -
578 - updateBallSize();
579 -
580 - glEnableClientState(GL_VERTEX_ARRAY);
581 - }
582 -
583 - public void updateBallSize() {
584 - glPointSize(ballSize);
585 - }
586 -
587 - public abstract void updateBalls(int count);
588 -
589 - protected abstract void render(boolean render, boolean animate, int delta);
590 -
591 - }
592 -
593 - private abstract class SpriteRendererBatched extends SpriteRenderer {
594 -
595 - protected static final int BALLS_PER_BATCH = 10 * 1000;
596 -
597 - SpriteRendererBatched() {
598 - vshID = glCreateShader(GL_VERTEX_SHADER);
599 - glShaderSource(vshID, "void main(void) {\n" +
600 - " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" +
601 - "}");
602 - glCompileShader(vshID);
603 - if ( glGetShaderi(vshID, GL_COMPILE_STATUS) == GL_FALSE ) {
604 - System.out.println(glGetShaderInfoLog(vshID, glGetShaderi(vshID, GL_INFO_LOG_LENGTH)));
605 - throw new RuntimeException("Failed to compile vertex shader.");
606 - }
607 -
608 - createProgram();
609 - }
610 -
611 - public void updateBalls(final int count) {
612 - final Random random = new Random();
613 -
614 - final Sprite newSprites = Sprite.malloc(count);
615 - if ( sprites != null ) {
616 - sprites.view = 0;
617 - sprites.copyRange(newSprites, Math.min(count, spriteCount));
618 - }
619 -
620 - if ( count > spriteCount ) {
621 - for ( int i = spriteCount; i < count; i++ ) {
622 - newSprites.view = i;
623 -
624 - newSprites.x = (int)(random.nextFloat() * (SCREEN_WIDTH - ballSize) + ballSize * 0.5f);
625 - newSprites.y = (int)(random.nextFloat() * (SCREEN_HEIGHT - ballSize) + ballSize * 0.5f);
626 - newSprites.dx = random.nextFloat() * 0.4f - 0.2f;
627 - newSprites.dy = random.nextFloat() * 0.4f - 0.2f;
628 - }
629 - }
630 -
631 - sprites = newSprites;
632 - spriteCount = count;
633 - }
634 -
635 - protected void animate(
636 - final Sprite sprite,
637 - final SpriteRender spriteRender,
638 - final int ballSize, final int ballIndex, final int batchSize, final int delta
639 - ) {
640 - final float ballRadius = ballSize * 0.5f;
641 - final float boundW = SCREEN_WIDTH - ballRadius;
642 - final float boundH = SCREEN_HEIGHT - ballRadius;
643 -
644 - final Sprite[] sprites = sprite.asArray();
645 - final SpriteRender[] spritesRender = spriteRender.asArray();
646 - for ( int b = ballIndex, r = 0, len = (ballIndex + batchSize); b < len; b++, r++ ) {
647 - float dx = sprites[b].dx;
648 - float x = sprites[b].x;
649 -
650 - x += dx * delta;
651 - if ( x < ballRadius ) {
652 - x = ballRadius;
653 - dx = -dx;
654 - } else if ( x > boundW ) {
655 - x = boundW;
656 - dx = -dx;
657 - }
658 -
659 - sprites[b].dx = dx;
660 - sprites[b].x = x;
661 - spritesRender[r].x = x;
662 -
663 - float dy = sprites[b].dy;
664 - float y = sprites[b].y;
665 -
666 - y += dy * delta;
667 - if ( y < ballRadius ) {
668 - y = ballRadius;
669 - dy = -dy;
670 - } else if ( y > boundH ) {
671 - y = boundH;
672 - dy = -dy;
673 - }
674 -
675 - sprites[b].dy = dy;
676 - sprites[b].y = y;
677 - spritesRender[r].y = y;
678 - }
679 - }
680 -
681 - }
682 -
683 - private class SpriteRendererPlain extends SpriteRendererBatched {
684 -
685 - private final int DATA_PER_BATCH = BALLS_PER_BATCH * 2 * 4; // balls * 2 floats * 4 bytes
686 -
687 - protected int[] animVBO;
688 -
689 - private SpriteRender spritesRender;
690 -
691 - SpriteRendererPlain() {
692 - System.out.println("Shootout Implementation: CPU animation & BufferData");
693 - spritesRender = SpriteRender.malloc(BALLS_PER_BATCH);
694 - }
695 -
696 - public void updateBalls(final int count) {
697 - super.updateBalls(count);
698 -
699 - final int batchCount = count / BALLS_PER_BATCH + (count % BALLS_PER_BATCH == 0 ? 0 : 1);
700 - if ( animVBO != null && batchCount == animVBO.length )
701 - return;
702 -
703 - final int[] newAnimVBO = new int[batchCount];
704 - if ( animVBO != null ) {
705 - System.arraycopy(animVBO, 0, newAnimVBO, 0, Math.min(animVBO.length, newAnimVBO.length));
706 - for ( int i = newAnimVBO.length; i < animVBO.length; i++ )
707 - glDeleteBuffers(animVBO[i]);
708 - }
709 - for ( int i = animVBO == null ? 0 : animVBO.length; i < newAnimVBO.length; i++ ) {
710 - newAnimVBO[i] = glGenBuffers();
711 - glBindBuffer(GL_ARRAY_BUFFER, newAnimVBO[i]);
712 - }
713 -
714 - animVBO = newAnimVBO;
715 - }
716 -
717 - public void render(final boolean render, final boolean animate, final int delta) {
718 - int batchSize = Math.min(ballCount, BALLS_PER_BATCH);
719 - int ballIndex = 0;
720 - int batchIndex = 0;
721 - while ( ballIndex < ballCount ) {
722 - glBindBuffer(GL_ARRAY_BUFFER, animVBO[batchIndex]);
723 -
724 - if ( animate )
725 - animate(ballIndex, batchSize, delta);
726 -
727 - if ( render ) {
728 - glVertexPointer(2, GL_FLOAT, 0, 0);
729 - glDrawArrays(GL_POINTS, 0, batchSize);
730 - }
731 -
732 - ballIndex += batchSize;
733 - batchSize = Math.min(ballCount - ballIndex, BALLS_PER_BATCH);
734 - batchIndex++;
735 - }
736 - }
737 -
738 - private void animate(final int ballIndex, final int batchSize, final int delta) {
739 - animate(
740 - sprites, spritesRender,
741 - ballSize, ballIndex, batchSize, delta
742 - );
743 -
744 - glBufferData(GL_ARRAY_BUFFER, DATA_PER_BATCH, GL_STREAM_DRAW);
745 - glBufferSubData(GL_ARRAY_BUFFER, 0, spritesRender.backingByteBuffer());
746 - }
747 -
748 - }
749 -
750 - private class SpriteRendererMapped extends SpriteRendererBatched {
751 -
752 - private StreamVBO animVBO;
753 -
754 - SpriteRendererMapped() {
755 - System.out.println("Shootout Implementation: CPU animation & MapBufferRange");
756 - }
757 -
758 - public void updateBalls(final int count) {
759 - super.updateBalls(count);
760 -
761 - if ( animVBO != null )
762 - animVBO.destroy();
763 -
764 - animVBO = new StreamVBO(GL_ARRAY_BUFFER, ballCount * (2 * 4));
765 - }
766 -
767 - public void render(final boolean render, final boolean animate, final int delta) {
768 - int batchSize = Math.min(ballCount, BALLS_PER_BATCH);
769 - int ballIndex = 0;
770 - while ( ballIndex < ballCount ) {
771 - if ( animate ) {
772 - final ByteBuffer buffer = animVBO.map(batchSize * (2 * 4));
773 -
774 - long t0 = System.nanoTime();
775 - animate(sprites, SpriteRender.<SpriteRender>map(buffer), ballSize, ballIndex, batchSize, delta);
776 - long t1 = System.nanoTime();
777 -
778 - animateTime += t1 - t0;
779 -
780 - animVBO.unmap();
781 - }
782 -
783 - if ( render ) {
784 - glVertexPointer(2, GL_FLOAT, 0, ballIndex * (2 * 4));
785 - glDrawArrays(GL_POINTS, 0, batchSize);
786 - }
787 -
788 - ballIndex += batchSize;
789 - batchSize = Math.min(ballCount - ballIndex, BALLS_PER_BATCH);
790 - }
791 - }
792 -
793 - }
794 -
795 - private class SpriteRendererTF extends SpriteRenderer {
796 -
797 - private int progIDTF;
798 - private int ballSizeLoc;
799 - private int deltaLoc;
800 -
801 - private int[] tfVBO = new int[2];
802 - private int currVBO;
803 -
804 - SpriteRendererTF() {
805 - System.out.println("Shootout Implementation: TF GPU animation");
806 -
807 - // Transform-feedback program
808 -
809 - final int vshID = glCreateShader(GL_VERTEX_SHADER);
810 - glShaderSource(vshID, "#version 130\n" +
811 - "const float WIDTH = " + SCREEN_WIDTH + ";\n" +
812 - "const float HEIGHT = " + SCREEN_HEIGHT + ";\n" +
813 - "uniform float ballSize;\n" + // ballSize / 2
814 - "uniform float delta;\n" +
815 - "void main(void) {\n" +
816 - " vec4 anim = gl_Vertex;\n" +
817 - " anim.xy = anim.xy + anim.zw * delta;\n" +
818 - " vec2 animC = clamp(anim.xy, vec2(ballSize), vec2(WIDTH - ballSize, HEIGHT - ballSize));\n" +
819 - " if ( anim.x != animC.x ) anim.z = -anim.z;\n" +
820 - " if ( anim.y != animC.y ) anim.w = -anim.w;\n" +
821 - " gl_Position = vec4(animC, anim.zw);\n" +
822 - "}");
823 - glCompileShader(vshID);
824 - if ( glGetShaderi(vshID, GL_COMPILE_STATUS) == GL_FALSE ) {
825 - System.out.println(glGetShaderInfoLog(vshID, glGetShaderi(vshID, GL_INFO_LOG_LENGTH)));
826 - throw new RuntimeException("Failed to compile vertex shader.");
827 - }
828 -
829 - progIDTF = glCreateProgram();
830 - glAttachShader(progIDTF, vshID);
831 - glTransformFeedbackVaryings(progIDTF, new CharSequence[] { "gl_Position" }, GL_SEPARATE_ATTRIBS);
832 - glLinkProgram(progIDTF);
833 - if ( glGetProgrami(progIDTF, GL_LINK_STATUS) == GL_FALSE ) {
834 - System.out.println(glGetProgramInfoLog(progIDTF, glGetProgrami(progIDTF, GL_INFO_LOG_LENGTH)));
835 - throw new RuntimeException("Failed to link shader program.");
836 - }
837 -
838 - glUseProgram(progIDTF);
839 -
840 - ballSizeLoc = glGetUniformLocation(progIDTF, "ballSize");
841 - deltaLoc = glGetUniformLocation(progIDTF, "delta");
842 -
843 - glUniform1f(ballSizeLoc, ballSize * 0.5f);
844 -
845 - // -----------------
846 -
847 - this.vshID = glCreateShader(GL_VERTEX_SHADER);
848 - glShaderSource(this.vshID, "void main(void) {\n" +
849 - " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" +
850 - "}");
851 - glCompileShader(this.vshID);
852 - if ( glGetShaderi(this.vshID, GL_COMPILE_STATUS) == GL_FALSE ) {
853 - System.out.println(glGetShaderInfoLog(this.vshID, glGetShaderi(this.vshID, GL_INFO_LOG_LENGTH)));
854 - throw new RuntimeException("Failed to compile vertex shader.");
855 - }
856 -
857 - createProgram();
858 - }
859 -
860 - public void updateBallSize() {
861 - glUseProgram(progIDTF);
862 - glUniform1f(ballSizeLoc, ballSize * 0.5f);
863 -
864 - glUseProgram(progID);
865 - super.updateBallSize();
866 - }
867 -
868 - private void doUpdateBalls(final int count) {
869 - final Random random = new Random();
870 -
871 - final Sprite newSprites = Sprite.malloc(count);
872 - if ( sprites != null ) {
873 - sprites.view = 0;
874 - sprites.copyRange(newSprites, Math.min(count, spriteCount));
875 - }
876 -
877 - if ( count > spriteCount ) {
878 - for ( int i = spriteCount; i < count; i++ ) {
879 - newSprites.view = i;
880 -
881 - newSprites.x = (int)(random.nextFloat() * (SCREEN_WIDTH - ballSize) + ballSize * 0.5f);
882 - newSprites.y = (int)(random.nextFloat() * (SCREEN_HEIGHT - ballSize) + ballSize * 0.5f);
883 - newSprites.dx = random.nextFloat() * 0.4f - 0.2f;
884 - newSprites.dy = random.nextFloat() * 0.4f - 0.2f;
885 - }
886 - }
887 -
888 - sprites = newSprites;
889 - spriteCount = count;
890 - }
891 -
892 - public void updateBalls(final int count) {
893 - if ( tfVBO[0] != 0 ) {
894 - // Fetch current animation state
895 - glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sprites.backingByteBuffer());
896 - }
897 -
898 - doUpdateBalls(count);
899 -
900 - if ( tfVBO[0] != 0 ) {
901 - for ( int i = 0; i < tfVBO.length; i++ )
902 - glDeleteBuffers(tfVBO[i]);
903 - }
904 -
905 - for ( int i = 0; i < tfVBO.length; i++ ) {
906 - tfVBO[i] = glGenBuffers();
907 - glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tfVBO[i]);
908 - glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sprites.backingByteBuffer(), GL_STATIC_DRAW);
909 - }
910 -
911 - glBindBuffer(GL_ARRAY_BUFFER, tfVBO[0]);
912 - glVertexPointer(2, GL_FLOAT, (4 * 4), 0);
913 - }
914 -
915 - public void render(final boolean render, final boolean animate, final int delta) {
916 - if ( animate ) {
917 - glUseProgram(progIDTF);
918 - glUniform1f(deltaLoc, delta);
919 -
920 - final int vbo = currVBO;
921 - currVBO = 1 - currVBO;
922 -
923 - glBindBuffer(GL_ARRAY_BUFFER, tfVBO[vbo]);
924 - glVertexPointer(4, GL_FLOAT, 0, 0);
925 -
926 - glEnable(GL_RASTERIZER_DISCARD);
927 - if ( GLContext.getCapabilities().OpenGL30 ) {
928 - glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfVBO[1 - vbo]);
929 -
930 - glBeginTransformFeedback(GL_POINTS);
931 - glDrawArrays(GL_POINTS, 0, ballCount);
932 - glEndTransformFeedback();
933 - } else {
934 - glBindBufferBaseEXT(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0, tfVBO[1 - vbo]);
935 -
936 - glBeginTransformFeedbackEXT(GL_POINTS);
937 - glDrawArrays(GL_POINTS, 0, ballCount);
938 - glEndTransformFeedbackEXT();
939 - }
940 - glDisable(GL_RASTERIZER_DISCARD);
941 -
942 - glUseProgram(progID);
943 - glVertexPointer(2, GL_FLOAT, (4 * 4), 0);
944 - }
945 -
946 - if ( render )
947 - glDrawArrays(GL_POINTS, 0, ballCount);
948 - }
949 -
950 - }
951 -
952 -}
953 \ No newline at end of file
954 diff --git a/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java b/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java
955 deleted file mode 100644
956 index 463823f..0000000
957 --- a/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java
958 +++ /dev/null
959 @@ -1,193 +0,0 @@
960 -/*
961 - * Copyright (c) 2002-2011 LWJGL Project
962 - * All rights reserved.
963 - *
964 - * Redistribution and use in source and binary forms, with or without
965 - * modification, are permitted provided that the following conditions are
966 - * met:
967 - *
968 - * * Redistributions of source code must retain the above copyright
969 - * notice, this list of conditions and the following disclaimer.
970 - *
971 - * * Redistributions in binary form must reproduce the above copyright
972 - * notice, this list of conditions and the following disclaimer in the
973 - * documentation and/or other materials provided with the distribution.
974 - *
975 - * * Neither the name of 'LWJGL' nor the names of
976 - * its contributors may be used to endorse or promote products derived
977 - * from this software without specific prior written permission.
978 - *
979 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
980 - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
981 - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
982 - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
983 - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
984 - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
985 - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
986 - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
987 - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
988 - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
989 - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
990 - */
991 -package org.lwjgl.util.mapped;
992 -
993 -import org.lwjgl.LWJGLUtil;
994 -
995 -import java.io.IOException;
996 -import java.io.InputStream;
997 -import java.lang.reflect.InvocationTargetException;
998 -import java.lang.reflect.Method;
999 -import java.net.URLClassLoader;
1000 -
1001 -/**
1002 - * This classloader is responsible for applying the bytecode transformation to mapped objects.
1003 - * The transformation can either be applied using a Java agent, or with the convenient {@link #fork} method.
1004 - *
1005 - * @author Riven
1006 - */
1007 -public class MappedObjectClassLoader extends URLClassLoader {
1008 -
1009 - static final String MAPPEDOBJECT_PACKAGE_PREFIX = MappedObjectClassLoader.class.getPackage().getName() + ".";
1010 -
1011 - static boolean FORKED;
1012 -
1013 - /**
1014 - * Forks the specified class containing a main method, passing the specified arguments. See
1015 - * {@link org.lwjgl.test.mapped.TestMappedObject} for example usage.
1016 - *
1017 - * @param mainClass the class containing the main method
1018 - * @param args the arguments to pass
1019 - *
1020 - * @return true if the fork was successful.
1021 - */
1022 - public static boolean fork(Class<?> mainClass, String[] args) {
1023 - if ( FORKED ) {
1024 - return false;
1025 - }
1026 -
1027 - FORKED = true;
1028 -
1029 - try {
1030 - MappedObjectClassLoader loader = new MappedObjectClassLoader(mainClass);
1031 - loader.loadMappedObject();
1032 -
1033 - Class<?> replacedMainClass = loader.loadClass(mainClass.getName());
1034 - Method mainMethod = replacedMainClass.getMethod("main", String[].class);
1035 - mainMethod.invoke(null, new Object[] { args });
1036 - } catch (InvocationTargetException exc) {
1037 - Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), exc.getCause());
1038 - } catch (Throwable cause) {
1039 - throw new Error("failed to fork", cause);
1040 - }
1041 -
1042 - return true;
1043 - }
1044 -
1045 - private MappedObjectClassLoader(Class<?> mainClass) {
1046 - super(((URLClassLoader)mainClass.getClassLoader()).getURLs());
1047 - }
1048 -
1049 - protected synchronized Class<?> loadMappedObject() throws ClassNotFoundException {
1050 - final String name = MappedObject.class.getName();
1051 - String className = name.replace('.', '/');
1052 -
1053 - byte[] bytecode = readStream(this.getResourceAsStream(className.concat(".class")));
1054 -
1055 - long t0 = System.nanoTime();
1056 - bytecode = MappedObjectTransformer.transformMappedObject(bytecode);
1057 - long t1 = System.nanoTime();
1058 - total_time_transforming += (t1 - t0);
1059 -
1060 - if ( MappedObjectTransformer.PRINT_ACTIVITY )
1061 - printActivity(className, t0, t1);
1062 -
1063 - Class<?> clazz = super.defineClass(name, bytecode, 0, bytecode.length);
1064 - resolveClass(clazz);
1065 - return clazz;
1066 - }
1067 -
1068 - private static long total_time_transforming;
1069 -
1070 - @Override
1071 - protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
1072 - if ( name.startsWith("java.")
1073 - || name.startsWith("javax.")
1074 - || name.startsWith("sun.")
1075 - || name.startsWith("sunw.")
1076 - || name.startsWith("org.objectweb.asm.")
1077 - )
1078 - return super.loadClass(name, resolve);
1079 -
1080 - final String className = name.replace('.', '/');
1081 - final boolean inThisPackage = name.startsWith(MAPPEDOBJECT_PACKAGE_PREFIX);
1082 -
1083 - if ( inThisPackage && (
1084 - name.equals(MappedObjectClassLoader.class.getName())
1085 - || name.equals((MappedObjectTransformer.class.getName()))
1086 - || name.equals((CacheUtil.class.getName()))
1087 - ) )
1088 - return super.loadClass(name, resolve);
1089 -
1090 - byte[] bytecode = readStream(this.getResourceAsStream(className.concat(".class")));
1091 -
1092 - // Classes in this package do not get transformed, but need to go through here because we have transformed MappedObject.
1093 - if ( !(inThisPackage && name.substring(MAPPEDOBJECT_PACKAGE_PREFIX.length()).indexOf('.') == -1) ) {
1094 - long t0 = System.nanoTime();
1095 - final byte[] newBytecode = MappedObjectTransformer.transformMappedAPI(className, bytecode);
1096 - long t1 = System.nanoTime();
1097 -
1098 - total_time_transforming += (t1 - t0);
1099 -
1100 - if ( bytecode != newBytecode ) {
1101 - bytecode = newBytecode;
1102 - if ( MappedObjectTransformer.PRINT_ACTIVITY )
1103 - printActivity(className, t0, t1);
1104 - }
1105 - }
1106 -
1107 - Class<?> clazz = super.defineClass(name, bytecode, 0, bytecode.length);
1108 - if ( resolve )
1109 - resolveClass(clazz);
1110 - return clazz;
1111 - }
1112 -
1113 - private static void printActivity(final String className, final long t0, final long t1) {
1114 - final StringBuilder msg = new StringBuilder(MappedObjectClassLoader.class.getSimpleName() + ": " + className);
1115 -
1116 - if ( MappedObjectTransformer.PRINT_TIMING )
1117 - msg.append("\n\ttransforming took " + (t1 - t0) / 1000 + " micros (total: " + (total_time_transforming / 1000 / 1000) + "ms)");
1118 -
1119 - LWJGLUtil.log(msg);
1120 - }
1121 -
1122 - private static byte[] readStream(InputStream in) {
1123 - byte[] bytecode = new byte[256];
1124 - int len = 0;
1125 - try {
1126 - while ( true ) {
1127 - if ( bytecode.length == len )
1128 - bytecode = copyOf(bytecode, len * 2);
1129 - int got = in.read(bytecode, len, bytecode.length - len);
1130 - if ( got == -1 )
1131 - break;
1132 - len += got;
1133 - }
1134 - } catch (IOException exc) {
1135 - // stop!
1136 - } finally {
1137 - try {
1138 - in.close();
1139 - } catch (IOException exc) {
1140 - // ignore...
1141 - }
1142 - }
1143 - return copyOf(bytecode, len);
1144 - }
1145 -
1146 - private static byte[] copyOf(byte[] original, int newLength) {
1147 - byte[] copy = new byte[newLength];
1148 - System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
1149 - return copy;
1150 - }
1151 -
1152 -}
1153 \ No newline at end of file
1154 diff --git a/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java b/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java
1155 deleted file mode 100644
1156 index c34c14e..0000000
1157 --- a/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java
1158 +++ /dev/null
1159 @@ -1,1319 +0,0 @@
1160 -/*
1161 - * Copyright (c) 2002-2011 LWJGL Project
1162 - * All rights reserved.
1163 - *
1164 - * Redistribution and use in source and binary forms, with or without
1165 - * modification, are permitted provided that the following conditions are
1166 - * met:
1167 - *
1168 - * * Redistributions of source code must retain the above copyright
1169 - * notice, this list of conditions and the following disclaimer.
1170 - *
1171 - * * Redistributions in binary form must reproduce the above copyright
1172 - * notice, this list of conditions and the following disclaimer in the
1173 - * documentation and/or other materials provided with the distribution.
1174 - *
1175 - * * Neither the name of 'LWJGL' nor the names of
1176 - * its contributors may be used to endorse or promote products derived
1177 - * from this software without specific prior written permission.
1178 - *
1179 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1180 - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1181 - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1182 - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
1183 - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
1184 - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1185 - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1186 - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
1187 - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
1188 - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1189 - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1190 - */
1191 -package org.lwjgl.util.mapped;
1192 -
1193 -import org.lwjgl.BufferUtils;
1194 -import org.lwjgl.LWJGLUtil;
1195 -import org.lwjgl.MemoryUtil;
1196 -import org.objectweb.asm.*;
1197 -import org.objectweb.asm.tree.*;
1198 -import org.objectweb.asm.tree.analysis.*;
1199 -import org.objectweb.asm.tree.analysis.Frame;
1200 -import org.objectweb.asm.util.TraceClassVisitor;
1201 -
1202 -import java.io.PrintWriter;
1203 -import java.io.StringWriter;
1204 -import java.lang.reflect.Field;
1205 -import java.lang.reflect.Modifier;
1206 -import java.nio.Buffer;
1207 -import java.nio.ByteBuffer;
1208 -import java.util.HashMap;
1209 -import java.util.Map;
1210 -
1211 -import static org.objectweb.asm.ClassWriter.*;
1212 -import static org.objectweb.asm.Opcodes.*;
1213 -
1214 -/**
1215 - * This class implements the bytecode transformation that mapped object go through.
1216 - * Mapped object classes need to first be registered with the transformer, see {@link #register(Class)}.
1217 - * <p/>
1218 - * The transformer supports some debugging tools, enabled through JVM system properties:<br/>
1219 - * org.lwjgl.util.mapped.PrintTiming=true, prints timing information for the transformation step.<br/>
1220 - * org.lwjgl.util.mapped.PrintActivity=true, prints activity information.<br/>
1221 - * org.lwjgl.util.mapped.PrintBytecode=true, prints the transformed bytecode.<br/>
1222 - * org.lwjgl.util.Debug must also be set to true for the above to work.
1223 - *
1224 - * @author Riven
1225 - */
1226 -public class MappedObjectTransformer {
1227 -
1228 - static final boolean PRINT_ACTIVITY = LWJGLUtil.DEBUG && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintActivity");
1229 - static final boolean PRINT_TIMING = PRINT_ACTIVITY && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintTiming");
1230 - static final boolean PRINT_BYTECODE = LWJGLUtil.DEBUG && LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.PrintBytecode");
1231 -
1232 - static final Map<String, MappedSubtypeInfo> className_to_subtype;
1233 -
1234 - static final String MAPPED_OBJECT_JVM = jvmClassName(MappedObject.class);
1235 - static final String MAPPED_HELPER_JVM = jvmClassName(MappedHelper.class);
1236 -
1237 - static final String MAPPEDSET_PREFIX = jvmClassName(MappedSet.class);
1238 - static final String MAPPED_SET2_JVM = jvmClassName(MappedSet2.class);
1239 - static final String MAPPED_SET3_JVM = jvmClassName(MappedSet3.class);
1240 - static final String MAPPED_SET4_JVM = jvmClassName(MappedSet4.class);
1241 -
1242 - static final String CACHE_LINE_PAD_JVM = "L" + jvmClassName(CacheLinePad.class) + ";";
1243 -
1244 - // Public methods
1245 - static final String VIEWADDRESS_METHOD_NAME = "getViewAddress";
1246 - static final String NEXT_METHOD_NAME = "next";
1247 - static final String ALIGN_METHOD_NAME = "getAlign";
1248 - static final String SIZEOF_METHOD_NAME = "getSizeof";
1249 - static final String CAPACITY_METHOD_NAME = "capacity"; // Used for .asArray().length
1250 -
1251 - // Internal methods
1252 - static final String VIEW_CONSTRUCTOR_NAME = "constructView$LWJGL"; // Used by runViewConstructor
1253 -
1254 - static final Map<Integer, String> OPCODE_TO_NAME = new HashMap<Integer, String>();
1255 - static final Map<Integer, String> INSNTYPE_TO_NAME = new HashMap<Integer, String>();
1256 -
1257 - static boolean is_currently_computing_frames;
1258 -
1259 - static {
1260 - getClassEnums(Opcodes.class, OPCODE_TO_NAME, "V1_", "ACC_", "T_", "F_", "MH_");
1261 - getClassEnums(AbstractInsnNode.class, INSNTYPE_TO_NAME);
1262 -
1263 - className_to_subtype = new HashMap<String, MappedSubtypeInfo>();
1264 -
1265 - {
1266 - // HACK: required for mapped.view++
1267 - //
1268 - // because the compiler generates:
1269 - // => GETFIELD MappedObject.view
1270 - // => ICONST_1
1271 - // => IADD
1272 - // => PUTFIELD MyMappedType.view
1273 - //
1274 - // instead of:
1275 - // => GETFIELD MyMappedType.view
1276 - // => ICONST_1
1277 - // => IADD
1278 - // => PUTFIELD MyMappedType.view
1279 - //
1280 - className_to_subtype.put(MAPPED_OBJECT_JVM, new MappedSubtypeInfo(MAPPED_OBJECT_JVM, null, -1, -1, -1, false));
1281 - }
1282 -
1283 - final String vmName = System.getProperty("java.vm.name");
1284 - if ( vmName != null && !vmName.contains("Server") ) {
1285 - System.err.println("Warning: " + MappedObject.class.getSimpleName() + "s have inferiour performance on Client VMs, please consider switching to a Server VM.");
1286 - }
1287 - }
1288 -
1289 - /**
1290 - * Registers a class as a mapped object.
1291 - * The class must extend {@link org.lwjgl.util.mapped.MappedObject} and be annotated with {@link org.lwjgl.util.mapped.MappedField}.
1292 - *
1293 - * @param type the mapped object class.
1294 - */
1295 - public static void register(Class<? extends MappedObject> type) {
1296 - if ( MappedObjectClassLoader.FORKED )
1297 - return;
1298 -
1299 - final MappedType mapped = type.getAnnotation(MappedType.class);
1300 -
1301 - if ( mapped != null && mapped.padding() < 0 )
1302 - throw new ClassFormatError("Invalid mapped type padding: " + mapped.padding());
1303 -
1304 - if ( type.getEnclosingClass() != null && !Modifier.isStatic(type.getModifiers()) )
1305 - throw new InternalError("only top-level or static inner classes are allowed");
1306 -
1307 - final String className = jvmClassName(type);
1308 - final Map<String, FieldInfo> fields = new HashMap<String, FieldInfo>();
1309 -
1310 - long sizeof = 0;
1311 - for ( Field field : type.getDeclaredFields() ) {
1312 - FieldInfo fieldInfo = registerField(mapped == null || mapped.autoGenerateOffsets(), className, sizeof, field);
1313 - if ( fieldInfo == null )
1314 - continue;
1315 -
1316 - fields.put(field.getName(), fieldInfo);
1317 -
1318 - sizeof = Math.max(sizeof, fieldInfo.offset + fieldInfo.lengthPadded);
1319 - }
1320 -
1321 - int align = 4;
1322 - int padding = 0;
1323 - boolean cacheLinePadded = false;
1324 -
1325 - if ( mapped != null ) {
1326 - align = mapped.align();
1327 - if ( mapped.cacheLinePadding() ) {
1328 - if ( mapped.padding() != 0 )
1329 - throw new ClassFormatError("Mapped type padding cannot be specified together with cacheLinePadding.");
1330 -
1331 - final int cacheLineMod = (int)(sizeof % CacheUtil.getCacheLineSize());
1332 - if ( cacheLineMod != 0 )
1333 - padding = CacheUtil.getCacheLineSize() - cacheLineMod;
1334 -
1335 - cacheLinePadded = true;
1336 - } else
1337 - padding = mapped.padding();
1338 - }
1339 -
1340 - sizeof += padding;
1341 -
1342 - final MappedSubtypeInfo mappedType = new MappedSubtypeInfo(className, fields, (int)sizeof, align, padding, cacheLinePadded);
1343 - if ( className_to_subtype.put(className, mappedType) != null )
1344 - throw new InternalError("duplicate mapped type: " + mappedType.className);
1345 - }
1346 -
1347 - private static FieldInfo registerField(final boolean autoGenerateOffsets, final String className, long advancingOffset, final Field field) {
1348 - if ( Modifier.isStatic(field.getModifiers()) ) // static fields are never mapped
1349 - return null;
1350 -
1351 - // we only support primitives and ByteBuffers
1352 - if ( !field.getType().isPrimitive() && field.getType() != ByteBuffer.class )
1353 - throw new ClassFormatError("field '" + className + "." + field.getName() + "' not supported: " + field.getType());
1354 -
1355 - MappedField meta = field.getAnnotation(MappedField.class);
1356 - if ( meta == null && !autoGenerateOffsets )
1357 - throw new ClassFormatError("field '" + className + "." + field.getName() + "' missing annotation " + MappedField.class.getName() + ": " + className);
1358 -
1359 - Pointer pointer = field.getAnnotation(Pointer.class);
1360 - if ( pointer != null && field.getType() != long.class )
1361 - throw new ClassFormatError("The @Pointer annotation can only be used on long fields. @Pointer field found: " + className + "." + field.getName() + ": " + field.getType());
1362 -
1363 - if ( Modifier.isVolatile(field.getModifiers()) && (pointer != null || field.getType() == ByteBuffer.class) )
1364 - throw new ClassFormatError("The volatile keyword is not supported for @Pointer or ByteBuffer fields. Volatile field found: " + className + "." + field.getName() + ": " + field.getType());
1365 -
1366 - // quick hack
1367 - long byteLength;
1368 - if ( field.getType() == long.class || field.getType() == double.class ) {
1369 - if ( pointer == null )
1370 - byteLength = 8;
1371 - else
1372 - byteLength = MappedObjectUnsafe.INSTANCE.addressSize();
1373 - } else if ( field.getType() == double.class )
1374 - byteLength = 8;
1375 - else if ( field.getType() == int.class || field.getType() == float.class )
1376 - byteLength = 4;
1377 - else if ( field.getType() == char.class || field.getType() == short.class )
1378 - byteLength = 2;
1379 - else if ( field.getType() == byte.class )
1380 - byteLength = 1;
1381 - else if ( field.getType() == ByteBuffer.class ) {
1382 - byteLength = meta.byteLength();
1383 - if ( byteLength < 0 )
1384 - throw new IllegalStateException("invalid byte length for mapped ByteBuffer field: " + className + "." + field.getName() + " [length=" + byteLength + "]");
1385 - } else
1386 - throw new ClassFormatError(field.getType().getName());
1387 -
1388 - if ( field.getType() != ByteBuffer.class && (advancingOffset % byteLength) != 0 )
1389 - throw new IllegalStateException("misaligned mapped type: " + className + "." + field.getName());
1390 -
1391 - CacheLinePad pad = field.getAnnotation(CacheLinePad.class);
1392 -
1393 - long byteOffset = advancingOffset;
1394 - if ( meta != null && meta.byteOffset() != -1 ) {
1395 - if ( meta.byteOffset() < 0 )
1396 - throw new ClassFormatError("Invalid field byte offset: " + className + "." + field.getName() + " [byteOffset=" + meta.byteOffset() + "]");
1397 - if ( pad != null )
1398 - throw new ClassFormatError("A field byte offset cannot be specified together with cache-line padding: " + className + "." + field.getName());
1399 -
1400 - byteOffset = meta.byteOffset();
1401 - }
1402 -
1403 - long byteLengthPadded = byteLength;
1404 - if ( pad != null ) {
1405 - // Pad before
1406 - if ( pad.before() && byteOffset % CacheUtil.getCacheLineSize() != 0 )
1407 - byteOffset += CacheUtil.getCacheLineSize() - (byteOffset & (CacheUtil.getCacheLineSize() - 1));
1408 -
1409 - // Pad after
1410 - if ( pad.after() && (byteOffset + byteLength) % CacheUtil.getCacheLineSize() != 0 )
1411 - byteLengthPadded += CacheUtil.getCacheLineSize() - (byteOffset + byteLength) % CacheUtil.getCacheLineSize();
1412 -
1413 - assert !pad.before() || (byteOffset % CacheUtil.getCacheLineSize() == 0);
1414 - assert !pad.after() || ((byteOffset + byteLengthPadded) % CacheUtil.getCacheLineSize() == 0);
1415 - }
1416 -
1417 - if ( PRINT_ACTIVITY )
1418 - LWJGLUtil.log(MappedObjectTransformer.class.getSimpleName() + ": " + className + "." + field.getName() + " [type=" + field.getType().getSimpleName() + ", offset=" + byteOffset + "]");
1419 -
1420 - return new FieldInfo(byteOffset, byteLength, byteLengthPadded, Type.getType(field.getType()), Modifier.isVolatile(field.getModifiers()), pointer != null);
1421 - }
1422 -
1423 - /** Removes final from methods that will be overriden by subclasses. */
1424 - static byte[] transformMappedObject(byte[] bytecode) {
1425 - final ClassWriter cw = new ClassWriter(0);
1426 -
1427 - ClassVisitor cv = new ClassAdapter(cw) {
1428 -
1429 - private final String[] DEFINALIZE_LIST = {
1430 - VIEWADDRESS_METHOD_NAME,
1431 - NEXT_METHOD_NAME,
1432 - ALIGN_METHOD_NAME,
1433 - SIZEOF_METHOD_NAME,
1434 - CAPACITY_METHOD_NAME,
1435 - };
1436 -
1437 - public MethodVisitor visitMethod(int access, final String name, final String desc, final String signature, final String[] exceptions) {
1438 - for ( String method : DEFINALIZE_LIST ) {
1439 - if ( name.equals(method) ) {
1440 - access &= ~ACC_FINAL;
1441 - break;
1442 - }
1443 - }
1444 - return super.visitMethod(access, name, desc, signature, exceptions);
1445 - }
1446 - };
1447 -
1448 - new ClassReader(bytecode).accept(cv, 0);
1449 - return cw.toByteArray();
1450 - }
1451 -
1452 - static byte[] transformMappedAPI(final String className, byte[] bytecode) {
1453 - final ClassWriter cw = new ClassWriter(COMPUTE_FRAMES) {
1454 -
1455 - @Override
1456 - protected String getCommonSuperClass(String a, String b) {
1457 - // HACK: prevent user-code static-initialization-blocks to be executed
1458 - if ( is_currently_computing_frames && !a.startsWith("java/") || !b.startsWith("java/") )
1459 - return "java/lang/Object";
1460 -
1461 - return super.getCommonSuperClass(a, b);
1462 - }
1463 -
1464 - };
1465 -
1466 - final TransformationAdapter ta = new TransformationAdapter(cw, className);
1467 -
1468 - ClassVisitor cv = ta;
1469 - if ( className_to_subtype.containsKey(className) ) // Do a first pass to generate address getters
1470 - cv = getMethodGenAdapter(className, cv);
1471 -
1472 - new ClassReader(bytecode).accept(cv, ClassReader.SKIP_FRAMES);
1473 -
1474 - if ( !ta.transformed )
1475 - return bytecode;
1476 -
1477 - bytecode = cw.toByteArray();
1478 - if ( PRINT_BYTECODE )
1479 - printBytecode(bytecode);
1480 -
1481 - return bytecode;
1482 - }
1483 -
1484 - private static ClassAdapter getMethodGenAdapter(final String className, final ClassVisitor cv) {
1485 - return new ClassAdapter(cv) {
1486 -
1487 - @Override
1488 - public void visitEnd() {
1489 - final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
1490 -
1491 - generateViewAddressGetter();
1492 - generateCapacity();
1493 - generateAlignGetter(mappedSubtype);
1494 - generateSizeofGetter();
1495 - generateNext();
1496 -
1497 - for ( String fieldName : mappedSubtype.fields.keySet() ) {
1498 - final FieldInfo field = mappedSubtype.fields.get(fieldName);
1499 -
1500 - if ( field.type.getDescriptor().length() > 1 ) { // ByteBuffer, getter only
1501 - generateByteBufferGetter(fieldName, field);
1502 - } else {
1503 - generateFieldGetter(fieldName, field);
1504 - generateFieldSetter(fieldName, field);
1505 - }
1506 - }
1507 -
1508 - super.visitEnd();
1509 - }
1510 -
1511 - private void generateViewAddressGetter() {
1512 - MethodVisitor mv = super.visitMethod(ACC_PUBLIC, VIEWADDRESS_METHOD_NAME, "(I)J", null, null);
1513 - mv.visitCode();
1514 - mv.visitVarInsn(ALOAD, 0);
1515 - mv.visitFieldInsn(GETFIELD, MAPPED_OBJECT_JVM, "baseAddress", "J");
1516 - mv.visitVarInsn(ILOAD, 1);
1517 - mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
1518 - mv.visitInsn(IMUL);
1519 - mv.visitInsn(I2L);
1520 - mv.visitInsn(LADD);
1521 - if ( MappedObject.CHECKS ) {
1522 - mv.visitInsn(DUP2);
1523 - mv.visitVarInsn(ALOAD, 0);
1524 - mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "checkAddress", "(JL" + MAPPED_OBJECT_JVM + ";)V");
1525 - }
1526 - mv.visitInsn(LRETURN);
1527 - mv.visitMaxs(3, 2);
1528 - mv.visitEnd();
1529 - }
1530 -
1531 - private void generateCapacity() {
1532 - // return (backingByteBuffer().capacity() + (int)(MemoryUtil.getAddress0(backingByteBuffer()) - baseAddress)) / SIZEOF;
1533 - MethodVisitor mv = super.visitMethod(ACC_PUBLIC, CAPACITY_METHOD_NAME, "()I", null, null);
1534 - mv.visitCode();
1535 - mv.visitVarInsn(ALOAD, 0);
1536 - mv.visitMethodInsn(INVOKEVIRTUAL, MAPPED_OBJECT_JVM, "backingByteBuffer", "()L" + jvmClassName(ByteBuffer.class) + ";");
1537 - mv.visitInsn(DUP);
1538 - mv.visitMethodInsn(INVOKEVIRTUAL, jvmClassName(ByteBuffer.class), "capacity", "()I");
1539 - mv.visitInsn(SWAP);
1540 - mv.visitMethodInsn(INVOKESTATIC, jvmClassName(MemoryUtil.class), "getAddress0", "(L" + jvmClassName(Buffer.class) + ";)J");
1541 - mv.visitVarInsn(ALOAD, 0);
1542 - mv.visitFieldInsn(GETFIELD, MAPPED_OBJECT_JVM, "baseAddress", "J");
1543 - mv.visitInsn(LSUB);
1544 - mv.visitInsn(L2I);
1545 - mv.visitInsn(IADD);
1546 - mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
1547 - mv.visitInsn(IDIV);
1548 - mv.visitInsn(IRETURN);
1549 - mv.visitMaxs(3, 1);
1550 - mv.visitEnd();
1551 - }
1552 -
1553 - private void generateAlignGetter(final MappedSubtypeInfo mappedSubtype) {
1554 - MethodVisitor mv = super.visitMethod(ACC_PUBLIC, ALIGN_METHOD_NAME, "()I", null, null);
1555 - mv.visitCode();
1556 - visitIntNode(mv, mappedSubtype.sizeof);
1557 - mv.visitInsn(IRETURN);
1558 - mv.visitMaxs(1, 1);
1559 - mv.visitEnd();
1560 - }
1561 -
1562 - private void generateSizeofGetter() {
1563 - MethodVisitor mv = super.visitMethod(ACC_PUBLIC, SIZEOF_METHOD_NAME, "()I", null, null);
1564 - mv.visitCode();
1565 - mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
1566 - mv.visitInsn(IRETURN);
1567 - mv.visitMaxs(1, 1);
1568 - mv.visitEnd();
1569 - }
1570 -
1571 - private void generateNext() {
1572 - MethodVisitor mv = super.visitMethod(ACC_PUBLIC, NEXT_METHOD_NAME, "()V", null, null);
1573 - mv.visitCode();
1574 - mv.visitVarInsn(ALOAD, 0);
1575 - mv.visitInsn(DUP);
1576 - mv.visitFieldInsn(GETFIELD, MAPPED_OBJECT_JVM, "viewAddress", "J");
1577 - mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
1578 - mv.visitInsn(I2L);
1579 - mv.visitInsn(LADD);
1580 - mv.visitMethodInsn(INVOKEVIRTUAL, className, "setViewAddress", "(J)V");
1581 - mv.visitInsn(RETURN);
1582 - mv.visitMaxs(3, 1);
1583 - mv.visitEnd();
1584 - }
1585 -
1586 - private void generateByteBufferGetter(final String fieldName, final FieldInfo field) {
1587 - MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, getterName(fieldName), "(L" + className + ";I)" + field.type.getDescriptor(), null, null);
1588 - mv.visitCode();
1589 - mv.visitVarInsn(ALOAD, 0);
1590 - mv.visitVarInsn(ILOAD, 1);
1591 - mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
1592 - visitIntNode(mv, (int)field.offset);
1593 - mv.visitInsn(I2L);
1594 - mv.visitInsn(LADD);
1595 - visitIntNode(mv, (int)field.length);
1596 - mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";");
1597 - mv.visitInsn(ARETURN);
1598 - mv.visitMaxs(3, 2);
1599 - mv.visitEnd();
1600 - }
1601 -
1602 - private void generateFieldGetter(final String fieldName, final FieldInfo field) {
1603 - MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, getterName(fieldName), "(L" + className + ";I)" + field.type.getDescriptor(), null, null);
1604 - mv.visitCode();
1605 - mv.visitVarInsn(ALOAD, 0);
1606 - mv.visitVarInsn(ILOAD, 1);
1607 - mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
1608 - visitIntNode(mv, (int)field.offset);
1609 - mv.visitInsn(I2L);
1610 - mv.visitInsn(LADD);
1611 - mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, field.getAccessType() + "get", "(J)" + field.type.getDescriptor());
1612 - mv.visitInsn(field.type.getOpcode(IRETURN));
1613 - mv.visitMaxs(3, 2);
1614 - mv.visitEnd();
1615 - }
1616 -
1617 - private void generateFieldSetter(final String fieldName, final FieldInfo field) {
1618 - MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, setterName(fieldName), "(L" + className + ";I" + field.type.getDescriptor() + ")V", null, null);
1619 - mv.visitCode();
1620 - int load = 0;
1621 - switch ( field.type.getSort() ) {
1622 - case Type.BOOLEAN:
1623 - case Type.CHAR:
1624 - case Type.BYTE:
1625 - case Type.SHORT:
1626 - case Type.INT:
1627 - load = ILOAD;
1628 - break;
1629 - case Type.FLOAT:
1630 - load = FLOAD;
1631 - break;
1632 - case Type.LONG:
1633 - load = LLOAD;
1634 - break;
1635 - case Type.DOUBLE:
1636 - load = DLOAD;
1637 - break;
1638 - }
1639 - mv.visitVarInsn(load, 2);
1640 - mv.visitVarInsn(ALOAD, 0);
1641 - mv.visitVarInsn(ILOAD, 1);
1642 - mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
1643 - visitIntNode(mv, (int)field.offset);
1644 - mv.visitInsn(I2L);
1645 - mv.visitInsn(LADD);
1646 - mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, field.getAccessType() + "put", "(" + field.type.getDescriptor() + "J)V");
1647 - mv.visitInsn(RETURN);
1648 - mv.visitMaxs(4, 4);
1649 - mv.visitEnd();
1650 - }
1651 -
1652 - };
1653 - }
1654 -
1655 - private static class TransformationAdapter extends ClassAdapter {
1656 -
1657 - final String className;
1658 -
1659 - boolean transformed;
1660 -
1661 - TransformationAdapter(final ClassVisitor cv, final String className) {
1662 - super(cv);
1663 - this.className = className;
1664 - }
1665 -
1666 - @Override
1667 - public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) {
1668 - // remove redirected fields
1669 - final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
1670 - if ( mappedSubtype != null && mappedSubtype.fields.containsKey(name) ) {
1671 - if ( PRINT_ACTIVITY )
1672 - LWJGLUtil.log(MappedObjectTransformer.class.getSimpleName() + ": discarding field: " + className + "." + name + ":" + desc);
1673 - return null;
1674 - }
1675 -
1676 - if ( (access & ACC_STATIC) == 0 ) {
1677 - return new FieldNode(access, name, desc, signature, value) {
1678 - public void visitEnd() {
1679 - if ( visibleAnnotations == null ) { // early-out
1680 - accept(cv);
1681 - return;
1682 - }
1683 -
1684 - boolean before = false;
1685 - boolean after = false;
1686 - int byteLength = 0;
1687 - for ( AnnotationNode pad : visibleAnnotations ) {
1688 - if ( CACHE_LINE_PAD_JVM.equals(pad.desc) ) {
1689 - if ( "J".equals(desc) || "D".equals(desc) )
1690 - byteLength = 8;
1691 - else if ( "I".equals(desc) || "F".equals(desc) )
1692 - byteLength = 4;
1693 - else if ( "S".equals(desc) || "C".equals(desc) )
1694 - byteLength = 2;
1695 - else if ( "B".equals(desc) || "Z".equals(desc) )
1696 - byteLength = 1;
1697 - else
1698 - throw new ClassFormatError("The @CacheLinePad annotation cannot be used on non-primitive fields: " + className + "." + name);
1699 -
1700 - transformed = true;
1701 -
1702 - after = true;
1703 - if ( pad.values != null ) {
1704 - for ( int i = 0; i < pad.values.size(); i += 2 ) {
1705 - final boolean value = pad.values.get(i + 1).equals(Boolean.TRUE);
1706 - if ( "before".equals(pad.values.get(i)) )
1707 - before = value;
1708 - else
1709 - after = value;
1710 - }
1711 - }
1712 - break;
1713 - }
1714 - }
1715 -
1716 - /*
1717 - We make the fields public to force the JVM to keep the fields in the object.
1718 - Instead of using only longs or integers, we use the same type as the original
1719 - field. That's because modern JVMs usually reorder fields by type:
1720 - longs, then doubles, then integers, then booleans, etc. This way it's more
1721 - likely that the padding will work as expected.
1722 - */
1723 -
1724 - if ( before ) {
1725 - final int count = CacheUtil.getCacheLineSize() / byteLength - 1;
1726 - for ( int i = count; i >= 1; i-- )
1727 - cv.visitField(access | ACC_PUBLIC | ACC_SYNTHETIC, name + "$PAD_" + i, desc, signature, null);
1728 - }
1729 -
1730 - accept(cv);
1731 -
1732 - if ( after ) {
1733 - final int count = CacheUtil.getCacheLineSize() / byteLength - 1;
1734 - for ( int i = 1; i <= count; i++ )
1735 - cv.visitField(access | ACC_PUBLIC | ACC_SYNTHETIC, name + "$PAD" + i, desc, signature, null);
1736 - }
1737 - }
1738 - };
1739 - } else
1740 - return super.visitField(access, name, desc, signature, value);
1741 - }
1742 -
1743 - @Override
1744 - public MethodVisitor visitMethod(final int access, String name, final String desc, final String signature, final String[] exceptions) {
1745 - // Move MappedSubtype constructors to another method
1746 - if ( "<init>".equals(name) ) {
1747 - final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
1748 - if ( mappedSubtype != null ) {
1749 - if ( !"()V".equals(desc) )
1750 - throw new ClassFormatError(className + " can only have a default constructor, found: " + desc);
1751 -
1752 - final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
1753 - mv.visitVarInsn(ALOAD, 0);
1754 - mv.visitMethodInsn(INVOKESPECIAL, MAPPED_OBJECT_JVM, "<init>", "()V");
1755 - mv.visitInsn(RETURN);
1756 - mv.visitMaxs(0, 0);
1757 -
1758 - // put the method body in another method
1759 - name = VIEW_CONSTRUCTOR_NAME;
1760 - }
1761 - }
1762 -
1763 - final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
1764 - return new MethodNode(access, name, desc, signature, exceptions) {
1765 -
1766 - /** When true, the method has touched a mapped object and needs to be transformed. We track this
1767 - * so we can skip the expensive frame analysis and tree API usage. */
1768 - boolean needsTransformation;
1769 -
1770 - @Override
1771 - public void visitMaxs(int a, int b) {
1772 - try {
1773 - is_currently_computing_frames = true;
1774 - super.visitMaxs(a, b);
1775 - } finally {
1776 - is_currently_computing_frames = false;
1777 - }
1778 - }
1779 -
1780 - @Override
1781 - public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
1782 - if ( className_to_subtype.containsKey(owner) || owner.startsWith(MAPPEDSET_PREFIX) )
1783 - needsTransformation = true;
1784 -
1785 - super.visitFieldInsn(opcode, owner, name, desc);
1786 - }
1787 -
1788 - @Override
1789 - public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
1790 - if ( className_to_subtype.containsKey(owner) )
1791 - needsTransformation = true;
1792 -
1793 - super.visitMethodInsn(opcode, owner, name, desc);
1794 - }
1795 -
1796 - @Override
1797 - public void visitEnd() {
1798 - if ( needsTransformation ) { // Early-out for methods that do not touch a mapped object.
1799 - //System.err.println("\nTRANSFORMING: " + className + "." + name + desc);
1800 - transformed = true;
1801 - try {
1802 - transformMethod(analyse());
1803 - } catch (Exception e) {
1804 - throw new RuntimeException(e);
1805 - }
1806 - }
1807 -
1808 - // Pass the instruction stream to the adapter's MethodVisitor
1809 - accept(mv);
1810 - }
1811 -
1812 - private Frame<BasicValue>[] analyse() throws AnalyzerException {
1813 - final Analyzer<BasicValue> a = new Analyzer<BasicValue>(new SimpleVerifier());
1814 - a.analyze(className, this);
1815 - return a.getFrames();
1816 - }
1817 -
1818 - private void transformMethod(final Frame<BasicValue>[] frames) {
1819 - final InsnList instructions = this.instructions;
1820 -
1821 - final Map<Integer, MappedSubtypeInfo> arrayVars = new HashMap<Integer, MappedSubtypeInfo>();
1822 -
1823 - /*
1824 - We need this map because we insert/remove instructions from the stream and we need a way
1825 - to match each original instruction with the corresponding frame.
1826 - TODO: Can we keep track of everything more efficiently without a map?
1827 - */
1828 - final Map<AbstractInsnNode, Frame<BasicValue>> frameMap = new HashMap<AbstractInsnNode, Frame<BasicValue>>();
1829 - for ( int i = 0; i < frames.length; i++ )
1830 - frameMap.put(instructions.get(i), frames[i]);
1831 -
1832 - for ( int i = 0; i < instructions.size(); i++ ) { // f is a separate cursor for frames
1833 - final AbstractInsnNode instruction = instructions.get(i);
1834 -
1835 - //System.out.println("MAIN LOOP #" + i + " - " + getOpcodeName(instruction));
1836 -
1837 - switch ( instruction.getType() ) {
1838 - case AbstractInsnNode.VAR_INSN:
1839 - if ( instruction.getOpcode() == ALOAD ) {
1840 - VarInsnNode varInsn = (VarInsnNode)instruction;
1841 - final MappedSubtypeInfo mappedSubtype = arrayVars.get(varInsn.var);
1842 - if ( mappedSubtype != null )
1843 - i = transformArrayAccess(instructions, i, frameMap, varInsn, mappedSubtype, varInsn.var);
1844 - }
1845 - break;
1846 - case AbstractInsnNode.FIELD_INSN:
1847 - FieldInsnNode fieldInsn = (FieldInsnNode)instruction;
1848 -
1849 - final InsnList list = transformFieldAccess(fieldInsn);
1850 - if ( list != null )
1851 - i = replace(instructions, i, instruction, list);
1852 -
1853 - break;
1854 - case AbstractInsnNode.METHOD_INSN:
1855 - MethodInsnNode methodInsn = (MethodInsnNode)instruction;
1856 - final MappedSubtypeInfo mappedType = className_to_subtype.get(methodInsn.owner);
1857 - if ( mappedType != null )
1858 - i = transformMethodCall(instructions, i, frameMap, methodInsn, mappedType, arrayVars);
1859 - break;
1860 - }
1861 - }
1862 - }
1863 - };
1864 - }
1865 - }
1866 -
1867 - 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) {
1868 - switch ( methodInsn.getOpcode() ) {
1869 - case INVOKEVIRTUAL:
1870 - if ( "asArray".equals(methodInsn.name) && methodInsn.desc.equals("()[L" + MAPPED_OBJECT_JVM + ";") ) {
1871 - // Go forward and store the local variable index.
1872 - // We only allow this pattern: INVOKEVIRTUAL -> CHECKCAST -> ASTORE.
1873 - // We remove the first two and store the target MappedSubtype in the ASTORE variable
1874 - AbstractInsnNode nextInstruction;
1875 - checkInsnAfterIsArray(nextInstruction = methodInsn.getNext(), CHECKCAST);
1876 - checkInsnAfterIsArray(nextInstruction = nextInstruction.getNext(), ASTORE);
1877 -
1878 - final Frame<BasicValue> frame = frameMap.get(nextInstruction);
1879 - final String targetType = frame.getStack(frame.getStackSize() - 1).getType().getElementType().getInternalName();
1880 - if ( !methodInsn.owner.equals(targetType) ) {
1881 - /*
1882 - This may happen with the current API, like so:
1883 - MappedA foo = MappedA.malloc(...);
1884 - MappedB[] cursor = foo.asArray();
1885 - We have to parameterize MappedObject to avoid this.
1886 - */
1887 - throw new ClassCastException("Source: " + methodInsn.owner + " - Target: " + targetType);
1888 - }
1889 -
1890 - final VarInsnNode varInstruction = (VarInsnNode)nextInstruction;
1891 -
1892 - arrayVars.put(varInstruction.var, mappedType);
1893 -
1894 - instructions.remove(methodInsn.getNext()); // Remove CHECKCAST
1895 - instructions.remove(methodInsn); // Remove INVOKEVIRTUAL
1896 - }
1897 -
1898 - if ( "dup".equals(methodInsn.name) && methodInsn.desc.equals("()L" + MAPPED_OBJECT_JVM + ";") ) {
1899 - i = replace(instructions, i, methodInsn, generateDupInstructions(methodInsn));
1900 - break;
1901 - }
1902 -
1903 - if ( "slice".equals(methodInsn.name) && methodInsn.desc.equals("()L" + MAPPED_OBJECT_JVM + ";") ) {
1904 - i = replace(instructions, i, methodInsn, generateSliceInstructions(methodInsn));
1905 - break;
1906 - }
1907 -
1908 - if ( "runViewConstructor".equals(methodInsn.name) && "()V".equals(methodInsn.desc) ) {
1909 - i = replace(instructions, i, methodInsn, generateRunViewConstructorInstructions(methodInsn));
1910 - break;
1911 - }
1912 -
1913 - if ( "copyTo".equals(methodInsn.name) && methodInsn.desc.equals("(L" + MAPPED_OBJECT_JVM + ";)V") ) {
1914 - i = replace(instructions, i, methodInsn, generateCopyToInstructions(mappedType));
1915 - break;
1916 - }
1917 -
1918 - if ( "copyRange".equals(methodInsn.name) && methodInsn.desc.equals("(L" + MAPPED_OBJECT_JVM + ";I)V") ) {
1919 - i = replace(instructions, i, methodInsn, generateCopyRangeInstructions(mappedType));
1920 - break;
1921 - }
1922 -
1923 - break;
1924 - case INVOKESPECIAL:
1925 - // super() in VIEW_CONSTRUCTOR_NAME, remove
1926 - if ( methodInsn.owner.equals(MAPPED_OBJECT_JVM) && "<init>".equals(methodInsn.name) && "()V".equals(methodInsn.desc) ) {
1927 - instructions.remove(methodInsn.getPrevious()); // ALOAD
1928 - instructions.remove(methodInsn); // INVOKESPECIAL
1929 -
1930 - i -= 2;
1931 - }
1932 - break;
1933 - case INVOKESTATIC:
1934 - boolean isMapDirectMethod = "map".equals(methodInsn.name) && methodInsn.desc.equals("(JI)L" + MAPPED_OBJECT_JVM + ";");
1935 - boolean isMapBufferMethod = "map".equals(methodInsn.name) && methodInsn.desc.equals("(Ljava/nio/ByteBuffer;)L" + MAPPED_OBJECT_JVM + ";");
1936 - boolean isMallocMethod = "malloc".equals(methodInsn.name) && methodInsn.desc.equals("(I)L" + MAPPED_OBJECT_JVM + ";");
1937 -
1938 - if ( (isMapDirectMethod || isMapBufferMethod) || isMallocMethod )
1939 - i = replace(instructions, i, methodInsn, generateMapInstructions(mappedType, methodInsn.owner, isMapDirectMethod, isMallocMethod));
1940 - break;
1941 - }
1942 -
1943 - return i;
1944 - }
1945 -
1946 - private static InsnList generateCopyRangeInstructions(final MappedSubtypeInfo mappedType) {
1947 - final InsnList list = new InsnList();
1948 -
1949 - // stack: instances, target, this
1950 - list.add(getIntNode(mappedType.sizeof));
1951 - // stack: sizeof, instances, target, this
1952 - list.add(new InsnNode(IMUL));
1953 - // stack: bytes, target, this
1954 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "copy", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";I)V"));
1955 - // stack: -
1956 -
1957 - return list;
1958 - }
1959 -
1960 - private static InsnList generateCopyToInstructions(final MappedSubtypeInfo mappedType) {
1961 - final InsnList list = new InsnList();
1962 -
1963 - // stack: target, this
1964 - list.add(getIntNode(mappedType.sizeof - mappedType.padding));
1965 - // stack: sizeof, target, this
1966 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "copy", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";I)V"));
1967 - // stack: -
1968 -
1969 - return list;
1970 - }
1971 -
1972 - private static InsnList generateRunViewConstructorInstructions(final MethodInsnNode methodInsn) {
1973 - final InsnList list = new InsnList();
1974 -
1975 - // stack: this
1976 - list.add(new InsnNode(DUP));
1977 - // stack: this, this
1978 - list.add(new MethodInsnNode(INVOKEVIRTUAL, methodInsn.owner, VIEW_CONSTRUCTOR_NAME, "()V"));
1979 - // stack: this
1980 -
1981 - return list;
1982 - }
1983 -
1984 - private static InsnList generateSliceInstructions(final MethodInsnNode methodInsn) {
1985 - final InsnList list = new InsnList();
1986 -
1987 - // stack: this
1988 - list.add(new TypeInsnNode(NEW, methodInsn.owner));
1989 - // stack: new, this
1990 - list.add(new InsnNode(DUP));
1991 - // stack: new, new, this
1992 - list.add(new MethodInsnNode(INVOKESPECIAL, methodInsn.owner, "<init>", "()V"));
1993 - // stack: new, this
1994 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "slice", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";)L" + MAPPED_OBJECT_JVM + ";"));
1995 - // stack: new
1996 -
1997 - return list;
1998 - }
1999 -
2000 - private static InsnList generateDupInstructions(final MethodInsnNode methodInsn) {
2001 - final InsnList list = new InsnList();
2002 -
2003 - // stack: this
2004 - list.add(new TypeInsnNode(NEW, methodInsn.owner));
2005 - // stack: new, this
2006 - list.add(new InsnNode(DUP));
2007 - // stack: new, new, this
2008 - list.add(new MethodInsnNode(INVOKESPECIAL, methodInsn.owner, "<init>", "()V"));
2009 - // stack: new, this
2010 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "dup", "(L" + MAPPED_OBJECT_JVM + ";L" + MAPPED_OBJECT_JVM + ";)L" + MAPPED_OBJECT_JVM + ";"));
2011 - // stack: new
2012 -
2013 - return list;
2014 - }
2015 -
2016 - private static InsnList generateMapInstructions(final MappedSubtypeInfo mappedType, final String className, final boolean mapDirectMethod, final boolean mallocMethod) {
2017 - final InsnList trg = new InsnList();
2018 -
2019 - if ( mallocMethod ) {
2020 - // stack: count
2021 - trg.add(getIntNode(mappedType.sizeof));
2022 - // stack: sizeof, count
2023 - trg.add(new InsnNode(IMUL));
2024 - // stack: bytes
2025 - trg.add(new MethodInsnNode(INVOKESTATIC, mappedType.cacheLinePadded ? jvmClassName(CacheUtil.class) : jvmClassName(BufferUtils.class), "createByteBuffer", "(I)L" + jvmClassName(ByteBuffer.class) + ";"));
2026 - // stack: buffer
2027 - } else if ( mapDirectMethod ) {
2028 - // stack: capacity, address
2029 - trg.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";"));
2030 - // stack: buffer
2031 - }
2032 -
2033 - // stack: buffer
2034 - trg.add(new TypeInsnNode(NEW, className));
2035 - // stack: new, buffer
2036 - trg.add(new InsnNode(DUP));
2037 - // stack: new, new, buffer
2038 - trg.add(new MethodInsnNode(INVOKESPECIAL, className, "<init>", "()V"));
2039 - // stack: new, buffer
2040 - trg.add(new InsnNode(DUP_X1));
2041 - // stack: new, buffer, new
2042 - trg.add(new InsnNode(SWAP));
2043 - // stack: buffer, new, new
2044 - trg.add(getIntNode(mappedType.align));
2045 - // stack: int, buffer, new, new
2046 - trg.add(getIntNode(mappedType.sizeof));
2047 - // stack: int, int, buffer, new, new
2048 - trg.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "setup", "(L" + MAPPED_OBJECT_JVM + ";Ljava/nio/ByteBuffer;II)V"));
2049 - // stack: new
2050 -
2051 - return trg;
2052 - }
2053 -
2054 - static InsnList transformFieldAccess(final FieldInsnNode fieldInsn) {
2055 - final MappedSubtypeInfo mappedSubtype;
2056 - mappedSubtype = className_to_subtype.get(fieldInsn.owner);
2057 - if ( mappedSubtype == null ) { // early out
2058 - // MappedSet.view
2059 - outer:
2060 - if ( "view".equals(fieldInsn.name) && fieldInsn.owner.startsWith(MAPPEDSET_PREFIX) )
2061 - return generateSetViewInstructions(fieldInsn);
2062 -
2063 - return null; // early out
2064 - }
2065 -
2066 - if ( "SIZEOF".equals(fieldInsn.name) )
2067 - return generateSIZEOFInstructions(fieldInsn, mappedSubtype);
2068 -
2069 - if ( "view".equals(fieldInsn.name) )
2070 - return generateViewInstructions(fieldInsn, mappedSubtype);
2071 -
2072 - if ( "baseAddress".equals(fieldInsn.name) || "viewAddress".equals(fieldInsn.name) ) {
2073 - return generateAddressInstructions(fieldInsn);
2074 - }
2075 -
2076 - final FieldInfo field = mappedSubtype.fields.get(fieldInsn.name);
2077 - if ( field == null ) // early out
2078 - return null;
2079 -
2080 - // now we're going to transform ByteBuffer-typed field access
2081 - if ( fieldInsn.desc.equals("L" + jvmClassName(ByteBuffer.class) + ";") )
2082 - return generateByteBufferInstructions(fieldInsn, mappedSubtype, field.offset);
2083 -
2084 - // we're now going to transform the field access
2085 - return generateFieldInstructions(fieldInsn, field);
2086 - }
2087 -
2088 - private static InsnList generateSetViewInstructions(final FieldInsnNode fieldInsn) {
2089 - if ( fieldInsn.getOpcode() == GETFIELD )
2090 - throwAccessErrorOnReadOnlyField(fieldInsn.owner, fieldInsn.name);
2091 - if ( fieldInsn.getOpcode() != PUTFIELD )
2092 - throw new InternalError();
2093 -
2094 - final InsnList list = new InsnList();
2095 -
2096 - // stack: index, this
2097 - if ( MAPPED_SET2_JVM.equals(fieldInsn.owner) )
2098 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_views", "(L" + MAPPED_SET2_JVM + ";I)V"));
2099 - else if ( MAPPED_SET3_JVM.equals(fieldInsn.owner) )
2100 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_views", "(L" + MAPPED_SET3_JVM + ";I)V"));
2101 - else if ( MAPPED_SET4_JVM.equals(fieldInsn.owner) )
2102 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_views", "(L" + MAPPED_SET4_JVM + ";I)V"));
2103 - else
2104 - throw new InternalError();
2105 - // stack: -
2106 -
2107 - return list;
2108 - }
2109 -
2110 - private static InsnList generateSIZEOFInstructions(final FieldInsnNode fieldInsn, final MappedSubtypeInfo mappedSubtype) {
2111 - if ( !"I".equals(fieldInsn.desc) )
2112 - throw new InternalError();
2113 -
2114 - final InsnList list = new InsnList();
2115 -
2116 - if ( fieldInsn.getOpcode() == GETSTATIC ) {
2117 - list.add(getIntNode(mappedSubtype.sizeof));
2118 - return list;
2119 - }
2120 -
2121 - if ( fieldInsn.getOpcode() == PUTSTATIC )
2122 - throwAccessErrorOnReadOnlyField(fieldInsn.owner, fieldInsn.name);
2123 -
2124 - throw new InternalError();
2125 - }
2126 -
2127 - private static InsnList generateViewInstructions(final FieldInsnNode fieldInsn, final MappedSubtypeInfo mappedSubtype) {
2128 - if ( !"I".equals(fieldInsn.desc) )
2129 - throw new InternalError();
2130 -
2131 - final InsnList list = new InsnList();
2132 -
2133 - if ( fieldInsn.getOpcode() == GETFIELD ) {
2134 - if ( mappedSubtype.sizeof_shift != 0 ) {
2135 - // stack: instance
2136 - list.add(getIntNode(mappedSubtype.sizeof_shift));
2137 - // stack: sizeof, instance
2138 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "get_view_shift", "(L" + MAPPED_OBJECT_JVM + ";I)I"));
2139 - // stack: view
2140 - } else {
2141 - // stack: instance
2142 - list.add(getIntNode(mappedSubtype.sizeof));
2143 - // stack: sizeof, instance
2144 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "get_view", "(L" + MAPPED_OBJECT_JVM + ";I)I"));
2145 - // stack: view
2146 - }
2147 - return list;
2148 - }
2149 -
2150 - if ( fieldInsn.getOpcode() == PUTFIELD ) {
2151 - if ( mappedSubtype.sizeof_shift != 0 ) {
2152 - // stack: view, instance
2153 - list.add(getIntNode(mappedSubtype.sizeof_shift));
2154 - // stack: sizeof, view, instance
2155 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_view_shift", "(L" + MAPPED_OBJECT_JVM + ";II)V"));
2156 - // stack: -
2157 - } else {
2158 - // stack: view, instance
2159 - list.add(getIntNode(mappedSubtype.sizeof));
2160 - // stack: sizeof, view, instance
2161 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_view", "(L" + MAPPED_OBJECT_JVM + ";II)V"));
2162 - // stack: -
2163 - }
2164 - return list;
2165 - }
2166 -
2167 - throw new InternalError();
2168 - }
2169 -
2170 - private static InsnList generateAddressInstructions(final FieldInsnNode fieldInsn) {
2171 - if ( !"J".equals(fieldInsn.desc) )
2172 - throw new IllegalStateException();
2173 -
2174 - if ( fieldInsn.getOpcode() == GETFIELD ) // do not change a thing
2175 - return null;
2176 -
2177 - if ( fieldInsn.getOpcode() == PUTFIELD )
2178 - throwAccessErrorOnReadOnlyField(fieldInsn.owner, fieldInsn.name);
2179 -
2180 - throw new InternalError();
2181 - }
2182 -
2183 - private static InsnList generateByteBufferInstructions(final FieldInsnNode fieldInsn, final MappedSubtypeInfo mappedSubtype, final long fieldOffset) {
2184 - if ( fieldInsn.getOpcode() == PUTFIELD )
2185 - throwAccessErrorOnReadOnlyField(fieldInsn.owner, fieldInsn.name);
2186 -
2187 - if ( fieldInsn.getOpcode() == GETFIELD ) {
2188 - final InsnList list = new InsnList();
2189 -
2190 - // stack: ref
2191 - list.add(new FieldInsnNode(GETFIELD, mappedSubtype.className, "viewAddress", "J"));
2192 - // stack: long
2193 - list.add(new LdcInsnNode(fieldOffset));
2194 - // stack: long, long
2195 - list.add(new InsnNode(LADD));
2196 - // stack: long
2197 - list.add(new LdcInsnNode(mappedSubtype.fields.get(fieldInsn.name).length));
2198 - // stack: long, long
2199 - list.add(new InsnNode(L2I));
2200 - // stack: int, long
2201 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "newBuffer", "(JI)L" + jvmClassName(ByteBuffer.class) + ";"));
2202 - // stack: buffer
2203 -
2204 - return list;
2205 - }
2206 -
2207 - throw new InternalError();
2208 - }
2209 -
2210 - private static InsnList generateFieldInstructions(final FieldInsnNode fieldInsn, final FieldInfo field) {
2211 - final InsnList list = new InsnList();
2212 -
2213 - if ( fieldInsn.getOpcode() == PUTFIELD ) {
2214 - // stack: value, ref
2215 - list.add(getIntNode((int)field.offset));
2216 - // stack: fieldOffset, value, ref
2217 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, field.getAccessType() + "put", "(L" + MAPPED_OBJECT_JVM + ";" + fieldInsn.desc + "I)V"));
2218 - // stack -
2219 - return list;
2220 - }
2221 -
2222 - if ( fieldInsn.getOpcode() == GETFIELD ) {
2223 - // stack: ref
2224 - list.add(getIntNode((int)field.offset));
2225 - // stack: fieldOffset, ref
2226 - list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, field.getAccessType() + "get", "(L" + MAPPED_OBJECT_JVM + ";I)" + fieldInsn.desc));
2227 - // stack: -
2228 - return list;
2229 - }
2230 -
2231 - throw new InternalError();
2232 - }
2233 -
2234 - static int transformArrayAccess(final InsnList instructions, int i, final Map<AbstractInsnNode, Frame<BasicValue>> frameMap, final VarInsnNode loadInsn, final MappedSubtypeInfo mappedSubtype, final int var) {
2235 - // We need to go forward in time to find how we use the array var
2236 - final int loadStackSize = frameMap.get(loadInsn).getStackSize() + 1;
2237 -
2238 - AbstractInsnNode nextInsn = loadInsn;
2239 -
2240 - while ( true ) {
2241 - nextInsn = nextInsn.getNext();
2242 - if ( nextInsn == null )
2243 - throw new InternalError();
2244 -
2245 - Frame<BasicValue> frame = frameMap.get(nextInsn);
2246 - if ( frame == null )
2247 - continue;
2248 -
2249 - int stackSize = frame.getStackSize();
2250 -
2251 - if ( stackSize == loadStackSize + 1 && nextInsn.getOpcode() == AALOAD ) {
2252 - final AbstractInsnNode aaLoadInsn = nextInsn;
2253 -
2254 - while ( true ) {
2255 - nextInsn = nextInsn.getNext();
2256 - if ( nextInsn == null )
2257 - break;
2258 -
2259 - frame = frameMap.get(nextInsn);
2260 - if ( frame == null )
2261 - continue;
2262 - stackSize = frame.getStackSize();
2263 -
2264 - if ( stackSize == loadStackSize + 1 && nextInsn.getOpcode() == PUTFIELD ) {
2265 - final FieldInsnNode fieldInsn = (FieldInsnNode)nextInsn;
2266 -
2267 - // stack: value, view, ref
2268 - instructions.insert(nextInsn, new MethodInsnNode(INVOKESTATIC, mappedSubtype.className, setterName(fieldInsn.name), "(L" + mappedSubtype.className + ";I" + fieldInsn.desc + ")V"));
2269 - // stack: -
2270 - instructions.remove(nextInsn);
2271 -
2272 - break;
2273 - } else if ( stackSize == loadStackSize && nextInsn.getOpcode() == GETFIELD ) {
2274 - final FieldInsnNode fieldInsn = (FieldInsnNode)nextInsn;
2275 -
2276 - // stack: view, ref
2277 - instructions.insert(nextInsn, new MethodInsnNode(INVOKESTATIC, mappedSubtype.className, getterName(fieldInsn.name), "(L" + mappedSubtype.className + ";I)" + fieldInsn.desc));
2278 - // stack: value
2279 - instructions.remove(nextInsn);
2280 -
2281 - break;
2282 - } else if ( stackSize == loadStackSize && nextInsn.getOpcode() == DUP && nextInsn.getNext().getOpcode() == GETFIELD ) {
2283 - // May happen with operator+assignment (e.g. cursor[i].value += 10)
2284 - final FieldInsnNode fieldInsn = (FieldInsnNode)nextInsn.getNext();
2285 -
2286 - final MethodInsnNode getter = new MethodInsnNode(INVOKESTATIC, mappedSubtype.className, getterName(fieldInsn.name), "(L" + mappedSubtype.className + ";I)" + fieldInsn.desc);
2287 -
2288 - // stack: view, ref
2289 - instructions.insert(nextInsn, new InsnNode(DUP2));
2290 - // stack: view, ref, view, ref
2291 - instructions.insert(nextInsn.getNext(), getter);
2292 - // stack: value, view, ref
2293 -
2294 - instructions.remove(nextInsn);
2295 - instructions.remove(fieldInsn);
2296 -
2297 - nextInsn = getter;
2298 - continue;
2299 - } else if ( stackSize < loadStackSize )
2300 - throw new ClassFormatError("Invalid " + mappedSubtype.className + " view array usage detected: " + getOpcodeName(nextInsn));
2301 - }
2302 -
2303 - instructions.remove(aaLoadInsn);
2304 -
2305 - return i;
2306 - } else if ( stackSize == loadStackSize && nextInsn.getOpcode() == ARRAYLENGTH ) {
2307 - if ( LWJGLUtil.DEBUG && loadInsn.getNext() != nextInsn )
2308 - throw new InternalError();
2309 -
2310 - instructions.remove(nextInsn);
2311 - loadInsn.var = var;
2312 - instructions.insert(loadInsn, new MethodInsnNode(INVOKEVIRTUAL, mappedSubtype.className, CAPACITY_METHOD_NAME, "()I"));
2313 -
2314 - return i + 1;
2315 - } else if ( stackSize < loadStackSize ) // Consumed by something other than AALOAD or ARRAYLENGTH
2316 - throw new ClassFormatError("Invalid " + mappedSubtype.className + " view array usage detected: " + getOpcodeName(nextInsn));
2317 - }
2318 - }
2319 -
2320 - private static class FieldInfo {
2321 -
2322 - final long offset;
2323 - final long length;
2324 - final long lengthPadded;
2325 - final Type type;
2326 - final boolean isVolatile;
2327 - final boolean isPointer;
2328 -
2329 - FieldInfo(final long offset, final long length, final long lengthPadded, final Type type, final boolean isVolatile, final boolean isPointer) {
2330 - this.offset = offset;
2331 - this.length = length;
2332 - this.lengthPadded = lengthPadded;
2333 - this.type = type;
2334 - this.isVolatile = isVolatile;
2335 - this.isPointer = isPointer;
2336 - }
2337 -
2338 - String getAccessType() {
2339 - return isPointer ? "a" : type.getDescriptor().toLowerCase() + (isVolatile ? "v" : "");
2340 - }
2341 -
2342 - }
2343 -
2344 - private static class MappedSubtypeInfo {
2345 -
2346 - final String className;
2347 -
2348 - final int sizeof;
2349 - final int sizeof_shift;
2350 - final int align;
2351 - final int padding;
2352 - final boolean cacheLinePadded;
2353 -
2354 - final Map<String, FieldInfo> fields;
2355 -
2356 - MappedSubtypeInfo(String className, Map<String, FieldInfo> fields, int sizeof, int align, int padding, final boolean cacheLinePadded) {
2357 - this.className = className;
2358 -
2359 - this.sizeof = sizeof;
2360 - if ( ((sizeof - 1) & sizeof) == 0 )
2361 - this.sizeof_shift = getPoT(sizeof);
2362 - else
2363 - this.sizeof_shift = 0;
2364 - this.align = align;
2365 - this.padding = padding;
2366 - this.cacheLinePadded = cacheLinePadded;
2367 -
2368 - this.fields = fields;
2369 - }
2370 -
2371 - private static int getPoT(int value) {
2372 - int pot = -1;
2373 - while ( value > 0 ) {
2374 - pot++;
2375 - value >>= 1;
2376 - }
2377 - return pot;
2378 - }
2379 -
2380 - }
2381 -
2382 - // -------------------------------------------------------
2383 - // -------------------[ MACROS & UTILS ]------------------
2384 - // -------------------------------------------------------
2385 -
2386 - private static void getClassEnums(final Class clazz, final Map<Integer, String> map, final String... prefixFilters) {
2387 - try {
2388 - OUTER:
2389 - for ( Field field : clazz.getFields() ) {
2390 - if ( !Modifier.isStatic(field.getModifiers()) || field.getType() != int.class )
2391 - continue;
2392 -
2393 - for ( String filter : prefixFilters ) {
2394 - if ( field.getName().startsWith(filter) )
2395 - continue OUTER;
2396 - }
2397 -
2398 - if ( map.put((Integer)field.get(null), field.getName()) != null )
2399 - throw new IllegalStateException();
2400 - }
2401 - } catch (Exception e) {
2402 - e.printStackTrace();
2403 - }
2404 - }
2405 -
2406 - static String getOpcodeName(final AbstractInsnNode insn) {
2407 - final String op = OPCODE_TO_NAME.get(insn.getOpcode());
2408 - return INSNTYPE_TO_NAME.get(insn.getType()) + ": " + insn.getOpcode() + (op == null ? "" : " [" + OPCODE_TO_NAME.get(insn.getOpcode()) + "]");
2409 - }
2410 -
2411 - static String jvmClassName(Class<?> type) {
2412 - return type.getName().replace('.', '/');
2413 - }
2414 -
2415 - static String getterName(final String fieldName) {
2416 - return "get$" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1) + "$LWJGL";
2417 - }
2418 -
2419 - static String setterName(final String fieldName) {
2420 - return "set$" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1) + "$LWJGL";
2421 - }
2422 -
2423 - private static void checkInsnAfterIsArray(final AbstractInsnNode instruction, final int opcode) {
2424 - if ( instruction == null )
2425 - throw new ClassFormatError("Unexpected end of instructions after .asArray() method.");
2426 -
2427 - if ( instruction.getOpcode() != opcode )
2428 - throw new ClassFormatError("The result of .asArray() must be stored to a local variable. Found: " + getOpcodeName(instruction));
2429 - }
2430 -
2431 - static AbstractInsnNode getIntNode(final int value) {
2432 - if ( value <= 5 && -1 <= value )
2433 - return new InsnNode(ICONST_M1 + value + 1);
2434 -
2435 - if ( value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE )
2436 - return new IntInsnNode(BIPUSH, value);
2437 -
2438 - if ( value >= Short.MIN_VALUE && value <= Short.MAX_VALUE )
2439 - return new IntInsnNode(SIPUSH, value);
2440 -
2441 - return new LdcInsnNode(value);
2442 - }
2443 -
2444 - static void visitIntNode(final MethodVisitor mv, final int value) {
2445 - if ( value <= 5 && -1 <= value )
2446 - mv.visitInsn(ICONST_M1 + value + 1);
2447 - else if ( value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE )
2448 - mv.visitIntInsn(BIPUSH, value);
2449 - else if ( value >= Short.MIN_VALUE && value <= Short.MAX_VALUE )
2450 - mv.visitIntInsn(SIPUSH, value);
2451 - else
2452 - mv.visitLdcInsn(value);
2453 - }
2454 -
2455 - /** Replace an instruction with a list of instructions. */
2456 - static int replace(final InsnList instructions, final int i, final AbstractInsnNode location, final InsnList list) {
2457 - final int size = list.size();
2458 -
2459 - instructions.insert(location, list);
2460 - instructions.remove(location);
2461 -
2462 - return i + (size - 1);
2463 - }
2464 -
2465 - private static void throwAccessErrorOnReadOnlyField(String className, String fieldName) {
2466 - throw new IllegalAccessError("The " + className + "." + fieldName + " field is final.");
2467 - }
2468 -
2469 - private static void printBytecode(byte[] bytecode) {
2470 - StringWriter sw = new StringWriter();
2471 - ClassVisitor tracer = new TraceClassVisitor(new ClassWriter(0), new PrintWriter(sw));
2472 - new ClassReader(bytecode).accept(tracer, 0);
2473 - String dump = sw.toString();
2474 -
2475 - LWJGLUtil.log(dump);
2476 - }
2477 -
2478 -}
2479 \ No newline at end of file
33 ppc64el.patch
44 systemjinput.patch
55 build-failure.patch
6 no-asm-support.patch