rbuilder and bytesurgeon
DESCRIPTION
Lecture "RBuilder and ByteSurgeon", DCC University of Chile, October 2005TRANSCRIPT
![Page 1: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/1.jpg)
Working with Bytecodes:
IRBuilder andByteSurgeon
Marcus Denker
![Page 2: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/2.jpg)
Marcus Denker
Reasons for working with Bytecode
• Generating Bytecode– Implementing compilers for other languages– Experimentation with new language features
• Bytecode Transformation– Adaptation of running Systems– Tracing / Debugging– New language features
![Page 3: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/3.jpg)
Marcus Denker
Overview
1. Introduction to Squeak Bytecodes2. Generating Bytecode with IRBuilder3. Introduction to ByteSurgeon
![Page 4: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/4.jpg)
Marcus Denker
The Squeak Virtual Machine
• From last lecture:– Virtual machine provides a virtual processor– Bytecode: The ‘machine-code’ of the virtual machine– Smalltalk (like Java): Stack machine
• Today:– Closer look at Squeak bytecode
![Page 5: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/5.jpg)
Marcus Denker
Bytecode in the CompiledMethod
• CompiledMethods format:
Header
Literals
Bytecode
TrailerPointer toSource
Array of all Literal Objects
Number of temps, literals...
(Number>>#asInteger)inspect
![Page 6: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/6.jpg)
Marcus Denker
Example: Number>>asInteger
• Smalltalk code:
• Symbolic Bytecode
Number>>asInteger "Answer an Integer nearest the receiver toward zero."
^self truncated
9 <70> self10 <D0> send: truncated11 <7C> returnTop
![Page 7: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/7.jpg)
Marcus Denker
Example: Step by Step
• 9 <70> self– The receiver (self) is pushed on the stack
• 10 <D0> send: truncated– Bytecode 208: send literal selector 1– Get the selector from the first literal– start message lookup in the class of the object
that is top of the stack– result is pushed on the stack
• 11 <7C> returnTop– return the object on top of the stack to the
calling method
![Page 8: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/8.jpg)
Marcus Denker
Squeak Bytecodes
• 256 Bytecodes, four groups:
– Stack Bytecodes• Stack manipulation: push / pop / dup
– Send Bytecodes• Invoke Methods
– Return Bytecodes• Return to caller
– Jump Bytecodes• Control flow inside a method
![Page 9: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/9.jpg)
Marcus Denker
Stack Bytecodes
• Push values on the stack, e.g., temps, instVars, literals– e.g: 16 - 31: push instance variable
• Push Constants (False/True/Nil/1/0/2/-1)• Push self, thisContext• Duplicate top of stack• Pop
![Page 10: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/10.jpg)
Marcus Denker
Sends and Returns
• Sends: receiver is on top of stack– Normal send– Super Sends– Hard-coded sends for efficiency, e.g. +, -
• Returns– Return top of stack to the sender – Return from a block– Special bytecodes for return self, nil, true, false
(for efficiency)
![Page 11: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/11.jpg)
Marcus Denker
Jump Bytecodes
• Control Flow inside one method• Used to implement control-flow efficiently• Example:
9 <76> pushConstant: 110 <77> pushConstant: 211 <B2> send: <12 <99> jumpFalse: 1513 <20> pushConstant: 'true'14 <90> jumpTo: 1615 <73> pushConstant: nil16 <7C> returnTop
^ 1<2 ifTrue: ['true']
![Page 12: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/12.jpg)
What you should have learned...
• ... dealing with bytecodes directly is possible, but very boring.
• We want reusable abstractions that hide the details (e.g. the different send bytecodes)
• We would like to have frameworks for – Generating bytecode easily – Transforming bytecode
![Page 13: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/13.jpg)
Marcus Denker
Generating Bytecodes
• IRBuilder: A tool for generating bytecode• Part of the new compiler for Squeak 3.9
• Idea: a symbolic Assembler for Squeak
![Page 14: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/14.jpg)
Marcus Denker
IRBuilder: Simple Example
• Number>>asInteger
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver" pushTemp: #self; send: #truncated; returnTop; ir.
aCompiledMethod := iRMethod compiledMethod.
aCompiledMethod valueWithReceiver:3.5 arguments: #()
![Page 15: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/15.jpg)
Marcus Denker
IRBuilder: Step by Step
• Number>>asInteger
– Make a instance of IRBuilder
iRMethod := IRBuilder new
![Page 16: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/16.jpg)
Marcus Denker
IRBuilder: Step by Step
• Number>>asInteger
– Define arguments. Note: “self” is default argument
iRMethod := IRBuilder new numRargs: 1;
![Page 17: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/17.jpg)
Marcus Denker
IRBuilder: Step by Step
• Number>>asInteger
– define temporary variables. Note: arguments are temps
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver"
![Page 18: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/18.jpg)
Marcus Denker
IRBuilder: Step by Step
• Number>>asInteger
– push “self” on the stack
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver" pushTemp: #self
![Page 19: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/19.jpg)
Marcus Denker
IRBuilder: Step by Step
• Number>>asInteger
– call method truncated on “self”
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver" pushTemp: #self send: #truncated;
![Page 20: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/20.jpg)
Marcus Denker
IRBuilder: Step by Step
• Number>>asInteger
– return Top of Stack
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver" pushTemp: #self send: #truncated; returnTop;
![Page 21: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/21.jpg)
Marcus Denker
IRBuilder: Step by Step
• Number>>asInteger
– tell IRBuilder to generate Intermediate Representation (IR)
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver" pushTemp: #self send: #truncated; returnTop; ir.
![Page 22: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/22.jpg)
Marcus Denker
IRBuilder: Step by Step
• Number>>asInteger
– Generate method from IR
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver" pushTemp: #self send: #truncated; returnTop; ir.
aCompiledMethod := iRMethod compiledMethod.
![Page 23: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/23.jpg)
Marcus Denker
IRBuilder: Step by Step
• Number>>asInteger
– Execute the method with reveiver 3.5 and no arguments.– “3.5 truncated”
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver" pushTemp: #self send: #truncated; returnTop; ir.
aCompiledMethod := iRMethod compiledMethod.
aCompiledMethod valueWithReceiver:3.5 arguments: #()
![Page 24: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/24.jpg)
Marcus Denker
IRBuilder: Stack Manipulation
• popTop - remove the top of stack• pushDup - push top of stack on the stack• pushLiteral: • pushReceiver - push self• pushThisContext
![Page 25: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/25.jpg)
Marcus Denker
IRBuilder: Symbolic Jumps
• Jump targets are resolved: • Example: false ifTrue: [’true’] ifFalse: [’false’]
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver" pushLiteral: false; jumpAheadTo: #false if: false; pushLiteral: 'true'; "ifTrue: ['true']" jumpAheadTo: #end; jumpAheadTarget: #false; pushLiteral: 'false'; "ifFalse: ['false']" jumpAheadTarget: #end; returnTop; ir.
![Page 26: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/26.jpg)
Marcus Denker
IRBuiler: Instance Variables
• Access by offset• Read: getField:
– receiver on top of stack• Write: setField:
– receiver and value on stack• Example: set the first instance variable to 2
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver" pushLiteral: 2; pushTemp: #self; setField: 1; pushTemp: #self; returnTop; ir. aCompiledMethod := iRMethod compiledMethod. aCompiledMethod valueWithReceiver: 1@2 arguments: #()
![Page 27: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/27.jpg)
Marcus Denker
IRBuilder: Temporary Variables
• Accessed by name• Define with addTemp: / addTemps:• Read with pushTemp:• Write with storeTemp:• Examle: set variables a and b, return value of a
iRMethod := IRBuilder new numRargs: 1; addTemps: #(self); "receiver" addTemps: #(a b); pushLiteral: 1; storeTemp: #a; pushLiteral: 2; storeTemp: #b; pushTemp: #a; returnTop; ir.
![Page 28: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/28.jpg)
Marcus Denker
IRBuilder: Sends
• normal send
• super send
– The second parameter specifies the class were the lookup starts.
....builder send: #selector toSuperOf: aClass;
builder pushLiteral: ‘hello’builder send: #size;
![Page 29: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/29.jpg)
IRBuilder: Lessons learned
• IRBuilder: Easy bytecode generation– Jumps– Instance variable– Temporary variables– Sends
• Next: Manipulating bytecode
![Page 30: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/30.jpg)
Marcus Denker
ByteSurgeon
• Library for bytecode transformation in Smalltalk • Full flexibility of Smalltalk Runtime • Provides high-level API • For Squeak, but portable
• Runtime transformation needed for • Adaptation of running systems • Tracing / debugging • New language features (MOP, AOP)
![Page 31: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/31.jpg)
Marcus Denker
Example: Logging
• Goal: logging message send.• First way: Just edit the text:
example self test.
example Transcript show: ‘sending #test’. self test.
![Page 32: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/32.jpg)
Marcus Denker
Logging with Bytesurgen
• Goal: Change the method without changing program text
• Example:
(Example>>#example)instrumentSend: [:send | send insertBefore: ‘Transcript show: ‘’sending #test’’ ‘.]
![Page 33: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/33.jpg)
Marcus Denker
Logging: Step by Step
(Example>>#example)instrumentSend: [:send | send insertBefore: ‘Transcript show: ‘’sending #test’’ ‘.]
Example >> #example
Class Name of Method
>>: - takes a name of a method - returns the CompiledMethod object
![Page 34: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/34.jpg)
Marcus Denker
Logging: Step by Step
• instrumentSend:– takes a block as an argument– evaluates it for all send bytecodes
(Example>>#example)instrumentSend: [:send | send insertBefore: ‘Transcript show: ‘’sending #test’’ ‘.]
![Page 35: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/35.jpg)
Marcus Denker
Logging: Step by Step
• The block has one parameter: send• It is executed for each send bytecode in the method
(Example>>#example)instrumentSend: [:send | send insertBefore: ‘Transcript show: ‘’sending #test’’ ‘.]
![Page 36: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/36.jpg)
Marcus Denker
Logging: Step by Step
• Objects describing bytecode understand how to insert code– insertBefor– insertAfter– replace
(Example>>#example)instrumentSend: [:send | send insertBefore: ‘Transcript show: ‘’sending #test’’ ‘.]
![Page 37: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/37.jpg)
Marcus Denker
Logging: Step by Step
• The code to be inserted.• Double quoting for string inside string
–Transcript show: ’sending #test’
(Example>>#example)instrumentSend: [:send | send insertBefore: ‘Transcript show: ‘’sending #test’’ ‘.]
![Page 38: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/38.jpg)
Marcus Denker
Inside ByteSurgeon
• Uses IRBuilder internally
• Transformation (Code inlining) done on IR
Bytecode IR Bytecode
Decompile Compile
![Page 39: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/39.jpg)
Marcus Denker
ByteSurgeon Usage
• On Methods or Classes:
• Different instrument methods:– instrument:– instrumentSend:– instrumentTempVarRead: – instrumentTempVarStore:– instrumentTempVarAccess:– same for InstVar
MyClass instrument: [.... ]. (MyClass>>#myMethod) instrument: [.... ].
![Page 40: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/40.jpg)
ByteSurgeon: Lessons learned
• ByteSurgeon: Tool for editing bytecode– Simple example– Based on IRBuilder
• Next: Advanced ByteSurgeon
![Page 41: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/41.jpg)
Marcus Denker
Advanced ByteSurgeon:
• Goal: extend a send with after logging
example self test.
example self test. Logger logSendTo: self.
![Page 42: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/42.jpg)
Marcus Denker
Advanced ByteSurgeon
• With Bytesurgeon, something like:
• How can we access the receiver of the send?• Solution: Metavariable
(Example>>#example)instrumentSend: [:send | send insertAfter: ‘Logger logSendTo: ?’ .]
![Page 43: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/43.jpg)
Marcus Denker
Advanced ByteSurgeon
• With Bytesurgeon, something like:
• How can we access the receiver of the send?• Solution: Metavariable
(Example>>#example)instrumentSend: [:send | send insertAfter: ‘Logger logSendTo: <meta: #receiver>’ .]
![Page 44: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/44.jpg)
Marcus Denker
Implementation Metavariables
• Stack during send:
• Problem 1: After send, receiver is not available• Problem II: Before send, receiver is deep in the stack
receiver
arg1
arg2 result
before after
![Page 45: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/45.jpg)
Marcus Denker
Metavariables: Implementation
• Solution: ByteSurgeon generates preamble
– Pop the arguments into temps– Pop the receiver into temps– Rebuild the stack– Do the send– Now we can acces the receiver even after the send
![Page 46: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/46.jpg)
Marcus Denker
Metavariables: Implementation
25 <70> self26 <81 40> storeIntoTemp: 028 <D0> send: test29 <41> pushLit: Transcript30 <10> pushTemp: 031 <E2> send: show:32 <87> pop33 <87> pop34 <78> returnSelf
Preamble
Inlined Code
![Page 47: RBuilder and ByteSurgeon](https://reader036.vdocument.in/reader036/viewer/2022081403/5554f8b7b4c905bb2a8b533f/html5/thumbnails/47.jpg)
End
• Short overview of Squeak bytecode• Introduction to bytecode generation with IRBuilder• Manipulating bytecode with ByteSurgeon
• Questions?