JavaDecompiler.st
author Claus Gittinger <cg@exept.de>
Sun, 23 Feb 2020 14:03:15 +0100
branchcvs_MAIN
changeset 3997 5bb44f7e1d20
parent 3687 d76245c8ee37
child 3998 183ab41fbdbd
permissions -rw-r--r--
#REFACTORING by exept class: Java class changed: #dumpConfigOn:

"
 COPYRIGHT (c) 1996-2015 by Claus Gittinger

 New code and modifications done at SWING Research Group [1]:

 COPYRIGHT (c) 2010-2015 by Jan Vrany, Jan Kurs and Marcel Hlopko
                            SWING Research Group, Czech Technical University in Prague

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.

 [1] Code written at SWING Research Group contains a signature
     of one of the above copright owners. For exact set of such code,
     see the differences between this version and version stx:libjava
     as of 1.9.2010
"
"{ Package: 'stx:libjava' }"

"{ NameSpace: Smalltalk }"

Object subclass:#JavaDecompiler
	instanceVariableNames:'code pc javaMethod outStream classToCompileFor isStaticMethod
		lastConstIndex lastConstant accessedInstvars modifiedInstvars
		accessedStaticVars modifiedStaticVars sentMessages'
	classVariableNames:'DecoderTable'
	poolDictionaries:''
	category:'Languages-Java-Support-Decompiling'
!

!JavaDecompiler class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1996-2015 by Claus Gittinger

 New code and modifications done at SWING Research Group [1]:

 COPYRIGHT (c) 2010-2015 by Jan Vrany, Jan Kurs and Marcel Hlopko
                            SWING Research Group, Czech Technical University in Prague

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.

 [1] Code written at SWING Research Group contains a signature
     of one of the above copright owners. For exact set of such code,
     see the differences between this version and version stx:libjava
     as of 1.9.2010

"
!

examples
"

                                                                        [exBegin]
    |m|

    m := JAVA::java::lang::Object compiledMethodAt:#'toString()Ljava/lang/String;'.
    JavaDecompiler decompile:m to:Transcript.
                                                                        [exEnd]



                                                                        [exBegin]
    |m|

    m := JAVA::java::lang::Object compiledMethodAt:#'toString()Ljava/lang/String;'.
    JavaDecompiler decompile:m to:nil.
                                                                        [exEnd]

"

! !

!JavaDecompiler class methodsFor:'initialization'!

initialize
    DecoderTable := #(
        (nop)                                   "/ 0
        (aconst_null)                           "/ 1
        (iconst_m1)                             "/ 2
        (iconst_0)                              "/ 3
        (iconst_1)                              "/ 4
        (iconst_2)                              "/ 5
        (iconst_3)                              "/ 6
        (iconst_4)                              "/ 7
        (iconst_5)                              "/ 8
        (lconst_0)                              "/ 9
        
        (lconst_1)                              "/ 10
        (fconst_0)                              "/ 11
        (fconst_1)                              "/ 12
        (fconst_2)                              "/ 13
        (dconst_0)                              "/ 14
        (dconst_1)                              "/ 15
        (bipush signedByte)                     "/ 16
        (sipush signedShort)                    "/ 17
        (ldc1 constIndexByte remember_ldc1)              "/ 18
        (ldc2 constIndexShort remember_ldc2)             "/ 19

        (ldc2w constIndexShort remember_ldc2w)            "/ 20
        (iload localIndexByte)                  "/ 21
        (lload localIndexByte)                  "/ 22
        (fload localIndexByte)                  "/ 23
        (dload localIndexByte)                  "/ 24
        (aload localIndexByte)                  "/ 25
        (iload_0)                               "/ 26
        (iload_1)                               "/ 27
        (iload_2)                               "/ 28
        (iload_3)                               "/ 29

        (lload_0)                               "/ 30
        (lload_1)                               "/ 31
        (lload_2)                               "/ 32
        (lload_3)                               "/ 33
        (fload_0)                               "/ 34
        (fload_1)                               "/ 35
        (fload_2)                               "/ 36
        (fload_3)                               "/ 37
        (dload_0)                               "/ 38
        (dload_1)                               "/ 39

        (dload_2)                               "/ 40
        (dload_3)                               "/ 41
        (aload_0)                               "/ 42
        (aload_1)                               "/ 43
        (aload_2)                               "/ 44
        (aload_3)                               "/ 45
        (iaload)                                "/ 46
        (laload)                                "/ 47
        (faload)                                "/ 48
        (daload)                                "/ 49

        (aaload)                                "/ 50
        (baload)                                "/ 51
        (caload)                                "/ 52
        (saload)                                "/ 53
        (istore localIndexByte)                 "/ 54
        (lstore localIndexByte)                 "/ 55
        (fstore localIndexByte)                 "/ 56
        (dstore localIndexByte)                 "/ 57
        (astore localIndexByte)                 "/ 58
        (istore_0)                              "/ 59

        (istore_1)                              "/ 60
        (istore_2)                              "/ 61
        (istore_3)                              "/ 62
        (lstore_0)                              "/ 63
        (lstore_1)                              "/ 64
        (lstore_2)                              "/ 65
        (lstore_3)                              "/ 66
        (fstore_0)                              "/ 67
        (fstore_1)                              "/ 68
        (fstore_2)                              "/ 69

        (fstore_3)                              "/ 70
        (dstore_0)                              "/ 71
        (dstore_1)                              "/ 72
        (dstore_2)                              "/ 73
        (dstore_3)                              "/ 74
        (astore_0)                              "/ 75
        (astore_1)                              "/ 76
        (astore_2)                              "/ 77
        (astore_3)                              "/ 78
        (iastore)                               "/ 79

        (lastore)                               "/ 80
        (fastore)                               "/ 81
        (dastore)                               "/ 82
        (aastore)                               "/ 83
        (bastore)                               "/ 84
        (castore)                               "/ 85
        (sastore)                               "/ 86
        (pop)                                   "/ 87
        (pop2)                                  "/ 88
        (dup)                                   "/ 89

        (dup_x1)                                "/ 90
        (dup_x2)                                "/ 91
        (dup2)                                  "/ 92
        (dup2_x1)                               "/ 93
        (dup2_x2)                               "/ 94
        (swap)                                  "/ 95
        (iadd)                                  "/ 96
        (ladd)                                  "/ 97
        (fadd)                                  "/ 98
        (dadd)                                  "/ 99

        (isub)                                  "/ 100
        (lsub)                                  "/ 101
        (fsub)                                  "/ 102
        (dsub)                                  "/ 103
        (imul)                                  "/ 104
        (lmul)                                  "/ 105
        (fmul)                                  "/ 106
        (dmul)                                  "/ 107
        (idiv)                                  "/ 108
        (ldiv)                                  "/ 109

        (fdiv)                                  "/ 110
        (ddiv)                                  "/ 111
"/        (imod)                                  "/ 112     "/ obsolete
        (irem)                                  "/ 112
"/        (lmod)                                  "/ 113     "/ obsolete
        (lrem)                                  "/ 113
"/        (fmod)                                  "/ 114     "/ obsolete
        (frem)                                  "/ 114
"/        (dmod)                                  "/ 115     "/ obsolete
        (drem)                                  "/ 115
        (ineg)                                  "/ 116
        (lneg)                                  "/ 117
        (fneg)                                  "/ 118
        (dneg)                                  "/ 119

        (ishl)                                  "/ 120
        (lshl)                                  "/ 121
        (ishr)                                  "/ 122
        (lshr)                                  "/ 123
        (iushr)                                 "/ 124
        (lushr)                                 "/ 125
        (iand)                                  "/ 126
        (land)                                  "/ 127
        (ior)                                   "/ 128
        (lor)                                   "/ 129

        (ixor)                                  "/ 130
        (lxor)                                  "/ 131
        (iinc localIndexByte signedByte)        "/ 132
        (i2l)                                   "/ 133
        (i2f)                                   "/ 134
        (i2d)                                   "/ 135
        (l2i)                                   "/ 136    
        (l2f)                                   "/ 137
        (l2d)                                   "/ 138
        (f2i)                                   "/ 139

        (f2l)                                   "/ 140
        (f2d)                                   "/ 141
        (d2i)                                   "/ 142
        (d2l)                                   "/ 143
        (d2f)                                   "/ 144
        (int2byte)                              "/ 145
        (int2char)                              "/ 146
        (int2short)                             "/ 147
        (lcmp)                                  "/ 148
        (fcmpl)                                 "/ 149

        (fcmpg)                                 "/ 150
        (dcmpl)                                 "/ 151
        (dcmpg)                                 "/ 152
        (ifeq signedBranchShort)                "/ 153
        (ifne signedBranchShort)                "/ 154
        (iflt signedBranchShort)                "/ 155
        (ifge signedBranchShort)                "/ 156
        (ifgt signedBranchShort)                "/ 157
        (ifle signedBranchShort)                "/ 158
        (if_icmpeq signedBranchShort)           "/ 159

        (if_icmpne signedBranchShort)           "/ 160
        (if_icmplt signedBranchShort)           "/ 161
        (if_icmpge signedBranchShort)           "/ 162
        (if_icmpgt signedBranchShort)           "/ 163
        (if_icmple signedBranchShort)           "/ 164
        (if_acmpeq signedBranchShort)           "/ 165
        (if_acmpne signedBranchShort)           "/ 166
        (goto signedBranchShort)                "/ 167
        (jsr signedBranchShort)                 "/ 168
        (ret localIndexByte)                    "/ 169

        (tableswitch tableSwitchBytes)          "/ 170
        (lookupswitch lookupSwitchBytes)        "/ 171
        (ireturn)                               "/ 172
        (lreturn)                               "/ 173
        (freturn)                               "/ 174
        (dreturn)                               "/ 175
        (areturn)                               "/ 176
        (return)                                "/ 177
        (getstatic constIndexShort remember_getstatic)               "/ 178
        (putstatic constIndexShort remember_putstatic)               "/ 179

        (getfield constIndexShort remember_getfield)                 "/ 180
        (putfield constIndexShort remember_putfield)                 "/ 181
        (invokevirtual constIndexShort remember_invokevirtual)       "/ 182
        (invokenonvirtual constIndexShort remember_invokenonvirtual) "/ 183
        (invokestatic constIndexShort remember_invokestatic)         "/ 184
        (invokeinterface constIndexShort nargsByte reservedByte remember_invokeinterface)          "/ 185
        (newfromname)                           "/ 186
        (new constIndexShort remember_new)      "/ 187
        (newarray arrayTypeByte)                "/ 188
        (anewarray constIndexShort)             "/ 189

        (arraylength)                           "/ 190
        (athrow remember_athrow)                "/ 191
        (checkcast constIndexShort)             "/ 192
        (instanceof constIndexShort)            "/ 193
        (monitorenter)                          "/ 194
        (monitorexit)                           "/ 195
"/        (verifystack)                           "/ 196 obsolete (Alpha release)
        (wide)                                  "/ 196
        (multianewarray constIndexShort dimensionsByte) "/ 197

        (ifnull    signedBranchShort)           "/ 198
        (ifnonnull signedBranchShort)           "/ 199

        (#'goto_w' signedBranchLong)            "/ 200
        (#'jsr_w' signedBranchShort)            "/ 201

        (breakpoint)                            "/ 202

        nil                                     "/ 203
        nil                                     "/ 204
        nil                                     "/ 205
        nil                                     "/ 206
        nil                                     "/ 207
        nil                                     "/ 208
        (#'ret_w' signedBranchShort)            "/ 209
                                         
        nil                                     "/ 210
        nil                                     "/ 211
        nil                                     "/ 212
        nil                                     "/ 213
        nil                                     "/ 214
        nil                                     "/ 215
        nil                                     "/ 216
        nil                                     "/ 217
        nil                                     "/ 218
        nil                                     "/ 219

        nil                                     "/ 220
        nil                                     "/ 221
        nil                                     "/ 222
        nil                                     "/ 223
        nil                                     "/ 224
        nil                                     "/ 225
        nil                                     "/ 226
        nil                                     "/ 227
        nil                                     "/ 228
        nil                                     "/ 229
                                    
        nil                                     "/ 230
        nil                                     "/ 231
        nil                                     "/ 232
        nil                                     "/ 233
        nil                                     "/ 234
        nil                                     "/ 235
        nil                                     "/ 236
        nil                                     "/ 237
        nil                                     "/ 238
        nil                                     "/ 239

        nil                                     "/ 240
        nil                                     "/ 241
        nil                                     "/ 242
        nil                                     "/ 243
        nil                                     "/ 244
        nil                                     "/ 245
        nil                                     "/ 246
        nil                                     "/ 247
        nil                                     "/ 248
        nil                                     "/ 249
                                              
        nil                                     "/ 250
        nil                                     "/ 251
        nil                                     "/ 252
        nil                                     "/ 253
        nil                                     "/ 254
        (invokenonvirtual_d constIndexShort)    "/ 255 special - dummy invokenonvirtual
    )

    "
     JavaDecompiler initialize
    "

    "Modified: / 16.11.1998 / 15:55:49 / cg"
! !

!JavaDecompiler class methodsFor:'accessing'!

instructionTable
    ^ DecoderTable
! !

!JavaDecompiler class methodsFor:'class definition generation'!

definitionOf:aJavaClass on:s
    |pckgName needCR fields staticFields superClass
     interfaces staticMethods nonStaticMethods
     accessAttributeStyle codeStyle classNameStyle methodNameStyle|

    accessAttributeStyle := Java prettyPrintStyle at:#accessAttribute.
    codeStyle := Java prettyPrintStyle at:#code.
    classNameStyle := Java prettyPrintStyle at:#className.
    methodNameStyle := Java prettyPrintStyle at:#className.

    pckgName := aJavaClass package.
    pckgName ~= 'java' ifTrue:[
        s nextPutAll:'package ' , ((pckgName copyFrom: 6) copyReplaceAll:$/ with:$.).
        s nextPutAll:';'; cr; cr.

    ].

    needCR := false.
    s emphasis:accessAttributeStyle.

    aJavaClass isPublic ifTrue:[
       s nextPutAll:'public '.
       needCR := true.
    ].
    aJavaClass isAbstract ifTrue:[
       s nextPutAll:'abstract '.
       needCR := true.
    ].
    aJavaClass isFinal ifTrue:[
       s nextPutAll:'final '.
       needCR := true.
    ].
    s emphasis:codeStyle.

    needCR ifTrue:[
        s cr
    ].
    aJavaClass isInterface ifTrue:[
       s nextPutAll:'interface '.
    ] ifFalse:[
       s nextPutAll:'class '.
    ].
    s emphasis:classNameStyle; 
      nextPutAll:aJavaClass lastName; 
      emphasis:codeStyle; 
      space.
    superClass := aJavaClass superclass.

    (superClass ~~ (JavaVM classNamed:'java/lang/Object')
    and:[superClass isJavaClass]) ifTrue:[
        s nextPutAll:'extends '.
        s emphasis:classNameStyle.
        (superClass package ~= 'java/lang' 
        and:[superClass package ~= pckgName]) ifTrue:[
            s nextPutAll:(superClass displayString). 
        ] ifFalse:[
            s nextPutAll:(superClass lastName).
        ].
        s emphasis:codeStyle.
        s space.
    ].

    (interfaces := aJavaClass interfaces) size > 0 ifTrue:[
        (aJavaClass isInterface
        and:[interfaces size == 1]) ifTrue:[
            s nextPutAll:'extends '.
        ] ifFalse:[
            s nextPutAll:'implements '.
        ].
        interfaces keysAndValuesDo:[:nr :if |
            |nameString|

            nr ~~ 1 ifTrue:[
                s nextPutAll:', '.
            ].
            s emphasis:classNameStyle.
            (if package ~= 'java/lang' 
            and:[if package ~= pckgName]) ifTrue:[
                if isJavaClass ifFalse:[
                    "/ ought to be an unresolved class ...
                    nameString := if fullName copyReplaceAll:$/ with:$.
                ] ifTrue:[
                    nameString := if displayString
                ].
            ] ifFalse:[
                nameString := if lastName
            ].
            s nextPutAll:nameString.
            s emphasis:codeStyle.
        ].
        s space.
    ].

    s nextPutAll:'{'; cr.

    needCR := false.
    staticFields := aJavaClass staticFields.
    staticFields size > 0 ifTrue:[
        needCR := true.

        staticFields do:[:aField |
            |type v|

            s nextPutAll:'    '.
            s emphasis:accessAttributeStyle.
            aField isSynthetic ifTrue:[
                s nextPutAll: '/*SYNTHETIC*/ '.
            ].
            aField isPublic ifTrue:[
                s nextPutAll:'public '.
            ] ifFalse:[
                aField isPrivate ifTrue:[
                    s nextPutAll:'private '.
                ] ifFalse:[
                    aField isProtected ifTrue:[
                        s nextPutAll:'protected '.
                    ]
                ]
            ].
            s nextPutAll:'static '.
            aField isFinal ifTrue:[
                s nextPutAll:'final '.
            ].
            aField isVolatile ifTrue:[
                s nextPutAll:'volatile '.
            ].
            s emphasis:codeStyle.

            (((type := aField type) startsWith:pckgName) 
            or:[type startsWith:(pckgName copyReplaceAll:$/ with:$.)]) ifTrue:[
                type := type copyFrom:(pckgName size + 1 + 1).
            ] ifFalse:[
                (type startsWith:'java.lang.') ifTrue:[
                    type := type copyFrom:(11).
                ]
            ].
            type := type copy replaceAll:$/ with:$..
            s nextPutAll:type; space;
              nextPutAll:aField name.

            (v := aField constantValue) notNil ifTrue:[
                s nextPutAll:' = '; nextPutAll:v displayString.
            ].

            s nextPutAll:';'; cr.
            needCR := true.
        ].
    ].


    fields := aJavaClass fields.
    fields size > 0 ifTrue:[
        needCR ifTrue:[
            s cr
        ].
        needCR := true.

        fields do:[:aField |
            |type v|

            s nextPutAll:'    '.
            s emphasis:accessAttributeStyle.
            aField isPublic ifTrue:[
                s nextPutAll:'public '.
            ] ifFalse:[
                aField isPrivate ifTrue:[
                    s nextPutAll:'private '.
                ] ifFalse:[
                    aField isProtected ifTrue:[
                        s nextPutAll:'protected '.
                    ]
                ]
            ].
            aField isFinal ifTrue:[
                s nextPutAll:'final '.
            ].
            aField isTransient ifTrue:[
                s nextPutAll:'transient '.
            ].
            aField isVolatile ifTrue:[
                s nextPutAll:'volatile '.
            ].
            s emphasis:codeStyle.

            (((type := aField type) startsWith:pckgName) 
            or:[type startsWith:(pckgName copyReplaceAll:$/ with:$.)]) ifTrue:[
                type := type copyFrom:(pckgName size + 1 + 1).
            ].
            type := type copy replaceAll:$/ with:$..
            s nextPutAll:type; space;
              nextPutAll:aField name.

            (v := aField constantValue) notNil ifTrue:[
                s nextPutAll:' = '; nextPutAll:v displayString.
            ].
            s nextPutAll:';'; cr.
        ].
    ].

    aJavaClass hasMethods ifTrue:[
        needCR ifTrue:[
            s cr.
            needCR := false.
        ].

        staticMethods := OrderedCollection new.
        nonStaticMethods := OrderedCollection new.
        "/
        "/ static methods first ...
        "/
        aJavaClass methodDictionary do:[:aMethod |
            aMethod isJavaMethod ifTrue:[
            |m|

            m := aMethod.
            m isWrapped ifTrue:[
                m := m originalMethod
            ].
            m isStatic ifTrue:[
                staticMethods add:m.
            ] ifFalse:[
                nonStaticMethods add:m.
            ]
        ].

        staticMethods notEmpty ifTrue:[
            staticMethods sort:[:a :b | a name < b name].
            staticMethods do:[:aMethod |
                "JV@2011-12-14: method dictionary may contain non-Java methods
                (proxies, for instance)"
                aMethod isJavaMethod ifTrue:[
                    self methodDefinitionOf:aMethod inPackage:pckgName on:s.
                ]
            ].
            s cr.
        ].

        "/
        "/ instance methods ...
        "/
        nonStaticMethods notEmpty ifTrue:[
            nonStaticMethods sort:[:a :b | a name < b name].
            nonStaticMethods do:[:aMethod |
                "JV@2011-12-14: method dictionary may contain non-Java methods
                 (proxies, for instance)"
                aMethod isJavaMethod ifTrue:[
                    self methodDefinitionOf:aMethod inPackage:pckgName on:s.
                ]
            ].
        ].
        ]
    ].

    s nextPutAll:'}'; cr.

    "Created: / 22-03-1997 / 14:29:37 / cg"
    "Modified: / 05-12-1998 / 15:58:37 / cg"
    "Modified: / 21-10-2011 / 13:40:44 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 31-03-2012 / 00:36:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

methodDefinitionOf: m inPackage: pckgName on: s 
    | aMethod nm  specComponents  accessAttributeStyle  codeStyle  methodNameStyle |

    aMethod := m.
    m isWrapped ifTrue: [
        aMethod := m originalMethod
    ].
    accessAttributeStyle := Java prettyPrintStyle at: #accessAttribute.
    codeStyle := Java prettyPrintStyle at: #code.
    methodNameStyle := Java prettyPrintStyle at: #methodName.
    s nextPutAll: '    '.
    s emphasis: accessAttributeStyle.
    aMethod isSynthetic ifTrue:[
        s nextPutAll: '/*SYNTHETIC*/ '.
    ].
    aMethod isPublic ifTrue: [
        s nextPutAll: 'public '.
    ] ifFalse: [
        aMethod isProtected ifTrue: [
            s nextPutAll: 'protected '.
        ] ifFalse: [ s nextPutAll: 'private '. ]
    ].
    aMethod isFinal ifTrue: [
        s nextPutAll: 'final '.
    ].
    aMethod isStatic ifTrue: [
        s nextPutAll: 'static '.
    ].
    aMethod isNative ifTrue: [
        s nextPutAll: 'native '.
    ].
    aMethod isSynchronized ifTrue: [
        s nextPutAll: 'synchronized '.
    ].
    s emphasis: codeStyle.
    (nm := aMethod name) = '<init>' ifTrue: [
        nm := aMethod javaClass lastName.
    ].
    specComponents := JavaMethod 
                specComponentsWithArgsFromSignature: (aMethod instVarNamed:#descriptor)
                withName: nm
                in: (aMethod javaClass package).
    s nextPutAll: (specComponents at: 1).
    s space.
    s emphasis: methodNameStyle.
    s nextPutAll: (specComponents at: 2).
    s emphasis: codeStyle.
    s nextPutAll: ' ('.
    s nextPutAll: (specComponents at: 3).
    s nextPutAll: ')'.
    aMethod exceptionTable size > 0 ifTrue: [
        s nextPutAll: ' throws '.
        aMethod exceptionTable 
            keysAndValuesDo: [
                :index :aClassRef | 
                | nm |

                nm := aClassRef name.
                (nm startsWith: pckgName) ifTrue: [
                    nm := nm copyFrom: pckgName size + 2
                ] ifFalse: [
                    (nm startsWith: 'java/lang') ifTrue: [
                        nm := nm copyFrom: 'java/lang' size + 2.
                    ].
                ].
                index ~~ 1 ifTrue: [ s nextPutAll: ', ' ].
                s nextPutAll: (nm copyReplaceAll: $/ with: $.)
            ]
    ].
    s
        nextPutAll: ';';
        cr.

    "Created: / 01-08-1997 / 12:24:11 / cg"
    "Modified: / 14-11-1998 / 00:03:09 / cg"
    "Modified: / 04-06-2011 / 17:18:56 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified (format): / 30-03-2012 / 19:52:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!JavaDecompiler class methodsFor:'decompiling'!

decompile:aJavaMethod
    self decompile:aJavaMethod to:Transcript
!

decompile:aJavaMethod to:aStream
    self new decompile:aJavaMethod to:aStream
! !

!JavaDecompiler methodsFor:'decompiling'!

decompile:aJavaMethod to:aStream
    |who endPC|

    outStream := aStream.

    isStaticMethod := aJavaMethod isStatic.

    who := aJavaMethod who.
    who notNil ifTrue:[
        classToCompileFor := who methodClass.
        outStream notNil ifTrue:[
            outStream cr.
"/            outStream showCR:'decompiling ' , classToCompileFor name , '>>' , (who methodSelector) , ':'.
            outStream showCR:'decompiling ' , aJavaMethod displayString , ':'.
            isStaticMethod ifTrue:[
                outStream show:'static method'.
            ].
            outStream cr.
            outStream cr.
        ]
    ].

    javaMethod := aJavaMethod.
    code := aJavaMethod javaByteCode.
    endPC := code size.
    endPC == 0 ifTrue:[
        outStream notNil ifTrue:[
            javaMethod isNative ifTrue:[
                outStream nextPutAll:'// native method'; cr
            ] ifFalse:[
                outStream nextPutAll:'{}  // no bytecode'; cr
            ].
        ].
        ^ self
    ].

    self enumerateInstructions.

    "Modified: / 9.11.1999 / 15:33:20 / cg"
!

enumerateInstructions
    |endPC insn spec op wide|

    wide := false.
    pc := 1.
    endPC := code size.
    [pc <= endPC] whileTrue:[
        insn := code at:pc.
        pc := pc + 1.

        spec := DecoderTable at:(insn + 1).
        spec isNil ifTrue:[
            op := '** invalid opcode: ', insn printString, ' **'
        ] ifFalse:[
            op := spec at:1
        ].

        outStream notNil ifTrue:[
            outStream 
                show:((pc - 1 - 1) printStringPaddedTo:4); 
                show:' '.
            outStream
                show:(wide ifTrue:[op , '(w)'] ifFalse:[op]).
            outStream
                show:' '.
        ].

        op == #wide ifTrue:[
            wide := true.
        ] ifFalse:[
            self instructionHookPC:(pc-1) op:op spec:spec.

            spec notNil ifTrue:[
                spec from:2 to:spec size do:[:what |
                    wide ifTrue:[
                        self perform:(what , '_wide') asSymbol.
                    ] ifFalse:[
                        self perform:what
                    ]
                ].
            ].
            wide := false.
        ].

        outStream notNil ifTrue:[
            outStream cr.
        ]
    ]

    "Created: / 9.11.1999 / 15:32:49 / cg"
    "Modified: / 9.11.1999 / 15:36:22 / cg"
!

instructionHookPC:pc op:op spec:spec

    "Created: / 9.11.1999 / 15:35:19 / cg"
! !

!JavaDecompiler methodsFor:'operand decoding'!

arrayTypeByte
    |index type|

    index := code at:pc.
    pc := pc + 1.

    type := #('T_ARRAY' 'invalid2' 'invalid3' 'T_BOOLEAN'
              'T_CHAR'  'T_FLOAT'  'T_DOUBLE'  'T_BYTE' 
              'T_SHORT' 'T_INT'    'T_LONG' ) at:index ifAbsent:['invalid' , index printString].

    outStream notNil ifTrue:[
        outStream
            show:index; 
            show:' [';
            show:type;
            show:']'
    ]

    "Created: / 16.11.1998 / 15:41:47 / cg"
    "Modified: / 16.11.1998 / 15:43:27 / cg"
!

constIndexByte
    lastConstIndex := code at:pc.
    pc := pc + 1.

    lastConstant := javaMethod constantPool at:lastConstIndex ifAbsent:nil.

    outStream notNil ifTrue:[
        outStream
            show:lastConstIndex; 
            show:' ['; 
            show:(lastConstant ? '??') displayString; 
            show:'] '
    ]

    "Created: / 16.11.1998 / 15:42:56 / cg"
    "Modified: / 16.11.1998 / 15:58:52 / cg"
!

constIndexShort
    |s|

    lastConstIndex := code wordAt:pc MSB:true.
    pc := pc + 2.

    lastConstant := javaMethod constantPool at:lastConstIndex ifAbsent:nil.
    outStream notNil ifTrue:[
        s := (lastConstant ? '??') displayString.
        s isString ifTrue:[
            s bitsPerCharacter > 8 ifTrue:[
                s := '...a 2-byte string...'
            ]
        ].
        outStream
            show:lastConstIndex; 
            show:' ['; 
            show:s; 
            show:'] '
    ]

    "Created: / 16.4.1996 / 15:00:04 / cg"
    "Modified: / 16.11.1998 / 15:59:23 / cg"
!

dimensionsByte
    outStream notNil ifTrue:[
        outStream show:' dims= '. 
    ].
    self unsignedByte

    "Modified: / 9.11.1999 / 15:46:06 / cg"
!

localIndexByte
    |index|

    index := code at:pc.
    pc := pc + 1.

    outStream notNil ifTrue:[
        outStream
            show:index; 
            show:' '
    ]

    "Created: / 16.4.1996 / 15:00:04 / cg"
    "Modified: / 16.11.1998 / 15:43:55 / cg"
!

localIndexByte_wide
    |index|

    index := code wordAt:pc MSB:true.
    pc := pc + 2.

    outStream notNil ifTrue:[
        outStream
            show:index; 
            show:' '
    ]

    "Created: / 4.8.1997 / 19:02:09 / cg"
    "Modified: / 16.11.1998 / 15:44:02 / cg"
!

lookupSwitchBytes
    |defaultOffset delta nPairs match pc0|

    pc0 := pc-1.  "/ i.e. the pc of the tableSwitch op

    [(pc-1) \\ 4 ~~ 0] whileTrue:[
        pc := pc + 1
    ].

    defaultOffset := code signedDoubleWordAt:pc MSB:true.
    pc := pc + 4.
    nPairs := code signedDoubleWordAt:pc MSB:true.
    pc := pc + 4.

    outStream notNil ifTrue:[
        outStream show:'n='; show:nPairs; cr.
    ].

    nPairs timesRepeat:[
        match := code signedDoubleWordAt:pc MSB:true.
        pc := pc + 4.
        delta := code signedDoubleWordAt:pc MSB:true.
        pc := pc + 4.
        outStream notNil ifTrue:[
            outStream show:'    '; 
                      show:match;
                      show:' -> ';
                      show:delta;
                      show:' [';
                      show:(pc0 - 1 + delta);
                      show:']';
                      cr.
        ]
    ].

    outStream notNil ifTrue:[
        outStream show:'    '; 
                  show:'default';
                  show:' -> ';
                  show:defaultOffset;
                  show:' [';
                  show:(pc0 - 1 + defaultOffset);
                  show:']'.
    ]

    "Modified: / 9.11.1999 / 15:45:50 / cg"
!

nargsByte
    |byte|

    byte := code byteAt:pc.
    pc := pc + 1.

    outStream notNil ifTrue:[
        outStream
            show:byte 
    ]

    "Created: / 16.4.1996 / 15:00:04 / cg"
    "Modified: / 16.11.1998 / 15:44:34 / cg"
!

reservedByte
    |byte|

    byte := code byteAt:pc.
    pc := pc + 1.

    outStream notNil ifTrue:[
        outStream
            show:byte 
    ]

    "Created: / 16.4.1996 / 15:00:04 / cg"
    "Modified: / 16.11.1998 / 15:44:42 / cg"
!

signedBranchShort
    |index|

    index := code signedWordAt:pc MSB:true.

    outStream notNil ifTrue:[
        outStream
            show:index; 
            show:' ['; 
            show:(pc - 1 + index - 1); 
            show:']'.
    ].

    pc := pc + 2.

    "Created: / 16.4.1996 / 15:00:04 / cg"
    "Modified: / 16.11.1998 / 15:44:51 / cg"
!

signedByte
    |byte|

    byte := code signedByteAt:pc.
    pc := pc + 1.

    outStream notNil ifTrue:[
        outStream
            show:byte 
    ]

    "Created: / 16.4.1996 / 15:00:04 / cg"
    "Modified: / 16.11.1998 / 15:44:58 / cg"
!

signedByte_wide
    self signedShort

    "Created: / 13.1.1998 / 23:56:36 / cg"
!

signedShort
    |word|

    word := code signedWordAt:pc MSB:true.
    pc := pc + 2.

    outStream notNil ifTrue:[
        outStream
            show:word 
    ]

    "Created: / 16.4.1996 / 15:00:04 / cg"
    "Modified: / 16.11.1998 / 15:45:06 / cg"
!

tableSwitchBytes
    |defaultOffset delta low high pc0|

    pc0 := pc-1.  "/ i.e. the pc of the tableSwitch op

    [(pc-1) \\ 4 ~~ 0] whileTrue:[
        pc := pc + 1
    ].

    defaultOffset := code signedDoubleWordAt:pc MSB:true.
    pc := pc + 4.
    low := code signedDoubleWordAt:pc MSB:true.
    pc := pc + 4.
    high := code signedDoubleWordAt:pc MSB:true.
    pc := pc + 4.

    outStream notNil ifTrue:[
        outStream cr.
    ].

    low to:high do:[:switchValue |
        delta := code signedDoubleWordAt:pc MSB:true.
        pc := pc + 4.
        outStream notNil ifTrue:[
            outStream show:'    '; 
                      show:switchValue;
                      show:' -> ';
                      show:delta;
                      show:' [';
                      show:(pc0 - 1 + delta);
                      show:']';
                      cr.
        ].
    ].

    outStream notNil ifTrue:[
        outStream show:'    '; 
                  show:'default';
                  show:' -> ';
                  show:defaultOffset;
                  show:' [';
                  show:(pc0 - 1 + defaultOffset);
                  show:']'.
    ]

    "Modified: / 9.11.1999 / 15:44:36 / cg"
!

unsignedByte
    |byte|

    byte := code byteAt:pc.
    pc := pc + 1.

    outStream notNil ifTrue:[
        outStream
            show:byte 
    ]

    "Created: / 16.4.1996 / 15:00:04 / cg"
    "Modified: / 16.11.1998 / 15:45:33 / cg"
! !

!JavaDecompiler methodsFor:'private'!

popType:type
    (type == #long) ifTrue:[
        ^ self popLong
    ].
    type == #double ifTrue:[
        ^ self popDouble
    ].
    ^ self popStack

    "Created: 16.8.1997 / 03:14:11 / cg"
! !

!JavaDecompiler methodsFor:'statistics'!

remember_athrow

    "Created: / 16.11.1998 / 19:37:32 / cg"
!

remember_getfield
    |fieldRef|

    fieldRef := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:07:58 / cg"
!

remember_getstatic
    |fieldRef|

    fieldRef := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:08:06 / cg"
!

remember_invokeinterface
    |mthdRef|

    mthdRef := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:07:29 / cg"
!

remember_invokenonvirtual
    |mthdRef|

    mthdRef := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:06:49 / cg"
!

remember_invokestatic
    |mthdRef|

    mthdRef := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:06:40 / cg"
!

remember_invokevirtual
    |mthdRef|

    mthdRef := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:06:32 / cg"
!

remember_ldc1
    |what|

    what := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:07:12 / cg"
!

remember_ldc2
    |what|

    what := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:07:19 / cg"
!

remember_ldc2w
    |what|

    what := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:07:20 / cg"
!

remember_new
    |class|

    class := lastConstant.

    "Created: / 16.11.1998 / 15:59:43 / cg"
    "Modified: / 16.11.1998 / 16:12:27 / cg"
!

remember_putfield
    |fieldRef|

    fieldRef := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:08:00 / cg"
!

remember_putstatic
    |fieldRef|

    fieldRef := lastConstant.
    "/ ....

    "Created: / 16.11.1998 / 16:08:04 / cg"
! !

!JavaDecompiler class methodsFor:'documentation'!

version
    ^ '$Header$'
!

version_CVS
    ^ '$Header$'
!

version_HG

    ^ '$Changeset: <not expanded> $'
!

version_SVN
    ^ '$Id$'

! !


JavaDecompiler initialize!