You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2017/02/20 06:27:40 UTC

groovy git commit: GROOVY-8091: Add a ASMifier tab to AstBrowser

Repository: groovy
Updated Branches:
  refs/heads/master c79ef79f8 -> 6120cedb5


GROOVY-8091: Add a ASMifier tab to AstBrowser


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/6120cedb
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/6120cedb
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/6120cedb

Branch: refs/heads/master
Commit: 6120cedb5e24aa54b06fdb0ff880ba24018d3525
Parents: c79ef79
Author: sunlan <su...@apache.org>
Authored: Mon Feb 20 14:27:26 2017 +0800
Committer: sunlan <su...@apache.org>
Committed: Mon Feb 20 14:27:26 2017 +0800

----------------------------------------------------------------------
 gradle/assemble.gradle                          |  2 +-
 .../groovy/inspect/swingui/AstBrowser.groovy    | 79 +++++++++++++-------
 2 files changed, 52 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/6120cedb/gradle/assemble.gradle
----------------------------------------------------------------------
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index 050a9ec..f83e2e6 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -191,7 +191,7 @@ allprojects {
                         }
 
                         zipfileset(src: configurations.runtime.files.find { file -> file.name.startsWith('asm-util') },
-                                includes: 'org/objectweb/asm/util/Printer.class,org/objectweb/asm/util/Textifier.class,org/objectweb/asm/util/Trace*')
+                                includes: 'org/objectweb/asm/util/Printer.class,org/objectweb/asm/util/Textifier.class,org/objectweb/asm/util/ASMifier.class,org/objectweb/asm/util/Trace*')
                     }
                     rule pattern: 'antlr.**', result: 'groovyjarjarantlr.@1'
                     rule pattern: 'org.objectweb.**', result: 'groovyjarjarasm.@1'

http://git-wip-us.apache.org/repos/asf/groovy/blob/6120cedb/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/AstBrowser.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/AstBrowser.groovy b/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/AstBrowser.groovy
index 55d7647..5e7ee1b 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/AstBrowser.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/AstBrowser.groovy
@@ -25,6 +25,7 @@ import org.codehaus.groovy.control.CompilationUnit
 import org.codehaus.groovy.control.Phases
 import org.codehaus.groovy.control.SourceUnit
 import org.objectweb.asm.ClassReader
+import org.objectweb.asm.util.ASMifier
 import org.objectweb.asm.util.TraceClassVisitor
 
 import javax.swing.Action
@@ -62,8 +63,9 @@ import static java.awt.GridBagConstraints.WEST
 class AstBrowser {
 
     private static final String BYTECODE_MSG_SELECT_NODE = '// Please select a class node in the tree view.'
+    private static final String NO_BYTECODE_AVAILABLE_AT_THIS_PHASE = '// No bytecode available at this phase'
 
-    private inputArea, rootElement, decompiledSource, jTree, propertyTable, splitterPane, mainSplitter, bytecodeView
+    private inputArea, rootElement, decompiledSource, jTree, propertyTable, splitterPane, mainSplitter, bytecodeView, asmifierView
     boolean showScriptFreeForm, showScriptClass, showClosureClasses, showTreeView, showIndyBytecode
     GeneratedBytecodeAwareGroovyClassLoader classLoader
     def prefs = new AstBrowserUiPreferences()
@@ -161,6 +163,7 @@ class AstBrowser {
                         actionPerformed: {
                             // reset text to the default as the phase change removes the focus from the class node
                             bytecodeView.textEditor.text = BYTECODE_MSG_SELECT_NODE
+                            asmifierView.textEditor.text = BYTECODE_MSG_SELECT_NODE
 
                             decompile(phasePicker.selectedItem.phaseId, script())
                             compile(jTree, script(), phasePicker.selectedItem.phaseId)
@@ -195,6 +198,7 @@ class AstBrowser {
                         bottomComponent: tabbedPane {
                             widget(decompiledSource = new groovy.ui.ConsoleTextEditor(editable: false, showLineNumbers: false), title:'Source')
                             widget(bytecodeView = new groovy.ui.ConsoleTextEditor(editable: false, showLineNumbers: false), title:getByteCodeTitle())
+                            widget(asmifierView = new groovy.ui.ConsoleTextEditor(editable: false, showLineNumbers: false), title:getASMifierTitle())
                         },
                         constraints: gbc(gridx: 0, gridy: 2, gridwidth: 3, gridheight: 1, weightx: 1.0, weighty: 1.0, anchor: NORTHWEST, fill: BOTH, insets: [2, 2, 2, 2])) { }
 
@@ -202,6 +206,7 @@ class AstBrowser {
         }
 
         bytecodeView.textEditor.text = BYTECODE_MSG_SELECT_NODE
+        asmifierView.textEditor.text = BYTECODE_MSG_SELECT_NODE
 
         propertyTable.model.rows.clear() //for some reason this suppress an empty row
 
@@ -274,43 +279,33 @@ class AstBrowser {
 
                 if (node.classNode || node.methodNode) {
                     bytecodeView.textEditor.text = '// Loading bytecode ...'
+                    asmifierView.textEditor.text = '// Loading ASMifier\'s output ...'
                     boolean showOnlyMethodCode = node.methodNode
 
                     swing.doOutside {
                         def className = showOnlyMethodCode ? node.getPropertyValue('declaringClass') : node.getPropertyValue('name')
                         def bytecode = classLoader.getBytecode(className)
                         if (bytecode) {
-                            def writer = new StringWriter()
-                            def visitor = new TraceClassVisitor(new PrintWriter(writer))
-                            def reader = new ClassReader(bytecode)
-                            reader.accept(visitor, 0)
+                            def methodName = node.getPropertyValue('name')
+                            def methodDescriptor = node.getPropertyValue('descriptor')
+                            boolean isMethodNameAndMethodDescriptorAvailable = methodName && methodDescriptor
 
-                            def source = writer.toString()
-                            swing.doLater {
-                                bytecodeView.textEditor.text = source
-
-                                if (showOnlyMethodCode)  {
-                                    def methodName = node.getPropertyValue('name')
-                                    def methodDescriptor = node.getPropertyValue('descriptor')
-
-                                    if (methodName && methodDescriptor)  {
-                                        def pattern = Pattern.compile("^.*\\n.*${Pattern.quote(methodName + methodDescriptor)}[\\s\\S]*?\\n[}|\\n]", Pattern.MULTILINE)
-                                        def matcher = pattern.matcher(source)
-                                        if (matcher.find())  {
-                                            bytecodeView.textEditor.text = source.substring(matcher.start(0), matcher.end(0))
-                                        }
-                                    }
-                                }
+                            String bytecodeSource = generateSource(bytecode, {writer -> new TraceClassVisitor(new PrintWriter(writer))})
+                            showSource(bytecodeView, bytecodeSource, showOnlyMethodCode, isMethodNameAndMethodDescriptorAvailable, {"^.*\\n.*${Pattern.quote(methodName + methodDescriptor)}[\\s\\S]*?\\n[}|\\n]"})
 
-                                bytecodeView.textEditor.caretPosition = 0
-                            }
+                            String asmifierSource = generateSource(bytecode, {writer -> new TraceClassVisitor(null, new ASMifier(), new PrintWriter(writer))})
+                            showSource(asmifierView, asmifierSource, showOnlyMethodCode, isMethodNameAndMethodDescriptorAvailable, {"^.*\\n.*${Pattern.quote(methodName)}.*?${Pattern.quote(methodDescriptor)}[\\s\\S]*?\\n[}|\\n]"})
                         } else {
-                            swing.doLater { bytecodeView.textEditor.text = '// No bytecode available at this phase' }
+                            swing.doLater {
+                                bytecodeView.textEditor.text = NO_BYTECODE_AVAILABLE_AT_THIS_PHASE
+                                asmifierView.textEditor.text = NO_BYTECODE_AVAILABLE_AT_THIS_PHASE
+                            }
                         }
                     }
 
                 } else {
                     bytecodeView.textEditor.text = ''
+                    asmifierView.textEditor.text = ''
                 }
             }
             propertyTable.model.fireTableDataChanged()
@@ -333,6 +328,27 @@ class AstBrowser {
 
     }
 
+    private String generateSource(byte[] bytecode, getVisitor) {
+        def sw = new StringWriter()
+        new ClassReader(bytecode).accept(getVisitor(sw), 0)
+        return sw.toString()
+    }
+
+    private void showSource(view, String source, boolean showOnlyMethodCode, boolean isMethodNameAndMethodDescriptorAvailable, getPatternStr) {
+        swing.doLater {
+            view.textEditor.text = source
+            if (showOnlyMethodCode && isMethodNameAndMethodDescriptorAvailable) {
+                def pattern = Pattern.compile(getPatternStr(), Pattern.MULTILINE)
+                def matcher = pattern.matcher(source)
+                if (matcher.find()) {
+                    view.textEditor.text = source.substring(matcher.start(0), matcher.end(0))
+                }
+            }
+
+            view.textEditor.caretPosition = 0
+        }
+    }
+
     void largerFont(EventObject evt = null) {
         updateFontSize(decompiledSource.textEditor.font.size + 2)
     }
@@ -395,17 +411,20 @@ class AstBrowser {
     void showIndyBytecode(EventObject evt = null) {
         showIndyBytecode = evt.source.selected
         bytecodeView.textEditor.text = BYTECODE_MSG_SELECT_NODE
+        asmifierView.textEditor.text = BYTECODE_MSG_SELECT_NODE
         refreshAction.actionPerformed(null)
-        updateByteCodeTabTitle()
+        updateTabTitles()
     }
 
-    private void updateByteCodeTabTitle() {
+    private void updateTabTitles() {
         def tabPane = mainSplitter.bottomComponent
         int tabCount = tabPane.getTabCount()
         for (int i = 0; i < tabCount; i++) {
-            if (bytecodeView.is(tabPane.getComponentAt(i))) {
+            def component = tabPane.getComponentAt(i);
+            if (bytecodeView.is(component)) {
                 tabPane.setTitleAt(i, getByteCodeTitle())
-                break
+            } else if (asmifierView.is(component)) {
+                tabPane.setTitleAt(i, getASMifierTitle())
             }
         }
     }
@@ -414,6 +433,10 @@ class AstBrowser {
         'Bytecode' + (showIndyBytecode ? ' (Indy)' : '')
     }
 
+    private String getASMifierTitle() {
+        'ASMifier' + (showIndyBytecode ? ' (Indy)' : '')
+    }
+
     void decompile(phaseId, source) {
 
         decompiledSource.textEditor.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))