001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.jjs.test;
017:
018: import com.google.gwt.core.client.JavaScriptException;
019: import com.google.gwt.junit.client.GWTTestCase;
020:
021: import junit.framework.Assert;
022:
023: // CHECKSTYLE_OFF
024:
025: /**
026: * TODO: doc me
027: */
028: public class CompilerTest extends GWTTestCase {
029:
030: private abstract static class Apple implements Fruit {
031: }
032:
033: private static interface Fruit {
034: }
035:
036: private static class Fuji extends Apple {
037: }
038:
039: private static class Granny extends Apple {
040: }
041:
042: private static class NonSideEffectCauser {
043: public static final String NOT_A_COMPILE_TIME_CONSTANT = null;
044: }
045:
046: private static class SideEffectCauser {
047: private static Object instance = new Object();
048:
049: static {
050: CompilerTest.sideEffectChecker++;
051: }
052:
053: public static Object causeClinitSideEffect() {
054: return instance;
055: }
056: }
057:
058: private static class SideEffectCauser2 {
059: static {
060: CompilerTest.sideEffectChecker++;
061: }
062:
063: public static Object causeClinitSideEffect() {
064: return null;
065: }
066: }
067:
068: private static class SideEffectCauser3 {
069: static {
070: CompilerTest.sideEffectChecker++;
071: }
072:
073: public static void causeClinitSideEffect() {
074: }
075: }
076:
077: private static class SideEffectCauser4 {
078: public static String causeClinitSideEffectOnRead = "foo";
079:
080: static {
081: CompilerTest.sideEffectChecker++;
082: }
083: }
084:
085: private static class SideEffectCauser5 {
086: public static String causeClinitSideEffectOnRead = "bar";
087:
088: static {
089: CompilerTest.sideEffectChecker++;
090: }
091: }
092:
093: private static class SideEffectCauser6 extends
094: SideEffectCauser6Super {
095: public static String causeClinitSideEffectOnRead = "bar";
096: }
097:
098: private static class SideEffectCauser6Super {
099: static {
100: CompilerTest.sideEffectChecker++;
101: }
102: }
103:
104: /**
105: * Ensures that a superclass's clinit is run before supercall arguments are
106: * evaluated.
107: */
108: private static class SideEffectCauser7 extends
109: SideEffectCauser7Super {
110: public SideEffectCauser7() {
111: super (SideEffectCauser7Super.SHOULD_BE_TRUE);
112: }
113: }
114:
115: private static class SideEffectCauser7Super {
116: public static boolean SHOULD_BE_TRUE = false;
117:
118: static {
119: SHOULD_BE_TRUE = true;
120: }
121:
122: public SideEffectCauser7Super(boolean should_be_true) {
123: if (should_be_true) {
124: CompilerTest.sideEffectChecker++;
125: }
126: }
127: }
128:
129: private static final class UninstantiableType {
130: public Object field;
131:
132: private UninstantiableType() {
133: }
134:
135: public Object returnNull() {
136: return null;
137: }
138: }
139:
140: private static int sideEffectChecker;
141:
142: private static String barShouldInline() {
143: return "bar";
144: }
145:
146: private static void foo(String string) {
147: Object o = string;
148: }
149:
150: private static void foo(Throwable throwable) {
151: Object o = throwable;
152: }
153:
154: private static native String jsniReadSideEffectCauser5() /*-{
155: return @com.google.gwt.dev.jjs.test.CompilerTest$SideEffectCauser5::causeClinitSideEffectOnRead;
156: }-*/;
157:
158: private static native boolean noOptimizeFalse() /*-{
159: return false;
160: }-*/;
161:
162: private static native boolean noOptimizeTrue() /*-{
163: return true;
164: }-*/;
165:
166: public String getModuleName() {
167: return "com.google.gwt.dev.jjs.CompilerSuite";
168: }
169:
170: public void testArrayStore() {
171: Object[][] oaa;
172: oaa = new Object[4][4];
173: oaa[0][0] = "foo";
174: assertEquals(oaa[0][0], "foo");
175:
176: oaa = new Object[4][];
177: oaa[0] = new Object[4];
178: oaa[0][0] = "bar";
179: assertEquals(oaa[0][0], "bar");
180:
181: Apple[] apple = noOptimizeTrue() ? new Granny[3] : new Apple[3];
182: Apple g = noOptimizeTrue() ? (Apple) new Granny()
183: : (Apple) new Fuji();
184: Apple a = apple[0] = g;
185: assertEquals(g, a);
186:
187: byte[] bytes = new byte[10];
188: bytes[0] = (byte) '1';
189: assertEquals(49, bytes[0]);
190: }
191:
192: public void testCastOptimizer() {
193: Granny g = new Granny();
194: Apple a = g;
195: Fruit f = g;
196: a = (Apple) f;
197: g = (Granny) a;
198: g = (Granny) f;
199: }
200:
201: public void testClassLiterals() {
202: assertEquals("void", void.class.toString());
203: assertEquals("int", int.class.toString());
204: assertEquals("class java.lang.String", String.class.toString());
205: assertEquals("class com.google.gwt.dev.jjs.test.CompilerTest",
206: CompilerTest.class.toString());
207: assertEquals(
208: "class com.google.gwt.dev.jjs.test.CompilerTest$UninstantiableType",
209: UninstantiableType.class.toString());
210: assertEquals(
211: "interface com.google.gwt.dev.jjs.test.CompilerTest$Fruit",
212: Fruit.class.toString());
213: assertEquals("class [I", int[].class.toString());
214: assertEquals("class [Ljava.lang.String;", String[].class
215: .toString());
216: assertEquals(
217: "class [Lcom.google.gwt.dev.jjs.test.CompilerTest;",
218: CompilerTest[].class.toString());
219: assertEquals(
220: "class [Lcom.google.gwt.dev.jjs.test.CompilerTest$UninstantiableType;",
221: UninstantiableType[].class.toString());
222: assertEquals(
223: "class [Lcom.google.gwt.dev.jjs.test.CompilerTest$Fruit;",
224: Fruit[].class.toString());
225: }
226:
227: public void testClinitSideEffectInlining() {
228: sideEffectChecker = 0;
229: SideEffectCauser.causeClinitSideEffect();
230: assertEquals(1, sideEffectChecker);
231: SideEffectCauser2.causeClinitSideEffect();
232: assertEquals(2, sideEffectChecker);
233: SideEffectCauser3.causeClinitSideEffect();
234: assertEquals(3, sideEffectChecker);
235: String foo = SideEffectCauser4.causeClinitSideEffectOnRead;
236: assertEquals(4, sideEffectChecker);
237: jsniReadSideEffectCauser5();
238: assertEquals(5, sideEffectChecker);
239: foo = SideEffectCauser6.causeClinitSideEffectOnRead;
240: assertEquals(6, sideEffectChecker);
241: new SideEffectCauser7();
242: assertEquals(7, sideEffectChecker);
243: String checkRescued = NonSideEffectCauser.NOT_A_COMPILE_TIME_CONSTANT;
244: assertEquals(null, checkRescued);
245: }
246:
247: public void testConditionals() {
248: assertTrue(noOptimizeTrue() ? noOptimizeTrue()
249: : noOptimizeFalse());
250: assertFalse(noOptimizeFalse() ? noOptimizeTrue()
251: : noOptimizeFalse());
252: assertFalse(noOptimizeTrue() ? noOptimizeFalse()
253: : noOptimizeTrue());
254: assertTrue(noOptimizeFalse() ? noOptimizeFalse()
255: : noOptimizeTrue());
256:
257: assertTrue(true ? noOptimizeTrue() : noOptimizeFalse());
258: assertFalse(false ? noOptimizeTrue() : noOptimizeFalse());
259: assertFalse(true ? noOptimizeFalse() : noOptimizeTrue());
260: assertTrue(false ? noOptimizeFalse() : noOptimizeTrue());
261:
262: assertTrue(noOptimizeTrue() ? true : noOptimizeFalse());
263: assertFalse(noOptimizeFalse() ? true : noOptimizeFalse());
264: assertFalse(noOptimizeTrue() ? false : noOptimizeTrue());
265: assertTrue(noOptimizeFalse() ? false : noOptimizeTrue());
266:
267: assertTrue(noOptimizeTrue() ? noOptimizeTrue() : false);
268: assertFalse(noOptimizeFalse() ? noOptimizeTrue() : false);
269: assertFalse(noOptimizeTrue() ? noOptimizeFalse() : true);
270: assertTrue(noOptimizeFalse() ? noOptimizeFalse() : true);
271: }
272:
273: public void testDeadCode() {
274: while (returnFalse()) {
275: break;
276: }
277:
278: do {
279: break;
280: } while (false);
281:
282: do {
283: break;
284: } while (returnFalse());
285:
286: for (; returnFalse();) {
287: }
288:
289: boolean check = false;
290: for (check = true; returnFalse(); fail()) {
291: fail();
292: }
293: assertTrue(check);
294:
295: if (returnFalse()) {
296: fail();
297: } else {
298: }
299:
300: if (!returnFalse()) {
301: } else {
302: fail();
303: }
304:
305: // For these following tests, make sure that side effects in conditions
306: // get propagated, even if they cause introduction of dead code.
307: //
308: boolean b = false;
309: if ((b = true) ? true : true) {
310: }
311: assertTrue(b);
312:
313: boolean c = true;
314: int val = 0;
315: for (val = 1; c = false; ++val) {
316: }
317: assertFalse(c);
318:
319: boolean d = true;
320: while (d = false) {
321: }
322: assertFalse(d);
323:
324: boolean e = true;
325: if (true | (e = false)) {
326: }
327: assertFalse(e);
328: }
329:
330: public void testDeadTypes() {
331: if (false) {
332: new Object() {
333: }.toString();
334:
335: class Foo {
336: void a() {
337: }
338: }
339: new Foo().a();
340: }
341: }
342:
343: public void testEmptyBlockStatements() {
344: boolean b = false;
345: while (b) {
346: }
347:
348: do {
349: } while (b);
350:
351: for (; b;) {
352: }
353:
354: for (;;) {
355: break;
356: }
357:
358: if (b) {
359: }
360:
361: if (b) {
362: } else {
363: b = false;
364: }
365:
366: if (b) {
367: } else {
368: }
369: }
370:
371: public native void testEmptyBlockStatementsNative() /*-{
372: var b = false;
373: while (b) {
374: }
375:
376: do {
377: } while (b);
378:
379: for (; b; ) {
380: }
381:
382: for (;;) {
383: break;
384: }
385:
386: if (b) {
387: }
388:
389: if (b) {
390: } else {
391: b = false;
392: }
393:
394: if (b) {
395: } else {
396: }
397: }-*/;
398:
399: public void testEmptyStatements() {
400: boolean b = false;
401:
402: while (b)
403: ;
404:
405: do
406: ; while (b);
407:
408: for (; b;)
409: ;
410:
411: for (;;)
412: break;
413:
414: if (b)
415: ;
416:
417: if (b)
418: ;
419: else
420: b = false;
421:
422: if (b)
423: ;
424: else
425: ;
426: }
427:
428: public native void testEmptyStatementsNative() /*-{
429: var b = false;
430:
431: while (b);
432:
433: do; while (b);
434:
435: for (; b;);
436:
437: for (;;)
438: break;
439:
440: if (b)
441: ;
442:
443: if (b)
444: ;
445: else
446: b = false;
447:
448: if (b)
449: ;
450: else
451: ;
452: }-*/;
453:
454: public void testEmptyTryBlock() {
455: int x = 0;
456: try {
457: } finally {
458: x = 1;
459: }
460: assertEquals(1, x);
461: }
462:
463: public void testForStatement() {
464: {
465: int i;
466: for (i = 0; i < 10; ++i) {
467: }
468: assertEquals(i, 10);
469: }
470: {
471: int i, c;
472: for (i = 0, c = 10; i < c; ++i) {
473: }
474: assertEquals(i, 10);
475: assertEquals(c, 10);
476: }
477: {
478: int j = 0;
479: for (int i = 0; i < 10; ++i) {
480: ++j;
481: }
482: assertEquals(j, 10);
483: }
484: {
485: int j = 0;
486: for (int i = 0, c = 10; i < c; ++i) {
487: ++j;
488: }
489: assertEquals(j, 10);
490: }
491: }
492:
493: /**
494: * Issue #615: Internal Compiler Error
495: */
496: public void testImplicitNull() {
497: boolean b;
498: String test = ((((b = true) ? null : null) + " ") + b);
499: }
500:
501: public void testJavaScriptReservedWords() {
502: boolean delete = noOptimizeTrue();
503: for (int in = 0; in < 10; ++in) {
504: assertTrue(in < 10);
505: assertTrue(delete);
506: }
507: }
508:
509: public void testLabels() {
510: int i = 0, j = 0;
511: outer: for (i = 0; i < 1; ++i) {
512: inner: for (j = 0; j < 1; ++j) {
513: break outer;
514: }
515: fail();
516: }
517: assertEquals(0, i);
518: assertEquals(0, j);
519:
520: outer: for (i = 0; i < 1; ++i) {
521: inner: for (j = 0; j < 1; ++j) {
522: continue outer;
523: }
524: fail();
525: }
526: assertEquals(1, i);
527: assertEquals(0, j);
528:
529: outer: for (i = 0; i < 1; ++i) {
530: inner: for (j = 0; j < 1; ++j) {
531: break inner;
532: }
533: }
534: assertEquals(1, i);
535: assertEquals(0, j);
536:
537: outer: for (i = 0; i < 1; ++i) {
538: inner: for (j = 0; j < 1; ++j) {
539: continue inner;
540: }
541: }
542: assertEquals(1, i);
543: assertEquals(1, j);
544: }
545:
546: public void testLocalClasses() {
547: class Foo {
548: public Foo(int j) {
549: assertEquals(1, j);
550: };
551: }
552: final int i;
553: new Foo(i = 1) {
554: {
555: assertEquals(1, i);
556: }
557: };
558: assertEquals(1, i);
559: }
560:
561: public void testLocalRefs() {
562: final String foo = noOptimizeTrue() ? "foo" : "bar";
563: final String bar = noOptimizeTrue() ? "bar" : "foo";
564: String result = new Object() {
565:
566: private String a = foo;
567:
568: {
569: a = foo;
570: }
571:
572: public String toString() {
573: return new Object() {
574:
575: private static final String constantString = "wallawalla";
576:
577: private String ai = foo;
578:
579: {
580: ai = foo;
581: }
582:
583: public String toString() {
584: // this line used to cause ICE due to no synthetic path to bar
585: bar.valueOf(false);
586:
587: assertEquals("wallawalla", constantString);
588: return foo + a + ai;
589: }
590:
591: }.toString()
592: + a;
593: }
594:
595: }.toString();
596: assertEquals(result, "foofoofoofoo");
597: }
598:
599: public void testNotOptimizations() {
600: assertFalse(!true);
601: assertTrue(!false);
602:
603: assertTrue(!(noOptimizeTrue() == noOptimizeFalse()));
604: assertFalse(!(noOptimizeTrue() != noOptimizeFalse()));
605:
606: assertFalse(!(3 < 4));
607: assertFalse(!(3 <= 4));
608: assertTrue(!(3 > 4));
609: assertTrue(!(3 >= 4));
610:
611: assertTrue(!(4 < 3));
612: assertTrue(!(4 <= 3));
613: assertFalse(!(4 > 3));
614: assertFalse(!(4 >= 3));
615:
616: assertTrue(!!noOptimizeTrue());
617: assertFalse(!!noOptimizeFalse());
618: }
619:
620: public void testNullFlow() {
621: UninstantiableType f = null;
622:
623: try {
624: f.returnNull().toString();
625: fail();
626: } catch (NullPointerException e) {
627: // hosted mode
628: } catch (JavaScriptException e) {
629: // web mode
630: }
631:
632: try {
633: f.field = null;
634: fail();
635: } catch (NullPointerException e) {
636: // hosted mode
637: } catch (JavaScriptException e) {
638: // web mode
639: }
640:
641: try {
642: UninstantiableType[] fa = null;
643: fa[4] = null;
644: fail();
645: } catch (NullPointerException e) {
646: // hosted mode
647: } catch (JavaScriptException e) {
648: // web mode
649: }
650: }
651:
652: public void testNullFlowArray() {
653: UninstantiableType[] uta = new UninstantiableType[10];
654: assertEquals(uta.length, 10);
655: assertEquals(uta[0], null);
656: uta[1] = null;
657: assertEquals(uta[1], null);
658: }
659:
660: public void testNullFlowOverloads() {
661: foo((Throwable) null);
662: foo((String) null);
663: }
664:
665: public void testNullFlowVsClassCastPrecedence() {
666: try {
667: ((UninstantiableType) new Object()).returnNull();
668: fail();
669: } catch (ClassCastException e) {
670: // success
671: }
672: }
673:
674: public void testOuterSuperThisRefs() {
675: new B();
676: }
677:
678: public void testReturnStatementInCtor() {
679: class Foo {
680: int i;
681:
682: Foo(int i) {
683: this .i = i;
684: if (i == 0)
685: return;
686: else if (i == 1)
687: return;
688: return;
689: }
690: }
691: assertEquals(new Foo(0).i, 0);
692: assertEquals(new Foo(1).i, 1);
693: assertEquals(new Foo(2).i, 2);
694: }
695:
696: public void testStringOptimizations() {
697: assertEquals("Herro, AJAX", "Hello, AJAX".replace('l', 'r'));
698: assertEquals('J', "Hello, AJAX".charAt(8));
699: assertEquals(11, "Hello, AJAX".length());
700: assertFalse("Hello, AJAX".equals("me"));
701: assertTrue("Hello, AJAX".equals("Hello, AJAX"));
702: assertTrue("Hello, AJAX".equalsIgnoreCase("HELLO, ajax"));
703: assertEquals("hello, ajax", "Hello, AJAX".toLowerCase());
704:
705: assertEquals("foobar", "foo" + barShouldInline());
706: assertEquals("1bar", 1 + barShouldInline());
707: assertEquals("fbar", 'f' + barShouldInline());
708: assertEquals("truebar", true + barShouldInline());
709: assertEquals("3.3bar", 3.3 + barShouldInline());
710: assertEquals("3.3bar", 3.3f + barShouldInline());
711: assertEquals("27bar", 27L + barShouldInline());
712: assertEquals("nullbar", null + barShouldInline());
713: }
714:
715: public void testSubclassStaticInnerAndClinitOrdering() {
716: new CheckSubclassStaticInnerAndClinitOrdering();
717: }
718:
719: public void testSwitchStatement() {
720: switch (0) {
721: case 0:
722: int test; // used to cause an ICE
723: break;
724: }
725: }
726:
727: /**
728: * Tests cases where the compiler will convert to a simple if or block.
729: */
730: public void testSwitchStatementConversions() {
731: int i = 1;
732:
733: switch (i) {
734: case 1:
735: i = 2;
736: }
737: assertEquals(2, i);
738:
739: switch (i) {
740: case 1:
741: i = 3;
742: }
743: assertEquals(2, i);
744:
745: switch (i) {
746: default:
747: i = 3;
748: }
749: assertEquals(3, i);
750: }
751:
752: public void testSwitchStatementFallthroughs() {
753: int i = 1;
754: switch (i) {
755: case 1:
756: i = 2;
757: case 2:
758: break;
759: case 3:
760: fail("Shouldn't get here");
761: }
762: assertEquals(2, i);
763:
764: switch (i) {
765: case 1:
766: break;
767: case 2:
768: i = 3;
769: break;
770: case 3:
771: break;
772: case 4:
773: fail("Shouldn't get here");
774: break;
775: }
776: assertEquals(3, i);
777: }
778:
779: public void testSwitchStatementWithUsefulDefault() {
780: switch (1) {
781: case 1:
782: case 2:
783: case 3: {
784: break;
785: }
786: case 4:
787: case 5:
788: case 6:
789: default:
790: fail("Shouldn't get here");
791: break;
792: }
793: }
794:
795: public void testSwitchStatementWithUselessCases() {
796: switch (1) {
797: case 1:
798: case 2:
799: case 3: {
800: break;
801: }
802: case 4:
803: case 5:
804: case 6:
805: default:
806: break;
807: }
808: }
809:
810: public void testSwitchStatementWontRemoveExpression() {
811: class Foo {
812: boolean setFlag;
813:
814: int setFlag() {
815: setFlag = true;
816: return 3;
817: }
818: }
819:
820: Foo foo = new Foo();
821: switch (foo.setFlag()) {
822: case 3:
823: break;
824: }
825:
826: // Make sure that compiler didn't optimize away the switch statement's
827: // expression
828: assertTrue(foo.setFlag);
829: }
830:
831: public void testUnaryPlus() {
832: int x, y = -7;
833: x = +y;
834: assertEquals(-7, x);
835: }
836:
837: private boolean returnFalse() {
838: return false;
839: }
840:
841: }
842:
843: class A {
844: public abstract class AA {
845: }
846: }
847:
848: class B extends A {
849: {
850: new AA() {
851: };
852: }
853: }
854:
855: // This construct used to cause an ICE
856: class CheckSubclassStaticInnerAndClinitOrdering extends
857: Outer.StaticInner {
858: private static class Foo {
859: }
860:
861: private static final Foo FOO = new Foo();
862:
863: public CheckSubclassStaticInnerAndClinitOrdering() {
864: this (FOO);
865: }
866:
867: public CheckSubclassStaticInnerAndClinitOrdering(Foo foo) {
868: // This used to be null due to clinit ordering issues
869: Assert.assertNotNull(foo);
870: }
871: }
872:
873: class Outer {
874: public static class StaticInner {
875: }
876: }
|