The Trunk: MethodMassage-ct.75.mcz
[email protected] Fri, 12 Jun 2026 00:00:13 0000
| Newsgroups | gmane.comp.lang.smalltalk.squeak.general |
|---|---|
| Message-ID | <[email protected]> |
Christoph Thiede uploaded a new version of MethodMassage to project The Trunk:
http://source.squeak.org/trunk/MethodMassage-ct.75.mcz
==================== Summary ====================
Name: MethodMassage-ct.75
Author: ct
Time: 12 June 2026, 2:00:13.167523 am
UUID: 0febae50-8cda-4140-b711-655af5d211f2
Ancestors: MethodMassage-dtl.74
Uses new #isAssociation instead of #isVariableBinding to detect labels between instructions, and reuses #isLabel: to improve readability. The new selector is especially helpful here because MethodMassage indeed deals with literals and associations as domain objects. :-)
=============== Diff against MethodMassage-dtl.74 ===============
Item was changed:
----- Method: AssemblerMethod>>isLabel: (in category 'private') -----
isLabel: aMessageOrLookupKey
+ ^aMessageOrLookupKey isAssociation!
- ^aMessageOrLookupKey isVariableBinding!
Item was changed:
----- Method: AssemblerMethod>>labels (in category 'accessing') -----
labels
+ ^instructions select: [:ea| ea isAssociation]!
- ^instructions select: [:ea| ea isVariableBinding]!
Item was changed:
----- Method: AssemblerMethod>>reshapeUsing:oldVars: (in category 'utilities') -----
reshapeUsing: instVarMap oldVars: originalInstVarNames
"Reindex inst var accesses according to the Dictionary instVarMap from old index to new.
Indices are zero-relative"
"Scan instructions looking for inst var refs..."
instructions withIndexDo:
[:messageOrLabel :index|
+ (self isLabel: messageOrLabel) ifFalse:
- messageOrLabel isVariableBinding ifFalse:
[(#(popIntoReceiverVariable:
pushReceiverVariable:
storeIntoReceiverVariable:) identityIncludes: messageOrLabel selector) ifTrue:
[instVarMap
at: (messageOrLabel arguments at: 1)
ifPresent: [:newOffset| messageOrLabel arguments at: 1 put: newOffset]
ifAbsent:"A missing ref needs to be mapped to a global variable, e.g. in Undeclared. This is trivial for reads; tediously difficult for writes"
[| binding |
selector ~~ #pushReceiverVariable: ifTrue:
[UndeclaredVariable name: selector].
binding := self declareAndAddToLiterals: (originalInstVarNames at: messageOrLabel argument + 1) asSymbol.
instructions at: index put: (Message selector: #pushLiteralVariable: argument: binding)]]]].
"scan any and all blocks also..."
literals do:
[:literalOrLabelOrAssemblerMethod|
literalOrLabelOrAssemblerMethod class == self class ifTrue:
[literalOrLabelOrAssemblerMethod
selector: selector; "for UndeclaredVariable name: selector above"
reshapeUsing: instVarMap oldVars: originalInstVarNames]].
"Don't forget quick field read methods... Update both primitive and the callPrimitive: instruction used to generate."
(self isReturnFieldPrimitiveIndex: primitive) ifTrue:
[self assert: (instructions first class == Message
and: [instructions first selector == #callPrimitive:
and: [instructions first arguments first = primitive]]).
instVarMap
at: primitive - 264
ifPresent:
[:newIndex|
self assert: newIndex + 264 <= 519.
instructions first arguments at: 1 put: (primitive := newIndex + 264)]
ifAbsent:
[| binding |
self assert: (primitive - 263 between: 1 and: originalInstVarNames size).
binding := self declareAndAddToLiterals: (originalInstVarNames at: primitive - 263) asSymbol.
instructions := { Message selector: #pushLiteralVariable: argument: binding.
Message selector: #methodReturnTop}]]!
Item was changed:
----- Method: BytecodeAssembler>>isLabel: (in category 'testing') -----
isLabel: aMessageOrLookupKey
+ ^aMessageOrLookupKey isAssociation!
- ^aMessageOrLookupKey isVariableBinding!
Item was changed:
----- Method: BytecodeAssemblerTests>>testAsAssemblerFor: (in category 'test support') -----
testAsAssemblerFor: aMethod
"self new testAsAssemblerFor: self >> #testAsAssemblerFor:"
| assemblerMethod assembler reassembledMethod |
assemblerMethod := BytecodeDisassembler new disassemble: aMethod.
assembler := String streamContents: [:s| assemblerMethod printAsAssemblerOn: s].
self shouldnt: [reassembledMethod := Compiler evaluate: assembler]
raise: Error.
self assert: assemblerMethod compiledMethodClass equals: reassembledMethod compiledMethodClass.
self assert: assemblerMethod flag equals: reassembledMethod flag.
self assert: assemblerMethod frameSize equals: reassembledMethod frameSize.
self assert: assemblerMethod methodClass equals: reassembledMethod methodClass.
self assert: assemblerMethod numArgs equals: reassembledMethod numArgs.
self assert: assemblerMethod numTemps equals: reassembledMethod numTemps.
self assert: assemblerMethod primitive equals: reassembledMethod primitive.
self assert: assemblerMethod selector equals: reassembledMethod selector.
self assert: assemblerMethod signFlag equals: reassembledMethod signFlag.
1 to: reassembledMethod literals size - 1 "ignore methodClass literal" do:
[:i|
self assert: (assemblerMethod literals at: i)
equals: (reassembledMethod literals at: i)].
assemblerMethod instructions
ifNil: [self assert: reassembledMethod instructions isNil]
ifNotNil:
[:insts|
self assert: insts size equals: reassembledMethod instructions size.
"Nil the labels' values for analogousCodeTo: comparison below; the values
are usefully the bytecode pcs of the labels, but this fails the comparisons."
+ insts do: [:inst| (assemblerMethod isLabel: inst) ifTrue: [inst value: nil]].
- insts do: [:inst| inst isVariableBinding ifTrue: [inst value: nil]].
insts
with: reassembledMethod instructions
do: [:old :new|
+ (assemblerMethod isLabel: old)
- old isVariableBinding
ifTrue: [self assert: old key = new key]
ifFalse: [self assert: (old analogousCodeTo: new)]]].
self assert: aMethod equals: (BytecodeAssembler new assemble: reassembledMethod)!
Squeak-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]