JavaMethod.st
author cg
Mon, 17 Mar 1997 17:16:07 +0000
changeset 141 0baa4706b898
parent 135 098936234135
child 142 1cc00567fb75
permissions -rw-r--r--
checkin from browser

CompiledCode subclass:#JavaMethod
	instanceVariableNames:'javaByteCode numArgs numLocals returnType accessFlags name
		signature exceptionHandlerTable exceptionTable lineNumberTable
		localVariableTable javaClass numStack'
	classVariableNames:'SignatureTypeCodes'
	poolDictionaries:''
	category:'Java-Classes'
!


!JavaMethod class methodsFor:'initialization'!

initialize
    SignatureTypeCodes := IdentityDictionary new.
    SignatureTypeCodes at:$B put:#byte.
    SignatureTypeCodes at:$C put:#char.
    SignatureTypeCodes at:$D put:#double.
    SignatureTypeCodes at:$F put:#float.
    SignatureTypeCodes at:$I put:#int.
    SignatureTypeCodes at:$J put:#long.
    SignatureTypeCodes at:$S put:#'unsigned short'.
    SignatureTypeCodes at:$Z put:#boolean.
    SignatureTypeCodes at:$L put:#object.
    SignatureTypeCodes at:$[ put:#array.

    "
     JavaMethod initialize
    "
! !

!JavaMethod class methodsFor:'signature parsing'!

argSigArrayFromSignature:aSignature
    "given a signature, return a specArray for the arguments"

    |s argSpec retvalSpec|

    s := aSignature readStream.
    s next ~~ $( ifTrue:[self halt. ^ name].

    ^ self argSigArrayFromStream:s.

    "
     JavaMethod argSigArrayFromSignature:'(LObject;)V'
     JavaMethod argSigArrayFromSignature:'(BB)S'      
     JavaMethod argSigArrayFromSignature:'(LObject;LObject;II)V'      
    "
!

argSigArrayFromStream:s
    "parse an argSpec, return an array of specs - see java doc"

    |argSpec spec|

    spec := #().
    [s atEnd or:[s peek == $)]] whileFalse:[
"/        s peek == Character space ifTrue:[
"/            s next
"/        ] ifFalse:[
            argSpec := self fieldTypeFromStream:s.
            spec := spec copyWith:argSpec.
"/        ]
    ].
    ^ spec


!

argSpecFromSignature:aSignature withName:name
    "given a signature, return a spec"

    |s argSpec retvalSpec|

    s := aSignature readStream.
    s next ~~ $( ifTrue:[self halt. ^ name].

    argSpec := self argSpecFromStream:s.

    s next ~~ $) ifTrue:[self halt. ^ name].

    ^ name , ' (' , argSpec , ')'

    "
     JavaMethod argSpecFromSignature:'(LObject;)V' withName:'foo' 
     JavaMethod argSpecFromSignature:'(BB)S'       withName:'foo' 
    "
!

argSpecFromStream:s
    "parse an argSpec - see java doc"

    |argSpec spec|

    spec := ''.
    [s atEnd or:[s peek == $)]] whileFalse:[
"/        s peek == Character space ifTrue:[
"/            s next
"/        ] ifFalse:[
            argSpec := self fieldTypeFromStream:s.
            spec size ~~ 0 ifTrue:[
                spec := spec , ' '
            ].
            spec := spec , argSpec.
"/        ]
    ].
    ^ spec


!

fieldTypeFromStream:s
    "parse a fieldTypeSpec - see java doc"

    |typeChar typeSym spec elType size className|

    typeChar := s next.

    typeSym := SignatureTypeCodes at:typeChar ifAbsent:#unknown.

    typeSym == #unknown ifTrue:[
        ^ typeSym
    ].
    typeSym == #object ifTrue:[
        className := s upTo:$;.
        "/ strip off default
"/        (className startsWith:'java/lang/') ifTrue:[
"/            ^ className copyFrom:11
"/        ].
        ^ className copy replaceAll:$/ by:$.
    ].
    typeSym == #array ifTrue:[
        s peek isDigit ifTrue:[
            size := Integer readFrom:s.
            elType := self fieldTypeFromStream:s.
            ^ elType , '[' , size printString , ']'
        ].
        elType := self fieldTypeFromStream:s.
        ^ elType , '[]'
    ].
    ^ typeSym
!

numArgsFromSignature:aSignature
    "given a signature, return the number of args"

    |s argSpec|

    s := aSignature readStream.
    s next ~~ $( ifTrue:[self halt. ^ name].

    ^ self numArgsFromStream:s.

    "
     JavaMethod numArgsFromSignature:'(LObject;)V'
     JavaMethod numArgsFromSignature:'(BB)S'      
     JavaMethod numArgsFromSignature:'()V'      
    "
!

numArgsFromStream:s
    "parse an argSpec - see java doc"

    |argSpec n t|

    n := 0.
    [s atEnd or:[s peek == $)]] whileFalse:[
        t := self fieldTypeFromStream:s.
        "/
        "/ some args count as 2
        "/
        t == #long ifTrue:[
            n := n + 2.
        ] ifFalse:[
            t == #double ifTrue:[
                n := n + 2
            ] ifFalse:[
                n := n + 1.
            ]
        ]
    ].
    ^ n
!

retValSpecFromSignature:aSignature
    "given a signature, return a spec"

    |s argSpec retvalSpec|

    s := aSignature readStream.
    s next ~~ $( ifTrue:[self halt. ^ name].

    argSpec := self argSpecFromStream:s.

    s next ~~ $) ifTrue:[self halt. ^ name].

    retvalSpec := self retvalSpecFromStream:s.

    ^ retvalSpec 

    "
     JavaMethod retValSpecFromSignature:'(LObject;)V'
     JavaMethod retValSpecFromSignature:'(BB)S'      
    "
!

returnTypeFromSignature:aSignature
    "given a signature, return its type as a string"

    |s c argSpec retvalSpec|

    s := aSignature readStream.
    (c := s peek) ~~ $( ifTrue:[
        c == $' ifTrue:[
           [s peek ~= $'] whileTrue:[s next].
           s next.
           ^ (self retvalSpecFromStream:s)
        ].
        ^ (self retvalSpecFromStream:s)
    ].

    s next.
    self argSpecFromStream:s.
    s next ~~ $) ifTrue:[self halt. ^ nil].

    ^ (self retvalSpecFromStream:s)

    "
     JavaMethod returnTypeFromSignature:'(LObject;)V' 
     JavaMethod returnTypeFromSignature:'(BB)S'       
     JavaMethod returnTypeFromSignature:'()J'       
     JavaMethod returnTypeFromSignature:'''first''J'       
    "
!

returnsVoidFromSignature:aSignature
    "given a signature, return true if it returns void, false if not"

    ^ (self typeFromSignature:aSignature) = 'void'

    "
     JavaMethod returnsVoidFromSignature:'(LObject;)V' 
     JavaMethod returnsVoidFromSignature:'(BB)S'       
    "
!

retvalSpecFromStream:s
    "parse a retvalSpec - see java doc"

    |argSpec spec|

    s atEnd ifTrue:[self halt. ^ #void].
    s peek == $V ifTrue:[^ #void].
    ^ self fieldTypeFromStream:s

!

specFromSignature:aSignature withName:name
    "given a signature, return a spec"

    |s argSpec retvalSpec|

    s := aSignature readStream.
    s next ~~ $( ifTrue:[self halt. ^ name].

    argSpec := self argSpecFromStream:s.

    s next ~~ $) ifTrue:[self halt. ^ name].

    retvalSpec := self retvalSpecFromStream:s.

    ^ retvalSpec , ' ' , name , ' (' , argSpec , ')'

    "
     JavaMethod specFromSignature:'(LObject;)V' withName:'foo' 
     JavaMethod specFromSignature:'(BB)S'       withName:'foo' 
    "
!

typeFromSignature:aSignature
    "given a signature, return its type as a string"

    |s c argSpec retvalSpec|

    s := aSignature readStream.
    (c := s peek) ~~ $( ifTrue:[
        c == $' ifTrue:[
           s next.
           [s peek ~= $'] whileTrue:[s next].
           s next.
           ^ (self retvalSpecFromStream:s)
        ].
        ^ (self retvalSpecFromStream:s)
    ].

    s next.
    self argSpecFromStream:s.
    s next ~~ $) ifTrue:[self halt. ^ nil].

    ^ (self retvalSpecFromStream:s)

    "
     JavaMethod typeFromSignature:'(LObject;)V'  
     JavaMethod typeFromSignature:'(BB)S'        
     JavaMethod typeFromSignature:'()J'          
     JavaMethod typeFromSignature:'J'          
     JavaMethod typeFromSignature:'''first''J'       
    "
! !

!JavaMethod methodsFor:'accessing'!

argSignature
    ^ self class argSigArrayFromSignature:signature
!

constantPool
    ^ javaClass constantPool

    "Modified: 16.4.1996 / 12:36:27 / cg"
    "Created: 16.4.1996 / 15:28:50 / cg"
!

containingClass
    ^ javaClass

!

decompiledSource
    |s|

    s := '' writeStream.
    self decompileTo:s.
    ^ s contents
!

exceptionHandlerTable
    ^ exceptionHandlerTable

    "Modified: 16.4.1996 / 12:49:06 / cg"
    "Created: 7.2.1997 / 20:04:20 / cg"
!

exceptionTable
    ^ exceptionTable

    "Created: 16.4.1996 / 12:34:04 / cg"
    "Modified: 16.4.1996 / 12:49:06 / cg"
!

hasLineNumberInformation
    ^ lineNumberTable notNil

    "Created: 16.4.1996 / 12:34:04 / cg"
    "Modified: 16.4.1996 / 12:49:06 / cg"
!

javaByteCode
    ^ javaByteCode

    "Modified: 16.4.1996 / 12:36:27 / cg"
    "Created: 16.4.1996 / 14:55:44 / cg"
!

javaClass
    ^ javaClass

    "Modified: 16.4.1996 / 12:36:27 / cg"
    "Created: 16.4.1996 / 14:55:44 / cg"
!

lineNumber
    ^ lineNumberTable at:2

    "Created: 16.4.1996 / 12:34:04 / cg"
    "Modified: 16.4.1996 / 12:49:06 / cg"
!

lineNumberTable
    ^ lineNumberTable

    "Created: 16.4.1996 / 12:34:04 / cg"
    "Modified: 16.4.1996 / 12:49:06 / cg"
!

localVariableTable
    ^ localVariableTable

    "
     JavaMethod allInstancesDo:[:m| m localVariableTable notNil ifTrue:[self halt]]
    "
!

methodArgAndVarNames
    ^ ((1 to:self numArgs) collect:[:i | 'arg' , i printString])
      ,
      ((1 to:self numVars) collect:[:i | 'local' , i printString])

!

methodArgNames
    localVariableTable notNil ifTrue:[
        ^ (1 to:self numArgs) collect:
            [:argIndex | |slot name|
                "/ search for an entry with that index (slot),
                "/ which has is valid at PC 0

                self isStatic ifTrue:[
                    slot := argIndex
                ] ifFalse:[
                    slot := argIndex + 1
                ].
                name := localVariableTable nameForSlot:slot atPC:0.
                name isNil ifTrue:[
                    'arg' , argIndex printString
                ] ifFalse:[
                    name
                ].
            ]
    ].
    ^ (1 to:self numArgs) collect:[:i | 'arg' , i printString]
!

name
    ^ name

    "Created: 16.4.1996 / 11:34:22 / cg"
!

numArgs
    numArgs isNil ifTrue:[^ 0].
    ^ numArgs
!

numLocals
    numLocals isNil ifTrue:[^ 0].
    ^ numLocals
!

numStack
    numStack isNil ifTrue:[^ 0].
    ^ numStack
!

numVars
    numLocals isNil ifTrue:[^ 0].
    numArgs isNil ifTrue:[^ numLocals].
    ^ numLocals - numArgs
!

numberOfMethodArgs:n
    numArgs := n
!

retValSignature
    ^ self class retValSpecFromSignature:signature

!

returnType
    ^ returnType
!

returnsDouble
    ^ returnType == #double
!

returnsLong
    ^ returnType == #long
!

returnsVoid
    ^ returnType == #void
!

setAccessFlags:flags
    accessFlags := flags.

    "Created: 16.4.1996 / 11:34:14 / cg"
!

setCode:codeBytes maxStack:max_stack maxLocals:max_locals u1:unknown1 u2:unknown2
    javaByteCode := codeBytes.
    numStack := max_stack.
    numLocals := max_locals.

"/    self displayString printNL.
"/    '   nStack: ' print. numStack print. 
"/    ' nLocal: ' print. numLocals print. 
"/    ' u1: ' print. unknown1 print.
"/    ' u2: ' print. unknown2 printNL.

!

setExceptionHandlerTable:anArray
    exceptionHandlerTable := anArray.

    "Created: 16.4.1996 / 12:34:04 / cg"
!

setExceptionTable:anArray
    exceptionTable := anArray.

    "Created: 16.4.1996 / 12:34:04 / cg"
!

setJavaClass:aJavaClass
    javaClass := aJavaClass

    "Modified: 16.4.1996 / 12:36:27 / cg"
    "Created: 16.4.1996 / 15:28:15 / cg"
!

setLineNumberTable:anArrayOfPCtoLineAssociations
    "since this uses up lots of memory, compress it"

    |allBytes allWords idx|

    allBytes := allWords := true.

    anArrayOfPCtoLineAssociations do:[:assoc |
        assoc key > 255 ifTrue:[
            allBytes := false.
            assoc key > 16rFFFF ifTrue:[
                allWords := false.
            ].
        ].
        assoc value > 255 ifTrue:[
            allBytes := false.
            assoc value > 16rFFFF ifTrue:[
                allWords := false
            ].
        ].
    ].
    allBytes ifTrue:[
        lineNumberTable := ByteArray new:(anArrayOfPCtoLineAssociations size * 2).
    ] ifFalse:[
        allWords ifTrue:[
            lineNumberTable := WordArray new:(anArrayOfPCtoLineAssociations size * 2).
        ] ifFalse:[
            lineNumberTable := Array new:(anArrayOfPCtoLineAssociations size * 2).
        ]
    ].

    idx := 1.
    anArrayOfPCtoLineAssociations do:[:assoc |
        lineNumberTable at:idx   put:assoc key.
        lineNumberTable at:idx+1 put:assoc value.
        idx := idx + 2.
    ].

    "Created: 16.4.1996 / 12:34:04 / cg"
    "Modified: 16.4.1996 / 12:49:06 / cg"
!

setLocalVariableTable:anArray
     localVariableTable := anArray.
!

setName:aString
    name := aString asSymbol.

    "Created: 16.4.1996 / 11:34:22 / cg"
!

setSignature:aString
    signature := aString asSymbol.

    self numberOfMethodArgs:(self class numArgsFromSignature:aString).
    returnType := self class typeFromSignature:aString.

    "Created: 16.4.1996 / 11:34:29 / cg"
!

signature
    ^ signature 

    "Created: 16.4.1996 / 11:34:29 / cg"
!

source
    |classSource|

    lineNumberTable notNil ifTrue:[
        classSource := javaClass source.
        classSource notNil ifTrue:[^ classSource].
    ].

    ^ self decompiledSource
!

sourceFilename
    ^ javaClass sourceFile
! !

!JavaMethod methodsFor:'decompiling'!

decompileTo:aStream
    JavaDecompiler decompile:self to:aStream.
    ^ true


! !

!JavaMethod methodsFor:'methodref interchangability'!

method
    ^ self
! !

!JavaMethod methodsFor:'printing & storing'!

displayString
    ^ 'JavaMethod(' , javaClass name , '::' , self signatureName , ')'
!

printStringForBrowserWithSelector:selector
"/    self isStatic ifTrue:[
"/        ^ 'static ' , self signatureName
"/    ].
    self isBreakpointed ifTrue:[
        ^ '!! ' , self signatureName
    ].
    ^ self signatureName
!

shortDisplayString
    ^ javaClass name , '::' , self signatureNameWithoutReturnType
!

signatureName
    "return a string to be used when browsing"

    ^ self class specFromSignature:signature withName:name
!

signatureNameWithoutReturnType
    "return a string to be used when browsing"

    ^ self class argSpecFromSignature:signature withName:name

! !

!JavaMethod methodsFor:'queries'!

handlerFor:anException at:pc
    exceptionHandlerTable isNil ifTrue:[^ nil].
    exceptionHandlerTable do:[:entry |
        |hpc|

        hpc := entry handlerPCFor:anException at:pc in:self.
        hpc notNil ifTrue:[^ hpc].
    ].

    ^ nil
!

hasResource
    ^ false
!

isAbstract
    ^ (accessFlags bitAnd:16r0400) ~~ 0
!

isBreakpointed
    ^ false
!

isFinal
    ^ (accessFlags bitAnd:16r0010) ~~ 0
!

isNative
    ^ (accessFlags bitAnd:16r0100) ~~ 0
!

isPrivate
    ^ (accessFlags bitAnd:16r0002) ~~ 0

!

isProtected
    ^ (accessFlags bitAnd:16r0004) ~~ 0
!

isPublic
    ^ (accessFlags bitAnd:16r0001) ~~ 0

!

isStatic
    ^ (accessFlags bitAnd:16r0008) ~~ 0
!

isSynchronized
    ^ (accessFlags bitAnd:16r0020) ~~ 0
!

isUnloaded
    ^ false
!

lineNumberForPC:pc
    |last num text classSource|

    num := nil.

    lineNumberTable notNil ifTrue:[
        classSource := javaClass source.
        classSource notNil ifTrue:[
            lineNumberTable pairWiseDo:[:lPc :lNr |
                lPc >= pc ifTrue:[
                    lPc == pc ifTrue:[^ lNr].
                    last isNil ifTrue:[^ lNr].
                    ^ last.
                ].
                last := lNr.
            ].
            last notNil ifTrue:[        
                ^ last
            ].
            ^ lineNumberTable at:2
        ].
    ].

    "/ decompile and look which line the pc falls into
    text := self decompiledSource asCollectionOfLines.

    text keysAndValuesDo:[:lineNr :line |
        |nr|

        (line startsWith:'    ') ifFalse:[
            nr := Integer readFrom:line onError:0.
            nr >= pc ifTrue:[
                ^ lineNr
            ]
        ]
    ].
    ^ num

    "Modified: 17.3.1997 / 18:06:43 / cg"
!

who
    "return the class and selector of where I am defined in."

    |sel|

    sel := javaClass methodDictionary keyAtValue:self ifAbsent:nil.
    sel isNil ifTrue:[^ nil].
    ^ Method::MethodWhoInfo class:javaClass selector:sel.
! !

!JavaMethod class methodsFor:'documentation'!

version
    ^ '$Header: /home/jv/Projects/SmalltalkX/repositories/cvs/stx/libjava/JavaMethod.st,v 1.31 1997/03/17 17:16:07 cg Exp $'
! !
JavaMethod initialize!