### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java,v retrieving revision 1.523 diff -u -r1.523 GenericTypeTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 26 Sep 2006 21:27:18 -0000 1.523 +++ src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 28 Sep 2006 11:35:34 -0000 @@ -33103,4 +33103,271 @@ "Zork cannot be resolved to a type\n" + "----------\n"); } +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=159021 - variation +public void test1038() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.OPTIMIZE_OUT); + this.runConformTest( + new String[] { + "X.java", + "interface I {\n" + + " int CONST = A.foo();\n" + + "}\n" + + "\n" + + "class A {\n" + + " static int foo() {\n" + + " System.out.println(\"SUCCESS\");\n" + + " return 0;\n" + + " }\n" + + "}\n" + + "class B implements I {\n" + + " static int LOCAL_STATIC;\n" + + " int local_field;\n" + + " B(int param) {\n" + + " int i = CONST; // keep for possible \n" + + " int j = param; // may optimize out\n" + + " int k = LOCAL_STATIC; // may optimize out\n" + + " int l = local_field; // may optimize out\n" + + " }\n" + + "}\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " new B(12);\n" + + " }\n" + + "}", // ================= + }, + "SUCCESS", + null, + false, + null, + options, + null); + // check the reference to I.CONST still got generated (for invocation side-effect) + String expectedOutput = + " // Method descriptor #10 (I)V\n" + + " // Stack: 1, Locals: 2\n" + + " B(int param);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [12]\n" + + " 4 getstatic B.CONST : int [15]\n" + + " 7 pop\n" + + " 8 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 14]\n" + + " [pc: 4, line: 15]\n" + + " [pc: 8, line: 19]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 9] local: this index: 0 type: B\n" + + " [pc: 0, pc: 9] local: param index: 1 type: int\n"; + + try { + File f = new File(OUTPUT_DIR + File.separator + "B.class"); + byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f); + ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler(); + String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.DETAILED); + int index = result.indexOf(expectedOutput); + if (index == -1 || expectedOutput.length() == 0) { + System.out.println(Util.displayString(result, 3)); + } + if (index == -1) { + assertEquals("Wrong contents", expectedOutput, result); + } + } catch (org.eclipse.jdt.core.util.ClassFormatException e) { + assertTrue(false); + } catch (IOException e) { + assertTrue(false); + } +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=159021 - variation +public void test1039() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.OPTIMIZE_OUT); + this.runConformTest( + new String[] { + "X.java", + "interface I {\n" + + " Value CONST = A.foo(\"[I.CONST]\");\n" + + "}\n" + + "class Value {\n" + + " static String NAME = \"\";\n" + + " V v;\n" + + " Value(V v) {\n" + + " this.v = v;\n" + + " }\n" + + "}\n" + + "class A {\n" + + " static Value foo(String str) {\n" + + " System.out.print(str);\n" + + " return new Value(\"str\");\n" + + " }\n" + + "}\n" + + "class B implements I {\n" + + " static Value LOCAL_STATIC = A.foo(\"[B.LOCAL_STATIC]\");\n" + + " Value local_field = A.foo(\"[B.local_field]\");\n" + + " B(Value param) {\n" + + " String i = CONST.NAME; // keep for possible \n" + + " String j = param.NAME; // may optimize out\n" + + " String k = LOCAL_STATIC.NAME; // may optimize out\n" + + " String l = local_field.NAME; // may optimize out\n" + + " }\n" + + "}\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " new B(new Value(\"[PARAM]\"));\n" + + " }\n" + + "}", // ================= + }, + "[B.LOCAL_STATIC][B.local_field][I.CONST]", + null, + false, + null, + options, + null); + // check the reference to I.CONST still got generated (for invocation side-effect) + String expectedOutput = + " // Method descriptor #28 (LValue;)V\n" + + " // Signature: (LValue;)V\n" + + " // Stack: 2, Locals: 2\n" + + " B(Value param);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [30]\n" + + " 4 aload_0 [this]\n" + + " 5 ldc [32]\n" + + " 7 invokestatic A.foo(java.lang.String) : Value [17]\n" + + " 10 putfield B.local_field : Value [34]\n" + + " 13 getstatic I.CONST : Value [36]\n" + + " 16 pop\n" + + " 17 getstatic Value.NAME : java.lang.String [39]\n" + + " 20 pop\n" + + " 21 getstatic Value.NAME : java.lang.String [39]\n" + + " 24 pop\n" + + " 25 getstatic Value.NAME : java.lang.String [39]\n" + + " 28 pop\n" + + " 29 getstatic Value.NAME : java.lang.String [39]\n" + + " 32 pop\n" + + " 33 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 20]\n" + + " [pc: 4, line: 19]\n" + + " [pc: 13, line: 21]\n" + + " [pc: 21, line: 22]\n" + + " [pc: 25, line: 23]\n" + + " [pc: 29, line: 24]\n" + + " [pc: 33, line: 25]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 34] local: this index: 0 type: B\n" + + " [pc: 0, pc: 34] local: param index: 1 type: Value\n"; + + try { + File f = new File(OUTPUT_DIR + File.separator + "B.class"); + byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f); + ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler(); + String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.DETAILED); + int index = result.indexOf(expectedOutput); + if (index == -1 || expectedOutput.length() == 0) { + System.out.println(Util.displayString(result, 3)); + } + if (index == -1) { + assertEquals("Wrong contents", expectedOutput, result); + } + } catch (org.eclipse.jdt.core.util.ClassFormatException e) { + assertTrue(false); + } catch (IOException e) { + assertTrue(false); + } +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=159021 - variation +public void test1040() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.OPTIMIZE_OUT); + this.runConformTest( + new String[] { + "X.java", + "interface I {\n" + + " Value CONST = A.foo(\"[I.CONST]\");\n" + + "}\n" + + "class Value {\n" + + " static String NAME = \"\";\n" + + " V v;\n" + + " Value(V v) {\n" + + " this.v = v;\n" + + " }\n" + + "}\n" + + "class A {\n" + + " static Value foo(String str) {\n" + + " System.out.print(str);\n" + + " return new Value(\"str\");\n" + + " }\n" + + "}\n" + + "class B implements I {\n" + + " static Value LOCAL_STATIC = A.foo(\"[B.LOCAL_STATIC]\");\n" + + " Value local_field = A.foo(\"[B.local_field]\");\n" + + " B(Value param) {\n" + + " String i = this.CONST.NAME; // keep for possible \n" + + " String k = this.LOCAL_STATIC.NAME; // may optimize out\n" + + " String l = this.local_field.NAME; // may optimize out\n" + + " }\n" + + "}\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " new B(new Value(\"[PARAM]\"));\n" + + " }\n" + + "}", // ================= + }, + "[B.LOCAL_STATIC][B.local_field][I.CONST]", + null, + false, + null, + options, + null); + // check the reference to I.CONST still got generated (for invocation side-effect) + String expectedOutput = + " // Method descriptor #28 (LValue;)V\n" + + " // Signature: (LValue;)V\n" + + " // Stack: 2, Locals: 2\n" + + " B(Value param);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [30]\n" + + " 4 aload_0 [this]\n" + + " 5 ldc [32]\n" + + " 7 invokestatic A.foo(java.lang.String) : Value [17]\n" + + " 10 putfield B.local_field : Value [34]\n" + + " 13 getstatic B.CONST : Value [36]\n" + + " 16 pop\n" + + " 17 getstatic Value.NAME : java.lang.String [39]\n" + + " 20 pop\n" + + " 21 getstatic Value.NAME : java.lang.String [39]\n" + + " 24 pop\n" + + " 25 getstatic Value.NAME : java.lang.String [39]\n" + + " 28 pop\n" + + " 29 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 20]\n" + + " [pc: 4, line: 19]\n" + + " [pc: 13, line: 21]\n" + + " [pc: 21, line: 22]\n" + + " [pc: 25, line: 23]\n" + + " [pc: 29, line: 24]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 30] local: this index: 0 type: B\n" + + " [pc: 0, pc: 30] local: param index: 1 type: Value\n"; + + try { + File f = new File(OUTPUT_DIR + File.separator + "B.class"); + byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f); + ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler(); + String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.DETAILED); + int index = result.indexOf(expectedOutput); + if (index == -1 || expectedOutput.length() == 0) { + System.out.println(Util.displayString(result, 3)); + } + if (index == -1) { + assertEquals("Wrong contents", expectedOutput, result); + } + } catch (org.eclipse.jdt.core.util.ClassFormatException e) { + assertTrue(false); + } catch (IOException e) { + assertTrue(false); + } +} } \ No newline at end of file #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java,v retrieving revision 1.106 diff -u -r1.106 QualifiedNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java 28 Mar 2006 20:29:56 -0000 1.106 +++ compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java 28 Sep 2006 11:35:36 -0000 @@ -653,7 +653,20 @@ codeStream.pop(); } } else { - if (this.codegenBinding != lastFieldBinding && !lastFieldBinding.isStatic()){ + if (this.codegenBinding == lastFieldBinding) { + if (lastFieldBinding.isStatic()){ + // if no valueRequired, still need possible side-effects of invocation, if field belongs to different class + if (((FieldBinding)binding).original().declaringClass != this.actualReceiverType.erasure()) { + MethodBinding accessor = syntheticReadAccessors == null ? null : syntheticReadAccessors[i]; + if (accessor == null) { + codeStream.getstatic(lastFieldBinding); + } else { + codeStream.invokestatic(accessor); + } + codeStream.pop(); + } + } + } else if (!lastFieldBinding.isStatic()){ codeStream.invokeObjectGetClass(); // perform null check codeStream.pop(); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java,v retrieving revision 1.89 diff -u -r1.89 SingleNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 9 Feb 2006 16:01:30 -0000 1.89 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 28 Sep 2006 11:35:37 -0000 @@ -346,43 +346,57 @@ if (valueRequired) { codeStream.generateConstant(fieldConstant, implicitConversion); } - } else { - if (valueRequired) { - boolean isStatic = fieldBinding.isStatic(); - if (!isStatic) { - if ((bits & DepthMASK) != 0) { - ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); - Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); - codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); - } else { - generateReceiver(codeStream); - } + break; + } + if (fieldBinding.isStatic()) { + if (!valueRequired) { + // if no valueRequired, still need possible side-effects of invocation, if field belongs to different class + if (((FieldBinding)binding).original().declaringClass == this.actualReceiverType.erasure()) { + break; } - // managing private access - if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { - if (isStatic) { - codeStream.getstatic(fieldBinding); - } else { - codeStream.getfield(fieldBinding); - } - } else { - codeStream.invokestatic(syntheticAccessors[READ]); + } + // managing private access + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + codeStream.getstatic(fieldBinding); + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + if (valueRequired) { + if (this.genericCast != null) codeStream.checkcast(this.genericCast); + codeStream.generateImplicitConversion(implicitConversion); + } else { + // could occur if !valueRequired but static field belongs to different class + switch (fieldBinding.type.id) { + case T_long : + case T_double : + codeStream.pop2(); + break; + default : + codeStream.pop(); } - if (valueRequired) { - if (this.genericCast != null) codeStream.checkcast(this.genericCast); - codeStream.generateImplicitConversion(implicitConversion); - } else { - // could occur if !valueRequired but compliance >= 1.4 - switch (fieldBinding.type.id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - } - } + } + } else { + if (!valueRequired) { + // if no valueRequired, optimize out entire gen + break; } + // managing enclosing instance access + if ((bits & DepthMASK) != 0) { + ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); + Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); + codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); + } else { + generateReceiver(codeStream); + } + // managing private access + if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) { + codeStream.getfield(fieldBinding); + } else { + codeStream.invokestatic(syntheticAccessors[READ]); + } + // managing generic cast + if (this.genericCast != null) codeStream.checkcast(this.genericCast); + codeStream.generateImplicitConversion(implicitConversion); } break; case Binding.LOCAL : // reading a local Index: compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java,v retrieving revision 1.102 diff -u -r1.102 FieldReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 28 Mar 2006 20:29:57 -0000 1.102 +++ compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 28 Sep 2006 11:35:36 -0000 @@ -168,67 +168,89 @@ if (valueRequired) { codeStream.generateConstant(constant, implicitConversion); } - } else { - boolean isStatic = this.codegenBinding.isStatic(); - boolean isThisReceiver = this.receiver instanceof ThisReference; - Constant fieldConstant = this.codegenBinding.constant(); - if (fieldConstant != Constant.NotAConstant) { - if (!isThisReceiver) { - receiver.generateCode(currentScope, codeStream, !isStatic); - if (!isStatic){ - codeStream.invokeObjectGetClass(); - codeStream.pop(); - } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + boolean isStatic = this.codegenBinding.isStatic(); + boolean isThisReceiver = this.receiver instanceof ThisReference; + Constant fieldConstant = this.codegenBinding.constant(); + if (fieldConstant != Constant.NotAConstant) { + if (!isThisReceiver) { + receiver.generateCode(currentScope, codeStream, !isStatic); + if (!isStatic){ + codeStream.invokeObjectGetClass(); + codeStream.pop(); } + } + if (valueRequired) { + codeStream.generateConstant(fieldConstant, implicitConversion); + } + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } + if (valueRequired || (!isThisReceiver && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)) { + receiver.generateCode(currentScope, codeStream, !isStatic); + if (this.codegenBinding.declaringClass == null) { // array length + codeStream.arraylength(); if (valueRequired) { - codeStream.generateConstant(fieldConstant, implicitConversion); + codeStream.generateImplicitConversion(implicitConversion); + } else { + // could occur if !valueRequired but compliance >= 1.4 + codeStream.pop(); } } else { - if (valueRequired || (!isThisReceiver && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)) { - receiver.generateCode(currentScope, codeStream, !isStatic); - if (this.codegenBinding.declaringClass == null) { // array length - codeStream.arraylength(); - if (valueRequired) { - codeStream.generateImplicitConversion(implicitConversion); - } else { - // could occur if !valueRequired but compliance >= 1.4 - codeStream.pop(); - } + if (syntheticAccessors == null || syntheticAccessors[READ] == null) { + if (isStatic) { + codeStream.getstatic(this.codegenBinding); } else { - if (syntheticAccessors == null || syntheticAccessors[READ] == null) { - if (isStatic) { - codeStream.getstatic(this.codegenBinding); - } else { - codeStream.getfield(this.codegenBinding); - } - } else { - codeStream.invokestatic(syntheticAccessors[READ]); - } - if (valueRequired) { - if (this.genericCast != null) codeStream.checkcast(this.genericCast); - codeStream.generateImplicitConversion(implicitConversion); - } else { - // could occur if !valueRequired but compliance >= 1.4 - switch (this.codegenBinding.type.id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - } - } + codeStream.getfield(this.codegenBinding); } } else { - if (!isThisReceiver) { - receiver.generateCode(currentScope, codeStream, !isStatic); - if (!isStatic){ - codeStream.invokeObjectGetClass(); // perform null check + codeStream.invokestatic(syntheticAccessors[READ]); + } + if (valueRequired) { + if (this.genericCast != null) codeStream.checkcast(this.genericCast); + codeStream.generateImplicitConversion(implicitConversion); + } else { + // could occur if !valueRequired but compliance >= 1.4 + switch (this.codegenBinding.type.id) { + case T_long : + case T_double : + codeStream.pop2(); + break; + default : codeStream.pop(); - } } } } + } else { + if (isThisReceiver) { + if (isStatic){ + // if no valueRequired, still need possible side-effects of invocation, if field belongs to different class + if (this.binding.original().declaringClass != this.receiverType.erasure()) { + MethodBinding accessor = syntheticAccessors == null ? null : syntheticAccessors[READ]; + if (accessor == null) { + codeStream.getstatic(this.codegenBinding); + } else { + codeStream.invokestatic(accessor); + } + switch (this.codegenBinding.type.id) { + case T_long : + case T_double : + codeStream.pop2(); + break; + default : + codeStream.pop(); + } + } + } + } else { + receiver.generateCode(currentScope, codeStream, !isStatic); + if (!isStatic){ + codeStream.invokeObjectGetClass(); // perform null check + codeStream.pop(); + } + } } codeStream.recordPositionsFrom(pc, this.sourceStart); } #P org.eclipse.jdt.core.tests Index: Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core.tests/Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java,v retrieving revision 1.99 diff -u -r1.99 InitializationTest.java --- Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java 10 Apr 2006 19:02:50 -0000 1.99 +++ Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java 28 Sep 2006 11:35:38 -0000 @@ -10,9 +10,16 @@ *******************************************************************************/ package org.eclipse.jdt.tests.compiler.regression; +import java.io.File; +import java.io.IOException; import java.util.Hashtable; +import java.util.Map; +import org.eclipse.jdt.core.ToolFactory; import org.eclipse.jdt.core.tests.compiler.regression.*; +import org.eclipse.jdt.core.tests.util.Util; +import org.eclipse.jdt.core.util.ClassFileBytesDisassembler; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import junit.framework.Test; @@ -5101,6 +5108,326 @@ " ^^^^\n" + "Zork cannot be resolved to a type\n" + "----------\n"); +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=159021 +public void test189() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.OPTIMIZE_OUT); + this.runConformTest( + new String[] { + "X.java", + "interface I {\n" + + " int CONST = A.foo();\n" + + "}\n" + + "\n" + + "class A {\n" + + " static int foo() {\n" + + " System.out.println(\"SUCCESS\");\n" + + " return 0;\n" + + " }\n" + + "}\n" + + "class B implements I {\n" + + " static int LOCAL_STATIC;\n" + + " int local_field;\n" + + " B(int param) {\n" + + " int i = CONST; // keep for possible \n" + + " int j = param; // may optimize out\n" + + " int k = LOCAL_STATIC; // may optimize out\n" + + " int l = local_field; // may optimize out\n" + + " }\n" + + "}\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " new B(12);\n" + + " }\n" + + "}", // ================= + }, + "SUCCESS", + null, + false, + null, + options, + null); + // check the reference to I.CONST still got generated (for invocation side-effect) + String expectedOutput = new CompilerOptions(options).complianceLevel < ClassFileConstants.JDK1_4 + ? " // Method descriptor #10 (I)V\n" + + " // Stack: 1, Locals: 2\n" + + " B(int param);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [12]\n" + + " 4 getstatic I.CONST : int [15]\n" + + " 7 pop\n" + + " 8 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 14]\n" + + " [pc: 4, line: 15]\n" + + " [pc: 8, line: 19]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 9] local: this index: 0 type: B\n" + + " [pc: 0, pc: 9] local: param index: 1 type: int\n" + : " // Method descriptor #10 (I)V\n" + + " // Stack: 1, Locals: 2\n" + + " B(int param);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [12]\n" + + " 4 getstatic B.CONST : int [15]\n" + + " 7 pop\n" + + " 8 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 14]\n" + + " [pc: 4, line: 15]\n" + + " [pc: 8, line: 19]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 9] local: this index: 0 type: B\n" + + " [pc: 0, pc: 9] local: param index: 1 type: int\n"; + + try { + File f = new File(OUTPUT_DIR + File.separator + "B.class"); + byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f); + ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler(); + String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.DETAILED); + int index = result.indexOf(expectedOutput); + if (index == -1 || expectedOutput.length() == 0) { + System.out.println(Util.displayString(result, 3)); + } + if (index == -1) { + assertEquals("Wrong contents", expectedOutput, result); + } + } catch (org.eclipse.jdt.core.util.ClassFormatException e) { + assertTrue(false); + } catch (IOException e) { + assertTrue(false); + } +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=159021 - variation +public void test190() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.OPTIMIZE_OUT); + this.runConformTest( + new String[] { + "X.java", + "interface I {\n" + + " Value CONST = A.foo(\"[I.CONST]\");\n" + + "}\n" + + "class Value {\n" + + " static String NAME = \"\";\n" + + " String v;\n" + + " Value(String v) {\n" + + " this.v = v;\n" + + " }\n" + + "}\n" + + "class A {\n" + + " static Value foo(String str) {\n" + + " System.out.print(str);\n" + + " return new Value(\"str\");\n" + + " }\n" + + "}\n" + + "class B implements I {\n" + + " static Value LOCAL_STATIC = A.foo(\"[B.LOCAL_STATIC]\");\n" + + " Value local_field = A.foo(\"[B.local_field]\");\n" + + " B(Value param) {\n" + + " String i = CONST.NAME; // keep for possible \n" + + " String j = param.NAME; // may optimize out\n" + + " String k = LOCAL_STATIC.NAME; // may optimize out\n" + + " String l = local_field.NAME; // may optimize out\n" + + " }\n" + + "}\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " new B(new Value(\"[PARAM]\"));\n" + + " }\n" + + "}", // ================= + }, + "[B.LOCAL_STATIC][B.local_field][I.CONST]", + null, + false, + null, + options, + null); + // check the reference to I.CONST still got generated (for invocation side-effect) + String expectedOutput = new CompilerOptions(options).complianceLevel < ClassFileConstants.JDK1_4 + ? " // Method descriptor #26 (LValue;)V\n" + + " // Stack: 2, Locals: 2\n" + + " B(Value param);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [27]\n" + + " 4 aload_0 [this]\n" + + " 5 ldc [29]\n" + + " 7 invokestatic A.foo(java.lang.String) : Value [15]\n" + + " 10 putfield B.local_field : Value [31]\n" + + " 13 getstatic I.CONST : Value [33]\n" + + " 16 pop\n" + + " 17 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 20]\n" + + " [pc: 4, line: 19]\n" + + " [pc: 13, line: 21]\n" + + " [pc: 17, line: 25]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 18] local: this index: 0 type: B\n" + + " [pc: 0, pc: 18] local: param index: 1 type: Value\n" + : " // Method descriptor #26 (LValue;)V\n" + + " // Stack: 2, Locals: 2\n" + + " B(Value param);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [27]\n" + + " 4 aload_0 [this]\n" + + " 5 ldc [29]\n" + + " 7 invokestatic A.foo(java.lang.String) : Value [15]\n" + + " 10 putfield B.local_field : Value [31]\n" + + " 13 getstatic I.CONST : Value [33]\n" + + " 16 pop\n" + + " 17 getstatic Value.NAME : java.lang.String [36]\n" + + " 20 pop\n" + + " 21 getstatic Value.NAME : java.lang.String [36]\n" + + " 24 pop\n" + + " 25 getstatic Value.NAME : java.lang.String [36]\n" + + " 28 pop\n" + + " 29 getstatic Value.NAME : java.lang.String [36]\n" + + " 32 pop\n" + + " 33 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 20]\n" + + " [pc: 4, line: 19]\n" + + " [pc: 13, line: 21]\n" + + " [pc: 21, line: 22]\n" + + " [pc: 25, line: 23]\n" + + " [pc: 29, line: 24]\n" + + " [pc: 33, line: 25]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 34] local: this index: 0 type: B\n" + + " [pc: 0, pc: 34] local: param index: 1 type: Value\n"; + + try { + File f = new File(OUTPUT_DIR + File.separator + "B.class"); + byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f); + ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler(); + String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.DETAILED); + int index = result.indexOf(expectedOutput); + if (index == -1 || expectedOutput.length() == 0) { + System.out.println(Util.displayString(result, 3)); + } + if (index == -1) { + assertEquals("Wrong contents", expectedOutput, result); + } + } catch (org.eclipse.jdt.core.util.ClassFormatException e) { + assertTrue(false); + } catch (IOException e) { + assertTrue(false); + } +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=159021 - variation +public void test191() { + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.OPTIMIZE_OUT); + this.runConformTest( + new String[] { + "X.java", + "interface I {\n" + + " Value CONST = A.foo(\"[I.CONST]\");\n" + + "}\n" + + "class Value {\n" + + " static String NAME = \"\";\n" + + " String v;\n" + + " Value(String v) {\n" + + " this.v = v;\n" + + " }\n" + + "}\n" + + "class A {\n" + + " static Value foo(String str) {\n" + + " System.out.print(str);\n" + + " return new Value(\"str\");\n" + + " }\n" + + "}\n" + + "class B implements I {\n" + + " static Value LOCAL_STATIC = A.foo(\"[B.LOCAL_STATIC]\");\n" + + " Value local_field = A.foo(\"[B.local_field]\");\n" + + " B(Value param) {\n" + + " String i = this.CONST.NAME; // keep for possible \n" + + " String k = this.LOCAL_STATIC.NAME; // may optimize out\n" + + " String l = this.local_field.NAME; // may optimize out\n" + + " }\n" + + "}\n" + + "public class X {\n" + + " public static void main(String[] args) {\n" + + " new B(new Value(\"[PARAM]\"));\n" + + " }\n" + + "}", // ================= + }, + "[B.LOCAL_STATIC][B.local_field][I.CONST]", + null, + false, + null, + options, + null); + // check the reference to I.CONST still got generated (for invocation side-effect) + String expectedOutput = new CompilerOptions(options).complianceLevel < ClassFileConstants.JDK1_4 + ? " // Method descriptor #26 (LValue;)V\n" + + " // Stack: 2, Locals: 2\n" + + " B(Value param);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [27]\n" + + " 4 aload_0 [this]\n" + + " 5 ldc [29]\n" + + " 7 invokestatic A.foo(java.lang.String) : Value [15]\n" + + " 10 putfield B.local_field : Value [31]\n" + + " 13 getstatic I.CONST : Value [33]\n" + + " 16 pop\n" + + " 17 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 20]\n" + + " [pc: 4, line: 19]\n" + + " [pc: 13, line: 21]\n" + + " [pc: 17, line: 24]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 18] local: this index: 0 type: B\n" + + " [pc: 0, pc: 18] local: param index: 1 type: Value\n" + : " // Method descriptor #26 (LValue;)V\n" + + " // Stack: 2, Locals: 2\n" + + " B(Value param);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [27]\n" + + " 4 aload_0 [this]\n" + + " 5 ldc [29]\n" + + " 7 invokestatic A.foo(java.lang.String) : Value [15]\n" + + " 10 putfield B.local_field : Value [31]\n" + + " 13 getstatic B.CONST : Value [33]\n" + + " 16 pop\n" + + " 17 getstatic Value.NAME : java.lang.String [36]\n" + + " 20 pop\n" + + " 21 getstatic Value.NAME : java.lang.String [36]\n" + + " 24 pop\n" + + " 25 getstatic Value.NAME : java.lang.String [36]\n" + + " 28 pop\n" + + " 29 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 20]\n" + + " [pc: 4, line: 19]\n" + + " [pc: 13, line: 21]\n" + + " [pc: 21, line: 22]\n" + + " [pc: 25, line: 23]\n" + + " [pc: 29, line: 24]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 30] local: this index: 0 type: B\n" + + " [pc: 0, pc: 30] local: param index: 1 type: Value\n"; + + try { + File f = new File(OUTPUT_DIR + File.separator + "B.class"); + byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f); + ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler(); + String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.DETAILED); + int index = result.indexOf(expectedOutput); + if (index == -1 || expectedOutput.length() == 0) { + System.out.println(Util.displayString(result, 3)); + } + if (index == -1) { + assertEquals("Wrong contents", expectedOutput, result); + } + } catch (org.eclipse.jdt.core.util.ClassFormatException e) { + assertTrue(false); + } catch (IOException e) { + assertTrue(false); + } } public static Class testClass() { return InitializationTest.class;