This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.
Created attachment 162102 [details] JMH perf test for type.isAssignableFrom() I'm opening in HTML editor a file, which is not a real HTML, but rather an HTML template with some special syntax like this: {#rgn "region-name" hidden=true} <div class="className"> <div class="className">${title}<div class="className"> <i class="className" onclick=${@item_onClick}/> </div> </div> ... </div> {/rgn} Note: 'onclick' attribute is not enclosed into quotes - this is intended because it should be evaluated as a function reference at run-time, not a string. HTML editor goes crazy with many of such elements on the page - it looks like it thinks that 'i' tag is not closed - and therefore consecutive elements are treated as children rather than siblings. On one of such pages Netbeans completely freezes for around 3-4 minutes and becomes completely unresponsive - here is lengthy call stack for this "Editor Parsing Loop" at org.netbeans.modules.html.parser.ElementsFactory$VirtualOpenTag.children(ElementsFactory.java:793) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:183) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:187) at org.netbeans.modules.html.editor.lib.api.elements.ElementUtils.findBySemanticRange(ElementUtils.java:193) at org.netbeans.modules.html.editor.api.gsf.HtmlParserResult.findBySemanticRange(HtmlParserResult.java:215) at org.netbeans.modules.css.visual.HtmlEditorSourceTask.setActiveElement(HtmlEditorSourceTask.java:152) at org.netbeans.modules.css.visual.HtmlEditorSourceTask.run(HtmlEditorSourceTask.java:121) at org.netbeans.modules.css.visual.HtmlEditorSourceTask.run(HtmlEditorSourceTask.java:72) at org.netbeans.modules.parsing.impl.TaskProcessor.callParserResultTask(TaskProcessor.java:584) at org.netbeans.modules.parsing.impl.TaskProcessor$RequestPerformer.run(TaskProcessor.java:809) at org.openide.util.lookup.Lookups.executeWith(Lookups.java:304) at org.netbeans.modules.parsing.impl.TaskProcessor$RequestPerformer.execute(TaskProcessor.java:725) at org.netbeans.modules.parsing.impl.TaskProcessor$CompilationJob.run(TaskProcessor.java:686) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:1443) at org.netbeans.modules.openide.util.GlobalLookup.execute(GlobalLookup.java:68) at org.openide.util.lookup.Lookups.executeWith(Lookups.java:303) at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:2058) Few things with this issue: 1. Is it possible to make Netbeans understand non-quoted attribute values? I think that will fix the root cause. <i class="className" onclick=${@item_onClick}/> 2. I tried digging into findBySemanticRange(), but it seems to be beyond my understanding. Probably it has sense to limit recursion to something around 10 levels - valid HTML typically does not have larger level of 'indentation', or add some self-guarding against overall time of the gsf.HtmlParserResult.findBySemanticRange() 3. Self profiler says that in this whole lookup 99% of time is spent in package org.netbeans.modules.html.parser; public class ElementsFactory { static class VirtualOpenTag implements OpenTag, ModifiableOpenTag { @Override public <T extends Element> Collection<T> children(Class<T> type) Nevertheless that particular problem cannot be fixed in that only method, but I see few things which can significantly improve performance (let's say 10 times) of findBySemanticRange() in general. 3.1) Class.isAssignableFrom() is rather slow and better be replaced by functionally equivalent for this use-case Class.isInstance(), which is roughly 20 times faster (JVM specific feature?) package org.netbeans.modules.html.parser; public class ElementsFactory { static class VirtualOpenTag implements OpenTag, ModifiableOpenTag { @Override public <T extends Element> Collection<T> children(Class<T> type) { Collection<T> filtered = new ArrayList<T>(); for (Element child : children()) { if (type.isInstance(child)) { --> // if (type.isAssignableFrom(child.getClass())) { <-- filtered.add(type.cast(child)); } } return filtered; } I've attached a JMH benchmark as a prooflink, the summary is (Per 1 mln of iterations) Benchmark Mode Cnt Score Error Units Casting.cast_isAssignableFrom avgt 5 0.044 ? 0.002 s/op Casting.cast_isInstance avgt 5 0.002 ? 0.001 s/op 2. empty instance of array list is created per each iteration, even when there is no matching results. Assuming that method in that particular 'bad' environment is invoked many thousands of times - many thousands of unneeded empty ArrayLists are created and put extra pressure on GC. It is better to rewrite it as following: @Override public <T extends Element> Collection<T> children(Class<T> type) { Collection<T> filtered = null; for (Element child : children()) { if (type.isInstance(child)) { if( filtered == null ) filtered = new ArrayList<T>(); filtered.add(type.cast(child)); } } return (filtered != null) ? filtered : Collections.<T>emptyList(); }
It looks like dirty safe-guard hack like following fixes the issue: public static Node findBySemanticRange(Node node, int offset, boolean forward) { int depth = 0; for( Node parent = node.parent(); parent != null; parent = parent.parent(), depth++ ) { if( depth > 10 ) return node; } for (OpenTag child : node.children(OpenTag.class)) { However root cause is wrong custom file mapping configured in my environment - it should be xxx->XHTML (which supports and requires self-closing tags), not just HTML. Unquoted attributes like 'onclick=${@item_onClick}/>' do not cause problems. After applying both changes I do not experience performance problems.