This commit is contained in:
Jesper Wilhelmsson 2021-07-28 00:36:16 +00:00
commit a50161b750
14 changed files with 152 additions and 91 deletions

View File

@ -154,19 +154,19 @@ static void print_message(outputStream* output, oop content, TRAPS) {
}
static void log(oop content, TRAPS) {
LogMessage(jfr,startup) msg;
objArrayOop lines = objArrayOop(content);
assert(lines != NULL, "invariant");
assert(lines->is_array(), "must be array");
const int length = lines->length();
for (int i = 0; i < length; ++i) {
const char* text = JfrJavaSupport::c_str(lines->obj_at(i), THREAD);
if (text == NULL) {
// An oome has been thrown and is pending.
break;
}
msg.info("%s", text);
LogMessage(jfr,startup) msg;
objArrayOop lines = objArrayOop(content);
assert(lines != NULL, "invariant");
assert(lines->is_array(), "must be array");
const int length = lines->length();
for (int i = 0; i < length; ++i) {
const char* text = JfrJavaSupport::c_str(lines->obj_at(i), THREAD);
if (text == NULL) {
// An oome has been thrown and is pending.
break;
}
msg.info("%s", text);
}
}
static void handle_dcmd_result(outputStream* output,
@ -215,6 +215,8 @@ static oop construct_dcmd_instance(JfrJavaArguments* args, TRAPS) {
return args->result()->get_oop();
}
JfrDCmd::JfrDCmd(outputStream* output, bool heap, int num_arguments) : DCmd(output, heap), _args(NULL), _num_arguments(num_arguments), _delimiter('\0') {}
void JfrDCmd::invoke(JfrJavaArguments& method, TRAPS) const {
JavaValue constructor_result(T_OBJECT);
JfrJavaArguments constructor_args(&constructor_result);
@ -274,6 +276,20 @@ void JfrDCmd::print_help(const char* name) const {
handle_dcmd_result(output(), result.get_oop(), DCmd_Source_MBean, thread);
}
static void initialize_dummy_descriptors(GrowableArray<DCmdArgumentInfo*>* array) {
assert(array != NULL, "invariant");
DCmdArgumentInfo * const dummy = new DCmdArgumentInfo(NULL,
NULL,
NULL,
NULL,
false,
true, // a DcmdFramework "option"
false);
for (int i = 0; i < array->max_length(); ++i) {
array->append(dummy);
}
}
// Since the DcmdFramework does not support dynamically allocated strings,
// we keep them in a thread local arena. The arena is reset between invocations.
static THREAD_LOCAL Arena* dcmd_arena = NULL;
@ -340,16 +356,29 @@ static DCmdArgumentInfo* create_info(oop argument, TRAPS) {
GrowableArray<DCmdArgumentInfo*>* JfrDCmd::argument_info_array() const {
static const char signature[] = "()[Ljdk/jfr/internal/dcmd/Argument;";
JavaThread* thread = JavaThread::current();
GrowableArray<DCmdArgumentInfo*>* const array = new GrowableArray<DCmdArgumentInfo*>(_num_arguments);
JavaValue result(T_OBJECT);
JfrJavaArguments getArgumentInfos(&result, javaClass(), "getArgumentInfos", signature, thread);
invoke(getArgumentInfos, thread);
if (thread->has_pending_exception()) {
// Most likely an OOME, but the DCmdFramework is not the best place to handle it.
// We handle it locally by clearing the exception and returning an array with dummy descriptors.
// This lets the MBean server initialization routine complete successfully,
// but this particular command will have no argument descriptors exposed.
// Hence we postpone, or delegate, handling of OOME's to code that is better suited.
log_debug(jfr, system)("Exception in DCmd getArgumentInfos");
thread->clear_pending_exception();
initialize_dummy_descriptors(array);
assert(array->length() == _num_arguments, "invariant");
return array;
}
objArrayOop arguments = objArrayOop(result.get_oop());
assert(arguments != NULL, "invariant");
assert(arguments->is_array(), "must be array");
GrowableArray<DCmdArgumentInfo*>* const array = new GrowableArray<DCmdArgumentInfo*>();
const int length = arguments->length();
const int num_arguments = arguments->length();
assert(num_arguments == _num_arguments, "invariant");
prepare_dcmd_string_arena();
for (int i = 0; i < length; ++i) {
for (int i = 0; i < num_arguments; ++i) {
DCmdArgumentInfo* const dai = create_info(arguments->obj_at(i), thread);
assert(dai != NULL, "invariant");
array->append(dai);

View File

@ -31,23 +31,23 @@ class JfrJavaArguments;
class JfrDCmd : public DCmd {
private:
const char* _args;
const int _num_arguments;
char _delimiter;
protected:
JfrDCmd(outputStream* output, bool heap, int num_arguments);
virtual const char* javaClass() const = 0;
void invoke(JfrJavaArguments& method, TRAPS) const;
public:
JfrDCmd(outputStream* output, bool heap) : DCmd(output,heap), _args(NULL), _delimiter('\0') {}
virtual void execute(DCmdSource source, TRAPS);
virtual void print_help(const char* name) const;
virtual GrowableArray<const char*>* argument_name_array() const;
virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array() const;
virtual void parse(CmdLine* line, char delim, TRAPS);
protected:
virtual const char* javaClass() const = 0;
void invoke(JfrJavaArguments& method, TRAPS) const;
};
class JfrStartFlightRecordingDCmd : public JfrDCmd {
public:
JfrStartFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap) {}
JfrStartFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap, num_arguments()) {}
static const char* name() {
return "JFR.start";
@ -72,7 +72,7 @@ class JfrStartFlightRecordingDCmd : public JfrDCmd {
class JfrDumpFlightRecordingDCmd : public JfrDCmd {
public:
JfrDumpFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap) {}
JfrDumpFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap, num_arguments()) {}
static const char* name() {
return "JFR.dump";
@ -97,7 +97,7 @@ class JfrDumpFlightRecordingDCmd : public JfrDCmd {
class JfrCheckFlightRecordingDCmd : public JfrDCmd {
public:
JfrCheckFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap) {}
JfrCheckFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap, num_arguments()) {}
static const char* name() {
return "JFR.check";
@ -122,7 +122,7 @@ class JfrCheckFlightRecordingDCmd : public JfrDCmd {
class JfrStopFlightRecordingDCmd : public JfrDCmd {
public:
JfrStopFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap) {}
JfrStopFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap, num_arguments()) {}
static const char* name() {
return "JFR.stop";

View File

@ -335,7 +335,7 @@ public abstract class AbstractMemberWriter implements MemberSummaryWriter, Membe
: HtmlLinkInfo.Kind.MEMBER,
te, element, typeContent);
Content desc = new ContentBuilder();
writer.addSummaryLinkComment(this, element, desc);
writer.addSummaryLinkComment(element, desc);
useTable.addRow(summaryType, typeContent, desc);
}
contentTree.add(useTable);
@ -363,7 +363,7 @@ public abstract class AbstractMemberWriter implements MemberSummaryWriter, Membe
addSummaryLink(tElement, member, summaryLink);
rowContents.add(summaryLink);
Content desc = new ContentBuilder();
writer.addSummaryLinkComment(this, member, firstSentenceTrees, desc);
writer.addSummaryLinkComment(member, firstSentenceTrees, desc);
rowContents.add(desc);
table.addRow(member, rowContents);
}

View File

@ -1162,7 +1162,7 @@ public class HtmlDocletWriter {
public void addInlineComment(Element element, DocTree tag, Content htmltree) {
CommentHelper ch = utils.getCommentHelper(element);
List<? extends DocTree> description = ch.getDescription(tag);
addCommentTags(element, tag, description, false, false, false, htmltree);
addCommentTags(element, description, false, false, false, htmltree);
}
/**
@ -1249,22 +1249,6 @@ public class HtmlDocletWriter {
*/
private void addCommentTags(Element element, List<? extends DocTree> tags, boolean depr,
boolean first, boolean inSummary, Content htmltree) {
addCommentTags(element, null, tags, depr, first, inSummary, htmltree);
}
/**
* Adds the comment tags.
*
* @param element for which the comment tags will be generated
* @param holderTag the block tag context for the inline tags
* @param tags the first sentence tags for the doc
* @param depr true if it is deprecated
* @param first true if the first sentence tags should be added
* @param inSummary true if the comment tags are added into the summary section
* @param htmltree the documentation tree to which the comment tags will be added
*/
private void addCommentTags(Element element, DocTree holderTag, List<? extends DocTree> tags, boolean depr,
boolean first, boolean inSummary, Content htmltree) {
if (options.noComment()) {
return;
}

View File

@ -38,7 +38,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
@ -136,25 +135,22 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter {
/**
* Add the summary link for the member.
*
* @param mw the writer for the member being documented
* @param member the member to be documented
* @param contentTree the content tree to which the link will be added
*/
public void addSummaryLinkComment(AbstractMemberWriter mw, Element member, Content contentTree) {
public void addSummaryLinkComment(Element member, Content contentTree) {
List<? extends DocTree> tags = utils.getFirstSentenceTrees(member);
addSummaryLinkComment(mw, member, tags, contentTree);
addSummaryLinkComment(member, tags, contentTree);
}
/**
* Add the summary link comment.
*
* @param mw the writer for the member being documented
* @param member the member being documented
* @param firstSentenceTags the first sentence tags for the member to be documented
* @param tdSummary the content tree to which the comment will be added
*/
public void addSummaryLinkComment(AbstractMemberWriter mw,
Element member, List<? extends DocTree> firstSentenceTags, Content tdSummary) {
public void addSummaryLinkComment(Element member, List<? extends DocTree> firstSentenceTags, Content tdSummary) {
addIndexComment(member, firstSentenceTags, tdSummary);
}

View File

@ -97,7 +97,6 @@ public class InheritDocTaglet extends BaseTaglet {
if (!inheritedDoc.inlineTags.isEmpty()) {
replacement = writer.commentTagsToOutput(inheritedDoc.holder, inheritedDoc.holderTag,
inheritedDoc.inlineTags, isFirstSentence);
ch.setOverrideElement(inheritedDoc.holder);
}
} else {

View File

@ -206,9 +206,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
String lname = kind != ParamKind.TYPE_PARAMETER
? utils.getSimpleName(e)
: utils.getTypeName(e.asType(), false);
CommentHelper ch = utils.getCommentHelper(holder);
ch.setOverrideElement(inheritedDoc.holder);
Content content = processParamTag(holder, kind, writer,
Content content = processParamTag(inheritedDoc.holder, kind, writer,
(ParamTree) inheritedDoc.holderTag,
lname,
alreadyDocumented.isEmpty());

View File

@ -121,9 +121,7 @@ public class ReturnTaglet extends BaseTaglet implements InheritableTaglet {
Input input = new DocFinder.Input(utils, holder, this);
DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), input);
if (inheritedDoc.holderTag != null) {
CommentHelper ch = utils.getCommentHelper(input.element);
ch.setOverrideElement(inheritedDoc.holder);
return writer.returnTagOutput(holder, (ReturnTree) inheritedDoc.holderTag, false);
return writer.returnTagOutput(inheritedDoc.holder, (ReturnTree) inheritedDoc.holderTag, false);
}
return null;
}

View File

@ -165,26 +165,8 @@ public class CommentHelper {
}
return configuration.docEnv.getTypeUtils().asElement(symbol);
}
// case A: the element contains no comments associated and
// the comments need to be copied from ancestor
// case B: the element has @inheritDoc, then the ancestral comment
// as appropriate has to be copied over.
// Case A.
if (dcTree == null && overriddenElement != null) {
CommentHelper ovch = utils.getCommentHelper(overriddenElement);
return ovch.getElement(rtree);
}
if (dcTree == null) {
return null;
}
DocTreePath docTreePath = DocTreePath.getPath(path, dcTree, rtree);
DocTreePath docTreePath = getDocTreePath(rtree);
if (docTreePath == null) {
// Case B.
if (overriddenElement != null) {
CommentHelper ovch = utils.getCommentHelper(overriddenElement);
return ovch.getElement(rtree);
}
return null;
}
DocTrees doctrees = configuration.docEnv.getDocTrees();
@ -192,10 +174,7 @@ public class CommentHelper {
}
public TypeMirror getType(ReferenceTree rtree) {
// Workaround for JDK-8269706
if (path == null || dcTree == null || rtree == null)
return null;
DocTreePath docTreePath = DocTreePath.getPath(path, dcTree, rtree);
DocTreePath docTreePath = getDocTreePath(rtree);
if (docTreePath != null) {
DocTrees doctrees = configuration.docEnv.getDocTrees();
return doctrees.getType(docTreePath);
@ -700,9 +679,18 @@ public class CommentHelper {
}
public DocTreePath getDocTreePath(DocTree dtree) {
if (path == null || dcTree == null || dtree == null)
if (dcTree == null && overriddenElement != null) {
// This is an inherited comment, return path from ancestor.
return configuration.utils.getCommentHelper(overriddenElement).getDocTreePath(dtree);
} else if (path == null || dcTree == null || dtree == null) {
return null;
return DocTreePath.getPath(path, dcTree, dtree);
}
DocTreePath dtPath = DocTreePath.getPath(path, dcTree, dtree);
if (dtPath == null && overriddenElement != null) {
// The overriding element has a doc tree, but it doesn't contain what we're looking for.
return configuration.utils.getCommentHelper(overriddenElement).getDocTreePath(dtree);
}
return dtPath;
}
public Element getOverriddenElement() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2021, 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
@ -74,6 +74,7 @@ public class JsrRewriting {
className);
output = new OutputAnalyzer(pb.start());
output.shouldNotHaveExitValue(0);
String[] expectedMsgs = {
"java.lang.LinkageError",
"java.lang.NoSuchMethodError",

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2021, 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
@ -73,6 +73,7 @@ public class OomWhileParsingRepeatedJsr {
className );
output = new OutputAnalyzer(pb.start());
output.shouldNotHaveExitValue(0);
output.shouldContain("Cannot reserve enough memory");
}
}

View File

@ -74,7 +74,7 @@ public class TestAbortOnVMOperationTimeout {
if (shouldPass) {
output.shouldHaveExitValue(0);
} else {
output.shouldMatch("VM operation took too long");
output.shouldContain("VM operation took too long");
output.shouldNotHaveExitValue(0);
}
}

View File

@ -55,13 +55,13 @@ public class TestAbortVMOnSafepointTimeout {
);
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldMatch("Timed out while spinning to reach a safepoint.");
output.shouldContain("Timed out while spinning to reach a safepoint.");
if (Platform.isWindows()) {
output.shouldMatch("Safepoint sync time longer than");
output.shouldContain("Safepoint sync time longer than");
} else {
output.shouldMatch("SIGILL");
output.shouldContain("SIGILL");
if (Platform.isLinux()) {
output.shouldMatch("(sent by kill)");
output.shouldContain("(sent by kill)");
}
}
output.shouldNotHaveExitValue(0);

View File

@ -23,7 +23,7 @@
/*
* @test
* @bug 8269722
* @bug 8269722 8270866
* @summary NPE in HtmlDocletWriter, reporting errors on inherited tags
* @library /tools/lib ../../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@ -67,6 +67,14 @@ public class TestInherited extends JavadocTester {
"-Xdoclint:-missing", "-XDdoe",
src.resolve("BadParam.java").toString());
checkExit(Exit.OK);
checkOutput("BadParam.Base.html", true, """
<dt>Parameters:</dt>
<dd><code>i</code> - a &lt; b</dd>
""");
checkOutput("BadParam.Sub.html", true, """
<dt>Parameters:</dt>
<dd><code>i</code> - a &lt; b</dd>
""");
}
@Test
@ -91,5 +99,64 @@ public class TestInherited extends JavadocTester {
"-Xdoclint:-missing",
src.resolve("BadReturn.java").toString());
checkExit(Exit.OK);
checkOutput("BadReturn.Base.html", true, """
<dt>Returns:</dt>
<dd>a &lt; b</dd>
""");
checkOutput("BadReturn.Sub.html", true, """
<dt>Returns:</dt>
<dd>a &lt; b</dd>
""");
}
}
@Test
public void testBadInheritedReference(Path base) throws Exception {
Path src = base.resolve("src");
tb.writeJavaFiles(src, """
public class BadReference {
public interface Intf {
/**
* {@link NonExistingClass}
*/
public void m();
}
public static class Impl1 implements Intf {
public void m() { }
}
public static class Impl2 implements Intf {
/**
* {@inheritDoc}
*/
public void m() { }
}
// subclass has doc comment but inherits main description
public static class Impl3 implements Intf {
/**
* @since 1
*/
public void m() { }
}
}
""");
javadoc("-d", base.resolve("out").toString(),
"-Xdoclint:-reference",
src.resolve("BadReference.java").toString());
checkExit(Exit.OK);
checkOutput("BadReference.Intf.html", true, """
<div class="block"><code>NonExistingClass</code></div>
""");
checkOutput("BadReference.Impl1.html", true, """
<div class="block"><code>NonExistingClass</code></div>
""");
checkOutput("BadReference.Impl2.html", true, """
<div class="block"><code>NonExistingClass</code></div>
""");
checkOutput("BadReference.Impl3.html", true, """
<div class="block"><code>NonExistingClass</code></div>
""");
}
}