23
Building run-time analysis tools by means of pluggable interpreters Michel Tilman System Architect, Unisys Belgium [email protected] http://users.pandora.be/michel.tilman ESUG’2000 Summer School ESUG’2000 Summer School Southampton Southampton August 28, 2000 August 28, 2000

Building run-time analysis tools by means of pluggable interpreters

  • Upload
    kumiko

  • View
    17

  • Download
    0

Embed Size (px)

DESCRIPTION

Building run-time analysis tools by means of pluggable interpreters. Michel Tilman System Architect, Unisys Belgium [email protected] http://users.pandora.be/michel.tilman ESUG’2000 Summer School Southampton August 28, 2000. Contents. Introduction Method wrappers Interpreter - PowerPoint PPT Presentation

Citation preview

Page 1: Building run-time analysis tools by means of pluggable interpreters

Building run-time analysis tools by means of pluggable interpreters

Michel TilmanSystem Architect, Unisys Belgium

[email protected]

http://users.pandora.be/michel.tilman

ESUG’2000 Summer SchoolESUG’2000 Summer SchoolSouthamptonSouthampton

August 28, 2000August 28, 2000

Page 2: Building run-time analysis tools by means of pluggable interpreters

Contents

IntroductionMethod wrappers InterpreterCompatiblity issuesDemoReferences

Page 3: Building run-time analysis tools by means of pluggable interpreters

Introduction

Need for tools Coverage

Methods, blocks, arguments, variables

Run-time typing information

Current tools Smalltalk reflection

Low-level, hard to understand, operationalBytecodes, processes, ….

Page 4: Building run-time analysis tools by means of pluggable interpreters

Introduction

Smalltalk language Simple semantics

Interpreter Declarative feel

Easier to understand

SelectivePer method

Embedded interpreter

Page 5: Building run-time analysis tools by means of pluggable interpreters

Method wrappers

Intercept method activations Smalltalk reflection

Localized ‘tricks’

Easy to extend

Usage Before-after methods

Build interaction diagrams

...

Activate interpreter

Page 6: Building run-time analysis tools by means of pluggable interpreters

Interpreter

Recursive descent Abstract grammar

Parse tree

Eval method

Smalltalk = run-time engine Garbage collection Primitives

Include methods supporting interpreter implementation

Unwinding stack ….

Page 7: Building run-time analysis tools by means of pluggable interpreters

Abstract grammar

Expression tree

Expression ()

Assignment ('variable' 'value')

Code ('arguments' 'temporaries')

Block ('level')

Method ('mclass' 'selector')

Literal ('value')

MessageExpression ('receiver' 'selector' 'arguments’ ‘methodCache’)

PseudoVariable ('isSuper')

Return ('value')

Variable ()

InstanceVariable ('index' 'class')

LocalVariable ('name' 'level' 'index')

SharedVariable ('binding')

Expression ()

Assignment ('variable' 'value')

Code ('arguments' 'temporaries')

Block ('level')

Method ('mclass' 'selector')

Literal ('value')

MessageExpression ('receiver' 'selector' 'arguments’ ‘methodCache’)

PseudoVariable ('isSuper')

Return ('value')

Variable ()

InstanceVariable ('index' 'class')

LocalVariable ('name' 'level' 'index')

SharedVariable ('binding')

Page 8: Building run-time analysis tools by means of pluggable interpreters

Contexts

Contexts

CodeContext ()

BlockContext ('outerContext' 'level')

MethodContext ('receiver' 'method' 'returnHandler')

CodeContext ()

BlockContext ('outerContext' 'level')

MethodContext ('receiver' 'method' 'returnHandler')

Block closures

BlockClosure ('block' 'outerContext')BlockClosure ('block' 'outerContext')

Page 9: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Method wrappers

valueWithReceiver: anObject arguments: arrayOfObjects"Evaluate the method by invoking the interpreter.”

^ self methodExpression valueWithReceiver: anObject arguments: arrayOfObjects

valueWithReceiver: anObject arguments: arrayOfObjects"Evaluate the method by invoking the interpreter.”

^ self methodExpression valueWithReceiver: anObject arguments: arrayOfObjects

Method expressions

valueWithReceiver: anObject arguments: arrayOfObjects”Create a suitable context. Evaluate the method with given receiver and

arguments in this context. Answer the result.”

| context |

context := self contextWithReceiver: anObject arguments: arrayOfObjects.^ self valueInContext: context

valueWithReceiver: anObject arguments: arrayOfObjects”Create a suitable context. Evaluate the method with given receiver and

arguments in this context. Answer the result.”

| context |

context := self contextWithReceiver: anObject arguments: arrayOfObjects.^ self valueInContext: context

Page 10: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Method expressions

contextWithReceiver: anObject arguments: arrayOfObjects”Answer a context for evaluating the receiver. Install a return handler block.”

^ MethodContext on: self receiver: anObject arguments: arrayOfObjects returnHandler: [ :value | ^ value ]

contextWithReceiver: anObject arguments: arrayOfObjects”Answer a context for evaluating the receiver. Install a return handler block.”

^ MethodContext on: self receiver: anObject arguments: arrayOfObjects returnHandler: [ :value | ^ value ]

Method (Code) expressions

valueInContext: aMethodContext”Evaluate the statements for side effects. Answer the result of the last evaluation.”

| answer |

self statements do: [ :stat | answer := stat eval: aMethodContext ].^ answer

valueInContext: aMethodContext”Evaluate the statements for side effects. Answer the result of the last evaluation.”

| answer |

self statements do: [ :stat | answer := stat eval: aMethodContext ].^ answer

Page 11: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Literal expressions

eval: aContext”Answer the value.”

^ value

eval: aContext”Answer the value.”

^ value

Pseudo-variables (“self”, “super”)

eval: aContext”Answer the receiver.”

^ aContext receiver

eval: aContext”Answer the receiver.”

^ aContext receiver

Page 12: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Shared variables

eval: aContext”Answer the value bound to the variable.”

^ binding value

eval: aContext”Answer the value bound to the variable.”

^ binding value

Shared variables

bind: anObject context: aContext”Bind the object to the variable.”

binding value: anObject.^ anObject

bind: anObject context: aContext”Bind the object to the variable.”

binding value: anObject.^ anObject

Page 13: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Instance variables

eval: aContext”Answer the value bound to the variable.”

^ aContext receiver instVarAt: index

eval: aContext”Answer the value bound to the variable.”

^ aContext receiver instVarAt: index

Instance variables

bind: anObject context: aContext”Bind the object to the variable.”

^ aContext receiver instVarAt: index put: anObject

bind: anObject context: aContext”Bind the object to the variable.”

^ aContext receiver instVarAt: index put: anObject

Page 14: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Local variables

eval: aContext”Answer the value bound to the variable.”

^ (aContext contextAt: level) at: index

eval: aContext”Answer the value bound to the variable.”

^ (aContext contextAt: level) at: index

Local variables

bind: anObject context: aContext”Bind the object to the variable.”

^ (aContext contextAt: level) at: index put: anObject

bind: anObject context: aContext”Bind the object to the variable.”

^ (aContext contextAt: level) at: index put: anObject

Page 15: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Assignment expressions

eval: aContext”Bind the value to the variable. Answer the value.”

^ variable bind: (value eval: aContext) context: aContext

eval: aContext”Bind the value to the variable. Answer the value.”

^ variable bind: (value eval: aContext) context: aContext

Return expressions

eval: aContext”Evaluate the value expression. Return the answer as the return value of the

method that ‘defines’ this return expression.”

aContext returnHandler value: (value eval: aContext)

eval: aContext”Evaluate the value expression. Return the answer as the return value of the

method that ‘defines’ this return expression.”

aContext returnHandler value: (value eval: aContext)

Page 16: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Block expressions

eval: aContext”Build a block closure for this context. Answer the closure.”

^ BlockClosure block: self outerContext: aContext

eval: aContext”Build a block closure for this context. Answer the closure.”

^ BlockClosure block: self outerContext: aContext

Executing block closures

value”Execute the block (closure) without arguments. Answer the result.”

^ block numTemps = 0ifTrue: [ block valueInContext: outerContext ]ifFalse: [ block valueInContext: (BlockContext outerContext:

outerContext level: block level + 1 size: numTemps)]

value”Execute the block (closure) without arguments. Answer the result.”

^ block numTemps = 0ifTrue: [ block valueInContext: outerContext ]ifFalse: [ block valueInContext: (BlockContext outerContext:

outerContext level: block level + 1 size: numTemps)]

Page 17: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Wrapping block closures in ‘native’ closures

asNativeBlockClosure”Wrap the receiver in a native block closure. Note: this is self-modifying code.”

| numArgs |

(numArgs := block numArgs) = 0 ifTrue: [ ^ [ self value ]].numArgs = 1 ifTrue: [ ^ [ :arg1 | self value: arg1 ]].numArgs = 2 ifTrue: [ ^ [ :arg1 :arg2 | self value: arg1 value: arg2 ]].numArgs = 3 ifTrue: [ ^ [ :arg1 :arg2 :arg3 | self value: arg1 value: arg2 value: arg3 ]].numArgs = 4 ifTrue: [ ^ [ :arg1 :arg2 :arg3 :arg4 | | args |

args := Array new: 4. args at: 1 put: arg1. args at: 2 put: arg2. args at: 3 put: arg3. args at: 4 put: arg4. self valueWithArguments: args ]].

self generateUpTo: numArgs.^ self asNativeBlockClosure

asNativeBlockClosure”Wrap the receiver in a native block closure. Note: this is self-modifying code.”

| numArgs |

(numArgs := block numArgs) = 0 ifTrue: [ ^ [ self value ]].numArgs = 1 ifTrue: [ ^ [ :arg1 | self value: arg1 ]].numArgs = 2 ifTrue: [ ^ [ :arg1 :arg2 | self value: arg1 value: arg2 ]].numArgs = 3 ifTrue: [ ^ [ :arg1 :arg2 :arg3 | self value: arg1 value: arg2 value: arg3 ]].numArgs = 4 ifTrue: [ ^ [ :arg1 :arg2 :arg3 :arg4 | | args |

args := Array new: 4. args at: 1 put: arg1. args at: 2 put: arg2. args at: 3 put: arg3. args at: 4 put: arg4. self valueWithArguments: args ]].

self generateUpTo: numArgs.^ self asNativeBlockClosure

Page 18: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Message expressions

eval: aContext”Evaluate receiver and arguments. Do the actual lookup and execute the method

found.”

| rcvr args behavior |

rcvr := receiver eval: aContext .args := arguments collect: [ :arg | arg eval: aContext ].behavior := receiver isSuper

ifTrue: [ aContext methodClass superclass ]ifFalse: [ rcvr class ].

^ self perform: selector receiver: rcvr arguments: args class: behavior

eval: aContext”Evaluate receiver and arguments. Do the actual lookup and execute the method

found.”

| rcvr args behavior |

rcvr := receiver eval: aContext .args := arguments collect: [ :arg | arg eval: aContext ].behavior := receiver isSuper

ifTrue: [ aContext methodClass superclass ]ifFalse: [ rcvr class ].

^ self perform: selector receiver: rcvr arguments: args class: behavior

Page 19: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Message expressions

perform: sel receiver: rcvr arguments: args class: aBehavior”Retrieve the method for given selector, starting the lookup in the class. Execute

the method and return the result if successful. Otherwise fail with a #doesNotUnderstand: message. Note that executing a #perform: in the false branche instead of executing the method will acutally be faster. The lookup is only relevant in so far we are interested in keeping track of the different method invocations at the call site.”

| method |

^ (method := self lookupMethod: sel in: aBehavior) isNilifTrue: [ rcvr doesNotUnderstand: (Message selector: sel arguments:

args)]ifFalse: [ method valueWithReceiver: rcvr arguments: args ]

perform: sel receiver: rcvr arguments: args class: aBehavior”Retrieve the method for given selector, starting the lookup in the class. Execute

the method and return the result if successful. Otherwise fail with a #doesNotUnderstand: message. Note that executing a #perform: in the false branche instead of executing the method will acutally be faster. The lookup is only relevant in so far we are interested in keeping track of the different method invocations at the call site.”

| method |

^ (method := self lookupMethod: sel in: aBehavior) isNilifTrue: [ rcvr doesNotUnderstand: (Message selector: sel arguments:

args)]ifFalse: [ method valueWithReceiver: rcvr arguments: args ]

Page 20: Building run-time analysis tools by means of pluggable interpreters

Evaluation

Message expressions

lookupMethod: selector in: aClass” Search for an appropriate method. First perform a lookup in the local cache.

Upon failure do a regular lookup and cache the result.”

^ cache at: aClass ifAbsentPut: [ self basicLookupMethod: selector in: aClass ]

lookupMethod: selector in: aClass” Search for an appropriate method. First perform a lookup in the local cache.

Upon failure do a regular lookup and cache the result.”

^ cache at: aClass ifAbsentPut: [ self basicLookupMethod: selector in: aClass ]

Message expressions

lookupMethod: sel in: aBehavior” Search for an appropriate method. First perform a lookup in the local cache.

Upon failure do a regular lookup and cache the result.”

^ methodCache at: aBehavior ifAbsentPut: [ self basicLookupMethod: sel in: aBehavior]

lookupMethod: sel in: aBehavior” Search for an appropriate method. First perform a lookup in the local cache.

Upon failure do a regular lookup and cache the result.”

^ methodCache at: aBehavior ifAbsentPut: [ self basicLookupMethod: sel in: aBehavior]

Message expressions

basicLookupMethod: sel in: aBehavior"Search for a method in the class hierarchy. Answer nil upon failure."

^ (array := aBehavior findSelector: sel) isNilifTrue: [ nil ]ifFalse: [ array at: 2 ]

basicLookupMethod: sel in: aBehavior"Search for a method in the class hierarchy. Answer nil upon failure."

^ (array := aBehavior findSelector: sel) isNilifTrue: [ nil ]ifFalse: [ array at: 2 ]

Page 21: Building run-time analysis tools by means of pluggable interpreters

Compatibility issues

BlockClosure copied values, ...

Pseudo-variables thisContext

No saveguards Primitives

‘Kernel’ methods

Page 22: Building run-time analysis tools by means of pluggable interpreters

Demo

Tools Coverage tool

Updating number of activations in #eval: methods

Gathering run-time typingRemembering types in #eval: methods

• Variables

• Method invocations at call site

Fine-grained Disjoint lexical occurrences of same variable

Page 23: Building run-time analysis tools by means of pluggable interpreters

References

Method wrappers

http://st-www.cs.uiuc.edu/~brant