Skip to content

Commit

Permalink
Generate reference to classes holding constants used in the code
Browse files Browse the repository at this point in the history
fixes eclipse-jdt#1382

Emit a class constant into the constant pool for every class from which
a constant is used.
  • Loading branch information
stephan-herrmann committed Apr 13, 2024
1 parent 4874ebd commit 7c3e61b
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,17 @@ private void generateCode(
codeStream.recordPositionsFrom(0, declaringType.sourceStart);
classFile.completeCodeAttributeForClinit(codeAttributeOffset, classScope);
}
// the following block must happen after constantPool.resetForClinit()
if (TypeDeclaration.kind(declaringType.modifiers) != TypeDeclaration.ENUM_DECL
&& fieldDeclarations != null) {
int constantFlags = ClassFileConstants.AccStatic | ClassFileConstants.AccFinal;
for (FieldDeclaration fieldDecl : fieldDeclarations) {
if ((fieldDecl.modifiers & constantFlags) == constantFlags
&& fieldDecl.initialization instanceof NameReference nr) {
nr.emitDeclaringClassOfConstant(codeStream);
}
}
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2021 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -21,6 +21,8 @@

import java.util.function.Predicate;

import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.problem.AbortMethod;

Expand All @@ -41,6 +43,16 @@ public NameReference() {
this.bits |= Binding.TYPE | Binding.VARIABLE; // restrictiveFlag
}

/**
* Creates a constant pool entry which is not needed by the VM but might help tools.
* See https://bugs.openjdk.org/browse/JDK-7153958
*/
public void emitDeclaringClassOfConstant(CodeStream codeStream) {
if (this.constant != Constant.NotAConstant && this.binding instanceof FieldBinding f) {
codeStream.constantPool.literalIndex(f.declaringClass);
}
}

/**
* Use this method only when sure that the current reference is <strong>not</strong>
* a chain of several fields (QualifiedNameReference with more than one field).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ public void generateAssignment(BlockScope currentScope, CodeStream codeStream, A

@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
emitDeclaringClassOfConstant(codeStream);
int pc = codeStream.position;
if (this.constant != Constant.NotAConstant) {
if (valueRequired) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ public void generateAssignment(BlockScope currentScope, CodeStream codeStream, A

@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
emitDeclaringClassOfConstant(codeStream);
int pc = codeStream.position;
if (this.constant != Constant.NotAConstant) {
if (valueRequired) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2003, 2023 IBM Corporation and others.
* Copyright (c) 2003, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -1638,6 +1638,111 @@ public void testGH1256() throws Exception {
},
"2345");
}
public void testGH1382_singleName() throws Exception {
if (this.complianceLevel < ClassFileConstants.JDK1_5)
return;
this.runConformTest(
new String[] {
"api/Constants.java",
"""
package api;
public class Constants {
public static final boolean B = false;
public interface C1 {
int I = 1;
}
public interface C2 {
long L = 2l;
}
public interface C3 {
String S = "string";
}
}
""",
"X.java",
"""
import static api.Constants.B;
import static api.Constants.C1.I;
import static api.Constants.C2.L;
import static api.Constants.C3.S;
public class X {
static final String STRING = S;
void test() {
System.out.print(B);
System.out.print(I);
System.out.print(L);
}
}
""",
},
"");

File f = new File(OUTPUT_DIR + File.separator + "X.class");
byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f);
ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler();
String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.SYSTEM);
assertTrue(result.contains("Lapi/Constants;"));
assertTrue(result.contains("Lapi/Constants$C1;"));
assertTrue(result.contains("Lapi/Constants$C2;"));
assertTrue(result.contains("Lapi/Constants$C3;"));
}
public void testGH1382_qualifiedName() throws Exception {
if (this.complianceLevel < ClassFileConstants.JDK1_5)
return;
this.runConformTest(
new String[] {
"api/Constants.java",
"""
package api;
public class Constants {
public static final boolean B = false;
}
""",
"api/Constants1.java",
"""
package api;
public interface Constants1 {
int I = 1;
}
""",
"api/Constants2.java",
"""
package api;
public interface Constants2 {
long L = 2l;
}
""",
"api/Constants3.java",
"""
package api;
public interface Constants3 {
String S = "string";
}
""",
"X.java",
"""
public class X {
static final boolean BOOL = api.Constants.B;
void test() {
System.out.print(api.Constants1.I);
System.out.print(api.Constants2.L);
System.out.print(api.Constants3.S);
}
}
""",
},
"");

File f = new File(OUTPUT_DIR + File.separator + "X.class");
byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f);
ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler();
String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.SYSTEM);
assertTrue(result.contains("Lapi/Constants;"));
assertTrue(result.contains("Lapi/Constants1;"));
assertTrue(result.contains("Lapi/Constants2;"));
assertTrue(result.contains("Lapi/Constants3;"));
}

public static Class testClass() {
return ConstantTest.class;
}
Expand Down

0 comments on commit 7c3e61b

Please sign in to comment.