-
Notifications
You must be signed in to change notification settings - Fork 65
/
InstructionPrinter.class.st
396 lines (319 loc) · 11.3 KB
/
InstructionPrinter.class.st
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
"
My instances can print the object code of a CompiledMethod in symbolic format. They print into an instance variable, stream, and uses oldPC to determine how many bytes to print in the listing. The variable method is used to hold the method being printed.
"
Class {
#name : #InstructionPrinter,
#superclass : #InstructionClient,
#instVars : [
'method',
'scanner',
'stream',
'oldPC',
'innerIndents',
'indent',
'printPC',
'indentSpanOfFollowingJump'
],
#category : #VMMakerLoadingDependencies
}
{ #category : #printing }
InstructionPrinter class >> on: aMethod [
^self new method: aMethod.
]
{ #category : #printing }
InstructionPrinter class >> printClass: class [
"Create a file whose name is the argument followed by '.bytes'. Store on
the file the symbolic form of the compiled methods of the class."
| stream |
stream := (ZnNewLineWriterStream on: class name , '.bytes' asFileReference writeStream)
forLf;
yourself.
class selectorsAndMethodsDo:
[:sel :m |
stream newLine; nextPutAll: sel; newLine.
(self on: m) printInstructionsOn: stream].
stream close
"InstructionPrinter printClass: Parser."
]
{ #category : #'instruction decoding' }
InstructionPrinter >> blockReturnConstant: value [
"Print the Return Constant From Block bytecode."
self print: 'blockReturn: ', value printString
]
{ #category : #'instruction decoding' }
InstructionPrinter >> blockReturnTop [
"Print the Return Top Of Stack bytecode."
self print: 'blockReturn'
]
{ #category : #'instruction decoding' }
InstructionPrinter >> callPrimitive: index [
"Print the callPrimitive bytecode."
self print: 'callPrimitive: ' , index printString
]
{ #category : #'instruction decoding' }
InstructionPrinter >> directedSuperSend: selector "<Symbol>" numArgs: numArgs [ "<SmallInteger>"
self print: 'directedSuperSend: ' , (self stringForSelector: selector numArgs: numArgs)
]
{ #category : #'instruction decoding' }
InstructionPrinter >> doDup [
"Print the Duplicate Top Of Stack bytecode."
self print: 'dup'
]
{ #category : #'instruction decoding' }
InstructionPrinter >> doPop [
"Print the Remove Top Of Stack bytecode."
self print: 'pop'
]
{ #category : #accessing }
InstructionPrinter >> indent [
^ indent ifNil: [0]
]
{ #category : #'initialize-release' }
InstructionPrinter >> indent: numTabs [
indent := numTabs
]
{ #category : #'instruction decoding' }
InstructionPrinter >> jump: offset [
"Print the Unconditional Jump bytecode."
self print: 'jumpTo: ' , (scanner pc + offset) printString.
indentSpanOfFollowingJump ifTrue:
[indentSpanOfFollowingJump := false.
innerIndents atAll: (scanner pc to: scanner pc + offset - 1) put: (innerIndents at: scanner pc - 1) + 1]
]
{ #category : #'instruction decoding' }
InstructionPrinter >> jump: offset if: condition [
"Print the Conditional Jump bytecode."
self print:
(condition
ifTrue: ['jumpTrue: ']
ifFalse: ['jumpFalse: '])
, (scanner pc + offset) printString
]
{ #category : #accessing }
InstructionPrinter >> method [
^method.
]
{ #category : #accessing }
InstructionPrinter >> method: aMethod [
method := aMethod.
printPC := true.
indentSpanOfFollowingJump := false
]
{ #category : #'instruction decoding' }
InstructionPrinter >> methodReturnConstant: value [
"Print the Return Constant bytecode."
self print: 'return: ' , value printString
]
{ #category : #'instruction decoding' }
InstructionPrinter >> methodReturnReceiver [
"Print the Return Self bytecode."
self print: 'returnSelf'
]
{ #category : #'instruction decoding' }
InstructionPrinter >> methodReturnTop [
"Print the Return Top Of Stack bytecode."
self print: 'returnTop'
]
{ #category : #'instruction decoding' }
InstructionPrinter >> popIntoLiteralVariable: anAssociation [
"Print the Remove Top Of Stack And Store Into Literal Variable bytecode."
self print: 'popIntoLit: ' , anAssociation key
]
{ #category : #'instruction decoding' }
InstructionPrinter >> popIntoReceiverVariable: offset [
"Print the Remove Top Of Stack And Store Into Instance Variable
bytecode."
self print: 'popIntoRcvr: ' , offset printString
]
{ #category : #'instruction decoding' }
InstructionPrinter >> popIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex [
self print: 'popIntoTemp: ', remoteTempIndex printString, ' inVectorAt: ', tempVectorIndex printString
]
{ #category : #'instruction decoding' }
InstructionPrinter >> popIntoTemporaryVariable: offset [
"Print the Remove Top Of Stack And Store Into Temporary Variable
bytecode."
self print: 'popIntoTemp: ' , offset printString
]
{ #category : #printing }
InstructionPrinter >> print: instruction [
"Append to the receiver a description of the bytecode, instruction."
| code |
stream tab: self indent.
printPC ifTrue: [stream print: oldPC; space].
stream tab: (innerIndents at: oldPC).
stream nextPut: $<.
oldPC to: scanner pc - 1 do:
[:i |
code := (method at: i) radix: 16.
stream nextPut:
(code size < 2
ifTrue: [$0]
ifFalse: [code at: 1]).
stream nextPut: code last; space].
stream skip: -1.
stream nextPut: $>.
stream space.
stream nextPutAll: instruction.
stream newLine.
oldPC := scanner pc.
"(InstructionPrinter compiledMethodAt: #print:) symbolic."
]
{ #category : #'initialize-release' }
InstructionPrinter >> printInstructionsOn: aStream [
"Append to the stream, aStream, a description of each bytecode in the
instruction stream."
| end |
stream := aStream.
scanner := InstructionStream on: method.
end := method endPC.
oldPC := scanner pc.
innerIndents := Array new: end withAll: 0.
[scanner pc <= end] whileTrue:
[scanner interpretNextInstructionFor: self]
]
{ #category : #'initialize-release' }
InstructionPrinter >> printInstructionsOn: aStream do: aBlock [
"Append to the stream, aStream, a description of each bytecode in the
instruction stream. Evaluate aBlock with the receiver, the scanner and
the stream after each instruction."
| end |
stream := aStream.
scanner := InstructionStream on: method.
end := method endPC.
oldPC := scanner pc.
innerIndents := Array new: end withAll: 0.
[scanner pc <= end] whileTrue:
[scanner interpretNextInstructionFor: self.
aBlock value: self value: scanner value: stream]
]
{ #category : #accessing }
InstructionPrinter >> printPC [
^printPC
]
{ #category : #accessing }
InstructionPrinter >> printPC: aBoolean [
printPC := aBoolean
]
{ #category : #'instruction decoding' }
InstructionPrinter >> pushActiveContext [
"Print the Push Active Context On Top Of Its Own Stack bytecode."
self print: 'pushThisContext: '
]
{ #category : #'instruction decoding' }
InstructionPrinter >> pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize [
self print: 'closureNumCopied: ', numCopied printString
, ' numArgs: ', numArgs printString
, ' bytes ', scanner pc printString
, ' to ', (scanner pc + blockSize - 1) printString.
innerIndents
atAll: (scanner pc to: scanner pc + blockSize - 1)
put: (innerIndents at: scanner pc - 1) + 1
]
{ #category : #'instruction decoding' }
InstructionPrinter >> pushConsArrayWithElements: numElements [
self print: 'pop ', numElements printString, ' into (Array new: ', numElements printString, ')'
]
{ #category : #'instruction decoding' }
InstructionPrinter >> pushConstant: obj [
"Print the Push Constant, obj, on Top Of Stack bytecode."
self print: (String streamContents:
[:s |
s nextPutAll: 'pushConstant: '.
obj isVariableBinding
ifTrue:
[obj key
ifNotNil: [s nextPutAll: '##'; nextPutAll: obj key]
ifNil: [s nextPutAll: '###'; nextPutAll: obj value soleInstance name]]
ifFalse:
[obj isClosure
ifTrue: [s nextPutAll: obj sourceString]
ifFalse: [obj printOn: s]]]).
obj isCompiledMethod ifTrue:
[obj longPrintOn: stream indent: self indent + 2.
^self]
]
{ #category : #printing }
InstructionPrinter >> pushFullClosure: aCompiledBlock numCopied: numCopied [
| literalIndex |
literalIndex := method literals identityIndexOf: aCompiledBlock.
literalIndex = 0
ifTrue:
[self print: 'closureNumCopied: ', numCopied printString
, ' numArgs: ', aCompiledBlock numArgs printString]
ifFalse:
[self print: 'pushFullClosure: (self literalAt: ', literalIndex printString,
') numCopied: ', numCopied printString,
' "numArgs: ', aCompiledBlock numArgs printString, '"']
]
{ #category : #'instruction decoding' }
InstructionPrinter >> pushLiteralVariable: anAssociation [
"Print the Push Value Of anAssociation On Top Of Stack bytecode."
self print: 'pushLitVar: ' , (anAssociation printStringLimitedTo: 64)
]
{ #category : #'instruction decoding' }
InstructionPrinter >> pushNewArrayOfSize: numElements [
self print: 'push: (Array new: ', numElements printString, ')'
]
{ #category : #'instruction decoding' }
InstructionPrinter >> pushReceiver [
"Print the Push Active Context's Receiver on Top Of Stack bytecode."
self print: 'self'
]
{ #category : #'instruction decoding' }
InstructionPrinter >> pushReceiverVariable: offset [
"Print the Push Contents Of the Receiver's Instance Variable Whose Index
is the argument, offset, On Top Of Stack bytecode."
self print: 'pushRcvr: ' , offset printString
]
{ #category : #'instruction decoding' }
InstructionPrinter >> pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex [
self print: 'pushTemp: ', remoteTempIndex printString, ' inVectorAt: ', tempVectorIndex printString
]
{ #category : #'instruction decoding' }
InstructionPrinter >> pushTemporaryVariable: offset [
"Print the Push Contents Of Temporary Variable Whose Index Is the
argument, offset, On Top Of Stack bytecode."
self print: 'pushTemp: ' , offset printString
]
{ #category : #'instruction decoding' }
InstructionPrinter >> send: selector super: supered numArgs: numArgs [
"Print the Send Message With Selector, selector, bytecode. The argument,
supered, indicates whether the receiver of the message is specified with
'super' in the source method. The arguments of the message are found in
the top numArguments locations on the stack and the receiver just
below them."
self print: (supered
ifTrue: ['superSend: ']
ifFalse: ['send: '])
, (self stringForSelector: selector numArgs: numArgs)
]
{ #category : #'instruction decoding' }
InstructionPrinter >> storeIntoLiteralVariable: anAssociation [
"Print the Store Top Of Stack Into Literal Variable Of Method bytecode."
self print: 'storeIntoLit: ' , anAssociation key
]
{ #category : #'instruction decoding' }
InstructionPrinter >> storeIntoReceiverVariable: offset [
"Print the Store Top Of Stack Into Instance Variable Of Method bytecode."
self print: 'storeIntoRcvr: ' , offset printString
]
{ #category : #'instruction decoding' }
InstructionPrinter >> storeIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex [
self print: 'storeIntoTemp: ', remoteTempIndex printString, ' inVectorAt: ', tempVectorIndex printString
]
{ #category : #'instruction decoding' }
InstructionPrinter >> storeIntoTemporaryVariable: offset [
"Print the Store Top Of Stack Into Temporary Variable Of Method
bytecode."
self print: 'storeIntoTemp: ' , offset printString
]
{ #category : #printing }
InstructionPrinter >> stringForSelector: selector numArgs: numArgs [
^(selector isSymbol and: [selector numArgs = numArgs])
ifTrue: [selector]
ifFalse: [selector printString
, (numArgs = 1
ifTrue: [' (1 arg)']
ifFalse: [' (', numArgs printString, ' args)'])]
]