Eliot Miranda uploaded a new version of MethodMassageCompatibility to project VM Maker:
http://source.squeak.org/VMMaker/MethodMassageCompatibility-eem.7.mcz
==================== Summary ====================
Name: MethodMassageCompatibility-eem.7
Author: eem
Time: 20 July 2021, 8:40:31.958885 pm
UUID: 912fb668-9e12-4c8a-905e-04fbbb4cf1b8
Ancestors: MethodMassageCompatibility-eem.6
isCompiledCode is now in base Squeak
=============== Diff against MethodMassageCompatibility-eem.6 ===============
Item was removed:
- ----- Method: CompiledMethod>>isCompiledCode (in category '*MethodMassageCompatibility-accessing') -----
- isCompiledCode
- ^ true!
Eliot Miranda uploaded a new version of MethodMassage to project VM Maker:
http://source.squeak.org/VMMaker/MethodMassage-eem.55.mcz
==================== Summary ====================
Name: MethodMassage-eem.55
Author: eem
Time: 24 February 2022, 9:56:47.863914 am
UUID: c7d36dd7-ebee-4be9-94eb-6e855cf6f166
Ancestors: MethodMassage-eem.54
Get AssemblerAbsentClassImport to compile in trunk.
Allow pushSpecialConstant:, which is present in more modern InstructionStream, to fall back on pushConstant: support in the emission code.
=============== Diff against MethodMassage-eem.54 ===============
Item was changed:
----- Method: AssemblerAbsentClassImport>>allInstVarNames (in category 'accessing') -----
allInstVarNames
+ ^instVars ifNil: [#()]!
- ^instVars!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>decompilerClass (in category 'compiling') -----
+ decompilerClass
+ "Answer a decompiler class appropriate for compiled methods of this class."
+
+ ^ self compilerClass decompilerClass!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>newCompiler (in category 'compiling') -----
+ newCompiler
+ "Answer a Compiler suitable for compiling this Behavior"
+ ^self compilerClass new parser: self newParser!
Item was changed:
----- Method: BytecodeDisassembler>>pushConstant: (in category 'instruction decoding') -----
pushConstant: aLiteral
instructions
at: thePC
put: ((method encoderClass literalIndexOfBytecodeAt: thePC in: method)
+ ifNil: [self error: 'literal not found']
- ifNil: [Message
- selector: #pushSpecialConstant:
- argument: aLiteral]
ifNotNil:
[:index|
Message
selector: #pushConstantAtIndex:
argument: index])!
Item was added:
+ BytecodeDisassembler subclass: #BytecodeDisassemblerToIdentifyImplicitLiterals
+ instanceVariableNames: ''
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'MethodMassage-Kernel'!
+
+ !BytecodeDisassemblerToIdentifyImplicitLiterals commentStamp: 'eem 9/17/2021 11:39' prior: 0!
+ A BytecodeDisassemblerToIdentifyImplicitLiterals is a variation on BytecodeDisassembler that identifies if a pushConstant: or send:super:numArgs: is either an implciit literal bytecode or a special selector send. Newer versions of the interpretNextInstructionFor:in: scanners send pushSpecialConstant: and sendSpecial:numArgs: for these, meaning that no work is required. Older versions do not. This class is to cope with those older versions.
+
+ Instance Variables
+ !
Item was added:
+ ----- Method: BytecodeDisassemblerToIdentifyImplicitLiterals>>pushConstant: (in category 'instruction decoding') -----
+ pushConstant: aLiteral
+ instructions
+ at: thePC
+ put: ((method encoderClass literalIndexOfBytecodeAt: thePC in: method)
+ ifNil: [Message
+ selector: #pushSpecialConstant:
+ argument: aLiteral]
+ ifNotNil:
+ [:index|
+ Message
+ selector: #pushConstantAtIndex:
+ argument: index])!
Item was changed:
----- Method: BytecodeEmitter>>pushSpecialConstant: (in category 'assembly') -----
+ pushSpecialConstant: aLiteral
+ "rubbish way of handling special literals"
+ ^([encoder genPushSpecialLiteral: aLiteral]
+ on: Error
+ do: [:ex| ex return: nil])
+ ifNotNil: [:result| result]
+ ifNil: [encoder genPushLiteral: (encoder litIndex: aLiteral)]!
- pushSpecialConstant: aLiteral
- ^encoder genPushSpecialLiteral: aLiteral!
Item was changed:
----- Method: BytecodeSizer>>pushSpecialConstant: (in category 'assembly') -----
+ pushSpecialConstant: aLiteral
+ ^(encoder sizePushSpecialLiteral: aLiteral)
+ ifNotNil: [:size| size]
+ ifNil: [encoder sizePushLiteral: (encoder litIndex: aLiteral)]!
- pushSpecialConstant: aLiteral
- ^encoder sizePushSpecialLiteral: aLiteral!
Eliot Miranda uploaded a new version of MethodMassage to project VM Maker:
http://source.squeak.org/VMMaker/MethodMassage-eem.54.mcz
==================== Summary ====================
Name: MethodMassage-eem.54
Author: eem
Time: 21 July 2021, 9:21:51.551737 am
UUID: d57514ae-00cd-46a3-a83a-8d690b0e262c
Ancestors: MethodMassage-eem.53
Extend the AssemblerAbsentClassImport scheme to support disassembler annotations in current in-image compilation. Allow an AssemblerMethod to specify its source and the class's inst var names (AssemblerMethod>>assemblerStringForAbsentImport).
=============== Diff against MethodMassage-eem.53 ===============
Item was changed:
Object subclass: #AssemblerAbsentClassImport
+ instanceVariableNames: 'className instVars'
- instanceVariableNames: 'className'
classVariableNames: ''
poolDictionaries: ''
category: 'MethodMassage-Kernel'!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>allInstVarNames (in category 'accessing') -----
+ allInstVarNames
+ ^instVars!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>bindingOf:environment: (in category 'compiling') -----
+ bindingOf: aSymbol environment: anEnvironment
+ ^anEnvironment bindingOf: aSymbol!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>compilerClass (in category 'compiling') -----
+ compilerClass
+ "Answer a compiler class appropriate for source methods of this class."
+
+ ^Compiler!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>instSize (in category 'accessing') -----
+ instSize
+ ^instVars basicSize "answers 0 for nil"!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>instVarNames (in category 'accessing') -----
+ instVarNames
+
+ ^instVars!
Item was changed:
----- Method: AssemblerAbsentClassImport>>instVarNamesAndOffsetsDo: (in category 'compiling') -----
instVarNamesAndOffsetsDo: aBinaryBlock
"This is part of the interface between the compiler and a class's instance or field names.
The class should enumerate aBinaryBlock with the instance variable name strings and
their integer offsets. The order is important. Names evaluated later will override the
same names occurring earlier."
+ instVars ifNotNil:
+ [instVars withIndexDo: aBinaryBlock]!
- "Nothing to do here; We assume Context et al are present."
- ^self!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>instVars (in category 'accessing') -----
+ instVars
+
+ ^instVars!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>instVars: (in category 'accessing') -----
+ instVars: anArray
+
+ instVars := anArray!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>isAbsentClass (in category 'testing') -----
+ isAbsentClass
+ ^true!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>newParser (in category 'compiling') -----
+ newParser
+ "Answer a Parser suitable for parsing source code in this Behavior"
+ ^self parserClass new!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>parserClass (in category 'compiling') -----
+ parserClass
+ "Answer a parser class to use for parsing method headers."
+
+ ^self compilerClass parserClass!
Item was added:
+ ----- Method: AssemblerAbsentClassImport>>variablesAndOffsetsDo: (in category 'compiling') -----
+ variablesAndOffsetsDo: aBinaryBlock
+ "This is the interface between the compiler and a class's instance or field names. The
+ class should enumerate aBinaryBlock with the field definitions (with nil offsets) followed
+ by the instance variable name strings and their integer offsets (1-relative). The order is
+ important; names evaluated later will override the same names occurring earlier."
+
+ instVars ifNotNil:
+ [instVars withIndexDo: aBinaryBlock]!
Item was changed:
Object subclass: #AssemblerMethod
+ instanceVariableNames: 'literals instructions numArgs numTemps frameSize primitive flag signFlag noCountersFlag accessModifier trailer methodClass selector compiledMethodClass fixLabels encoder header initialPC endPC source allInstVars instVars'
- instanceVariableNames: 'literals instructions numArgs numTemps frameSize primitive flag signFlag noCountersFlag accessModifier trailer methodClass selector compiledMethodClass fixLabels encoder header initialPC endPC'
classVariableNames: 'AccessorGetters AccessorSetters VerifierGetters VerifierSetters'
poolDictionaries: ''
category: 'MethodMassage-Kernel'!
!AssemblerMethod commentStamp: 'eem 3/24/2017 08:26' prior: 0!
An AssemblerMethod is a holder for a sequence of literals and a sequence of instructions which can represent a disassembled method, or a method being assembled. AssemblerMethod supports three modes of operation.
The first mode is transcription, CompiledMethod -> AssemblerMethod -> CompiledMethod.
e.g.
| original "CompiledMethod"
assembler "AssemblerMethod"
replica "CompiledMethod" |
original := Object >> #printOn:.
assembler := original disassemble.
replica := assembler assemble.
self assert: original = replica
The second mode is to construct an AssemblerMethod and assemble it. e.g.
EncoderForSistaV1 assembler
pushReceiver;
trapIfNotInstanceOf: {SmallInteger. Character. LargePositiveInteger. LargeNegativeInteger.
Integer. Fraction. Magnitude};
pushReceiver;
methodReturnTop;
assemble
AssemblerMethod new
methodClass: Object;
selector: #printOn:;
numArgs: 1;
numTemps: 2;
pushReceiver;
send: #class;
send: #name;
popIntoTemporaryVariable: 1;
pushTemporaryVariable: 0;
doDup;
pushTemporaryVariable: 1;
send: #first;
send: #isVowel;
jump: 'L1' if: false;
pushConstant: 'an ';
jump: 'L2';
label: 'L1';
pushConstant: 'a ';
label: 'L2';
send: #nextPutAll:;
doPop;
pushTemporaryVariable: 1;
send: #nextPutAll:;
doPop;
methodReturnReceiver;
assemble
A third mode, useful for storage, inter-image transporation ,etc, is AssemblerMethod -> executable string -> AssemblerMethod.
e.g.
| original "CompiledMethod"
assembler "AssemblerMethod"
assemblerText "String"
replica "CompiledMethod" |
original := Object >> #printOn:.
assembler := original disassemble.
assemblerText := assembler assemblerString.
replica := (Compiler evaluate: assemblerText) assemble.
self assert: original = replica
Instance Variables
accessModifier: <nil|0,1,2,3>
compiledMethodClass: <nil|CompiledCode>
encoder: <BytecodeEncoder>
endPC: <nil|Integer>
fixLabels: <UndefinedObject|Boolean>
flag: <Boolean>
frameSize: <Integer>
header: <nil|Integer>
initialPC: <nil|Integer>
instructions: <SequenceableCollection>
literals: <SequenceableCollection>
methodClass: <Behavior>
noCountersFlag: <nil|Boolean>
numArgs: <Integer>
numTemps: <Integer>
primitive: <Integer>
signFlag: <Boolean>
trailer: <CompiledMethodTrailer>
accessModifier
- if not nil this is the values of the two bits of flags that specify Newspeak access control in the method header
compiledMethodClass
- if not nil this is the class to use to create a method from this assembly
encoder
- the encoder to use to encode literals during assembly
endPC
- this is the expected endPC of the resulting method. If not nil it will be checked against the actual endPC
fixLabels
- if nil, the AssemblerMethod is being used in transcription mode and branch offsets should be integers.
if a boolean then it indicates whether instructions contains one or more instructions that need their branches fixing up.
flag
- the value of the method's header flag (see CompiledMethod>>flag)
frameSize
- the size of the method's frame (see CompiledMethod>>frameSize)
header
- this is the expected header of the resulting method. If not nil it will be checked against the actual header
initialPC
- this is the expected initialPC of the resulting method. If not nil it will be checked against the actual initialPC
instructions
- the sequence of Message and LookupKey objects making up the method's instructions
literals
- the sequence of objects making up the method's literals
methodClass
- the target class for the method (see CompiledMethod>>methodClass)
noCountersFlag
- if not nil this is the value of the Sista JIT-without-performance-counters flag
numArgs
- the method's argument count (see CompiledMethod>>numArgs)
numTemps
- the method's temporary count (see CompiledMethod>>numTemps)
primitive
- the method's primitive (see CompiledMethod>>primitive)
signFlag
- the value of the method's signFlag (see CompiledMethod>>signFlag)
trailer
- the method's trailer (see CompiledMethod>>trailer)
!
Item was changed:
----- Method: AssemblerMethod>>assemble (in category 'assembling') -----
assemble
+ | assembler method |
- | assembler |
assembler := BytecodeAssembler new.
encoder ifNotNil: [assembler encoder: encoder].
+ method := assembler assemble: self.
+ (instVars notNil and: [methodClass isAbsentClass]) ifTrue: [methodClass instVars: instVars].
+ source ifNotNil: [method properties at: #source put: source].
+ ^method!
- ^assembler assemble: self!
Item was added:
+ ----- Method: AssemblerMethod>>assemblerStringForAbsentImport (in category 'printing') -----
+ assemblerStringForAbsentImport
+ "Include all inst var names and source code, in case the class is not present."
+ ^String streamContents:
+ [:s|
+ self printAsAssemblerOn: s
+ appending:
+ [:stream|
+ stream crtab; nextPutAll: 'instVars: '; store: allInstVars; nextPut: $;.
+ source ifNotNil:
+ [:theSource|
+ stream crtab; nextPutAll: 'source: '; store: theSource; nextPut: $;]]]!
Item was added:
+ ----- Method: AssemblerMethod>>instVars (in category 'accessing') -----
+ instVars
+ ^instVars!
Item was added:
+ ----- Method: AssemblerMethod>>instVars: (in category 'accessing') -----
+ instVars: anArray
+ instVars := anArray!
Item was changed:
----- Method: AssemblerMethod>>printAsAssemblerOn: (in category 'printing') -----
printAsAssemblerOn: aStream
+ self printAsAssemblerOn: aStream appending: nil!
- aStream nextPut: $(; print: self class; nextPutAll: ' new'.
-
- self printAccessorsForAssemblyOn: aStream.
- self printVerifiersForAssemblyOn: aStream.
- self printLiteralsForAssemblyOn: aStream.
- self printInstructionsForAssemblyOn: aStream.
-
- aStream crtab; nextPutAll: #yourself; nextPut: $)!
Item was added:
+ ----- Method: AssemblerMethod>>printAsAssemblerOn:appending: (in category 'private') -----
+ printAsAssemblerOn: aStream appending: aBlockOrNil
+ aStream nextPut: $(; print: self class; nextPutAll: ' new'.
+
+ self printAccessorsForAssemblyOn: aStream.
+ self printVerifiersForAssemblyOn: aStream.
+ self printLiteralsForAssemblyOn: aStream.
+ self printInstructionsForAssemblyOn: aStream.
+
+ aBlockOrNil ifNotNil: [:aBlock| aBlock value: aStream].
+
+ aStream crtab; nextPutAll: #yourself; nextPut: $)!
Item was changed:
----- Method: AssemblerMethod>>recordVerificationInfoFrom: (in category 'initialize-release') -----
recordVerificationInfoFrom: aMethod
"Record header, initialPC and endPC from aMethod for checking."
header := aMethod header.
endPC := aMethod endPC.
+ initialPC := aMethod initialPC.
+ source := aMethod sourcePointer ~= 0
+ ifTrue: [aMethod getSourceFromFile asString]
+ ifFalse: [aMethod properties at: #source ifAbsent: nil].
+ allInstVars := aMethod methodClass allInstVarNames!
- initialPC := aMethod initialPC!
Item was added:
+ ----- Method: AssemblerMethod>>source (in category 'accessing') -----
+ source
+ ^source!
Item was added:
+ ----- Method: AssemblerMethod>>source: (in category 'accessing') -----
+ source: aString
+ source := aString!
Item was added:
+ ----- Method: Behavior>>isAbsentClass (in category '*MethodMassage-testing') -----
+ isAbsentClass
+ ^false!