New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8298065: Provide more information in message of NoSuchFieldError #11745
Changes from 9 commits
12f46c4
5020595
f493579
0edddcf
6e037c8
3e8e923
b42ab12
7b7d6e6
59fad0b
7cdbd18
aa49b34
b89909c
3c07b81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/* | ||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. | ||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. | ||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
* | ||
* This code is free software; you can redistribute it and/or modify it | ||
|
@@ -275,6 +275,7 @@ class Symbol : public MetaspaceObj { | |
// separated by ', ' to the outputStream. Prints external names as | ||
// 'double' or 'java.lang.Object[][]'. | ||
void print_as_signature_external_parameters(outputStream *os); | ||
void print_signature_as_external_field_type(outputStream *os); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think Matias's version is more grammatically correct. Maybe we should rename the two existing functions
to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are methods on VMSymbol that print the VMSymbol as a signature, so the naming is correct. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry I am a bit obsessed with names. The two existing methods are used only for method signatures. They each print a portion of the signature. For example, when given a signature like "(ZI)J":
Matias's new function is used only for field signatures. David's suggestion of "print_as_signature_external_field_type" is not consistent with the existing names (which do not say "method"). While "print_as_signature_external_parameters()" can be read as "print the parameters of a (method) signature in external format", I think it's clumsy and incomplete. How about:
I think the word "external" is confusing and can be skipped. For method signatures, we don't need methods that just print the parameters in their internal format (i.e., Also, the first two methods should assert There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also get somewhat obsessed with names :) We are dealing with a VMSymbol which is really just a character string that could represent many things. One of those things is a method signature. So The issue with the new method is that fields don't have signatures** in the general sense that methods do. A field just has a name and a type. So to me the correct naming here would be ** In the VM the classfile Signature attribute does exist for a FieldInfo but it is only used for fields declared with type variables or parameterized types. Within the VM all fields have their erased type. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I still think the asserts for Signature::is_method should be added to these 3 functions. |
||
|
||
void metaspace_pointers_do(MetaspaceClosure* it); | ||
MetaspaceObj::Type type() const { return SymbolType; } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/* | ||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. | ||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
* | ||
* This code is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. | ||
* | ||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
*/ | ||
|
||
/* | ||
public class NoSuchFieldArray { | ||
static char[] z; | ||
public NoSuchFieldArray() { | ||
z = new char[1]; | ||
} | ||
} | ||
*/ | ||
|
||
super public class NoSuchFieldArray | ||
version 65:0 | ||
{ | ||
// REMOVED static Field z:"[C"; | ||
|
||
public Method "<init>":"()V" | ||
stack 1 locals 1 | ||
{ | ||
aload_0; | ||
invokespecial Method java/lang/Object."<init>":"()V"; | ||
iconst_1; | ||
newarray char; | ||
putstatic Field z:"[C"; | ||
return; | ||
} | ||
|
||
} // end Class NoSuchFieldArray |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. | ||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
* | ||
* This code is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. | ||
* | ||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
*/ | ||
|
||
/* | ||
public class NoSuchFieldMultiArray { | ||
static double[][] a; | ||
public NoSuchFieldMultiArray() { | ||
a = new double[1][1]; | ||
} | ||
} | ||
*/ | ||
|
||
super public class NoSuchFieldMultiArray | ||
version 65:0 | ||
{ | ||
// REMOVED static Field a:"[[D"; | ||
|
||
public Method "<init>":"()V" | ||
stack 2 locals 1 | ||
{ | ||
aload_0; | ||
invokespecial Method java/lang/Object."<init>":"()V"; | ||
iconst_1; | ||
iconst_1; | ||
multianewarray class "[[D", 2; | ||
putstatic Field a:"[[D"; | ||
return; | ||
} | ||
|
||
} // end Class NoSuchFieldMultiArray |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,108 @@ | ||||||
/* | ||||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. | ||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||||||
* | ||||||
* This code is free software; you can redistribute it and/or modify it | ||||||
* under the terms of the GNU General Public License version 2 only, as | ||||||
* published by the Free Software Foundation. | ||||||
* | ||||||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||||||
* version 2 for more details (a copy is included in the LICENSE file that | ||||||
* accompanied this code). | ||||||
* | ||||||
* You should have received a copy of the GNU General Public License version | ||||||
* 2 along with this work; if not, write to the Free Software Foundation, | ||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||
* | ||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||||||
* or visit www.oracle.com if you need additional information or have any | ||||||
* questions. | ||||||
*/ | ||||||
|
||||||
/* | ||||||
* @test | ||||||
* @bug 8298065 | ||||||
* @summary Test output of NoSuchFieldError when field signature does not match | ||||||
* @compile NoSuchFieldPrimitive.jasm NoSuchFieldReference.jasm | ||||||
* @compile NoSuchFieldArray.jasm NoSuchFieldMultiArray.jasm | ||||||
* @run main NoSuchFieldOutputTest | ||||||
*/ | ||||||
|
||||||
import java.util.regex.Matcher; | ||||||
import java.util.regex.Pattern; | ||||||
|
||||||
// Tests the output text of NoSuchFieldError | ||||||
public class NoSuchFieldOutputTest { | ||||||
|
||||||
public static void main(java.lang.String[] unused) throws Exception { | ||||||
try { | ||||||
Class.forName("NoSuchFieldPrimitive").newInstance(); | ||||||
} catch (NoSuchFieldError nsfe) { | ||||||
testNoSuchFieldOutput(nsfe, "primitive"); | ||||||
} | ||||||
try { | ||||||
Class.forName("NoSuchFieldReference").newInstance(); | ||||||
} catch (NoSuchFieldError nsfe) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could put each field access in a try block and remove all the fields in the second jasm file, so you can test for all the messages specifically. Although the pattern compiler is cool. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Compiling each jasm file after the main file, IS the easiest way to run it outside jtreg. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we have very simple conditions to test, so there's no need for NoSuchFieldOutputTest.java to access FieldName.java at all. That's why I propose that all the error conditions should be implemented inside the jasm files alone. NoSuchFieldOutputTest.java can just refer to the error class by name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay so rather than generate the NSFE by separate compilation, Ioi is suggesting the jasm code can reference a non-existent field directly and so throw NSFE. That works too and the test can be re-run stand-alone. |
||||||
testNoSuchFieldOutput(nsfe, "reference"); | ||||||
} | ||||||
try { | ||||||
Class.forName("NoSuchFieldArray").newInstance(); | ||||||
} catch (NoSuchFieldError nsfe) { | ||||||
testNoSuchFieldOutput(nsfe, "array"); | ||||||
} | ||||||
try { | ||||||
Class.forName("NoSuchFieldMultiArray").newInstance(); | ||||||
} catch (NoSuchFieldError nsfe) { | ||||||
testNoSuchFieldOutput(nsfe, "multiArray"); | ||||||
} | ||||||
} | ||||||
|
||||||
private static void testNoSuchFieldOutput(NoSuchFieldError nsfe, String testType) throws Exception { | ||||||
Pattern noSuchFieldPattern = Pattern.compile("Class (?<classname>[\\w\\d]+) does not have member field '(?<signature>[\\S]+) (?<varname>[\\w\\d]+)'"); | ||||||
String output = nsfe.getMessage(); | ||||||
Matcher noSuchFieldMatcher = noSuchFieldPattern.matcher(output); | ||||||
if (noSuchFieldMatcher.matches()) { | ||||||
switch(testType) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
case "primitive": | ||||||
checkOutputGroups(noSuchFieldMatcher, output, "NoSuchFieldPrimitive", "int", "x"); | ||||||
break; | ||||||
case "reference": | ||||||
checkOutputGroups(noSuchFieldMatcher, output, "NoSuchFieldReference", "TestClass", "y"); | ||||||
break; | ||||||
case "array": | ||||||
checkOutputGroups(noSuchFieldMatcher, output, "NoSuchFieldArray", "char[]", "z"); | ||||||
break; | ||||||
case "multiArray": | ||||||
checkOutputGroups(noSuchFieldMatcher, output, "NoSuchFieldMultiArray", "double[][]", "a"); | ||||||
break; | ||||||
default: | ||||||
throwTestException("No matching test", output); | ||||||
} | ||||||
} else { | ||||||
throwTestException("Output format does not match", output); | ||||||
} | ||||||
System.out.println(output); | ||||||
} | ||||||
|
||||||
private static void checkOutputGroups(Matcher noSuchFieldMatcher, String output, | ||||||
String testClass, String testSig, String testVar) throws Exception { | ||||||
String classname = noSuchFieldMatcher.group("classname"); | ||||||
String signature = noSuchFieldMatcher.group("signature"); | ||||||
String varname = noSuchFieldMatcher.group("varname"); | ||||||
if (!classname.equals(testClass)) { | ||||||
throwTestException("Failed to match class name", output); | ||||||
} | ||||||
if (!signature.equals(testSig)) { | ||||||
throwTestException("Failed to match type signature", output); | ||||||
} | ||||||
if (!varname.equals(testVar)) { | ||||||
throwTestException("Failed to match field name", output); | ||||||
} | ||||||
} | ||||||
|
||||||
private static void throwTestException(String reason, String output) throws Exception { | ||||||
throw new Exception(reason + " . Stdout is :\n" + output); | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. | ||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
* | ||
* This code is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. | ||
* | ||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
*/ | ||
|
||
/* | ||
public class NoSuchFieldPrimitive { | ||
// static int x; | ||
public NoSuchFieldPrimitive() { | ||
x = 123; | ||
} | ||
} | ||
*/ | ||
|
||
super public class NoSuchFieldPrimitive | ||
version 65:0 | ||
{ | ||
// REMOVED static Field x:I; | ||
|
||
public Method "<init>":"()V" | ||
stack 1 locals 1 | ||
{ | ||
aload_0; | ||
invokespecial Method java/lang/Object."<init>":"()V"; | ||
bipush 123; | ||
putstatic Field x:"I"; | ||
return; | ||
} | ||
|
||
} // end Class NoSuchFieldPrimitive | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These jasm test cases are too complicated and contain a lot of details unrelated to what you're testing. They should be simplified as:
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. | ||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
* | ||
* This code is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. | ||
* | ||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
*/ | ||
|
||
/* | ||
public class NoSuchFieldReference { | ||
static TestClass y; | ||
public NoSuchFieldReference() { | ||
y = new TestClass(); | ||
} | ||
} | ||
*/ | ||
|
||
super public class NoSuchFieldReference | ||
version 65:0 | ||
{ | ||
// REMOVED static Field y:"LTestClass;"; | ||
|
||
public Method "<init>":"()V" | ||
stack 2 locals 1 | ||
{ | ||
aload_0; | ||
invokespecial Method java/lang/Object."<init>":"()V"; | ||
new class TestClass; | ||
dup; | ||
invokespecial Method TestClass."<init>":"()V"; | ||
putstatic Field y:"LTestClass;"; | ||
return; | ||
} | ||
|
||
} // end Class NoSuchFieldReference |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SignatureStream for field refs should have exactly one element, and must not be a return type, so this function should be tightened (so it will assert on inputs such as
(I)V
or()L/java/lang.Object;
,