!AColorSelectorMorph commentStamp: 'gvc 5/18/2007 13:52'! ColorComponentSelector showing an alpha gradient over a hatched background.! !AColorSelectorMorph methodsFor: 'initialization' stamp: 'gvc 9/26/2006 11:54'! initialize "Initialize the receiver." super initialize. self value: 1.0; color: Color black! ! !AColorSelectorMorph methodsFor: 'drawing' stamp: 'gvc 9/19/2006 14:28'! drawOn: aCanvas "Draw a hatch pattern first." aCanvas fillRectangle: self innerBounds fillStyle: (InfiniteForm with: self hatchForm). super drawOn: aCanvas ! ! !AColorSelectorMorph methodsFor: '*Athens-Morphic' stamp: 'NicolaiHess 1/6/2015 18:11'! drawOnAthensCanvas: anAthensCanvas anAthensCanvas setPaint: (InfiniteForm with: self hatchForm). anAthensCanvas drawShape: self innerBounds. super drawOnAthensCanvas: anAthensCanvas! ! !AColorSelectorMorph methodsFor: 'protocol' stamp: 'gvc 9/3/2009 13:43'! defaultFillStyle "Answer the hue gradient." ^(GradientFillStyle colors: {self color alpha: 0. self color}) origin: self topLeft; direction: (self bounds isWide ifTrue: [self width@0] ifFalse: [0@self height])! ! !AColorSelectorMorph methodsFor: 'visual properties' stamp: 'gvc 9/19/2006 15:46'! fillStyle: fillStyle "If it is a color then override with gradient." fillStyle isColor ifTrue: [self color: fillStyle] ifFalse: [super fillStyle: fillStyle]! ! !AColorSelectorMorph methodsFor: 'accessing' stamp: 'gvc 9/3/2009 13:43'! color: aColor "Set the gradient colors." super color: aColor asNontranslucentColor. self fillStyle: self defaultFillStyle! ! !AColorSelectorMorph methodsFor: 'private' stamp: 'gvc 9/22/2006 09:17'! hatchForm "Answer a form showing a grid hatch pattern." ^ColorPresenterMorph hatchForm! ! !AGroupHasBeenAdded commentStamp: 'TorstenBergmann 2/4/2014 21:09'! Notify that a group has been added! !AGroupHasBeenAdded class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 4/14/2011 16:32'! group: aGroup into: anHolder ^ self group: aGroup from: anHolder! ! !AGroupHasBeenCreated commentStamp: 'TorstenBergmann 2/4/2014 21:09'! Notify that a group has been created! !AGroupHasBeenRegistered commentStamp: 'TorstenBergmann 2/4/2014 21:09'! Notify that a group has been registered! !AGroupHasBeenRegistered class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 4/14/2011 13:40'! with: aGroup ^ self new group: aGroup! ! !AGroupHasBeenRemoved commentStamp: 'TorstenBergmann 2/4/2014 21:10'! Notify that a group has been removed! !AGroupHasBeenRenamed commentStamp: 'TorstenBergmann 2/4/2014 21:10'! Notify that a group has been renamed! !AGroupHasBeenUnregistered commentStamp: 'TorstenBergmann 2/4/2014 21:10'! Notify that a group has been unregistered! !AGroupHasBeenUnregistered class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 4/14/2011 13:40'! with: aGroup ^ self new group: aGroup! ! !AJAlignmentInstruction commentStamp: ''! I am a pseudo instruction used to align the following instruction to a multiple of a given byte number. Example: asm := AJx64Assembler noStackFrame. "align the following instruction to a word (2bytes)" asm alignWord. asm inc: asm RAX. "align the following instruction to a double (4bytes)" asm alignDouble. asm inc: asm RAX. "align the following instruction to a QuadWord (8bytes)" asm alignQuad. asm inc: asm RAX. "align the following instruction to a multiple of an arbirary count" asm align: 64. asm inc: asm RAX.! !AJAlignmentInstruction methodsFor: 'alignment' stamp: 'CamilloBruni 4/12/2012 13:50'! alignDouble self align: 4! ! !AJAlignmentInstruction methodsFor: 'alignment' stamp: 'CamilloBruni 4/12/2012 13:50'! alignQuad self align: 8! ! !AJAlignmentInstruction methodsFor: 'accessing' stamp: 'MarcusDenker 12/12/2014 12:21'! printSelfOn: aStream self align <= 1 ifTrue: [ ^ self ]. aStream nextPut: $|. self align <= 8 ifTrue: [ self align timesRepeat: [ aStream nextPutAll: '----|']] ifFalse: [ aStream nextPutAll: (self align asString padLeftTo: 4 with: $ ); nextPut: $|]! ! !AJAlignmentInstruction methodsFor: 'initialization' stamp: ''! initialize super initialize. self alignByte.! ! !AJAlignmentInstruction methodsFor: 'visitor' stamp: 'CamilloBruni 4/12/2012 13:38'! accept: anObject self shouldBeImplemented ! ! !AJAlignmentInstruction methodsFor: 'alignment' stamp: 'CamilloBruni 4/12/2012 13:50'! alignWord self align: 2! ! !AJAlignmentInstruction methodsFor: 'emitting code' stamp: 'CamilloBruni 4/12/2012 13:44'! emitCode: asm | padding | padding := self paddingForPosition: position. "new machine code: | padding |" machineCode := ByteArray new: padding .! ! !AJAlignmentInstruction methodsFor: 'accessing' stamp: ''! align ^ alignTo! ! !AJAlignmentInstruction methodsFor: 'alignment' stamp: 'CamilloBruni 4/12/2012 13:50'! alignByte self align: 1! ! !AJAlignmentInstruction methodsFor: 'emitting code' stamp: 'CamilloBruni 4/12/2012 13:50'! paddingForPosition: aPositionNumber | padding | padding := aPositionNumber \\ self align. padding = 0 ifFalse: [ padding := self align - padding ]. ^ padding! ! !AJAlignmentInstruction methodsFor: 'accessing' stamp: 'CamilloBruni 4/12/2012 13:56'! name ^ String streamContents: [ :s| self printSelfOn: s]! ! !AJAlignmentInstruction methodsFor: 'accessing' stamp: ''! align: bytesSize "align the data to the given byte count" alignTo := bytesSize! ! !AJAlignmentInstruction class methodsFor: 'instance creation' stamp: ''! alignDouble ^ self new alignDouble! ! !AJAlignmentInstruction class methodsFor: 'instance creation' stamp: ''! alignQuad ^ self new alignQuad! ! !AJAlignmentInstruction class methodsFor: 'instance creation' stamp: 'CamilloBruni 4/12/2012 13:50'! align: byteSize ^ self new align: byteSize! ! !AJAlignmentInstruction class methodsFor: 'instance creation' stamp: ''! alignWord ^ self new alignWord! ! !AJAssembler commentStamp: 'TorstenBergmann 1/30/2014 09:08'! Common superclass for assemblers. Add a subclass for each specific processor architecures (x86, ...) ! !AJBaseReg commentStamp: 'MartinMcClure 1/27/2013 09:59'! AJBaseReg -- abstract superclass of all register operands. Instance Variables: size Width in bytes (1, 2, 4, 8...) code Non-negative integer, encoding varies with subclass. For AJx86GPRegisters, ten bits: xyttttnnnn where nnnn is the register number 0-15, tttt is the "type", which encodes size as a power of 2. Higher types are used in other subclasses. If y is 1, REX prefix is required to encode this register. If x is 1, this register cannot be used when any REX prefix is present in the instruction. name Name by which this register may be referenced in instructions! !AJBaseReg methodsFor: 'accessing' stamp: ''! code "Answer the value of code" ^ code! ! !AJBaseReg methodsFor: 'accessing' stamp: ''! index ^ code bitAnd: RegCodeMask! ! !AJBaseReg methodsFor: 'comparing' stamp: ''! hash ^ code hash! ! !AJBaseReg methodsFor: 'accessing' stamp: ''! code: anObject "Set the value of code" code := anObject! ! !AJBaseReg methodsFor: 'accessing' stamp: 'CamilloBruni 7/17/2012 11:07'! description ^ String streamContents: [ :s | self descriptionOn: s ].! ! !AJBaseReg methodsFor: 'accessing' stamp: ''! size ^ size! ! !AJBaseReg methodsFor: 'private' stamp: 'CamilloBruni 10/17/2012 15:54'! basicAnnotation: anObject "private setter" annotation := anObject! ! !AJBaseReg methodsFor: 'initialize-release' stamp: 'MartinMcClure 1/27/2013 09:35'! initializeWithCode: aRegisterCode name: aSymbol super initialize. self code: aRegisterCode. "Also sets size" name := aSymbol! ! !AJBaseReg methodsFor: 'accessing' stamp: 'CamilloBruni 7/17/2012 11:24'! influencingRegisters ^ #()! ! !AJBaseReg methodsFor: 'accessing' stamp: 'CamilloBruni 10/17/2012 15:54'! annotation: anObject "registers gereally are used as single instances, hence putting an annotation on the default register will change the annotation for all the users. To avoid that, the receiver is copied first" ^ self copy basicAnnotation: anObject; yourself! ! !AJBaseReg methodsFor: 'comparing' stamp: ''! = otherReg ^ (self class == otherReg class) and: [ code = otherReg code ]! ! !AJBaseReg methodsFor: 'printing' stamp: 'CamilloBruni 7/17/2012 11:07'! descriptionOn: aStream self subclassResponsibility! ! !AJBaseReg methodsFor: 'accessing' stamp: 'CamilloBruni 4/17/2012 17:59'! type ^ code bitAnd: RegTypeMask! ! !AJBaseReg methodsFor: 'testing' stamp: ''! isGeneralPurpose self subclassResponsibility ! ! !AJBaseReg methodsFor: 'testing' stamp: ''! isUpperBank "Used for emitting the REX Prefix Byte on 64bit machines" ^ self index > 7! ! !AJBaseReg methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 15:34'! isX86 self subclassResponsibility! ! !AJBaseReg methodsFor: 'accessing' stamp: ''! name ^ name! ! !AJBaseReg methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 16:04'! requiresRex "Answer true if use of this register requires that the instruction have a REX prefix. This can be because the register cannot be accessed except with REX (high bank or 64-only low byte) or because the register is 64-bits wide" ^(code & RegRequiresRexMask) ~~ 0! ! !AJBaseReg methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 16:04'! prohibitsRex "Answer true if this register cannot be used in any instruction that has a REX prefix. Of the general-purpose registers, this is true only of SPL, BPL, SIL, DIL." ^ (code & RegProhibitsRexMask) ~~ 0! ! !AJBaseReg class methodsFor: 'instance creation' stamp: ''! code: aRegisterCode name: aSymbol ^ self basicNew initializeWithCode: aRegisterCode name: aSymbol! ! !AJCallArgument commentStamp: 'TorstenBergmann 2/4/2014 21:38'! Argument for a call! !AJCallArgument methodsFor: 'accessing' stamp: ''! size: aSmallInteger size := aSmallInteger! ! !AJCallArgument methodsFor: 'accessing' stamp: ''! size ^ size ! ! !AJCallArgument methodsFor: 'accessing' stamp: ''! instructionName ^ #push! ! !AJCallArgument methodsFor: 'visitor' stamp: ''! accept: anObject ^ anObject visitCallArgument: self ! ! !AJCallArgument methodsFor: 'function calls' stamp: ''! prepareCallAlignments callInfo noticeArgument: self ! ! !AJCallArgument methodsFor: 'accessing' stamp: ''! stackOffset: anOffset stackOffset := anOffset ! ! !AJCallArgument methodsFor: 'accessing' stamp: ''! name ^ 'argument push:'! ! !AJCallCleanup commentStamp: 'TorstenBergmann 2/4/2014 21:38'! Cleanup for calls! !AJCallCleanup methodsFor: 'accessing' stamp: ''! name ^ 'call cleanup'! ! !AJCallCleanup methodsFor: 'visitor' stamp: ''! accept: anObject ^ anObject visitCallCleanup: self! ! !AJCallCleanup methodsFor: 'function calls' stamp: ''! prepareCallAlignments callInfo callCleanup: self ! ! !AJCallInfo commentStamp: 'TorstenBergmann 2/4/2014 21:36'! Infos for a call! !AJCallInfo methodsFor: 'accessing' stamp: ''! callCleanup: aCallCleanup self assert: callCleanup isNil. callCleanup := aCallCleanup ! ! !AJCallInfo methodsFor: 'accessing' stamp: ''! defaultArgumentSize self subclassResponsibility ! ! !AJCallInfo methodsFor: 'accessing' stamp: ''! stackSize: anObject stackSize := anObject! ! !AJCallInfo methodsFor: 'accessing' stamp: ''! noCleanup ^ noCleanup ! ! !AJCallInfo methodsFor: 'accessing' stamp: ''! alignmentInsertionPoint: instruction alignInsertionPoint := instruction! ! !AJCallInfo methodsFor: 'accessing' stamp: ''! noticeArgument: aCallArgument arguments add: aCallArgument. stackSize := stackSize + aCallArgument size.! ! !AJCallInfo methodsFor: 'accessing' stamp: ''! asm: assembler asm := assembler! ! !AJCallInfo methodsFor: 'accessing' stamp: ''! stackSize ^ stackSize! ! !AJCallInfo methodsFor: 'initialization' stamp: ''! initialize arguments := OrderedCollection new. stackSize := 0. stackAlignment := 1. noCleanup := false.! ! !AJCallInfo methodsFor: 'testing' stamp: ''! needsAlignment ^ stackAlignment > 1! ! !AJCallInfo methodsFor: 'accessing' stamp: ''! disableCleanup noCleanup := true! ! !AJCallInfo methodsFor: 'pushing args' stamp: ''! push: anArgument asm pushArgument: anArgument forCall: self. ! ! !AJCallInfo methodsFor: 'accessing' stamp: ''! name ^ 'call info' ! ! !AJCallInfo methodsFor: 'accessing' stamp: ''! alignment: aStackAlignment stackAlignment := aStackAlignment ! ! !AJCdeclCallInfo commentStamp: 'TorstenBergmann 2/4/2014 21:37'! Infos for a class according to Cdecl spec! !AJCdeclCallInfo methodsFor: 'accessing' stamp: ''! defaultArgumentSize ^ 4! ! !AJCdeclCallInfo methodsFor: 'emitting code' stamp: 'CamilloBruni 3/29/2012 14:01'! alignedCleanup asm mov: savedSP to: asm ESP. asm releaseTemps: 1 "release our temp afterwards" ! ! !AJCdeclCallInfo methodsFor: 'emitting code' stamp: ''! normalCleanup stackSize > 0 ifTrue: [ asm add: asm ESP with: stackSize ]! ! !AJCdeclCallInfo methodsFor: 'emitting code' stamp: 'CamilloBruni 4/4/2012 16:57'! emitAlignmentIfNeeded | alignment | self needsAlignment ifTrue: [ ^ self emitAlignment ]. self emitCleanup! ! !AJCdeclCallInfo methodsFor: 'emitting code' stamp: 'CamilloBruni 7/23/2012 13:29'! emitAlignment | instructions | instructions := asm instructionsFor: [ asm decorateWith: 'align stack' during: [ savedSP := asm reserveTemp annotation: 'saved SP'. asm mov: asm ESP to: savedSP. stackSize > 0 ifTrue: [ asm sub: asm ESP with: (stackSize asUImm annotation: 'stack size') ]. asm and: asm ESP with: stackAlignment - 1; neg: asm ESP; add: asm ESP with: savedSP ] ]. asm insert: instructions after: alignInsertionPoint. self emitCleanup! ! !AJCdeclCallInfo methodsFor: 'emitting code' stamp: ''! emitCleanup noCleanup ifTrue: [ ^ self ]. asm insert: ( asm instructionsFor: [ self needsAlignment ifTrue: [ self alignedCleanup ] ifFalse: [ self normalCleanup ] ] ) after: callCleanup! ! !AJConstants commentStamp: 'TorstenBergmann 1/30/2014 08:58'! A shared pool for constants from AsmJIT! !AJConstants class methodsFor: 'initialization' stamp: 'MartinMcClure 1/27/2013 15:13'! initialize "AJConstants initialize" "Operand is none, used only internally." OpNONE := 0. "Operand is register" OpREG := 1. "Operand is memory" OpMem := 2. "Operand is immediate." OpImm := 3. "Operand is label. " OpLabel := 4. RegTypeMask := 16rF0. RegCodeMask := 16r0F. RegRequiresRexMask := 16r100. RegProhibitsRexMask := 16r200. RegHighByteMask := 2r111100. "1 byte size." SizeByte := 1. "2 bytes size." SizeWord := 2. "4 bytes size." SizeDWord := 4. "8 bytes size." SizeQWord := 8. "10 bytes size." SizeTWord := 10. "16 bytes size." SizeDQWord := 16. "ID for AX/EAX/RAX registers." RIDEAX := 0. "ID for CX/ECX/RCX registers." RIDECX := 1. "ID for DX/EDX/RDX registers." RIDEDX := 2. "ID for BX/EBX/RBX registers." RIDEBX := 3. "ID for SP/ESP/RSP registers." RIDESP := 4. "ID for BP/EBP/RBP registers." RIDEBP := 5. "ID for SI/ESI/RSI registers." RIDESI := 6. "ID for DI/EDI/RDI registers." RIDEDI := 7. "8 bit general purpose register type." RegGPB := 16r00. "16 bit general purpose register type." RegGPW := 16r10. "32 bit general purpose register type." RegGPD := 16r20. "64 bit general purpose register type. " RegGPQ := 16r30. "X87 (FPU) register type. " RegX87 := 16r50. "64 bit mmx register type." RegMM := 16r60. "128 bit sse register type." RegXMM := 16r70. "Segment override prefixes." "No segment override prefix." SegmentNONE := 0. "Use 'cs' segment override prefix." SegmentCS := 1. "Use 'ss' segment override prefix." SegmentSS := 2. "Use 'ds' segment override prefix." SegmentDS := 3. "Use 'es' segment override prefix." SegmentES := 4. "Use 'fs' segment override prefix." SegmentFS := 5. "Use 'gs' segment override prefix." SegmentGS := 6. self initializePrefetchHints. self initializeConditionCodes. self initOpCodes. ! ! !AJConstants class methodsFor: 'initialization' stamp: ''! initializePrefetchHints "Prefetch hints." "Prefetch to L0 cache." PrefetchT0 := 1. "Prefetch to L1 cache." PrefetchT1 := 2. "Prefetch to L2 cache." PrefetchT2 := 3. "Prefetch using NT hint." PrefetchNTA := 0. ! ! !AJConstants class methodsFor: 'initialization' stamp: ''! initializeConditionCodes "Condition codes." "No condition code." CcNOCONDITION := -1. "Condition codes from processor manuals." CcA := 16r7. CcAE := 16r3. CcB := 16r2. CcBE := 16r6. CcC := 16r2. CcE := 16r4. CcG := 16rF. CcGE := 16rD. CcL := 16rC. CcLE := 16rE. CcNA := 16r6. CcNAE := 16r2. CcNB := 16r3. CcNBE := 16r7. CcNC := 16r3. CcNE := 16r5. CcNG := 16rE. CcNGE := 16rC. CcNL := 16rD. CcNLE := 16rF. CcNO := 16r1. CcNP := 16rB. CcNS := 16r9. CcNZ := 16r5. CcO := 16r0. CcP := 16rA. CcPE := 16rA. CcPO := 16rB. CcS := 16r8. CcZ := 16r4. " Simplified condition codes" CcOVERFLOW := 16r0. CcNOOVERFLOW := 16r1. CcBELOW := 16r2. CcABOVEEQUAL := 16r3. CcEQUAL := 16r4. CcNOTEQUAL := 16r5. CcBELOWEQUAL := 16r6. CcABOVE := 16r7. CcSIGN := 16r8. CcNOTSIGN := 16r9. CcPARITYEVEN := 16rA. CcPARITYODD := 16rB. CcLESS := 16rC. CcGREATEREQUAL := 16rD. CcLESSEQUAL := 16rE. CcGREATER := 16rF. "aliases" CcZERO := 16r4. CcNOTZERO := 16r5. CcNEGATIVE := 16r8. CcPOSITIVE := 16r9. "x87 floating point only" CcFPUNORDERED := 16. CcFPNOTUNORDERED := 17. ! ! !AJConstants class methodsFor: 'initialization' stamp: 'CamilloBruni 3/29/2012 13:49'! initOpCodes " x86 " OG8 := 16r01. OG16 := 16r02. OG32 := 16r04. OG64 := 16r08. OMEM := 16r40. OIMM := 16r80. O64Only := 16r100. OG8163264 := OG64 + OG32 + OG16 + OG8. OG163264 := OG64 + OG32 + OG16. OG3264 := OG64 + OG32. " x87" OFM1 := 16r01. OFM2 := 16r02. OFM4 := 16r04. OFM8 := 16r08. OFM10 := 16r10. OFM24 := OFM2 + OFM4. OFM248 := OFM2 + OFM4 + OFM8. OFM48 := OFM4 + OFM8. OFM4810 := OFM4 + OFM8 + OFM10. " mm|xmm" ONOREX := 16r01. " Used by MMX/SSE instructions. OG8 is never used for them " OMM := 16r10. OXMM := 16r20. OMMMEM := OMM + OMEM. OXMMMEM := OXMM + OMEM. OMMXMM := OMM + OXMM. OMMXMMMEM := OMM + OXMM + OMEM.! ! !AJData commentStamp: ''! I represent a pure data section in an assembly instruction stream. Example: asm := AJx64Assembler noStackFrame. "add a raw byte" asm db: 16rFF. "add a raw word" asm dw: #[16r34 16r12]. "add a raw double" asm dw: #[16r78 16r56 16r34 16r12]. "add a arbitrary sized data section with a byteArray" asm data: #[1 2 3 4 5 6 7 8 9 10 11 12 ].! !AJData methodsFor: 'accessing' stamp: 'CamilloBruni 4/12/2012 14:22'! data: aByteArray "the will be put in the executable." machineCode := aByteArray! ! !AJData methodsFor: 'testing' stamp: ''! is16 ^ self size = 2! ! !AJData methodsFor: 'accessing' stamp: ''! size ^ self data size! ! !AJData methodsFor: 'visitor' stamp: ''! accept: anObject anObject instructionData: self! ! !AJData methodsFor: 'accessing' stamp: 'CamilloBruni 4/12/2012 14:22'! data ^ machineCode! ! !AJData methodsFor: 'emitting code' stamp: 'CamilloBruni 4/12/2012 14:22'! emitCode: asm machineCode ifNil: [ machineCode := #[] ]! ! !AJData methodsFor: 'testing' stamp: ''! is32 ^ self size = 4! ! !AJData methodsFor: 'testing' stamp: ''! is8 ^ self size = 1! ! !AJData methodsFor: 'testing' stamp: ''! is64 ^ self size = 8! ! !AJData methodsFor: 'accessing' stamp: ''! name name ifNotNil: [ ^ name ]. "standard data sections" self is8 ifTrue: [ ^ 'db' ]. self is16 ifTrue: [ ^ 'dw' ]. self is32 ifTrue: [ ^ 'dd' ].! ! !AJData class methodsFor: 'instance creation' stamp: ''! data: aDataByteArray ^ self new data: aDataByteArray; yourself! ! !AJData class methodsFor: 'instance creation' stamp: ''! byte: aByteValue ^ self data: (ByteArray with: aByteValue)! ! !AJData class methodsFor: 'instance creation' stamp: ''! label: aLabel data: aDataByteArray ^ self new label: aLabel; data: aDataByteArray; yourself! ! !AJGeneratedCode commentStamp: 'TorstenBergmann 1/30/2014 09:09'! Instances of this class include the bytes and labels generated by AsmJIT |asm| asm := AJx64Assembler noStackFrame. asm neg: asm AL. asm ret. asm generatedCode ! !AJGeneratedCode methodsFor: 'initialization' stamp: ''! initialize labels := Dictionary new. ! ! !AJGeneratedCode methodsFor: 'output' stamp: ''! saveToFile self saveToFile: 'asm.bin'! ! !AJGeneratedCode methodsFor: 'output' stamp: ''! dumpWithLabels "dump the native code , interspersed with labels" | offsets i str | offsets := OrderedCollection new. labels keysAndValuesDo: [ :name :offset | offsets add: (offset -> name) ]. offsets := offsets sort: [:a :b | a key < b key ]. str := String new writeStream. i := 0. offsets do: [:offset | i to: offset key -1 do: [:x | str nextPutAll: ((bytes at: i+1) printStringBase: 16 nDigits: 2) ; space. i:=i+1. ]. str cr; nextPutAll: offset value; cr. ]. i to: bytes size-1 do: [:x | str nextPutAll: ((bytes at: i+1) printStringBase: 16 nDigits: 2) ; space. i := i + 1] . ^ str contents! ! !AJGeneratedCode methodsFor: 'accessing' stamp: ''! bytes: aBytes bytes := aBytes ! ! !AJGeneratedCode methodsFor: 'initialize-release' stamp: 'CamilloBruni 4/4/2012 16:30'! fromInstructions: instructions bytes := ByteArray new: 100 streamContents: [:stream| instructions do: [ :each | each extractLabels: [:name :pos | labels at: name put: pos ]. each storeOn: stream ]].! ! !AJGeneratedCode methodsFor: 'printing' stamp: ''! printOn: aStream bytes notNil ifTrue: [ aStream nextPutAll: self dumpWithLabels ]! ! !AJGeneratedCode methodsFor: 'accessing' stamp: ''! bytes ^ bytes! ! !AJGeneratedCode methodsFor: 'accessing' stamp: ''! offsetAt: aLabelName ^ labels at: aLabelName! ! !AJGeneratedCode methodsFor: 'output' stamp: ''! saveToFile: fileName (FileStream forceNewFileNamed: fileName) nextPutAll: bytes; close ! ! !AJGeneratedCode methodsFor: 'accessing' stamp: ''! labels: aLabels "turn labels into a simple name->offset pairs" aLabels keysAndValuesDo: [:name :lbl | labels at: name put: lbl paddedOffset ]. ! ! !AJGeneratedCode class methodsFor: 'instance creation' stamp: 'CamilloBruni 7/25/2012 12:44'! fromInstructions: instructions ^ self new fromInstructions: instructions! ! !AJImmediate commentStamp: ''! I am an immediate (constant integer) operand used by the assembler. Example: "create an immediate from an integer" 1 asImm. "implicitely use an immediate in an assembly instrution" asm := AJx64Assembler new. asm add: 1 to: asm RAX. ! !AJImmediate methodsFor: 'testing' stamp: ''! isInt8 ^ size ifNil: [ self fitsInSize: 1 ] ifNotNil: [ size = 1 ]! ! !AJImmediate methodsFor: 'converting' stamp: 'CamilloBruni 4/4/2012 16:52'! asQWord "answer the 64bit word representing a value" (self fitsInSize: 8) ifFalse: [ Error signal: self asString, ' exceeds quadword (64bit) range' ]. (self isSigned and: [ value < 0 ]) ifTrue: [ ^ (1<<64) + value ]. ^ value! ! !AJImmediate methodsFor: 'emitting code' stamp: 'CamilloBruni 4/4/2012 16:53'! emitUsing: emitter size: aSize label ifNotNil: [ "this will set the label offset" emitter setLabelPosition: label. ]. aSize = 1 ifTrue: [ ^ emitter emitByte: self asByte ]. aSize = 2 ifTrue: [ ^ emitter emitWord: self asWord ]. aSize = 4 ifTrue: [ ^ emitter emitDWord: self asDWord ]. aSize = 8 ifTrue: [ ^ emitter emitQWord: self asQWord ]. self error: aSize asString, 'bytes is an invalid immediate value size'! ! !AJImmediate methodsFor: 'testing' stamp: 'CamilloBruni 4/4/2012 16:54'! fitsInSize: aSize | maxSize | maxSize := 1 << (aSize * 8). self isUnsigned ifTrue: [ ^ maxSize > value ]. value < 0 ifTrue: [ ^ 0 - value <= (maxSize >> 1) ]. ^ value < (maxSize>>1)! ! !AJImmediate methodsFor: 'converting' stamp: 'CamilloBruni 4/4/2012 16:52'! asDWord "answer the 32bit word representing a value" (self fitsInSize: 4) ifFalse: [ Error signal: self asString, ' exceeds doubleword (32bit) range' ]. (self isSigned and: [ value < 0 ]) ifTrue: [ ^ (1<<32) + value ]. ^ value! ! !AJImmediate methodsFor: 'testing' stamp: ''! isImm ^ true! ! !AJImmediate methodsFor: 'testing' stamp: ''! isSigned ^ isUnsigned not! ! !AJImmediate methodsFor: 'converting' stamp: ''! asByte "answer the byte representing a value" (self fitsInSize: 1) ifFalse: [ Error signal: self asString, ' exceeds byte (8bit) range' ]. (self isSigned and: [ value < 0 ]) ifTrue: [ ^ (1<<8) + value ]. ^ value! ! !AJImmediate methodsFor: 'initialization' stamp: ''! initialize value := 0. isUnsigned := false.! ! !AJImmediate methodsFor: 'accessing' stamp: ''! value ^ value! ! !AJImmediate methodsFor: 'accessing' stamp: ''! ivalue: aValue "signed integer value" value := aValue. isUnsigned := false.! ! !AJImmediate methodsFor: 'printing' stamp: 'CamilloBruni 10/5/2012 14:39'! printOn: aStream aStream nextPut: $(. self printAnnotationOn: aStream. value > 1000000 ifTrue: [ aStream nextPutAll: value hex] ifFalse: [ aStream print: value]. aStream space. aStream nextPut: ( self isSigned ifTrue: [ $i ] ifFalse: [ $u ]). size ifNotNil: [ aStream print: size]. aStream nextPut: $). ! ! !AJImmediate methodsFor: 'accessing' stamp: ''! label: aLabelName label := aLabelName! ! !AJImmediate methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 15:53'! requiresRex "Answer true if use of this operand requires that the instruction have a REX prefix." ^ false! ! !AJImmediate methodsFor: 'accessing' stamp: ''! uvalue: aValue "unsigned value" self assert: (aValue >=0). value := aValue. isUnsigned := true.! ! !AJImmediate methodsFor: 'testing' stamp: 'CamilloBruni 4/4/2012 16:54'! isInt32 ^ value >= -2147483648 and: [ value <= 2147483647 ] ! ! !AJImmediate methodsFor: 'converting' stamp: ''! asWord "answer the 16bit word representing a value" (self fitsInSize: 2) ifFalse: [ Error signal: self asString, ' value exceeds word (16bit) range' ]. (self isSigned and: [ value < 0 ]) ifTrue: [ ^ (1<<16) + value ]. ^ value! ! !AJImmediate methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 17:49'! prohibitsRex "Answer true if use of this operand requires that the instruction *not* have a REX prefix." ^ false! ! !AJImmediate methodsFor: 'accessing' stamp: ''! extractLabels: aBlock label ifNotNil: [ label extractLabels: aBlock ] ! ! !AJImmediate methodsFor: 'accessing' stamp: ''! size ^ size! ! !AJImmediate methodsFor: 'accessing' stamp: ''! sizeFor: anOperand "Check if I am a valid size to be used together with anOperand If so, I will use as much size as it" self assert: (self fitsInSize: anOperand size). ^anOperand size! ! !AJImmediate methodsFor: 'converting' stamp: 'IgorStasenko 5/28/2012 01:54'! ptr "turn receiver into a memory operand with absolute address == receiver" ^ AJMem new displacement: self! ! !AJImmediate methodsFor: '*NativeBoost-core' stamp: 'IgorStasenko 11/18/2012 16:49'! asNBExternalType: gen ^ NBFFIConst value: self! ! !AJImmediate methodsFor: 'testing' stamp: ''! isUnsigned ^ isUnsigned! ! !AJImmediate methodsFor: 'accessing' stamp: ''! size: aSize size := aSize! ! !AJImmediate methodsFor: 'accessing' stamp: ''! relocMode ^ relocMode ifNil: [#RelocNone ]! ! !AJImmediate methodsFor: 'testing' stamp: ''! isZero ^ value = 0! ! !AJImmediate class methodsFor: 'as yet unclassified' stamp: ''! ivalue: aValue ^ self new ivalue: aValue! ! !AJInstruction commentStamp: 'TorstenBergmann 1/30/2014 09:11'! Implement machine code instructions! !AJInstruction methodsFor: 'iterating' stamp: ''! last "answer the last instruction in the list" | nn l | nn := self. [ (l := nn next) notNil ] whileTrue: [ nn := l ]. ^ nn! ! !AJInstruction methodsFor: 'accessing' stamp: ''! insert: anInstructions | n | self halt. n := next. next := anInstructions. anInstructions do: [:each | each increaseLevel: level ]. anInstructions last next: n! ! !AJInstruction methodsFor: 'printing' stamp: 'MartinMcClure 11/26/2012 18:54'! printSelfOn: aStream self printAnnotationOn: aStream. aStream nextPutAll: (self name ). "padRightTo: 4)." self printOperandsOn: aStream. self printMachineCodeOn: aStream! ! !AJInstruction methodsFor: 'printing' stamp: ''! printStringLimitedTo: aNumber ^ String streamContents: [:s | self printOn: s] ! ! !AJInstruction methodsFor: 'testing' stamp: ''! isLabelUsed: anAJJumpLabel ^ false! ! !AJInstruction methodsFor: 'testing' stamp: ''! hasLabel self shouldBeImplemented.! ! !AJInstruction methodsFor: 'accessing' stamp: ''! next ^ next! ! !AJInstruction methodsFor: 'helpers' stamp: ''! find: aByteString self shouldBeImplemented.! ! !AJInstruction methodsFor: 'accessing' stamp: ''! level ^ level! ! !AJInstruction methodsFor: 'accessing' stamp: ''! position: anObject position := anObject! ! !AJInstruction methodsFor: 'accessing' stamp: ''! annotation ^ annotation! ! !AJInstruction methodsFor: 'accessing' stamp: ''! annotation: anObject annotation := anObject! ! !AJInstruction methodsFor: 'accessing' stamp: ''! increaseLevel: num level := level + num! ! !AJInstruction methodsFor: 'initialization' stamp: ''! initialize level := 0! ! !AJInstruction methodsFor: 'printing' stamp: 'CamilloBruni 7/16/2012 15:29'! printOperandsOn: aStream (operands notNil and: [operands isEmpty not]) ifTrue: [aStream space; nextPut: $(. operands do: [ :operand | operand printAsOperandOn: aStream] separatedBy: [aStream space]. aStream nextPut: $)]! ! !AJInstruction methodsFor: 'visitor' stamp: ''! accept: anObject self subclassResponsibility! ! !AJInstruction methodsFor: 'printing' stamp: 'CamilloBruni 7/16/2012 15:24'! printOn: aStream "[ ^self ] value." self printListOn: aStream asLineStream! ! !AJInstruction methodsFor: 'visitor' stamp: ''! setPrologue: anInstrucitons "do nothing"! ! !AJInstruction methodsFor: 'accessing' stamp: ''! machineCodeSize ^ machineCode ifNil: [ 0 ] ifNotNil: [ machineCode size ]! ! !AJInstruction methodsFor: 'emitting code' stamp: ''! emitCodeAtOffset: offset assembler: asm position := offset. self emitCode: asm. next ifNotNil: [ next emitCodeAtOffset: offset + self machineCodeSize assembler: asm ].! ! !AJInstruction methodsFor: 'helpers' stamp: 'MartinMcClure 1/27/2013 17:40'! checkOperandsForConflict "Subclasses may signal an error here."! ! !AJInstruction methodsFor: 'accessing' stamp: 'MartinMcClure 2/9/2013 14:30'! operands: anObject operands := anObject! ! !AJInstruction methodsFor: 'accessing' stamp: ''! operands ^ operands! ! !AJInstruction methodsFor: 'accessing' stamp: ''! extractLabels: aBlock operands ifNotNil: [ operands do: [:each | each extractLabels: aBlock ]]! ! !AJInstruction methodsFor: 'printing' stamp: ''! storeOn: aStream "store machine code to binary stream" machineCode ifNotNil: [ aStream nextPutAll: machineCode ]! ! !AJInstruction methodsFor: 'emitting code' stamp: ''! emitCode: asm machineCode := #[] ! ! !AJInstruction methodsFor: 'manipulating' stamp: ''! insert: newInstruction before: anInstruction "replace a single instruction with one or more other instructions" | instr anext | anInstruction == self ifTrue: [ newInstruction last next: self. ^ newInstruction ]. instr := self. [ (anext := instr next) notNil and: [ anext ~~ anInstruction ]] whileTrue: [ instr := anext ]. instr next ifNotNil: [ newInstruction do: [:each | each increaseLevel: instr level ]. newInstruction last next: instr next. instr next: newInstruction ]. ! ! !AJInstruction methodsFor: 'accessing' stamp: ''! next: anObject next := anObject! ! !AJInstruction methodsFor: 'printing' stamp: 'CamilloBruni 7/16/2012 15:27'! printListOn: aStream self printIndentOn: aStream. self printSelfOn: aStream. next ifNotNil: [ aStream cr. next printListOn: aStream ]! ! !AJInstruction methodsFor: 'accessing' stamp: ''! level: aLevel level := aLevel ! ! !AJInstruction methodsFor: 'manipulating' stamp: ''! replace: anInstruction with: otherInstructions "replace a single instruction with one or more other instructions" | instr | anInstruction == self ifTrue: [ otherInstructions last next: self next. ^ otherInstructions ]. instr := self. [ instr notNil and: [instr next ~~ anInstruction ]] whileTrue: [ instr := instr next ]. instr notNil ifTrue: [ otherInstructions last next: instr next next. instr next: otherInstructions ]. ! ! !AJInstruction methodsFor: 'accessing' stamp: ''! instructionName ^ name! ! !AJInstruction methodsFor: 'iterating' stamp: ''! do: aBlock "evaluate all instructions for the list" | nn | nn := self. [ nn notNil ] whileTrue: [ aBlock value: nn. nn := nn next. ].! ! !AJInstruction methodsFor: 'accessing' stamp: ''! name: anObject name := anObject! ! !AJInstruction methodsFor: 'accessing' stamp: ''! position ^ position! ! !AJInstruction methodsFor: 'function calls' stamp: ''! prepareCallAlignments "do nothing"! ! !AJInstruction methodsFor: 'printing' stamp: 'CamilloBruni 10/12/2012 11:40'! printMachineCodeOn: aStream (machineCode isNil or: [machineCode isEmpty]) ifTrue: [^ self]. aStream padColumn: 65; nextPutAll: '#['. machineCode do: [ :byte | byte printOn: aStream base: 16 length: 2 padded: true ] separatedBy: [ aStream space ]. aStream nextPut: $]! ! !AJInstruction methodsFor: 'printing' stamp: 'CamilloBruni 7/23/2012 16:44'! printIndentOn: aStream level ifNil: [ ^ self ]. level timesRepeat: [ aStream nextPutAll: '| ']! ! !AJInstruction methodsFor: 'visitor' stamp: ''! processTempsWith: anObject "do nothing"! ! !AJInstruction methodsFor: 'accessing' stamp: ''! name ^ name ifNil: ['undefined']! ! !AJInstruction methodsFor: 'printing' stamp: 'CamilloBruni 7/16/2012 15:33'! printAnnotationOn: aStream annotation ifNil: [^ self]. aStream nextPut: $"; nextPutAll: annotation asString; nextPut: $"; cr. self printIndentOn: aStream! ! !AJInstructionDecoration commentStamp: 'TorstenBergmann 1/30/2014 09:16'! Used to decorate instructions with annotations! !AJInstructionDecoration methodsFor: 'accessing' stamp: ''! end end := true! ! !AJInstructionDecoration methodsFor: 'printing' stamp: 'CamilloBruni 7/23/2012 16:42'! printSelfOn: aStream end ifFalse: [ aStream nextPutAll: '/ "' ] ifTrue: [ aStream nextPutAll: '\ "end ' ]. aStream nextPutAll: annotation; nextPut: $". ! ! !AJInstructionDecoration methodsFor: 'printing' stamp: 'CamilloBruni 7/23/2012 16:43'! printIndentOn: aStream end ifFalse: [ super printIndentOn: aStream. aStream cr ]. ^ super printIndentOn: aStream! ! !AJInstructionDecoration methodsFor: 'visitor' stamp: ''! accept: anObject anObject instructionDecoration: self! ! !AJInstructionDecoration methodsFor: 'accessing' stamp: ''! start end := false! ! !AJJumpInstruction commentStamp: 'TorstenBergmann 1/30/2014 09:12'! An assembler jump instruction including a jump label and a description! !AJJumpInstruction methodsFor: 'printing' stamp: ''! printSelfOn: aStream aStream nextPutAll: name; space. label printSelfOn: aStream. machineCode ifNotNil: [ aStream space; nextPut: $[ . machineCode do: [:byte | aStream nextPutAll: (byte printStringBase: 16)] separatedBy: [ aStream space ]. aStream nextPut: $]. ]. ! ! !AJJumpInstruction methodsFor: 'accessing' stamp: 'CamilloBruni 4/17/2012 17:54'! description ^ description! ! !AJJumpInstruction methodsFor: 'accessing' stamp: ''! label ^ label! ! !AJJumpInstruction methodsFor: 'visitor' stamp: ''! accept: anObject ^ anObject jumpInstruction: self! ! !AJJumpInstruction methodsFor: 'testing' stamp: ''! isLabelUsed: anAJJumpLabel ^ label = anAJJumpLabel ! ! !AJJumpInstruction methodsFor: 'accessing' stamp: 'CamilloBruni 4/17/2012 17:55'! description: anInstructionDescription description := anInstructionDescription! ! !AJJumpInstruction methodsFor: 'accessing' stamp: ''! label: anObject label := anObject! ! !AJJumpInstruction methodsFor: 'accessing' stamp: ''! codeSize ^ machineCode size! ! !AJJumpLabel commentStamp: 'TorstenBergmann 1/30/2014 09:13'! A label for a jump! !AJJumpLabel methodsFor: 'accessing' stamp: ''! isSet: anObject isSet := anObject! ! !AJJumpLabel methodsFor: 'printing' stamp: 'CamilloBruni 7/17/2012 14:48'! printSelfOn: aStream aStream nextPutAll: '@@'; nextPutAll: name asString ! ! !AJJumpLabel methodsFor: 'accessing' stamp: ''! extractLabels: aBlock aBlock value: name value: position! ! !AJJumpLabel methodsFor: 'visitor' stamp: ''! accept: anObject anObject jumpLabel: self! ! !AJJumpLabel methodsFor: 'accessing' stamp: ''! isSet ^ isSet == true! ! !AJJumpLabel methodsFor: 'emitting code' stamp: ''! emitCode: asm ! ! !AJJumpLabel methodsFor: 'printing' stamp: ''! printOn: aStream aStream nextPutAll: '@@'; nextPutAll: name asString ! ! !AJJumpLabel methodsFor: 'testing' stamp: 'CamilloBruni 8/22/2012 16:43'! isLabel ^ true! ! !AJJumpLabel methodsFor: 'printing' stamp: ''! printAsOperandOn: aStream aStream nextPutAll: '@@'; nextPutAll: name asString ! ! !AJLineStream commentStamp: 'TorstenBergmann 1/30/2014 09:10'! Utility class implementing a specific stream for printing instructions! !AJLineStream methodsFor: 'error handling' stamp: 'CamilloBruni 7/16/2012 14:59'! doesNotUnderstand: aMessage writeStream perform: aMessage selector withArguments: aMessage arguments! ! !AJLineStream methodsFor: 'writing' stamp: ''! lf self updateLineStart. writeStream lf! ! !AJLineStream methodsFor: 'writing' stamp: 'CamilloBruni 7/16/2012 15:23'! padColumn: maxCharacterPosition "pad the current line up to maxCharacterPosition with spaces" [writeStream position - lineStart < maxCharacterPosition] whileTrue: [writeStream space]! ! !AJLineStream methodsFor: 'writing' stamp: ''! crlf self updateLineStart. writeStream crlf! ! !AJLineStream methodsFor: 'writing' stamp: ''! updateLineStart lineStart := writeStream position! ! !AJLineStream methodsFor: 'writing' stamp: 'CamilloBruni 7/16/2012 15:22'! writeStream: aWriteStream writeStream := aWriteStream. self updateLineStart! ! !AJLineStream methodsFor: 'writing' stamp: 'CamilloBruni 7/16/2012 15:00'! on: aStream ^ self new writeStream: aStream; yourself! ! !AJLineStream methodsFor: 'writing' stamp: ''! cr self updateLineStart. writeStream cr! ! !AJLineStream class methodsFor: 'instance creation' stamp: 'CamilloBruni 7/16/2012 15:33'! on: aWriteStream ^ self new writeStream: aWriteStream; yourself! ! !AJMMRegister commentStamp: ''! I am register used for the MMX integer instructions on IA-32 processors. MMX registers are 64Bit wide, depending on the instructions used the register is used either as 1 x 64bit value, 2 x 32bit values, 4 x 16bit values or 8 x 8bit values. Note that the MMX register overlap with the floating point register and only use the lower 64bits of the 80bits FPU registers.! !AJMMRegister methodsFor: 'testing' stamp: ''! isRegTypeMM ^ true! ! !AJMMRegister methodsFor: 'testing' stamp: ''! isGeneralPurpose ^ false! ! !AJMMRegister methodsFor: 'accessing' stamp: ''! code: aCode code := aCode. size := 8.! ! !AJMMRegister methodsFor: 'accessing' stamp: 'CamilloBruni 5/7/2013 11:32'! influencingRegisters "MMX registers overlap with the ST register" self shouldBeImplemented.! ! !AJMMRegister methodsFor: 'printing' stamp: 'CamilloBruni 7/17/2012 11:13'! descriptionOn: s s nextPutAll: 'An MMX register'.! ! !AJMMRegister methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 15:28'! isX86 ^ true! ! !AJMem commentStamp: ''! I am memory operand used in assembly instructions. I can be created from an immedate or a register. Memory operands are used to read values indirectly from memory using certain offsets. Example: asm := AJx86Assembler new. "create an memory operand on the address 1234" 1234 asImm ptr "create a simple memory operand with RAX as base" asm RAX ptr. "the same with a 8 byte offset" asm RAX ptr + 8! !AJMem methodsFor: 'testing' stamp: 'MartinMcClure 1/4/2013 22:14'! hasUpperBankIndex "True iff I have an index register, and it is one of r8-r15" ^ self hasIndex and: [ self index isUpperBank ]! ! !AJMem methodsFor: 'accessing' stamp: ''! hasLabel "Answer the value of hasLabel" ^ false! ! !AJMem methodsFor: 'testing' stamp: ''! isRip ^ self base isRip! ! !AJMem methodsFor: 'testing' stamp: ''! hasBase ^ base notNil! ! !AJMem methodsFor: 'accessing' stamp: ''! displacement "Answer the value of displacement" ^ displacement! ! !AJMem methodsFor: 'accessing' stamp: 'CamilloBruni 4/4/2012 16:45'! + displacementOrIndex displacementOrIndex isInteger ifTrue: [ self displacement: (AJImmediate new ivalue: displacementOrIndex). ^ self ]. displacementOrIndex isGeneralPurpose ifTrue: [ index := displacementOrIndex. ^ self ]. self error: 'Expected integer or general purpose register for memory displacement but got ', displacementOrIndex class name, '.'.! ! !AJMem methodsFor: 'accessing' stamp: 'CamilloBruni 4/4/2012 16:40'! - aDisplacement aDisplacement isInteger ifFalse: [ self error: 'Expected integer for memory displacement but got ', aDisplacement class name, '.' ]. self displacement: (AJImmediate new ivalue: aDisplacement negated). ^ self! ! !AJMem methodsFor: 'initialization' stamp: ''! initialize displacement := AJImmediate new. shift := 0.! ! !AJMem methodsFor: 'printing' stamp: 'MartinMcClure 1/25/2013 22:21'! printOn: aStream self printAnnotationOn: aStream. aStream nextPutAll: 'mem['. base ifNotNil: [ base printAsMemBaseOn: aStream. (index isNil and: [ displacement isNil ]) ifFalse: [ aStream nextPutAll: ' + ' ] ]. index ifNotNil: [ aStream nextPutAll: index registerName. self printScaleOn: aStream. displacement ifNotNil: [ aStream nextPutAll: ' + ' ] ]. displacement ifNotNil: [ aStream print: displacement ]. aStream nextPut: $]! ! !AJMem methodsFor: 'emitting' stamp: ''! emitBaseDisplacementModRM: emitter code: rCode | mod | self base isRip ifTrue: [ emitter emitMod: 0 reg: rCode rm: 2r101. displacement emitUsing: emitter size: 4. ^ self ]. mod := 0. displacement isZero ifFalse: [ mod := displacement isInt8 ifTrue: [ 1 ] ifFalse: [ 2 ]]. self base index == RIDESP ifTrue: [ "ESP/RSP/R12" emitter emitMod: mod reg: rCode rm: RIDESP. emitter emitScale: 0 index: RIDESP base: RIDESP ] ifFalse: [ (self base index ~= RIDEBP and: [ displacement isZero ]) ifTrue: [ "just base, and not EBP/RBP/R13 " ^ emitter emitMod: 0 reg: rCode rm: base index ]. "force emitting displacement" mod = 0ifTrue: [ mod := 1 ]. emitter emitMod: mod reg: rCode rm: base index ]. mod = 1 ifTrue: [ displacement emitUsing: emitter size: 1 ]. mod = 2 ifTrue: [ displacement emitUsing: emitter size: 4 ].! ! !AJMem methodsFor: 'accessing' stamp: ''! hasLabel: anObject "Set the value of hasLabel" hasLabel := anObject! ! !AJMem methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 16:16'! requiresRex "Answer true if use of this operand requires that the instruction have a REX prefix. For a memory reference, this is true if width of the transfer is 64, or if either the base or index register is in the upper bank -- the use of a 64-bit base or index register is not enough by itself." ^ self is64 or: [ (self hasBase and: [ base isUpperBank ]) or: [ self hasIndex and: [ index isUpperBank ] ] ]! ! !AJMem methodsFor: 'emitting' stamp: ''! emit32BitAbsoluteDisplacementModRM: emitter code: rCode self hasIndex ifTrue: [ self assert: index index ~= RIDESP. " ESP/RSP" emitter emitMod: 0 reg: rCode rm: 4. emitter emitScale: shift index: index index base: 5 ] ifFalse: [ emitter emitMod: 0 reg: rCode rm: 5 ]. self hasLabel ifTrue: [ "X86 uses absolute addressing model, all relative addresses will be relocated to absolute ones." "target is label" target addRelocationAt: emitter offset displacement: displacement absolute: true size: 4. emitter emitInt32: 0 ] ifFalse: [ " Absolute address" displacement emitUsing: emitter size: 4 ]! ! !AJMem methodsFor: 'accessing' stamp: ''! index "Answer the value of index" ^ index! ! !AJMem methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 17:49'! prohibitsRex "Answer true if use of this operand requires that the instruction *not* have a REX prefix." ^ false! ! !AJMem methodsFor: 'testing' stamp: ''! hasIndex ^ index notNil! ! !AJMem methodsFor: 'accessing' stamp: 'MartinMcClure 1/27/2013 16:23'! size ^ size! ! !AJMem methodsFor: 'accessing' stamp: ''! segmentPrefix "Answer the value of segmentPrefix" ^ segmentPrefix! ! !AJMem methodsFor: 'accessing' stamp: ''! base: anObject "Set the value of base" base := anObject! ! !AJMem methodsFor: 'accessing' stamp: ''! shift "Answer the value of shift" ^ shift! ! !AJMem methodsFor: 'emitting' stamp: 'MartinMcClure 1/4/2013 22:22'! emitModRM: emitter code: rCode immSize: immSize "Receiver is memory location. rCode is a register number" "[base + displacement]" (self hasBase and: [ self hasIndex not ]) ifTrue: [ ^ self emitBaseDisplacementModRM: emitter code: rCode ]. "[base + index * scale + displacement]" (self hasBase and: [ self hasIndex ]) ifTrue: [ ^ self emitScaledBaseDisplacementModRM: emitter code: rCode ]. " Address | 32-bit mode | 64-bit mode ------------------------------+-------------+--------------- [displacement] | ABSOLUTE | RELATIVE (RIP) [index * scale + displacemnt] | ABSOLUTE | ABSOLUTE (ZERO EXTENDED) In 32 bit mode is used absolute addressing model. In 64 bit mode is used relative addressing model together with absolute addressing one. The main problem is that if the instruction contains a SIB byte then relative addressing (RIP) is not possible. " emitter is32BitMode ifTrue: [ ^ self emit32BitAbsoluteDisplacementModRM: emitter code: rCode ]. emitter is64BitMode ifTrue: [ self shouldBeImplemented ]. self invalidInstruction! ! !AJMem methodsFor: 'testing' stamp: ''! hasSegmentPrefix ^ segmentPrefix notNil! ! !AJMem methodsFor: 'accessing' stamp: ''! shift: value "Set the value of shift" self assert: (value >=0 and: [ value < 4 ]). shift := value! ! !AJMem methodsFor: 'accessing' stamp: ''! size: anObject "Set the value of size" size := anObject! ! !AJMem methodsFor: 'accessing' stamp: ''! segmentPrefix: anObject "Set the value of segmentPrefix" segmentPrefix := anObject! ! !AJMem methodsFor: 'accessing' stamp: ''! base "Answer the value of base" ^ base! ! !AJMem methodsFor: 'accessing' stamp: ''! index: anIndex "Set the value of index, must be a general purpose register" self assert: (anIndex isGeneralPurpose). index := anIndex! ! !AJMem methodsFor: 'accessing' stamp: 'MartinMcClure 1/3/2013 21:15'! scale: aScale "a valid scale values is 1 , 2 , 4 and 8" aScale = 1 ifTrue: [ shift := 0. ^ self ]. aScale = 2 ifTrue: [ shift := 1. ^ self ]. aScale = 4 ifTrue: [ shift := 2. ^ self ]. aScale = 8 ifTrue: [ shift := 3. ^ self ]. self error: 'invalid scale value'! ! !AJMem methodsFor: 'testing' stamp: ''! isMem ^ true! ! !AJMem methodsFor: 'testing' stamp: ''! isUpperBank "see `AJBaseReg >> #isUpperBank` " ^ self base isUpperBank! ! !AJMem methodsFor: 'accessing' stamp: ''! displacement: anImm "Set the value of displacement" self assert: anImm isImm. displacement := anImm! ! !AJMem methodsFor: 'accessing' stamp: ''! * aScale self scale: aScale! ! !AJMem methodsFor: 'emitting' stamp: ''! emitScaledBaseDisplacementModRM: emitter code: rCode self assert: index index ~= RIDESP. (base index ~= RIDEBP and: [ displacement isZero ]) ifTrue: [ emitter emitMod: 0 reg: rCode rm: 4. ^ emitter emitScale: shift index: index index base: base index ]. displacement isInt8 ifTrue: [ emitter emitMod: 1 reg: rCode rm: 4. emitter emitScale: shift index: index index base: base index. displacement emitUsing: emitter size: 1 ] ifFalse: [ emitter emitMod: 2 reg: rCode rm: 4. emitter emitScale: shift index: index index base: base index. displacement emitUsing: emitter size: 4 ]. ^ self! ! !AJMem methodsFor: 'printing' stamp: 'MartinMcClure 1/25/2013 22:22'! printScaleOn: aStream aStream nextPutAll: ' * '. (2 raisedToInteger: shift) printOn: aStream! ! !AJOperand commentStamp: ''! I am a generic operand used in the ASMJit assembler. I define the interface for setting the final instruction code and annotations.! !AJOperand methodsFor: 'accessing' stamp: ''! compilerData ^ compilerData! ! !AJOperand methodsFor: 'testing' stamp: ''! is16 ^ self size == 2! ! !AJOperand methodsFor: 'converting' stamp: ''! asAJOperand "receiver is already an operand. no nothing"! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegCode: aRegCode self shouldBeImplemented ! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegTypeMM ^ false! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegTypeGPQ ^ self isRegType: RegGPQ! ! !AJOperand methodsFor: 'testing' stamp: ''! isRip ^ false! ! !AJOperand methodsFor: 'accessing' stamp: ''! size32 ^ self size: 4! ! !AJOperand methodsFor: 'testing' stamp: 'MartinMcClure 1/4/2013 22:15'! hasUpperBankIndex "True iff I have an index register, and it is one of r8-r15" ^ false "Only can be true for memory references."! ! !AJOperand methodsFor: 'testing' stamp: ''! isLabel ^ false! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegTypeX87 ^ false! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegMem: aRegType self shouldBeImplemented ! ! !AJOperand methodsFor: 'accessing' stamp: ''! annotation ^ annotation! ! !AJOperand methodsFor: 'accessing' stamp: ''! annotation: anObject annotation := anObject! ! !AJOperand methodsFor: 'testing' stamp: ''! isImm ^ false ! ! !AJOperand methodsFor: 'converting' stamp: 'IgorStasenko 5/28/2012 01:51'! ptr16 "turn receiver into a memory operand with receiver as base, with 2 bytes size" ^ self ptr size: 2! ! !AJOperand methodsFor: 'converting' stamp: 'IgorStasenko 5/28/2012 01:52'! ptr64 "turn receiver into a memory operand with receiver as base, with 8 bytes size" ^ self ptr size: 8! ! !AJOperand methodsFor: 'accessing' stamp: ''! stackSize ^ self size! ! !AJOperand methodsFor: 'accessing' stamp: ''! clearId operandId := 0.! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegIndex: aRegIndex ^ self isReg and: [ self index == (aRegIndex bitAnd: RegCodeMask ) ] ! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegTypeGPB ^ self isRegType: RegGPB! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegTypeXMM ^ false! ! !AJOperand methodsFor: 'printing' stamp: 'CamilloBruni 10/17/2012 15:57'! printAsOperandOn: aStream self printAnnotationOn: aStream. ^ self printOn: aStream ! ! !AJOperand methodsFor: 'code generation' stamp: ''! emitPushOnStack: asm asm push: self! ! !AJOperand methodsFor: 'testing' stamp: ''! is64 ^ self size == 8! ! !AJOperand methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 15:54'! requiresRex "Answer true if use of this operand requires that the instruction have a REX prefix." self subclassResponsibility! ! !AJOperand methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 17:48'! prohibitsRex "Answer true if use of this operand requires that the instruction *not* have a REX prefix." self subclassResponsibility! ! !AJOperand methodsFor: 'accessing' stamp: ''! size16 ^ self size: 2! ! !AJOperand methodsFor: 'labels' stamp: ''! extractLabels: aBlockClosure " do nothing"! ! !AJOperand methodsFor: 'converting' stamp: 'IgorStasenko 5/28/2012 01:52'! ptr8 "turn receiver into a memory operand with receiver as base, with 1 byte size" ^ self ptr size: 1! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegTypeGPW ^ self isRegType: RegGPW! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegMem ^ self isReg or: [ self isMem ]! ! !AJOperand methodsFor: 'accessing' stamp: ''! size "Return size of operand in bytes." self shouldBeImplemented ! ! !AJOperand methodsFor: 'converting' stamp: 'IgorStasenko 5/28/2012 01:52'! ptr "turn receiver into a memory operand " self subclassResponsibility ! ! !AJOperand methodsFor: 'converting' stamp: 'IgorStasenko 5/28/2012 01:52'! ptr32 "turn receiver into a memory operand with receiver as base, with 4 bytes size" ^ self ptr size: 4! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegType: aRegType ^ self isReg and: [self type == aRegType]! ! !AJOperand methodsFor: 'accessing' stamp: ''! size8 ^ self size: 1! ! !AJOperand methodsFor: 'testing' stamp: ''! isNone "Return true if operand is none (OP_NONE)." self shouldBeImplemented ! ! !AJOperand methodsFor: 'testing' stamp: ''! is32 ^ self size == 4! ! !AJOperand methodsFor: 'accessing' stamp: ''! operandId ^ operandId! ! !AJOperand methodsFor: 'testing' stamp: ''! isReg ^ false! ! !AJOperand methodsFor: 'testing' stamp: ''! isMem ^ false! ! !AJOperand methodsFor: 'accessing' stamp: ''! size64 ^ self size: 8! ! !AJOperand methodsFor: 'testing' stamp: ''! is8 ^ self size == 1! ! !AJOperand methodsFor: 'testing' stamp: ''! isRegTypeGPD ^ self isRegType: RegGPD! ! !AJOperand methodsFor: 'printing' stamp: 'CamilloBruni 8/24/2012 13:56'! printAnnotationOn: aStream annotation ifNil: [ ^ self ]. aStream nextPut: $" ; nextPutAll: annotation asString; nextPut: $"; space.! ! !AJRegister commentStamp: ''! I am an abstract superclass for the standard x86 registers.! !AJRegister methodsFor: 'testing' stamp: ''! isReg ^ true! ! !AJRegister methodsFor: 'accessing' stamp: 'CamilloBruni 7/17/2012 12:43'! influencingRegisters self is8 ifFalse: [ ^ self as8 influencingRegisters ]. ^ { self as8. self as16. self as32. self as64}! ! !AJRegister methodsFor: 'accessing' stamp: ''! code: aCode code := aCode. size := 1 << (( code bitAnd: RegTypeMask ) >> 4).! ! !AJRegister methodsFor: 'accessing' stamp: ''! size ^ 1 << (( code bitAnd: RegTypeMask ) >> 4).! ! !AJRegister methodsFor: 'testing' stamp: ''! isGeneralPurpose ^ false! ! !AJRegister methodsFor: 'testing' stamp: 'MartinMcClure 1/30/2013 20:52'! isX86 "Return whether this register is available in the standard x86 instruction set" ^ self requiresRex not & (self index < 8)! ! !AJReleaseTemps commentStamp: 'TorstenBergmann 2/4/2014 21:37'! Handling release of temps! !AJReleaseTemps methodsFor: 'printing' stamp: ''! printSelfOn: aStream aStream nextPutAll: 'Release temps: '; print: count ! ! !AJReleaseTemps methodsFor: 'accessing' stamp: ''! count ^ count! ! !AJReleaseTemps methodsFor: 'accessing' stamp: ''! count: anObject count := anObject! ! !AJReleaseTemps methodsFor: 'visitor' stamp: ''! accept: anObject anObject visitReleaseTemps: self ! ! !AJReleaseTemps methodsFor: 'printing' stamp: ''! printOn: aStream ^ self printSelfOn: aStream ! ! !AJReleaseTemps methodsFor: 'visitor' stamp: ''! processTempsWith: anObject anObject releaseTemps: count! ! !AJReserveTemp commentStamp: 'IgorStasenko 1/18/2012 13:09'! note: assembler should set size even before realizing a temp into stack location reference! !AJReserveTemp methodsFor: 'printing' stamp: 'CamilloBruni 7/20/2012 13:29'! printAsOperandOn: aStream annotation ifNotNil: [ aStream nextPut: $"; nextPutAll: annotation asString; nextPut: $"; space ]. operands ifNil: [ ^ aStream nextPutAll: 'aStackTEMP' ]. self operand printAsOperandOn: aStream.! ! !AJReserveTemp methodsFor: 'visitor' stamp: ''! processTempsWith: anObject anObject reserveTemp: self ! ! !AJReserveTemp methodsFor: 'converting' stamp: ''! asAJOperand ^ operands first! ! !AJReserveTemp methodsFor: 'accessing' stamp: ''! size ^ size! ! !AJReserveTemp methodsFor: 'accessing' stamp: ''! stackSize ^ self size! ! !AJReserveTemp methodsFor: 'accessing' stamp: ''! size: number size := number! ! !AJReserveTemp methodsFor: 'visitor' stamp: ''! accept: anObject ^ anObject reserveTemp: self! ! !AJReserveTemp methodsFor: 'printing' stamp: ''! printOn: aStream ^ self printSelfOn: aStream ! ! !AJReserveTemp methodsFor: 'testing' stamp: ''! isMem ^ true! ! !AJReserveTemp methodsFor: 'accessing' stamp: ''! operand: anObject anObject annotation: annotation. operands := Array with: anObject ! ! !AJReserveTemp methodsFor: 'emitting code' stamp: ''! emitPushOnStack: asm ^ asm push: self! ! !AJReserveTemp methodsFor: 'accessing' stamp: 'CamilloBruni 8/24/2012 13:32'! name ^ name ifNil: [ 'Reserve temp' ]! ! !AJReserveTemp methodsFor: 'accessing' stamp: ''! operand ^ operands first! ! !AJReserveTemp methodsFor: 'testing' stamp: 'IgorStasenko 8/13/2013 13:45'! prohibitsRex "This test is used to validate if operand(s) is valid.. but reserve temp could not have an operand assigned yet and validation can be only performed at instruction analyzis stage (right before emitting the code), but not at instruction creation time" self flag: #todo. ^ false! ! !AJRoutineEpilogue commentStamp: 'TorstenBergmann 1/30/2014 09:15'! In assembly language programming an epilogue is a few lines of code that appears at the end of a routine! !AJRoutinePrologue commentStamp: 'IgorStasenko 5/11/2011 00:32'! This is a pseudo-instruction to indicate a place in native code for routine prologue. It is later replaced by real instructions which contain code for initializing stack frame & extra stack space required by routine.! !AJRoutinePrologue methodsFor: 'visitor' stamp: 'CamilloBruni 10/4/2012 18:54'! setPrologue: anInstructions "do nothing" | old | old := next. next := anInstructions. anInstructions last next: old ! ! !AJRoutinePrologue methodsFor: 'accessing' stamp: ''! name ^ 'prologue' ! ! !AJRoutinePrologue methodsFor: 'visitor' stamp: ''! accept: anObject ^ anObject visitRoutinePrologue: self! ! !AJRoutinePrologue methodsFor: 'emitting code' stamp: ''! emitCode: asm machineCode := #[]! ! !AJRoutineStackManager commentStamp: 'TorstenBergmann 2/4/2014 21:37'! Stack handling for routines! !AJRoutineStackManager methodsFor: 'initialization' stamp: ''! initialize self reset. noStackFrame := false.! ! !AJRoutineStackManager methodsFor: 'as yet unclassified' stamp: ''! newStdCall self stackFrameCheck. ^ calls add: (AJStdCallCallInfo new) ! ! !AJRoutineStackManager methodsFor: 'as yet unclassified' stamp: ''! noStackFrame noStackFrame := true.! ! !AJRoutineStackManager methodsFor: 'as yet unclassified' stamp: 'CamilloBruni 4/4/2012 16:33'! analyzeInstructions: anInstructions assembler: asm instructions := anInstructions. assembler := asm. instructions do: #prepareCallAlignments. calls do: [:callInfo | callInfo asm: assembler. callInfo emitAlignmentIfNeeded ]. instructions do: [:each | each processTempsWith: self]. self emitPrologue. ^ instructions ! ! !AJRoutineStackManager methodsFor: 'as yet unclassified' stamp: ''! newCdeclCall self stackFrameCheck. ^ calls add: (AJCdeclCallInfo new)! ! !AJRoutineStackManager methodsFor: 'as yet unclassified' stamp: ''! releaseTemps: count temps := temps - count! ! !AJRoutineStackManager methodsFor: 'initialize-release' stamp: ''! reset instructions := nil. assembler := nil. calls := OrderedCollection new. temps := maxTemps := extraStackBytes := 0. ! ! !AJRoutineStackManager methodsFor: 'as yet unclassified' stamp: ''! reserveExtraBytesOnStack: numBytes self stackFrameCheck. extraStackBytes := numBytes ! ! !AJRoutineStackManager methodsFor: 'emitting' stamp: ''! emitPrologue noStackFrame == true ifTrue: [ ^self ]. instructions do: [:each | each setPrologue: (assembler instructionsFor: [ | numBytes | assembler push: assembler EBP; mov: assembler ESP to: assembler EBP. numBytes := extraStackBytes. numBytes := numBytes + (maxTemps * assembler wordSize ). numBytes > 0 ifTrue: [ (assembler sub: assembler ESP with: numBytes) annotation: extraStackBytes asString , ' extra bytes + ' , maxTemps asString , ' temps' ] ]). ] ! ! !AJRoutineStackManager methodsFor: 'as yet unclassified' stamp: 'IgorStasenko 8/7/2013 19:06'! reserveTemp: anAJReserveTemp self stackFrameCheck. temps := temps + 1. maxTemps := maxTemps max: temps . anAJReserveTemp operand: (assembler stackFrameValueAtOffset: extraStackBytes + (temps * assembler wordSize )).! ! !AJRoutineStackManager methodsFor: 'as yet unclassified' stamp: ''! stackFrameCheck noStackFrame ifTrue: [ self error: 'Operation requires stack frame management to be enabled for generated code' ].! ! !AJRoutineStackManager methodsFor: 'as yet unclassified' stamp: ''! emitEpilogue: popExtraBytes assembler: asm asm leave. popExtraBytes > 0 ifTrue: [ asm ret: popExtraBytes asUImm ] ifFalse: [ asm ret. ].! ! !AJStackAlignmentTests commentStamp: 'TorstenBergmann 2/4/2014 21:39'! SUnit Tests for stack alignment! !AJStackAlignmentTests methodsFor: 'tests' stamp: ''! testNewProtocolForAlignedCalls | asm callInfo | asm := self newAssembler. asm cdeclCall: [:call | call push: EAX; push: EAX; push: 4. asm call: EAX. callInfo := call. ] alignment: 32. asm generatedCode. "to analyze instructions" self assert: callInfo stackSize = 12. self assert: callInfo needsAlignment ! ! !AJStackAlignmentTests methodsFor: 'utility' stamp: ''! newAssembler ^ AJx86Assembler new! ! !AJStackAlignmentTests methodsFor: 'tests' stamp: ''! testJumps | asm callInfo | asm := self newAssembler. asm noStackFrame. asm jmp: #foo; nop; nop; nop; nop; nop; nop; nop; nop; label: #foo. ^ asm generatedCode.! ! !AJStackInstruction commentStamp: 'TorstenBergmann 2/4/2014 21:37'! Stack instructions! !AJStackInstruction methodsFor: 'accessing' stamp: ''! callInfo: anObject callInfo := anObject! ! !AJStackInstruction methodsFor: 'accessing' stamp: ''! callInfo ^ callInfo! ! !AJStdCallCallInfo commentStamp: 'IgorStasenko 8/5/2011 06:17'! stdcall calling convention. Used on windows. No need for stack cleanup after call. No need to align stack before making call.! !AJStdCallCallInfo methodsFor: 'emitting code' stamp: ''! emitAlignmentIfNeeded "do nothing" "stdcall calling convention requires no stack alignment, no stack cleanup after call"! ! !AJStdCallCallInfo methodsFor: 'emitting code' stamp: ''! emitAlignment "do nothing" "stdcall calling convention requires no stack alignment, no stack cleanup after call"! ! !AJx64Assembler commentStamp: ''! I am an assembler for the Intel x86-64 architecture.! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R12W "A 16bit general purpose register This register overlaps with R12B, R12W, R12D, R12" ^ R12W! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R9 "A 64bit general purpose register This register overlaps with R9B, R9W, R9D, R9" ^ R9! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! RCX "A 64bit general purpose register This register overlaps with CL, CX, ECX, RCX" ^ RCX! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! RIP "A 64bit instruction pointer register This register overlaps with IP, EIP, RIP" ^ RIP! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R10B "A 8bit general purpose register This register overlaps with R10B, R10W, R10D, R10" ^ R10B! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'MartinMcClure 1/27/2013 20:55'! SIL ^ SIL! ! !AJx64Assembler methodsFor: 'register' stamp: ''! basePointer ^ RBP ! ! !AJx64Assembler methodsFor: 'accessing' stamp: ''! numGPRegisters ^ 16! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R14B "A 8bit general purpose register This register overlaps with R14B, R14W, R14D, R14" ^ R14B! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R9D "A 32bit general purpose register This register overlaps with R9B, R9W, R9D, R9" ^ R9D! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM9 "An SSE register" ^ XMM9! ! !AJx64Assembler methodsFor: 'initialization' stamp: 'CamilloBruni 4/17/2012 18:16'! initialize super initialize. is64 := true.! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R15W "A 16bit general purpose register This register overlaps with R15B, R15W, R15D, R15" ^ R15W! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R11 "A 64bit general purpose register This register overlaps with R11B, R11W, R11D, R11" ^ R11! ! !AJx64Assembler methodsFor: 'register' stamp: ''! data ^ RDX! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'MartinMcClure 1/27/2013 20:54'! SPL ^ SPL! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R11D "A 32bit general purpose register This register overlaps with R11B, R11W, R11D, R11" ^ R11D! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R12D "A 32bit general purpose register This register overlaps with R12B, R12W, R12D, R12" ^ R12D! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R10W "A 16bit general purpose register This register overlaps with R10B, R10W, R10D, R10" ^ R10W! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! RDX "A 64bit general purpose register This register overlaps with DL, DX, EDX, RDX" ^ RDX! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM13 "An SSE register" ^ XMM13! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R8B "A 8bit general purpose register This register overlaps with R8B, R8W, R8D, R8" ^ R8B! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R8 "A 64bit general purpose register This register overlaps with R8B, R8W, R8D, R8" ^ R8! ! !AJx64Assembler methodsFor: 'register' stamp: ''! instructionPointer ^ RIP! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! RDI "A 64bit general purpose register This register overlaps with BH, BX, EBX, RBX" ^ RDI! ! !AJx64Assembler methodsFor: 'accessing' stamp: 'CamilloBruni 4/17/2012 18:17'! instructionDesciptions ^ AJx64InstructionDescription instructions! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM8 "An SSE register" ^ XMM8! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! IP "A 16bit instruction pointer register This register overlaps with IP, EIP, RIP" ^ IP! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM12 "An SSE register" ^ XMM12! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R12 "A 64bit general purpose register This register overlaps with R12B, R12W, R12D, R12" ^ R12! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R8D "A 32bit general purpose register This register overlaps with R8B, R8W, R8D, R8" ^ R8D! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R10D "A 32bit general purpose register This register overlaps with R10B, R10W, R10D, R10" ^ R10D! ! !AJx64Assembler methodsFor: 'register' stamp: ''! destinationIndex ^ RDI! ! !AJx64Assembler methodsFor: 'accessing' stamp: 'CamilloBruni 4/18/2012 15:25'! newInstruction ^ AJx64Instruction new! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R8W "A 16bit general purpose register This register overlaps with R8B, R8W, R8D, R8" ^ R8W! ! !AJx64Assembler methodsFor: 'register' stamp: ''! stackPointer ^ RSP! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! XMM14 "An SSE register" ^ XMM14! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! RSP "A 64bit general purpose register This register overlaps with AH, AX, EAX, RAX" ^ RSP! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! RBX "A 64bit general purpose register This register overlaps with BL, BX, EBX, RBX" ^ RBX! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! RSI "A 64bit general purpose register This register overlaps with DH, DX, EDX, RDX" ^ RSI! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R15D "A 32bit general purpose register This register overlaps with R15B, R15W, R15D, R15" ^ R15D! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM15 "An SSE register" ^ XMM15! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R9W "A 16bit general purpose register This register overlaps with R9B, R9W, R9D, R9" ^ R9W! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R13B "A 8bit general purpose register This register overlaps with R13B, R13W, R13D, R13" ^ R13B! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R14 "A 64bit general purpose register This register overlaps with R14B, R14W, R14D, R14" ^ R14! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! EIP "A 32bit instruction pointer register This register overlaps with IP, EIP, RIP" ^ EIP! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R14W "A 16bit general purpose register This register overlaps with R14B, R14W, R14D, R14" ^ R14W! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'MartinMcClure 1/27/2013 20:55'! BPL ^ BPL! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R15 "A 64bit general purpose register This register overlaps with R15B, R15W, R15D, R15" ^ R15! ! !AJx64Assembler methodsFor: 'accessing' stamp: 'CamilloBruni 4/18/2012 15:24'! newJumpInstruction ^ AJx64JumpInstruction new! ! !AJx64Assembler methodsFor: 'register' stamp: ''! sourceIndex ^ RSI! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM11 "An SSE register" ^ XMM11! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R14D "A 32bit general purpose register This register overlaps with R14B, R14W, R14D, R14" ^ R14D! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R12B "A 8bit general purpose register This register overlaps with R12B, R12W, R12D, R12" ^ R12B! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R13D "A 32bit general purpose register This register overlaps with R13B, R13W, R13D, R13" ^ R13D! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R10 "A 64bit general purpose register This register overlaps with R10B, R10W, R10D, R10" ^ R10! ! !AJx64Assembler methodsFor: 'register' stamp: ''! counter ^ RCX! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'MartinMcClure 1/27/2013 20:55'! DIL ^ DIL! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R13W "A 16bit general purpose register This register overlaps with R13B, R13W, R13D, R13" ^ R13W! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R11W "A 16bit general purpose register This register overlaps with R11B, R11W, R11D, R11" ^ R11W! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R11B "A 8bit general purpose register This register overlaps with R11B, R11W, R11D, R11" ^ R11B! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R13 "A 64bit general purpose register This register overlaps with R13B, R13W, R13D, R13" ^ R13! ! !AJx64Assembler methodsFor: 'register' stamp: ''! accumulator ^ RAX! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! RAX "A 64bit general purpose register This register overlaps with AL, AX, EAX, RAX" ^ RAX! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R15B "A 8bit general purpose register This register overlaps with R15B, R15W, R15D, R15" ^ R15B! ! !AJx64Assembler methodsFor: 'accessing' stamp: ''! pointerSize "see AJx86Assembler >> #pointerSize" ^ 8! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R9B "A 8bit general purpose register This register overlaps with R9B, R9W, R9D, R9" ^ R9B! ! !AJx64Assembler methodsFor: 'testing' stamp: ''! is32 ^ false! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! XMM10 "An SSE register" ^ XMM10! ! !AJx64Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! RBP "A 64bit general purpose register This register overlaps with CH, CX, ECX, RCX" ^ RBP! ! !AJx64AssemblerTests commentStamp: 'TorstenBergmann 2/4/2014 21:39'! SUnit tests for 64 bit assembler! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:14'! testAssemblyMemBaseDisp asm mov: RAX ptr + 1 -> EAX; mov: RBX ptr + ECX -> EAX. self assert: asm bytes = #(16r8B 16r40 16r01 16r8B 16r04 16r0B) asByteArray! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/25/2013 19:31'! testCallInvalid "on 64 bit .. - only 32bit relative offset are allowed - only 64bit registers for indirect addresses" "relative calls with 64bit addresses are not supported" self asmShould: [ :a | a call: 16r123456789ABCDEF ] raise: Error. AJx86Registers generalPurpose do: [ :register | register is64 ifFalse: [ self asmShould: [ :a | a call: register ] raise: Error ] ifTrue: [ self deny: (self bytes: [ :a | a call: register ]) isEmpty ] ]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 5/15/2012 14:19'! testBitTest "8 Bit =====================================================" self asmShould: [ :a| a bt: a R8B with: 16r1. ] raise: Error. "16 bit =====================================================" "lower bank 16bit register opcode + ModR/M" self assert: [ :a| a bt: a AX with: 16r01 ] bytes: #[ "16bit mode" 16r66 "OP" 16r0f 16rba "ModRM" 2r11100000 "immediate" 16r01]. "upper bank 16bit register opcode + ModR/M" self assert: [ :a| a bt: a R8W with: 16r01 ] bytes: #[ "16bit mode" 16r66 "REX" 2r01000001 "OP" 16r0f 16rba "ModRM" 2r11100000 "immediate" 16r01]. "32 bit =====================================================" "lower bank 32bit register opcode + ModR/M" self assert: [ :a| a bt: a EAX with: 16r01 ] bytes: #[ "OP" 16r0f 16rba "ModRM" 2r11100000 "immediate" 16r01]. "upper bank 32bit register opcode + ModR/M" self assert: [ :a| a bt: a R8D with: 16r01 ] bytes: #[ "REX" 2r01000001 "OP" 16r0f 16rba "ModRM" 2r11100000 "immediate" 16r01]. "64 bit =====================================================" "lower bank 32bit register opcode + ModR/M" self assert: [ :a| a bt: a RAX with: 16r01 ] bytes: #[ "REX" 2r01001000 "OP" 16r0f 16rba "ModRM" 2r11100000 "immediate" 16r01]. "upper bank 32bit register opcode + ModR/M" self assert: [ :a| a bt: a R8 with: 16r01 ] bytes: #[ "REX" 2r01001001 "OP" 16r0f 16rba "ModRM" 2r11100000 "immediate" 16r01].! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:42'! testPush "lower bank 64bit register" self assert: [:a | a push: a RSP ] bytes: #[ 16r54 "16r50 + RSP index" ].! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:42'! testPop "lower bank 64bit register" self assert: [:a | a pop: a RSP ] bytes: #[ 16r5c ].! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:42'! testNeg "8bit ======================================================" self assert: [ :a | a neg: a AL] bytes: #[ 16rF6 "ModR/M" 2r11011000 ]. "8bit upper bank with REX" self assert: [ :a | a neg: a R8B] bytes: #[ 2r01000001 16rF6 "ModR/M" 2r11011000 ]. "16bit with fallback =======================================" self assert: [ :a | a neg: a AX] bytes: #[ 16r66 16rF7"ModR/M" 2r11011000 ]. "16bit upper bank with REX" self assert: [ :a | a neg: a R8W] bytes: #[ 16r66 2r01000001 16rF7"ModR/M" 2r11011000 ]. "word 16bit IP relative " self assert: [ :a | a neg: a IP ptr16 + 16r12345678] bytes: #[16r66 16rF7 "ModR/M"2r00011101 16r78 16r56 16r34 16r12]. "32bit ====================================================" self assert: [ :a | a neg: a EAX] bytes: #[ 16rF7"ModR/M" 2r11011000 ]. "32bit upper bank with REX" self assert: [ :a | a neg: a R8D] bytes: #[ 2r01000001 16rF7"ModR/M" 2r11011000 ]. "negate double word 32bit EIP relative " self assert: [ :a | a neg: a EIP ptr32 + 16r12345678] bytes: #[16rF7 "ModR/M"2r00011101 16r78 16r56 16r34 16r12]. "64bit with REX ==========================================" self assert: [ :a | a neg: a RAX] bytes: #[ 2r01001000 16rF7 "ModR/M"2r11011000 ]. "64bit upper bank" self assert: [ :a | a neg: a R8] bytes: #[ 2r01001001 16rF7 "ModR/M"2r11011000 ]. "negate quadword 64bit RIP relative " self assert: [ :a | a neg: a RIP ptr64 + 16r12345678] bytes: #["REX"2r01001000 16rF7 "ModR/M"2r00011101 16r78 16r56 16r34 16r12]. ! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:37'! testMovMemory "mov memory to 8bit register ==========================" self assert: [:a | a mov: a RCX ptr to: a AL ] bytes: #[16r8A 16r00000001 "ModR/M"]. ! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:37'! testMovImmediate "8bit immediate to 8bit register" self assert: [:a | a mov: 16r12 to: a AL ] bytes: #[16rB0 16r12]. "16bit immediate to 16bit register (requires 16bit fallback prefix)" self assert: [:a | a mov: 16r1234 to: a AX ] bytes: #[16r66 16rB8 16r34 16r12]. "32bit immediate to 32bit register" self assert: [:a | a mov: 16r12345678 to: a EAX ] bytes: #[16rB8 16r78 16r56 16r34 16r12]. "64bit immediate to 64bit register (requires REX prefix)" self assert: [:a | a mov: 16r123456789ABCDEF0 to: a RAX ] bytes: #[2r01001000 16rB8 16rF0 16rDE 16rBC 16r9A 16r78 16r56 16r34 16r12]. "32bit immediate sign-extended to 64bit register (REX prefix)" self assert: [:a | a mov: 16r12345678 to: a RAX] bytes: #[ 2r01001000 16rc7 "ModR/M"16rc0 16r78 16r56 16r34 16r12 ]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'HenrikSperreJohansen 2/26/2015 14:47'! testStringOps64Mnemonics "Test that 64bit string operation mnemonics generate the same code as their noop versions" | mnemonicRegOpBytes mnemonicMemOpBytes | asm movs: asm RAX; cmps: asm RAX; stos: asm RAX; lods: asm RAX; scas: asm RAX. mnemonicRegOpBytes := asm bytes. asm reset; movs: (AJMem new size: 8); cmps: (AJMem new size: 8); stos: (AJMem new size: 8); lods: (AJMem new size: 8); scas: (AJMem new size: 8). mnemonicMemOpBytes:= asm bytes. asm reset; movsq; cmpsq; stosq; lodsq; scasq. self assert: mnemonicRegOpBytes equals: asm bytes. self assert: mnemonicMemOpBytes equals: asm bytes. "No 64bit locations allowed for ins/outs" self should: [ asm reset; ins: RAX; bytes] raise: Error. self should: [ asm reset; outs: RAX; bytes] raise: Error.! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/25/2013 20:53'! testInvalidTest "In 64-bit mode, r/m8 cannot be encoded to access the following byte registers if an REX prefix is used: AH, BH, CH, DH." {AH. CH. DH. BH} do: [ :reg | self deny: (self bytes: [ :a | a test: reg with: AL ]) isEmpty. self deny: (self bytes: [ :a | a test: AL with: reg ]) isEmpty. self deny: (self bytes: [ :a | a test: reg with: 16r12 ]) isEmpty. "with an upper bank byte register => requires REX prefix" self asmShould: [ :a | a test: reg with: R8B ] raise: Error. self asmShould: [ :a | a test: R8B with: reg ] raise: Error. "with a 64bit register requring again an REX prefix" self asmShould: [ :a | a test: reg with: RAX ] raise: Error. self asmShould: [ :a | a test: RAX with: reg ] raise: Error ]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:32'! testAssemblyMemBase self assert: [ :a | a mov: a RAX ptr to: a EAX ] bytes: #[ 16r8B 2r00000000 ]. self assert: [ :a | a mov: a RSP ptr to: a EAX] bytes: #[ 16r8B 16r04 16r24 ]. self assert: [ :a | a mov: a RBP ptr to: a EAX ] bytes: #[ 16r8B 16r45 16r00 ].! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 12/15/2012 13:13'! testSyscall self assert: [ :a | a syscall ] bytes: #[16r0F 16r05]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:45'! testXorFastCode self "shortcut for AL + 8bit immedidate" assert: [ :a | a xor: a AL with: 16r12] bytes: #[ 16r34 16r12]. self "shortcut for AX + 16bit immedidate" assert: [ :a | a xor: a AX with: 16r1234] bytes: #[ 16r66 16r35 16r34 16r12]. self "shortcut for EAX + 16bit immedidate" assert: [ :a | a xor: a EAX with: 16r12345678] bytes: #[ 16r35 16r78 16r56 16r34 16r12]. self "shortcut for RAX + 32bit immedidate" assert: [ :a | a xor: a RAX with: 16r12345678] bytes: #[ 2r01001000 16r35 16r78 16r56 16r34 16r12].! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:30'! testAssembly0 self assert: [ :a | a mov: 16rfeedface -> RAX ] bytes: #[72 184 206 250 237 254 0 0 0 0]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/26/2013 15:50'! testHighByteRegistersInvalid "Can't access AH, BH, CH, DH if a REX byte is required. This test attempts to test every instruction supported by AsmJit that can access an 8-bit general-purpose register AND also require a REX prefix." | legacyHRegs op2codes opBothCodes mixedWidthOpCodes byteOperandsRequiringRex wideRegistersRequiringRex | legacyHRegs := {AH. CH. DH. BH}. opBothCodes := #(#adc:with: #add:with: #mov:to: #cmp:with: #or:with: #sbb:with: #sub:with #xchg:with: #xor:with:). op2codes := #(#cmpxchg:with: #test:with: #xadd:with:). mixedWidthOpCodes := #(#crc32:with: #movsx:to: #movzx:to:). wideRegistersRequiringRex := {RAX. R8D}. "RAX requires REX.W, R8D requires REX.R or REX.B" byteOperandsRequiringRex := {SPL. BPL. SIL. DIL. R8B. (R8 ptr). (R8 ptr + 16r12). (R8 ptr + 16r1234). ((RAX ptr + R8) * 2). ((RAX ptr + R8) * 4 + 16r12). ((RAX ptr + R8) * 8 + 16r1234)}. legacyHRegs do: [ :hreg | byteOperandsRequiringRex do: [ :operand | opBothCodes do: [ :opcode | self asmShould: [ :a | a perform: opcode with: hreg with: operand ] raise: Error. self asmShould: [ :a | a perform: opcode with: operand with: hreg ] raise: Error ]. op2codes do: [ :opcode | self asmShould: [ :a | a perform: opcode with: operand with: hreg ] raise: Error ] ]. mixedWidthOpCodes do: [ :opcode | wideRegistersRequiringRex do: [ :wideReg | self asmShould: [ :a | a perform: opcode with: wideReg with: hreg ] raise: Error ] ] ]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'HenrikSperreJohansen 6/26/2014 13:04'! testAssembly3 " instructions without operands. (AJx86InstructionDescription instructions select: [:each | each group = #emit]) keys asSortedCollection " | str | str := #( #cbw 16r66 16r98 #cdq 16r99 #cdqe 16r48 16r98 #clc 16rF8 #cld 16rFC #cmc 16rF5 #cmpsb 16rA6 #cmpsd 16rA7 #cmpsq 16r48 16rA7 "64 bit" #cmpsw 16r66 16rA7 #cpuid 16r0F 16rA2 #cqo 16r48 16r99 "64 bit " #cwd 16r66 16r99 #cwde 16r98 "#daa 16r27 32 bit" "#das 16r2F 32 bit" #emms 16r0F 16r77 #f2xm1 16rD9 16rF0 #fabs 16rD9 16rE1 #fchs 16rD9 16rE0 #fclex 16r9B 16rDB 16rE2 #fcompp 16rDE 16rD9 #fcos 16rD9 16rFF #fdecstp 16rD9 16rF6 #fincstp 16rD9 16rF7 #finit 16r9B 16rDB 16rE3 #fld1 16rD9 16rE8 #fldl2e 16rD9 16rEA #fldl2t 16rD9 16rE9 #fldlg2 16rD9 16rEC #fldln2 16rD9 16rED #fldpi 16rD9 16rEB #fldz 16rD9 16rEE #fnclex 16rDB 16rE2 #fninit 16rDB 16rE3 #fnop 16rD9 16rD0 #fpatan 16rD9 16rF3 #fprem 16rD9 16rF8 #fprem1 16rD9 16rF5 #fptan 16rD9 16rF2 #frndint 16rD9 16rFC #fscale 16rD9 16rFD #fsin 16rD9 16rFE #fsincos 16rD9 16rFB #fsqrt 16rD9 16rFA #ftst 16rD9 16rE4 #fucompp 16rDA 16rE9 #fwait 16r9B #fxam 16rD9 16rE5 #fxtract 16rD9 16rF4 #fyl2x 16rD9 16rF1 #fyl2xp1 16rD9 16rF9 #insb 16r6C #insd 16r6D #insw 16r66 16r6D #int3 16rCC #leave 16rC9 #lfence 16r0F 16rAE 16rE8 #lock 16rF0 "prefix" #lodsb 16rAC #lodsd 16rAD #lodsq 16r48 16rAD "- 64 bit" #lodsw 16r66 16rAD #mfence 16r0F 16rAE 16rF0 #monitor 16r0F 16r01 16rC8 #movsb 16rA4 #movsd 16rA5 #movsq 16r48 16rA5 "- 64 bit" #movsw 16r66 16rA5 #mwait 16r0F 16r01 16rC9 #nop 16r90 #outsb 16r6E #outsd 16r6F #outsw 16r66 16r6F #pause 16rF3 16r90 "#popad 16r61 32 bit" #popfd 16r9D #popfq 16r48 16r9D "- 64 bit " "#pushad 16r60 32 bit" #pushf 16r66 16r9C "#pushfd 16r9C 32 bit" #pushfq 16r9c" -64 bit" #rdtsc 16r0F 16r31 #rdtscp 16r0F 16r01 16rF9 #sahf 16r9E #scasb 16rAE #scasd 16rAF #scasq 16r48 16rAF #scasw 16r66 16rAF #sfence 16r0F 16rAE 16rF8 #stc 16rF9 #std 16rFD #stosb 16rAA #stosd 16rAB #stosq 16r48 16rAB #stosw 16r66 16rAB #ud2 16r0F 16r0B #std 16rFD "dummy" ) readStream. [ str atEnd ] whileFalse: [ | instr tst bytes | instr := str next. tst := OrderedCollection new. [ str peek isInteger ] whileTrue: [ tst add: str next ]. asm reset noStackFrame. asm perform: instr. bytes := asm bytes. self assert: (bytes = tst asByteArray ) description: instr, ' failed. expected ', tst asByteArray printString, ' but got ', bytes asByteArray printString. ]. ! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/27/2013 21:32'! testByteRegs4through7 "Test valid uses of byte registers SPL BPL SIL DIL, only available in 64-bit mode, and when using a REX prefix. Can't be used in the same instruction with AH, CH, DH, or BH -- this is tested in testHighByteRegistersInvalid." | byteRegs op2codes opBothCodes mixedWidthOpCodes byteRMOperands wideRegisters | "byteRegs -- register -> contribution to ModRM byte when used as the reg operand" byteRegs := {(SPL -> 16r20). (BPL -> 16r28). (SIL -> 16r30). (DIL -> 16r38)}. "opBothCodes -- #selector -> #(opcode when byteReg second arg, opcode when byteReg first arg)" opBothCodes := {(#adc:with: -> #(16r10 16r12)). (#add:with: -> #(16r00 16r02)). (#mov:with: -> #(16r88 16r8A)). (#cmp:with: -> #(16r38 16r3A)). (#or:with: -> #(16r08 16r0A)). (#sbb:with: -> #(16r18 16r1A)). (#sub:with -> #(16r28 16r2A)). (#xor:with: -> #(16r30 16r32))}. "op2Codes -- #selector -> multiByteBytecode. ByteReg is always the second arg" op2codes := {(#cmpxchg:with: -> #[16r0F 16rB0]). (#test:with: -> #[16r84]). (#xadd:with: -> #[16r0F 16rC0]) "xchg is not actually supported at this time (#xchg:with: -> #[16r86])"}. "mixedWidthOpCodes -- #selector -> multiByteBytecode. ByteReg is always the second arg" mixedWidthOpCodes := {(#movsx:with: -> #[16r0F 16rBE]). (#movzx:with: -> #[16r0F 16rB6])}. "**** Handle #crc32:with: separately due to its legacy prefix ****" "wideRegisters -- register -> #[REX prefix, contribution to ModRM byte when used as r/m operand]" wideRegisters := {(EAX -> #[16r40 16rC0]). (RAX -> #[16r48 16rC0]). (R8D -> #[16r44 16rC0]). (R8 -> #[16r4C 16rC0])}. "byteRMOperands -- operand -> #(REX prefix, #[modRMContribution, SIB and displacement bytes if any])" byteRMOperands := {(SPL -> #(16r40 #[16rC4])). (BPL -> #(16r40 #[16rC5])). (SIL -> #(16r40 #[16rC6])). (DIL -> #(16r40 #[16rC7])). (R8B -> #(16r41 #[16rC0])). (AL -> #(16r40 #[16rC0])). (R8 ptr -> #(16r41 #[16r00])). (RAX ptr -> #(16r40 #[16r00])). (R8 ptr + 16r12 -> #(16r41 #[16r40 16r12])). (RAX ptr + 16r12 -> #(16r40 #[16r40 16r12])). (R8 ptr + 16r1234 -> #(16r41 #[16r80 16r34 16r12 16r00 16r00])). (RAX ptr + 16r1234 -> #(16r40 #[16r80 16r34 16r12 16r00 16r00])). ((RAX ptr + R8) * 2 -> #(16r42 #[16r04 16r40])). ((RAX ptr + RAX) * 2 -> #(16r40 #[16r04 16r40])). ((RAX ptr + R8) * 4 + 16r12 -> #(16r42 #[16r44 16r80 16r12])). ((RAX ptr + RAX) * 4 + 16r12 -> #(16r40 #[16r44 16r80 16r12])). ((RAX ptr + R8) * 8 + 16r1234 -> #(16r42 #[16r84 16rC0 16r34 16r12 16r00 16r00])). ((RAX ptr + RAX) * 8 + 16r1234 -> #(16r40 #[16r84 16rC0 16r34 16r12 16r00 16r00]))}. byteRegs do: [ :reg | byteRMOperands do: [ :rm | opBothCodes do: [ :opcode | | opcodeByte op1 op2 | op1 := reg key. op2 := rm key. opcodeByte := opcode value last. self assert: [ :a | a perform: opcode key with: op1 with: op2 ] bytes: (ByteArray with: rm value first with: opcodeByte with: reg value | rm value last first) , rm value last allButFirst "REX" "ModRM" "SIB and displacement" "Need to add the necessary data to allow testing the reverse order of operands." ]. op2codes do: [ :opcode | self assert: [ :a | a perform: opcode key with: rm key with: reg key ] bytes: ((ByteArray with: rm value first) , opcode value copyWith: reg value | rm value last first) , rm value last allButFirst "REX" "ModRM" "SIB and displacement" ] ]. mixedWidthOpCodes do: [ :opcode | wideRegisters do: [ :rm | self assert: [ :a | a perform: opcode key with: rm key with: reg key ] bytes: ((ByteArray with: rm value first) , opcode value copyWith: reg value >> 3 | rm value last) "REX" "ModRM" "SIB and displacement" ] ] ]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:30'! testAssembly01 self assert: [ :a | self assert: (a reg: 8 size: 4) = R8D. "mov $0xfeedface,%r8d" a mov: 16rfeedface asUImm to: R8D ] bytes: #[65 184 206 250 237 254]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:31'! testAssembly2 self assert: [ :a| asm push: a BP; mov: a SP -> a BP; mov: 16r400 -> a RAX; mov: a BP -> a SP; pop: a RSP; ret. ] bytes: #[ 102 85 102 139 236 72 199 192 0 4 0 0 102 139 229 92 195] ! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:31'! testAssembly1 self assert: [ :a| a push: a RBP; mov: a RSP -> a RBP; mov: 1024 -> a RAX; mov: a RBP -> a RSP; pop: a RBP; ret.] bytes: #[ 85 72 139 236 72 199 192 0 4 0 0 72 139 229 93 195]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/25/2013 21:11'! testMovZX "byte to word ========================================" "lower bank 8bit to lower bank 16bit" self assert: [:a | a movzx: a AL to: a AX ] bytes: #[102 15 182 192 ]. "lower bank 8bit to upper bank 16bit" self assert: [:a | a movzx: a AL to: a R8W ] bytes: #[102 68 15 182 192]. "upper bank 8bit to lower bank 16bit" self assert: [:a | a movzx: a R8B to: a AX ] bytes: #[102 65 15 182 192]. "upper bank 8bit to upper bank 16bit" self assert: [:a | a movzx: a R8B to: a R8W ] bytes: #[102 69 15 182 192]. "byte to doubleword ================================" "lower bank 8bit to lower bank 32bit" self assert: [:a | a movzx: a AL to: a EAX ] bytes: #[15 182 192 ]. "lower bank 8bit to upper bank 32bit" self assert: [:a | a movzx: a AL to: a R8D ] bytes: #[68 15 182 192]. "upper bank 8bit to lower bank 32bit" self assert: [:a | a movzx: a R8B to: a EAX ] bytes: #[65 15 182 192]. "upper bank 8bit to upper bank 32bit" self assert: [:a | a movzx: a R8B to: a R8D ] bytes: #[69 15 182 192]. "byte to quadword ===================" "lower bank 8bit to lower bank 64bit" self assert: [:a | a movzx: a AL to: a RAX ] bytes: #[72 15 182 192 ]. "lower bank 8bit to upper bank 64bit" self assert: [:a | a movzx: a AL to: a R8 ] bytes: #[76 15 182 192]. "upper bank 8bit to lower bank 64bit" self assert: [:a | a movzx: a R8B to: a RAX ] bytes: #[73 15 182 192 ]. "upper bank 8bit to upper bank 64bit" self assert: [:a | a movzx: a R8B to: a R8 ] bytes: #[77 15 182 192]. "word to quadword ===================" "lower bank 16bit to lower bank 64bit" self assert: [:a | a movzx: a AX to: a RAX ] bytes: #[72 15 183 192]. "lower bank 16bit to upper bank 64bit" self assert: [:a | a movzx: a AX to: a R8 ] bytes: #[76 15 183 192]. "upper bank 16bit to lower bank 64bit" self assert: [:a| a movzx: a R8W to: a RAX ] bytes: #[73 15 183 192]. "upper bank 16bit to upper bank 64bit" self assert: [:a | a movzx: a R8W to: a R8 ] bytes: #[77 15 183 192].! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/25/2013 20:37'! testAssemblyImmAddr "This is not supported in 64-bit mode -- the ModRM value for this results in RIP-relative addressing." super testAssemblyImmAddr! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:40'! testMul "8bit unsigned multiplication ==================================" "lower bank register: AX := AL * CL" self assert: [ :a | a mul: a CL] bytes: #[ 16rF6 "ModR/M" 2r11100001 ]. "upper bank register needs an REX prefix: AX := AL * R8B" self assert: [ :a | a mul: a R9B] bytes: #[ 2r01000001 16rF6 2r11100001]. "16bit unsigned multiplication ==================================" "DX:AX := AX * CX" self assert: [ :a | a mul: a CX] bytes: #[ "16bit fallback" 16r66 16rF7 2r11100001]. "32bit unsigned multiplication ==================================" "EDX:EAX := EAX * ECX" self assert: [ :a | a mul: a ECX] bytes: #[ 16rF7 2r11100001 ]. "64bit unsigned multiplication ==================================" "RDX:RAX := RAX * RCX" self assert: [ :a| a mul: a RCX] bytes: #[ 2r01001000 16rF7 2r11100001].! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/25/2013 19:41'! testXorInvalid "xor registers with non-matching sizes" self asmShould: [ :a | a xor: AL to: RAX ] raise: Error. self asmShould: [ :a | a xor: RAX to: AL ] raise: Error. self asmShould: [ :a | a xor: R8B to: RAX ] raise: Error. self asmShould: [ :a | a xor: RAX to: R8B ] raise: Error. "in 64bit mode AH CH DH and BH cannot be encoded when an REX prefix is present" {AH. CH. DH. BH} do: [ :reg | self asmShould: [ :a | a xor: reg to: a R8B ] raise: Error ]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/3/2013 21:36'! testIndexScales self assert: [ :a | a mov: RAX -> ((RCX ptr + RDX) * 1) ] bytes: #[16r48 16r89 16r04 16r11]; assert: [ :a | a mov: RAX -> ((RCX ptr + RDX) * 2) ] bytes: #[16r48 16r89 16r04 16r51]; assert: [ :a | a mov: RAX -> ((RCX ptr + RDX) * 4) ] bytes: #[16r48 16r89 16r04 16r91]; assert: [ :a | a mov: RAX -> ((RCX ptr + RDX) * 8) ] bytes: #[16r48 16r89 16r04 16rD1]. self assert: [ :a | a mov: (RCX ptr + RDX) * 1 -> RAX ] bytes: #[16r48 16r8B 16r04 16r11]; assert: [ :a | a mov: (RCX ptr + RDX) * 2 -> RAX ] bytes: #[16r48 16r8B 16r04 16r51]; assert: [ :a | a mov: (RCX ptr + RDX) * 4 -> RAX ] bytes: #[16r48 16r8B 16r04 16r91]; assert: [ :a | a mov: (RCX ptr + RDX) * 8 -> RAX ] bytes: #[16r48 16r8B 16r04 16rD1]! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:14'! testAssemblyMemBytes asm mov: (RSI ptr + ECX size: 1) -> BL; mov: BL -> (RSI ptr + ECX size: 1). self assert: asm bytes = #(16r8A 16r1C 16r0E 16r88 16r1C 16r0E) asByteArray! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/27/2013 16:46'! testCall "relative calls ===================================================================" "8bit offset" self assert: [:a | a call: 16r12 ] bytes: #[ 16rE8 16r12 0 0 0]. "16bit offset" self assert: [:a | a call: 16r1234 ] bytes: #[ 16rE8 16r34 16r12 0 0 ]. "32bit offset" self assert: [:a | a call: 16r12345678 ] bytes: #[ 16rE8 16r78 16r56 16r34 16r12 ]. "indirect calls ===================================================================" "lower bank register" self assert: [:a | a call: asm RAX ] bytes: #[ 16rFF 2r11010000 ]. self assert: [:a | a call: asm RDI ] bytes: #[ 16rFF 2r11010111 ]. "upper bank register (require REX prefix)" self assert: [:a | a call: asm R8 ] bytes: #[ 2r01001001 16rFF 2r11010000 ]. self assert: [:a | a call: asm R15 ] bytes: #[ 2r01001001 16rFF 2r11010111 ]. "double indirect calls (with ModR/M) ==============================================" "mod = 2r00" "lower bank register" self assert: [:a | a call: a RAX ptr ] bytes: #[ 16rFF 2r00010000 ]. self assert: [:a | a call: a RDI ptr ] bytes: #[ 16rFF 2r00010111 ]. "upper bank register (require REX prefix)" self assert: [:a | a call: a R8 ptr ] bytes: #[ 2r01000001 16rFF 2r00010000 ]. self assert: [:a | a call: a R15 ptr ] bytes: #[ 2r01000001 16rFF 2r00010111 ]. "double indirect calls with offsets ==============================================" "mod = 2r01 hence with a folllwing 8bit offset" "lower bank register" self assert: [:a | a call: a RAX ptr + 8 ] bytes: #[ 16rFF 2r01010000 8]. self assert: [:a | a call: a RDI ptr + 8 ] bytes: #[ 16rFF 2r01010111 8]. "upper bank register (require REX prefix)" self assert: [:a | a call: a R8 ptr + 8] bytes: #[ 2r01000001 16rFF 2r01010000 8]. self assert: [:a | a call: a R15 ptr + 8] bytes: #[ 2r01000001 16rFF 2r01010111 8]. "double indirect calls with offsets ==============================================" "mod = 2r10 hence with a following 32bit offset" "lower bank register" self assert: [:a | a call: a RAX ptr + 16r12345678 ] bytes: #[ 16rFF 2r10010000 16r78 16r56 16r34 16r12]. self assert: [:a | a call: a RDI ptr + 16r12345678 ] bytes: #[ 16rFF 2r10010111 16r78 16r56 16r34 16r12]. "upper bank register (require REX prefix)" self assert: [:a | a call: a R8 ptr + 16r12345678] bytes: #[ 2r01000001 16rFF 2r10010000 16r78 16r56 16r34 16r12]. self assert: [:a | a call: a R15 ptr + 16r12345678] bytes: #[ 2r01000001 16rFF 2r10010111 16r78 16r56 16r34 16r12].! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/4/2013 21:57'! testMovHighIndexRegister "Mov that use r8-r15 as an index register, therefore requiring REX.X" self assert: [ :a | a mov: RAX -> ((RCX ptr + R14) * 1) ] bytes: #[16r4A 16r89 16r04 16r31]; assert: [ :a | a mov: (RCX ptr + R14) * 1 -> RAX ] bytes: #[16r4A 16r8B 16r04 16r31]! ! !AJx64AssemblerTests methodsFor: 'utility' stamp: ''! newAssembler ^ AJx64Assembler new noStackFrame; yourself! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:36'! testJumps self assert: [:a| a label: #label1; nop; nop; nop; jz: #label1. ] bytes: #[144 144 144 16r74 251 "-5 asByte"]. asm reset; noStackFrame; label: #label1. 126 timesRepeat: [ asm nop ]. asm jz: #label1. self assert: (asm bytes size = 128). self assert: [:a | a reset; noStackFrame; label: #label1; nop; nop; nop; jmp: #label1. ] bytes: #[144 144 144 235 251 ]. self assert: [:a | a reset; noStackFrame; jmp: #label1; label: #label1. ] bytes: #[ 16rEB 0 ]. ! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:14'! testAssemblyMemBaseDisp2 asm mov: RAX ptr - 1 -> EAX; mov: (RBX ptr + ECX) * 2 - 5 -> EAX. self assert: asm bytes = #(16r8B 16r40 16rFF 16r8B 16r44 16r4B 16rFB) asByteArray! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:44'! testTest "8bit operand and lower bank 8bit register" self assert: [:a | a test: a CL with: 16r12 ] bytes: #[246 193 16r12]. "8bit operand and uppe bank 8bit register" self assert: [:a | a test: a R8B with: 16r12] bytes: #[2r01000001 2r11110110 2r11000000 16r12]. "16bit operand and lower bank 16bit register" self assert: [:a | a test: a CX with: 16r1234] bytes: #[102 247 193 16r34 16r12]. "16bit operand and uppe bank 16bit register" self assert: [:a | a test: a R8W with: 16r1234] bytes: #[102 65 247 192 16r34 16r12]. "32bit operand and lower bank 32bit register" self assert: [:a | a test: a ECX with: 16r12345678] bytes: #[247 193 16r78 16r56 16r34 16r12]. "32bit operand and uppe bank 32bit register" self assert: [:a | a test: a R8D with: 16r12345678] bytes: #[65 247 192 16r78 16r56 16r34 16r12]. "32bit operand and lower bank 64bit register" self assert: [:a| a test: a RCX with: 16r12345678] bytes: #[72 247 193 16r78 16r56 16r34 16r12]. "32bit operand and uppe bank 64bit register" self assert: [:a| a test: a R8 with: 16r12345678] bytes: #[73 247 192 16r78 16r56 16r34 16r12]. ! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:44'! testXor "8bit register xor 8bit immediate ==================================" "lower bank 8bit register opcode + ModR/M" self assert: [ :a | a xor: a CL with: 16r12] bytes: #[ 16r80 2r11110001 16r12]. "upper bank 8bit register requiring REX" self assert: [ :a | a xor: a R8B with: 16r12] bytes: #[2r01000001 16r80 2r11110000 16r12]. "16bit register xor 8bit immediate ==================================" "lower bank 16bit register" self assert: [ :a | a xor: a CX with: 16r1234] bytes: #[16r66 16r81 2r11110001 16r34 16r12]. "upper bank 16bit" self assert: [ :a | a xor: a R8W with: 16r1234] bytes: #[16r66 2r01000001 16r81 2r11110000 16r34 16r12]. "32bit register =====================================================" "lower bank 32bit register" self assert: [ :a | a xor: a ECX with: 16r12345678] bytes: #[16r81 2r11110001 16r78 16r56 16r34 16r12]. "upper bank register requiring REX prefix" self assert: [ :a | a xor: a R8D with: 16r12345678] bytes: #[2r01000001 16r81 2r11110000 16r78 16r56 16r34 16r12] ! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/1/2013 22:14'! testImmLabels "test immediates with labels" | code pos | asm mov: RAX ptr -> EAX; mov: (16rFFFFFFFF asUImm label: (asm labelNamed: #foo)) to: EAX. code := asm generatedCode. pos := code offsetAt: #foo. self assert: (code bytes at: pos + 1) = 255. self assert: (code bytes at: pos + 2) = 255. self assert: (code bytes at: pos + 3) = 255. self assert: (code bytes at: pos + 4) = 255! ! !AJx64AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 1/25/2013 19:34'! testMovZxSxInvalid {AH. CH. DH. BH} do: [ :reg | self deny: (self bytes: [ :a | a movzx: reg to: a EAX ]) isEmpty. self asmShould: [ :a | a movzx: reg to: a RAX ] raise: Error ]! ! !AJx64AssemblerTests class methodsFor: 'as yet unclassified' stamp: ''! shouldInheritSelectors ^ true! ! !AJx64Instruction commentStamp: 'TorstenBergmann 1/30/2014 09:17'! The x86 - 64 bit machine instructions! !AJx64Instruction methodsFor: 'accessing' stamp: ''! instructionDesciptions ^ AJx64InstructionDescription instructions! ! !AJx64Instruction methodsFor: 'testing' stamp: ''! is64BitMode ^ true! ! !AJx64Instruction methodsFor: 'testing' stamp: 'MartinMcClure 1/30/2013 20:59'! requiresRex "Answer true if I absolutely must have a REX prefix." ^ (operands detect: [ :rawOp | | op | op := rawOp asAJOperand. op requiresRex | op is64 ] ifNone: [ #none ]) ~~ #none! ! !AJx64Instruction methodsFor: 'testing' stamp: ''! is32BitMode ^ false! ! !AJx64InstructionDescription commentStamp: 'TorstenBergmann 1/30/2014 09:19'! X64 instruction description! !AJx64InstructionDescription methodsFor: 'code emitting' stamp: ''! emitbswap: emitter operand1: op1 operand2: op2 operand3: op3 op1 isReg ifTrue: [ emitter emitRexForSingleOperand: op1. emitter emitByte: 16r0F. ^ emitter emitModR: 1 r: op1 code ]. self invalidInstruction.! ! !AJx64InstructionDescription methodsFor: 'code emitting' stamp: ''! emitpop: emitter operand1: op1 operand2: op2 operand3: op3 op1 isReg ifTrue: [ self assert: op1 isGeneralPurpose. (op1 is32 or: [ op1 is8 ]) ifTrue: [ Error signal: 'invalid register ', op1 name, '. push/pop requires 64bit/16bit reg in 64bit mode']. ^ emitter emitX86Inl: opCode1 reg: op1 withRex: op1 isUpperBank. ]. op1 isMem ifFalse: [ self invalidInstruction ]. emitter emitX86RM: opCode2 size: op1 size regOrCode: opCodeR rm: op1 ! ! !AJx64InstructionDescription methodsFor: 'code emitting' stamp: 'CamilloBruni 4/17/2012 18:43'! emitcall: emitter operand1: op1 operand2: op2 operand3: op3 (op1 isReg and: [ op1 is64 and: [ op1 isUpperBank not ]]) ifTrue: [ "shortcut" emitter emitByte: 16rFF. op1 emitModRM: emitter code: 2 immSize: 4. ^ self]. (op1 isMem and: [op1 hasBase and: [ op1 base is64 and: [ op1 base isUpperBank not ]]]) ifTrue: [ "shortcut" emitter emitByte: 16rFF. op1 emitModRM: emitter code: 2 immSize: 4. ^ self]. (op1 isMem or: [ op1 isReg and: [ op1 is64 ] ]) ifTrue: [ ^ emitter emitX86RM: 16rFF size: 4 regOrCode: 2 rm: op1 ]. op1 isImm ifTrue: [ "call by relative offset, you should be really sure what you're' doing" emitter emitByte: 16rE8. op1 emitUsing: emitter size: 4. ^ self. ]. op1 isLabel ifTrue: [ emitter emitByte: 16rE8. emitter emitDisplacement: op1 inlinedDisp: -4. ^ self ]. self invalidInstruction. ! ! !AJx64InstructionDescription methodsFor: 'code emitting' stamp: 'MartinMcClure 1/30/2013 22:13'! emitmovSxZx: emitter operand1: dst operand2: src operand3: op3 dst isReg & src isRegMem ifFalse: [ self invalidInstruction ]. src size >= dst size ifTrue: [ self invalidInstruction ]. dst isGeneralPurpose ifFalse: [ self invalidInstruction ]. src is16 ifTrue: [ ^ emitter emitX86RM: opCode1 + 1 size: dst size regOrCode: dst rm: src ]. src is32 ifTrue: [ self invalidInstruction ]. "64 bit source" emitter emitX86RM: opCode1 size: dst size regOrCode: dst rm: src! ! !AJx64InstructionDescription methodsFor: 'code emitting' stamp: 'IgorStasenko 5/28/2012 03:01'! emitmov: emitter operand1: dst operand2: src operand3: op3 src isReg & dst isReg ifTrue: [ self assert: (src isRegTypeGPB | src isRegTypeGPW | src isRegTypeGPD | src isRegTypeGPQ ). ]. " reg <- mem " dst isReg & src isRegMem ifTrue: [ self assert: (dst isRegTypeGPB | dst isRegTypeGPW | dst isRegTypeGPD | dst isRegTypeGPQ ). src isMem ifTrue: [ (src base notNil and: [ src base is64 not ]) ifTrue: [ Error signal: 'use a 64bit base register instead of ', src base asString, '(', (src base size * 8) asString, 'bit) for memory access on a 64bit CPU' ]] ifFalse:[ (src size = dst size) ifFalse: [ Error signal: 'source ',src asString,' and destination ',dst asString,' need to have the same size' ]]. ^ emitter emitX86RM: 16r0000008A + dst isRegTypeGPB not asBit size: dst size regOrCode: dst rm: src ]. " reg <- imm " dst isReg & src isImm ifTrue: [ | immSize | immSize := dst size. "Optimize instruction size by using 32 bit immediate if value can fit to it" emitter is64BitMode & immSize = 8 & src isInt32 & (src relocMode == #RelocNone) ifTrue: [ emitter emitX86RM: 16rC7 size: dst size regOrCode: 0 rm: dst. immSize := 4 ] ifFalse: [ emitter emitX86Inl: (immSize=1 ifTrue: [16rB0] ifFalse: [16rB8]) reg: dst. ]. ^ emitter emitImmediate: src size: immSize ]. "mem <- reg" dst isMem & src isReg ifTrue: [ self assert: (src isRegTypeGPB | src isRegTypeGPW | src isRegTypeGPD | src isRegTypeGPQ ). ^ emitter emitX86RM: 16r88 + src isRegTypeGPB not asBit size: src size regOrCode: src rm: dst ]. "mem <- imm" dst isMem & src isImm ifTrue: [ | immSize | immSize := dst size <= 4 ifTrue: [ dst size ] ifFalse: [4]. emitter emitX86RM: 16rC6 + ((dst size = 1) not) asBit size: dst size regOrCode: 0 rm: dst immSize: immSize. ^ emitter emitImmediate: src size: immSize ]. self invalidInstruction ! ! !AJx64InstructionDescription methodsFor: 'code emitting' stamp: 'HenrikSperreJohansen 6/26/2014 14:40'! emitalu: emitter operand1: op1 operand2: op2 operand3: op3 | opCode opReg | opCode := opCode1. opReg := opCodeR. " Mem <- Reg " (op1 isMem and: [ op2 isReg ]) ifTrue: [ ^ emitter emitX86RM: opCode + op2 isRegTypeGPB not asBit size: op2 size regOrCode: op2 rm: op1 ]. "Reg <- Reg|Mem" (op1 isReg and: [ op2 isRegMem ]) ifTrue: [ (op2 isReg and: [ op1 size ~= op2 size ]) ifTrue: [ self invalidInstruction ]. ^ emitter emitX86RM: opCode + 2 + op1 isRegTypeGPB not asBit size: op1 size regOrCode: op1 rm: op2 ]. op2 isImm ifFalse: [ self invalidInstruction ]. " AL, AX, EAX, RAX register shortcuts" (op1 isRegIndex: 0) ifTrue: [ emitter emitOperandSizeOverridePrefix: op1. emitter emitByte: (opReg << 3 bitOr: 16r04 + op1 isRegTypeGPB not asBit). ^ emitter emitImmediate: op2 size: (op1 size min: 4) ]. "short constant" op2 isInt8 ifTrue: [ | szBits | szBits := op1 size = 1 ifTrue: [ 0 ] ifFalse: [ 3 ]. emitter emitX86RM: opCode2 + szBits size: op1 size regOrCode: opReg rm: op1 immSize: 1. ^ emitter emitImmediate: op2 size: 1 ]. op1 isRegMem ifTrue: [ | immSize szBits | immSize := op2 isInt8 ifTrue: [ 1 ] ifFalse: [ op1 size min: 4 ]. szBits := op1 size ~= 1 ifTrue: [ immSize ~= 1 ifTrue: [ 1 ] ifFalse: [ 3 ] ] ifFalse: [ 0 ]. emitter emitX86RM: opCode2 + szBits size: op1 size regOrCode: opReg rm: op1 immSize: immSize. ^ emitter emitImmediate: op2 size: immSize ]. self invalidInstruction! ! !AJx64InstructionDescription methodsFor: 'code emitting' stamp: ''! emitmovPtr: emitter operand1: op1 operand2: op2 operand3: op3 | reg imm opCode | (op1 isReg & op2 isImm) | (op1 isImm & op2 isReg) ifFalse: [ self invalidInstruction ]. opCode := op1 isReg ifTrue: [reg := op1. imm := op2. 16rA0] ifFalse: [reg := op2. imm := op1. 16rA2]. reg index ~= 0 ifTrue: [ self invalidInstruction ]. reg isRegTypeGPW ifTrue: [ emitter emitByte: 16r66 ]. emitter emitRexForSingleOperand: reg. emitter emitByte: opCode + (reg size ~=1) asBit. emitter emitImmediate: imm size: reg size ! ! !AJx64JumpInstruction commentStamp: 'TorstenBergmann 1/30/2014 09:18'! Jump instruction for X64! !AJx64JumpInstruction methodsFor: 'accessing' stamp: ''! instructionDesciptions ^ AJx64InstructionDescription instructions! ! !AJx64RipRegister commentStamp: ''! Virtual registers used for relative instruction pointer addressing in 64Bit mode In IA-32 architecture and compatibility mode, addressing relative to the instruction pointer is available only with control-transfer instructions. In 64-bit mode, instruc- tions that use ModR/M addressing can use RIP-relative addressing. Without RIP-rela- tive addressing, all ModR/M instruction modes address memory relative to zero.! !AJx64RipRegister methodsFor: 'converting' stamp: ''! as64 ^ AJx86Registers at: #RIP! ! !AJx64RipRegister methodsFor: 'accessing' stamp: ''! code self ripAccessError! ! !AJx64RipRegister methodsFor: 'converting' stamp: ''! as32 ^ AJx86Registers at: #EIP! ! !AJx64RipRegister methodsFor: 'testing' stamp: ''! isRip ^ true! ! !AJx64RipRegister methodsFor: 'accessing' stamp: 'CamilloBruni 7/17/2012 12:48'! influencingRegisters self is16 ifFalse: [ ^ self as16 influencingRegisters ]. ^ { self as16. self as32. self as64 }! ! !AJx64RipRegister methodsFor: 'error' stamp: ''! ripAccessError self error: 'RIP register ', self name, ' cannot be used only for relative addressing'! ! !AJx64RipRegister methodsFor: 'converting' stamp: ''! as8 self error: 'No 8bit register available for instruction pointer relative addressing'! ! !AJx64RipRegister methodsFor: 'printing' stamp: 'CamilloBruni 7/17/2012 11:08'! descriptionOn: s s nextPutAll: 'A '; print: self size * 8; nextPutAll: 'bit instruction pointer register'.! ! !AJx64RipRegister methodsFor: 'testing' stamp: ''! isGeneralPurpose ^ false! ! !AJx64RipRegister methodsFor: 'testing' stamp: ''! isUpperBank ^ false! ! !AJx64RipRegister methodsFor: 'converting' stamp: ''! as16 ^ AJx86Registers at: #IP! ! !AJx64RipRegister methodsFor: 'testing' stamp: 'CamilloBruni 7/17/2012 11:01'! isX86 ^ false! ! !AJx64RipRegister methodsFor: 'accessing' stamp: ''! index self ripAccessError! ! !AJx86Assembler commentStamp: ''! I am an Assmbler for the Intel x86 (32Bit) architecture. Example: asm := AJx64Assembler new. "by default the assembler will set up a stack frame" asm noStackFrame. "load the constant 16r12 into the RAX register" asm mov: 16r12 to: asm RAX. "output the bytes for this instruction" asm bytes ! !AJx86Assembler methodsFor: 'alignment' stamp: ''! alignDouble self addInstruction: AJAlignmentInstruction alignDouble! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fldenv: aMemoryOperand "Load x87 FPU Environment Pseudo Code ----------- FPUControlWord = SRC[FPUControlWord]; FPUStatusWord = SRC[FPUStatusWord]; FPUTagWord = SRC[FPUTagWord]; FPUDataPointer = SRC[FPUDataPointer]; FPUInstructionPointer = SRC[FPUInstructionPointer]; FPULastInstructionOpcode = SRC[FPULastInstructionOpcode]; Description ----------- Loads the complete x87 FPU operating environment from memory into the FPU registers. The source operand specifies the first byte of the operating-environment data in memory. This data is typically written to the specified memory location by a FSTENV or FNSTENV instruction. The FPU operating environment consists of the FPU control word, status word, tag word, instruction pointer, data pointer, and last opcode. Figures 8-9 through 8-12 in the Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1, show the layout in memory of the loaded environment, depending on the operating mode of the processor (protected or real) and the current operand-size attribute (16-bit or 32-bit). In virtual-8086 mode, the real mode layouts are used. The FLDENV instruction should be executed in the same operating mode as the corresponding FSTENV/FNSTENV instruction. If one or more unmasked exception flags are set in the new FPU status word, a floating-point exception will be generated upon execution of the next floating-point instruction (except for the no-wait floating-point instructions, see the section titled 'Software Exception Handling' in Chapter 8 of the Intel®64 and IA-32 ArchitecturesSoftware Developer's Manual, Volume 1). To avoid generating exceptions when loading a new environment, clear all the exception flags in the FPU status word that is being loaded. If a page or limit fault occurs during the execution of this instruction, the state of the x87 FPU registers as seen by the fault handler may be different than the state being loaded from memory. In such situations, the fault handler should ignore the status of the x87 FPU registers, handle the fault, and return. The FLDENV instruction will then complete the loading of the x87 FPU registers with no resulting context inconsistency. This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #fldenv operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movzx: aDestinationRegister with: aSourceRegisterOrMemory "Move with Zero-Extend Pseudo Code ----------- DEST = ZeroExtend(SRC); Description ----------- Copies the contents of the source operand (register or memory location) to the destination operand (register) and zero extends the value. The size of the converted value depends on the operand-size attribute. In 64-bit mode, the instruction's default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8-R15). Use of the REX.W prefix promotes operation to 64 bit operands. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #movzx operands: { aDestinationRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! amdprefetch: aMemoryOperand " " ^ self addInstruction: #amdprefetch operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jno: targetLabel "Jump short if not overflow (OF=0) " ^ self addInstruction: #jno operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! ESP "A 32bit general purpose register This register overlaps with AH, AX, EAX, RAX" ^ ESP! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jnae: targetLabel " " ^ self addInstruction: #jnae operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fxsave: aMemoryOperand "Save x87 FPU, MMX, XMM, and MXCSR State Description ----------- Saves the current state of the x87 FPU, MMX technology, XMM, and MXCSR registers to a 512-byte memory location specified in the destination operand. The content layout of the 512 byte region depends on whether the processor is operating in non-64-bit operating modes or 64-bit sub-mode of IA-32e mode. Bytes 464:511 are available to software use. The processor does not write to bytes 464:511 of an FXSAVE area. The operation of FXSAVE in non-64-bit modes is described first. ### Non-64-Bit Mode Operation The following table shows the layout of the state information in memory when the processoris operating in legacy modes. ------------- --------- -------- ----- -------- ----- ----- ----- --- --- --- --- --- --- --- --- -- 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Rsrvd CS FPU IP FOP Rs rvd FTW FSW FCW 0 MXCSR\_MASK MXCSR Rsrvd DS FPU DP 16 Reserved ST0/MM0 32 Reserved ST1/MM1 48 Reserved ST2/MM2 64 Reserved ST3/MM3 80 Reserved ST4/MM4 96 Reserved ST5/MM5 112 Reserved ST6/MM6 128 Reserved ST7/MM7 144 XMM0 160 XMM1 176 XMM2 192 XMM3 208 XMM4 224 XMM5 240 XMM6 256 XMM7 272 Reserved 288 Reserved 304 Reserved 320 Reserved 336 Reserved 352 Reserved 368 Reserved 384 Reserved 400 Reserved 416 Reserved 432 Reserved 448 Available 464 Available 480 Available 496 ------------- --------- -------- ----- -------- ----- ----- ----- --- --- --- --- --- --- --- --- -- : Non-64-bit-Mode Layout of FXSAVE and FXRSTOR Memory Region The destination operand contains the first byte of the memory image, and it must be aligned on a 16-byte boundary. A misaligned destination operand will result in a general-protection (\#GP) exception being generated (or in some cases, an alignment check exception [\#AC]). The FXSAVE instruction is used when an operating system needs to perform a context switch or when an exception handler needs to save and examine the current state of the x87 FPU, MMX technology, and/or XMM and MXCSR registers. The fields used in the previous table are defined in the following table. Field Definitions Field Definition FCW x87 FPU Control Word (16 bits). See Figure 8-6 in the Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1, for the layout of the x87 FPU control word. FSW x87 FPU Status Word (16 bits). See Figure 8-4 in the Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1, for the layout of the x87 FPU status word. Abridged FTW x87 FPU Tag Word (8 bits). The tag information saved here is abridged, as described in the following paragraphs. FOP x87 FPU Opcode (16 bits). The lower 11 bits of this field contain the opcode, upper 5 bits are reserved. See Figure 8-8 in the Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1, for the layout of the x87 FPU opcode field. FPU IP x87 FPU Instruction Pointer Offset (32 bits). The contents of this field differ depending on the current addressing mode (32-bit or 16-bit) of the processor when the FXSAVE instruction was executed: - 32-bit mode — 32-bit IP offset. - 16-bit mode — low 16 bits are IP offset; high 16 bits are reserved. See 'x87 FPU Instruction and Operand (Data) Pointers' in Chapter 8 of the Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1, for a description of the x87 FPU instruction pointer. CS x87 FPU Instruction Pointer Selector (16 bits). FPU DP x87 FPU Instruction Operand (Data) Pointer Offset (32 bits). The contents of this field differ depending on the current addressing mode (32-bit or 16bit) of the processor when the FXSAVE instruction was executed: - 32-bit mode — 32-bit DP offset. - 16-bit mode — low 16 bits are DP offset; high 16 bits are reserved. See 'x87 FPU Instruction and Operand (Data) Pointers' in Chapter 8 of the Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1, for a description of the x87 FPU operand pointer. DS x87 FPU Instruction Operand (Data) Pointer Selector (16 bits). MXCSR MXCSR Register State (32 bits). See Figure 10-3 in the Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1, for the layout of the MXCSR register. If the OSFXSR bit in control register CR4 is not set, the FXSAVE instruction may not save this register. This behavior is implementation dependent. MXCSR\_ MXCSR\_MASK (32 bits). This mask can be used to adjust values written to MASK the MXCSR register, ensuring that reserved bits are set to 0. Set the mask bits and flags in MXCSR to the mode of operation desired for SSE and SSE2 SIMD floating-point instructions. See 'Guidelines for Writing to the MXCSR Register' in Chapter 11 of the Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1, for instructions for how to determine and use the MXCSR\_MASK value. ST0/MM0 through x87 FPU or MMX technology registers. These 80-bit fields contain the x87 ST7/MM7 FPU data registers or the MMX technology registers, depending on the state of the processor prior to the execution of the FXSAVE instruction. If the processor had been executing x87 FPU instruction prior to the FXSAVE instruction, the x87 FPU data registers are saved; if it had been executing MMX instructions (or SSE or SSE2 instructions that operated on the MMX technology registers), the MMX technology registers are saved. When the MMX technology registers are saved, the high 16 bits of the field are reserved. XMM0 through XMM7 XMM registers (128 bits per field). If the OSFXSR bit in control register CR4 is not set, the FXSAVE instruction may not save these registers. This behavior is implementation dependent. The FXSAVE instruction saves an abridged version of the x87 FPU tag word in the FTW field (unlike the FSAVE instruction, which saves the complete tag word). The tag information is saved in physical register order (R0 through R7), rather than in top-ofstack (TOS) order. With the FXSAVE instruction, however, only a single bit (1 for valid or 0 for empty) is saved for each tag. For example, assume that the tag word is currently set as follows: ---- ---- ---- ---- ---- ---- ---- ---- R7 R6 R5 R4 R3 R2 R1 R0 11 xx xx xx 11 11 11 11 ---- ---- ---- ---- ---- ---- ---- ---- Here, 11B indicates empty stack elements and 'xx' indicates valid (00B), zero (01B), or special (10B). For this example, the FXSAVE instruction saves only the following 8 bits of information: ---- ---- ---- ---- ---- ---- ---- ---- R7 R6 R5 R4 R3 R2 R1 R0 0 1 1 1 0 0 0 0 ---- ---- ---- ---- ---- ---- ---- ---- Here, a 1 is saved for any valid, zero, or special tag, and a 0 is saved for any empty tag. The operation of the FXSAVE instruction differs from that of the FSAVE instruction, the as follows: - FXSAVE instruction does not check for pending unmasked floating-point exceptions. (The FXSAVE operation in this regard is similar to the operation of the FNSAVE instruction). - After the FXSAVE instruction has saved the state of the x87 FPU, MMX technology, XMM, and MXCSR registers, the processor retains the contents of the registers. Because of this behavior, the FXSAVE instruction cannot be used by an application program to pass a 'clean' x87 FPU state to a procedure, since it retains the current state. To clean the x87 FPU state, an application must explicitly execute an FINIT instruction after an FXSAVE instruction to reinitialize the x87 FPU state. - The format of the memory image saved with the FXSAVE instruction is the same regardless of the current addressing mode (32-bit or 16-bit) and operating mode (protected, real address, or system management). This behavior differs from the FSAVE instructions, where the memory image format is different depending on the addressing mode and operating mode. Because of the different image formats, the memory image saved with the FXSAVE instruction cannot be restored correctly with the FRSTOR instruction, and likewise the state saved with the FSAVE instruction cannot be restored correctly with the FXRSTOR instruction. The FSAVE format for FTW can be recreated from the FTW valid bits and the stored 80-bit FP data (assuming the stored data was not the contents of MMX technology registers) using Table 3-50. Exponent all 1's Exponent all 0's Fraction all 0's J and M bits FTW valid bit x87 FTW ----------------------------------- ------------------ ------------------ -------------- --------------- --------- ---- 0 0 0 0x 1 Special 10 0 0 0 1x 1 Valid 00 0 0 1 00 1 Special 10 0 0 1 10 1 Valid 00 0 1 0 0x 1 Special 10 0 1 0 1x 1 Special 10 0 1 1 00 1 Zero 01 0 1 1 10 1 Special 10 1 0 0 1x 1 Special 10 1 0 0 1x 1 Special 10 1 0 1 00 1 Special 10 1 0 1 10 1 Special 10 For all legal combinations above. 0 Empty 11 : Recreating FSAVE Format The J-bit is defined to be the 1-bit binary integer to the left of the decimal place in the significand. The M-bit is defined to be the most significant bit of the fractional portion of the significand (i.e., the bit immediately to the right of the decimal place). When the M-bit is the most significant bit of the fractional portion of the significand, it must be 0 if the fraction is all 0's. ### IA-32e Mode Operation In compatibility sub-mode of IA-32e mode, legacy SSE registers, XMM0 through XMM7, are saved according to the legacy FXSAVE map. In 64-bit mode, all of the SSE registers, XMM0 through XMM15, are saved. Additionally, there are two different layouts of the FXSAVE map in 64-bit mode, corresponding to FXSAVE64 (which requires REX.W=1) and FXSAVE (REX.W=0). In the FXSAVE64 map (following table), theFPU IP and FPU DP pointers are 64-bit wide. In the FXSAVE map for 64-bit mode (see the following tables), the FPU IP and FPU DP pointers are 32-bits. ------------- --------- ---------- ----- ----- ----- --- --- --- --- --- --- --- --- --- --- -- 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 FPU IP FOP Reserved FTW FSW FCW 0 MXCSR\_MASK MXCSR FPU DP 16 Reserved ST0/MM0 32 Reserved ST1/MM1 48 Reserved ST2/MM2 64 Reserved ST3/MM3 80 Reserved ST4/MM4 96 Reserved ST5/MM5 112 Reserved ST6/MM6 128 Reserved ST7/MM7 144 XMM0 160 XMM1 176 XMM2 192 XMM3 208 XMM4 224 XMM5 240 XMM6 256 XMM7 272 XMM8 288 XMM9 304 XMM10 320 XMM11 336 XMM12 352 XMM13 368 XMM14 384 XMM15 400 Reserved 416 Reserved 432 Reserved 448 Available 464 Available 480 Available 496 ------------- --------- ---------- ----- ----- ----- --- --- --- --- --- --- --- --- --- --- -- : Layout of the 64-bit-mode FXSAVE64 Map (requires REX.W = 1) ------------- --------- ---------- -------- ---------- ----- ----- ----- --- --- --- --- --- --- --- --- -- 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Reserved CS FPU IP FOP Reserved FTW FSW FCW 0 MXCSR\_MASK MXCSR Reserved FPU DP 16 Reserved ST0/MM0 32 Reserved ST1/MM1 48 Reserved ST2/MM2 64 Reserved ST3/MM3 80 ------------- --------- ---------- -------- ---------- ----- ----- ----- --- --- --- --- --- --- --- --- -- : Layout of the 64-bit-mode FXSAVE Map (REX.W = 0) Reserved ST4/MM4 96 Reserved ST5/MM5 112 Reserved ST6/MM6 128 Reserved ST7/MM7 144 XMM0 160 XMM1 176 XMM2 192 XMM3 208 XMM4 224 XMM5 240 XMM6 256 XMM7 272 XMM8 288 XMM9 304 XMM10 320 XMM11 336 XMM12 352 XMM13 368 XMM14 384 XMM15 400 Reserved 416 Reserved 432 Reserved 448 Available 464 Available 480 Available 496 " ^ self addInstruction: #fxsave operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! mov: aDestinationRegisterOrMemory with: aSource "Move Description ----------- Copies the second operand (source operand) to the first operand (destination operand). The source operand can be an immediate value, general-purpose register, segment register, or memory location; the destination register can be a general-purpose register, segment register, or memory location. Both operands must be the same size, which can be a byte, a word, a doubleword, or a quadword. The MOV instruction cannot be used to load the CS register. Attempting to do so results in an invalid opcode exception (\#UD). To load the CS register, use the far JMP, CALL, or RET instruction. If the destination operand is a segment register (DS, ES, FS, GS, or SS), the source operand must be a valid segment selector. In protected mode, moving a segment selector into a segment register automatically causes the segment descriptor information associated with that segment selector to be loaded into the hidden (shadow) part of the segment register. While loading this information, the segment selector and segment descriptor information is validated (see the 'Operation' algorithm below). The segment descriptor data is obtained from the GDT or LDT entry for the specified segment selector. A NULL segment selector (values 0000-0003) can be loaded into the DS, ES, FS, and GS registers without causing a protection exception. However, any subsequent attempt to reference a segment whose corresponding segment register is loaded with a NULL value causes a general protection exception (\#GP) and no memory reference occurs. Loading the SS register with a MOV instruction inhibits all interrupts until after the execution of the next instruction. This operation allows a stack pointer to be loaded into the ESP register with the next instruction (MOV ESP, stack-pointer value) before an interrupt occurs1. Be aware that the LSS instruction offers a more efficient method of loading the SS and ESP registers. When operating in 32-bit mode and moving data between a segment register and a general-purpose register, the 32-bit IA-32 processors do not require the use of the 16-bit operand-size prefix (a byte with the value 66H) with this instruction, but most assemblers will insert it if the standard form of the instruction is used (for example, MOV DS, AX). The processor will execute this instruction correctly, but it will usually require an extra clock. With most assemblers, using the instruction form MOV DS, EAX will avoid this unneeded 66H prefix. When the processor executes the instruction with a 32-bit general-purpose register, it assumes that the 16 least-significant bits of the general-purpose register are the destination or source operand. If the register is a destination operand, the resulting value in the two high-order bytes of the register is implementation dependent. For the Pentium 4, Intel Xeon, and P6 family processors, the two high-order bytes are filled with zeros; for earlier 32-bit IA-32 processors, the two high order bytes are undefined. In 64-bit mode, the instruction's default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8-R15). Use of the REX.W prefix promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #mov operands: { aDestinationRegisterOrMemory . aSource }! ! !AJx86Assembler methodsFor: 'initialization' stamp: 'CamilloBruni 3/30/2012 16:20'! initialize is64 := false. self reset.! ! !AJx86Assembler methodsFor: 'register' stamp: ''! data ^ self is32BitMode ifTrue: [ EDX ] ifFalse: [ DX ]! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovbe: aRegister with: aSourceRegisterOrMemory "Conditional Move - below or equal/not above (CF=1 AND ZF=1) " ^ self addInstruction: #cmovbe operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! imul: aRegister with: aRegisterOrMemory with: anImmediate " see #imul" ^ self addInstruction: #imul operands: { aRegister . aRegisterOrMemory . anImmediate }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jnc: targetLabel " " ^ self addInstruction: #jnc operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movmskpd: aRegisterOrMemory1 with: aRegisterOrMemory2 "Extract Packed Double-FP Sign Mask Pseudo Code ----------- DEST[0] = SRC[63]; DEST[1] = SRC[127]; IF DEST = r32 DEST[31:2] = ZeroExtend; ELSE DEST[63:2] = ZeroExtend; FI; Description ----------- Extracts the sign bits from the packed double-precision floating-point values in the source operand (second operand), formats them into a 2-bit mask, and stores the mask in the destination operand (first operand). The source operand is an XMM register, and the destination operand is a general-purpose register. The mask is stored in the 2 low-order bits of the destination operand. Zero-extend the upper bits of the destination. In 64-bit mode, the instruction can access additional registers (XMM8-XMM15, R8-R15) when used with a REX.R prefix. The default operand size is 64-bit in 64-bit mode. " ^ self addInstruction: #movmskpd operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'function calls' stamp: ''! newCdeclCall "answer an instance of CallInfo" ^ stackManager newCdeclCall asm: self.! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovae: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovae operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'converting' stamp: ''! imm: value ^ value asImm ! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jnle: targetLabel "Jump short if not less nor equal/greater ((ZF=0) AND (SF=OF)) " ^ self addInstruction: #jnle operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! adc: aRegisterOrMemoryOperand with: aSource "Add with Carry " ^ self addInstruction: #adc operands: { aRegisterOrMemoryOperand . aSource }! ! !AJx86Assembler methodsFor: 'accessing' stamp: 'CamilloBruni 8/23/2012 16:01'! instructionDesciptions ^ AJx86InstructionDescription instructions! ! !AJx86Assembler methodsFor: 'register' stamp: 'CamilloBruni 1/10/2013 18:58'! stackPointer ^ self is32 ifTrue: [ ESP ] ifFalse: [ RSP ]! ! !AJx86Assembler methodsFor: 'options' stamp: ''! noStackFrame stackManager noStackFrame.! ! !AJx86Assembler methodsFor: 'initialize-release' stamp: ''! reset instructions := last := nil. labels := Dictionary new. stackManager ifNil: [stackManager := AJRoutineStackManager new.] ifNotNil: #reset. level := 0. self addInstruction: AJRoutinePrologue new. ! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM1 "An SSE register" ^ XMM1! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fstcw: aMemoryOperand "Store x87 FPU Control Word " ^ self addInstruction: #fstcw operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! ficom: aMemoryOperand "Compare Integer " ^ self addInstruction: #ficom operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! MM4 "An MMX register" ^ MM4! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovp: aRegister with: aSourceRegisterOrMemory "Conditional Move - parity/parity even (PF=1) " ^ self addInstruction: #cmovp operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fmul: aMemoryOperand "Multiply " ^ self addInstruction: #fmul operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fsubp: aX87Register "Subtract and Pop " ^ self addInstruction: #fsubp operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fucomp: aX87Register "Unordered Compare Floating Point Values and Pop " ^ self addInstruction: #fucomp operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! dec: aRegisterOrMemory "Decrement by 1 Pseudo Code ----------- DEST = DEST - 1; Description ----------- Subtracts 1 from the destination operand, while preserving the state of the CF flag. The destination operand can be a register or a memory location. This instruction allows a loop counter to be updated without disturbing the CF flag. (To perform a decrement operation that updates the CF flag, use a SUB instruction with an immediate operand of 1.) This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. In 64-bit mode, DEC r16 and DEC r32 are not encodable (because opcodes 48H through 4FH are REX prefixes). Otherwise, the instruction's 64-bit mode default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8-R15). Use of the REX.W prefix promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #dec operands: { aRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'stack management' stamp: ''! releaseTemps: count ^ self addInstruction: (AJReleaseTemps new count: count).! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmove: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmove operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmpxchg16b: aMemoryOperand "... " ^ self addInstruction: #cmpxchg16b operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fbld: aMemoryOperand "Load Binary Coded Decimal Pseudo Code ----------- TOP = TOP - 1; ST(0) = ConvertToDoubleExtendedPrecisionFP(SRC); Description ----------- Converts the BCD source operand into double extended-precision floating-point format and pushes the value onto the FPU stack. The source operand is loaded without rounding errors. The sign of the source operand is preserved, including that of -0. The packed BCD digits are assumed to be in the range 0 through 9; the instruction does not check for invalid digits (AH through FH). Attempting to load an invalid encoding produces an undefined result. This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #fbld operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fldcw: aMemoryOperand "Load x87 FPU Control Word " ^ self addInstruction: #fldcw operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! and: aRegisterOrMemoryOperand with: aSource "Logical AND " ^ self addInstruction: #and operands: { aRegisterOrMemoryOperand . aSource }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movsxd: aDestinationRegister with: aSourceRegisterOrMemory "Move with Sign-Extension " ^ self addInstruction: #movsxd operands: { aDestinationRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovna: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovna operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovo: aRegister with: aSourceRegisterOrMemory "Conditional Move - overflow (OF=1) " ^ self addInstruction: #cmovo operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcomip: aX87Register "Compare Floating Point Values and Set EFLAGS and Pop " ^ self addInstruction: #fcomip operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! AH "A 8bit general purpose register This register overlaps with AH, AX, EAX, RAX" ^ AH! ! !AJx86Assembler methodsFor: 'instruction list' stamp: 'CamilloBruni 4/25/2012 14:23'! addInstruction: sel operands: operands ^ self addInstruction: sel description: (self instructionDesciptions at: sel) operands: operands ! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovne: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovne operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fild: aMemoryOperand "Load Integer Pseudo Code ----------- TOP = TOP - 1; ST(0) = ConvertToDoubleExtendedPrecisionFP(SRC); Description ----------- Converts the signed-integer source operand into double extended-precision floating-point format and pushes the value onto the FPU register stack. The source operand can be a word, doubleword, or quadword integer. It is loaded without rounding errors. The sign of the source operand is preserved. This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #fild operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! bts: aDestinationRegisterOrMemory with: aSourceRegisterOrImmediate "Bit Test and Set Pseudo Code ----------- CF = Bit(BitBase, BitOffset); Bit(BitBase, BitOffset) = 1; Description ----------- Selects the bit in a bit string (specified with the first operand, called the bit base) at the bit-position designated by the bit offset operand (second operand), stores the value of the bit in the CF flag, and sets the selected bit in the bit string to 1. The bit base operand can be a register or a memory location; the bit offset operand can be a register or an immediate value: - If the bit base operand specifies a register, the instruction takes the modulo 16, 32, or 64 of the bit offset operand (modulo size depends on the mode and register size; 64-bit operands are available only in 64-bit mode). This allows any bit position to be selected. - If the bit base operand specifies a memory location, the operand represents the address of the byte in memory that contains the bit base (bit 0 of the specified byte) of the bit string. The range of the bit position that can be referenced by the offset operand depends on the operand size. See also: Bit(BitBase, BitOffset) on page 3-11. Some assemblers support immediate bit offsets larger than 31 by using the immediate bit offset field in combination with the displacement field of the memory operand. See 'BT—Bit Test' in this chapter for more information on this addressingmechanism. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #bts operands: { aDestinationRegisterOrMemory . aSourceRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovb: aRegister with: aSourceRegisterOrMemory "Conditional Move - below/not above or equal/carry (CF=1) " ^ self addInstruction: #cmovb operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'testing' stamp: ''! isLabelUsed: aLabel | used | used := false. instructions do: [:instr | used := used or: [instr isLabelUsed: aLabel ] ]. ^ used! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM3 "An SSE register" ^ XMM3! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! pop: aRegisterOrMemoryDestination "Pop a Value from the Stack Description ----------- Loads the value from the top of the stack to the location specified with the destination operand (or explicit opcode) and then increments the stack pointer. The destination operand can be a general-purpose register, memory location, or segment register. The address-size attribute of the stack segment determines the stack pointer size (16, 32, 64 bits) and the operand-size attribute of the current code segment determines the amount the stack pointer is incremented (2, 4, 8 bytes). For example, if the address- and operand-size attributes are 32, the 32-bit ESP register (stack pointer) is incremented by 4; if they are 16, the 16-bit SP register is incremented by 2. (The B flag in the stack segment's segment descriptor determines the stack's address-size attribute, and the D flag in the current code segment's segment descriptor, along with prefixes, determines the operand-size attribute and also the address-size attribute of the destination operand.) If the destination operand is one of the segment registers DS, ES, FS, GS, or SS, the value loaded into the register must be a valid segment selector. In protected mode, popping a segment selector into a segment register automatically causes the descriptor information associated with that segment selector to be loaded into the hidden (shadow) part of the segment register and causes the selector and the descriptor information to be validated (see the 'Operation' section below). A NULL value (0000-0003) may be popped into the DS, ES, FS, or GS register without causing a general protection fault. However, any subsequent attempt to reference a segment whose corresponding segment register is loaded with a NULL value causes a general protection exception (\#GP). In this situation, no memory reference occurs and the saved value of the segment register is NULL. The POP instruction cannot pop a value into the CS register. To load the CS register from the stack, use the RET instruction. If the ESP register is used as a base register for addressing a destination operand in memory, the POP instruction computes the effective address of the operand after it increments the ESP register. For the case of a 16-bit stack where ESP wraps to 0H as a result of the POP instruction, the resulting location of the memory write is processor-family-specific. The POP ESP instruction increments the stack pointer (ESP) before data at the old top of stack is written into the destination. A POP SS instruction inhibits all interrupts, including the NMI interrupt, until after execution of the next instruction. This action allows sequential execution of POP SS and MOV ESP, EBP instructions without the danger of having an invalid stack during an interrupt1. However, use of the LSS instruction is the preferred method of loading the SS and ESP registers. In 64-bit mode, using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). When in 64-bit mode, POPs using 32-bit operands are not encodable and POPs to DS, ES, SS are not valid. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #pop operands: { aRegisterOrMemoryDestination }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! rcl: aDestinationRegisterOrMemory with: aRegisterOrImmediate "Rotate " ^ self addInstruction: #rcl operands: { aDestinationRegisterOrMemory . aRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovnc: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovnc operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! shld: aDestinationRegisterOrMemory with: aSourceRegister with: aSourceRegisterOrImmediate "Double Precision Shift Left Description ----------- The SHLD instruction is used for multi-precision shifts of 64 bits or more. The instruction shifts the first operand (destination operand) to the left the number of bits specified by the third operand (count operand). The second operand (source operand) provides bits to shift in from the right (starting with bit 0 of the destination operand). The destination operand can be a register or a memory location; the source operand is a register. The count operand is an unsigned integer that can be stored in an immediate byte or in the CL register. If the count operand is CL, the shift count is the logical AND of CL and a count mask. In non-64-bit modes and default 64-bit mode; only bits 0 through 4 of the count are used. This masks the count to a value between 0 and 31. If a count is greater than the operand size, the result is undefined. If the count is 1 or greater, the CF flag is filled with the last bit shifted out of the destination operand. For a 1-bit shift, the OF flag is set if a sign change occurred; otherwise, it is cleared. If the count operand is 0, flags are not affected. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits (upgrading the count mask to 6 bits). See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #shld operands: { aDestinationRegisterOrMemory . aSourceRegister . aSourceRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'accessing' stamp: 'CamilloBruni 3/28/2012 14:43'! reg8: index "answer one of 8bit general-purpose registers, based on index" index < 0 ifTrue: [ self invalidRegisterIndex ]. (index >= self numGPRegisters) ifTrue: [ self invalidRegisterIndex ]. ^ AJx86Registers code: index! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jle: targetLabel "Jump short if less or equal/not greater ((ZF=1) OR (SF!!=OF)) " ^ self addInstruction: #jle operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'accessing' stamp: ''! reg: index size: nBytes nBytes = 1 ifTrue: [ ^ self reg8: index ]. nBytes = 2 ifTrue: [ ^ self reg16: index ]. nBytes = 4 ifTrue: [ ^ self reg32: index ]. nBytes = 8 ifTrue: [ ^ self reg64: index ]. self error: 'invalid register size'.! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movntpd: aRegisterOrMemory1 with: aRegisterOrMemory2 "Store Packed Double-FP Values Using Non-Temporal Hint Pseudo Code ----------- DEST = SRC; Description ----------- Moves the double quadword in the source operand (second operand) to the destination operand (first operand) using a non-temporal hint to minimize cache pollution during the write to memory. The source operand is an XMM register, which is assumed to contain two packed double-precision floating-point values. The destination operand is a 128-bit memory location. The non-temporal hint is implemented by using a write combining (WC) memory type protocol when writing the data to memory. Using this protocol, the processor does not write the data into the cache hierarchy, nor does it fetch the corresponding cache line from memory into the cache hierarchy. The memory type of the region being written to can override the non-temporal hint, if the memory address specified for the non-temporal store is in an uncacheable (UC) or write protected (WP) memory region. For more information on non-temporal stores, see 'Caching of Temporal vs. Non-Temporal Data' in Chapter 10 in theIntel®64 and IA-32 Architectures Software Developer's Manual, Volume 1. Because the WC protocol uses a weakly-ordered memory consistency model, a fencing operation implemented with the SFENCE or MFENCE instruction should be used in conjunction with MOVNTPD instructions if multiple processors might use different memory types to read/write the destination memory locations. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movntpd operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! SP "A 16bit general purpose register This register overlaps with AH, AX, EAX, RAX" ^ SP! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! btr: aDestinationRegisterOrMemory with: aSourceRegisterOrImmediate "Bit Test and Reset Pseudo Code ----------- CF = Bit(BitBase, BitOffset); Bit(BitBase, BitOffset) = 0; Description ----------- Selects the bit in a bit string (specified with the first operand, called the bit base) at the bit-position designated by the bit offset operand (second operand), stores the value of the bit in the CF flag, and clears the selected bit in the bit string to 0. The bit base operand can be a register or a memory location; the bit offset operand can be a register or an immediate value: - If the bit base operand specifies a register, the instruction takes the modulo 16, 32, or 64 of the bit offset operand (modulo size depends on the mode and register size; 64-bit operands are available only in 64-bit mode). This allows any bit position to be selected. - If the bit base operand specifies a memory location, the operand represents the address of the byte in memory that contains the bit base (bit 0 of the specified byte) of the bit string. The range of the bit position that can be referenced by the offset operand depends on the operand size. See also: Bit(BitBase, BitOffset) on page 3-11. Some assemblers support immediate bit offsets larger than 31 by using the immediate bit offset field in combination with the displacement field of the memory operand. See 'BT—Bit Test' in this chapter for more information on this addressingmechanism. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #btr operands: { aDestinationRegisterOrMemory . aSourceRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcom: aX87Register1 with: aX87Register2 " see #fcom" ^ self addInstruction: #fcom operands: { aX87Register1 . aX87Register2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fucomi: aX87Register "Unordered Compare Floating Point Values and Set EFLAGS " ^ self addInstruction: #fucomi operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movdq2q: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Quadword from XMM to MMX Technology Register Pseudo Code ----------- DEST = SRC[63:0]; Description ----------- Moves the low quadword from the source operand (second operand) to the destination operand (first operand). The source operand is an XMM register and the destination operand is an MMX technology register. This instruction causes a transition from x87 FPU to MMX technology operation (that is, the x87 FPU top-of-stack pointer is set to 0 and the x87 FPU tag word is set to all 0s [valid]). If this instruction is executed while an x87 FPU floating-point exception is pending, the exception is handled before the MOVDQ2Q instruction is executed. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movdq2q operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovs: aRegister with: aSourceRegisterOrMemory "Conditional Move - sign (SF=1) " ^ self addInstruction: #cmovs operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'function calls' stamp: ''! performingCall: ci in: aBlock ci asm: self; alignmentInsertionPoint: last. aBlock value: ci. self callCleanup: ci.! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movlhps: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Packed Single-FP Values Low to High Pseudo Code ----------- DEST[127:64] = SRC[63:0]; (* DEST[63:0] unchanged *) Description ----------- Moves two packed single-precision floating-point values from the low quadword of the source operand (second operand) to the high quadword of the destination operand (first operand). The low quadword of the destination operand is left unchanged. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movlhps operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ST5 "A floating point register" ^ ST5! ! !AJx86Assembler methodsFor: 'instruction list' stamp: ''! insert: newInstruction before: anInstruction "insert one or more instructions before an instruction" ^ instructions := instructions insert: newInstruction before: anInstruction! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movPtr: aRegisterOrImmedate1 with: aRegisterOrImmedate2 " " ^ self addInstruction: #movPtr operands: { aRegisterOrImmedate1 . aRegisterOrImmedate2 }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! ST3 "A floating point register" ^ ST3! ! !AJx86Assembler methodsFor: 'alignment' stamp: ''! alignQuad self addInstruction: AJAlignmentInstruction alignQuad! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcomp: aX87Register1 with: aX87Register2 " see #fcomp" ^ self addInstruction: #fcomp operands: { aX87Register1 . aX87Register2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! shrd: aDestinationRegisterOrMemory with: aSourceRegister with: aSourceRegisterOrImmediate "Double Precision Shift Right Description ----------- The SHRD instruction is useful for multi-precision shifts of 64 bits or more. The instruction shifts the first operand (destination operand) to the right the number of bits specified by the third operand (count operand). The second operand (source operand) provides bits to shift in from the left (starting with the most significant bit of the destination operand). The destination operand can be a register or a memory location; the source operand is a register. The count operand is an unsigned integer that can be stored in an immediate byte or the CL register. If the count operand is CL, the shift count is the logical AND of CL and a count mask. In non-64-bit modes and default 64-bit mode, the width of the count mask is 5 bits. Only bits 0 through 4 of the count register are used (masking the count to a value between 0 and 31). If the count is greater than the operand size, the result is undefined. If the count is 1 or greater, the CF flag is filled with the last bit shifted out of the destination operand. For a 1-bit shift, the OF flag is set if a sign change occurred; otherwise, it is cleared. If the count operand is 0, flags are not affected. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits (upgrading the count mask to 6 bits). See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #shrd operands: { aDestinationRegisterOrMemory . aSourceRegister . aSourceRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fist: aMemoryOperand "Store Integer " ^ self addInstruction: #fist operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! CX "A 16bit general purpose register This register overlaps with CL, CX, ECX, RCX" ^ CX! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! ret: anImmediate " " ^ self addInstruction: #ret operands: { anImmediate }! ! !AJx86Assembler methodsFor: 'stack management' stamp: 'MartinMcClure 2/9/2013 14:25'! stackFrameValueAtOffset: offset ^ EBP ptr32 - offset! ! !AJx86Assembler methodsFor: 'function calls' stamp: ''! callCleanup: anAJCdeclCallInfo ^ self addInstruction: (AJCallCleanup new callInfo: anAJCdeclCallInfo )! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jl: targetLabel "Jump short if less/not greater (SF!!=OF) " ^ self addInstruction: #jl operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! ficomp: aMemoryOperand "Compare Integer and Pop " ^ self addInstruction: #ficomp operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fld: aMemoryOrX87Register "Load Floating Point Value Description ----------- Pushes the source operand onto the FPU register stack. The source operand can be in single-precision, double-precision, or double extended-precision floating-point format. If the source operand is in single-precision or double-precision floating-point format, it is automatically converted to the double extended-precision floating-point format before being pushed on the stack. The FLD instruction can also push the value in a selected FPU register [ST(i)] onto the stack. Here, pushing register ST(0) duplicates the stack top. This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #fld operands: { aMemoryOrX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fbstp: aMemoryOperand "Store BCD Integer and Pop Pseudo Code ----------- DEST = BCD(ST(0)); PopRegisterStack; Description ----------- Converts the value in the ST(0) register to an 18-digit packed BCD integer, stores the result in the destination operand, and pops the register stack. If the source value is a non-integral value, it is rounded to an integer value, according to rounding mode specified by the RC field of the FPU control word. To pop the register stack, the processor marks the ST(0) register as empty and increments the stack pointer (TOP) by 1. The destination operand specifies the address where the first byte destination value is to be stored. The BCD value (including its sign bit) requires 10 bytes of space in memory. The following table shows the results obtained when storing various classes of numbers in packed BCD format. ST(0) DEST ---------------------------------------- ------ - = or Value Too Large for DEST Format \* F \<= - 1 - D -1 \< F \< -0 \*\* - 0 - 0 + 0 + 0 + 0 \< F \< +1 \*\* F \>= +1 + D + = or Value Too Large for DEST Format \* NaN \* : FBSTP Results - Notes: - F refers to a finite floating-point value. - D refers to packed-BCD number. - \* Indicates floating-point invalid-operation (\#IA) exception. - \*\* ±0 or ±1, depending on the rounding mode. If the converted value is too large for the destination format, or if the source operand is an ∞, SNaN, QNAN, or is in an unsupported format, an invalid-arithmetic-operand condition is signaled. If the invalid-operation exception is not masked, an invalidarithmetic-operand exception (\#IA) is generated and no value is stored in the desti-nation operand. If the invalid-operation exception is masked, the packed BCD indefinite value is stored in memory. This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #fbstp operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jpe: targetLabel " " ^ self addInstruction: #jpe operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ECX "A 32bit general purpose register This register overlaps with CL, CX, ECX, RCX" ^ ECX! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movnti: aRegisterOrMemory1 with: aRegisterOrMemory2 "Store Doubleword Using Non-Temporal Hint Pseudo Code ----------- DEST = SRC; Description ----------- Moves the doubleword integer in the source operand (second operand) to the destination operand (first operand) using a non-temporal hint to minimize cache pollution during the write to memory. The source operand is a general-purpose register. The destination operand is a 32-bit memory location. The non-temporal hint is implemented by using a write combining (WC) memory type protocol when writing the data to memory. Using this protocol, the processor does not write the data into the cache hierarchy, nor does it fetch the corresponding cache line from memory into the cache hierarchy. The memory type of the region being written to can override the non-temporal hint, if the memory address specified for the non-temporal store is in an uncacheable (UC) or write protected (WP) memory region. For more information on non-temporal stores, see 'Caching of Temporal vs. Non-Temporal Data' in Chapter 10 in theIntel®64 and IA-32 Architectures Software Developer's Manual, Volume 1. Because the WC protocol uses a weakly-ordered memory consistency model, a fencing operation implemented with the SFENCE or MFENCE instruction should be used in conjunction with MOVNTI instructions if multiple processors might use different memory types to read/write the destination memory locations. In 64-bit mode, the instruction's default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8-R15). Use of the REX.W prefix promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #movnti operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'convenience' stamp: ''! movsx: src to: dest "Ensure right src/dest order" ^ self movsx: dest with: src! ! !AJx86Assembler methodsFor: 'accessing' stamp: 'CamilloBruni 3/28/2012 14:43'! reg32: index "answer one of 32bit general-purpose registers, based on index" | code | index < 0 ifTrue: [ self invalidRegisterIndex ]. (index >= self numGPRegisters) ifTrue: [ self invalidRegisterIndex ]. code := 16r20 + index. ^ AJx86Registers code: code! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! sub: aRegisterOrMemoryOperand with: aSource "Subtract Pseudo Code ----------- DEST = (DEST - SRC); Description ----------- Subtracts the second operand (source operand) from the first operand (destination operand) and stores the result in the destination operand. The destination operand can be a register or a memory location; the source operand can be an immediate, register, or memory location. (However, two memory operands cannot be used in one instruction.) When an immediate value is used as an operand, it is sign-extended to the length of the destination operand format. The SUB instruction performs integer subtraction. It evaluates the result for both signed and unsigned integer operands and sets the OF and CF flags to indicate an overflow in the signed or unsigned result, respectively. The SF flag indicates the sign of the signed result. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. " ^ self addInstruction: #sub operands: { aRegisterOrMemoryOperand . aSource }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! div: aDestination "Unsigned Divide Description ----------- Divides unsigned the value in the AX, DX:AX, EDX:EAX, or RDX:RAX registers (dividend) by the source operand (divisor) and stores the result in the AX (AH:AL), DX:AX, EDX:EAX, or RDX:RAX registers. The source operand can be a general-purpose register or a memory location. The action of this instruction depends on the operand size (dividend/divisor). Division using 64-bit operand is available only in 64-bit mode. Non-integral results are truncated (chopped) towards 0. The remainder is always less than the divisor in magnitude. Overflow is indicated with the \#DE (divide error) exception rather than with the CF flag. In 64-bit mode, the instruction's default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8-R15). Use of the REX.W prefix promotes operation to 64 bits. In 64-bit mode when REX.W is applied, the instruction divides the unsigned value in RDX:RAX by the source operand and stores the quotient in RAX, the remainder in RDX. See the summary chart at the beginning of this section for encoding data and limits. See the following table. DIV Action Maximum Operand Size Dividend Divisor Quotient Remainder Quotient Word/byte AX r/m8 AL AH 255 Doubleword/word DX:AX r/m16 AX DX 65,535 Quadword/doubleword EDX:EAX r/m32 EAX EDX 2^32^ - 1 Doublequadword/quadword RDX:RAX r/m64 RAX RDX 2^64^ - 1 " ^ self addInstruction: #div operands: { aDestination }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! frstor: aMemoryOperand "Restore x87 FPU State Description ----------- Loads the FPU state (operating environment and register stack) from the memory area specified with the source operand. This state data is typically written to the specified memory location by a previous FSAVE/FNSAVE instruction. The FPU operating environment consists of the FPU control word, status word, tag word, instruction pointer, data pointer, and last opcode. Figures 8-9 through 8-12 in the Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1, show the layout in memory of the stored environment, depending on the operating mode of the processor (protected or real) and the current operand-size attribute (16-bit or 32-bit). In virtual-8086 mode, the real mode layouts are used. The contents of the FPU register stack are stored in the 80 bytes immediately following the operating environment image. The FRSTOR instruction should be executed in the same operating mode as the corresponding FSAVE/FNSAVE instruction. If one or more unmasked exception bits are set in the new FPU status word, a floating-point exception will be generated. To avoid raising exceptions when loading a new operating environment, clear all the exception flags in the FPU status word that is being loaded. This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #frstor operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jge: targetLabel " " ^ self addInstruction: #jge operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fdivp: aX87Register "Divide and Pop " ^ self addInstruction: #fdivp operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jng: targetLabel " " ^ self addInstruction: #jng operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fdivr: aX87Register1 with: aX87Register2 " see #fdivr" ^ self addInstruction: #fdivr operands: { aX87Register1 . aX87Register2 }! ! !AJx86Assembler methodsFor: 'debugging' stamp: 'IgorStasenko 5/28/2012 02:25'! writeCodeToFile: aFileName aFileName asReference asReference delete writeStreamDo: [:s| s nextPutAll: self bytes ] ! ! !AJx86Assembler methodsFor: 'accessing' stamp: ''! stackManager: aStackManager stackManager := aStackManager ! ! !AJx86Assembler methodsFor: 'convenience' stamp: ''! db: aByteValue ^ self addInstruction: (AJData byte: aByteValue)! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! imul: aRegister with: aRegisterOrMemoryOrImmediate " see #imul" ^ self addInstruction: #imul operands: { aRegister . aRegisterOrMemoryOrImmediate }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! EDI "A 32bit general purpose register This register overlaps with BH, BX, EBX, RBX" ^ EDI! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jns: targetLabel "Jump short if not sign (SF=0) " ^ self addInstruction: #jns operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'register' stamp: ''! instructionPointer "not available on 32bit x86 CPUs" self notYetImplemented ! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcmovb: aX87Register "FP Conditional Move - below (CF=1) " ^ self addInstruction: #fcmovb operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'labels' stamp: 'CamilloBruni 5/29/2012 13:15'! label: aNameOrLabel ^ self label: aNameOrLabel ifPresent: [ self error: 'label ', aNameOrLabel asString, ' already set' ].! ! !AJx86Assembler methodsFor: 'instruction list' stamp: ''! insert: i after: instruction | next | i ifNil: [ "nothing to insert" ^ self ]. i do: [:each | each increaseLevel: instruction level ]. next := instruction next. instruction next: i. i last next: next! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movdqa: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Aligned Double Quadword Pseudo Code ----------- DEST = SRC; (* #GP if SRC or DEST unaligned memory operand *) Description ----------- Moves a double quadword from the source operand (second operand) to the destination operand (first operand). This instruction can be used to load an XMM register from a 128-bit memory location, to store the contents of an XMM register into a 128-bit memory location, or to move data between two XMM registers. When the source or destination operand is a memory operand, the operand must be aligned on a 16-byte boundary or a general-protection exception (\#GP) will be generated. To move a double quadword to or from unaligned memory locations, use the MOVDQU instruction. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movdqa operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'code generation' stamp: ''! prepareInstructions "A final step before generating machine code: prepare instructions by injecting a stack alignment and reifying jump labels. Prepared instructions will contain machine code, ready for use " instructions := stackManager analyzeInstructions: instructions assembler: self. instructions emitCodeAtOffset: 0 assembler: self. ^ instructions! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movlps: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Low Packed Single-FP Values Pseudo Code ----------- (* MOVLPD instruction for memory to XMM move *) DEST[63:0] = SRC; (* DEST[127:64] unchanged *) (* MOVLPD instruction for XMM to memory move *) DEST = SRC[63:0]; Description ----------- Moves two packed single-precision floating-point values from the source operand (second operand) and the destination operand (first operand). The source and destination operands can be an XMM register or a 64-bit memory location. This instruction allows two single-precision floating-point values to be moved to and from the low quadword of an XMM register and memory. It cannot be used for register to register or memory to memory moves. When the destination operand is an XMM register, the high quadword of the register remains unchanged. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movlps operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jp: targetLabel "Jump short if parity/parity even (PF=1) " ^ self addInstruction: #jp operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instruction list' stamp: 'IgorStasenko 8/13/2013 13:39'! newInstruction: name description: description operands: operands "check if name is jump " description isJump ifTrue: [ ^ self newJumpInstruction: name description: description operands: operands ]. ^ self newInstruction name: name; description: description; operands: operands; checkOperandsForConflict "Cannot check that at construction stage. Some operands may not be resolved yet (as AJReserveTemp) checkOperandsForConflict "! ! !AJx86Assembler methodsFor: 'register' stamp: ''! destinationIndex ^ self is32BitMode ifTrue: [ EDI ] ifFalse: [ DI ]! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movntq: aRegisterOrMemory1 with: aRegisterOrMemory2 "Store of Quadword Using Non-Temporal Hint Pseudo Code ----------- DEST = SRC; Description ----------- Moves the quadword in the source operand (second operand) to the destination operand (first operand) using a non-temporal hint to minimize cache pollution during the write to memory. The source operand is an MMX technology register, which is assumed to contain packed integer data (packed bytes, words, or doublewords). The destination operand is a 64-bit memory location. The non-temporal hint is implemented by using a write combining (WC) memory type protocol when writing the data to memory. Using this protocol, the processor does not write the data into the cache hierarchy, nor does it fetch the corresponding cache line from memory into the cache hierarchy. The memory type of the region being written to can override the non-temporal hint, if the memory address specified for the non-temporal store is in an uncacheable (UC) or write protected (WP) memory region. For more information on non-temporal stores, see 'Caching of Temporal vs. Non-Temporal Data' in Chapter 10 in theIntel®64 and IA-32 Architectures Software Developer's Manual, Volume 1. Because the WC protocol uses a weakly-ordered memory consistency model, a fencing operation implemented with the SFENCE or MFENCE instruction should be used in conjunction with MOVNTQ instructions if multiple processors might use different memory types to read/write the destination memory locations. This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #movntq operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmp: aRegisterOrMemoryOperand with: aSource "Compare Two Operands Pseudo Code ----------- temp = SRC1 - SignExtend(SRC2); ModifyStatusFlags; (* Modify status flags in the same manner as the SUB instruction *) Description ----------- Compares the first source operand with the second source operand and sets the status flags in the EFLAGS register according to the results. The comparison is performed by subtracting the second operand from the first operand and then setting the status flags in the same manner as the SUB instruction. When an immediate value is used as an operand, it is sign-extended to the length of the first operand. The condition codes used by the Jcc, CMOVcc, and SETcc instructions are based on the results of a CMP instruction. Appendix B, 'EFLAGS Condition Codes,' in theIntel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1, shows the relationship of the status flags and the condition codes. In 64-bit mode, the instruction's default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8-R15). Use of the REX.W prefix promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #cmp operands: { aRegisterOrMemoryOperand . aSource }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! or: aRegisterOrMemoryOperand with: aSource "Logical Inclusive OR Pseudo Code ----------- DEST = DEST OR SRC; Description ----------- Performs a bitwise inclusive OR operation between the destination (first) and source (second) operands and stores the result in the destination operand location. The source operand can be an immediate, a register, or a memory location; the destination operand can be a register or a memory location. (However, two memory operands cannot be used in one instruction.) Each bit of the result of the OR instruction is set to 0 if both corresponding bits of the first and second operands are 0; otherwise, each bit is set to 1. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #or operands: { aRegisterOrMemoryOperand . aSource }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movsx: aDestinationRegister with: aSourceRegisterOrMemory "Move with Sign-Extension " ^ self addInstruction: #movsx operands: { aDestinationRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fiadd: aMemoryOperand "Add " ^ self addInstruction: #fiadd operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! BP "A 16bit general purpose register This register overlaps with CH, CX, ECX, RCX" ^ BP! ! !AJx86Assembler methodsFor: 'function calls' stamp: ''! pushArgument: anArgument forCall: call | arg argSize | arg := anArgument. anArgument isInteger ifTrue: [ arg := anArgument asImm size: call defaultArgumentSize. ]. self addInstruction: (AJCallArgument new size: arg stackSize; callInfo: call ). arg emitPushOnStack: self! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM5 "An SSE register" ^ XMM5! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! ja: targetLabel " " ^ self addInstruction: #ja operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! MM0 "An MMX register" ^ MM0! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! XMM6 "An SSE register" ^ XMM6! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fadd: aX87Register1 with: aX87Register2 " see #fadd" ^ self addInstruction: #fadd operands: { aX87Register1 . aX87Register2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fnstcw: aMemoryOperand "Store x87 FPU Control Word " ^ self addInstruction: #fnstcw operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovno: aRegister with: aSourceRegisterOrMemory "Conditional Move - not overflow (OF=0) " ^ self addInstruction: #cmovno operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fxch: aX87Register "Exchange Register Contents Description ----------- Exchanges the contents of registers ST(0) and ST(i). If no source operand is specified, the contents of ST(0) and ST(1) are exchanged. This instruction provides a simple means of moving values in the FPU register stack to the top of the stack [ST(0)], so that they can be operated on by those floating-point instructions that can only operate on values in ST(0). For example, the following instruction sequence takes the square root of the third register from the top of the register stack: FXCH ST(3); FSQRT; FXCH ST(3); This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #fxch operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! bsr: aRegister with: aSourceRegisterOrMemory "Bit Scan Reverse Description ----------- Searches the source operand (second operand) for the most significant set bit (1 bit). If a most significant 1 bit is found, its bit index is stored in the destination operand (first operand). The source operand can be a register or a memory location; the destination operand is a register. The bit index is an unsigned offset from bit 0 of the source operand. If the content source operand is 0, the content of the destination operand is undefined. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #bsr operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! inc: aRegisterOrMemory "Increment by 1 Pseudo Code ----------- DEST = DEST + 1; AFlags Affected The CF flag is not affected. The OF, SF, ZF, AF, and PF flags are set according to the result. Description ----------- Adds 1 to the destination operand, while preserving the state of the CF flag. The destination operand can be a register or a memory location. This instruction allows a loop counter to be updated without disturbing the CF flag. (Use a ADD instruction with an immediate operand of 1 to perform an increment operation that does updates the CF flag.) This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. In 64-bit mode, INC r16 and INC r32 are not encodable (because opcodes 40H through 47H are REX prefixes). Otherwise, the instruction's 64-bit mode default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8-R15). Use of the REX.W prefix promotes operation to 64 bits. " ^ self addInstruction: #inc operands: { aRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'accessing' stamp: 'CamilloBruni 3/28/2012 14:43'! reg16: index "answer one of 16bit general-purpose registers, based on index" | code | index < 0 ifTrue: [ self invalidRegisterIndex ]. (index >= self numGPRegisters) ifTrue: [ self invalidRegisterIndex ]. code := 16r10 + index. ^ AJx86Registers code: code! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovnl: aRegister with: aSourceRegisterOrMemory "Conditional Move - not less/greater or equal (SF=OF) " ^ self addInstruction: #cmovnl operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! enter: stackFrameSize with: lexicalNesting "Make Stack Frame for Procedure Parameters Description ----------- Creates a stack frame for a procedure. The first operand (size operand) specifies the size of the stack frame (that is, the number of bytes of dynamic storage allocated on the stack for the procedure). The second operand (nesting level operand) gives the lexical nesting level (0 to 31) of the procedure. The nesting level determines the number of stack frame pointers that are copied into the 'display area' of the new stack frame from the preceding frame. Both of these operands are immediate values. The stack-size attribute determines whether the BP (16 bits), EBP (32 bits), or RBP (64 bits) register specifies the current frame pointer and whether SP (16 bits), ESP (32 bits), or RSP (64 bits) specifies the stack pointer. In 64-bit mode, stack-size attribute is always 64-bits. The ENTER and companion LEAVE instructions are provided to support block structured languages. The ENTER instruction (when used) is typically the first instruction in a procedure and is used to set up a new stack frame for a procedure. The LEAVE instruction is then used at the end of the procedure (just before the RET instruction) to release the stack frame. If the nesting level is 0, the processor pushes the frame pointer from the BP/EBP/RBP register onto the stack, copies the current stack pointer from the SP/ESP/RSP register into the BP/EBP/RBP register, and loads the SP/ESP/RSP register with the current stack-pointer value minus the value in the size operand. For nesting levels of 1 or greater, the processor pushes additional frame pointers on the stack before adjusting the stack pointer. These additional frame pointers provide the called procedure with access points to other nested frames on the stack. See 'Procedure Calls for Block-Structured Languages' in Chapter 6 of theIntel®64 and IA-32 ArchitecturesSoftware Developer's Manual, Volume 1, for more information about the actions of the ENTER instruction. The ENTER instruction causes a page fault whenever a write using the final value of the stack pointer (within the current stack segment) would do so. In 64-bit mode, default operation size is 64 bits; 32-bit operation size cannot be encoded. " ^ self addInstruction: #enter operands: { stackFrameSize . lexicalNesting }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! EDX "A 32bit general purpose register This register overlaps with DL, DX, EDX, RDX" ^ EDX! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! CH "A 8bit general purpose register This register overlaps with CH, CX, ECX, RCX" ^ CH! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movlpd: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Low Packed Double-FP Value Pseudo Code ----------- (* MOVLPD instruction for memory to XMM move *) DEST[63:0] = SRC; (* DEST[127:64] unchanged *) (* MOVLPD instruction for XMM to memory move *) DEST = SRC[63:0]; Description ----------- Moves a double-precision floating-point value from the source operand (second operand) to the destination operand (first operand). The source and destination operands can be an XMM register or a 64-bit memory location. This instruction allows a double-precision floating-point value to be moved to and from the low quadword of an XMM register and memory. It cannot be used for register to register or memory to memory moves. When the destination operand is an XMM register, the high quad-word of the register remains unchanged. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movlpd operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'accessing' stamp: 'CamilloBruni 8/22/2012 14:26'! newJumpInstruction ^ AJx86JumpInstruction new! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movss: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Scalar Single-FP Values Description ----------- Moves a scalar single-precision floating-point value from the source operand (second operand) to the destination operand (first operand). The source and destination operands can be XMM registers or 32-bit memory locations. This instruction can be used to move a single-precision floating-point value to and from the low doubleword of an XMM register and a 32-bit memory location, or to move a single-precision floating-point value between the low doublewords of two XMM registers. The instruction cannot be used to transfer data between memory locations. When the source and destination operands are XMM registers, the three high-order doublewords of the destination operand remain unchanged. When the source operand is a memory location and destination operand is an XMM registers, the three high-order doublewords of the destination operand are cleared to all 0s. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movss operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! EBP "A 32bit general purpose register This register overlaps with CH, CX, ECX, RCX" ^ EBP! ! !AJx86Assembler methodsFor: 'register' stamp: ''! sourceIndex ^ self is32BitMode ifTrue: [ RSI ] ifFalse: [ SI ]! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! xor: aRegisterOrMemoryOperand with: aSource "Logical Exclusive OR Pseudo Code ----------- DEST = DEST XOR SRC; Description ----------- Performs a bitwise exclusive OR (XOR) operation on the destination (first) and source (second) operands and stores the result in the destination operand location. The source operand can be an immediate, a register, or a memory location; the destination operand can be a register or a memory location. (However, two memory operands cannot be used in one instruction.) Each bit of the result is 1 if the corresponding bits of the operands are different; each bit is 0 if the corresponding bits are the same. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. In 64-bit mode, using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #xor operands: { aRegisterOrMemoryOperand . aSource }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fstenv: aMemoryOperand "Store x87 FPU Environment " ^ self addInstruction: #fstenv operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! MM1 "An MMX register" ^ MM1! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jb: targetLabel "Jump short if below/not above or equal/carry (CF=1) " ^ self addInstruction: #jb operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! MM2 "An MMX register" ^ MM2! ! !AJx86Assembler methodsFor: 'convenience' stamp: 'IgorStasenko 5/26/2012 15:14'! mov: src to: dest "Ensure right src/dest order" src = dest ifTrue: [ ^ self ]. "do not if source and dest are same " ^ self mov: dest with: src! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jna: targetLabel " " ^ self addInstruction: #jna operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! mul: aDestination "Unsigned Multiply Description ----------- Performs an unsigned multiplication of the first operand (destination operand) and the second operand (source operand) and stores the result in the destination operand. The destination operand is an implied operand located in register AL, AX or EAX (depending on the size of the operand); the source operand is located in a general-purpose register or a memory location. The action of this instruction and the location of the result depends on the opcode and the operand size as shown in the following table. The result is stored in register AX, register pair DX:AX, or register pair EDX:EAX (depending on the operand size), with the high-order bits of the product contained in register AH, DX, or EDX, respectively. If the high-order bits of the product are 0, the CF and OF flags are cleared; otherwise, the flags are set. In 64-bit mode, the instruction's default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8 - R15). Use of the REX.W prefix promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. Operand Size Source 1 Source 2 Destination -------------- ---------- ---------- ------------- Byte AL r/m8 AX Word AX r/m16 DX:AX Doubleword EAX r/m32 EDX:EAX Quadword RAX r/m64 RDX:RAX : MUL Results " ^ self addInstruction: #mul operands: { aDestination }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fsub: aX87Register1 with: aX87Register2 " see #fsub" ^ self addInstruction: #fsub operands: { aX87Register1 . aX87Register2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! push: aSource "Push Word, Doubleword or Quadword Onto the Stack " ^ self addInstruction: #push operands: { aSource }! ! !AJx86Assembler methodsFor: 'stack management' stamp: ''! reserveExtraBytesOnStack: numBytes ^ stackManager reserveExtraBytesOnStack: numBytes ! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fstp: aMemoryOrX87Register "Store Floating Point Value and Pop " ^ self addInstruction: #fstp operands: { aMemoryOrX87Register }! ! !AJx86Assembler methodsFor: 'stack management' stamp: ''! reserveTemp ^ self addInstruction: (AJReserveTemp new size: self wordSize). ! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! crc32: aRegister with: aSourceRegisterOrMemory "Accumulate CRC32 Value Description ----------- Starting with an initial value in the first operand (destination operand), accumulates a CRC32 (polynomial 0x11EDC6F41) value for the second operand (source operand) and stores the result in the destination operand. The source operand can be a register or a memory location. The destination operand must be an r32 or r64 register. If the destination is an r64 register, then the 32-bit result is stored in the least significant double word and 00000000H is stored in the most significant double word of the r64 register. The initial value supplied in the destination operand is a double word integer stored in the r32 register or the least significant double word of the r64 register. To incrementally accumulate a CRC32 value, software retains the result of the previous CRC32 operation in the destination operand, then executes the CRC32 instruction again with new input data in the source operand. Data contained in the source operand is processed in reflected bit order. This means that the most significant bit of the source operand is treated as the least significant bit of the quotient, and so on, for all the bits of the source operand. Likewise, the result of the CRC operation is stored in the destination operand in reflected bit order. This means that the most significant bit of the resulting CRC (bit 31) is stored in the least significant bit of the destination operand (bit 0), and so on, for all the bits of the CRC. " ^ self addInstruction: #crc32 operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! stmxcsr: aMemoryOperand "Store MXCSR Register State Pseudo Code ----------- m32 = MXCSR; Description ----------- Stores the contents of the MXCSR control and status register to the destination operand. The destination operand is a 32-bit memory location. The reserved bits in the MXCSR register are stored as 0s. This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #stmxcsr operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! xadd: aDestinationRegisterOrMemory with: aSourceRegister "Exchange and Add Pseudo Code ----------- TEMP = SRC + DEST; SRC = DEST; DEST = TEMP; Description ----------- Exchanges the first operand (destination operand) with the second operand (source operand), then loads the sum of the two values into the destination operand. The destination operand can be a register or a memory location; the source operand is a register. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. " ^ self addInstruction: #xadd operands: { aDestinationRegisterOrMemory . aSourceRegister }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! bswap: aDestinationRegister "Byte Swap Description ----------- Reverses the byte order of a 32-bit or 64-bit (destination) register. This instruction is provided for converting little-endian values to big-endian format and vice versa. To swap bytes in a word value (16-bit register), use the XCHG instruction. When the BSWAP instruction references a 16-bit register, the result is undefined. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. IA-32 Architecture Legacy Compatibility The BSWAP instruction is not supported on IA-32 processors earlier than the Intel486™ processor family. For compatibility with this instruction, software should include functionally equivalent code for execution on Intel processors earlier than the Intel486 processor family. " ^ self addInstruction: #bswap operands: { aDestinationRegister }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovnp: aRegister with: aSourceRegisterOrMemory "Conditional Move - not parity/parity odd " ^ self addInstruction: #cmovnp operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fsave: aMemoryOperand "Store x87 FPU State " ^ self addInstruction: #fsave operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! ldmxcsr: aMemoryOperand "Load MXCSR Register Pseudo Code ----------- MXCSR = m32; C/C++ Compiler Intrinsic Equivalent _mm_setcsr(unsigned int i) Description ----------- Loads the source operand into the MXCSR control/status register. The source operand is a 32-bit memory location. See 'MXCSR Control and Status Register' in Chapter 10, of theIntel®64 and IA-32 Architectures Software Developer's Manual,Volume 1, for a description of the MXCSR register and its contents. The LDMXCSR instruction is typically used in conjunction with the STMXCSR instruction, which stores the contents of the MXCSR register in memory. The default MXCSR value at reset is 1F80H. If a LDMXCSR instruction clears a SIMD floating-point exception mask bit and sets the corresponding exception flag bit, a SIMD floating-point exception will not be immediately generated. The exception will be generated only upon the execution of the next SSE or SSE2 instruction that causes that particular SIMD floating-point exception to be reported. This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #ldmxcsr operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcom: aMemoryOperand "Compare Real " ^ self addInstruction: #fcom operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcomp: aMemoryOperand "Compare Real and Pop " ^ self addInstruction: #fcomp operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movaps: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Aligned Packed Single-FP Values Pseudo Code ----------- DEST = SRC; (* #GP if SRC or DEST unaligned memory operand *) Description ----------- Moves a double quadword containing four packed single-precision floating-point values from the source operand (second operand) to the destination operand (first operand). This instruction can be used to load an XMM register from a 128-bit memory location, to store the contents of an XMM register into a 128-bit memory location, or to move data between two XMM registers. When the source or destination operand is a memory operand, the operand must be aligned on a 16-byte boundary or a general-protection exception (\#GP) is generated. To move packed single-precision floating-point values to or from unaligned memory locations, use the MOVUPS instruction. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movaps operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'function calls' stamp: ''! noticePush: numBytes forCall: aCallInfo self addInstruction: (AJCallArgument new size: numBytes; callInfo: aCallInfo ). ! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! xchg: aDestinationRegisterOrMemory with: aSourceRegister "Exchange Register/Memory with Register Pseudo Code ----------- TEMP = DEST; DEST = SRC; SRC = TEMP; Description ----------- Exchanges the contents of the destination (first) and source (second) operands. The operands can be two general-purpose registers or a register and a memory location. If a memory operand is referenced, the processor's locking protocol is automatically implemented for the duration of the exchange operation, regardless of the presence or absence of the LOCK prefix or of the value of the IOPL. (See the LOCK prefix description in this chapter for more information on the locking protocol.) This instruction is useful for implementing semaphores or similar data structures for process synchronization. (See 'Bus Locking' in Chapter 8 of theIntel® 64 and IA-32Architectures Software Developer's Manual, Volume 3A, for more information on bus locking.) The XCHG instruction can also be used instead of the BSWAP instruction for 16-bit operands. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #xchg operands: { aDestinationRegisterOrMemory . aSourceRegister }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! je: targetLabel " " ^ self addInstruction: #je operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fidivr: aMemoryOperand "Reverse Divide " ^ self addInstruction: #fidivr operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movhpd: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move High Packed Double-FP Value Pseudo Code ----------- (* MOVHPD instruction for memory to XMM move *) DEST[127:64] = SRC; (* DEST[63:0] unchanged *) (* MOVHPD instruction for XMM to memory move *) DEST = SRC[127:64]; Description ----------- Moves a double-precision floating-point value from the source operand (second operand) to the destination operand (first operand). The source and destination operands can be an XMM register or a 64-bit memory location. This instruction allows a double-precision floating-point value to be moved to and from the high quadword of an XMM register and memory. It cannot be used for register to register or memory to memory moves. When the destination operand is an XMM register, the low quad-word of the register remains unchanged. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movhpd operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! SI "A 16bit general purpose register This register overlaps with DH, DX, EDX, RDX" ^ SI! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movntps: aRegisterOrMemory1 with: aRegisterOrMemory2 "Store Packed Single-FP Values Using Non-Temporal Hint Pseudo Code ----------- DEST = SRC; Description ----------- Moves the double quadword in the source operand (second operand) to the destination operand (first operand) using a non-temporal hint to minimize cache pollution during the write to memory. The source operand is an XMM register, which is assumed to contain four packed single-precision floating-point values. The destination operand is a 128-bit memory location. The non-temporal hint is implemented by using a write combining (WC) memory type protocol when writing the data to memory. Using this protocol, the processor does not write the data into the cache hierarchy, nor does it fetch the corresponding cache line from memory into the cache hierarchy. The memory type of the region being written to can override the non-temporal hint, if the memory address specified for the non-temporal store is in an uncacheable (UC) or write protected (WP) memory region. For more information on non-temporal stores, see 'Caching of Temporal vs. Non-Temporal Data' in Chapter 10 in theIntel®64 and IA-32 Architectures Software Developer's Manual, Volume 1. Because the WC protocol uses a weakly-ordered memory consistency model, a fencing operation implemented with the SFENCE or MFENCE instruction should be used in conjunction with MOVNTPS instructions if multiple processors might use different memory types to read/write the destination memory locations. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movntps operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! DX "A 16bit general purpose register This register overlaps with DL, DX, EDX, RDX" ^ DX! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovge: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovge operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fisubr: aMemoryOperand "Reverse Subtract " ^ self addInstruction: #fisubr operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instruction list' stamp: 'MartinMcClure 2/9/2013 14:29'! newJumpInstruction: name description: description operands: operands | jumpInstruction destination | jumpInstruction := self newJumpInstruction name: name; description: description. operands size ~= 1 ifTrue: [ Error signal: 'Jump instruction only takes one argument!!' ]. destination := operands first. destination isString ifTrue: [ ^ jumpInstruction label: (self labelNamed: destination) ]. destination isLabel ifTrue: [ ^ jumpInstruction label: destination ]. ^ self newInstruction name: name; description: description; operands: operands; checkOperandsForConflict! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! faddp: aX87Register "Add and Pop " ^ self addInstruction: #faddp operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovle: aRegister with: aSourceRegisterOrMemory "Conditional Move - less or equal/not greater ((ZF=1) OR (SF!!=OF)) " ^ self addInstruction: #cmovle operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'testing' stamp: ''! is32 ^ true! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jbe: targetLabel "Jump short if below or equal/not above (CF=1 AND ZF=1) " ^ self addInstruction: #jbe operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM4 "An SSE register" ^ XMM4! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! DL "A 8bit general purpose register This register overlaps with DL, DX, EDX, RDX" ^ DL! ! !AJx86Assembler methodsFor: 'code generation' stamp: ''! bytes ^ self generatedCode bytes.! ! !AJx86Assembler methodsFor: 'labels' stamp: ''! uniqueLabelName: aName ^ self labelNamed: aName, labels size asString! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movntdqa: aRegisterOrMemory1 with: aRegisterOrMemory2 "Load Double Quadword Non-Temporal Aligned Hint Pseudo Code ----------- DST = SRC; Description ----------- MOVNTDQA loads a double quadword from the source operand (second operand) to the destination operand (first operand) using a non-temporal hint. A processor implementation may make use of the non-temporal hint associated with this instruction if the memory source is WC (write combining) memory type. An implementation may also make use of the non-temporal hint associated with this instruction if the memory source is WB (write back) memory type. A processor's implementation of the non-temporal hint does not override the effective memory type semantics, but the implementation of the hint is processor dependent. For example, a processor implementation may choose to ignore the hint and process the instruction as a normal MOVDQA for any memory type. Another implementation of the hint for WC memory type may optimize data transfer throughput of WC reads. A third implementation may optimize cache reads generated by MOVNTDQA on WB memory type to reduce cache evictions. WC Streaming Load Hint For WC memory type in particular, the processor never appears to read the data into the cache hierarchy. Instead, the non-temporal hint may be implemented by loading a temporary internal buffer with the equivalent of an aligned cache line without filling this data to the cache. Any memory-type aliased lines in the cache will be snooped and flushed. Subsequent MOVNTDQA reads to unread portions of the WC cache line will receive data from the temporary internal buffer if data is available. The temporary internal buffer may be flushed by the processor at any time for any reason, for example: - A load operation other than a MOVNTDQA which references memory already resident in a temporary internal buffer. - A non-WC reference to memory already resident in a temporary internal buffer. - Interleaving of reads and writes to memory currently residing in a single temporary internal buffer. - Repeated MOVNTDQA loads of a particular 16-byte item in a streaming line. - Certain micro-architectural conditions including resource shortages, detection of a mis-speculation condition, and various fault conditions The memory type of the region being read can override the non-temporal hint, if the memory address specified for the non-temporal read is not a WC memory region. Information on non-temporal reads and writes can be found in Chapter 11, 'MemoryCache Control' ofIntel® 64 and IA-32 Architectures Software Developer's Manual,Volume 3A. Because the WC protocol uses a weakly-ordered memory consistency model, an MFENCE or locked instruction should be used in conjunction with MOVNTDQA instructions if multiple processors might reference the same WC memory locations or in order to synchronize reads of a processor with writes by other agents in the system. Because of the speculative nature of fetching due to MOVNTDQA, Streaming loads must not be used to reference memory addresses that are mapped to I/O devices having side effects or when reads to these devices are destructive. For additional information on MOVNTDQA usages, see Section 12.10.3 in Chapter 12, 'Programming with SSE3, SSSE3 and SSE4' ofIntel®64 and IA-32 Architectures SoftwareDeveloper's Manual, Volume 1. " ^ self addInstruction: #movntdqa operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! MM7 "An MMX register" ^ MM7! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jpo: targetLabel " " ^ self addInstruction: #jpo operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'convenience' stamp: ''! movzx: src to: dest "Ensure right src/dest order" ^ self movzx: dest with: src! ! !AJx86Assembler methodsFor: 'instruction list' stamp: 'CamilloBruni 7/23/2012 13:29'! decorateWith: annotation during: aBlock self addInstruction: (AJInstructionDecoration new start annotation: annotation). level := level + 1. aBlock ensure: [ level := level - 1. self addInstruction: (AJInstructionDecoration new end annotation: annotation) ] ! ! !AJx86Assembler methodsFor: 'alignment' stamp: ''! alignWord self addInstruction: AJAlignmentInstruction alignWord! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ESI "A 32bit general purpose register This register overlaps with DH, DX, EDX, RDX" ^ ESI! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! CL "A 8bit general purpose register This register overlaps with CL, CX, ECX, RCX" ^ CL! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovnbe: aRegister with: aSourceRegisterOrMemory "Conditional Move - not below or equal/above (CF=0 AND ZF=0) " ^ self addInstruction: #cmovnbe operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jnbe: targetLabel "Jump short if not below or equal/above (CF=0 AND ZF=0) " ^ self addInstruction: #jnbe operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'convenience' stamp: ''! dw: aByteArray self assert: aByteArray size == SizeWord. ^ self addInstruction: (AJData data: aByteArray)! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcmovbe: aX87Register "FP Conditional Move - below or equal (CF=1 or ZF=1) " ^ self addInstruction: #fcmovbe operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movapd: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Aligned Packed Double-FP Values Pseudo Code ----------- DEST = SRC; (* #GP if SRC or DEST unaligned memory operand *) Description ----------- Moves a double quadword containing two packed double-precision floating-point values from the source operand (second operand) to the destination operand (first operand). This instruction can be used to load an XMM register from a 128-bit memory location, to store the contents of an XMM register into a 128-bit memory location, or to move data between two XMM registers. When the source or destination operand is a memory operand, the operand must be aligned on a 16-byte boundary or a general-protection exception (\#GP) will be generated. To move double-precision floating-point values to and from unaligned memory locations, use the MOVUPD instruction. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movapd operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'convenience' stamp: ''! mov: assoc "convenience" ^ self mov: assoc key to: assoc value! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcmovnb: aX87Register "FP Conditional Move - not below (CF=0) " ^ self addInstruction: #fcmovnb operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovnle: aRegister with: aSourceRegisterOrMemory "Conditional Move - not less nor equal/greater ((ZF=0) AND (SF=OF)) " ^ self addInstruction: #cmovnle operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jmp: aLabelOrRegisterOrMemory "Jump Description ----------- Transfers program control to a different point in the instruction stream without recording return information. The destination (target) operand specifies the address of the instruction being jumped to. This operand can be an immediate value, a general-purpose register, or a memory location. This instruction can be used to execute four different types of jumps: - Near jump—A jump to an instruction within the current code segment (the segment currently pointed to by the CS register), sometimes referred to as an intrasegment jump. - Short jump—A near jump where the jump range is limited to -128 to +127 from the current EIP value. - Far jump—A jump to an instruction located in a different segment than the current code segment but at the same privilege level, sometimes referred to as an intersegment jump. - Task switch—A jump to an instruction located in a different task. A task switch can only be executed in protected mode (see Chapter 7, in theIntel® 64 and IA-32 Architectures Software Developer's Manual, Volume 3A, for information on performing task switches with the JMP instruction). Near and Short Jumps. When executing a near jump, the processor jumps to the address (within the current code segment) that is specified with the target operand. The target operand specifies either an absolute offset (that is an offset from the base of the code segment) or a relative offset (a signed displacement relative to the current value of the instruction pointer in the EIP register). A near jump to a relative offset of 8-bits (rel8) is referred to as a short jump. The CS register is not changed on near and short jumps. An absolute offset is specified indirectly in a general-purpose register or a memory location (r/m16 or r/m32). The operand-size attribute determines the size of the target operand (16 or 32 bits). Absolute offsets are loaded directly into the EIP register. If the operand-size attribute is 16, the upper two bytes of the EIP register are cleared, resulting in a maximum instruction pointer size of 16 bits. A relative offset (rel8, rel16, or rel32) is generally specified as a label in assembly code, but at the machine code level, it is encoded as a signed 8-, 16-, or 32-bit immediate value. This value is added to the value in the EIP register. (Here, the EIP register contains the address of the instruction following the JMP instruction). When using relative offsets, the opcode (for short vs. near jumps) and the operand-size attribute (for near relative jumps) determines the size of the target operand (8, 16, or 32 bits). Far Jumps in Real-Address or Virtual-8086 Mode. When executing a far jump in real-address or virtual-8086 mode, the processor jumps to the code segment and offset specified with the target operand. Here the target operand specifies an absolute far address either directly with a pointer (ptr16:16 or ptr16:32) or indirectly with a memory location (m16:16 or m16:32). With the pointer method, the segment and address of the called procedure is encoded in the instruction, using a 4-byte (16-bit operand size) or 6-byte (32-bit operand size) far address immediate. With the indirect method, the target operand specifies a memory location that contains a 4-byte (16-bit operand size) or 6-byte (32-bit operand size) far address. The far address is loaded directly into the CS and EIP registers. If the operand-size attribute is 16, the upper two bytes of the EIP register are cleared. Far Jumps in Protected Mode. When the processor is operating in protected mode, the JMP instruction can be used to perform the following three types of far jumps: - A far jump to a conforming or non-conforming code segment. - A far jump through a call gate. - A task switch. (The JMP instruction cannot be used to perform inter-privilege-level far jumps.) In protected mode, the processor always uses the segment selector part of the far address to access the corresponding descriptor in the GDT or LDT. The descriptor type (code segment, call gate, task gate, or TSS) and access rights determine the type of jump to be performed. If the selected descriptor is for a code segment, a far jump to a code segment at the same privilege level is performed. (If the selected code segment is at a different privilege level and the code segment is non-conforming, a general-protection exception is generated.) A far jump to the same privilege level in protected mode is very similar to one carried out in real-address or virtual-8086 mode. The target operand specifies an absolute far address either directly with a pointer (ptr16:16 or ptr16:32) or indirectly with a memory location (m16:16 or m16:32). The operand-size attribute determines the size of the offset (16 or 32 bits) in the far address. The new code segment selector and its descriptor are loaded into CS register, and the offset from the instruction is loaded into the EIP register. Note that a call gate (described in the next paragraph) can also be used to perform far call to a code segment at the same privilege level. Using this mechanism provides an extra level of indirection and is the preferred method of making jumps between 16-bit and 32-bit code segments. When executing a far jump through a call gate, the segment selector specified by the target operand identifies the call gate. (The offset part of the target operand is ignored.) The processor then jumps to the code segment specified in the call gate descriptor and begins executing the instruction at the offset specified in the call gate. No stack switch occurs. Here again, the target operand can specify the far address of the call gate either directly with a pointer (ptr16:16 or ptr16:32) or indirectly with a memory location (m16:16 or m16:32). Executing a task switch with the JMP instruction is somewhat similar to executing a jump through a call gate. Here the target operand specifies the segment selector of the task gate for the task being switched to (and the offset part of the target operand is ignored). The task gate in turn points to the TSS for the task, which contains the segment selectors for the task's code and stack segments. The TSS also contains the EIP value for the next instruction that was to be executed before the task was suspended. This instruction pointer value is loaded into the EIP register so that the task begins executing again at this next instruction. The JMP instruction can also specify the segment selector of the TSS directly, which eliminates the indirection of the task gate. See Chapter 7 inIntel® 64 and IA-32Architectures Software Developer's Manual, Volume 3A, for detailed information on the mechanics of a task switch. Note that when you execute at task switch with a JMP instruction, the nested task flag (NT) is not set in the EFLAGS register and the new TSS's previous task link field is not loaded with the old task's TSS selector. A return to the previous task can thus not be carried out by executing the IRET instruction. Switching tasks with the JMP instruction differs in this regard from the CALL instruction which does set the NT flag and save the previous task link information, allowing a return to the calling task with an IRET instruction. In 64-Bit Mode — The instruction's operation size is fixed at 64 bits. If a selector points to a gate, then RIP equals the 64-bit displacement taken from gate; else RIP equals the zero-extended offset from the far pointer referenced in the instruction. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #jmp operands: { aLabelOrRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'stack management' stamp: ''! emitEpilogue: popExtraBytes ^ stackManager emitEpilogue: popExtraBytes assembler: self! ! !AJx86Assembler methodsFor: 'code generation' stamp: ''! generatedCode ^ AJGeneratedCode new fromInstructions: self prepareInstructions. ! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fsubr: aX87Register1 with: aX87Register2 " see #fsubr" ^ self addInstruction: #fsubr operands: { aX87Register1 . aX87Register2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcmovnbe: aX87Register "FP Conditional Move - below or equal (CF=0 and ZF=0) " ^ self addInstruction: #fcmovnbe operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! imul: aRegisterOrMemory "Signed Multiply Description ----------- Performs a signed multiplication of two operands. This instruction has three forms, depending on the number of operands. - One-operand form — This form is identical to that used by the MUL instruction. Here, the source operand (in a general-purpose register or memory location) is multiplied by the value in the AL, AX, EAX, or RAX register (depending on the operand size) and the product is stored in the AX, DX:AX, EDX:EAX, or RDX:RAX registers, respectively. - Two-operand form — With this form the destination operand (the first operand) is multiplied by the source operand (second operand). The destination operand is a general-purpose register and the source operand is an immediate value, a general-purpose register, or a memory location. The product is then stored in the destination operand location. - Three-operand form — This form requires a destination operand (the first operand) and two source operands (the second and the third operands). Here, the first source operand (which can be a general-purpose register or a memory location) is multiplied by the second source operand (an immediate value). The product is then stored in the destination operand (a general-purpose register). When an immediate value is used as an operand, it is sign-extended to the length of the destination operand format. The CF and OF flags are set when significant bit (including the sign bit) are carried into the upper half of the result. The CF and OF flags are cleared when the result (including the sign bit) fits exactly in the lower half of the result. The three forms of the IMUL instruction are similar in that the length of the product is calculated to twice the length of the operands. With the one-operand form, the product is stored exactly in the destination. With the two- and three- operand forms, however, the result is truncated to the length of the destination before it is stored in the destination register. Because of this truncation, the CF or OF flag should be tested to ensure that no significant bits are lost. The two- and three-operand forms may also be used with unsigned operands because the lower half of the product is the same regardless if the operands are signed or unsigned. The CF and OF flags, however, cannot be used to determine if the upper half of the result is non-zero. In 64-bit mode, the instruction's default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8-R15). Use of the REX.W prefix promotes operation to 64 bits. Use of REX.W modifies the three forms of the instruction as follows. - One-operand form —The source operand (in a 64-bit general-purpose register or memory location) is multiplied by the value in the RAX register and the product is stored in the RDX:RAX registers. - Two-operand form — The source operand is promoted to 64 bits if it is a register or a memory location. If the source operand is an immediate, it is sign extended to 64 bits. The destination operand is promoted to 64 bits. - Three-operand form — The first source operand (either a register or a memory location) and destination operand are promoted to 64 bits. " ^ self addInstruction: #imul operands: { aRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instruction list' stamp: ''! instructionsFor: aBlockWithCode | old new | old := instructions. instructions := nil. [ aBlockWithCode value. ] ensure: [ new := instructions. instructions := old ]. ^ new! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movhlps: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Packed Single-FP Values High to Low Pseudo Code ----------- DEST[63:0] = SRC[127:64]; (* DEST[127:64] unchanged *) Description ----------- Moves two packed single-precision floating-point values from the high quadword of the source operand (second operand) to the low quadword of the destination operand (first operand). The high quadword of the destination operand is left unchanged. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movhlps operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fdivrp: aX87Register "Reverse Divide and Pop " ^ self addInstruction: #fdivrp operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! call: anAddressSource "Call Procedure Description ----------- Saves procedure linking information on the stack and branches to the called procedure specified using the target operand. The target operand specifies the address of the first instruction in the called procedure. The operand can be an immediate value, a general-purpose register, or a memory location. This instruction can be used to execute four types of calls: - Near Call — A call to a procedure in the current code segment (the segment currently pointed to by the CS register), sometimes referred to as an intrasegment call. - Far Call — A call to a procedure located in a different segment than the current code segment, sometimes referred to as an inter-segment call. - Inter-privilege-level far call — A far call to a procedure in a segment at a different privilege level than that of the currently executing program or procedure. - Task switch — A call to a procedure located in a different task. The latter two call types (inter-privilege-level call and task switch) can only be executed in protected mode. See 'Calling Procedures Using Call and RET' in Chapter6 of the Intel®64 and IA-32 Architectures Software Developer's Manual, Volume 1, for additional information on near, far, and inter-privilege-level calls. See Chapter 7,'Task Management,' in theIntel® 64 and IA-32 Architectures Software Developer'sManual, Volume 3A, for information on performing task switches with the CALL instruction. Near Call. When executing a near call, the processor pushes the value of the EIP register (which contains the offset of the instruction following the CALL instruction) on the stack (for use later as a return-instruction pointer). The processor then branches to the address in the current code segment specified by the target operand. The target operand specifies either an absolute offset in the code segment (an offset from the base of the code segment) or a relative offset (a signed displacement relative to the current value of the instruction pointer in the EIP register; this value points to the instruction following the CALL instruction). The CS register is not changed on near calls. For a near call absolute, an absolute offset is specified indirectly in a general-purpose register or a memory location (r/m16, r/m32, or r/m64). The operand-size attribute determines the size of the target operand (16, 32 or 64 bits). When in 64-bit mode, the operand size for near call (and all near branches) is forced to 64-bits. Absolute offsets are loaded directly into the EIP(RIP) register. If the operand size attribute is 16, the upper two bytes of the EIP register are cleared, resulting in a maximum instruction pointer size of 16 bits. When accessing an absolute offset indirectly using the stack pointer [ESP] as the base register, the base value used is the value of the ESP before the instruction executes. A relative offset (rel16 or rel32) is generally specified as a label in assembly code. But at the machine code level, it is encoded as a signed, 16- or 32-bit immediate value. This value is added to the value in the EIP(RIP) register. In 64-bit mode the relative offset is always a 32-bit immediate value which is sign extended to 64-bits before it is added to the value in the RIP register for the target calculation. As with absolute offsets, the operand-size attribute determines the size of the target operand (16, 32, or 64 bits). In 64-bit mode the target operand will always be 64-bits because the operand size is forced to 64-bits for near branches. Far Calls in Real-Address or Virtual-8086 Mode. When executing a far call in real- address or virtual-8086 mode, the processor pushes the current value of both the CS and EIP registers on the stack for use as a return-instruction pointer. The processor then performs a 'far branch' to the code segment and offset specified with the target operand for the called procedure. The target operand specifies an absolute far address either directly with a pointer (ptr16:16 or ptr16:32) or indirectly with a memory location (m16:16 or m16:32). With the pointer method, the segment and offset of the called procedure is encoded in the instruction using a 4-byte (16-bit operand size) or 6-byte (32-bit operand size) far address immediate. With the indirect method, the target operand specifies a memory location that contains a 4-byte (16-bit operand size) or 6-byte (32-bit operand size) far address. The operand-size attribute determines the size of the offset (16 or 32 bits) in the far address. The far address is loaded directly into the CS and EIP registers. If the operand-size attribute is 16, the upper two bytes of the EIP register are cleared. Far Calls in Protected Mode. When the processor is operating in protected mode, the CALL instruction can be used to perform the following types of far calls: - Far call to the same privilege level - Far call to a different privilege level (inter-privilege level call) - Task switch (far call to another task) In protected mode, the processor always uses the segment selector part of the far address to access the corresponding descriptor in the GDT or LDT. The descriptor type (code segment, call gate, task gate, or TSS) and access rights determine the type of call operation to be performed. If the selected descriptor is for a code segment, a far call to a code segment at the same privilege level is performed. (If the selected code segment is at a different privilege level and the code segment is non-conforming, a general-protection exception is generated.) A far call to the same privilege level in protected mode is very similar to one carried out in real-address or virtual-8086 mode. The target operand specifies an absolute far address either directly with a pointer (ptr16:16 or ptr16:32) or indirectly with a memory location (m16:16 or m16:32). The operand- size attribute determines the size of the offset (16 or 32 bits) in the far address. The new code segment selector and its descriptor are loaded into CS register; the offset from the instruction is loaded into the EIP register. A call gate (described in the next paragraph) can also be used to perform a far call to a code segment at the same privilege level. Using this mechanism provides an extra level of indirection and is the preferred method of making calls between 16-bit and 32-bit code segments. When executing an inter-privilege-level far call, the code segment for the procedure being called must be accessed through a call gate. The segment selector specified by the target operand identifies the call gate. The target operand can specify the call gate segment selector either directly with a pointer (ptr16:16 or ptr16:32) or indirectly with a memory location (m16:16 or m16:32). The processor obtains the segment selector for the new code segment and the new instruction pointer (offset) from the call gate descriptor. (The offset from the target operand is ignored when a call gate is used.) On inter-privilege-level calls, the processor switches to the stack for the privilege level of the called procedure. The segment selector for the new stack segment is specified in the TSS for the currently running task. The branch to the new code segment occurs after the stack switch. (Note that when using a call gate to perform a far call to a segment at the same privilege level, no stack switch occurs.) On the new stack, the processor pushes the segment selector and stack pointer for the calling procedure's stack, an optional set of parameters from the calling procedures stack, and the segment selector and instruction pointer for the calling procedure's code segment. (A value in the call gate descriptor determines how many parameters to copy to the new stack.) Finally, the processor branches to the address of the procedure being called within the new code segment. Executing a task switch with the CALL instruction is similar to executing a call through a call gate. The target operand specifies the segment selector of the task gate for the new task activated by the switch (the offset in the target operand is ignored). The task gate in turn points to the TSS for the new task, which contains the segment selectors for the task's code and stack segments. Note that the TSS also contains the EIP value for the next instruction that was to be executed before the calling task was suspended. This instruction pointer value is loaded into the EIP register to re-start the calling task. The CALL instruction can also specify the segment selector of the TSS directly, which eliminates the indirection of the task gate. See Chapter 7, 'Task Management,' in the Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 3A, for information on the mechanics of a task switch. When you execute at task switch with a CALL instruction, the nested task flag (NT) is set in the EFLAGS register and the new TSS's previous task link field is loaded with the old task's TSS selector. Code is expected to suspend this nested task by executing an IRET instruction which, because the NT flag is set, automatically uses the previous task link to return to the calling task. (See 'Task Linking' in Chapter 7 ofthe Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 3A, for information on nested tasks.) Switching tasks with the CALL instruction differs in this regard from JMP instruction. JMP does not set the NT flag and therefore does not expect an IRET instruction to suspend the task. Mixing 16-Bit and 32-Bit Calls. When making far calls between 16-bit and 32-bit code segments, use a call gate. If the far call is from a 32-bit code segment to a 16-bit code segment, the call should be made from the first 64 KBytes of the 32-bit code segment. This is because the operand-size attribute of the instruction is set to 16, so only a 16-bit return address offset can be saved. Also, the call should be made using a 16-bit call gate so that 16-bit values can be pushed on the stack. See Chapter 18,'Mixing 16-Bit and 32-Bit Code,' in theIntel® 64 and IA-32 Architectures SoftwareDeveloper's Manual, Volume 3A, for more information. Far Calls in Compatibility Mode. When the processor is operating in compatibility mode, the CALL instruction can be used to perform the following types of far calls: - Far call to the same privilege level, remaining in compatibility mode - Far call to the same privilege level, transitioning to 64-bit mode - Far call to a different privilege level (inter-privilege level call), transitioning to 64bit mode Note that a CALL instruction can not be used to cause a task switch in compatibility mode since task switches are not supported in IA-32e mode. In compatibility mode, the processor always uses the segment selector part of the far address to access the corresponding descriptor in the GDT or LDT. The descriptor type (code segment, call gate) and access rights determine the type of call operation to be performed. If the selected descriptor is for a code segment, a far call to a code segment at the same privilege level is performed. (If the selected code segment is at a different privilege level and the code segment is non-conforming, a general-protection exception is generated.) A far call to the same privilege level in compatibility mode is very similar to one carried out in protected mode. The target operand specifies an absolute far address either directly with a pointer (ptr16:16 or ptr16:32) or indirectly with a memory location (m16:16 or m16:32). The operand-size attribute determines the size of the offset (16 or 32 bits) in the far address. The new code segment selector and its descriptor are loaded into CS register and the offset from the instruction is loaded into the EIP register. The difference is that 64-bit mode may be entered. This specified by the L bit in the new code segment descriptor. Note that a 64-bit call gate (described in the next paragraph) can also be used to perform a far call to a code segment at the same privilege level. However, using this mechanism requires that the target code segment descriptor have the L bit set, causing an entry to 64-bit mode. When executing an inter-privilege-level far call, the code segment for the procedure being called must be accessed through a 64-bit call gate. The segment selector specified by the target operand identifies the call gate. The target operand can specify the call gate segment selector either directly with a pointer (ptr16:16 or ptr16:32) or indirectly with a memory location (m16:16 or m16:32). The processor obtains the segment selector for the new code segment and the new instruction pointer (offset) from the 16-byte call gate descriptor. (The offset from the target operand is ignored when a call gate is used.) On inter-privilege-level calls, the processor switches to the stack for the privilege level of the called procedure. The segment selector for the new stack segment is set to NULL. The new stack pointer is specified in the TSS for the currently running task. The branch to the new code segment occurs after the stack switch. (Note that when using a call gate to perform a far call to a segment at the same privilege level, an implicit stack switch occurs as a result of entering 64-bit mode. The SS selector is unchanged, but stack segment accesses use a segment base of 0x0, the limit is ignored, and the default stack size is 64-bits. The full value of RSP is used for the offset, of which the upper 32-bits are undefined.) On the new stack, the processor pushes the segment selector and stack pointer for the calling procedure's stack and the segment selector and instruction pointer for the calling procedure's code segment. (Parameter copy is not supported in IA-32e mode.) Finally, the processor branches to the address of the procedure being called within the new code segment. Near/(Far) Calls in 64-bit Mode. When the processor is operating in 64-bit mode, the CALL instruction can be used to perform the following types of far calls: - Far call to the same privilege level, transitioning to compatibility mode - Far call to the same privilege level, remaining in 64-bit mode - Far call to a different privilege level (inter-privilege level call), remaining in 64-bit mode Note that in this mode the CALL instruction can not be used to cause a task switch in 64-bit mode since task switches are not supported in IA-32e mode. In 64-bit mode, the processor always uses the segment selector part of the far address to access the corresponding descriptor in the GDT or LDT. The descriptor type (code segment, call gate) and access rights determine the type of call operation to be performed. If the selected descriptor is for a code segment, a far call to a code segment at the same privilege level is performed. (If the selected code segment is at a different privilege level and the code segment is non-conforming, a general-protection exception is generated.) A far call to the same privilege level in 64-bit mode is very similar to one carried out in compatibility mode. The target operand specifies an absolute far address indirectly with a memory location (m16:16, m16:32 or m16:64). The form of CALL with a direct specification of absolute far address is not defined in 64-bit mode. The operand-size attribute determines the size of the offset (16, 32, or 64 bits) in the far address. The new code segment selector and its descriptor are loaded into the CS register; the offset from the instruction is loaded into the EIP register. The new code segment may specify entry either into compatibility or 64-bit mode, based on the L bit value. A 64-bit call gate (described in the next paragraph) can also be used to perform a far call to a code segment at the same privilege level. However, using this mechanism requires that the target code segment descriptor have the L bit set. When executing an inter-privilege-level far call, the code segment for the procedure being called must be accessed through a 64-bit call gate. The segment selector specified by the target operand identifies the call gate. The target operand can only specify the call gate segment selector indirectly with a memory location (m16:16, m16:32 or m16:64). The processor obtains the segment selector for the new code segment and the new instruction pointer (offset) from the 16-byte call gate descriptor. (The offset from the target operand is ignored when a call gate is used.) On inter-privilege-level calls, the processor switches to the stack for the privilege level of the called procedure. The segment selector for the new stack segment is set to NULL. The new stack pointer is specified in the TSS for the currently running task. The branch to the new code segment occurs after the stack switch. Note that when using a call gate to perform a far call to a segment at the same privilege level, an implicit stack switch occurs as a result of entering 64-bit mode. The SS selector is unchanged, but stack segment accesses use a segment base of 0x0, the limit is ignored, and the default stack size is 64-bits. (The full value of RSP is used for the offset.) On the new stack, the processor pushes the segment selector and stack pointer for the calling procedure's stack and the segment selector and instruction pointer for the calling procedure's code segment. (Parameter copy is not supported in IA-32e mode.) Finally, the processor branches to the address of the procedure being called within the new code segment. " ^ self addInstruction: #call operands: { anAddressSource }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcmove: aX87Register "FP Conditional Move - equal (ZF=1) " ^ self addInstruction: #fcmove operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fnsave: aMemoryOperand "Store x87 FPU State " ^ self addInstruction: #fnsave operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! ffree: aX87Register "Free Floating-Point Register " ^ self addInstruction: #ffree operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fmul: aX87Register1 with: aX87Register2 " see #fmul" ^ self addInstruction: #fmul operands: { aX87Register1 . aX87Register2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fmulp: aX87Register "Multiply and Pop " ^ self addInstruction: #fmulp operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fnstenv: aMemoryOperand "Store x87 FPU Environment " ^ self addInstruction: #fnstenv operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovng: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovng operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! bsf: aRegister with: aSourceRegisterOrMemory "Bit Scan Forward Description ----------- Searches the source operand (second operand) for the least significant set bit (1 bit). If a least significant 1 bit is found, its bit index is stored in the destination operand (first operand). The source operand can be a register or a memory location; the destination operand is a register. The bit index is an unsigned offset from bit 0 of the source operand. If the content of the source operand is 0, the content of the destination operand is undefined. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #bsf operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! bt: aDestinationRegisterOrMemory with: aSourceRegisterOrImmediate "Bit Test Pseudo Code ----------- CF = Bit(BitBase, BitOffset); Description ----------- Selects the bit in a bit string (specified with the first operand, called the bit base) at the bit-position designated by the bit offset (specified by the second operand) and stores the value of the bit in the CF flag. The bit base operand can be a register or a memory location; the bit offset operand can be a register or an immediate value: - If the bit base operand specifies a register, the instruction takes the modulo 16, 32, or 64 of the bit offset operand (modulo size depends on the mode and register size; 64-bit operands are available only in 64-bit mode). - If the bit base operand specifies a memory location, the operand represents the address of the byte in memory that contains the bit base (bit 0 of the specified byte) of the bit string. The range of the bit position that can be referenced by the offset operand depends on the operand size. See also: Bit(BitBase, BitOffset) on page 3-11. Some assemblers support immediate bit offsets larger than 31 by using the immediate bit offset field in combination with the displacement field of the memory operand. In this case, the low-order 3 or 5 bits (3 for 16-bit operands, 5 for 32-bit operands) of the immediate bit offset are stored in the immediate bit offset field, and the high-order bits are shifted and combined with the byte displacement in the addressing mode by the assembler. The processor will ignore the high order bits if they are not zero. When accessing a bit in memory, the processor may access 4 bytes starting from the memory address for a 32-bit operand size, using by the following relationship: Effective Address + (4 \* (BitOffset DIV 32)) Or, it may access 2 bytes starting from the memory address for a 16-bit operand, using this relationship: Effective Address + (2 \* (BitOffset DIV 16)) It may do so even when only a single byte needs to be accessed to reach the given bit. When using this bit addressing mechanism, software should avoid referencing areas of memory close to address space holes. In particular, it should avoid references to memory-mapped I/O registers. Instead, software should use the MOV instructions to load from or store to these addresses, and use the register form of these instructions to manipulate the data. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bit operands. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #bt operands: { aDestinationRegisterOrMemory . aSourceRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmpxchg8b: aMemoryOperand "Compare and Exchange Bytes " ^ self addInstruction: #cmpxchg8b operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'labels' stamp: 'CamilloBruni 7/18/2012 16:27'! label: aNameOrLabel ifPresent: anExceptionBlock | label | label := aNameOrLabel. label isString ifTrue: [ label := self labelNamed: label ]. label isSet ifTrue: [ ^ anExceptionBlock cull: label ]. label isSet: true. ^ self addInstruction: label. ! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! DH "A 8bit general purpose register This register overlaps with DH, DX, EDX, RDX" ^ DH! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fdiv: aX87Register1 with: aX87Register2 " see #fdiv" ^ self addInstruction: #fdiv operands: { aX87Register1 . aX87Register2 }! ! !AJx86Assembler methodsFor: 'dnu' stamp: 'CamilloBruni 4/17/2012 17:51'! doesNotUnderstand: aMessage "try to dispatch a message based on instruction name" | sel pos | sel := aMessage selector. sel isBinary ifTrue: [ "binary selectors" ^ super doesNotUnderstand: aMessage ]. "use the first keyword to find the instruction" pos := sel indexOf: $:. pos > 0 ifTrue: [ sel := (sel first: pos - 1) asSymbol ]. self instructionDesciptions at: sel ifPresent: [ :description| ^ self addInstruction: sel description: description operands: aMessage arguments ]. ^ super doesNotUnderstand: aMessage! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! btc: aDestinationRegisterOrMemory with: aSourceRegisterOrImmediate "Bit Test and Complement Pseudo Code ----------- CF = Bit(BitBase, BitOffset); Bit(BitBase, BitOffset) = NOT Bit(BitBase, BitOffset); Description ----------- Selects the bit in a bit string (specified with the first operand, called the bit base) at the bit-position designated by the bit offset operand (second operand), stores the value of the bit in the CF flag, and complements the selected bit in the bit string. The bit base operand can be a register or a memory location; the bit offset operand can be a register or an immediate value: - If the bit base operand specifies a register, the instruction takes the modulo 16, 32, or 64 of the bit offset operand (modulo size depends on the mode and register size; 64-bit operands are available only in 64-bit mode). This allows any bit position to be selected. - If the bit base operand specifies a memory location, the operand represents the address of the byte in memory that contains the bit base (bit 0 of the specified byte) of the bit string. The range of the bit position that can be referenced by the offset operand depends on the operand size. See also: Bit(BitBase, BitOffset) on page 3-11. Some assemblers support immediate bit offsets larger than 31 by using the immediate bit offset field in combination with the displacement field of the memory operand. See 'BT—Bit Test' in this chapter for more information on this addressingmechanism. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #btc operands: { aDestinationRegisterOrMemory . aSourceRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! add: aRegisterOrMemoryOperand with: aSource "Add Pseudo Code ----------- DEST = DEST + SRC; Description ----------- Adds the destination operand (first operand) and the source operand (second operand) and then stores the result in the destination operand. The destination operand can be a register or a memory location; the source operand can be an immediate, a register, or a memory location. (However, two memory operands cannot be used in one instruction.) When an immediate value is used as an operand, it is sign-extended to the length of the destination operand format. The ADD instruction performs integer addition. It evaluates the result for both signed and unsigned integer operands and sets the OF and CF flags to indicate a carry (overflow) in the signed or unsigned result, respectively. The SF flag indicates the sign of the signed result. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #add operands: { aRegisterOrMemoryOperand . aSource }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jg: targetLabel " " ^ self addInstruction: #jg operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! test: aRegisterOrMemory with: aRegisterOrImmediate "Logical Compare Description ----------- Computes the bit-wise logical AND of first operand (source 1 operand) and the second operand (source 2 operand) and sets the SF, ZF, and PF status flags according to the result. The result is then discarded. In 64-bit mode, using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #test operands: { aRegisterOrMemory . aRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ST4 "A floating point register" ^ ST4! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fdivr: aMemoryOperand "Reverse Divide " ^ self addInstruction: #fdivr operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fdiv: aMemoryOperand "Divide " ^ self addInstruction: #fdiv operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovpo: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovpo operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! ST7 "A floating point register" ^ ST7! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! XMM2 "An SSE register" ^ XMM2! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! BX "A 16bit general purpose register This register overlaps with BL, BX, EBX, RBX" ^ BX! ! !AJx86Assembler methodsFor: 'function calls' stamp: ''! cdeclCall: aBlock alignment: align ^ self performingCall: (self newCdeclCall alignment: align) in: aBlock ! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fucom: aX87Register "Unordered Compare Floating Point Values " ^ self addInstruction: #fucom operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovpe: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovpe operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! clflush: aMemoryOperand "Flush Cache Line Pseudo Code ----------- Flush_Cache_Line(SRC); Description ----------- Invalidates the cache line that contains the linear address specified with the source operand from all levels of the processor cache hierarchy (data and instruction). The invalidation is broadcast throughout the cache coherence domain. If, at any level of the cache hierarchy, the line is inconsistent with memory (dirty) it is written to memory before invalidation. The source operand is a byte memory location. The availability of CLFLUSH is indicated by the presence of the CPUID feature flag CLFSH (bit 19 of the EDX register, see 'CPUID—CPU Identification' in this chapter).The aligned cache line size affected is also indicated with the CPUID instruction (bits 8 through 15 of the EBX register when the initial value in the EAX register is 1). The memory attribute of the page containing the affected line has no effect on the behavior of this instruction. It should be noted that processors are free to speculatively fetch and cache data from system memory regions assigned a memory-type allowing for speculative reads (such as, the WB, WC, and WT memory types). PREFETCHh instructions can be used to provide the processor with hints for this speculative behavior. Because this speculative fetching can occur at any time and is not tied to instruction execution, the CLFLUSH instruction is not ordered with respect to PREFETCHh instructions or any of the speculative fetching mechanisms (that is, data can be speculatively loaded into a cache line just before, during, or after the execution of a CLFLUSH instruction that references the cache line). CLFLUSH is only ordered by the MFENCE instruction. It is not guaranteed to be ordered by any other fencing or serializing instructions or by another CLFLUSH instruction. For example, software can use an MFENCE instruction to ensure that previous stores are included in the write-back. The CLFLUSH instruction can be used at all privilege levels and is subject to all permission checking and faults associated with a byte load (and in addition, a CLFLUSH instruction is allowed to flush a linear address in an execute-only segment). Like a load, the CLFLUSH instruction sets the A bit but not the D bit in the page tables. The CLFLUSH instruction was introduced with the SSE2 extensions; however, because it has its own CPUID feature flag, it can be implemented in IA-32 processors that do not include the SSE2 extensions. Also, detecting the presence of the SSE2 extensions with the CPUID instruction does not guarantee that the CLFLUSH instruction is implemented in the processor. CLFLUSH operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #clflush operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! idiv: aDestination "Signed Divide Description ----------- Divides the (signed) value in the AX, DX:AX, or EDX:EAX (dividend) by the source operand (divisor) and stores the result in the AX (AH:AL), DX:AX, or EDX:EAX registers. The source operand can be a general-purpose register or a memory location. The action of this instruction depends on the operand size (dividend/divisor). Non-integral results are truncated (chopped) towards 0. The remainder is always less than the divisor in magnitude. Overflow is indicated with the \#DE (divide error) exception rather than with the CF flag. In 64-bit mode, the instruction's default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8-R15). Use of the REX.W prefix promotes operation to 64 bits. In 64-bit mode when REX.W is applied, the instruction divides the signed value in RDX:RAX by the source operand. RAX contains a 64-bit quotient; RDX contains a 64-bit remainder. See the summary chart at the beginning of this section for encoding data and limits. See the following. Operand Size Dividend Divisor Quotient Remainder Quotient Range ------------------------- ---------- --------- ---------- ----------- --------------------- Word/byte AX r/m8 AL AH -128 to +127 Doubleword/word DX:AX r/m16 AX DX -32,768 to +32,767 Quadword/doubleword EDX:EAX r/m32 EAX EDX -2^31^ to 2^32^ - 1 Doublequadword/quadword RDX:RAX r/m64 RAX RDX -2^63^ to 2^64^ - 1 : IDIV Results " ^ self addInstruction: #idiv operands: { aDestination }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jnl: targetLabel "Jump short if not less/greater or equal (SF=OF) " ^ self addInstruction: #jnl operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fxrstor: aMemoryOperand "Restore x87 FPU, MMX, XMM, and MXCSR State Pseudo Code ----------- (x87 FPU, MMX, XMM7-XMM0, MXCSR) = Load(SRC); Description ----------- Reloads the x87 FPU, MMX technology, XMM, and MXCSR registers from the 512-byte memory image specified in the source operand. This data should have been written to memory previously using the FXSAVE instruction, and in the same format as required by the operating modes. The first byte of the data should be located on a 16-byte boundary. There are three distinct layouts of the FXSAVE state map: one for legacy and compatibility mode, a second format for 64-bit mode FXSAVE/FXRSTOR with REX.W=0, and the third format is for 64-bit mode with FXSAVE64/FXRSTOR64. Table 3-48 ('Non-64-bit-Mode Layout of FXSAVE and FXRSTOR Memory Region') shows the layout of the legacy/compatibility mode state information inmemory and describes the fields in the memory image for the FXRSTOR and FXSAVE instructions.Table 3-51 shows the layout of the 64-bit mode state information whenREX.W is set (FXSAVE64/FXRSTOR64). Table 3-52 shows the layout of the 64-bitmode state information when REX.W is clear (FXSAVE/FXRSTOR). The state image referenced with an FXRSTOR instruction must have been saved using an FXSAVE instruction or be in the same format as required by Table 3-48, Table 3-51, or Table 3-52. Referencing a state image saved with an FSAVE, FNSAVEinstruction or incompatible field layout will result in an incorrect state restoration. The FXRSTOR instruction does not flush pending x87 FPU exceptions. To check and raise exceptions when loading x87 FPU state information with the FXRSTOR instruction, use an FWAIT instruction after the FXRSTOR instruction. If the OSFXSR bit in control register CR4 is not set, the FXRSTOR instruction may not restore the states of the XMM and MXCSR registers. This behavior is implementation dependent. If the MXCSR state contains an unmasked exception with a corresponding status flag also set, loading the register with the FXRSTOR instruction will not result in a SIMD floating-point error condition being generated. Only the next occurrence of this unmasked exception will result in the exception being generated. Bits 16 through 32 of the MXCSR register are defined as reserved and should be set to 0. Attempting to write a 1 in any of these bits from the saved state image will result in a general protection exception (\#GP) being generated. Bytes 464:511 of an FXSAVE image are available for software use. FXRSTOR ignores the content of bytes 464:511 in an FXSAVE state image. " ^ self addInstruction: #fxrstor operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jnz: targetLabel "Jump short if not zero/not equal (ZF=1) " ^ self addInstruction: #jnz operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovc: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovc operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jne: targetLabel " " ^ self addInstruction: #jne operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movmskps: aRegisterOrMemory1 with: aRegisterOrMemory2 "Extract Packed Single-FP Sign Mask Description ----------- Extracts the sign bits from the packed single-precision floating-point values in the source operand (second operand), formats them into a 4-bit mask, and stores the mask in the destination operand (first operand). The source operand is an XMM register, and the destination operand is a general-purpose register. The mask is stored in the 4 low-order bits of the destination operand. Zero-extend the upper bits of the destination operand. In 64-bit mode, the instruction can access additional registers (XMM8-XMM15, R8-R15) when used with a REX.R prefix. The default operand size is 64-bit in 64-bit mode. " ^ self addInstruction: #movmskps operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movntdq: aRegisterOrMemory1 with: aRegisterOrMemory2 "Store Double Quadword Using Non-Temporal Hint Pseudo Code ----------- DEST = SRC; Description ----------- Moves the double quadword in the source operand (second operand) to the destination operand (first operand) using a non-temporal hint to prevent caching of the data during the write to memory. The source operand is an XMM register, which is assumed to contain integer data (packed bytes, words, doublewords, or quadwords). The destination operand is a 128-bit memory location. The non-temporal hint is implemented by using a write combining (WC) memory type protocol when writing the data to memory. Using this protocol, the processor does not write the data into the cache hierarchy, nor does it fetch the corresponding cache line from memory into the cache hierarchy. The memory type of the region being written to can override the non-temporal hint, if the memory address specified for the non-temporal store is in an uncacheable (UC) or write protected (WP) memory region. For more information on non-temporal stores, see 'Caching of Temporal vs. Non-Temporal Data' in Chapter 10 in theIntel®64 and IA-32 Architectures Software Developer's Manual, Volume 1. Because the WC protocol uses a weakly-ordered memory consistency model, a fencing operation implemented with the SFENCE or MFENCE instruction should be used in conjunction with MOVNTDQ instructions if multiple processors might use different memory types to read/write the destination memory locations. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movntdq operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! neg: aDestination "Two's Complement Negation Pseudo Code ----------- IF DEST = 0 CF = 0; ELSE CF = 1; FI; DEST = [- (DEST)] Description ----------- Replaces the value of operand (the destination operand) with its two's complement. (This operation is equivalent to subtracting the operand from 0.) The destination operand is located in a general-purpose register or a memory location. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #neg operands: { aDestination }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! sal: aDestinationRegisterOrMemory with: aRegisterOrImmediate " " ^ self addInstruction: #sal operands: { aDestinationRegisterOrMemory . aRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fsub: aMemoryOperand "Subtract " ^ self addInstruction: #fsub operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! BL "A 8bit general purpose register This register overlaps with BL, BX, EBX, RBX" ^ BL! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! AL "A 8bit general purpose register This register overlaps with AL, AX, EAX, RAX" ^ AL! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fisub: aMemoryOperand "Subtract " ^ self addInstruction: #fisub operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! BH "A 8bit general purpose register This register overlaps with BH, BX, EBX, RBX" ^ BH! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fsubrp: aX87Register "Reverse Subtract and Pop " ^ self addInstruction: #fsubrp operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'MartinMcClure 12/15/2012 13:37'! syscall "SYSCALL saves the RIP of the instruction following SYSCALL to RCX and loads a new RIP from the IA32_LSTAR (64-bit mode). Upon return, SYSRET copies the value saved in RCX to the RIP. SYSCALL saves RFLAGS (lower 32 bit only) in R11. It then masks RFLAGS with an OS-defined value using the IA32_FMASK (MSR C000_0084). The actual mask value used by the OS is the complement of the value written to the IA32_FMASK MSR. None of the bits in RFLAGS are automatically cleared (except for RF). SYSRET restores RFLAGS from R11 (the lower 32 bits only). Software should not alter the CS or SS descriptors in a manner that violates the following assumptions made by SYSCALL/SYSRET: * The CS and SS base and limit remain the same for all processes, including the operating system (the base is 0H and the limit is 0FFFFFFFFH). * The CS of the SYSCALL target has a privilege level of 0. * The CS of the SYSRET target has a privilege level of 3. SYSCALL/SYSRET do not check for violations of these assumptions. Operation IF (CS.L ~= 1 ) or (IA32_EFER.LMA ~= 1) or (IA32_EFER.SCE ~= 1) (* Not in 64-Bit Mode or SYSCALL/SYSRET not enabled in IA32_EFER *) THEN #UD; FI; RCX := RIP; RIP := LSTAR_MSR; R11 := EFLAGS; EFLAGS := (EFLAGS MASKED BY IA32_FMASK); CPL := 0; CS(SEL) := IA32_STAR_MSR[47:32]; CS(DPL) := 0; CS(BASE) := 0; CS(LIMIT) := 0xFFFFF; CS(GRANULAR) := 1; SS(SEL) := IA32_STAR_MSR[47:32] + 8; SS(DPL) := 0; SS(BASE) := 0; SS(LIMIT) := 0xFFFFF; SS(GRANULAR) := 1; SS(LIMIT) := 0xFFFFF; SS(GRANULAR) := 1; " ^ self addInstruction: #syscall operands: #()! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ST1 "A floating point register" ^ ST1! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! sbb: aRegisterOrMemoryOperand with: aSource "Integer Subtraction with Borrow " ^ self addInstruction: #sbb operands: { aRegisterOrMemoryOperand . aSource }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovg: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovg operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fucomip: aX87Register "Unordered Compare Floating Point Values and Set EFLAGS and Pop " ^ self addInstruction: #fucomip operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! ror: aDestinationRegisterOrMemory with: aRegisterOrImmediate "Rotate " ^ self addInstruction: #ror operands: { aDestinationRegisterOrMemory . aRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! AX "A 16bit general purpose register This register overlaps with AL, AX, EAX, RAX" ^ AX! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM7 "An SSE register" ^ XMM7! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovnb: aRegister with: aSourceRegisterOrMemory "Conditional Move - not below/above or equal/not carry (CF=0) " ^ self addInstruction: #cmovnb operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'register' stamp: ''! basePointer ^ self is32BitMode ifTrue: [ EBP ] ifFalse: [ BP ]! ! !AJx86Assembler methodsFor: 'accessing' stamp: ''! numGPRegisters "answer the total number of general-purpose registers for target platform" ^ 8 ! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fst: aMemoryOrX87Register "Store Floating Point Value " ^ self addInstruction: #fst operands: { aMemoryOrX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! rcr: aDestinationRegisterOrMemory with: aRegisterOrImmediate "Rotate " ^ self addInstruction: #rcr operands: { aDestinationRegisterOrMemory . aRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! DI "A 16bit general purpose register This register overlaps with BH, BX, EBX, RBX" ^ DI! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jnb: targetLabel "Jump short if not below/above or equal/not carry (CF=0) " ^ self addInstruction: #jnb operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movddup: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move One Double-FP and Duplicate Description ----------- The linear address corresponds to the address of the least-significant byte of the referenced memory data. When a memory address is indicated, the 8 bytes of data at memory location m64 are loaded. When the register-register form of this operation is used, the lower half of the 128-bit source register is duplicated and copied into the 128-bit destination register. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movddup operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcmovu: aX87Register "FP Conditional Move - unordered (PF=1) " ^ self addInstruction: #fcmovu operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! rol: aDestinationRegisterOrMemory with: aRegisterOrImmediate "Rotate " ^ self addInstruction: #rol operands: { aDestinationRegisterOrMemory . aRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jc: targetLabel " " ^ self addInstruction: #jc operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jo: targetLabel "Jump short if overflow (OF=1) " ^ self addInstruction: #jo operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! sar: aDestinationRegisterOrMemory with: aRegisterOrImmediate "Shift " ^ self addInstruction: #sar operands: { aDestinationRegisterOrMemory . aRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'accessing' stamp: ''! undefinedLabels "answer a collection of labels, which having no defined position " | lbls | lbls := OrderedCollection new. labels keysAndValuesDo: [:key :value | value ifNil: [ lbls add: key] ]. ^ lbls! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovnz: aRegister with: aSourceRegisterOrMemory "Conditional Move - not zero/not equal (ZF=1) " ^ self addInstruction: #cmovnz operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'accessing' stamp: 'CamilloBruni 4/18/2012 15:26'! newInstruction ^ AJx86Instruction new! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcmovne: aX87Register "FP Conditional Move - not equal (ZF=0) " ^ self addInstruction: #fcmovne operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! ST6 "A floating point register" ^ ST6! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! shr: aDestinationRegisterOrMemory with: aRegisterOrImmediate "Shift " ^ self addInstruction: #shr operands: { aDestinationRegisterOrMemory . aRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM0 "An SSE register" ^ XMM0! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fsubr: aMemoryOperand "Reverse Subtract " ^ self addInstruction: #fsubr operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcomi: aX87Register "Compare Floating Point Values and Set EFLAGS " ^ self addInstruction: #fcomi operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovnae: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovnae operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'convenience' stamp: 'CamilloBruni 4/19/2012 13:20'! dd: aByteArray self assert: aByteArray size == SizeDWord. ^ self addInstruction: (AJData data: aByteArray)! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fcmovnu: aX87Register "FP Conditional Move - not unordered (PF=0) " ^ self addInstruction: #fcmovnu operands: { aX87Register }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmova: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmova operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovns: aRegister with: aSourceRegisterOrMemory "Conditional Move - not sign (SF=0) " ^ self addInstruction: #cmovns operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fimul: aMemoryOperand "Multiply " ^ self addInstruction: #fimul operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! lea: aDestinationRegister with: aSourceMemory "Load Effective Address " ^ self addInstruction: #lea operands: { aDestinationRegister . aSourceMemory }! ! !AJx86Assembler methodsFor: 'function calls' stamp: ''! newStdCall ^ stackManager newStdCall asm: self ! ! !AJx86Assembler methodsFor: 'instruction list' stamp: ''! replace: anInstruction with: otherInstructions "replace a single instruction with one or more other instructions" ^ instructions := instructions replace: anInstruction with: otherInstructions.! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! EBX "A 32bit general purpose register This register overlaps with BL, BX, EBX, RBX" ^ EBX! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jnp: targetLabel "Jump short if not parity/parity odd " ^ self addInstruction: #jnp operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ST0 "A floating point register" ^ ST0! ! !AJx86Assembler methodsFor: 'alignment' stamp: 'CamilloBruni 4/12/2012 13:52'! align: aByteSize self addInstruction: (AJAlignmentInstruction align: aByteSize)! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fadd: aMemoryOperand "Add " ^ self addInstruction: #fadd operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! js: targetLabel "Jump short if sign (SF=1) " ^ self addInstruction: #js operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instruction list' stamp: ''! addInstruction: anInstruction "add one or multiple instructions to the tail" instructions ifNil: [ instructions := anInstruction. ] ifNotNil: [ last := last last next: anInstruction. ]. anInstruction level: level. last := anInstruction last. ^ anInstruction ! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jz: targetLabel "Jump short if zero/equal (ZF=0) " ^ self addInstruction: #jz operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'labels' stamp: 'CamilloBruni 5/29/2012 13:06'! labelNamed: aNameOrLabel "directly use an object as label" aNameOrLabel isString ifFalse: [ self assert: (labels at: aNameOrLabel name ) = aNameOrLabel. ^ aNameOrLabel ]. ^ labels at: aNameOrLabel ifAbsentPut: [ AJJumpLabel new name: aNameOrLabel ]! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovl: aRegister with: aSourceRegisterOrMemory "Conditional Move - less/not greater (SF!!=OF) " ^ self addInstruction: #cmovl operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movups: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Unaligned Packed Single-FP Values Pseudo Code ----------- DEST = SRC; Description ----------- Moves a double quadword containing four packed single-precision floating-point values from the source operand (second operand) to the destination operand (first operand). This instruction can be used to load an XMM register from a 128-bit memory location, store the contents of an XMM register into a 128-bit memory location, or move data between two XMM registers. When the source or destination operand is a memory operand, the operand may be unaligned on a 16-byte boundary without causing a general-protection exception (\#GP) to be generated.1 To move packed single-precision floating-point values to and from memory locations that are known to be aligned on 16-byte boundaries, use the MOVAPS instruction. While executing in 16-bit addressing mode, a linear address for a 128-bit data access that overlaps the end of a 16-bit segment is not allowed and is defined as reserved behavior. A specific processor implementation may or may not generate a general-protection exception (\#GP) in this situation, and the address that spans the end of the segment may or may not wrap around to the beginning of the segment. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). ​1. If alignment checking is enabled (CR0.AM = 1, RFLAGS.AC = 1, and CPL = 3), an alignment-check exception (\#AC) may or may not be generated (depending on processor implementation) when the operand is not aligned on an 8-byte boundary. " ^ self addInstruction: #movups operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! EAX "A 32bit general purpose register This register overlaps with AL, AX, EAX, RAX" ^ EAX! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovnge: aRegister with: aSourceRegisterOrMemory " " ^ self addInstruction: #cmovnge operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'converting' stamp: ''! operand: anObject anObject isInteger ifTrue: [ ^ anObject asImm ]. anObject isString ifTrue: [ ^ anObject ]. ^ anObject! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! amdprefetchw: aMemoryOperand " " ^ self addInstruction: #amdprefetchw operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmovz: aRegister with: aSourceRegisterOrMemory "Conditional Move - zero/equal (ZF=0) " ^ self addInstruction: #cmovz operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'register' stamp: ''! counter ^ self is32BitMode ifTrue: [ ECX ] ifFalse: [ CX ]! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! MM3 "An MMX register" ^ MM3! ! !AJx86Assembler methodsFor: 'testing' stamp: ''! hasLabelNamed: aName ^ labels includesKey: aName ! ! !AJx86Assembler methodsFor: 'debugging' stamp: ''! gccDisassemble ^ self gccDisassemble: self bytes.! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movupd: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Unaligned Packed Double-FP Value Pseudo Code ----------- DEST = SRC; Description ----------- Moves a double quadword containing two packed double-precision floating-point values from the source operand (second operand) to the destination operand (first operand). This instruction can be used to load an XMM register from a 128-bit memory location, store the contents of an XMM register into a 128-bit memory location, or move data between two XMM registers. When the source or destination operand is a memory operand, the operand may be unaligned on a 16-byte boundary without causing a general-protection exception (\#GP) to be generated.1 To move double-precision floating-point values to and from memory locations that are known to be aligned on 16-byte boundaries, use the MOVAPD instruction. While executing in 16-bit addressing mode, a linear address for a 128-bit data access that overlaps the end of a 16-bit segment is not allowed and is defined as reserved behavior. A specific processor implementation may or may not generate a general-protection exception (\#GP) in this situation, and the address that spans the end of the segment may or may not wrap around to the beginning of the segment. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). ​1. If alignment checking is enabled (CR0.AM = 1, RFLAGS.AC = 1, and CPL = 3), an alignment-check exception (\#AC) may or may not be generated (depending on processor implementation) when the operand is not aligned on an 8-byte boundary. " ^ self addInstruction: #movupd operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movdqu: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move Unaligned Double Quadword Pseudo Code ----------- DEST = SRC; 1. If alignment checking is enabled (CR0.AM = 1, RFLAGS.AC = 1, and CPL = 3), an alignment-check exception (#AC) may or may not be generated (depending on processor implementation) when the operand is not aligned on an 8-byte boundary. Description ----------- Moves a double quadword from the source operand (second operand) to the destination operand (first operand). This instruction can be used to load an XMM register from a 128-bit memory location, to store the contents of an XMM register into a 128-bit memory location, or to move data between two XMM registers. When the source or destination operand is a memory operand, the operand may be unaligned on a 16-byte boundary without causing a general-protection exception (\#GP) to be generated.1 To move a double quadword to or from memory locations that are known to be aligned on 16-byte boundaries, use the MOVDQA instruction. While executing in 16-bit addressing mode, a linear address for a 128-bit data access that overlaps the end of a 16-bit segment is not allowed and is defined as reserved behavior. A specific processor implementation may or may not generate a general-protection exception (\#GP) in this situation, and the address that spans the end of the segment may or may not wrap around to the beginning of the segment. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movdqu operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! movhps: aRegisterOrMemory1 with: aRegisterOrMemory2 "Move High Packed Single-FP Values Pseudo Code ----------- (* MOVHPS instruction for memory to XMM move *) DEST[127:64] = SRC; (* DEST[63:0] unchanged *) (* MOVHPS instruction for XMM to memory move *) DEST = SRC[127:64]; Description ----------- Moves two packed single-precision floating-point values from the source operand (second operand) to the destination operand (first operand). The source and destination operands can be an XMM register or a 64-bit memory location. This instruction allows two single-precision floating-point values to be moved to and from the high quadword of an XMM register and memory. It cannot be used for register to register or memory to memory moves. When the destination operand is an XMM register, the low quadword of the register remains unchanged. In 64-bit mode, use of the REX.R prefix permits this instruction to access additional registers (XMM8-XMM15). " ^ self addInstruction: #movhps operands: { aRegisterOrMemory1 . aRegisterOrMemory2 }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fistp: aMemoryOperand "Store Integer and Pop " ^ self addInstruction: #fistp operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'register' stamp: ''! accumulator ^ self is32BitMode ifTrue: [ EAX ] ifFalse: [ AX ]! ! !AJx86Assembler methodsFor: 'accessing' stamp: ''! wordSize ^ 4! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jnge: targetLabel " " ^ self addInstruction: #jnge operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'accessing' stamp: ''! pointerSize "the default pointer size in bytes on this CPU" ^ 4! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! jae: targetLabel " " ^ self addInstruction: #jae operands: { targetLabel }! ! !AJx86Assembler methodsFor: 'instruction list' stamp: 'CamilloBruni 4/17/2012 17:51'! addInstruction: sel description: description operands: operands ^ self addInstruction: (self newInstruction: sel description: description operands: operands)! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! popcnt: aRegister with: aSourceRegisterOrMemory "Bit Population Count Description ----------- This instruction calculates of number of bits set to 1 in the second operand (source) and returns the count in the first operand (a destination register). " ^ self addInstruction: #popcnt operands: { aRegister . aSourceRegisterOrMemory }! ! !AJx86Assembler methodsFor: 'debugging' stamp: 'CamilloBruni 7/23/2012 15:25'! gccDisassemble: bytes 'disas.sh' asFileReference delete writeStreamDo: [:s| s nextPutAll: '#!!/bin/bash'; lf; nextPutAll: 'gcc -g -O0 '; nextPutAll: (self is32 ifTrue: ['-m32'] ifFalse: [ '-m64' ]); nextPutAll: ' disas.test.c >> /dev/null 2>&1'; lf; nextPutAll: 'gdb -q -x gdb.commands a.out | grep "^0x" > disas.output'; lf]. 'gdb.commands' asFileReference delete writeStreamDo: [:s| s nextPutAll: 'b 4'; lf; nextPutAll: 'r'; lf; nextPutAll: 'x /'; print: bytes size; nextPutAll: 'xb &instructions'; lf; nextPutAll: 'x /'; print: bytes size; nextPutAll: 'ub &instructions'; lf; nextPutAll: 'disas &instructions &instructions+1'; lf; nextPutAll: 'q']. 'disas.test.c' asFileReference delete writeStreamDo: [ :f| { '#include '. 'void main() {' . 'const char instructions[]= {'. String streamContents: [:s| bytes do: [:b | s print: b] separatedBy: [ s << ', ']]. '};'. 'printf("%d", instructions);'. '}' } do: [:x | f nextPutAll: x value asString; lf ]]. Smalltalk at: #OSProcess ifPresent: [ :cls| cls waitForCommand: 'cd "', Smalltalk imagePath, '"; chmod a+x ./disas.sh; sh ./disas.sh'. ^ 'disas.output' asFileReference readStream contents asString]. self inform: 'OSProcess has to be installed to run gccDisassemble'.! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! shl: aDestinationRegisterOrMemory with: aRegisterOrImmediate "Shift " ^ self addInstruction: #shl operands: { aDestinationRegisterOrMemory . aRegisterOrImmediate }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ST2 "A floating point register" ^ ST2! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! MM6 "An MMX register" ^ MM6! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fisttp: aMemoryOperand "Store Integer with Truncation and Pop Pseudo Code ----------- DEST = ST; pop ST; Description ----------- FISTTP converts the value in ST into a signed integer using truncation (chop) as rounding mode, transfers the result to the destination, and pop ST. FISTTP accepts word, short integer, and long integer destinations. The following table shows the results obtained when storing various classes of numbers in integer format. ST(0) DEST --------------------------------------- ------ -∞ or Value Too Large for DEST Format \* F ≤ - 1 - I - 1 \< F \< + 1 0 F ≥ + 1 + I +∞ or Value Too Large for DEST Format \* NaN \* : FISTTP Results - Notes - F means finite floating-point value. - I means integer. - Indicates floating-point invalid-operation (\#IA) exception. This instruction's operation is the same in non-64-bit modes and 64-bit mode. " ^ self addInstruction: #fisttp operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! MM5 "An MMX register" ^ MM5! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! cmpxchg: aDestinationRegisterOrMemory with: aSourceRegister "Compare and Exchange Pseudo Code ----------- (* Accumulator = AL, AX, EAX, or RAX depending on whether a byte, word, doubleword, or quadword comparison is being performed *) IF accumulator = DEST ZF = 1; DEST = SRC; ELSE ZF = 0; accumulator = DEST; FI; Description ----------- Compares the value in the AL, AX, EAX, or RAX register with the first operand (destination operand). If the two values are equal, the second operand (source operand) is loaded into the destination operand. Otherwise, the destination operand is loaded into the AL, AX, EAX or RAX register. RAX register is available only in 64-bit mode. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. To simplify the interface to the processor's bus, the destination operand receives a write cycle without regard to the result of the comparison. The destination operand is written back if the comparison fails; otherwise, the source operand is written into the destination. (The processor never produces a locked read without also producing a locked write.) In 64-bit mode, the instruction's default operation size is 32 bits. Use of the REX.R prefix permits access to additional registers (R8-R15). Use of the REX.W prefix promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #cmpxchg operands: { aDestinationRegisterOrMemory . aSourceRegister }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! fidiv: aMemoryOperand "Divide " ^ self addInstruction: #fidiv operands: { aMemoryOperand }! ! !AJx86Assembler methodsFor: 'instructions generated' stamp: 'CamilloBruni 7/17/2012 13:38'! not: aDestination "One's Complement Negation Pseudo Code ----------- DEST = NOT DEST; Description ----------- Performs a bitwise NOT operation (each 1 is set to 0, and each 0 is set to 1) on the destination operand and stores the result in the destination operand location. The destination operand can be a register or a memory location. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. In 64-bit mode, the instruction's default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits. " ^ self addInstruction: #not operands: { aDestination }! ! !AJx86Assembler class methodsFor: 'instance creation' stamp: 'CamilloBruni 4/19/2012 11:46'! noStackFrame ^ self new noStackFrame! ! !AJx86Assembler class methodsFor: 'debugging' stamp: ''! gccDisassemble: bytesArray "compile the given bytes to a C binary and disassemble it using gdb" ^ self new gccDisassemble: bytesArray! ! !AJx86AssemblerTests commentStamp: 'TorstenBergmann 2/4/2014 21:39'! SUnit tests for x86 assembler! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:22'! testAssemblyMemBaseDisp asm mov: EAX ptr + 1 -> EAX; mov: EBX ptr + ECX -> EAX. self assert: asm bytes = #(16r8B 16r40 16r01 16r8B 16r04 16r0B) asByteArray! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:22'! testBitTest asm bt: EAX with: 0. self assert: asm bytes = #(16r0F 16rBA 16rE0 16r00) asByteArray! ! !AJx86AssemblerTests methodsFor: 'utility' stamp: 'MartinMcClure 1/1/2013 22:19'! bytes: aBlock asm := self newAssembler. aBlock value: asm. ^ asm bytes! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'HenrikSperreJohansen 2/26/2015 14:45'! testStringOpMnemonics "Test that string operation mnemonics using both register and memory operands generate the same code as their noop versions" | mnemonicRegOpBytes mnemonicMemOpBytes | asm reset; ins: asm AL; ins: asm AX; ins: asm EAX; outs: asm AL; outs: asm AX; outs: asm EAX; movs: asm AL; movs: asm AX; movs: asm EAX; cmps: asm AL; cmps: asm AX; cmps: asm EAX; stos: asm AL; stos: asm AX; stos: asm EAX; lods: asm AL; lods: asm AX; lods: asm EAX; scas: asm AL; scas: asm AX; scas: asm EAX. mnemonicRegOpBytes := asm bytes. asm reset; ins: (AJMem new size: 1); ins: (AJMem new size: 2); ins: (AJMem new size: 4); outs: (AJMem new size: 1); outs: (AJMem new size: 2); outs: (AJMem new size: 4); movs: (AJMem new size: 1); movs: (AJMem new size: 2); movs: (AJMem new size: 4); cmps:(AJMem new size: 1); cmps: (AJMem new size: 2); cmps: (AJMem new size: 4); stos: (AJMem new size: 1); stos: (AJMem new size: 2); stos: (AJMem new size: 4); lods: (AJMem new size: 1); lods: (AJMem new size: 2); lods: (AJMem new size: 4); scas: (AJMem new size: 1); scas: (AJMem new size: 2); scas: (AJMem new size: 4). mnemonicMemOpBytes := asm bytes. asm reset; insb; insw; insd; outsb; outsw; outsd; movsb; movsw; movsd; cmpsb; cmpsw; cmpsd; stosb; stosw; stosd; lodsb; lodsw; lodsd; scasb; scasw; scasd. self assert: mnemonicRegOpBytes equals: asm bytes. self assert: mnemonicMemOpBytes equals: asm bytes. asm reset ! ! !AJx86AssemblerTests methodsFor: 'tests-FPU' stamp: 'CamilloBruni 7/23/2012 15:03'! testFXCH self assert: [ :a| a fxch "the same as: asm fxch: asm ST1" ] bytes: #[ 2r11011001 2r11001001 ] ! ! !AJx86AssemblerTests methodsFor: 'utility' stamp: 'CamilloBruni 8/22/2012 14:47'! assert: aBlock bytes: aByteArray self assert: (self bytes: aBlock) equals: aByteArray .! ! !AJx86AssemblerTests methodsFor: 'tests-data' stamp: 'CamilloBruni 4/12/2012 14:25'! testDataBytesAlignWord |data| data := self setUpDataBytesAlign: 2. self assert: asm bytes equals: #[144 0 16r12].! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:22'! testAssemblyMemBase asm mov: EAX ptr -> EAX; mov: ESP ptr -> EAX; mov: EBP ptr -> EAX. self assert: asm bytes = #(16r8B 0 16r8B 16r04 16r24 16r8B 16r45 16r00) asByteArray! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'MartinMcClure 12/15/2012 13:39'! testSyscall "Syscall instruction is only valid in 64-bit mode" self asmShould: [ :a | a syscall ] raise: Error! ! !AJx86AssemblerTests methodsFor: 'tests-data' stamp: ''! setUpDataBytesAlign: alignToBytes asm nop. asm align: alignToBytes. ^ asm db: 16r12.! ! !AJx86AssemblerTests methodsFor: 'tests-FPU' stamp: 'CamilloBruni 7/23/2012 15:15'! testFXCHST1 self assert: [ :a| a fxch: asm ST1 ] bytes: #[ 2r11011001 2r11001001 ] ! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:23'! testForwardJumps asm jmp: #label1; label: #label1. self assert: asm bytes = #(16rEB 0 ) asByteArray. ! ! !AJx86AssemblerTests methodsFor: 'tests-data' stamp: ''! testDataWord | data| asm nop. data := asm dw: #[16r34 16r12]. self assert: asm bytes equals: #[144 16r34 16r12]. ! ! !AJx86AssemblerTests methodsFor: 'tests-data' stamp: 'CamilloBruni 4/12/2012 14:24'! testDataBytesAlignDouble |data| data := self setUpDataBytesAlign: 4. self assert: asm bytes equals: #[144 0 0 0 16r12].! ! !AJx86AssemblerTests methodsFor: 'tests-data' stamp: 'CamilloBruni 4/12/2012 14:24'! testDataBytesAlignQuad |data| data := self setUpDataBytesAlign: 8. self assert: asm bytes equals: #[144 0 0 0 0 0 0 0 16r12].! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:22'! testAssembly3 " instructions without operands. (AJInstructionDescription instructions select: [:each | each group = #emit]) keys asSortedCollection " | str | str := #( #cbw 16r66 16r98 #cdq 16r99 "#cdqe 64 bit " #clc 16rF8 #cld 16rFC #cmc 16rF5 #cpuid 16r0F 16rA2 "#cqo 64 bit " #cwd 16r66 16r99 #cwde 16r98 #daa 16r27 #das 16r2F #emms 16r0F 16r77 #f2xm1 16rD9 16rF0 #fabs 16rD9 16rE1 #fchs 16rD9 16rE0 #fclex 16r9B 16rDB 16rE2 #fcompp 16rDE 16rD9 #fcos 16rD9 16rFF #fdecstp 16rD9 16rF6 #fincstp 16rD9 16rF7 #finit 16r9B 16rDB 16rE3 #fld1 16rD9 16rE8 #fldl2e 16rD9 16rEA #fldl2t 16rD9 16rE9 #fldlg2 16rD9 16rEC #fldln2 16rD9 16rED #fldpi 16rD9 16rEB #fldz 16rD9 16rEE #fnclex 16rDB 16rE2 #fninit 16rDB 16rE3 #fnop 16rD9 16rD0 #fpatan 16rD9 16rF3 #fprem 16rD9 16rF8 #fprem1 16rD9 16rF5 #fptan 16rD9 16rF2 #frndint 16rD9 16rFC #fscale 16rD9 16rFD #fsin 16rD9 16rFE #fsincos 16rD9 16rFB #fsqrt 16rD9 16rFA #ftst 16rD9 16rE4 #fucompp 16rDA 16rE9 #fwait 16r9B #fxam 16rD9 16rE5 #fxtract 16rD9 16rF4 #fyl2x 16rD9 16rF1 #fyl2xp1 16rD9 16rF9 #int3 16rCC #leave 16rC9 #lfence 16r0F 16rAE 16rE8 #lock 16rF0 "prefix" #mfence 16r0F 16rAE 16rF0 #monitor 16r0F 16r01 16rC8 #mwait 16r0F 16r01 16rC9 #nop 16r90 #pause 16rF3 16r90 #popad 16r61 #popfd 16r9D " #popfq 16r48 16r9D - 64 bit " #pushad 16r60 #pushf 16r66 16r9C #pushfd 16r9C " #pushfq -64 bit" #rdtsc 16r0F 16r31 #rdtscp 16r0F 16r01 16rF9 #sahf 16r9E #sfence 16r0F 16rAE 16rF8 #stc 16rF9 #std 16rFD #ud2 16r0F 16r0B #std 16rFD "dummy" ) readStream. [ str atEnd ] whileFalse: [ | instr tst | instr := str next. tst := OrderedCollection new. [ str peek isInteger ] whileTrue: [ tst add: str next ]. asm reset noStackFrame. asm perform: instr. self assert: (asm bytes = tst asByteArray ) ]. ! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:23'! testMovSxZx asm movsx: asm AX to: asm EAX; movzx: asm AX to: asm EAX; movsx: asm AL to: asm EAX; movzx: asm AH to: asm EAX. self assert: asm bytes = #[ 16r0F 16rBF 16rC0 16r0F 16rB7 16rC0 16r0F 16rBE 16rC0 16r0F 16rB6 16rC4 ] ! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:22'! testAssembly1 asm push: EBP; mov: ESP -> EBP; mov: 1024 -> EAX; mov: EBP -> ESP; pop: EBP; ret. self assert: asm bytes = #(85 139 236 184 0 4 0 0 139 229 93 195) asByteArray! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 8/22/2012 14:50'! testJMPRegister self assert: [ :assembler | assembler jmp: assembler EAX ] bytes: #[ 16rFF 2r11100000 ]. self assert: [ :assembler | assembler jmp: assembler ECX ] bytes: #[ 16rFF 2r11100001 ]. self assert: [ :assembler | assembler jmp: assembler EDX ] bytes: #[ 16rFF 2r11100010 ]! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'IgorStasenko 5/28/2012 02:58'! testAssemblyImmAddr "test generating immediate address, note GDB disassembling it to: 0x1fab : 0x8b 0x05 0xef 0xbe 0xad 0xde 0x00001fab : mov 0xdeadbeef,%eax which is WRONG!! " asm mov: 16rdeadbeef asUImm ptr32 to: asm EAX. " 8b05efbeadde mov eax, [deadbeef] " self assert: asm bytes = #[139 5 239 190 173 222] ! ! !AJx86AssemblerTests methodsFor: 'running' stamp: ''! setUp super setUp. asm := self newAssembler.! ! !AJx86AssemblerTests methodsFor: 'tests-data' stamp: 'CamilloBruni 4/19/2012 11:51'! testDataDouble | data| asm nop. data := asm dd: #[16r78 16r56 16r34 16r12]. self assert: asm bytes equals: #[144 16r78 16r56 16r34 16r12].! ! !AJx86AssemblerTests methodsFor: 'tests-data' stamp: 'CamilloBruni 4/12/2012 14:25'! setUpDataBytes ^ self setUpDataBytesAlign: 1! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:22'! testAssemblyMemBytes asm mov: ((ESI ptr + ECX) size: 1) -> BL; mov: BL -> ((ESI ptr + ECX) size:1). self assert: asm bytes = #(16r8A 16r1C 16r0E 16r88 16r1C 16r0E ) asByteArray! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:22'! testCall asm call: EAX; call: EAX ptr - 4; call: EAX ptr. self assert: asm bytes = #(255 208 255 80 252 255 16) asByteArray! ! !AJx86AssemblerTests methodsFor: 'tests-data' stamp: ''! testDataBytes |data| data := self setUpDataBytes. self assert: asm bytes equals: #[144 16r12].! ! !AJx86AssemblerTests methodsFor: 'utility' stamp: ''! asmShould: aBlock raise: anError self should: [self bytes: aBlock] raise: anError.! ! !AJx86AssemblerTests methodsFor: 'utility' stamp: 'CamilloBruni 4/3/2012 09:56'! newAssembler ^ AJx86Assembler new noStackFrame; yourself! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:23'! testJumps asm label: #label1; nop; nop; nop; jz: #label1. self assert: asm bytes = #(144 144 144 116 251) asByteArray. asm reset; noStackFrame; label: #label1. 126 timesRepeat: [ asm nop ]. asm jz: #label1. self assert: (asm bytes size = 128). asm reset; noStackFrame; label: #label1; nop; nop; nop; jmp: #label1. self assert: asm bytes = #(144 144 144 235 251) asByteArray. asm reset; noStackFrame; jmp: #label1; label: #label1. self assert: asm bytes = #(16rEB 0 ) asByteArray. ! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:22'! testAssemblyMemBaseDisp2 asm mov: EAX ptr - 1 -> EAX; mov: EBX ptr + ECX * 2 - 5 -> EAX. self assert: asm bytes = #(16r8B 16r40 16rFF 16r8B 16r44 16r4B 16rFB) asByteArray! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:23'! testTest "Special RAX opcodes" "8bit operand opcode" asm test: AL with: 5. self assert: asm bytes = #[16rA8 05]. asm reset; test: AX with: 5. "16bit operand Prefix byte, 16bit immediate (LSB)" self assert: asm bytes = #[16r66 16rA9 05 0]. "32bit operand " asm reset; test: EAX with: 1. self assert: asm bytes = #[16rA9 01 00 00 00]. "Need more assert for non-EAX receiver, non-immediate operands" ! ! !AJx86AssemblerTests methodsFor: 'tests' stamp: 'CamilloBruni 4/3/2012 10:23'! testImmLabels "test immediates with labels" | code pos | asm mov: EAX ptr -> EAX; mov: (16rFFFFFFFF asUImm label: (asm labelNamed: #foo) ) to: EAX. code := asm generatedCode. pos := code offsetAt: #foo. self assert: (code bytes at: pos+1) = 255. self assert: (code bytes at: pos+2) = 255. self assert: (code bytes at: pos+3) = 255. self assert: (code bytes at: pos+4) = 255. ! ! !AJx86AssemblerTests methodsFor: 'tests-FPU' stamp: 'HenrikSperreJohansen 6/26/2014 15:10'! testMOVCMPSD "MOVSD/CMPSD is aliased to no-op string operations, make sure we generate correct code when the intention is to use SSE2 instruction" | instructions | instructions := asm instructionsFor: [ [ asm movsd: XMM1 with: XMM2; cmpsd:XMM1 with: XMM2; bytes ] on: ShouldBeImplemented do: [:e | "Dispatch to correct op happens during emission, don't let an operation whose group is unimplemented yet stop us from checking the operation is at least converted correctly." "We do want to run the next ops as well though, so resume this even though it can't" e resumeUnchecked: nil] ]. instructions do: [ :instruction | self assert: (AJx86InstructionDescription instructionsAmbiguous contains: [ :one | one first = instruction name and: [ one second = instruction description group ] ]) ]! ! !AJx86GPRegister commentStamp: 'sig 12/7/2009 03:22'! A general purpose x86 & x64 registers! !AJx86GPRegister methodsFor: 'converting' stamp: 'MartinMcClure 1/30/2013 21:44'! as64 ^ self isHighByte ifTrue: [ self asLowByte as64 ] ifFalse: [ AJx86Registers generalPurposeWithIndex: self index size: 8 requiresRex: self index > 7 prohibitsRex: false ]! ! !AJx86GPRegister methodsFor: 'converting' stamp: 'MartinMcClure 1/30/2013 21:43'! as32 ^ self isHighByte ifTrue: [ self asLowByte as32 ] ifFalse: [ AJx86Registers generalPurposeWithIndex: self index size: 4 requiresRex: self index > 7 prohibitsRex: false ]! ! !AJx86GPRegister methodsFor: 'testing' stamp: 'MartinMcClure 1/30/2013 21:55'! isLowByte "return true for 8bit low-byte register (AL - DL)" "Note that this does *not* answer true for all byte registers -- send #is8 for that." ^ self code <= 3! ! !AJx86GPRegister methodsFor: 'printing' stamp: 'MartinMcClure 1/1/2013 18:55'! printAsMemBaseOn: aStream aStream nextPutAll: self registerName ! ! !AJx86GPRegister methodsFor: 'converting' stamp: ''! ptr "turn receiver into a memory operand with receiver as base" ^ AJMem new base: self! ! !AJx86GPRegister methodsFor: 'accessing' stamp: 'CamilloBruni 3/20/2012 18:48'! registerName ^ name asString.! ! !AJx86GPRegister methodsFor: 'converting' stamp: 'MartinMcClure 1/30/2013 21:46'! asLowByte self isLowByte ifTrue: [ ^ self ]. self isHighByte ifFalse: [ Error signal: 'Can only convert high byte 8bit register to low byte' ]. ^ AJx86Registers generalPurposeWithIndex: self index - 2r100 size: 1 requiresRex: false prohibitsRex: false! ! !AJx86GPRegister methodsFor: 'emitting' stamp: ''! emitModRM: emitter code: rCode immSize: immSize "Receiver is register, hence mod = 3 immSize is ignored" ^ emitter emitMod: 3 reg: rCode rm: self code! ! !AJx86GPRegister methodsFor: 'accessing' stamp: ''! stackSize ^ self size! ! !AJx86GPRegister methodsFor: 'testing' stamp: 'MartinMcClure 1/30/2013 21:33'! isHighByte "return true for 8bit high-byte registers (AH - DH)" ^ self prohibitsRex! ! !AJx86GPRegister methodsFor: 'converting' stamp: 'MartinMcClure 1/30/2013 21:40'! as8 "8-bit low-byte registers require REX if they have a high index (>7), or if they are one of BPL, SIL, DIL, SPL (indices 4-7). The only way to get AH, BH, CH, or DH out of this method is to send it to one of those registers." ^ self is8 ifTrue: [ self ] ifFalse: [ AJx86Registers generalPurposeWithIndex: self index size: 1 requiresRex: self index > 3 prohibitsRex: false ]! ! !AJx86GPRegister methodsFor: 'accessing' stamp: 'CamilloBruni 7/17/2012 11:07'! descriptionOn: s s nextPutAll: 'A '; print: self size * 8; nextPutAll: 'bit general purpose register'.! ! !AJx86GPRegister methodsFor: 'printing' stamp: ''! printOn: aStream aStream nextPutAll: self registerName ! ! !AJx86GPRegister methodsFor: 'testing' stamp: ''! isGeneralPurpose ^ true! ! !AJx86GPRegister methodsFor: 'converting' stamp: 'MartinMcClure 1/30/2013 21:42'! as16 ^ self isHighByte ifTrue: [ self asLowByte as16 ] ifFalse: [ AJx86Registers generalPurposeWithIndex: self index size: 2 requiresRex: self index > 7 prohibitsRex: false ]! ! !AJx86GPRegister methodsFor: 'converting' stamp: 'MartinMcClure 1/30/2013 21:53'! asHighByte self isHighByte ifTrue: [ ^ self ]. self isLowByte ifFalse: [ Error signal: 'Can only convert AH, BH, CH, or DH to high byte' ]. ^ AJx86Registers generalPurposeWithIndex: self index + 2r100 size: 1 requiresRex: false prohibitsRex: true! ! !AJx86Instruction commentStamp: 'TorstenBergmann 1/30/2014 09:17'! The x86 machine instructions! !AJx86Instruction methodsFor: 'code generation' stamp: ''! emitQWord: dword "Emit a qword (8 bytes) in little-endian order (since our target it x86 anyways)" self emitByte: (dword bitAnd: 255); emitByte: (dword>>8 bitAnd: 255); emitByte: (dword>>16 bitAnd: 255); emitByte: (dword>>24 bitAnd: 255); emitByte: (dword>>32 bitAnd: 255); emitByte: (dword>>40 bitAnd: 255); emitByte: (dword>>48 bitAnd: 255); emitByte: (dword>>56 bitAnd: 255) ! ! !AJx86Instruction methodsFor: 'accessing' stamp: 'CamilloBruni 4/17/2012 17:55'! description ^ description! ! !AJx86Instruction methodsFor: 'code generation - prefixes' stamp: ''! emitRexR: w opReg: opReg regCode: regCode "no-op in 32 bit mode" ! ! !AJx86Instruction methodsFor: 'code generation' stamp: ''! setLabelPosition: label "set label position for immediate operand(s), if any" label position: self position + machineCode size. ! ! !AJx86Instruction methodsFor: 'code generation - prefixes' stamp: 'MartinMcClure 1/4/2013 22:14'! emitRexForOp1: op1 op2: op2 "op1 is the general-purpose register argument (or a register number). op2 is the reg/mem argument. In 64-bit mode, the instruction's default operation size is 32 bits. Use of the REX.W prefix promotes operation to 64 bits. Use of the REX.R prefix permits access to additional registers (R8-R15) for the op1 (reg) register. Use of the REX.B prefix permits access to additional registers (R8-R15) for the op2 (r/m) register, or the base register of op2 if register indirect. Use of the REX.X prefix permits access to additional registers (R8-R15) for the index register of op2, if indexed. See the summary chart at the beginning of this section for encoding data and limits." | requires64Bit | "no-op in 32 bit mode" self is32BitMode ifTrue: [ ^ self ]. op1 isInteger ifTrue: [ ^ self emitRexForInteger: op1 op2: op2 ]. requires64Bit := op1 is64 or: [ op2 isReg and: [ op2 is64 ] ]. self emitRexPrefixW: requires64Bit R: op1 isUpperBank X: op2 hasUpperBankIndex B: op2 isUpperBank! ! !AJx86Instruction methodsFor: 'code generation' stamp: ''! emitOpCode: opCode | byte | "instruction prefix" (byte := (opCode bitAnd: 16rFF000000)) = 0 ifFalse: [ self emitByte: byte >> 24 ]. (byte := (opCode bitAnd: 16r00FF0000)) = 0 ifFalse: [ self emitByte: byte >> 16 ]. (byte := (opCode bitAnd: 16r0000FF00)) = 0 ifFalse: [ self emitByte: byte >> 8 ]. self emitByte: (opCode bitAnd: 16rFF). ! ! !AJx86Instruction methodsFor: 'emitting code' stamp: ''! emitWord: aWord "little-endian" self emitByte: (aWord bitAnd: 255); emitByte: ((aWord >> 8) bitAnd: 255) ! ! !AJx86Instruction methodsFor: 'testing' stamp: ''! is64BitMode ^ false! ! !AJx86Instruction methodsFor: 'visitor' stamp: ''! accept: anObject "generic instruction" ^ anObject visitInstruction: self ! ! !AJx86Instruction methodsFor: 'accessing' stamp: 'CamilloBruni 4/17/2012 17:55'! description: anInstructionDescription description := anInstructionDescription! ! !AJx86Instruction methodsFor: 'code generation - prefixes' stamp: ''! emitRexForInteger: anInt op2: op2 self emitRexPrefixW: op2 is64 R: false X: false B: op2 isUpperBank.! ! !AJx86Instruction methodsFor: 'testing' stamp: ''! is32BitMode ^ true! ! !AJx86Instruction methodsFor: 'code generation' stamp: 'CamilloBruni 3/30/2012 17:10'! emitX86Inl: opCode reg: reg "Emit instruction where register is inlined to opcode." ^ self emitX86Inl: opCode reg: reg withRex: true! ! !AJx86Instruction methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 15:47'! requiresRex ^false! ! !AJx86Instruction methodsFor: 'code generation - prefixes' stamp: 'CamilloBruni 4/4/2012 17:10'! emitRexRM: opRequires64Bit regCode: regCode rm: rm self emitRexPrefixW: opRequires64Bit R: (regCode > 7) X: false B: rm isUpperBank ! ! !AJx86Instruction methodsFor: 'consistency' stamp: 'MartinMcClure 2/9/2013 14:15'! checkOperandsForConflict "Signal an error if the given operands cannot be used together. Must be sent after operands are set." | prohibited required | required := self requiresRex. prohibited := false. operands do: [ :op | (op isInteger not and: [ op prohibitsRex ]) ifTrue: [ prohibited := true ] ]. prohibited & required ifTrue: [ self error: 'Mix of operands that require and prohibit a REX prefix' ]! ! !AJx86Instruction methodsFor: 'code generation' stamp: 'CamilloBruni 3/28/2012 15:59'! emitMod: mod reg: reg rm: rm "Emit MODR/M byte. mmrrrxxx mm = mod rrr = REG (r8/r16/r32/mm/xmm xxx = r/m " ^ self emitByte: (mod & 3) << 3 + (reg & 7) << 3 + (rm & 7) ! ! !AJx86Instruction methodsFor: 'accessing' stamp: 'CamilloBruni 8/23/2012 16:01'! instructionDesciptions ^ AJx86InstructionDescription instructions! ! !AJx86Instruction methodsFor: 'code generation - prefixes' stamp: 'HenrikSperreJohansen 6/25/2014 22:42'! emitOperandSizeOverridePrefix: anOperand "If creating 64bit code, this must be called last of the prefix-generators, as the 64-bit prefixes are required to precede the opcode" "Switch to 16-bit operand mode for the next opcode if necessary" anOperand is16 ifTrue: [ self emitByte: self operandSizeOverridePrefix]. self emitRexRM: anOperand is64 regCode: 0 rm: anOperand ! ! !AJx86Instruction methodsFor: 'code generation - prefixes' stamp: ''! emitRexForSingleOperand: op "In 64-bit mode, the instruction’s default operation size is 32 bits. Use of the REX.W prefix promotes operation to 64 bits. Use of the REX.B prefix permits access to additional registers (R8-R15). See the summary chart at the beginning of this section for encoding data and limits." self emitRexPrefixW: op is64 R: false X: false B: op isUpperBank .! ! !AJx86Instruction methodsFor: 'code generation' stamp: 'CamilloBruni 4/17/2012 17:56'! emitCode: asm "do not generate machine code if it is already there" machineCode ifNotNil: [ ^ self ]. "make sure all operands are converted" operands ifNotNil: [ operands := operands collect: #asAJOperand ]. machineCode := WriteStream on: (ByteArray new: 16). description emitUsing: self operands: operands. machineCode := machineCode contents.! ! !AJx86Instruction methodsFor: 'code generation' stamp: ''! emitDWord: dword "Emit dword (4 bytes) in little-endian order (since our target it x86 anyways)" self emitByte: (dword bitAnd: 255); emitByte: (dword>>8 bitAnd: 255); emitByte: (dword>>16 bitAnd: 255); emitByte: (dword>>24 bitAnd: 255) ! ! !AJx86Instruction methodsFor: 'code generation' stamp: ''! emitImmediate: imm size: size ^ imm emitUsing: self size: size! ! !AJx86Instruction methodsFor: 'prefixes' stamp: 'HenrikSperreJohansen 6/25/2014 22:33'! operandSizeOverridePrefix ^16r66! ! !AJx86Instruction methodsFor: 'code generation' stamp: ''! emitSegmentPrefix: aMem (aMem isMem and: [ aMem hasSegmentPrefix ]) ifTrue: [ self emitByte: aMem segmentPrefixCode. ] ! ! !AJx86Instruction methodsFor: 'code generation' stamp: 'CamilloBruni 3/30/2012 16:50'! emitX86RM: opCode size: aSize regOrCode: regOrCode rm: regOrMem immSize: immSize "Emit instruction with reg/memory operand." | byte code | code := regOrCode isInteger ifTrue: [ regOrCode ] ifFalse: [ regOrCode code ]. "16 bit prefix" aSize == 2 ifTrue: [ self emitByte: 16r66 ]. "segment prefix" self emitSegmentPrefix: regOrMem. "instruction prefix" (byte := (opCode bitAnd: 16rFF000000)) = 0 ifFalse: [ self emitByte: byte >> 24 ]. self emitRexForOp1: regOrCode op2: regOrMem. (byte := (opCode bitAnd: 16r00FF0000)) = 0 ifFalse: [ self emitByte: byte >> 16 ]. (byte := (opCode bitAnd: 16r0000FF00)) = 0 ifFalse: [ self emitByte: byte >> 8 ]. self emitByte: (opCode bitAnd: 16rFF). "ModR/M" ^ regOrMem emitModRM: self code: code immSize: immSize ! ! !AJx86Instruction methodsFor: 'code generation - prefixes' stamp: 'MartinMcClure 1/27/2013 16:24'! emitRexPrefixW: w R: r X: x B: b " field bit def - 7-4 2r0100 REX prefix identifier W 3 0 = Operand size determined by CS.D 1 = 64 Bit Operand Size R 2 Extension of the ModR/M reg field X 1 Extension of the SIB index field B 0 Extension of the ModR/M r/m field. SIB base field, or Opcode reg field " self requiresRex ifTrue: [ self is32BitMode ifTrue: [ self error: 'Attempt to use a 64-bit-specific instruction or operand in 32-bit mode' ] ifFalse: [ self emitByte: 2r0100 << 4 | (w asBit << 3) | (r asBit << 2) | (x asBit << 1) | b asBit ] ]! ! !AJx86Instruction methodsFor: 'code generation' stamp: 'CamilloBruni 3/29/2012 13:54'! emitByte: byte self assert: byte isByte. machineCode nextPut: byte ! ! !AJx86Instruction methodsFor: 'code generation' stamp: ''! emitX86Inl: opCode reg: reg withRex: useREX "Emit instruction where register is inlined to opcode." | byte | "16 bit prefix" reg size == 2 ifTrue: [ self emitByte: 16r66 ]. "instruction prefix" (byte := (opCode bitAnd: 16rFF000000)) = 0 ifFalse: [ self emitByte: byte >> 24 ]. useREX ifTrue: [ self emitRexForSingleOperand: reg ]. (byte := (opCode bitAnd: 16r00FF0000)) = 0 ifFalse: [ self emitByte: byte >> 16 ]. (byte := (opCode bitAnd: 16r0000FF00)) = 0 ifFalse: [ self emitByte: byte >> 8 ]. self emitByte: (opCode bitAnd: 16rFF) + (reg code bitAnd: 7). ! ! !AJx86Instruction methodsFor: 'code generation' stamp: ''! emitX86RM: opCode size: aSize regOrCode: regOrCode rm: regOrMem "Emit instruction with reg/memory operand." ^ self emitX86RM: opCode size: aSize regOrCode: regOrCode rm: regOrMem immSize: 0 ! ! !AJx86Instruction methodsFor: 'code generation' stamp: 'MartinMcClure 1/4/2013 22:27'! emitScale: shift index: indexCode base: baseCode self emitByte: ((shift << 3) + (indexCode bitAnd: 7) << 3) + (baseCode bitAnd: 7)! ! !AJx86Instruction methodsFor: 'testing' stamp: ''! isGPNRegister: reg "answer true if given register is native general purpose register, matching the target native size i.e. 32 bits for x86 or 64 bits for x64" ^ reg isGeneralPurpose and: [ reg size = 4 ]! ! !AJx86InstructionDescription commentStamp: 'sig 12/7/2009 10:36'! name: an instruction mnemonic group: an instruction encoding group o1Flags: operand1 flags o2Flags: operand2 flags opCode1: opcode 1 opCode2: opcode 2 opCodeR: code for inlining in MR field as register Operand flags: bit: 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ______________________________________________ *86| *64 | XMM | MM | IMM | MEM | 64 | 32 | 16 | 8| - *64 , set on o1Flags, meaning that instruction available only for x64 processor mode - *86 , set on o1Flags, meaning that instruction available only for x86 processor mode ! !AJx86InstructionDescription methodsFor: 'emitting-dispatch' stamp: 'CamilloBruni 3/30/2012 17:05'! emitUsing: emitter operands: operands |args| (self is64BitOnly and: [ emitter is64BitMode not ]) ifTrue: [ self error: 'instruction ', self name asUppercase,' is only for 64 bit mode' ]. (self is32BitOnly and: [ emitter is32BitMode not ]) ifTrue: [ self error: 'instruction ', self name asUppercase,' is only for 32 bit mode' ]. "manually create the arguments array" args := Array new: 4. args at: 1 put: emitter. args replaceFrom: 2 to: (operands size + 1 min: 4) with: operands startingAt: 1. ^ self perform: groupEmitSelector withArguments: args! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: 'CamilloBruni 4/13/2012 15:44'! comment: aString comment := aString! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitrot: emitter operand1: op1 operand2: op2 operand3: op3 | useImm8 opCode | op1 isRegMem & ((op2 isRegTypeGPB and: [ op2 index = 1 "cl" ]) | op2 isImm) ifFalse: [ self invalidInstruction ]. useImm8 := op2 isImm and: [ (op2 value ~= 1) | (op2 relocMode ~~ #RelocNone) ]. opCode := useImm8 ifTrue: [ 16rC0 ] ifFalse: [ 16rD0 ]. op1 size ~= 1 ifTrue: [ opCode := opCode bitOr: 1 ]. op2 isReg ifTrue: [ opCode := opCode bitOr: 2 ]. emitter emitX86RM: opCode size: op1 size regOrCode: opCodeR rm: op1 immSize: useImm8 asBit. useImm8 ifTrue: [ emitter emitImmediate: op2 size: 1 ] ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: 'CamilloBruni 4/13/2012 14:51'! description ^ description! ! !AJx86InstructionDescription methodsFor: 'emitting - mmu' stamp: ''! emitmmuMov: emitter operand1: op1 operand2: op2 operand3: op3 self shouldBeImplemented. self assert: o1Flags ~= 0. self assert: o2Flags ~= 0. "Check parameters (X)MM|GP32_64 <- (X)MM|GP32_64|Mem|Imm" (op1 isMem & ((o1Flags bitAnd: OMEM) = 0)) | (op1 isRegTypeMM & ((o1Flags bitAnd: OMM) = 0)) | (op1 isRegTypeXMM & ((o1Flags bitAnd: OXMM) = 0)) | (op1 isRegTypeGPD & ((o1Flags bitAnd: OG32) = 0)) | (op1 isRegTypeGPQ & ((o1Flags bitAnd: OG64) = 0)) | (op2 isRegTypeMM & ((o2Flags bitAnd: OMM) = 0)) | (op2 isRegTypeXMM & ((o2Flags bitAnd: OXMM) = 0)) | (op2 isRegTypeGPD & ((o2Flags bitAnd: OG32) = 0)) | (op2 isRegTypeGPQ & ((o2Flags bitAnd: OG64) = 0)) | (op2 isMem & ((o2Flags bitAnd: OMEM) = 0)) | (op1 isMem & op2 isMem) ifTrue: [ self invalidInstruction ]. ! ! !AJx86InstructionDescription methodsFor: 'emitting - mmu' stamp: ''! emitmmuPextr: emitter operand1: op1 operand2: op2 operand3: op3 self shouldBeImplemented! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitmovbe: anAJx86Assembler operand1: anUndefinedObject operand2: anUndefinedObject3 operand3: anUndefinedObject4 self shouldBeImplemented! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitmovSxZx: emitter operand1: dst operand2: src operand3: op3 dst isReg & src isRegMem ifFalse: [ self invalidInstruction ]. dst isRegTypeGPB ifTrue: [ self invalidInstruction ]. (src size ~= 2 and: [src size ~= 1 ]) ifTrue: [ self invalidInstruction ]. (src size = 2 and: [dst isRegTypeGPW ]) ifTrue: [ self invalidInstruction ]. src size = 2 ifTrue: [ ^ emitter emitX86RM: opCode1 + 1 size: dst size regOrCode: dst rm: src ]. emitter emitX86RM: opCode1 size: dst size regOrCode: dst rm: src ! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitshldShrd: emitter operand1: dst operand2: src1 operand3: src2 (src2 isImm or: [ src2 isRegTypeGPB and: [ src2 index = 1 "cl"]]) ifFalse: [ self invalidInstruction ]. dst isRegMem & src1 isReg ifFalse: [ self invalidInstruction ]. self assert: (dst size = src1 size). emitter emitX86RM: opCode1 + src2 isReg asBit size: src1 size regOrCode: src1 rm: dst immSize: src2 isImm asBit. src2 isImm ifTrue: [ emitter emitImmediate: src2 size: 1 ]! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitx87mem: emitter operand1: m operand2: op2 operand3: op3 | opCode mod | m isMem ifFalse: [ ^ self invalidInstruction ]. opCode := mod := 0. (m is16 and: [ (o1Flags bitAnd: OFM2) ~= 0 ]) ifTrue: [ opCode := (opCode1 bitAnd: 16rFF000000) >> 24. mod := opCodeR ]. (m is32 and: [ (o1Flags bitAnd: OFM4) ~= 0 ]) ifTrue: [ opCode := (opCode1 bitAnd: 16r00FF0000) >> 16. mod := opCodeR ]. (m is64 and: [ (o1Flags bitAnd: OFM8) ~= 0 ]) ifTrue: [ opCode := (opCode1 bitAnd: 16r0000FF00) >> 8. mod := (opCode1 bitAnd: 16r000000FF) ]. opCode = 0 ifTrue: [ self invalidInstruction ]. emitter emitSegmentPrefix: m; emitByte: opCode. m emitModRM: emitter code: mod immSize: 0. ! ! !AJx86InstructionDescription methodsFor: 'testing' stamp: ''! is32BitOnly ^ (o1Flags bitAnd: 2r1000000000) ~= 0! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitmovPtr: emitter operand1: op1 operand2: op2 operand3: op3 | reg imm opCode | (op1 isReg & op2 isImm) | (op1 isImm & op2 isReg) ifFalse: [ self invalidInstruction ]. opCode := op1 isReg ifTrue: [reg := op1. imm := op2. 16rA0] ifFalse: [reg := op2. imm := op1. 16rA2]. reg index ~= 0 ifTrue: [ self invalidInstruction ]. reg isRegTypeGPW ifTrue: [ emitter emitByte: 16r66 ]. emitter emitRexR: (reg size=8) opReg: 0 regCode: 0. emitter emitByte: opCode + (reg size ~=1) asBit. emitter emitImmediate: imm size: reg size ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: 'CamilloBruni 4/13/2012 15:44'! comment ^ comment! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitjmp: emitter operand1: target operand2: op2 operand3: op3 target isString ifTrue: [ "jump on label" ^ emitter addJump: target condition: nil hint: nil ]. target isRegMem ifTrue: [ ^ emitter emitX86RM: 16rFF size: 0 regOrCode: 4 rm: target ]. emitter emitByte: 16rE9. emitter emitDisplacement: target inlinedDisp: -4 ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! opCode1: anObject "Set the value of opCode1" opCode1 := anObject! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitcrc32: emitter operand1: dst operand2: src operand3: op3 (dst isReg and: [ src isRegMem ]) ifTrue: [ self assert: (dst isRegTypeGPD | dst isRegTypeGPQ). ^ emitter emitX86RM: opCode1 + (src size ~= 1) asBit size: src size regOrCode: dst rm: src ]. self invalidInstruction. ! ! !AJx86InstructionDescription methodsFor: 'testing' stamp: ''! is64BitOnly ^ (o1Flags bitAnd: 2r100000000) ~= 0! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! o2Flags: anObject "Set the value of o2Flags" o2Flags := anObject! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: 'CamilloBruni 4/13/2012 14:51'! description: aString description := aString! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitmem: emitter operand1: op1 operand2: op2 operand3: op3 op1 isMem ifFalse: [ self invalidInstruction ]. self assert: (opCode2 = 0 or: [ opCode2 = 1 ]). emitter emitX86RM: opCode1 size: opCode2 << 3 regOrCode: opCodeR rm: op1 ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! opCodeR: anObject "Set the value of opCodeR" opCodeR := anObject! ! !AJx86InstructionDescription methodsFor: 'initialize-release' stamp: ''! fromArray: arr | tmp | name := arr at: 1. group := arr at: 2. groupEmitSelector := ('emit', group,':operand1:operand2:operand3:') asSymbol. tmp := arr at: 3. tmp isSymbol ifTrue: [ tmp := self translateSymFlag: tmp ]. o1Flags := tmp. o2Flags := arr at: 4. opCodeR := arr at: 5. opCode1 := arr at: 6. opCode2 := arr at: 7.! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! o1Flags "Answer the value of o1Flags" ^ o1Flags! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! group ^ group! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitalu: emitter operand1: op1 operand2: op2 operand3: op3 | opCode opReg | opCode := opCode1. opReg := opCodeR. " Mem <- Reg " (op1 isMem and: [ op2 isReg ]) ifTrue: [ ^ emitter emitX86RM: opCode + op2 isRegTypeGPB not asBit size: op2 size regOrCode: op2 rm: op1 ]. "Reg <- Reg|Mem" (op1 isReg and: [op2 isRegMem]) ifTrue: [ ^ emitter emitX86RM: opCode + 2 + op1 isRegTypeGPB not asBit size: op1 size regOrCode: op1 rm: op2 ]. op2 isImm ifFalse: [ self invalidInstruction ]. "short constant" op2 isInt8 ifTrue: [ | szBits | szBits := op1 size = 1 ifTrue: [ 0 ] ifFalse: [ 3 ]. emitter emitX86RM: opCode2 + szBits size: op1 size regOrCode: opReg rm: op1 immSize: 1. ^ emitter emitImmediate: op2 size: 1. ]. " AL, AX, EAX, RAX register shortcuts" (op1 isRegIndex: 0) ifTrue: [ op1 isRegTypeGPW ifTrue: [ emitter emitByte: 16r66 " 16 bit " ]. op1 isRegTypeGPQ ifTrue: [ emitter emitByte: 16r48 " REX.W" ]. emitter emitByte: (opReg << 3 bitOr: (16r04 + op1 isRegTypeGPB not asBit)). ^ emitter emitImmediate: op2 size: (op1 size min: 4) ]. (op1 isRegMem) ifTrue: [ | immSize szBits | immSize := op2 isInt8 ifTrue: [1] ifFalse: [ op1 size min: 4]. szBits := op1 size ~= 1 ifTrue: [ immSize ~= 1 ifTrue: [1] ifFalse: [3]] ifFalse: [ 0]. emitter emitX86RM: opCode2 + szBits size: op1 size regOrCode: opReg rm: op1 immSize: immSize. ^ emitter emitImmediate: op2 size: immSize. ]. self invalidInstruction. ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! o2Flags "Answer the value of o2Flags" ^ o2Flags! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: 'CamilloBruni 4/17/2012 19:02'! emitimul: emitter operand1: op1 operand2: op2 operand3: op3 | immSize | op1 isRegMem ifFalse: [ ^ self invalidInstruction ]. " 1 operand " (op2 isNil and: [ op3 isNil ]) ifTrue: [ ^ emitter emitX86RM: 16rF6 + (op1 size ~= 1) asBit size: op1 size regOrCode: 5 rm: op1 ]. op1 isReg ifFalse: [ ^ self invalidInstruction ]. "2 operands" op3 isNil ifTrue: [ " self assert: op1 isRegTypeGPW." op2 isRegMem ifTrue: [ ^ emitter emitX86RM: 16r0FAF size: op1 size regOrCode: op1 code rm: op2 ]. op2 isImm ifFalse: [ ^ self invalidInstruction ]. (op2 isInt8 and: [ op2 relocMode == #RelocNone ]) ifTrue: [ emitter emitX86RM: 16r6B size: op1 size regOrCode: op1 code rm: op1 immSize: 1. ^ emitter emitImmediate: op2 size: 1. ]. immSize := op1 isRegTypeGPW ifTrue: [ 2 ] ifFalse: [ 4 ]. emitter emitX86RM: 16r69 size: op1 size regOrCode: op1 code rm: op1 immSize: immSize. ^ emitter emitImmediate: op2 size: immSize. ]. " 3 operands " (op2 isRegMem and: [op3 isImm ]) ifFalse: [ ^ self invalidInstruction ]. (op3 isInt8 and: [ op3 relocMode == #RelocNone ]) ifTrue: [ emitter emitX86RM: 16r6B size: op1 size regOrCode: op1 rm: op2 immSize: 1. ^ emitter emitImmediate: op3 size: 1. ]. immSize := op1 isRegTypeGPW ifTrue: [2] ifFalse: [4]. emitter emitX86RM: 16r69 size: op1 size regOrCode: op1 rm: op2 immSize: immSize. emitter emitImmediate: op3 size: immSize. ! ! !AJx86InstructionDescription methodsFor: 'emitting - mmu' stamp: ''! emitmmuMovD: emitter operand1: op1 operand2: op2 operand3: op3 self shouldBeImplemented! ! !AJx86InstructionDescription methodsFor: 'code emitting' stamp: 'HenrikSperreJohansen 6/26/2014 14:37'! emittest: emitter operand1: op1 operand2: op2 operand3: op3 | immSize | op1 isRegMem & op2 isReg ifTrue: [ op1 size notNil & (op1 size ~= op2 size) ifTrue: [ self error: 'Operands ' , op1 asString , ' and ' , op2 asString , ' don''t match in size: ' , op1 size asString , ' !!= ' , op2 size asString ]. ^ emitter emitX86RM: 16r84 + op2 isRegTypeGPB not asBit size: op2 size regOrCode: op2 rm: op1 ]. (op1 isReg and: [ op1 index = 0 and: [ op2 isImm ] ]) ifTrue: [ immSize := op1 size min: 4. emitter emitOperandSizeOverridePrefix: op1. emitter emitByte: 16rA8 + (op1 size ~= 1) asBit. ^ emitter emitImmediate: op2 size: immSize ]. (op1 isRegMem and: [ op2 isImm ]) ifFalse: [ self invalidInstruction ]. immSize := op1 size min: 4. (op2 fitsInSize: immSize) ifFalse: [ self invalidInstruction ]. emitter emitSegmentPrefix: op1. emitter emitOperandSizeOverridePrefix: op1. emitter emitByte: 16rF6 + (op1 size ~= 1) asBit. op1 emitModRM: emitter code: 0 immSize: immSize. emitter emitImmediate: op2 size: immSize! ! !AJx86InstructionDescription methodsFor: 'emitting - mmu' stamp: ''! emitmmuPrefetch: emitter operand1: op1 operand2: op2 operand3: op3 self shouldBeImplemented! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitx87fstsw: anAJx86Assembler operand1: anUndefinedObject operand2: anUndefinedObject3 operand3: anUndefinedObject4 self shouldBeImplemented! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitret: emitter operand1: op1 operand2: op2 operand3: op3 op1 ifNil: [ ^ emitter emitByte: 16rC3 ]. op1 isImm ifFalse: [ self invalidInstruction ]. self assert: (op1 isUnsigned and: [op1 fitsInSize: 2]). (op1 value = 0 and: [ op1 relocMode == #RelocNone ]) ifTrue: [ ^ emitter emitByte: 16rC3 ]. emitter emitByte: 16rC2. emitter emitImmediate: op1 size: 2! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitx87memSti: emitter operand1: op1 operand2: op2 operand3: op3 op1 isRegTypeX87 ifTrue: [ emitter emitByte: (opCode2 bitAnd: 16rFF000000)>>24. emitter emitByte: (opCode2 bitAnd: 16r00FF0000)>>16 + op1 index. ^ self ]. " ... fall through to I_X87_MEM ... " ^ self emitx87mem: emitter operand1: op1 operand2: op2 operand3: op3 ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! name: anObject "Set the value of name" name := anObject! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitcjmp: emitter operand1: target operand2: hint operand3: op3 "Conditional jump. Use only symbols as labels" target isString ifTrue: [ "jump on label" ^ emitter addJump: target condition: opCode1 hint: hint ]. "we could check if label is bound , and emit short jump, instead of 32-bit relative jump address" self invalidInstruction. emitter emitByte: 16r0F; emitByte: (16r80 bitOr: opCode1); emitDisplacement: target inlinedDisp: -4 ! ! !AJx86InstructionDescription methodsFor: 'emitting - mmu' stamp: ''! emitmmuRm3DNow: emitter operand1: op1 operand2: op2 operand3: op3 self shouldBeImplemented! ! !AJx86InstructionDescription methodsFor: 'emitting - mmu' stamp: ''! emitmmurmi: emitter operand1: op1 operand2: op2 operand3: op3 self shouldBeImplemented! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitrm: emitter operand1: dst operand2: src operand3: op3 emitter emitX86RM: opCode1 + (dst isRegTypeGPB not) asBit size: dst size regOrCode: opCodeR rm: dst! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitcall: emitter operand1: op1 operand2: op2 operand3: op3 (op1 isMem or: [ op1 isReg and: [ op1 index = 0 "EAX" ] ]) ifTrue: [ ^ emitter emitX86RM: 16rFF size: 4 regOrCode: 2 rm: op1 ]. op1 isImm ifTrue: [ "call by relative offset, you should be really sure what you're' doing" emitter emitByte: 16rE8. op1 emitUsing: emitter size: 4. ^ self. ]. op1 isLabel ifTrue: [ emitter emitByte: 16rE8. emitter emitDisplacement: op1 inlinedDisp: -4. ^ self ]. self invalidInstruction. ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! name ^ name! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitrrm: emitter operand1: dst operand2: src operand3: op3 dst isReg & src isRegMem ifFalse: [ self invalidInstruction ]. self assert: (dst isRegTypeGPB not). emitter emitX86RM: opCode1 size: dst size regOrCode: dst rm: src! ! !AJx86InstructionDescription methodsFor: 'emitting-dispatch' stamp: ''! emitUsing: emitter operand1: op1 operand2: op2 operand3: op3 (self is64BitOnly and: [ emitter is64BitMode not ]) ifTrue: [ self error: 'instruction is only for 64 bit mode' ]. (self is32BitOnly and: [ emitter is32BitMode not ]) ifTrue: [ self error: 'instruction is only for 32 bit mode' ]. ^ self perform: groupEmitSelector withArguments: { emitter. op1. op2. op3 }! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitbswap: emitter operand1: op1 operand2: op2 operand3: op3 op1 isReg ifTrue: [ emitter emitRexR: op1 isRegTypeGPQ opReg: 1 regCode: op1 code. emitter emitByte: 16r0F. ^ emitter emitModR: 1 r: op1 code ]. self invalidInstruction.! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! opCode2: anObject "Set the value of opCode2" opCode2 := anObject! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: 'IgorStasenko 3/20/2012 16:08'! emitmov: emitter operand1: dst operand2: src operand3: op3 src isReg & dst isReg ifTrue: [ self assert: (src isRegTypeGPB | src isRegTypeGPW | src isRegTypeGPD | src isRegTypeGPQ ). ]. " reg <- mem " dst isReg & src isRegMem ifTrue: [ self assert: (dst isRegTypeGPB | dst isRegTypeGPW | dst isRegTypeGPD | dst isRegTypeGPQ ). " (src size = dst size) ifFalse: [ self invalidInstruction ]. " ^ emitter emitX86RM: 16r0000008A + dst isRegTypeGPB not asBit size: dst size regOrCode: dst rm: src ]. " reg <- imm " dst isReg & src isImm ifTrue: [ | immSize | immSize := dst size. emitter is64BitMode & immSize = 8 & src isInt32 & (src relocMode == #RelocNone) ifTrue: [ "Optimize instruction size by using 32 bit immediate if value can fit to it" emitter emitX86RM: 16rC7 size: dst size regOrCode: 0 rm: dst. immSize := 4 ] ifFalse: [ emitter emitX86Inl: (immSize=1 ifTrue: [16rB0] ifFalse: [16rB8]) reg: dst ]. ^ emitter emitImmediate: src size: immSize ]. "mem <- reg" dst isMem & src isReg ifTrue: [ self assert: (src isRegTypeGPB | src isRegTypeGPW | src isRegTypeGPD | src isRegTypeGPQ ). ^ emitter emitX86RM: 16r88 + src isRegTypeGPB not asBit size: src size regOrCode: src rm: dst ]. "mem <- imm" dst isMem & src isImm ifTrue: [ | immSize | immSize := dst size <= 4 ifTrue: [ dst size ] ifFalse: [4]. emitter emitX86RM: 16rC6 + ((dst size = 1) not) asBit size: dst size regOrCode: 0 rm: dst immSize: immSize. ^ emitter emitImmediate: src size: immSize ]. self invalidInstruction ! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: 'CamilloBruni 7/17/2012 11:10'! emitx87addp: emitter operand1: op1 operand2: op2 operand3: op3 | opp | opp := op1 ifNil: [ AJx87Register new code: 1 ]. opp isRegTypeX87 ifTrue: [ emitter emitByte: (opCode1 bitAnd: 16rFF00)>>8. emitter emitByte: (opCode1 bitAnd: 16rFF) + opp index. ^ self ]. ^self emitx87sti: emitter operand1: opp operand2: op2 operand3: op3 ! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitpush: emitter operand1: op1 operand2: op2 operand3: op3 "This section is only for immediates, memory/register operands are handled in emitpop:..." op1 isImm ifTrue: [ op1 isInt8 & (op1 relocMode == #RelocNone) ifTrue: [ emitter emitByte: 16r6A. ^ emitter emitImmediate: op1 size: 1 ]. emitter emitByte: 16r68. ^ emitter emitImmediate: op1 size: 4 ]. ^ self emitpop: emitter operand1: op1 operand2: op2 operand3: op3 ! ! !AJx86InstructionDescription methodsFor: 'printing' stamp: ''! printOn: aStream aStream nextPutAll: '('; nextPutAll: name printString; space; nextPutAll: group printString; space. "print o1Flags" o1Flags > 0 ifTrue: [ aStream nextPutAll: '"op1" 2r' , (o1Flags printStringBase: 2) ] ifFalse: [ aStream nextPutAll: '0']. aStream space. "print o2Flags" o2Flags > 0 ifTrue: [ aStream nextPutAll: '"op2" 2r' , (o2Flags printStringBase: 2) ] ifFalse: [ aStream nextPutAll: '0']. aStream space. "print opCodeR" aStream nextPutAll: '"R" '. opCodeR printOn: aStream. aStream space. "print opCode1" opCode1 > 0 ifTrue: [ aStream nextPutAll: '"C1" '. aStream nextPutAll: (self printDWord: opCode1 ) ] ifFalse: [ aStream nextPutAll: '0']. aStream space. "print opCode2" opCode2 > 0 ifTrue: [ aStream nextPutAll: '"C2" '. aStream nextPutAll: (self printDWord: opCode2 ) ] ifFalse: [ aStream nextPutAll: '0']. aStream space; nextPut: $) ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! o1Flags: anObject "Set the value of o1Flags" o1Flags := anObject! ! !AJx86InstructionDescription methodsFor: 'initialize-release' stamp: ''! translateSymFlag: aflag " 64-bit mode only instruction " aflag == #x64 ifTrue: [ ^ 2r100000000 ]. " 32-bit mode only instruction " aflag == #x86 ifTrue: [ ^ 2r1000000000 ]. self error: 'unknown flag'.! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitx87fpu: emitter operand1: op1 operand2: op2 operand3: op3 "Either we are in memory, and carry out by using D8 / DC followed by modRM where reg indicates the operation" op1 isMem ifTrue: [ (op2 notNil or: [op3]) notNil ifTrue: [self error: 'Invalid arguments!!']. emitter emitByte: (opCode1 >> (32 - (op1 size* 2)) bitAnd: 16rFF). ^op1 emitModRM: emitter code: opCodeR immSize: nil]. "Or both my arguments are X87 registers, one of which is ST0. Store in op1 register." (op1 isRegTypeX87 and: [op2 isRegTypeX87]) ifTrue: [|shift offset| op1 index = 0 ifTrue: [shift := 24. offset := op2 index] ifFalse: [ op2 index = 0 ifTrue: [shift = 16. offset := op1 index] ifFalse: [self error: 'ST0 must be one of arguments']]. "D8 if Storing in ST0, DC if storing in other" emitter emitByte: (opCode1 >> shift bitAnd: 16rFF). emitter emitByte: (opCode1 >> (shift - 16) bitAnd: 16rFF) + offset ] ifFalse: [self error: 'Invalid arguments!!'] ! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: 'CamilloBruni 5/15/2012 14:18'! emitbt: emitter operand1: dst operand2: src operand3: op3 dst isRegMem ifFalse: [ self error: 'Expected register or memory but got ', dst asString ]. (dst isReg and: [ dst is8 ]) ifTrue: [ self error: '8 bit register ', dst asString, ' not supported for bit test operations']. src isReg ifTrue: [ ^ emitter emitX86RM: opCode1 size: src size regOrCode: src rm: dst ]. src isImm ifTrue: [ src isInt8 ifFalse: [ self error: 'Expected imm8 but got ', src size asString, ' immediate.' ]. emitter emitX86RM: opCode2 size: dst size regOrCode: opCodeR rm: dst immSize: 1. ^ emitter emitImmediate: src size: 1 ]. self invalidInstruction ! ! !AJx86InstructionDescription methodsFor: 'errors' stamp: ''! invalidInstruction self error: 'invalid instruction'! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitemit: emitter operand1: op1 operand2: op2 operand3: op3 ^ emitter emitOpCode: opCode1! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitxchg: emitter operand1: dst operand2: src operand3: op3 dst isRegMem & src isReg ifFalse: [ self invalidInstruction ]. emitter emitSizePrefix: src segment: dst. "Special opcode for index 0 registers (AX, EAX, RAX vs register)" dst isReg & (dst size > 1) & (dst index =0 or: [ src index = 0 ] ) ifTrue: [ | index | index := dst index + src index. ^ emitter emitByte: 16r90 + index. ]. emitter emitByte: 16r86 + src isRegTypeGPB not asBit. dst emitModRM: emitter code: src code immSize: 0! ! !AJx86InstructionDescription methodsFor: 'printing' stamp: ''! printDWord: value | str | str := value printStringBase: 16. [str size < 8] whileTrue: [ str:= '0',str ]. ^ '16r', str! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitmovsxd: emitter operand1: dst operand2: src operand3: op3 emitter is64BitMode ifFalse: [ self invalidInstruction ]. dst isReg & src isRegMem ifFalse: [ self invalidInstruction ]. emitter emitX86RM: 16r63 size: dst size regOrCode: dst rm: src! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: 'HenrikSperreJohansen 2/26/2015 14:37'! emitsmnemonic: emitter operand1: dst operand2: op2 operand3: op3 "Emit a string operation mnemonic. See self class >> # initStringOperations for details" | fauxReg| dst isRegMem ifFalse: [ ^ self invalidInstruction ]. "quick test for illegal ins/outs with 64bit-sized arg" (dst is64 and: [((opCode1 bitShift: -3) bitXor: 16rD) = 0 ]) ifTrue: [ ^ self invalidInstruction ]. "Really, movs and friends are to be called with two parameters, both of the correct size (but inconsequential location). We don't really care, so just check sizes are the same if a second operand happens to be there. It's only 'provided to allow documentation' anyways, so leave it up to user to mess that up as he sees fit" (op2 notNil and: [ dst size ~= op2 size]) ifTrue:[^self invalidInstruction]. "Create a faux register that will have operand size prefix and REX byte set appropriately, and a code of 1 if op size > 1 byte" fauxReg := AJRegister new. fauxReg code: ((dst size highBit - 1 << 4 ) bitOr:((dst size > 1) asBit)). ^ emitter emitX86Inl: opCode1 reg: fauxReg ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! group: anObject "Set the value of group" group := anObject! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitenter: emitter operand1: op1 operand2: op2 operand3: op3 (op1 isImm and: [ op2 isImm ]) ifFalse: [ self invalidInstruction ]. emitter emitByte: 16rC8. emitter emitImmediate: op1 size: 2. emitter emitImmediate: op2 size: 1. ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! opCodeR "Answer the value of opCodeR" ^ opCodeR! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitrmr: emitter operand1: dst operand2: src operand3: op3 dst isRegMem & src isReg ifFalse: [ self invalidInstruction ]. emitter emitX86RM: opCode1 + (src isRegTypeGPB not) asBit size: src size regOrCode: src rm: dst! ! !AJx86InstructionDescription methodsFor: 'emitting-dispatch' stamp: 'HenrikSperreJohansen 6/26/2014 13:39'! emitsddisambiguate: emitter operand1: op1 operand2: op2 operand3: op3 "XXXsd can be two different operations based on which operands are used; - 0 arg version is a string operation on doubleword (32bit) values - 2arg version is an SSE2/AVX mmu operation. Since mmu operations have differing emit methods, rely on the string versions being the one installed in instruction dictionary, " | correctDescription | op1 ifNil: [ "String op was correct" ^ self emitemit: emitter operand1: op1 operand2: op2 operand3: op3 ]. "Emit other instruction instead" correctDescription := self class fromArray: (self class instructionsAmbiguous detect: [ :one | one first = name ]). emitter description: correctDescription. correctDescription emitUsing: emitter operand1: op1 operand2: op2 operand3: op3! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: 'CamilloBruni 4/17/2012 17:41'! emitlea: emitter operand1: op1 operand2: op2 operand3: op3 (op1 isReg and: [ op2 isMem ]) ifFalse: [ self error: 'LEA: Expected Reg and Mem but got ', op1 asString, ' and ', op2 asString ]. emitter emitX86RM: 16r8D size: op1 size regOrCode: op1 rm: op2! ! !AJx86InstructionDescription methodsFor: 'emitting - mmu' stamp: ''! emitmmuMovQ: emitter operand1: op1 operand2: op2 operand3: op3 self shouldBeImplemented! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: 'CamilloBruni 7/23/2012 15:21'! emitx87sti: emitter operand1: op1 operand2: op2 operand3: op3 (op1 isNil and: [ op2 isNil and: [ op3 isNil ]]) ifTrue: [ "Convenience fallback for ST1 " ^ self emitx87sti: emitter operand1: AJx86Registers ST1 operand2: nil operand3: nil ]. op1 isRegTypeX87 ifTrue: [ emitter emitByte: (opCode1 bitAnd: 16rFF00)>>8. emitter emitByte: (opCode1 bitAnd: 16rFF) + op1 index. ^ self ]. self invalidInstruction! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: 'CamilloBruni 4/25/2012 15:15'! emitpop: emitter operand1: op1 operand2: op2 operand3: op3 op1 isReg ifTrue: [ (op1 isRegTypeGPW | (emitter isGPNRegister: op1)) ifFalse: [ self error: 'Invalid register given: ', op1 asString]. ^ emitter emitX86Inl: opCode1 reg: op1. ]. op1 isMem ifFalse: [ self invalidInstruction ]. emitter emitX86RM: opCode2 size: op1 size regOrCode: opCodeR rm: op1 ! ! !AJx86InstructionDescription methodsFor: 'emitting' stamp: ''! emitincdec: emitter operand1: dst operand2: op2 operand3: op3 dst isRegMem ifFalse: [ ^ self invalidInstruction ]. "INC [r16|r32] in 64 bit mode is not encodable." emitter is32BitMode ifTrue: [ (dst isReg & dst isRegTypeGPW & dst isRegTypeGPD) ifTrue: [ ^ emitter emitX86Inl: opCode1 reg: dst ]]. emitter emitX86RM: opCode2 + (dst size ~= 1) asBit size: dst size regOrCode: opCodeR rm: dst ! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! opCode1 "Answer the value of opCode1" ^ opCode1! ! !AJx86InstructionDescription methodsFor: 'testing' stamp: ''! isJump ^ group == #cjmp or: [ group == #jmp ]! ! !AJx86InstructionDescription methodsFor: 'emitting - mmu' stamp: ''! emitmmuRmImm8: emitter operand1: op1 operand2: op2 operand3: op3 self shouldBeImplemented! ! !AJx86InstructionDescription methodsFor: 'accessing' stamp: ''! opCode2 "Answer the value of opCode2" ^ opCode2! ! !AJx86InstructionDescription class methodsFor: 'initialization' stamp: 'HenrikSperreJohansen 6/26/2014 02:37'! initInstructions " self initInstructions " | data | instructions := IdentityDictionary new. data := OrderedCollection new. data addAll: self instructionData; addAll: self instructionsCDQ; addAll: self instructionsStrings; addAll: self instructionsOther. data do: [:dt | instructions at: dt first put: (self fromArray: dt) ]. ^ instructions! ! !AJx86InstructionDescription class methodsFor: 'initialization' stamp: 'HenrikSperreJohansen 6/26/2014 03:14'! instructionsOther ^ #()! ! !AJx86InstructionDescription class methodsFor: 'printing' stamp: ''! printInstructionsOn: aStream " AJInstructionDescription printInstructionsOn: (FileStream newFileNamed: 'asm.st'). " aStream nextPutAll: '#(' ; cr. self instructions keys asSortedCollection do: [:aname | | instr | instr := instructions at: aname. instr printOn: aStream. aStream cr. ]. aStream cr; nextPut: $); cr ! ! !AJx86InstructionDescription class methodsFor: 'printing' stamp: ''! printInstructions " AJInstructionDescription printInstructions. AJInstructionDescription printInstructions openInWorkspaceWithTitle: 'x86 instructions' " ^ String streamContents: [:str | self printInstructionsOn: str ] ! ! !AJx86InstructionDescription class methodsFor: 'accessing' stamp: ''! instructions ^ instructions ifNil: [ self initInstructions ]! ! !AJx86InstructionDescription class methodsFor: 'initialization' stamp: ''! initialize self initInstructions.! ! !AJx86InstructionDescription class methodsFor: 'initialization' stamp: 'HenrikSperreJohansen 6/26/2014 13:38'! instructionsStrings "String operations, often used in conjunction with rep prefix for efficient batch operations" "General note: - Memory locations written X / Y means X unless prefixed by address-size override (16r67), in that case Y." ^ #( "Repeat prefixes, only to be used with string operations (Could be nice to create group emitPrefix, and build a stack of applied prefixes which can be checked for validity with next op)" "When used, repeat string operation max (E)CX times or until condition met" (#repne #emit 0 0 "R" 0 "C1" 16r000000F2 0 ) (#repnz #emit 0 0 "R" 0 "C1" 16r000000F2 0 ) (#rep #emit 0 0 "R" 0 "C1" 16r000000F3 0 ) (#repe #emit 0 0 "R" 0 "C1" 16r000000F3 0 ) (#repz #emit 0 0 "R" 0 "C1" 16r000000F3 0 ) "Direction flag setters, only used by string ops" (#cld #emit 0 0 "R" 0 "C1" 16r000000FC 0 ) "DF := 0, string ops increment addresses" (#std #emit 0 0 "R" 0 "C1" 16r000000FD 0 ) "DF := 1, string ops decrement addresses" "String input: In 32-bit mode, input byte/word/doubleword from i/o port specified in DX to address in ES:EDI / ES:DI. In 64-bit mode, input byte/word/doubleword, from i/o port specified in DX to address in RDI / EDI" (#ins #smnemonic 0 0 "R" 0 "C1" 16r0000006C 0 ) "mnemonic, arg size determines actual prefixes/op" (#insb #emit 0 0 "R" 0 "C1" 16r0000006C 0 ) "8 bit" (#insw #emit 0 0 "R" 0 "C1" 16r6600006D 0 ) "16 bit" "Mandatory Operand override prefix (16r66) in 32/64bit mode" (#insd #emit 0 0 "R" 0 "C1" 16r0000006D 0 ) "32 bit" "(#insq #emit #x64 0 0 16r4800006D 0 ) 64bit version does not exist according to intel IS reference" "String output: In 32-bit mode output byte/word/doubleword at address in DS:ESI / DS:SI to io port specified in DX. In 64-bit mode, output byte/word/doubleword, at address in RSI/ESI to io port specified in DX " (#outs #smnemonic 0 0 "R" 0 "C1" 16r0000006E 0 ) "mnemonic, arg size determines actual prefixes/op" (#outsb #emit 0 0 "R" 0 "C1" 16r0000006E 0 ) "8 bit" (#outsw #emit 0 0 "R" 0 "C1" 16r6600006F 0 ) "16 bit" "Mandatory Operand override prefix (16r66) in 32/64bit mode" (#outsd #emit 0 0 "R" 0 "C1" 16r0000006F 0 ) "32 bit" "(#outsq #emit #x64 0 0 16r4800006F 0 ) 64bit version does not exist according to intel IS reference" "String move: In 32-bit mode move byte/word/doubleword at address in DS:ESI / DS:SI to address in ES:EDI / ES:DI. In 64-bit mode move byte/word/doubleword/quadword at address in from RSI / ESI to address in RDI / EDI." (#movs #smnemonic 0 0 "R" 0 "C1" 16r000000A4 0 ) "mnemonic, arg sizes determines actual prefixes/op" (#movsb #emit 0 0 "R" 0 "C1" 16r000000A4 0 ) "8 bit" (#movsw #emit 0 0 "R" 0 "C1" 16r660000A5 0 ) "16 bit" "Mandatory Operand override prefix (16r66) in 32/64bit mode" (#movsd #sddisambiguate 0 0 "R" 0 "C1" 16r000000A5 0 ) "32 bit" (#movsq #emit #x64 0 "R" 0 "C1" 16r480000A5 0 ) "64bit, in 64-bit mode only. Naughtily embed required REX.W prefix" "String compare: In 32-bit mode compare byte/word/doubleword at address in DS:ESI / DS:SI to same at address in ES:EDI / ES:DI. In 64-bit mode compare byte/word/doubleword/quadword at address in RSI / ESI to same at address in RDI / EDI." (#cmps #smnemonic 0 0 "R" 0 "C1" 16r000000A6 0 ) "mnemonic, arg sizes determines actual prefixes/op" (#cmpsb #emit 0 0 "R" 0 "C1" 16r000000A6 0 ) "8 bit" (#cmpsw #emit 0 0 "R" 0 "C1" 16r660000A7 0 ) "16 bit" "Mandatory Operand override prefix (16r66) in 32/64bit mode" (#cmpsd #sddisambiguate 0 0 "R" 0 "C1" 16r000000A7 0 ) "32 bit" (#cmpsq #emit #x64 0 "R" 0 "C1" 16r480000A7 0 ) "64bit, in 64-bit mode only. Naughtily embed required REX.W prefix" "String store: In 32-bit mode store AL/AX/EAX at address in ES:EDI / ES:DI In 64-bit mode store AL/AX/EAX/RAX to RDI / EDI " (#stos #smnemonic 0 0 "R" 0 "C1" 16r000000AA 0 ) "mnemonic, arg sizes determines actual prefixes/op" (#stosb #emit 0 0 "R" 0 "C1" 16r000000AA 0 ) "8bit" (#stosw #emit 0 0 "R" 0 "C1" 16r660000AB 0 ) "16bit" "Mandatory Operand override prefix (16r66) in 32/64bit mode" (#stosd #emit 0 0 "R" 0 "C1" 16r000000AB 0 ) "32bit" (#stosq #emit #x64 0 "R" 0 "C1" 16r480000AB 0 ) "64bit, in 64-bit mode only. Naughtily embed required REX.W prefix" "String load: In 32-bit mode load byte/word/doubleword from address in ES:EDI / ES:DI to AL/AX/ EAX In 64-bit mode load byte/word/doubleword/quadword from address in RDI / EDI to AX / EAX / RAX" (#lods #smnemonic 0 0 "R" 0 "C1" 16r000000AC 0 ) "mnemonic, arg sizes determines actual prefixes/op" (#lodsb #emit 0 0 "R" 0 "C1" 16r000000AC 0 ) "8bit" (#lodsw #emit 0 0 "R" 0 "C1" 16r660000AD 0 ) "16bit" "Mandatory Operand override prefix (16r66) in 32/64bit mode" (#lodsd #emit 0 0 "R" 0 "C1" 16r000000AD 0 ) "32bit" (#lodsq #emit #x64 0 "R" 0 "C1" 16r480000AD 0 ) "64bit, in 64-bit mode only. Naughtily embed required REX.W prefix" "String scan: In 32-bit mode compare AL/AX/EAX L with ES:EDI / ES:DI In 64-bit mode compare AL/AX/EAX/RAX with RDI / EDI" (#scas #smnemonic 0 0 "R" 0 "C1" 16r000000AE 0 ) "mnemonic, arg sizes determines actual op" (#scasb #emit 0 0 "R" 0 "C1" 16r000000AE 0 ) "8bit" (#scasw #emit 0 0 "R" 0 "C1" 16r660000AF 0 ) "16bit" "Mandatory Operand override prefix (16r66) in 32/64bit mode" (#scasd #emit 0 0 "R" 0 "C1" 16r000000AF 0 ) "32bit" (#scasq #emit #x64 0 "R" 0 "C1" 16r480000AF 0 ) "64bit, in 64-bit mode only. Naughtily embed required REX.W prefix" )! ! !AJx86InstructionDescription class methodsFor: 'initialization' stamp: 'CamilloBruni 4/17/2012 17:39'! at: instructionName ^ instructions at: instructionName ! ! !AJx86InstructionDescription class methodsFor: 'initialization' stamp: 'HenrikSperreJohansen 6/26/2014 11:47'! instructionData ^ #( (#adc #alu 0 0 "R" 2 "C1" 16r00000010 "C2" 16r00000080 ) (#add #alu 0 0 "R" 0 0 "C2" 16r00000080 ) (#addpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F58 0 ) (#addps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F58 0 ) (#addsd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F58 0 ) (#addss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F58 0 ) (#addsubpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000FD0 0 ) (#addsubps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000FD0 0 ) (#amdprefetch #mem "op1" 2r1000000 0 "R" 0 "C1" 16r00000F0D 0 ) (#amdprefetchw #mem "op1" 2r1000000 0 "R" 1 "C1" 16r00000F0D 0 ) (#and #alu 0 0 "R" 4 "C1" 16r00000020 "C2" 16r00000080 ) (#andnpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F55 0 ) (#andnps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F55 0 ) (#andpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F54 0 ) (#andps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F54 0 ) (#blendpd #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A0D 0 ) (#blendps #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A0C 0 ) (#blendvpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3815 0 ) (#blendvps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3814 0 ) (#bsf #rrm 0 0 "R" 0 "C1" 16r00000FBC 0 ) (#bsr #rrm 0 0 "R" 0 "C1" 16r00000FBD 0 ) (#bswap #bswap 0 0 "R" 0 0 0 ) (#bt #bt "op1" 2r1001110 "op2" 2r10001110 "R" 4 "C1" 16r00000FA3 "C2" 16r00000FBA ) (#btc #bt "op1" 2r1001110 "op2" 2r10001110 "R" 7 "C1" 16r00000FBB "C2" 16r00000FBA ) (#btr #bt "op1" 2r1001110 "op2" 2r10001110 "R" 6 "C1" 16r00000FB3 "C2" 16r00000FBA ) (#bts #bt "op1" 2r1001110 "op2" 2r10001110 "R" 5 "C1" 16r00000FAB "C2" 16r00000FBA ) (#call #call 0 0 "R" 0 0 0 ) (#clc #emit 0 0 "R" 0 "C1" 16r000000F8 0 ) (#clflush #mem "op1" 2r1000000 0 "R" 7 "C1" 16r00000FAE 0 ) (#cmc #emit 0 0 "R" 0 "C1" 16r000000F5 0 ) (#cmova #rrm 0 0 "R" 0 "C1" 16r00000F47 0 ) (#cmovae #rrm 0 0 "R" 0 "C1" 16r00000F43 0 ) (#cmovb #rrm 0 0 "R" 0 "C1" 16r00000F42 0 ) (#cmovbe #rrm 0 0 "R" 0 "C1" 16r00000F46 0 ) (#cmovc #rrm 0 0 "R" 0 "C1" 16r00000F42 0 ) (#cmove #rrm 0 0 "R" 0 "C1" 16r00000F44 0 ) (#cmovg #rrm 0 0 "R" 0 "C1" 16r00000F4F 0 ) (#cmovge #rrm 0 0 "R" 0 "C1" 16r00000F4D 0 ) (#cmovl #rrm 0 0 "R" 0 "C1" 16r00000F4C 0 ) (#cmovle #rrm 0 0 "R" 0 "C1" 16r00000F4E 0 ) (#cmovna #rrm 0 0 "R" 0 "C1" 16r00000F46 0 ) (#cmovnae #rrm 0 0 "R" 0 "C1" 16r00000F42 0 ) (#cmovnb #rrm 0 0 "R" 0 "C1" 16r00000F43 0 ) (#cmovnbe #rrm 0 0 "R" 0 "C1" 16r00000F47 0 ) (#cmovnc #rrm 0 0 "R" 0 "C1" 16r00000F43 0 ) (#cmovne #rrm 0 0 "R" 0 "C1" 16r00000F45 0 ) (#cmovng #rrm 0 0 "R" 0 "C1" 16r00000F4E 0 ) (#cmovnge #rrm 0 0 "R" 0 "C1" 16r00000F4C 0 ) (#cmovnl #rrm 0 0 "R" 0 "C1" 16r00000F4D 0 ) (#cmovnle #rrm 0 0 "R" 0 "C1" 16r00000F4F 0 ) (#cmovno #rrm 0 0 "R" 0 "C1" 16r00000F41 0 ) (#cmovnp #rrm 0 0 "R" 0 "C1" 16r00000F4B 0 ) (#cmovns #rrm 0 0 "R" 0 "C1" 16r00000F49 0 ) (#cmovnz #rrm 0 0 "R" 0 "C1" 16r00000F45 0 ) (#cmovo #rrm 0 0 "R" 0 "C1" 16r00000F40 0 ) (#cmovp #rrm 0 0 "R" 0 "C1" 16r00000F4A 0 ) (#cmovpe #rrm 0 0 "R" 0 "C1" 16r00000F4A 0 ) (#cmovpo #rrm 0 0 "R" 0 "C1" 16r00000F4B 0 ) (#cmovs #rrm 0 0 "R" 0 "C1" 16r00000F48 0 ) (#cmovz #rrm 0 0 "R" 0 "C1" 16r00000F44 0 ) (#cmp #alu 0 0 "R" 7 "C1" 16r00000038 "C2" 16r00000080 ) (#cmppd #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000FC2 0 ) (#cmpps #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000FC2 0 ) (#cmpsd #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000FC2 0 ) (#cmpss #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000FC2 0 ) (#cmpxchg #rmr 0 0 "R" 0 "C1" 16r00000FB0 0 ) (#cmpxchg16b #mem "op1" 2r1000000 0 "R" 1 "C1" 16r00000FC7 "C2" 16r00000001 ) (#cmpxchg8b #mem "op1" 2r1000000 0 "R" 1 "C1" 16r00000FC7 0 ) (#comisd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F2F 0 ) (#comiss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F2F 0 ) (#cpuid #emit 0 0 "R" 0 "C1" 16r00000FA2 0 ) (#crc32 #crc32 0 0 "R" 0 "C1" 16rF20F38F0 0 ) (#cvtdq2pd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000FE6 0 ) (#cvtdq2ps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F5B 0 ) (#cvtpd2dq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000FE6 0 ) (#cvtpd2pi #mmurmi "op1" 2r10000 "op2" 2r1100000 "R" 0 "C1" 16r66000F2D 0 ) (#cvtpd2ps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F5A 0 ) (#cvtpi2pd #mmurmi "op1" 2r100000 "op2" 2r1010000 "R" 0 "C1" 16r66000F2A 0 ) (#cvtpi2ps #mmurmi "op1" 2r100000 "op2" 2r1010000 "R" 0 "C1" 16r00000F2A 0 ) (#cvtps2dq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F5B 0 ) (#cvtps2pd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F5A 0 ) (#cvtps2pi #mmurmi "op1" 2r10000 "op2" 2r1100000 "R" 0 "C1" 16r00000F2D 0 ) (#cvtsd2si #mmurmi "op1" 2r1100 "op2" 2r1100000 "R" 0 "C1" 16rF2000F2D 0 ) (#cvtsd2ss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F5A 0 ) (#cvtsi2sd #mmurmi "op1" 2r100000 "op2" 2r1001100 "R" 0 "C1" 16rF2000F2A 0 ) (#cvtsi2ss #mmurmi "op1" 2r100000 "op2" 2r1001100 "R" 0 "C1" 16rF3000F2A 0 ) (#cvtss2sd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F5A 0 ) (#cvtss2si #mmurmi "op1" 2r1100 "op2" 2r1100000 "R" 0 "C1" 16rF3000F2D 0 ) (#cvttpd2dq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000FE6 0 ) (#cvttpd2pi #mmurmi "op1" 2r10000 "op2" 2r1100000 "R" 0 "C1" 16r66000F2C 0 ) (#cvttps2dq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F5B 0 ) (#cvttps2pi #mmurmi "op1" 2r10000 "op2" 2r1100000 "R" 0 "C1" 16r00000F2C 0 ) (#cvttsd2si #mmurmi "op1" 2r1100 "op2" 2r1100000 "R" 0 "C1" 16rF2000F2C 0 ) (#cvttss2si #mmurmi "op1" 2r1100 "op2" 2r1100000 "R" 0 "C1" 16rF3000F2C 0 ) (#daa #emit #x86 0 "R" 0 "C1" 16r00000027 0 ) (#das #emit #x86 0 "R" 0 "C1" 16r0000002F 0 ) (#dec #incdec 0 0 "R" 1 "C1" 16r00000048 "C2" 16r000000FE ) (#div #rm 0 0 "R" 6 "C1" 16r000000F6 0 ) (#divpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F5E 0 ) (#divps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F5E 0 ) (#divsd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F5E 0 ) (#divss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F5E 0 ) (#dppd #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A41 0 ) (#dpps #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A40 0 ) (#emms #emit 0 0 "R" 0 "C1" 16r00000F77 0 ) (#enter #enter 0 0 "R" 0 "C1" 16r000000C8 0 ) (#extractps #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A17 0 ) (#f2xm1 #emit 0 0 "R" 0 "C1" 16r0000D9F0 0 ) (#fabs #emit 0 0 "R" 0 "C1" 16r0000D9E1 0 ) (#fadd #x87fpu 0 0 "R" 0 "C1" 16rD8DCC0C0 0 ) (#faddp #x87sti 0 0 "R" 0 "C1" 16r0000DEC0 0 ) (#fbld #mem "op1" 2r1000000 0 "R" 4 "C1" 16r000000DF 0 ) (#fbstp #mem "op1" 2r1000000 0 "R" 6 "C1" 16r000000DF 0 ) (#fchs #emit 0 0 "R" 0 "C1" 16r0000D9E0 0 ) (#fclex #emit 0 0 "R" 0 "C1" 16r9B00DBE2 0 ) (#fcmovb #x87sti 0 0 "R" 0 "C1" 16r0000DAC0 0 ) (#fcmovbe #x87sti 0 0 "R" 0 "C1" 16r0000DAD0 0 ) (#fcmove #x87sti 0 0 "R" 0 "C1" 16r0000DAC8 0 ) (#fcmovnb #x87sti 0 0 "R" 0 "C1" 16r0000DBC0 0 ) (#fcmovnbe #x87sti 0 0 "R" 0 "C1" 16r0000DBD0 0 ) (#fcmovne #x87sti 0 0 "R" 0 "C1" 16r0000DBC8 0 ) (#fcmovnu #x87sti 0 0 "R" 0 "C1" 16r0000DBD8 0 ) (#fcmovu #x87sti 0 0 "R" 0 "C1" 16r0000DAD8 0 ) (#fcom #x87fpu 0 0 "R" 2 "C1" 16rD8DCD0D0 0 ) (#fcomi #x87sti 0 0 "R" 0 "C1" 16r0000DBF0 0 ) (#fcomip #x87sti 0 0 "R" 0 "C1" 16r0000DFF0 0 ) (#fcomp #x87fpu 0 0 "R" 3 "C1" 16rD8DCD8D8 0 ) (#fcompp #emit 0 0 "R" 0 "C1" 16r0000DED9 0 ) (#fcos #emit 0 0 "R" 0 "C1" 16r0000D9FF 0 ) (#fdecstp #emit 0 0 "R" 0 "C1" 16r0000D9F6 0 ) (#fdiv #x87fpu 0 0 "R" 6 "C1" 16rD8DCF0F8 0 ) (#fdivp #x87sti 0 0 "R" 0 "C1" 16r0000DEF8 0 ) (#fdivr #x87fpu 0 0 "R" 7 "C1" 16rD8DCF8F0 0 ) (#fdivrp #x87sti 0 0 "R" 0 "C1" 16r0000DEF0 0 ) (#ffree #x87sti 0 0 "R" 0 "C1" 16r0000DDC0 0 ) (#fiadd #x87mem "op1" 2r110 0 "R" 0 "C1" 16rDEDA0000 0 ) (#ficom #x87mem "op1" 2r110 0 "R" 2 "C1" 16rDEDA0000 0 ) (#ficomp #x87mem "op1" 2r110 0 "R" 3 "C1" 16rDEDA0000 0 ) (#fidiv #x87mem "op1" 2r110 0 "R" 6 "C1" 16rDEDA0000 0 ) (#fidivr #x87mem "op1" 2r110 0 "R" 7 "C1" 16rDEDA0000 0 ) (#fild #x87mem "op1" 2r1110 0 "R" 0 "C1" 16rDFDBDF05 0 ) (#fimul #x87mem "op1" 2r110 0 "R" 1 "C1" 16rDEDA0000 0 ) (#fincstp #emit 0 0 "R" 0 "C1" 16r0000D9F7 0 ) (#finit #emit 0 0 "R" 0 "C1" 16r9B00DBE3 0 ) (#fist #x87mem "op1" 2r110 0 "R" 2 "C1" 16rDFDB0000 0 ) (#fistp #x87mem "op1" 2r1110 0 "R" 3 "C1" 16rDFDBDF07 0 ) (#fisttp #x87mem "op1" 2r1110 0 "R" 1 "C1" 16rDFDBDD01 0 ) (#fisub #x87mem "op1" 2r110 0 "R" 4 "C1" 16rDEDA0000 0 ) (#fisubr #x87mem "op1" 2r110 0 "R" 5 "C1" 16rDEDA0000 0 ) (#fld #x87memSti "op1" 2r11100 0 "R" 0 "C1" 16r00D9DD00 "C2" 16rD9C0DB05 ) (#fld1 #emit 0 0 "R" 0 "C1" 16r0000D9E8 0 ) (#fldcw #mem "op1" 2r1000000 0 "R" 5 "C1" 16r000000D9 0 ) (#fldenv #mem "op1" 2r1000000 0 "R" 4 "C1" 16r000000D9 0 ) (#fldl2e #emit 0 0 "R" 0 "C1" 16r0000D9EA 0 ) (#fldl2t #emit 0 0 "R" 0 "C1" 16r0000D9E9 0 ) (#fldlg2 #emit 0 0 "R" 0 "C1" 16r0000D9EC 0 ) (#fldln2 #emit 0 0 "R" 0 "C1" 16r0000D9ED 0 ) (#fldpi #emit 0 0 "R" 0 "C1" 16r0000D9EB 0 ) (#fldz #emit 0 0 "R" 0 "C1" 16r0000D9EE 0 ) (#fmul #x87fpu 0 0 "R" 1 "C1" 16rD8DCC8C8 0 ) (#fmulp #x87sti 0 0 "R" 0 "C1" 16r0000DEC8 0 ) (#fnclex #emit 0 0 "R" 0 "C1" 16r0000DBE2 0 ) (#fninit #emit 0 0 "R" 0 "C1" 16r0000DBE3 0 ) (#fnop #emit 0 0 "R" 0 "C1" 16r0000D9D0 0 ) (#fnsave #mem "op1" 2r1000000 0 "R" 6 "C1" 16r000000DD 0 ) (#fnstcw #mem "op1" 2r1000000 0 "R" 7 "C1" 16r000000D9 0 ) (#fnstenv #mem "op1" 2r1000000 0 "R" 6 "C1" 16r000000D9 0 ) (#fnstsw #x87fstsw "op1" 2r1000000 0 "R" 7 "C1" 16r000000DD "C2" 16r0000DFE0 ) (#fpatan #emit 0 0 "R" 0 "C1" 16r0000D9F3 0 ) (#fprem #emit 0 0 "R" 0 "C1" 16r0000D9F8 0 ) (#fprem1 #emit 0 0 "R" 0 "C1" 16r0000D9F5 0 ) (#fptan #emit 0 0 "R" 0 "C1" 16r0000D9F2 0 ) (#frndint #emit 0 0 "R" 0 "C1" 16r0000D9FC 0 ) (#frstor #mem "op1" 2r1000000 0 "R" 4 "C1" 16r000000DD 0 ) (#fsave #mem "op1" 2r1000000 0 "R" 6 "C1" 16r9B0000DD 0 ) (#fscale #emit 0 0 "R" 0 "C1" 16r0000D9FD 0 ) (#fsin #emit 0 0 "R" 0 "C1" 16r0000D9FE 0 ) (#fsincos #emit 0 0 "R" 0 "C1" 16r0000D9FB 0 ) (#fsqrt #emit 0 0 "R" 0 "C1" 16r0000D9FA 0 ) (#fst #x87memSti "op1" 2r1100 0 "R" 2 "C1" 16r00D9DD02 "C2" 16rDDD00000 ) (#fstcw #mem "op1" 2r1000000 0 "R" 7 "C1" 16r9B0000D9 0 ) (#fstenv #mem "op1" 2r1000000 0 "R" 6 "C1" 16r9B0000D9 0 ) (#fstp #x87memSti "op1" 2r11100 0 "R" 3 "C1" 16r00D9DD03 "C2" 16rDDD8DB07 ) (#fstsw #x87fstsw "op1" 2r1000000 0 "R" 7 "C1" 16r9B0000DD "C2" 16r9B00DFE0 ) (#fsub #x87fpu 0 0 "R" 4 "C1" 16rD8DCE0E8 0 ) (#fsubp #x87sti 0 0 "R" 0 "C1" 16r0000DEE8 0 ) (#fsubr #x87fpu 0 0 "R" 5 "C1" 16rD8DCE8E0 0 ) (#fsubrp #x87sti 0 0 "R" 0 "C1" 16r0000DEE0 0 ) (#ftst #emit 0 0 "R" 0 "C1" 16r0000D9E4 0 ) (#fucom #x87sti 0 0 "R" 0 "C1" 16r0000DDE0 0 ) (#fucomi #x87sti 0 0 "R" 0 "C1" 16r0000DBE8 0 ) (#fucomip #x87sti 0 0 "R" 0 "C1" 16r0000DFE8 0 ) (#fucomp #x87sti 0 0 "R" 0 "C1" 16r0000DDE8 0 ) (#fucompp #emit 0 0 "R" 0 "C1" 16r0000DAE9 0 ) (#fwait #emit 0 0 "R" 0 "C1" 16r0000009B 0 ) (#fxam #emit 0 0 "R" 0 "C1" 16r0000D9E5 0 ) (#fxch #x87sti 0 0 "R" 0 "C1" 16r0000D9C8 0 ) (#fxrstor #mem 0 0 "R" 1 "C1" 16r00000FAE 0 ) (#fxsave #mem 0 0 "R" 0 "C1" 16r00000FAE 0 ) (#fxtract #emit 0 0 "R" 0 "C1" 16r0000D9F4 0 ) (#fyl2x #emit 0 0 "R" 0 "C1" 16r0000D9F1 0 ) (#fyl2xp1 #emit 0 0 "R" 0 "C1" 16r0000D9F9 0 ) (#haddpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F7C 0 ) (#haddps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F7C 0 ) (#hsubpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F7D 0 ) (#hsubps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F7D 0 ) (#idiv #rm 0 0 "R" 7 "C1" 16r000000F6 0 ) (#imul #imul 0 0 "R" 0 0 0 ) (#inc #incdec 0 0 "R" 0 "C1" 16r00000040 "C2" 16r000000FE ) (#int3 #emit 0 0 "R" 0 "C1" 16r000000CC 0 ) (#ja #cjmp 0 0 "R" 0 "C1" 16r00000007 0 ) (#jae #cjmp 0 0 "R" 0 "C1" 16r00000003 0 ) (#jb #cjmp 0 0 "R" 0 "C1" 16r00000002 0 ) (#jbe #cjmp 0 0 "R" 0 "C1" 16r00000006 0 ) (#jc #cjmp 0 0 "R" 0 "C1" 16r00000002 0 ) (#je #cjmp 0 0 "R" 0 "C1" 16r00000004 0 ) (#jg #cjmp 0 0 "R" 0 "C1" 16r0000000F 0 ) (#jge #cjmp 0 0 "R" 0 "C1" 16r0000000D 0 ) (#jl #cjmp 0 0 "R" 0 "C1" 16r0000000C 0 ) (#jle #cjmp 0 0 "R" 0 "C1" 16r0000000E 0 ) (#jmp #jmp 0 0 "R" 0 0 0 ) (#jna #cjmp 0 0 "R" 0 "C1" 16r00000006 0 ) (#jnae #cjmp 0 0 "R" 0 "C1" 16r00000002 0 ) (#jnb #cjmp 0 0 "R" 0 "C1" 16r00000003 0 ) (#jnbe #cjmp 0 0 "R" 0 "C1" 16r00000007 0 ) (#jnc #cjmp 0 0 "R" 0 "C1" 16r00000003 0 ) (#jne #cjmp 0 0 "R" 0 "C1" 16r00000005 0 ) (#jng #cjmp 0 0 "R" 0 "C1" 16r0000000E 0 ) (#jnge #cjmp 0 0 "R" 0 "C1" 16r0000000C 0 ) (#jnl #cjmp 0 0 "R" 0 "C1" 16r0000000D 0 ) (#jnle #cjmp 0 0 "R" 0 "C1" 16r0000000F 0 ) (#jno #cjmp 0 0 "R" 0 "C1" 16r00000001 0 ) (#jnp #cjmp 0 0 "R" 0 "C1" 16r0000000B 0 ) (#jns #cjmp 0 0 "R" 0 "C1" 16r00000009 0 ) (#jnz #cjmp 0 0 "R" 0 "C1" 16r00000005 0 ) (#jo #cjmp 0 0 "R" 0 0 0 ) (#jp #cjmp 0 0 "R" 0 "C1" 16r0000000A 0 ) (#jpe #cjmp 0 0 "R" 0 "C1" 16r0000000A 0 ) (#jpo #cjmp 0 0 "R" 0 "C1" 16r0000000B 0 ) (#js #cjmp 0 0 "R" 0 "C1" 16r00000008 0 ) (#jz #cjmp 0 0 "R" 0 "C1" 16r00000004 0 ) (#lddqu #mmurmi "op1" 2r100000 "op2" 2r1000000 "R" 0 "C1" 16rF2000FF0 0 ) (#ldmxcsr #mem "op1" 2r1000000 0 "R" 2 "C1" 16r00000FAE 0 ) (#lea #lea 0 0 "R" 0 0 0 ) (#leave #emit 0 0 "R" 0 "C1" 16r000000C9 0 ) (#lfence #emit 0 0 "R" 0 "C1" 16r000FAEE8 0 ) (#lock #emit 0 0 "R" 0 "C1" 16r000000F0 0 ) (#maskmovdqu #mmurmi "op1" 2r100000 "op2" 2r100000 "R" 0 "C1" 16r66000F57 0 ) (#maskmovq #mmurmi "op1" 2r10000 "op2" 2r10000 "R" 0 "C1" 16r00000FF7 0 ) (#maxpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F5F 0 ) (#maxps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F5F 0 ) (#maxsd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F5F 0 ) (#maxss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F5F 0 ) (#mfence #emit 0 0 "R" 0 "C1" 16r000FAEF0 0 ) (#minpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F5D 0 ) (#minps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F5D 0 ) (#minsd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F5D 0 ) (#minss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F5D 0 ) (#monitor #emit 0 0 "R" 0 "C1" 16r000F01C8 0 ) (#mov #mov 0 0 "R" 0 0 0 ) (#movPtr #movPtr 0 0 "R" 0 0 0 ) (#movapd #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F28 "C2" 16r66000F29 ) (#movaps #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F28 "C2" 16r00000F29 ) (#movbe #movbe "op1" 2r1001110 "op2" 2r1001110 "R" 0 "C1" 16r000F38F0 "C2" 16r000F38F1 ) (#movd #mmuMovD 0 0 "R" 0 0 0 ) (#movddup #mmuMov "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F12 0 ) (#movdq2q #mmuMov "op1" 2r10000 "op2" 2r100000 "R" 0 "C1" 16rF2000FD6 0 ) (#movdqa #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F6F "C2" 16r66000F7F ) (#movdqu #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F6F "C2" 16rF3000F7F ) (#movhlps #mmuMov "op1" 2r100000 "op2" 2r100000 "R" 0 "C1" 16r00000F12 0 ) (#movhpd #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F16 "C2" 16r66000F17 ) (#movhps #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F16 "C2" 16r00000F17 ) (#movlhps #mmuMov "op1" 2r100000 "op2" 2r100000 "R" 0 "C1" 16r00000F16 0 ) (#movlpd #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F12 "C2" 16r66000F13 ) (#movlps #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F12 "C2" 16r00000F13 ) (#movmskpd #mmuMov "op1" 2r1101 "op2" 2r100000 "R" 0 "C1" 16r66000F50 0 ) (#movmskps #mmuMov "op1" 2r1101 "op2" 2r100000 "R" 0 "C1" 16r00000F50 0 ) (#movntdq #mmuMov "op1" 2r1000000 "op2" 2r100000 "R" 0 0 "C2" 16r66000FE7 ) (#movntdqa #mmuMov "op1" 2r100000 "op2" 2r1000000 "R" 0 "C1" 16r660F382A 0 ) (#movnti #mmuMov "op1" 2r1000000 "op2" 2r1100 "R" 0 0 "C2" 16r00000FC3 ) (#movntpd #mmuMov "op1" 2r1000000 "op2" 2r100000 "R" 0 0 "C2" 16r66000F2B ) (#movntps #mmuMov "op1" 2r1000000 "op2" 2r100000 "R" 0 0 "C2" 16r00000F2B ) (#movntq #mmuMov "op1" 2r1000000 "op2" 2r10000 "R" 0 0 "C2" 16r00000FE7 ) (#movq #mmuMovQ 0 0 "R" 0 0 0 ) (#movq2dq #mmurmi "op1" 2r100000 "op2" 2r10000 "R" 0 "C1" 16rF3000FD6 0 ) (#movsd #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F10 "C2" 16rF2000F11 ) (#movshdup #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F16 0 ) (#movsldup #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F12 0 ) (#movss #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F10 "C2" 16rF3000F11 ) (#movsx #movSxZx 0 0 "R" 0 "C1" 16r00000FBE 0 ) (#movsxd #movsxd 0 0 "R" 0 0 0 ) (#movupd #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F10 "C2" 16r66000F11 ) (#movups #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F10 "C2" 16r00000F11 ) (#movzx #movSxZx 0 0 "R" 0 "C1" 16r00000FB6 0 ) (#mpsadbw #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A42 0 ) (#mul #rm 0 0 "R" 4 "C1" 16r000000F6 0 ) (#mulpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F59 0 ) (#mulps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F59 0 ) (#mulsd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F59 0 ) (#mulss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F59 0 ) (#mwait #emit 0 0 "R" 0 "C1" 16r000F01C9 0 ) (#neg #rm 0 0 "R" 3 "C1" 16r000000F6 0 ) (#nop #emit 0 0 "R" 0 "C1" 16r00000090 0 ) (#not #rm 0 0 "R" 2 "C1" 16r000000F6 0 ) (#or #alu 0 0 "R" 1 "C1" 16r00000008 "C2" 16r00000080 ) (#orpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F56 0 ) (#orps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F56 0 ) (#pabsb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F381C 0 ) (#pabsd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F381E 0 ) (#pabsw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F381D 0 ) (#packssdw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F6B 0 ) (#packsswb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F63 0 ) (#packusdw #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F382B 0 ) (#packuswb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F67 0 ) (#paddb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FFC 0 ) (#paddd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FFE 0 ) (#paddq #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FD4 0 ) (#paddsb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FEC 0 ) (#paddsw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FED 0 ) (#paddusb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FDC 0 ) (#paddusw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FDD 0 ) (#paddw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FFD 0 ) (#palignr #mmuRmImm8 "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3A0F 0 ) (#pand #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FDB 0 ) (#pandn #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FDF 0 ) (#pause #emit 0 0 "R" 0 "C1" 16rF3000090 0 ) (#pavgb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FE0 0 ) (#pavgw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FE3 0 ) (#pblendvb #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3810 0 ) (#pblendw #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A0E 0 ) (#pcmpeqb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F74 0 ) (#pcmpeqd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F76 0 ) (#pcmpeqq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3829 0 ) (#pcmpeqw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F75 0 ) (#pcmpestri #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A61 0 ) (#pcmpestrm #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A60 0 ) (#pcmpgtb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F64 0 ) (#pcmpgtd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F66 0 ) (#pcmpgtq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3837 0 ) (#pcmpgtw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F65 0 ) (#pcmpistri #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A63 0 ) (#pcmpistrm #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A62 0 ) (#pextrb #mmuPextr "op1" 2r1000101 "op2" 2r100000 "R" 0 "C1" 16r000F3A14 0 ) (#pextrd #mmuPextr "op1" 2r1000100 "op2" 2r100000 "R" 0 "C1" 16r000F3A16 0 ) (#pextrq #mmuPextr "op1" 2r1001100 "op2" 2r100000 "R" 1 "C1" 16r000F3A16 0 ) (#pextrw #mmuPextr "op1" 2r1000100 "op2" 2r110000 "R" 0 "C1" 16r000F3A16 0 ) (#pf2id #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r0000001D ) (#pf2iw #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r0000001C ) (#pfacc #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r000000AE ) (#pfadd #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r0000009E ) (#pfcmpeq #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r000000B0 ) (#pfcmpge #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r00000090 ) (#pfcmpgt #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r000000A0 ) (#pfmax #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r000000A4 ) (#pfmin #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r00000094 ) (#pfmul #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r000000B4 ) (#pfnacc #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r0000008A ) (#pfpnacc #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r0000008E ) (#pfrcp #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r00000096 ) (#pfrcpit1 #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r000000A6 ) (#pfrcpit2 #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r000000B6 ) (#pfrsqit1 #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r000000A7 ) (#pfrsqrt #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r00000097 ) (#pfsub #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r0000009A ) (#pfsubr #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r000000AA ) (#phaddd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3802 0 ) (#phaddsw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3803 0 ) (#phaddw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3801 0 ) (#phminposuw #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3841 0 ) (#phsubd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3806 0 ) (#phsubsw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3807 0 ) (#phsubw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3805 0 ) (#pi2fd #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r0000000D ) (#pi2fw #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r0000000C ) (#pinsrb #mmuRmImm8 "op1" 2r100000 "op2" 2r1000100 "R" 0 "C1" 16r660F3A20 0 ) (#pinsrd #mmuRmImm8 "op1" 2r100000 "op2" 2r1000100 "R" 0 "C1" 16r660F3A22 0 ) (#pinsrq #mmuRmImm8 "op1" 2r100000 "op2" 2r1001000 "R" 0 "C1" 16r660F3A22 0 ) (#pinsrw #mmuRmImm8 "op1" 2r110000 "op2" 2r1000100 "R" 0 "C1" 16r00000FC4 0 ) (#pmaddubsw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3804 0 ) (#pmaddwd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FF5 0 ) (#pmaxsb #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F383C 0 ) (#pmaxsd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F383D 0 ) (#pmaxsw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FEE 0 ) (#pmaxub #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FDE 0 ) (#pmaxud #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F383F 0 ) (#pmaxuw #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F383E 0 ) (#pminsb #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3838 0 ) (#pminsd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3839 0 ) (#pminsw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FEA 0 ) (#pminub #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FDA 0 ) (#pminud #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F383B 0 ) (#pminuw #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F383A 0 ) (#pmovmskb #mmurmi "op1" 2r1100 "op2" 2r110000 "R" 0 "C1" 16r00000FD7 0 ) (#pmovsxbd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3821 0 ) (#pmovsxbq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3822 0 ) (#pmovsxbw #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3820 0 ) (#pmovsxdq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3825 0 ) (#pmovsxwd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3823 0 ) (#pmovsxwq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3824 0 ) (#pmovzxbd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3831 0 ) (#pmovzxbq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3832 0 ) (#pmovzxbw #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3830 0 ) (#pmovzxdq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3835 0 ) (#pmovzxwd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3833 0 ) (#pmovzxwq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3834 0 ) (#pmuldq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3828 0 ) (#pmulhrsw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F380B 0 ) (#pmulhuw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FE4 0 ) (#pmulhw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FE5 0 ) (#pmulld #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3840 0 ) (#pmullw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FD5 0 ) (#pmuludq #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FF4 0 ) (#pop #pop 0 0 "R" 0 "C1" 16r00000058 "C2" 16r0000008F ) (#popad #emit #x86 0 "R" 0 "C1" 16r00000061 0 ) (#popcnt #rrm 0 0 "R" 0 "C1" 16rF3000FB8 0 ) (#popfd #emit 0 0 "R" 0 "C1" 16r0000009D 0 ) (#popfq #emit 0 0 "R" 0 "C1" 16r4800009D 0 ) (#por #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FEB 0 ) (#prefetch #mmuPrefetch "op1" 2r1000000 "op2" 2r10000000 "R" 0 0 0 ) (#psadbw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FF6 0 ) (#pshufb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3800 0 ) (#pshufd #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F70 0 ) (#pshufhw #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F70 0 ) (#pshuflw #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F70 0 ) (#pshufw #mmuRmImm8 "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F70 0 ) (#psignb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3808 0 ) (#psignd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F380A 0 ) (#psignw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r000F3809 0 ) (#pslld #mmurmi "op1" 2r110000 "op2" 2r11110000 "R" 6 "C1" 16r00000FF2 "C2" 16r00000F72 ) (#pslldq #mmurmi "op1" 2r100000 "op2" 2r10000000 "R" 7 0 "C2" 16r66000F73 ) (#psllq #mmurmi "op1" 2r110000 "op2" 2r11110000 "R" 6 "C1" 16r00000FF3 "C2" 16r00000F73 ) (#psllw #mmurmi "op1" 2r110000 "op2" 2r11110000 "R" 6 "C1" 16r00000FF1 "C2" 16r00000F71 ) (#psrad #mmurmi "op1" 2r110000 "op2" 2r11110000 "R" 4 "C1" 16r00000FE2 "C2" 16r00000F72 ) (#psraw #mmurmi "op1" 2r110000 "op2" 2r11110000 "R" 4 "C1" 16r00000FE1 "C2" 16r00000F71 ) (#psrld #mmurmi "op1" 2r110000 "op2" 2r11110000 "R" 2 "C1" 16r00000FD2 "C2" 16r00000F72 ) (#psrldq #mmurmi "op1" 2r100000 "op2" 2r10000000 "R" 3 0 "C2" 16r66000F73 ) (#psrlq #mmurmi "op1" 2r110000 "op2" 2r11110000 "R" 2 "C1" 16r00000FD3 "C2" 16r00000F73 ) (#psrlw #mmurmi "op1" 2r110000 "op2" 2r11110000 "R" 2 "C1" 16r00000FD1 "C2" 16r00000F71 ) (#psubb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FF8 0 ) (#psubd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FFA 0 ) (#psubq #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FFB 0 ) (#psubsb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FE8 0 ) (#psubsw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FE9 0 ) (#psubusb #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FD8 0 ) (#psubusw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FD9 0 ) (#psubw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FF9 0 ) (#pswapd #mmuRm3DNow "op1" 2r10000 "op2" 2r1010000 "R" 0 "C1" 16r00000F0F "C2" 16r000000BB ) (#ptest #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3817 0 ) (#punpckhbw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F68 0 ) (#punpckhdq #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F6A 0 ) (#punpckhqdq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F6D 0 ) (#punpckhwd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F69 0 ) (#punpcklbw #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F60 0 ) (#punpckldq #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F62 0 ) (#punpcklqdq #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F6C 0 ) (#punpcklwd #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000F61 0 ) (#push #push 0 0 "R" 6 "C1" 16r00000050 "C2" 16r000000FF ) (#pushad #emit #x86 0 "R" 0 "C1" 16r00000060 0 ) (#pushf #emit 0 0 "R" 0 "C1" 16r6600009C 0 ) (#pushfd #emit #x86 0 "R" 0 "C1" 16r0000009C 0 ) (#pushfq #emit #x64 0 "R" 0 "C1" 16r0000009C 0 ) (#pxor #mmurmi "op1" 2r110000 "op2" 2r1110000 "R" 0 "C1" 16r00000FEF 0 ) (#rcl #rot 0 0 "R" 2 0 0 ) (#rcpps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F53 0 ) (#rcpss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F53 0 ) (#rcr #rot 0 0 "R" 3 0 0 ) (#rdtsc #emit 0 0 "R" 0 "C1" 16r00000F31 0 ) (#rdtscp #emit 0 0 "R" 0 "C1" 16r000F01F9 0 ) (#ret #ret 0 0 "R" 0 0 0 ) (#rol #rot 0 0 "R" 0 0 0 ) (#ror #rot 0 0 "R" 1 0 0 ) (#roundpd #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A09 0 ) (#roundps #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A08 0 ) (#roundsd #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A0B 0 ) (#roundss #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r660F3A0A 0 ) (#rsqrtps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F52 0 ) (#rsqrtss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F52 0 ) (#sahf #emit 0 0 "R" 0 "C1" 16r0000009E 0 ) (#sal #rot 0 0 "R" 4 0 0 ) (#sar #rot 0 0 "R" 7 0 0 ) (#sbb #alu 0 0 "R" 3 "C1" 16r00000018 "C2" 16r00000080 ) (#sfence #emit 0 0 "R" 0 "C1" 16r000FAEF8 0 ) (#shl #rot 0 0 "R" 4 0 0 ) (#shld #shldShrd 0 0 "R" 0 "C1" 16r00000FA4 0 ) (#shr #rot 0 0 "R" 5 0 0 ) (#shrd #shldShrd 0 0 "R" 0 "C1" 16r00000FAC 0 ) (#shufps #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000FC6 0 ) (#sqrtpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F51 0 ) (#sqrtps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F51 0 ) (#sqrtsd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F51 0 ) (#sqrtss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F51 0 ) (#stc #emit 0 0 "R" 0 "C1" 16r000000F9 0 ) (#stmxcsr #mem "op1" 2r1000000 0 "R" 3 "C1" 16r00000FAE 0 ) (#sub #alu 0 0 "R" 5 "C1" 16r00000028 "C2" 16r00000080 ) (#subpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F5C 0 ) (#subps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F5C 0 ) (#subsd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F5C 0 ) (#subss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF3000F5C 0 ) (#syscall #emit "op1" 2r100000000 0 "R" 0 "C1" 16r00000F05 0 ) (#test #test 0 0 "R" 0 0 0 ) (#ucomisd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F2E 0 ) (#ucomiss #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F2E 0 ) (#ud2 #emit 0 0 "R" 0 "C1" 16r00000F0B 0 ) (#unpckhpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F15 0 ) (#unpckhps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F15 0 ) (#unpcklpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F14 0 ) (#unpcklps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F14 0 ) (#xadd #rmr 0 0 "R" 0 "C1" 16r00000FC0 0 ) (#xchg #xchg 0 0 "R" 0 0 0 ) (#xor #alu 0 0 "R" 6 "C1" 16r00000030 "C2" 16r00000080 ) (#xorpd #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r66000F57 0 ) (#xorps #mmurmi "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16r00000F57 0 ) ) ! ! !AJx86InstructionDescription class methodsFor: 'accessing' stamp: 'HenrikSperreJohansen 6/26/2014 12:47'! instructionsAmbiguous "These instructions have differing meaning based on arguments. We drew the short straw, and the other versions group emitter decides whether we were in fact the intended target" ^#("Disambiguated using emitsddisambiguate:" (#movsd #mmuMov "op1" 2r1100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000F10 "C2" 16rF2000F11 ) (#cmpsd #mmuRmImm8 "op1" 2r100000 "op2" 2r1100000 "R" 0 "C1" 16rF2000FC2 0 ))! ! !AJx86InstructionDescription class methodsFor: 'instance creation' stamp: 'CamilloBruni 4/13/2012 14:30'! fromArray: aSpecArray ^ self basicNew fromArray: aSpecArray! ! !AJx86InstructionDescription class methodsFor: 'initialization' stamp: ''! instructionsCDQ "CBW/CWDE/CDQE Convert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword" ^#( (#cbw #emit 0 0 "R" 0 "C1" 16r66000098 0 ) (#cwde #emit 0 0 "R" 0 "C1" 16r00000098 0 ) (#cdqe #emit #x64 0 "R" 0 "C1" 16r48000098 0 ) "CWD/CDQ/CQO Convert Word to Doubleword/Convert Doubleword to Quadword" (#cwd #emit 0 0 "R" 0 "C1" 16r66000099 0 ) (#cdq #emit 0 0 "R" 0 "C1" 16r00000099 0 ) (#cqo #emit #x64 0 "R" 0 "C1" 16r48000099 0 ) )! ! !AJx86InstructionDescription class methodsFor: 'testing' stamp: ''! checkInstructionsIntegrity " self checkInstructionsIntegrity" | data | data := self instructionData. data do: [:dt | | instr | instr := instructions at: dt first. self assert: [ (instr name = (dt at: 1)) & (instr group = (dt at: 2)) & (instr o1Flags = (dt at:3)) & (instr o2Flags = (dt at:4)) & (instr opCodeR = (dt at:5)) & (instr opCode1 = (dt at:6)) & (instr opCode2 = (dt at:7)) ]. ]. ! ! !AJx86JumpInstruction commentStamp: 'TorstenBergmann 1/30/2014 09:18'! Jump instruction for X86! !AJx86JumpInstruction methodsFor: 'emitting code' stamp: ''! emitLongJump: desc target: target | addr sz nextInstruction | sz := self isConditional ifTrue: [ 2 ] ifFalse: [ 1 ]. nextInstruction := position + 4 + sz. addr := (AJImmediate ivalue: target - nextInstruction) asDWord. ^ self isConditional ifFalse: [ self emitUnconditionalJumpTo: addr ] ifTrue: [ self emitConditionalJump: addr to: desc ]! ! !AJx86JumpInstruction methodsFor: 'accessing' stamp: 'CamilloBruni 8/23/2012 16:01'! instructionDesciptions ^ AJx86InstructionDescription instructions! ! !AJx86JumpInstruction methodsFor: 'emitting code' stamp: ''! emitShortJump: desc offset: delta "short jump" ^ self isConditional ifTrue: [ {(16r70 + desc opCode1). (delta asByte)} asByteArray ] ifFalse: [ {16rEB. (delta asByte)} asByteArray ]! ! !AJx86JumpInstruction methodsFor: 'testing' stamp: ''! isConditional ^ name ~~ #jmp! ! !AJx86JumpInstruction methodsFor: 'emitting code' stamp: ''! emitConditionalJump: addr to: desc ^ {16r0F. (16r80 + desc opCode1). (addr bitAnd: 255). (addr >> 8 bitAnd: 255). (addr >> 16 bitAnd: 255). (addr >> 24 bitAnd: 255)} asByteArray! ! !AJx86JumpInstruction methodsFor: 'emitting code' stamp: 'CamilloBruni 8/22/2012 14:34'! emitCode: asm "generate opcodes" | delta code nextInstruction target desc | target := label position. target ifNil: [ ^ machineCode := nil ]. nextInstruction := position + 2. delta := (target - nextInstruction) asImm. desc := self instructionDesciptions at: name. "can we use 8bit offset?" machineCode := delta isInt8 ifTrue: [ self emitShortJump: desc offset: delta ] ifFalse: [ self emitLongJump: desc target: target ]! ! !AJx86JumpInstruction methodsFor: 'accessing' stamp: ''! machineCodeSize machineCode ifNil: [ ^ 2 ]. ^ machineCode size! ! !AJx86JumpInstruction methodsFor: 'emitting code' stamp: 'CamilloBruni 8/22/2012 18:07'! emitCodeAtOffset: offset assembler: asm position := offset. [ | labelPos | labelPos := label position. labelPos ifNotNil: [ self emitCode: asm ]. next ifNotNil: [ next emitCodeAtOffset: offset + self machineCodeSize assembler: asm ]. label position ~= labelPos ] whileTrue. label position ifNil: [ self errorUndefinedLabel: label ]! ! !AJx86JumpInstruction methodsFor: 'convenience' stamp: 'CamilloBruni 8/22/2012 18:07'! errorUndefinedLabel: aLabel ^ self error: 'undefined label: ', aLabel name! ! !AJx86JumpInstruction methodsFor: 'emitting code' stamp: ''! emitUnconditionalJumpTo: addr ^ { 16rE9. (addr bitAnd: 255). (addr >> 8 bitAnd: 255). (addr >> 16 bitAnd: 255). (addr >> 24 bitAnd: 255)} asByteArray! ! !AJx86JumpInstruction methodsFor: 'accessing' stamp: ''! codeSize machineCode ifNil: [ ^ 2 ]. ^ machineCode size! ! !AJx86RegisterTests commentStamp: 'TorstenBergmann 2/4/2014 21:38'! SUnit tests for x86 registers! !AJx86RegisterTests methodsFor: 'as yet unclassified' stamp: 'MartinMcClure 1/30/2013 21:56'! testAsHighByte | highByteRegs lowByteRegs otherGPRegs | highByteRegs := {AH. CH. DH. BH}. lowByteRegs := {AL. CL. DL. BL}. otherGPRegs := AJx86Registers generalPurpose reject: [ :r | r isHighByte | r isLowByte ]. self assert: (highByteRegs collect: [ :r | r asHighByte ]) equals: highByteRegs. self assert: (lowByteRegs collect: [ :r | r asHighByte ]) equals: highByteRegs. self assert: otherGPRegs size equals: 60. "16 of each size, less the lowByteRegs" otherGPRegs do: [ :r | self should: [ r asHighByte ] raise: Error ]! ! !AJx86RegisterTests methodsFor: 'as yet unclassified' stamp: 'MartinMcClure 1/30/2013 19:40'! testRegisterWidthConversions "Test the generalPurpose register methods #as8, #as16, #as32, #as64. Some resulting registers are not valid except in 64-bit mode, but that is not checked until you try to use the register in an instruction." | regs8 regs16 regs32 regs64 highByteRegs | regs8 := {AL. CL. DL. BL. SPL. BPL. SIL. DIL. R8B. R9B. R10B. R11B. R12B. R13B. R14B. R15B}. regs16 := {AX. CX. DX. BX. SP. BP. SI. DI. R8W. R9W. R10W. R11W. R12W. R13W. R14W. R15W}. regs32 := {EAX. ECX. EDX. EBX. ESP. EBP. ESI. EDI. R8D. R9D. R10D. R11D. R12D. R13D. R14D. R15D}. regs64 := {RAX. RCX. RDX. RBX. RSP. RBP. RSI. RDI. R8. R9. R10. R11. R12. R13. R14. R15}. highByteRegs := {AH. CH. DH. BH}. self assert: (regs8 collect: [ :r | r as8 ]) equals: regs8; assert: (regs16 collect: [ :r | r as8 ]) equals: regs8; assert: (regs32 collect: [ :r | r as8 ]) equals: regs8; assert: (regs64 collect: [ :r | r as8 ]) equals: regs8. self assert: (regs8 collect: [ :r | r as16 ]) equals: regs16; assert: (regs16 collect: [ :r | r as16 ]) equals: regs16; assert: (regs32 collect: [ :r | r as16 ]) equals: regs16; assert: (regs64 collect: [ :r | r as16 ]) equals: regs16. self assert: (regs8 collect: [ :r | r as32 ]) equals: regs32; assert: (regs16 collect: [ :r | r as32 ]) equals: regs32; assert: (regs32 collect: [ :r | r as32 ]) equals: regs32; assert: (regs64 collect: [ :r | r as32 ]) equals: regs32. self assert: (regs8 collect: [ :r | r as64 ]) equals: regs64; assert: (regs16 collect: [ :r | r as64 ]) equals: regs64; assert: (regs32 collect: [ :r | r as64 ]) equals: regs64; assert: (regs64 collect: [ :r | r as64 ]) equals: regs64. self assert: (highByteRegs collect: [ :r | r as8 ]) equals: highByteRegs; assert: (highByteRegs collect: [ :r | r as16 ]) equals: {AX. CX. DX. BX}; assert: (highByteRegs collect: [ :r | r as32 ]) equals: {EAX. ECX. EDX. EBX}; assert: (highByteRegs collect: [ :r | r as64 ]) equals: {RAX. RCX. RDX. RBX}! ! !AJx86RegisterTests methodsFor: 'as yet unclassified' stamp: 'MartinMcClure 1/30/2013 21:57'! testAsLowByte | highByteRegs lowByteRegs otherGPRegs | highByteRegs := {AH. CH. DH. BH}. lowByteRegs := {AL. CL. DL. BL}. otherGPRegs := AJx86Registers generalPurpose reject: [ :r | r isHighByte | r isLowByte ]. self assert: (highByteRegs collect: [ :r | r asLowByte ]) equals: lowByteRegs. self assert: (lowByteRegs collect: [ :r | r asLowByte ]) equals: lowByteRegs. self assert: otherGPRegs size equals: 60. "16 of each size, less the lowByteRegs" otherGPRegs do: [ :r | self should: [ r asLowByte ] raise: Error ]! ! !AJx86Registers commentStamp: ''! I am a SHaredPool which initializes all the registers needed by the Assmbler.! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! MM7 "An MMX register" ^ self at: #MM7! ! !AJx86Registers class methodsFor: 'initialization' stamp: 'CamilloBruni 3/20/2012 18:45'! registerBase: base class: regClass values: names | val | val := base. names do: [ :regName | | reg | reg := regClass code: val name: regName. self classPool at: regName put: reg. Codes at: val put: regName. val := val + 1]. ! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! all8 ^ self all select: [:reg| reg is8 ]! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! ESP "A 32bit general purpose register This register overlaps with AH, AX, EAX, RAX" ^ self at: #ESP! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ESI "A 32bit general purpose register This register overlaps with DH, DX, EDX, RDX" ^ self at: #ESI! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! CL "A 8bit general purpose register This register overlaps with CL, CX, ECX, RCX" ^ self at: #CL! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R14B "A 8bit general purpose register This register overlaps with R14B, R14W, R14D, R14" ^ self at: #R14B! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R9D "A 32bit general purpose register This register overlaps with R9B, R9W, R9D, R9" ^ self at: #R9D! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM9 "An SSE register" ^ self at: #XMM9! ! !AJx86Registers class methodsFor: 'initialization' stamp: 'MartinMcClure 1/27/2013 14:46'! initialize "AJx86Registers initialize" self classPool at: #Codes put: IdentityDictionary new. self initializeGeneralPurpose8BitRegisters. self initializeGeneralPurpose16BitRegisters. self initializeGeneralPurpose32BitRegisters. self initializeGeneralPurpose64BitRegisters. self initializeInstructionPointerRegisters. self initializeX87Registers. self initializeMMXRegisters. self initializeSSERegisters.! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R11 "A 64bit general purpose register This register overlaps with R11B, R11W, R11D, R11" ^ self at: #R11! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R12D "A 32bit general purpose register This register overlaps with R12B, R12W, R12D, R12" ^ self at: #R12D! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R10W "A 16bit general purpose register This register overlaps with R10B, R10W, R10D, R10" ^ self at: #R10W! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! RDX "A 64bit general purpose register This register overlaps with DL, DX, EDX, RDX" ^ self at: #RDX! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM13 "An SSE register" ^ self at: #XMM13! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R8B "A 8bit general purpose register This register overlaps with R8B, R8W, R8D, R8" ^ self at: #R8B! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! all16 ^ self all select: [:reg| reg is16 ]! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! RDI "A 64bit general purpose register This register overlaps with BH, BX, EBX, RBX" ^ self at: #RDI! ! !AJx86Registers class methodsFor: 'accessing' stamp: 'MarcusDenker 5/7/2013 15:27'! code: registerCode "Access a register by its code. Example: RBP == (self code: RBP code)" | registerName | self flag: 'XXX now this is some ugly code... add an instance variable for the requiresRex boolean instead of encoding it in #code'. registerName := Codes at: registerCode ifAbsent: [ Codes at: registerCode + 16r100 ifAbsent: [ Codes at: registerCode + 16r200 ifAbsent: [ KeyNotFound signalFor: registerCode ] ] ]. ^ self classPool at: registerName! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM8 "An SSE register" ^ self at: #XMM8! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! IP "A 16bit instruction pointer register This register overlaps with IP, EIP, RIP" ^ self at: #IP! ! !AJx86Registers class methodsFor: 'method compilation' stamp: 'CamilloBruni 7/17/2012 11:27'! printRegister: register descriptionOn: s s nextPut: $". register descriptionOn: s. register influencingRegisters ifNotEmpty: [ :registers| s crtab nextPutAll: 'This register overlaps with '. registers do: [ :reg| s nextPutAll: reg name ] separatedBy: [ s nextPutAll: ', ']]. s nextPut: $"! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM1 "An SSE register" ^ self at: #XMM1! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! MM4 "An MMX register" ^ self at: #MM4! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! XMM14 "An SSE register" ^ self at: #XMM14! ! !AJx86Registers class methodsFor: 'initialization' stamp: 'CamilloBruni 7/17/2012 11:04'! initializeInstructionPointerRegisters | ip eip rip | ip := AJx64RipRegister code: SI code name: #IP. eip := AJx64RipRegister code: ESI code name: #EIP. rip := AJx64RipRegister code: RSI code name: #RIP. Codes at: SI code negated put: #IP; at: ESI code negated put: #EIP; at: RSI code negated put: #RIP. self classPool at: #IP put: ip; at: #EIP put: eip; at: #RIP put: rip.! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM15 "An SSE register" ^ self at: #XMM15! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R13B "A 8bit general purpose register This register overlaps with R13B, R13W, R13D, R13" ^ self at: #R13B! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! generalPurpose ^ self all select: [ :reg| reg isGeneralPurpose ]! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R14W "A 16bit general purpose register This register overlaps with R14B, R14W, R14D, R14" ^ self at: #R14W! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! DH "A 8bit general purpose register This register overlaps with DH, DX, EDX, RDX" ^ self at: #DH! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! AH "A 8bit general purpose register This register overlaps with AH, AX, EAX, RAX" ^ self at: #AH! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R15 "A 64bit general purpose register This register overlaps with R15B, R15W, R15D, R15" ^ self at: #R15! ! !AJx86Registers class methodsFor: 'method compilation' stamp: 'CamilloBruni 7/17/2012 11:14'! installRegisterAccessors "this method creates simple accessors for all registers" | registerAccessorsCategory | registerAccessorsCategory := 'accessing registers'. "remove all methods in the 'accessing register' category" self class methodDict values select: [ :method | method category = registerAccessorsCategory ] thenDo: [ :method | self class removeSelector: method selector ]. self all do: [ :register | | method | "install the direct accessor on this class" self installRegister: register accessorCategory: registerAccessorsCategory. "install the accessor on the assembler" self installRegister: register accessorCategory: registerAccessorsCategory on: (register isX86 ifTrue: [ AJx86Assembler ] ifFalse: [ AJx64Assembler ])] displayingProgress: [ :each| each name ].! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM3 "An SSE register" ^ self at: #XMM3! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! doesNotUnderstand: aMessage self classPool at: aMessage selector ifPresent: [:val| ^ val ]. ^ super doesNotUnderstand: aMessage! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R14D "A 32bit general purpose register This register overlaps with R14B, R14W, R14D, R14" ^ self at: #R14D! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R13D "A 32bit general purpose register This register overlaps with R13B, R13W, R13D, R13" ^ self at: #R13D! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! SP "A 16bit general purpose register This register overlaps with AH, AX, EAX, RAX" ^ self at: #SP! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R10 "A 64bit general purpose register This register overlaps with R10B, R10W, R10D, R10" ^ self at: #R10! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ST4 "A floating point register" ^ self at: #ST4! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! generalPurpose8 ^ self sortRegistersByIndex: (self generalPurpose select: [:reg| reg is8 ])! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! ST7 "A floating point register" ^ self at: #ST7! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! XMM2 "An SSE register" ^ self at: #XMM2! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! BX "A 16bit general purpose register This register overlaps with BL, BX, EBX, RBX" ^ self at: #BX! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ST5 "A floating point register" ^ self at: #ST5! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R13 "A 64bit general purpose register This register overlaps with R13B, R13W, R13D, R13" ^ self at: #R13! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! ST3 "A floating point register" ^ self at: #ST3! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R15B "A 8bit general purpose register This register overlaps with R15B, R15W, R15D, R15" ^ self at: #R15B! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R9B "A 8bit general purpose register This register overlaps with R9B, R9W, R9D, R9" ^ self at: #R9B! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! BL "A 8bit general purpose register This register overlaps with BL, BX, EBX, RBX" ^ self at: #BL! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! AL "A 8bit general purpose register This register overlaps with AL, AX, EAX, RAX" ^ self at: #AL! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! CX "A 16bit general purpose register This register overlaps with CL, CX, ECX, RCX" ^ self at: #CX! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! BH "A 8bit general purpose register This register overlaps with BH, BX, EBX, RBX" ^ self at: #BH! ! !AJx86Registers class methodsFor: 'method compilation' stamp: 'CamilloBruni 7/17/2012 11:28'! installRegister: register accessorCategory: registerAccessorsCategory ^ self class compile:(String streamContents: [ :s | s nextPutAll: register name; crtab. self printRegister: register descriptionOn: s. s crtab; nextPutAll: '^ self at: #'; nextPutAll: register name ]) classified: registerAccessorsCategory! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R12W "A 16bit general purpose register This register overlaps with R12B, R12W, R12D, R12" ^ self at: #R12W! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R9 "A 64bit general purpose register This register overlaps with R9B, R9W, R9D, R9" ^ self at: #R9! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! RCX "A 64bit general purpose register This register overlaps with CL, CX, ECX, RCX" ^ self at: #RCX! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! RIP "A 64bit instruction pointer register This register overlaps with IP, EIP, RIP" ^ self at: #RIP! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ST1 "A floating point register" ^ self at: #ST1! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R10B "A 8bit general purpose register This register overlaps with R10B, R10W, R10D, R10" ^ self at: #R10B! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! AX "A 16bit general purpose register This register overlaps with AL, AX, EAX, RAX" ^ self at: #AX! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ECX "A 32bit general purpose register This register overlaps with CL, CX, ECX, RCX" ^ self at: #ECX! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM7 "An SSE register" ^ self at: #XMM7! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! all64 ^ self all select: [:reg| reg is64 ]! ! !AJx86Registers class methodsFor: 'initialization' stamp: ''! initializeMMXRegisters " MMX registers " self registerBase: 16r60 class: AJMMRegister values: #( #MM0 #MM1 #MM2 #MM3 #MM4 #MM5 #MM6 #MM7 ).! ! !AJx86Registers class methodsFor: 'initialization' stamp: 'MartinMcClure 1/27/2013 10:06'! initializeGeneralPurpose8BitRegisters "general purpose 8 bit registers " self registerBase: 0 class: AJx86GPRegister rex: #dontCare values: #(#AL #CL #DL #BL); registerBase: 4 class: AJx86GPRegister rex: #prohibited values: #(#AH #CH #DH #BH); registerBase: 4 class: AJx86GPRegister rex: #required values: #(#SPL #BPL #SIL #DIL #R8B #R9B #R10B #R11B #R12B #R13B #R14B #R15B)! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! DI "A 16bit general purpose register This register overlaps with BH, BX, EBX, RBX" ^ self at: #DI! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! generalPurpose16 ^ self sortRegistersByIndex: (self generalPurpose select: [:reg| reg is16 ])! ! !AJx86Registers class methodsFor: 'initialization' stamp: 'CamilloBruni 7/17/2012 11:10'! initializeSSERegisters " SSE registers " self registerBase: 16r70 class: AJxMMRegister values: #( #XMM0 #XMM1 #XMM2 #XMM3 #XMM4 #XMM5 #XMM6 #XMM7 #XMM8 #XMM9 #XMM10 #XMM11 #XMM12 #XMM13 #XMM14 #XMM15).! ! !AJx86Registers class methodsFor: 'initialization' stamp: 'MartinMcClure 1/27/2013 09:56'! registerBase: base class: regClass rex: rexSymbol values: names | val | val := 0. rexSymbol == #required ifTrue: [ val := 16r100 ]. rexSymbol == #prohibited ifTrue: [ val := 16r200 ]. val := val + base. names do: [ :regName | | reg | reg := regClass code: val name: regName. self classPool at: regName put: reg. Codes at: val put: regName. val := val + 1 ]! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R15W "A 16bit general purpose register This register overlaps with R15B, R15W, R15D, R15" ^ self at: #R15W! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! EDI "A 32bit general purpose register This register overlaps with BH, BX, EBX, RBX" ^ self at: #EDI! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! generalPurpose32 ^ self sortRegistersByIndex: (self generalPurpose select: [:reg| reg is32 ])! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R11D "A 32bit general purpose register This register overlaps with R11B, R11W, R11D, R11" ^ self at: #R11D! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R8 "A 64bit general purpose register This register overlaps with R8B, R8W, R8D, R8" ^ self at: #R8! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! ST6 "A floating point register" ^ self at: #ST6! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM12 "An SSE register" ^ self at: #XMM12! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R12 "A 64bit general purpose register This register overlaps with R12B, R12W, R12D, R12" ^ self at: #R12! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R8D "A 32bit general purpose register This register overlaps with R8B, R8W, R8D, R8" ^ self at: #R8D! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R10D "A 32bit general purpose register This register overlaps with R10B, R10W, R10D, R10" ^ self at: #R10D! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM0 "An SSE register" ^ self at: #XMM0! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R8W "A 16bit general purpose register This register overlaps with R8B, R8W, R8D, R8" ^ self at: #R8W! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! BP "A 16bit general purpose register This register overlaps with CH, CX, ECX, RCX" ^ self at: #BP! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! RBX "A 64bit general purpose register This register overlaps with BL, BX, EBX, RBX" ^ self at: #RBX! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! RSP "A 64bit general purpose register This register overlaps with AH, AX, EAX, RAX" ^ self at: #RSP! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM5 "An SSE register" ^ self at: #XMM5! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! EBX "A 32bit general purpose register This register overlaps with BL, BX, EBX, RBX" ^ self at: #EBX! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! RSI "A 64bit general purpose register This register overlaps with DH, DX, EDX, RDX" ^ self at: #RSI! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! MM0 "An MMX register" ^ self at: #MM0! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R15D "A 32bit general purpose register This register overlaps with R15B, R15W, R15D, R15" ^ self at: #R15D! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ST0 "A floating point register" ^ self at: #ST0! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R9W "A 16bit general purpose register This register overlaps with R9B, R9W, R9D, R9" ^ self at: #R9W! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! XMM6 "An SSE register" ^ self at: #XMM6! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R14 "A 64bit general purpose register This register overlaps with R14B, R14W, R14D, R14" ^ self at: #R14! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! all32 ^ self all select: [:reg| reg is32 ]! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! generalPurpose64 ^ self sortRegistersByIndex: (self generalPurpose select: [:reg| reg is64 ])! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! EIP "A 32bit instruction pointer register This register overlaps with IP, EIP, RIP" ^ self at: #EIP! ! !AJx86Registers class methodsFor: 'initialization' stamp: 'CamilloBruni 5/21/2013 17:28'! initializeGeneralPurpose64BitRegisters "initialize general purpose 64 bit registers" self registerBase: 16r30 class: AJx86GPRegister rex: #dontCare values: #(#RAX #RCX #RDX #RBX #RSP #RBP #RSI #RDI); registerBase: 16r38 class: AJx86GPRegister rex: #required values: #(#R8 #R9 #R10 #R11 #R12 #R13 #R14 #R15)! ! !AJx86Registers class methodsFor: 'initialization' stamp: 'MartinMcClure 1/27/2013 09:57'! initializeGeneralPurpose16BitRegisters "initialize general purpose 16 bit registers " self registerBase: 16r10 class: AJx86GPRegister rex: #dontCare values: #(#AX #CX #DX #BX #SP #BP #SI #DI); registerBase: 16r18 class: AJx86GPRegister rex: #required values: #(#R8W #R9W #R10W #R11W #R12W #R13W #R14W #R15W)! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! EDX "A 32bit general purpose register This register overlaps with DL, DX, EDX, RDX" ^ self at: #EDX! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! CH "A 8bit general purpose register This register overlaps with CH, CX, ECX, RCX" ^ self at: #CH! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! EAX "A 32bit general purpose register This register overlaps with AL, AX, EAX, RAX" ^ self at: #EAX! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! EBP "A 32bit general purpose register This register overlaps with CH, CX, ECX, RCX" ^ self at: #EBP! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM11 "An SSE register" ^ self at: #XMM11! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! MM1 "An MMX register" ^ self at: #MM1! ! !AJx86Registers class methodsFor: 'accessing' stamp: 'CamilloBruni 7/17/2012 10:54'! at: aRegisterIdentifierSymbol ^ self classPool at: aRegisterIdentifierSymbol! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! MM2 "An MMX register" ^ self at: #MM2! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! R12B "A 8bit general purpose register This register overlaps with R12B, R12W, R12D, R12" ^ self at: #R12B! ! !AJx86Registers class methodsFor: 'accessing' stamp: ''! all ^ Codes values collect: [ :each| self classPool at: each ]! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! MM3 "An MMX register" ^ self at: #MM3! ! !AJx86Registers class methodsFor: 'accessing' stamp: 'MartinMcClure 1/30/2013 21:13'! generalPurposeWithIndex: index size: numBytes requiresRex: requiresRex prohibitsRex: prohibitsRex "Access a register by its properties. Example: RBP == (self generalPurposeWithIndex: RBP index size: RBP size requiresRex: RBP requiresRex prohibitsRex: RBP prohibitsRex )" | type code | type := numBytes = 1 ifTrue: [ 0 ] ifFalse: [ numBytes = 2 ifTrue: [ 16r10 ] ifFalse: [ numBytes = 4 ifTrue: [ 16r20 ] ifFalse: [ numBytes = 8 ifTrue: [ 16r30 ] ifFalse: [ self error: 'Size must be 1, 2, 4, or 8 bytes' ] ] ] ]. code := type + index. requiresRex ifTrue: [ code := code + RegRequiresRexMask ]. prohibitsRex ifTrue: [ code := code + RegProhibitsRexMask ]. ^ self classPool at: (Codes at: code)! ! !AJx86Registers class methodsFor: 'initialization' stamp: 'CamilloBruni 7/17/2012 11:10'! initializeX87Registers "X87 registers" self registerBase: 16r50 class: AJx87Register values: #( #ST0 #ST1 #ST2 #ST3 #ST4 #ST5 #ST6 #ST7 ).! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R13W "A 16bit general purpose register This register overlaps with R13B, R13W, R13D, R13" ^ self at: #R13W! ! !AJx86Registers class methodsFor: 'initialization' stamp: ''! sortRegistersByIndex: aRegisterCollection ^ aRegisterCollection sort: [ :regA :regB| regA index < regB index ].! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R11W "A 16bit general purpose register This register overlaps with R11B, R11W, R11D, R11" ^ self at: #R11W! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! R11B "A 8bit general purpose register This register overlaps with R11B, R11W, R11D, R11" ^ self at: #R11B! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! SI "A 16bit general purpose register This register overlaps with DH, DX, EDX, RDX" ^ self at: #SI! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! DX "A 16bit general purpose register This register overlaps with DL, DX, EDX, RDX" ^ self at: #DX! ! !AJx86Registers class methodsFor: 'method compilation' stamp: 'CamilloBruni 7/17/2012 11:18'! installRegister: register accessorCategory: registerAccessorsCategory on: aClass aClass compile: (String streamContents: [ :s | s nextPutAll: register name; crtab. self printRegister: register descriptionOn: s. s crtab; nextPutAll: '^ '; nextPutAll: register name ]) classified: registerAccessorsCategory ! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! RAX "A 64bit general purpose register This register overlaps with AL, AX, EAX, RAX" ^ self at: #RAX! ! !AJx86Registers class methodsFor: 'initialization' stamp: 'MartinMcClure 1/27/2013 09:58'! initializeGeneralPurpose32BitRegisters "initialize general purpose 32 bit registers " self registerBase: 16r20 class: AJx86GPRegister rex: #dontCare values: #(#EAX #ECX #EDX #EBX #ESP #EBP #ESI #EDI); registerBase: 16r28 class: AJx86GPRegister rex: #required values: #(#R8D #R9D #R10D #R11D #R12D #R13D #R14D #R15D)! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! ST2 "A floating point register" ^ self at: #ST2! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! XMM4 "An SSE register" ^ self at: #XMM4! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! DL "A 8bit general purpose register This register overlaps with DL, DX, EDX, RDX" ^ self at: #DL! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! MM6 "An MMX register" ^ self at: #MM6! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! MM5 "An MMX register" ^ self at: #MM5! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:48'! XMM10 "An SSE register" ^ self at: #XMM10! ! !AJx86Registers class methodsFor: 'accessing registers' stamp: 'AsmJIT 8/21/2012 17:47'! RBP "A 64bit general purpose register This register overlaps with CH, CX, ECX, RCX" ^ self at: #RBP! ! !AJx87Register commentStamp: ''! I am an x87 Floating Point register (ST0 - ST7) used in the FPU stack. The lower 64bit of the floating point ST registers are shared with the MMX registers.! !AJx87Register methodsFor: 'testing' stamp: ''! isGeneralPurpose ^ false! ! !AJx87Register methodsFor: 'accessing' stamp: ''! code: aCode code := aCode bitOr: RegX87. size := 10.! ! !AJx87Register methodsFor: 'testing' stamp: ''! isRegTypeX87 ^ true! ! !AJx87Register methodsFor: 'printing' stamp: 'CamilloBruni 7/17/2012 11:12'! descriptionOn: s s nextPutAll: 'A floating point register'.! ! !AJx87Register methodsFor: 'accessing' stamp: 'CamilloBruni 5/7/2013 11:32'! influencingRegisters "ST registers overlap with the MMX register" self shouldBeImplemented.! ! !AJx87Register methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 15:31'! isX86 ^ true! ! !AJxMMRegister commentStamp: ''! I am a register used by the SSE (Streaming SIMD Extensions) for the x86 instruction set. The independent XMM registers are 128bit wide and do not overlap with any other existing registers. Depending on the instructions used the XMM registers represent different data types: SSE: 4 x 32bit single precision floats SSE2: 2 x 64bit double prexision floats 2 x 64bit integers 4 x 32bit integers 8 x 16bit short integers 16 x 8bit bytes/characters! !AJxMMRegister methodsFor: 'testing' stamp: ''! isGeneralPurpose ^ false! ! !AJxMMRegister methodsFor: 'accessing' stamp: ''! code: aCode code := aCode. size := 16! ! !AJxMMRegister methodsFor: 'testing' stamp: ''! isRegTypeXMM ^ true! ! !AJxMMRegister methodsFor: 'printing' stamp: 'CamilloBruni 7/17/2012 11:15'! descriptionOn: s s nextPutAll: 'An SSE register'.! ! !AJxMMRegister methodsFor: 'testing' stamp: 'MartinMcClure 1/27/2013 15:33'! isX86 ^ self index < 8! ! !ASTCache commentStamp: ''! I am a simple cache for AST nodes corresponding to CompiledMethods in the image. The cache is emptied when the image is saved.! !ASTCache methodsFor: 'accessing' stamp: 'GuillermoPolito 5/14/2013 10:52'! at: aCompiledMethod ^ self at: aCompiledMethod ifAbsentPut: [ aCompiledMethod parseTree doSemanticAnalysisIn: aCompiledMethod methodClass ]! ! !ASTCache methodsFor: 'accessing' stamp: 'CamilloBruni 2/17/2012 14:29'! reset self removeAll! ! !ASTCache class methodsFor: 'accessing' stamp: 'CamilloBruni 2/17/2012 14:27'! reset default reset.! ! !ASTCache class methodsFor: 'class initialization' stamp: 'CamilloBruni 2/20/2012 18:54'! initialize default := self new. Smalltalk addToShutDownList: self.! ! !ASTCache class methodsFor: 'accessing' stamp: 'CamilloBruni 2/17/2012 14:30'! default ^ default! ! !ASTCache class methodsFor: 'system startup' stamp: 'CamilloBruni 2/17/2012 15:10'! shutDown self reset.! ! !ASTCache class methodsFor: 'accessing' stamp: 'CamilloBruni 2/17/2012 14:30'! default: anASTCache default := anASTCache.! ! !ASTCache class methodsFor: 'accessing' stamp: 'CamilloBruni 2/17/2012 14:22'! at: aCompiledMethod ^ default at: aCompiledMethod! ! !ASTPluginMeaningOfLife commentStamp: 'MarcusDenker 2/28/2015 15:54'! A simple example for a AST transforming compiler plugin. I replace 42 with a 'meaning of life'.! !ASTPluginMeaningOfLife methodsFor: 'transformation' stamp: 'MarcusDenker 2/28/2015 15:56'! transform | rule | rule := RBParseTreeRewriter replaceLiteral: 42 with: 'meaning of life'. rule executeTree: ast. ^ast! ! !ASTTransformExamplePluginActive commentStamp: 'MarcusDenker 2/28/2015 16:02'! This class changes the default compiler used to compile itself to include the AST transforming plugin ASTPluginMeaningOfLife. #example42 does not mean what you think it means (see bytecode)! !ASTTransformExamplePluginActive methodsFor: 'example' stamp: 'MarcusDenker 2/28/2015 15:53'! example42 ^42! ! !ASTTransformExamplePluginActive class methodsFor: 'compiler' stamp: 'MarcusDenker 2/28/2015 15:17'! compiler "the example plugin is active for this class" ^super compiler addPlugin: ASTPluginMeaningOfLife.! ! !ASTTransformationPluginTest methodsFor: 'tests' stamp: 'MarcusDenker 2/28/2015 15:19'! testClassWithPluginEnabled self assert: ASTTransformExamplePluginActive new example42 = 'meaning of life'! ! !ASTTransformationPluginTest methodsFor: 'tests' stamp: 'MarcusDenker 2/28/2015 15:53'! testTransform | ast | ast := (OCOpalExamples>>#exampleReturn42) ast copy. self assert: ast body statements first value value = 42. ast := ASTPluginMeaningOfLife transform: ast. self assert: ast body statements first value value = 'meaning of life'.! ! !Abort commentStamp: 'TorstenBergmann 2/4/2014 21:42'! Notify to abort a task! !Abort methodsFor: 'accessing' stamp: 'ajh 3/24/2003 00:55'! defaultAction "No one has handled this error, but now give them a chance to decide how to debug it. If none handle this either then open debugger (see UnhandedError-defaultAction)" UnhandledError signalForException: self! ! !AboutDialogWindow commentStamp: 'gvc 5/18/2007 13:53'! Default superclass for application about dialogs.! !AboutDialogWindow methodsFor: 'actions' stamp: 'gvc 1/12/2007 16:32'! newButtons "Answer new buttons as appropriate." ^{self newCloseButton isDefault: true}! ! !AbsolutePath commentStamp: ''! I represent an absolute path (a position starting from Path root)! !AbsolutePath methodsFor: 'testing' stamp: 'cwp 2/26/2011 11:03'! isRoot ^ self size = 0! ! !AbsolutePath methodsFor: 'enumerating' stamp: 'EstebanLorenzano 4/2/2012 11:42'! withParents ^ super withParents addFirst: (Path root); yourself! ! !AbsolutePath methodsFor: '*zinc-resource-meta-filesystem' stamp: 'SvenVanCaekenberghe 1/14/2013 10:03'! asZnUrl "Convert the receiver in a file:// ZnUrl" | fileUrl | fileUrl := ZnUrl new. fileUrl scheme: #file. self do: [ :each | fileUrl addPathSegment: each ]. ^ fileUrl! ! !AbsolutePath methodsFor: 'printing' stamp: 'EstebanLorenzano 4/3/2012 11:15'! printOn: aStream aStream nextPutAll: 'Path'. self isRoot ifTrue: [aStream nextPutAll: ' root'] ifFalse: [1 to: self size do: [:i | aStream nextPutAll: ' / '''; nextPutAll: (self at: i); nextPut: $']]! ! !AbsolutePath methodsFor: 'testing' stamp: 'cwp 2/26/2011 10:58'! isAbsolute ^ true! ! !AbsolutePath class methodsFor: 'as yet unclassified' stamp: 'CamilloBruni 1/19/2012 15:12'! addEmptyElementTo: result! ! !AbsolutePath class methodsFor: 'as yet unclassified' stamp: 'CamilloBruni 1/19/2012 15:02'! from: aString delimiter: aDelimiterCharater aString = '/' ifTrue: [ ^ self root ]. ^ super from: aString delimiter: aDelimiterCharater! ! !AbstractAcceptor commentStamp: ''! I am an abstract acceptor. The goal of my children is to properly dispatch the behavior when text is accepted. Depending of the context, different actions could be triggered! !AbstractAcceptor methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 4/16/2013 16:45'! model ^ model! ! !AbstractAcceptor methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 4/16/2013 16:43'! accept: aText notifying: aController self subclassResponsibility! ! !AbstractAcceptor methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 4/16/2013 16:41'! model: anObject model := anObject! ! !AbstractAcceptor class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 4/16/2013 16:41'! model: model ^ self new model: model; yourself! ! !AbstractAdapter commentStamp: 'StephaneDucasse 2/27/2015 20:31'! I am an abstract class. I'm the superclass of all the adapters used to link a Spec widget model to a framework specific widget (by example ButtonModel <-> PluggableButtonMorph). The current implementation installs my instances as dependent of the model and my changed: method propagates updates to the widget I create (via my buildWidget method). This implementation is not optimal. In the future my instances should just be responsible to create a widget and install all the communication between the model and the widget. I should not be a middle man. ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:42'! hSpaceFill self subclassResponsibility! ! !AbstractAdapter methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 9/29/2013 14:16'! selector ^ selector! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:41'! layout: aLayout self subclassResponsibility! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:42'! vShrinkWrap self subclassResponsibility! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:42'! hRigid self subclassResponsibility! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:42'! hShrinkWrap self subclassResponsibility! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 10/1/2013 13:14'! when: anAnnouncement do: aBlock self subclassResponsibility! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:42'! vSpaceFill self subclassResponsibility! ! !AbstractAdapter methodsFor: 'updating' stamp: 'BenjaminVanRyseghem 9/25/2013 16:18'! update: aSymbol with: anArray self perform: aSymbol withArguments: anArray! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:42'! removeSubWidgets self subclassResponsibility! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:41'! add: aWidget self subclassResponsibility! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 13:42'! asWidget ^ self widget! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 14:40'! takeKeyboardFocus self widget ifNotNil: [:w | w takeKeyboardFocus ]! ! !AbstractAdapter methodsFor: 'initialization' stamp: 'BenjaminVanRyseghem 9/25/2013 14:46'! adapt: aComposableModel model := aComposableModel. aComposableModel addDependent: self. widget := self buildWidget.! ! !AbstractAdapter methodsFor: 'testing' stamp: 'BenjaminVanRyseghem 11/26/2013 17:19'! isSpecAdapter ^ true! ! !AbstractAdapter methodsFor: 'updating' stamp: 'BenjaminVanRyseghem 9/25/2013 14:44'! update: aSymbol self changed: aSymbol! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:42'! vRigid self subclassResponsibility! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:42'! useProportionalLayout self subclassResponsibility! ! !AbstractAdapter methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 9/25/2013 13:57'! widget ^ widget! ! !AbstractAdapter methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 9/29/2013 14:16'! selector: anObject selector := anObject! ! !AbstractAdapter methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 9/25/2013 13:48'! model ^ model! ! !AbstractAdapter methodsFor: '*Spec-MorphicAdapters' stamp: 'BenjaminVanRyseghem 10/10/2013 12:15'! isMorphicAdapter ^ false! ! !AbstractAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 10/1/2013 13:32'! isRedrawable "This must be overriden in the adapter representing your container" ^ false! ! !AbstractAdapter methodsFor: 'factory' stamp: 'StephaneDucasse 2/26/2015 16:40'! buildWidget ^ self subclassResponsibility! ! !AbstractAdapter methodsFor: 'private' stamp: 'BenjaminVanRyseghem 1/10/2014 12:35'! widgetDo: aBlock ^ self widget ifNotNil: aBlock! ! !AbstractAdapter class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 9/25/2013 14:17'! adapt: aComposableModel ^ self new adapt: aComposableModel; yourself! ! !AbstractCache commentStamp: ''! I am Cache. I am an abstract class. I am a limited cache holding onto key/value pairs. My primary interface is #at:ifAbsentPut: which takes two arguments: a key and a block. Either the key is found (cache hit) and its value is returned, or the key is not found (cache miss). If the latter case, block should compute a new value to cache. Because block takes the key as optional argument, you can specify a factory style argument as well. With an explicit factory specified, you can also use #at: to access me. For each addition to the cache, a weight is computed by #computeWeight (a selector or block) and added to #totalWeight. When #totalWeight is no longer below #maximumWeight, the least recently used item of the cache is evicted (removed) to make room. The default #computeWeight returns 1 for each value, effectively counting the number of entries. The default #maximumWeight is 16. I count hits and misses and can return my #hitRatio. Optionally, but not by default, I can be configured so that it is safe to access me from different threads/processess during my important operations. See #beThreadSafe.! !AbstractCache methodsFor: 'accessing' stamp: 'SvenVanCaekenberghe 12/9/2013 22:01'! at: key ifAbsentPut: block "If key is present in the cache, return the associated value. This is a hit and makes that key/value pair the most recently used. If key is absent, use block to compute a new value and cache it. Block can optionally take one argument, the key. This is a miss and will create a new key/value pair entry. Furthermore this could result in the least recently used key/value pair being removed when the specified maximum cache weight is exceeded." self subclassResponsibility ! ! !AbstractCache methodsFor: 'initialize' stamp: 'SvenVanCaekenberghe 12/9/2013 22:02'! maximumWeight: limit "Set my maximum allowed total weight of all cached values to limit. If the total weight is no longer below limit, the least recently used key/value pair will be removed. The default maximum weight limit is 16." weight maximum: limit! ! !AbstractCache methodsFor: 'accessing - statistics' stamp: 'SvenVanCaekenberghe 12/9/2013 21:59'! misses "Return how many misses, requests for keys not present I received." ^ statistics misses! ! !AbstractCache methodsFor: 'accessing - statistics' stamp: 'SvenVanCaekenberghe 12/9/2013 22:00'! size "Return the count of items currently present." self subclassResponsibility ! ! !AbstractCache methodsFor: 'accessing' stamp: 'SvenVanCaekenberghe 2/6/2015 10:44'! addAll: keyedCollection "Populate me with all key/value pairs from keyedCollection. Does not affect statistics." keyedCollection keysAndValuesDo: [ :key :value | self at: key put: value ]! ! !AbstractCache methodsFor: 'private' stamp: 'SvenVanCaekenberghe 12/9/2013 22:21'! critical: block ^ access ifNil: block ifNotNil: [ access critical: block ]! ! !AbstractCache methodsFor: 'removing' stamp: 'SvenVanCaekenberghe 12/9/2013 22:03'! removeKey: key "If I currently cache key, remove the entry. Signal a KeyNotFound when I currently do not cache key. Return the removed value." ^ self removeKey: key ifAbsent: [ KeyNotFound signalFor: key in: self ]! ! !AbstractCache methodsFor: 'initialize' stamp: 'SvenVanCaekenberghe 12/11/2013 15:36'! beThreadSafe "Configure me so that I can be safely used from multiple threads/processes during important operations. Note that this slows down these operations." access := Monitor new! ! !AbstractCache methodsFor: 'initialize' stamp: 'SvenVanCaekenberghe 12/16/2013 20:10'! initialize super initialize. weight := CacheWeight new. statistics := CacheStatistics new! ! !AbstractCache methodsFor: 'removing' stamp: 'SvenVanCaekenberghe 12/9/2013 22:04'! removeKey: key ifAbsent: block "If I currently cache key, remove the entry. Execute block when key is currently absent. Return the removed value." self subclassResponsibility ! ! !AbstractCache methodsFor: 'accessing' stamp: 'SvenVanCaekenberghe 2/6/2015 11:26'! at: key put: value "Populate me by storing value for key. Return value. This is neither a hit nor a miss. Statistics remain unchanged. Overwrite if already present without promotion. This could result in the least recently used key/value pair being removed when the specified maximum cache weight is exceeded." self subclassResponsibility! ! !AbstractCache methodsFor: 'accessing' stamp: 'SvenVanCaekenberghe 2/4/2015 13:46'! at: key "If key is present in the cache, return the associated value. This is a hit and makes that key/value pair the most recently used. If key is absent, use the factory to compute a new value and cache it. This is a miss and will create a new key/value pair entry. Furthermore this could result in the least recently used key/value pair being removed when the specified maximum cache weight is exceeded. If there is no factory and the key is not present, signal a KeyNotFound exception." ^ self at: key ifAbsentPut: (factory ifNil: [ [ :k | KeyNotFound signalFor: k in: self ] ])! ! !AbstractCache methodsFor: 'accessing - statistics' stamp: 'SvenVanCaekenberghe 12/9/2013 21:59'! hits "Return how many hits, requests for keys present I received." ^ statistics hits! ! !AbstractCache methodsFor: 'accessing - statistics' stamp: 'SvenVanCaekenberghe 12/9/2013 21:59'! hitRatio "Return the ratio of hits against total calls I received. This will be a number between 0 and 1. When I am empty, return 0." ^ statistics hitRatio! ! !AbstractCache methodsFor: 'printing' stamp: 'SvenVanCaekenberghe 12/9/2013 22:02'! printOn: stream super printOn: stream. stream nextPut: $(. self printElementsOn: stream. stream nextPut: $)! ! !AbstractCache methodsFor: 'initialize' stamp: 'SvenVanCaekenberghe 12/9/2013 22:02'! factory: block "Set the factory to compute values from keys to block. The factory will be evaluated for each key not present. Only my #at: message will use the factory." factory := block! ! !AbstractCache methodsFor: 'accessing - statistics' stamp: 'SvenVanCaekenberghe 12/9/2013 22:00'! totalWeight "Return the total weight of all cached values currently present." ^ weight total! ! !AbstractCache methodsFor: 'enumerating' stamp: 'SvenVanCaekenberghe 12/9/2013 22:06'! keysAndValuesDo: block "Execute block with each key and value present in me. This will be from least to most recently used." self subclassResponsibility ! ! !AbstractCache methodsFor: 'printing' stamp: 'SvenVanCaekenberghe 12/9/2013 22:03'! printElementsOn: stream stream nextPut: $#; print: self size. stream space; print: weight total; nextPut: $/; print: weight maximum. stream space; print: weight compute. factory ifNotNil: [ stream space; print: factory ]. stream space; print: (self hitRatio * 100.0) rounded ; nextPut: $%! ! !AbstractCache methodsFor: 'initialize' stamp: 'SvenVanCaekenberghe 12/9/2013 22:02'! computeWeight: valuable "Set the way to compute the weight of each cached value. This can be either a Symbol or one argument block. When the total weight is no longer below the maximum weight, the least recently used key/value pair will be removed. The default way to compute the weight returns 1 for each value, effectively counting the number of cached values." weight compute: valuable! ! !AbstractCache methodsFor: 'removing' stamp: 'SvenVanCaekenberghe 12/9/2013 22:03'! removeAll "Remove all key/value pairs that I currently hold, effectiley resetting me, but not my statistics." self subclassResponsibility ! ! !AbstractCategoryWidget commentStamp: ''! AbstractCategoryWidget is an abstraction describing a widget used to manage categories! !AbstractCategoryWidget methodsFor: 'protocol' stamp: 'NicolaiHess 8/9/2014 21:43'! resetCategoryList ^ self subclassResponsibility! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! vScrollValue ^ self subclassResponsibility! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! selectedCategory ^ self model selectedCategory! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! searchedElement: index ^ self subclassResponsibility! ! !AbstractCategoryWidget methodsFor: 'drag and drop' stamp: 'BenjaminVanRyseghem 5/9/2012 11:35'! wantsDroppedMorph: transferMorph event: anEvent inMorph: destinationLM "We are only interested in TransferMorphs as wrappers for informations. If their content is really interesting for us, will determined later in >>acceptDroppingMorph:event:." | srcType dstType | "only want drops on lists (not, for example, on pluggable texts)" (destinationLM isKindOf: PluggableListMorph) ifFalse: [ ^ false ]. srcType := transferMorph dragTransferType. dstType := self dragTransferTypeForMorph: destinationLM. ^ srcType == #getMethodItem: and: [ dstType == #getCategoryItem:]! ! !AbstractCategoryWidget methodsFor: 'drag and drop' stamp: ''! dropMethod: aCollectionOfMethods inARow: aRow self model dropMethod: aCollectionOfMethods inARow: aRow! ! !AbstractCategoryWidget methodsFor: 'drag and drop' stamp: 'BenjaminVanRyseghem 5/9/2012 11:34'! dragPassengersFor: item inMorph: dragSource | transferType object | (dragSource isKindOf: PluggableListMorph) ifFalse: [^ nil ]. transferType := self dragTransferTypeForMorph: dragSource. object := item originalObject. transferType == #getCategoryItem: ifTrue: [ ^ self selectedCategories ifEmpty: [ { object } ] ]. ^ nil! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! categoriesMenu: aMenuMorph shifted: aBoolean ^ self model categoriesMenu: aMenuMorph shifted: aBoolean ! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! showInstance ^ self model showInstance! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! vScrollValue: aNumber ^ self subclassResponsibility! ! !AbstractCategoryWidget methodsFor: 'item creation' stamp: ''! buildCategoriesList ^ self subclassResponsibility! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! categoriesSelection ^ self subclassResponsibility! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! keyPressedOnCategory: anEvent ^ self subclassResponsibility! ! !AbstractCategoryWidget methodsFor: 'updating' stamp: 'BenjaminVanRyseghem 4/17/2012 16:57'! okToChange ^ self model okToChange! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! selectedCategories ^ self subclassResponsibility! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: 'NicolaiHess 8/9/2014 21:06'! resetCategorySelection self subclassResponsibility ! ! !AbstractCategoryWidget methodsFor: 'icon' stamp: 'NicolaiHess 7/28/2014 22:17'! categoryIconFor: aString self flag: #todo. "this would work better with the new class organizer" "((aString beginsWith: '---') or: [ aString = 'no messages' ]) ifTrue: [ ^ Smalltalk ui icons protocolNoneIcon ]." (aString beginsWith: '*') ifTrue: [ ^ Smalltalk ui icons protocolExtensionIcon ]. (aString beginsWith: 'private') ifTrue: [ ^ Smalltalk ui icons protocolPrivateIcon ]. ((aString = 'initialization' ) or: [ (aString = 'initialize-release') or: [ aString = 'finalization' ]]) ifTrue: [ ^ Smalltalk ui icons protocolProtectedIcon ]. ^ Smalltalk ui icons protocolNoneIcon ! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: 'NicolaiHess 8/9/2014 21:23'! updateCategoryList self changed: #getCategoryItem:! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! label: aString ^ self subclassResponsibility! ! !AbstractCategoryWidget methodsFor: 'protocol' stamp: ''! takeKeyboardFocus ^ self subclassResponsibility! ! !AbstractClassInstaller commentStamp: ''! I take a ready class and install it in a given environment. My sublcasses implement custom strategies.! !AbstractClassInstaller methodsFor: 'notifications' stamp: 'ToonVerwaest 3/22/2011 17:43'! classAdded: aClass inCategory: aCategory self subclassResponsibility! ! !AbstractClassInstaller methodsFor: 'traits' stamp: 'MartinDias 7/1/2013 14:54'! copyTraitCompositionFrom: oldClass to: newClass self installTraitComposition: oldClass traitComposition copyTraitExpression on: newClass. "We have to manually unsubcribe the newClass from its traits. Later in the class-building phase newClass becomeForward: oldClass and hence we can no longer distinguish the two. Which would leave `newClass trait users`, an IdetitySet, in an invalid state, as it's elements have been modified (the becomeForward:) without a proper rehash." newClass traitComposition traits do: [ :trait | trait removeUser: newClass ]. ! ! !AbstractClassInstaller methodsFor: 'initialization' stamp: 'MartinDias 1/28/2014 15:13'! initialize builder := SlotClassBuilder new. builder installer: self! ! !AbstractClassInstaller methodsFor: 'notifications' stamp: 'ToonVerwaest 3/22/2011 18:38'! classDefinitionDeeplyChangedFrom: oldClass to: newClass by: classModification self subclassResponsibility! ! !AbstractClassInstaller methodsFor: 'accessing' stamp: 'ToonVerwaest 3/22/2011 17:42'! builder ^ builder! ! !AbstractClassInstaller methodsFor: 'accessing' stamp: 'ToonVerwaest 3/22/2011 17:45'! environment: anEnvironment self subclassResponsibility! ! !AbstractClassInstaller methodsFor: 'traits' stamp: 'MartinDias 6/24/2013 18:25'! installTraitComposition: aTraitComposition on: aClass self flag: 'Should probably send something else to test'. aClass setTraitComposition: aTraitComposition! ! !AbstractClassInstaller methodsFor: 'notifications' stamp: 'ToonVerwaest 3/22/2011 18:38'! classDefinitionShallowChangedFrom: oldClass to: newClass by: classModification self subclassResponsibility! ! !AbstractClassInstaller methodsFor: 'migrating' stamp: 'ToonVerwaest 3/22/2011 18:30'! migrateClasses: old to: new using: anInstanceModification self subclassResponsibility! ! !AbstractClassInstaller methodsFor: 'accessing' stamp: 'ToonVerwaest 3/22/2011 17:44'! classAt: aName ifAbsent: aBlock self subclassResponsibility! ! !AbstractClassInstaller methodsFor: 'notifications' stamp: 'ToonVerwaest 3/22/2011 17:44'! recategorize: aClass to: aCategory self subclassResponsibility! ! !AbstractClassInstaller methodsFor: 'accessing' stamp: 'CamilloBruni 6/28/2013 14:03'! environment self subclassResponsibility! ! !AbstractClassInstaller class methodsFor: 'building' stamp: 'ToonVerwaest 3/22/2011 19:12'! make: aBlock | builder | builder := self new builder. aBlock value: builder. ^ builder build! ! !AbstractClassModification commentStamp: ''! I represent a class modification. I content field modifications.! !AbstractClassModification methodsFor: 'accessing' stamp: 'MartinDias 4/12/2013 13:01'! layout: aLayout layout := aLayout. layout host: target. layout finalize. layout = target layout ifFalse: [ self computeChange ]! ! !AbstractClassModification methodsFor: 'private' stamp: 'MartinDias 7/11/2013 15:30'! propagate target subclassesDo: [ :subclass | propagations add: (ClassModificationPropagation propagate: self to: subclass) ]. "recursively propagate this change down" propagations do: [ :propagation | propagation propagate ] ! ! !AbstractClassModification methodsFor: 'accessing' stamp: 'MartinDias 7/11/2013 15:39'! allPropagationsDo: aBlock propagations do: [ :aPropagation | aBlock value: aPropagation. aPropagation allPropagationsDo: aBlock ]! ! !AbstractClassModification methodsFor: 'testing' stamp: 'MartinDias 1/28/2014 16:17'! isPropagation ^ self subclassResponsibility ! ! !AbstractClassModification methodsFor: 'public' stamp: 'ToonVerwaest 4/1/2011 17:49'! apply ^ newClass := target shallowCopy superclass: self superclass layout: layout! ! !AbstractClassModification methodsFor: 'private' stamp: 'ToonVerwaest 3/21/2011 01:20'! computeChange self checkSanity.! ! !AbstractClassModification methodsFor: 'accessing' stamp: 'ToonVerwaest 3/31/2011 19:53'! result ^ target! ! !AbstractClassModification methodsFor: 'accessing' stamp: 'ToonVerwaest 3/20/2011 13:50'! layout ^ layout! ! !AbstractClassModification methodsFor: 'accessing' stamp: 'ToonVerwaest 4/1/2011 17:49'! newClass ^ newClass! ! !AbstractClassModification methodsFor: 'accessing' stamp: 'ToonVerwaest 4/1/2011 17:24'! newLayout ^ layout! ! !AbstractClassModification methodsFor: 'initialization' stamp: 'ToonVerwaest 4/1/2011 03:31'! initialize propagations := OrderedCollection new.! ! !AbstractClassModification methodsFor: 'accessing' stamp: 'ToonVerwaest 4/1/2011 17:38'! oldLayout ^ target layout! ! !AbstractClassModification methodsFor: 'accessing' stamp: 'CamilloBruni 3/30/2011 19:27'! checkSanity layout checkSanity.! ! !AbstractClassModification methodsFor: 'accessing' stamp: 'ToonVerwaest 3/20/2011 19:40'! target ^ target! ! !AbstractClassModification methodsFor: 'accessing' stamp: 'ToonVerwaest 3/19/2011 15:57'! target: aTarget target := aTarget! ! !AbstractClassWidget commentStamp: 'NicolaiHess 7/26/2014 00:22'! AbstractClassWidget is an abstraction describing a widget used to manage a list of classes.! !AbstractClassWidget methodsFor: 'protocol' stamp: 'NicolaiHess 7/26/2014 13:39'! getClassesList ^ self subclassResponsibility! ! !AbstractClassWidget methodsFor: 'protocol' stamp: 'NicolaiHess 7/26/2014 13:59'! vScrollValue: aNumber ^ self subclassResponsibility! ! !AbstractClassWidget methodsFor: 'protocol' stamp: 'NicolaiHess 7/26/2014 13:39'! hasFocus ^ self subclassResponsibility! ! !AbstractClassWidget methodsFor: 'protocol' stamp: 'NicolaiHess 7/26/2014 13:59'! vScrollValue ^ self subclassResponsibility! ! !AbstractClassWidget methodsFor: 'item creation' stamp: 'NicolaiHess 7/26/2014 00:26'! buildClassesList ^ self subclassResponsibility ! ! !AbstractClassWidget methodsFor: 'protocol' stamp: 'NicolaiHess 8/9/2014 21:17'! resetClassList ^ self subclassResponsibility! ! !AbstractClassWidget methodsFor: 'protocol' stamp: 'NicolaiHess 8/9/2014 21:44'! resetClassSelection self subclassResponsibility ! ! !AbstractClassWidget methodsFor: 'drag and drop' stamp: 'NicolaiHess 7/30/2014 13:41'! dragPassengersFor: item inMorph: dragSource | transferType object | (dragSource isKindOf: PluggableListMorph) ifFalse: [^ nil ]. transferType := self dragTransferTypeForMorph: dragSource. object := item originalObject. transferType == #getClassItem: ifTrue: [ self model showGroups ifTrue: [ self model selectedGroup ifNil: [ ^ nil ] ifNotNil: [:g | g isFillable ifFalse: [ ^ nil ]]]. ^ self selectedClasses ifEmpty: [ { object } ] ]. ^ nil! ! !AbstractClassWidget methodsFor: 'drag and drop' stamp: 'NicolaiHess 7/27/2014 20:49'! wantsDroppedMorph: transferMorph event: anEvent inMorph: destinationLM | srcType dstType | "only want drops on lists (not, for example, on pluggable texts)" (destinationLM isKindOf: PluggableListMorph) ifFalse: [ ^ false ]. srcType := transferMorph dragTransferType. dstType := self dragTransferTypeForMorph: destinationLM. srcType == #getMethodItem: ifTrue: [ ^ dstType == #getClassItem: ]. srcType == #getCategoryItem: ifTrue: [ ^ dstType == #getClassItem: ]. ^ false! ! !AbstractClassWidget methodsFor: 'protocol' stamp: 'NicolaiHess 7/28/2014 21:40'! selectedClasses self subclassResponsibility ! ! !AbstractClassWidget methodsFor: 'protocol' stamp: 'NicolaiHess 7/26/2014 01:04'! takeKeyboardFocus ^ self subclassResponsibility! ! !AbstractClassWidget methodsFor: 'protocol' stamp: 'NicolaiHess 7/28/2014 21:39'! selectClass: aClass self subclassResponsibility ! ! !AbstractCompiler commentStamp: ''! I define the public API of compilers that can be used as system compilers (e.g. overriding #compiler on the class side).! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! evaluate: aString in: aContext to: aReceiver ^self source: aString; context: aContext; receiver: aReceiver; failBlock: [^ #failedDoit]; evaluate! ! !AbstractCompiler methodsFor: 'public access' stamp: 'MarcusDenker 7/27/2013 19:34'! translate self subclassResponsibility! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:09'! compiledMethodTrailer: aClass self subclassResponsibility! ! !AbstractCompiler methodsFor: 'public access' stamp: 'MarcusDenker 7/27/2013 19:25'! decompileMethod: aCompiledMethod self subclassResponsibility! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:10'! logged: aBoolean self subclassResponsibility! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! compileNoPattern: textOrStream in: aClass context: aContext notifying: aRequestor ifFail: aFailBlock ^self source: textOrStream; class: aClass; context: aContext; requestor: aRequestor; noPattern: true; failBlock: aFailBlock; translate! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:10'! useFaultyForParsing: anObject self subclassResponsibility! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! format: textOrStream in: aClass notifying: aRequestor ^self source: textOrStream; class: aClass; requestor: aRequestor; format ! ! !AbstractCompiler methodsFor: 'public access' stamp: 'MarcusDenker 7/27/2013 19:33'! compile self subclassResponsibility! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! evaluate: textOrString logged: logFlag ^ self source: textOrString; logged: logFlag; evaluate ! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! evaluate: textOrString notifying: aController logged: logFlag ^ self source: textOrString; logged: logFlag; requestor: aController; evaluate ! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! parse: aString class: aClass ^self source: aString; class: aClass; parse! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:09'! environment: anSmallTalkImage self subclassResponsibility! ! !AbstractCompiler methodsFor: 'public access' stamp: 'MarcusDenker 7/27/2013 19:32'! evaluate: textOrString ^self source: textOrString; evaluate! ! !AbstractCompiler methodsFor: 'public access' stamp: 'MarcusDenker 7/27/2013 19:33'! options: anArray self subclassResponsibility! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! evaluate: textOrStream in: aContext to: aReceiver notifying: aRequestor ifFail: aFailBlock ^self source: textOrStream; context: aContext; receiver: aReceiver; requestor: aRequestor; failBlock: aFailBlock; evaluate! ! !AbstractCompiler methodsFor: '*GT-SpotterExtensions-Core' stamp: 'StefanReichhart 3/23/2015 16:34'! silentlyDo: aBlock self silentlyDo: aBlock exceptionDo: [ " ignore " ]! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:09'! failBlock: aBlock self subclassResponsibility! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! compile: textOrStream in: aClass notifying: aRequestor ifFail: aFailBlock ^self source: textOrStream; class: aClass; requestor: aRequestor; failBlock: aFailBlock; translate ! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:10'! requestor: aRequestor self subclassResponsibility! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:09'! compilationContextClass: aClass self subclassResponsibility! ! !AbstractCompiler methodsFor: 'plugins' stamp: 'MarcusDenker 2/28/2015 15:32'! addPlugin: aClass "do nothing"! ! !AbstractCompiler methodsFor: 'public access' stamp: 'MarcusDenker 7/27/2013 19:34'! parse self subclassResponsibility! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! parse: textOrStream in: aClass notifying: req ^self source: textOrStream; class: aClass; requestor: req; translate.! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! parse: aString class: aClass noPattern: aBoolean context: aContext notifying: req ifFail: aBlock "Backwards compatibilty" ^self source: aString; class: aClass; noPattern: aBoolean; context: aContext; requestor: req; failBlock: aBlock; translate.! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:09'! context: aContext self subclassResponsibility! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:10'! noPattern: aBoolean self subclassResponsibility! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! evaluate: textOrStream in: aContext to: aReceiver notifying: aRequestor ifFail: aFailBlock logged: logFlag ^self source: textOrStream; context: aContext; receiver: aReceiver; requestor: aRequestor; failBlock: aFailBlock; logged: logFlag; evaluate! ! !AbstractCompiler methodsFor: 'public access' stamp: 'MarcusDenker 7/27/2013 19:34'! parseLiterals: aString self subclassResponsibility! ! !AbstractCompiler methodsFor: '*GT-SpotterExtensions-Core' stamp: 'StefanReichhart 3/23/2015 16:34'! silentlyDo: aBlock1 exceptionDo: aBlock2 aBlock1 on: Error, SyntaxErrorNotification, UndeclaredVariableWarning, OCSemanticWarning, OCSemanticError do: aBlock2! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:10'! receiver: anObject self subclassResponsibility! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:08'! compilationContext self subclassResponsibility! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:08'! class: aClass self subclassResponsibility! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! evaluate: textOrString for: anObject notifying: aController logged: logFlag ^ self source: textOrString; logged: logFlag; receiver: anObject; requestor: aController; evaluate ! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:09'! compilationContextClass self subclassResponsibility! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! compile: textOrStream in: aClass classified: aCategory notifying: aRequestor ifFail: aFailBlock ^self source: textOrStream; class: aClass; requestor: aRequestor; category: aCategory; failBlock: aFailBlock; translate! ! !AbstractCompiler methodsFor: 'public access' stamp: 'MarcusDenker 7/27/2013 19:33'! evaluate self subclassResponsibility! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:09'! compilationContext: anObject self subclassResponsibility! ! !AbstractCompiler methodsFor: 'public access' stamp: 'MarcusDenker 7/27/2013 19:33'! format self subclassResponsibility! ! !AbstractCompiler methodsFor: 'old - public' stamp: 'MarcusDenker 7/28/2013 15:06'! evaluate: textOrString for: anObject logged: logFlag ^self source: textOrString; logged: logFlag; receiver: anObject; evaluate! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:10'! source: aString self subclassResponsibility! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:10'! useFaultyForParsing self subclassResponsibility! ! !AbstractCompiler methodsFor: 'public access' stamp: 'MarcusDenker 7/27/2013 19:34'! parseSelector: aString self subclassResponsibility! ! !AbstractCompiler methodsFor: 'accessing' stamp: 'MarcusDenker 7/28/2013 15:08'! category: aCategory self subclassResponsibility! ! !AbstractCompiler class methodsFor: 'settings' stamp: 'ClementBera 1/27/2015 16:44'! compilerSettingsOn: aBuilder (aBuilder group: #compiler) label: 'Compiler'; with: [ (aBuilder pickOne: #compilerClass) target: SmalltalkImage; label: 'Default Compiler'; domainValues: AbstractCompiler subclasses. (aBuilder pickOne: #bytecodeBackend) target: CompilationContext; label: 'Bytecode Backend'; domainValues: {#V3PlusClosures -> EncoderForV3PlusClosures. #SistaV1 -> EncoderForSistaV1 }. (aBuilder setting: #warningAllowed) target: CompilationContext; label: 'Allow Warnings'; default: true]! ! !AbstractEcryptor commentStamp: ''! An AbstractEcryptor is an interface for encryptor. It's basically just an algorithm to encrypt a string, without ensuring it can be decrypted! !AbstractEcryptor methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 5/6/2012 22:08'! encrypt: aString ^ self subclassResponsibility! ! !AbstractEcryptorDecryptor commentStamp: ''! An AbstractEcryptorDecryptor is an interface providing the method for encrypting/decrypting a string! !AbstractEcryptorDecryptor methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 5/6/2012 22:07'! decrypt: aString base: aBase ^ self subclassResponsibility! ! !AbstractEcryptorDecryptor methodsFor: 'protocol' stamp: 'Camillo 5/15/2012 11:21'! encrypt: aString base: aBase ^ self subclassResponsibility! ! !AbstractEnumerationVisitor commentStamp: ''! I'm an abstract superclass for enumeration operations on directory entries. ! !AbstractEnumerationVisitor methodsFor: 'visiting' stamp: 'EstebanLorenzano 4/2/2012 11:37'! breadthFirst: aReference ^ self visit: aReference with: (BreadthFirstGuide for: self)! ! !AbstractEnumerationVisitor methodsFor: 'visiting' stamp: 'CamilloBruni 8/9/2011 15:48'! visitReference: anEntry self subclassResponsibility! ! !AbstractEnumerationVisitor methodsFor: 'visiting' stamp: 'CamilloBruni 8/9/2011 15:46'! visit: aReference with: aGuide out := (Array new: 10) writeStream. aGuide show: aReference. ^ out contents! ! !AbstractEnumerationVisitor methodsFor: 'visiting' stamp: 'EstebanLorenzano 4/2/2012 11:38'! preorder: aReference ^ self visit: aReference with: (PreorderGuide for: self)! ! !AbstractEnumerationVisitor methodsFor: 'visiting' stamp: 'EstebanLorenzano 4/2/2012 11:38'! postorder: aReference ^ self visit: aReference with: (PostorderGuide for: self)! ! !AbstractEnumerationVisitor methodsFor: 'initialization' stamp: 'CamilloBruni 8/9/2011 15:46'! initializeWithBlock: aBlock self initialize. block := aBlock! ! !AbstractEnumerationVisitorTest commentStamp: 'TorstenBergmann 1/31/2014 11:41'! SUnit tests for AbstractEnumerationVisitor! !AbstractEnumerationVisitorTest methodsFor: 'as yet unclassified' stamp: 'CamilloBruni 8/12/2011 15:45'! root ^ filesystem / 'alpha'! ! !AbstractEnumerationVisitorTest methodsFor: 'as yet unclassified' stamp: 'CamilloBruni 8/9/2011 16:01'! setUp super setUp. self setUpGreek.! ! !AbstractEnumerationVisitorTest methodsFor: 'as yet unclassified' stamp: 'CamilloBruni 4/10/2013 12:38'! assertEntries: references are: expected | strings | self assert: references isArray. references do: [ :ea | self assert: ea class = FileSystemDirectoryEntry ]. strings := references collect: [ :ea | ea reference pathString ]. self assert: strings equals: expected! ! !AbstractEnumerationVisitorTest class methodsFor: 'as yet unclassified' stamp: 'EstebanLorenzano 4/3/2012 09:42'! isAbstract ^ self name = #AbstractEnumerationVisitorTest! ! !AbstractEyeElement commentStamp: ''! I represent an abstract inspection element. In an EyeInspector, a eye element corresponds to a wrapper around a field element. Public API : label: display on left list panel of the eye inspector description: printed on the right panel of the eye inspector host: object inspected in the eye inspector value: object represented by this eye element ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'YuriyTymchuk 12/20/2013 11:32'! icon ^ (self value iconOrThumbnailOfSize: 16) ifNil: [ self value class systemIcon ]! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 4/30/2013 10:48'! description ^ self value printStringLimitedTo: 2000! ! !AbstractEyeElement methodsFor: 'action' stamp: 'CamilloBruni 4/30/2013 10:43'! browseValue ^ self value browse! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 2/25/2014 18:23'! errorWhileAccessing: selector do: aBlock [ self perform: selector ] on: Error do: [ :error | aBlock cull: error cull: selector ].! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 2/25/2014 18:29'! withErrorsDo: aBlock self errorPropertySelectors do: [ :selector | self errorWhileAccessing: selector do: aBlock ].! ! !AbstractEyeElement methodsFor: 'menu' stamp: 'CamilloBruni 4/30/2013 10:58'! customSubMenu: aMenu "Subclasse may add more menu items here"! ! !AbstractEyeElement methodsFor: 'action' stamp: 'CamilloBruni 4/30/2013 10:16'! exploreValue ^ self value explore! ! !AbstractEyeElement methodsFor: 'actions' stamp: ''! inspectInNewWindow: anObject anObject inspect! ! !AbstractEyeElement methodsFor: 'actions' stamp: ''! browseSelectedObjectClass self selectedObjectDo: [ :anObject | Smalltalk tools browser newOnClass: anObject class ]! ! !AbstractEyeElement methodsFor: 'testing' stamp: 'CamilloBruni 10/15/2013 17:14'! hasSelectedObject ^ true! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 10/15/2013 17:14'! selectedObject ^ self value! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 4/30/2013 10:58'! hostClass ^ host class! ! !AbstractEyeElement methodsFor: 'action' stamp: 'MarcusDenker 8/7/2014 11:36'! explorePointers ^ Smalltalk tools pointerExplorer openStrongOn: self value! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 4/30/2013 10:44'! value "Answers the object associated with this EyeElement." self subclassResponsibility! ! !AbstractEyeElement methodsFor: 'printing' stamp: 'CamilloBruni 4/30/2013 10:46'! printOn: aStream aStream print: self label; << '->'; << (self value printStringLimitedTo: 50)! ! !AbstractEyeElement methodsFor: 'menu' stamp: 'CamilloBruni 2/25/2014 18:16'! endSubMenu: aMenu aMenu addGroup: [ :aGroup | aGroup addItem: [ :anItem | anItem name: 'Copy Name'; action: [ self copyAccessorCode ]; shortcut: $c command mac | $c alt win | $c alt unix ] ]! ! !AbstractEyeElement methodsFor: 'actions' stamp: ''! browseSelectedObject self selectedObjectDo: [ :anObject | anObject browse ]! ! !AbstractEyeElement methodsFor: 'action' stamp: 'CamilloBruni 4/30/2013 10:20'! copyAccessorCode "Copy the name of the current variable, so the user can paste it into the window below and work with is." Clipboard clipboardText: self accessorCode asText! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 4/30/2013 10:32'! valueClass ^ self value class! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 4/30/2013 10:51'! host: anObject host := anObject! ! !AbstractEyeElement methodsFor: 'menu' stamp: 'CamilloBruni 2/25/2014 18:49'! errorSubMenu: aMenu "Add debug menu entries for the failing #errorPropertySelectors of this eye element" self hasError ifFalse: [ ^ self ]. aMenu addGroup: [ :aGroup | self withErrorsDo: [ :accessError :itemSelector | aGroup addItem: [ :anItem | anItem name: 'Debug Accessing ', itemSelector printString, ' of ', self accessorCode ; icon: Smalltalk ui icons smallWarningIcon; action: [ [ self perform: itemSelector] fork ]]]]! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 4/30/2013 10:52'! host "Answers the object currently inspected by the outer inspector. See #value for the object represented by this EyeElement." ^ host! ! !AbstractEyeElement methodsFor: 'action' stamp: 'CamilloBruni 10/15/2013 17:03'! inspectValue "Bring up a non-special inspector" ^ self value inspect! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'abc 10/18/2013 14:55'! selectedObjectDo: aBlock aBlock value: self selectedObject ! ! !AbstractEyeElement methodsFor: 'action' stamp: 'ClementBera 4/30/2013 11:37'! save: aValue "Subclasse may override this"! ! !AbstractEyeElement methodsFor: 'comparing' stamp: 'SvenVanCaekenberghe 3/30/2014 22:51'! hash ^ host hash! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 2/25/2014 18:30'! errorPropertySelectors "Return a collection of selectors on this eye-element that are checked against errors. See #withErrorsDo: and #errorSubMenu:" ^ #(icon label longLabel description)! ! !AbstractEyeElement methodsFor: 'menu' stamp: 'CamilloBruni 2/25/2014 18:15'! exploreSubMenu: aMenu aMenu addGroup: [ :aGroup | aGroup addItem: [ :anItem | anItem name: 'Explore Pointers'; action: [ self explorePointers ] ] ]! ! !AbstractEyeElement methodsFor: 'menu' stamp: 'GuillermoPolito 8/10/2014 14:13'! browseSubMenu: aMenu aMenu addGroup: [ :aGroup | aGroup addItem: [ :anItem | anItem name: 'Browse Full'; action: [ self browseSelectedObject ]; shortcut: PharoShortcuts current browseShortcut ]. aGroup addItem: [ :anItem | anItem name: 'Browse Class'; action: [ self browseSelectedObjectClass ] ]. aGroup addItem: [ :anItem | anItem name: 'Browse Hierarchy'; action: [ self browseSelectedObjectClassHierarchy ]; shortcut: $h command mac | $h alt win | $h alt unix ] ]! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'SvenVanCaekenberghe 3/7/2014 13:21'! longLabel "This is used by EyeTreeInspector" | description | description := self description. description size > 150 ifTrue: [ description := description first: 150 ]. ^ self label ifNotNil: [ :label | label , ': ' , description ] ifNil: [ description ]! ! !AbstractEyeElement methodsFor: 'action' stamp: 'CamilloBruni 10/15/2013 17:03'! browseValueClassHierarchy "Create and schedule a class list browser on the receiver's hierarchy." ^ self valueClass browseHierarchy! ! !AbstractEyeElement methodsFor: 'menu' stamp: 'CamilloBruni 2/25/2014 18:14'! inspectionMenu: aMenu "specific menu for the current element" self exploreSubMenu: aMenu; browseSubMenu: aMenu; customSubMenu: aMenu; endSubMenu: aMenu; errorSubMenu: aMenu.! ! !AbstractEyeElement methodsFor: 'action' stamp: 'CamilloBruni 10/15/2013 17:03'! browseValueClass "Open an class browser on the selectObject (class side)" ^ self valueClass browse! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 4/30/2013 10:21'! accessorCode "Answers a code string to access the value from the inspector" self subclassResponsibility! ! !AbstractEyeElement methodsFor: 'accessing' stamp: 'CamilloBruni 4/30/2013 10:45'! label "Answers the label associated with this EyeElement" self subclassResponsibility! ! !AbstractEyeElement methodsFor: 'menu' stamp: 'StephaneDucasse 10/22/2014 21:28'! mainInspectSubMenu: aMenu aMenu add: 'Inspect (i)' target: self selector: #inspectSelectedObjectInNewWindow. aMenu add: 'Explore (I)' target: self selector: #exploreSelectedObject.! ! !AbstractEyeElement methodsFor: 'comparing' stamp: 'IgorStasenko 8/14/2014 17:52'! = anObject self == anObject ifTrue: [ ^ true ]. self class = anObject class ifFalse: [ ^ false ]. ^ host == anObject host! ! !AbstractEyeElement methodsFor: 'actions' stamp: ''! browseSelectedObjectClassHierarchy self selectedObjectDo: [ :anObject | anObject class browseHierarchy ]! ! !AbstractEyeElement methodsFor: 'testing' stamp: 'CamilloBruni 2/25/2014 18:24'! hasError self withErrorsDo: [ ^ true ]. ^ false! ! !AbstractEyeElement methodsFor: 'actions' stamp: ''! exploreSelectedObject self selectedObjectDo: [ :anObject | anObject explore ].! ! !AbstractEyeElement methodsFor: 'actions' stamp: ''! inspectSelectedObjectInNewWindow self selectedObjectDo: [ :anObject | self inspectInNewWindow: anObject ].! ! !AbstractEyeElement methodsFor: 'testing' stamp: 'SvenVanCaekenberghe 3/14/2014 10:29'! shouldShowInTree ^ true! ! !AbstractEyeElement class methodsFor: 'instance creation' stamp: 'ClementBera 4/30/2013 11:20'! host: anObject ^ self new host: anObject; yourself! ! !AbstractFieldModification commentStamp: ''! I am an abstract field modification. Field modifications encapsulate the changes required to migrated instances.! !AbstractFieldModification methodsFor: 'installing' stamp: 'ToonVerwaest 3/28/2011 17:07'! installOn: aModification self subclassResponsibility! ! !AbstractFieldModification methodsFor: 'accessing' stamp: 'ToonVerwaest 3/28/2011 17:19'! fieldIndex: anObject fieldIndex := anObject! ! !AbstractFieldModification methodsFor: 'migrating' stamp: 'ToonVerwaest 3/28/2011 20:31'! migrateAt: index to: newInstance from: oldInstance! ! !AbstractFieldModification methodsFor: 'accessing' stamp: 'ToonVerwaest 3/28/2011 17:19'! fieldIndex ^ fieldIndex! ! !AbstractFileReference commentStamp: ''! I am an abstract superclass for FileLocator and FileReference. By implementing most of the methods on myself most code duplucation between the locator and the reference can be avoided! !AbstractFileReference methodsFor: 'testing' stamp: 'CamilloBruni 7/10/2012 15:04'! isRoot ^ self resolve isRoot! ! !AbstractFileReference methodsFor: 'testing' stamp: 'CamilloBruni 7/10/2012 15:05'! hasFiles ^self resolve hasFiles! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'CamilloBruni 7/10/2012 15:05'! resolve: anObject ^ anObject asResolvedBy: self! ! !AbstractFileReference methodsFor: 'streams-compatibility' stamp: 'MaxLeske 1/26/2014 20:49'! binaryReadStream ^ self subclassResponsibility! ! !AbstractFileReference methodsFor: 'comparing' stamp: 'CamilloBruni 9/5/2012 18:07'! isContainedBy: anObject "DoubleDispatch helper for #contains:" ^ anObject containsReference: self resolve! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 20:35'! filesMatching: patterns " FileSystem disk workingDirectory filesMatching: '*' FileSystem disk workingDirectory filesMatching: '*.image;*.changes' " ^ self childGeneratorBlock: [:reference : aBlock| reference fileSystem fileNamesAt: reference path do: aBlock ] matching: patterns ! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 20:37'! children "Answer an array containing references to the direct children of this reference." | reference | reference := self resolve. ^ (reference fileSystem childNamesAt: reference path) collect: [ :aName | self / aName ]! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 15:35'! allEntries ^ CollectVisitor breadthFirst: self resolve! ! !AbstractFileReference methodsFor: 'delegated' stamp: 'CamilloBruni 7/10/2012 15:04'! mimeTypes ^ self resolve mimeTypes! ! !AbstractFileReference methodsFor: 'operations' stamp: 'S 6/17/2013 13:24'! ensureCreateFile "Create if necessary a file for the receiver." self writeStream close. ! ! !AbstractFileReference methodsFor: 'delegated' stamp: 'CamilloBruni 7/10/2012 15:04'! parent ^ self withPath: self path parent! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 20:46'! allDirectories "Return all the directories recursively nested in the receiver." ^ (SelectVisitor breadthFirst: self resolve select: [:entry | entry isDirectory ]) collect: [ :each| each reference ]! ! !AbstractFileReference methodsFor: 'streams' stamp: 'CamilloBruni 7/10/2012 20:16'! openWritable: aBoolean ^ self resolve openWritable: aBoolean! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 20:51'! modificationTime ^ self resolve modificationTime ! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 15:30'! extension ^ self fullPath extension.! ! !AbstractFileReference methodsFor: 'delegated' stamp: 'CamilloBruni 7/10/2012 15:04'! macTypeAndCreator ^ self resolve macTypeAndCreator! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'CamilloBruni 7/10/2012 15:51'! relativeToReference: landmarkReference "Return the path of the receiver relative to landmarkReference." ^ self fullPath relativeTo: landmarkReference path! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'CamilloBruni 9/5/2012 11:26'! relativeTo: landmark "Answer a new path relative to landmark." "parent/child/grandChild relativeTo: parent returns child/grandChild (Filesystem disk / 'griffle' / 'plonk' / 'nurp') relativeTo: (Filesystem disk / 'griffle') returns plonk/nurp" ^ landmark makeRelative: self resolve! ! !AbstractFileReference methodsFor: '*Network-Url' stamp: 'SvenVanCaekenberghe 10/25/2013 17:12'! asUrl ^ self asZnUrl! ! !AbstractFileReference methodsFor: 'operations' stamp: 'S 6/17/2013 13:30'! moveTo: aReference "Move the receiver in the location passed as argument. (FileSystem disk workingDirectory / 'paf' ) ensureCreateFile. (FileSystem disk workingDirectory / 'fooFolder') ensureCreateDirectory. (FileSystem disk workingDirectory / 'paf' ) moveTo: (FileSystem disk workingDirectory / 'fooFolder' / 'paf') " ^ self resolve moveTo: aReference! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 20:43'! allChildren "Return all the files and folders recursively nested in the receiver" ^ CollectVisitor breadthFirst: self resolve collect: [:entry | entry reference]! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'PavelKrivanek 11/23/2012 12:21'! fullPath "Returns the absolute path, better use absolutePath" ^ self subclassResponsibility! ! !AbstractFileReference methodsFor: 'testing' stamp: 'PavelKrivanek 11/23/2012 12:21'! isRelative self subclassResponsibility ! ! !AbstractFileReference methodsFor: 'operations' stamp: 'S 6/17/2013 13:17'! delete "Delete the receiver, does raise an error if it is not present." ^ self resolve delete! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'StephaneDucasse 2/19/2015 18:03'! allDirectoriesMatching: aPattern "Return all the directories recursively nested in the receiver." ^ (SelectVisitor breadthFirst: self resolve select: [:entry | entry isDirectory and: [ aPattern match: entry basename ] ]) collect: [ :each | each reference ] ! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'CamilloBruni 7/10/2012 15:50'! relativeToPath: landmarkPath ^ self fullPath relativeTo: landmarkPath! ! !AbstractFileReference methodsFor: '*codeimport' stamp: 'CamilloBruni 7/10/2012 20:14'! fileIn self readStreamDo: [ :stream | CodeImporter evaluateFileStream: stream ]! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 15:47'! files "Return all the files (as opposed to folders) contained in the receiver" | reference | reference := self resolve. ^ (reference fileSystem fileNamesAt: reference path) collect: [ :aName | self withPath: self path / aName ]! ! !AbstractFileReference methodsFor: 'comparing' stamp: 'CamilloBruni 9/5/2012 18:02'! contains: anObject "Return true if anObject is in a subfolder of me" ^ anObject isContainedBy: self resolve! ! !AbstractFileReference methodsFor: 'streams' stamp: 'CamilloBruni 7/10/2012 15:26'! readStreamDo: doBlock ifAbsent: absentBlock ^ self isFile ifTrue: [ self readStreamDo: doBlock ] ifFalse: absentBlock! ! !AbstractFileReference methodsFor: 'operations' stamp: 'StephaneDucasse 5/22/2013 17:24'! createDirectory "Create a new repository and raise an error if the directory already exist." self resolve createDirectory! ! !AbstractFileReference methodsFor: 'testing' stamp: 'CamilloBruni 7/10/2012 20:19'! isWritable ^ self resolve isWritable! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 20:35'! childrenMatching: patterns " FileSystem disk workingDirectory childrenMatching: '*' FileSystem disk workingDirectory childrenMatching: '*.image;*.changes' " ^ self childGeneratorBlock: [:reference : aBlock| reference fileSystem childNamesAt: reference path do: aBlock ] matching: patterns ! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'StephaneDucasse 2/19/2015 18:02'! allChildrenMatching: aPattern "Return all the files and folders recursively nested in the receiver and matching the pattern, aPattern" ^ self allChildren select: [ :each | aPattern match: each basename ] ! ! !AbstractFileReference methodsFor: 'delegated' stamp: 'CamilloBruni 7/10/2012 15:04'! asPathWith: anObject ^ self resolve asPathWith: anObject! ! !AbstractFileReference methodsFor: 'testing' stamp: 'CamilloBruni 7/10/2012 20:17'! isChildOf: anObject ^ self parent = anObject! ! !AbstractFileReference methodsFor: 'operations' stamp: 'S 6/17/2013 13:20'! copyAllTo: aResolvable "Performs a deep copy of the receiver, to a location specified by the argument. If the receiver is a file, the file will be copied; if a directory, the directory and its contents will be copied recursively. The argument must be a reference that doesn't exist; it will be created by the copy." CopyVisitor copy: self resolve asAbsolute to: aResolvable resolve! ! !AbstractFileReference methodsFor: 'streams' stamp: 'CamilloBruni 7/10/2012 22:34'! streamWritable: writable do: aBlock ^ writable ifTrue: [ self writeStreamDo: aBlock ] ifFalse: [ self readStreamDo: aBlock ]! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 8/9/2012 11:38'! directoryNames ^ self directories collect: #basename! ! !AbstractFileReference methodsFor: 'streams-compatibility' stamp: 'MaxLeske 1/25/2014 22:48'! binaryReadStreamDo: doBlock ifAbsent: absentBlock ^ self isFile ifTrue: [ self binaryReadStreamDo: doBlock ] ifFalse: absentBlock! ! !AbstractFileReference methodsFor: 'utility' stamp: 'CamilloBruni 7/10/2012 15:04'! nextVersion ^ self resolve nextVersion! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 15:04'! entries ^ self resolve entries! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 22:05'! size ^ self resolve size! ! !AbstractFileReference methodsFor: 'printing' stamp: 'CamilloBruni 7/10/2012 20:15'! indicator "Returns a string indicating the type of reference: - '?' for a non existing reference', - '/' for a directory, - the empty string for a file." "When this framework gets more complete, it is possible to extend this behavior with the following indicators (taken from unix ls utility): - '*' for a regular file that is executable - '@' for a symbolic link - '|' for FIFOs - '=' for sockets - '>' for doors" ^ self exists ifTrue: [self isDirectory ifTrue: ['/'] ifFalse: [''] ] ifFalse: ['?']! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'CamilloBruni 7/10/2012 15:05'! withExtension: aString ^ self withPath: (self path withExtension: aString)! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 15:27'! extensions "#('foo' 'foo.tar' 'foo.tar.gz' 'foo.1.tar' 'foo.1.tar.gz') collect: [:thing| thing extensions] => #(#() #('tar') #('tar' 'gz') #('1' 'tar') #('1' 'tar' 'gz'))" ^ self fullPath extensions! ! !AbstractFileReference methodsFor: 'copying' stamp: 'PavelKrivanek 11/23/2012 12:21'! copyWithPath: newPath self subclassResponsibility! ! !AbstractFileReference methodsFor: 'testing' stamp: 'PavelKrivanek 11/23/2012 12:21'! isAbsolute self subclassResponsibility ! ! !AbstractFileReference methodsFor: 'resolving' stamp: 'CamilloBruni 7/10/2012 15:20'! asResolvedBy: anObject ^ anObject resolveReference: self! ! !AbstractFileReference methodsFor: 'private' stamp: 'StephaneDucasse 2/19/2015 18:04'! childGeneratorBlock: doBlock matching: patterns " FileSystem workingDirectory filesMatching: '*' FileSystem workingDirectory filesMatching: '*.image;*.changes' " | files reference| files := Set new. reference := self resolve. (patterns findTokens: ';', String crlf) do: [ :pattern | doBlock value: reference value: [ :basename| (pattern match: basename) ifTrue: [ files add: (self / basename) ]]]. ^files asOrderedCollection! ! !AbstractFileReference methodsFor: 'streams' stamp: 'CamilloBruni 7/10/2012 15:26'! readStreamDo: aBlock | stream | stream := self readStream. ^ [ aBlock value: stream ] ensure: [ stream close ]! ! !AbstractFileReference methodsFor: 'comparing' stamp: 'CamilloBruni 8/21/2013 17:51'! <= other ^ self path <= other path! ! !AbstractFileReference methodsFor: 'streams' stamp: 'CamilloBruni 7/10/2012 15:26'! readStreamIfAbsent: absentBlock ^ self isFile ifTrue: [ self readStream ] ifFalse: absentBlock! ! !AbstractFileReference methodsFor: 'testing' stamp: 'CamilloBruni 7/10/2012 15:04'! isReadable ^ self resolve isReadable! ! !AbstractFileReference methodsFor: 'operations' stamp: 'S 6/17/2013 13:29'! ensureDeleteAll "Delete this directory and all children of it, and does not raise an error if the file does not exist." self exists ifFalse: [ ^ self ]. self deleteAll ! ! !AbstractFileReference methodsFor: 'testing' stamp: 'CamilloBruni 7/10/2012 20:17'! ifFile: fBlock ifDirectory: dBlock ifAbsent: aBlock ^ self isFile ifTrue: fBlock ifFalse: [ self isDirectory ifTrue: dBlock ifFalse: aBlock ]! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'SvenVanCaekenberghe 10/27/2013 11:43'! uri "Convert my path into a file:// type url. For odd characters use %20 notation." ^ self asUrl! ! !AbstractFileReference methodsFor: 'operations' stamp: 'StephaneDucasse 5/22/2013 17:07'! deleteIfAbsent: aBlock "Delete the receiver, when it does not exist evaluate the block" self resolve deleteIfAbsent: aBlock! ! !AbstractFileReference methodsFor: 'converting' stamp: 'PavelKrivanek 11/23/2012 12:21'! asAbsolute self subclassResponsibility! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 15:04'! entry ^ self resolve entry! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'PavelKrivanek 11/23/2012 12:21'! absolutePath "Returns the absolute path" ^ self subclassResponsibility! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'PavelKrivanek 11/23/2012 12:21'! resolveString: aString self subclassResponsibility! ! !AbstractFileReference methodsFor: '*zinc-resource-meta-filesystem' stamp: 'SvenVanCaekenberghe 1/14/2013 10:01'! asZnUrl "Convert the receiver in a file:// ZnUrl. Only an absolute path can be represented as a file:// URL" ^ self asAbsolute path asZnUrl! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 20:45'! allFiles "Return all the files (not directories) recursively nested in the receiver." ^ (SelectVisitor breadthFirst: self resolve select: [:entry | entry isFile ]) collect: [ :each| each reference ]! ! !AbstractFileReference methodsFor: 'testing' stamp: 'CamilloBruni 7/10/2012 15:05'! hasDirectories ^self resolve hasDirectories! ! !AbstractFileReference methodsFor: 'delegated' stamp: 'CamilloBruni 7/10/2012 15:04'! exists ^ self resolve exists! ! !AbstractFileReference methodsFor: 'delegated' stamp: 'CamilloBruni 7/10/2012 15:04'! copyTo: aReference ^ self resolve copyTo: aReference resolve! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 15:30'! fullNameWithIndicator "Returns the basename with the indicator appended, i.e. /foo/gloops.taz basenameWithIndicator is '/foo/gloops.taz', whereras /foo basenameWithIndicator is '/foo/'" ^ self fullName, self indicator ! ! !AbstractFileReference methodsFor: 'delegated' stamp: 'CamilloBruni 7/10/2012 15:04'! fullName ^ self resolve fullName! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'CamilloBruni 7/10/2012 15:49'! makeRelative: anObject ^ anObject relativeToReference: self resolve! ! !AbstractFileReference methodsFor: 'operations' stamp: 'S 6/17/2013 13:26'! ensureCreateDirectory "Verifies that the directory does not exist and only creates if necessary. Do not remove files contained if they exist." ^ self resolve ensureCreateDirectory! ! !AbstractFileReference methodsFor: 'copying' stamp: 'CamilloBruni 2/21/2014 22:32'! , extension ^ self resolve, extension! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 15:47'! directories "Return all the directories (by opposition to files) contained in the receiver" | reference | reference := self resolve. ^ (reference fileSystem directoryNamesAt: reference path) collect: [ :aName | self withPath: self path / aName ]! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 15:01'! fileSystem ^ self resolve fileSystem! ! !AbstractFileReference methodsFor: 'streams' stamp: 'CamilloBruni 7/10/2012 15:24'! writeStreamDo: aBlock | stream | stream := self writeStream. ^ [ aBlock value: stream ] ensure: [ stream close ]! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 15:27'! base "Returns the base of the basename, i.e. /foo/gloops.taz base is 'gloops'" ^ self fullPath base! ! !AbstractFileReference methodsFor: 'testing' stamp: 'CamilloBruni 7/10/2012 15:05'! hasChildren ^self resolve hasChildren! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'CamilloBruni 7/10/2012 15:18'! resolvePath: aPath ^ self withPath: (self path resolvePath: aPath)! ! !AbstractFileReference methodsFor: 'streams' stamp: 'PavelKrivanek 11/23/2012 12:21'! writeStream self subclassResponsibility! ! !AbstractFileReference methodsFor: 'testing' stamp: 'CamilloBruni 7/10/2012 15:04'! isFile ^ self resolve isFile! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 15:28'! basenameWithoutExtension "Returns the basename, i.e. /foo/gloops.taz basenameWithoutExtension is 'gloops'" ^ self fullPath basenameWithoutExtension! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 15:28'! basename "Returns the basename, i.e. /foo/gloops.taz basename is 'gloops.taz'" ^ self fullPath basename! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'CamilloBruni 7/10/2012 20:36'! / aString ^ self withPath: self path / aString! ! !AbstractFileReference methodsFor: 'streams' stamp: 'CamilloBruni 7/10/2012 15:24'! writeStreamDo: doBlock ifPresent: presentBlock ^ self isFile ifTrue: presentBlock ifFalse: [ self writeStreamDo: doBlock ]! ! !AbstractFileReference methodsFor: 'operations' stamp: 'StephaneDucasse 5/22/2013 17:16'! deleteAllChildren "delete all children of the receiver, raise an error if the receiver does not exist" self children do: [:aReference | aReference deleteAll ]! ! !AbstractFileReference methodsFor: 'operations' stamp: 'S 6/17/2013 13:17'! ensureDelete "Delete the file and does not raise exception if it does not exist contrary to delete" self deleteIfAbsent: [].! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 20:51'! creationTime ^ self resolve creationTime ! ! !AbstractFileReference methodsFor: 'streams-compatibility' stamp: 'MaxLeske 1/25/2014 22:48'! binaryReadStreamDo: aBlock | stream | stream := self binaryReadStream. ^ [ aBlock value: stream ] ensure: [ stream close ]! ! !AbstractFileReference methodsFor: 'testing' stamp: 'CamilloBruni 7/10/2012 15:04'! isDirectory ^ self resolve isDirectory! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 22:12'! humanReadableSize ^ self size humanReadableSIByteSize! ! !AbstractFileReference methodsFor: 'streams-compatibility' stamp: 'MaxLeske 1/25/2014 22:49'! binaryReadStreamIfAbsent: absentBlock ^ self isFile ifTrue: [ self binaryReadStream ] ifFalse: absentBlock! ! !AbstractFileReference methodsFor: 'operations' stamp: 'S 6/17/2013 13:21'! deleteAll "Delete this directory and all children of it, raise an error if the file does not exist." DeleteVisitor delete: self resolve! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 15:35'! glob: aBlock ^ SelectVisitor breadthFirst: self resolve select: aBlock! ! !AbstractFileReference methodsFor: 'comparing' stamp: 'CamilloBruni 7/10/2012 15:32'! containsPath: aPath ^ self fullPath containsPath: aPath! ! !AbstractFileReference methodsFor: 'streams' stamp: 'CamilloBruni 7/10/2012 15:24'! writeStreamIfPresent: presentBlock ^ self isFile ifTrue: presentBlock ifFalse: [ self writeStream ]! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'CamilloBruni 7/10/2012 15:18'! resolveReference: aReference ^ aReference isAbsolute ifTrue: [ aReference ] ifFalse: [ self withPath: aReference path ]! ! !AbstractFileReference methodsFor: 'comparing' stamp: 'CamilloBruni 8/9/2012 12:31'! hash "Hash is reimplemented because #= is reimplemented" ^ self path hash! ! !AbstractFileReference methodsFor: 'delegated' stamp: 'BernardoContreras 2/20/2015 22:17'! parentUpTo: aParentDirName ^ self withPath: (self path parentUpTo: aParentDirName)! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 15:07'! basenameWithIndicator "Returns the basename with the indicator appended, i.e. /foo/gloops.taz basenameWithIndicator is 'gloops.taz', whereras /foo basenameWithIndicator is 'foo/'" ^ self basename, self indicator ! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 20:35'! directoriesMatching: patterns " FileSystem disk workingDirectory directoriesMatching: '*' FileSystem disk workingDirectory directoriesMatching: 'package-cache' " ^ self childGeneratorBlock: [:reference : aBlock| reference fileSystem directoryNamesAt: reference path do: aBlock ] matching: patterns ! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 7/10/2012 15:30'! fileNames ^ self files collect: #basename! ! !AbstractFileReference methodsFor: 'delegated' stamp: 'CamilloBruni 7/10/2012 15:04'! pathString ^ self resolve pathString! ! !AbstractFileReference methodsFor: 'streams' stamp: 'PavelKrivanek 11/23/2012 12:21'! readStream self subclassResponsibility! ! !AbstractFileReference methodsFor: 'converting' stamp: 'PavelKrivanek 11/23/2012 12:21'! asFileReference self subclassResponsibility ! ! !AbstractFileReference methodsFor: 'enumerating' stamp: 'CamilloBruni 8/9/2012 11:38'! childNames ^ self children collect: #basename! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 21:29'! permissions "Return the FileSystemPermission for this node" ^ self resolve permissions! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 1/23/2013 12:41'! item ^ self! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 7/10/2012 15:31'! pathSegments ^ self fullPath segments! ! !AbstractFileReference methodsFor: 'operations' stamp: 'PavelKrivanek 11/23/2012 12:21'! renameTo: newBasename self subclassResponsibility! ! !AbstractFileReference methodsFor: 'operations' stamp: 'S 6/17/2013 13:30'! ensureDeleteAllChildren "delete all children of the receiver and does not raise an error if the receiver does not exist" self exists ifFalse: [ ^ self ]. self deleteAllChildren! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'PavelKrivanek 11/23/2012 12:21'! resolve ^ self subclassResponsibility ! ! !AbstractFileReference methodsFor: 'navigating' stamp: 'CamilloBruni 7/10/2012 15:18'! withPath: newPath ^ self path == newPath ifTrue: [ self ] ifFalse: [ self copyWithPath: newPath ]! ! !AbstractFileReference methodsFor: 'accessing' stamp: 'CamilloBruni 6/13/2013 16:02'! contents self readStreamDo: [ :stream | ^ stream contents ]! ! !AbstractFont commentStamp: ''! AbstractFont defines the generic interface that all fonts need to implement.! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'tween 8/10/2006 07:13'! emphasisStringFor: emphasisCode "Answer a translated string that represents the attributes given in emphasisCode." ^self class emphasisStringFor: emphasisCode! ! !AbstractFont methodsFor: 'accessing' stamp: 'yo 1/7/2005 11:19'! ascent self subclassResponsibility. ! ! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'tween 7/29/2006 13:51'! displayUnderlineOn: aDisplayContext from: baselineStartPoint to: baselineEndPoint "display the underline if appropriate for the receiver"! ! !AbstractFont methodsFor: 'displaying' stamp: 'ar 5/19/2000 14:59'! displayString: aString on: aDisplayContext from: startIndex to: stopIndex at: aPoint kern: kernDelta "Draw the given string from startIndex to stopIndex at aPoint on the (already prepared) display context." ^self subclassResponsibility! ! !AbstractFont methodsFor: 'accessing' stamp: 'nk 3/22/2004 15:15'! textStyleName "Answer the name to be used as a key in the TextConstants dictionary." ^self familyName! ! !AbstractFont methodsFor: 'measuring' stamp: 'StephaneDucasse 5/28/2011 13:17'! widthOfString: aString aString ifNil: [^0]. ^self widthOfString: aString from: 1 to: aString size. " TextStyle default defaultFont widthOfString: 'zort' 21 "! ! !AbstractFont methodsFor: 'caching' stamp: 'nk 3/15/2004 18:47'! releaseCachedState ! ! !AbstractFont methodsFor: 'accessing' stamp: 'nk 5/26/2003 09:45'! isRegular ^false! ! !AbstractFont methodsFor: 'accessing' stamp: 'nk 8/31/2004 09:14'! height "Answer the height of the receiver, total of maximum extents of characters above and below the baseline." ^self subclassResponsibility! ! !AbstractFont methodsFor: 'displaying' stamp: 'ar 5/19/2000 14:59'! installOn: aDisplayContext foregroundColor: foregroundColor backgroundColor: backgroundColor "Install the receiver on the given DisplayContext (either BitBlt or Canvas) for further drawing operations." ^self subclassResponsibility! ! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'tween 3/10/2007 13:08'! kerningLeft: leftChar right: rightChar ^0! ! !AbstractFont methodsFor: 'measuring' stamp: 'StephaneDucasse 5/28/2011 13:17'! approxWidthOfText: aText "Return the width of aText -- quickly, and a little bit dirty. Used by lists morphs containing Text objects to get a quick, fairly accurate measure of the width of a list item." | w | (aText isNil or: [ aText size = 0 ]) ifTrue: [ ^ 0 ]. w := self widthOfString: aText asString. "If the text has no emphasis, just return the string size. If it is empasized, just approximate the width by adding about 20% to the width" ((aText runLengthFor: 1) = aText size and: [ (aText emphasisAt: 1) = 0 ]) ifTrue: [ ^ w ] ifFalse: [ ^ w * 6 // 5 ]! ! !AbstractFont methodsFor: 'accessing' stamp: 'yo 1/7/2005 11:20'! descentOf: aCharacter ^ self descent. ! ! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'tween 8/10/2006 07:16'! emphasisString "Answer a translated string that represents the receiver's emphasis." ^self emphasisStringFor: self emphasis! ! !AbstractFont methodsFor: '*Athens-Text' stamp: 'NicolaiHess 1/13/2015 12:33'! getPreciseHeight ^ self height! ! !AbstractFont methodsFor: 'accessing' stamp: 'nk 8/31/2004 09:14'! lineGrid "Answer the relative space between lines" ^self subclassResponsibility! ! !AbstractFont methodsFor: 'notifications' stamp: 'nk 4/2/2004 11:25'! pixelsPerInchChanged "The definition of TextStyle class>>pixelsPerInch has changed. Do whatever is necessary."! ! !AbstractFont methodsFor: 'accessing' stamp: 'nk 3/15/2004 18:57'! derivativeFonts ^#()! ! !AbstractFont methodsFor: 'accessing' stamp: 'ar 5/19/2000 14:57'! xTable "Return the xTable for the font. The xTable defines the left x-value for each individual glyph in the receiver. If such a table is not provided, the character scanner will ask the font directly for the appropriate width of each individual character." ^nil! ! !AbstractFont methodsFor: 'accessing' stamp: 'nk 4/2/2004 11:33'! pixelSize "Make sure that we don't return a Fraction" ^ TextStyle pointsToPixels: self pointSize! ! !AbstractFont methodsFor: 'displaying' stamp: 'yo 1/7/2005 11:36'! displayString: aString on: aDisplayContext from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY "Draw the given string from startIndex to stopIndex at aPoint on the (already prepared) display context." ^self subclassResponsibility! ! !AbstractFont methodsFor: 'accessing' stamp: 'nk 7/11/2004 21:15'! textStyle ^ TextStyle actualTextStyles detect: [:aStyle | aStyle fontArray includes: self] ifNone: [ TextStyle fontArray: { self } ]! ! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'tween 3/29/2007 13:43'! hasDistinctGlyphsForAll: asciiString "Answer true if the receiver has glyphs for all the characters in asciiString and no single glyph is shared by more than one character, false otherwise. The default behaviour is to answer true, but subclasses may reimplement" ^true! ! !AbstractFont methodsFor: 'measuring' stamp: 'StephaneDucasse 5/28/2011 13:17'! widthOfStringOrText: aStringOrText aStringOrText ifNil: [^0]. ^aStringOrText isText ifTrue:[self approxWidthOfText: aStringOrText ] ifFalse:[self widthOfString: aStringOrText ] ! ! !AbstractFont methodsFor: 'accessing' stamp: 'yo 1/7/2005 11:18'! ascentOf: aCharacter ^ self ascent. ! ! !AbstractFont methodsFor: '*Text-Scanning' stamp: 'tpr 10/3/2013 12:42'! scanMultibyteCharactersFrom: startIndex to: stopIndex in: aWideString with: aCharacterScanner rightX: rightX "scan a multibyte character string" ^aCharacterScanner scanMultibyteCharactersFrom: startIndex to: stopIndex in: aWideString rightX: rightX ! ! !AbstractFont methodsFor: 'testing' stamp: 'yo 2/12/2007 19:34'! isFontSet ^ false. ! ! !AbstractFont methodsFor: 'accessing' stamp: 'nk 8/31/2004 09:15'! familyName "Answer the name to be used as a key in the TextConstants dictionary." ^self subclassResponsibility! ! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'tween 7/29/2006 14:36'! displayStrikeoutOn: aDisplayContext from: baselineStartPoint to: baselineEndPoint "display the strikeout if appropriate for the receiver"! ! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'tween 3/31/2007 20:17'! linearWidthOf: aCharacter "This is the scaled, unrounded advance width." ^self widthOf: aCharacter! ! !AbstractFont methodsFor: '*Athens-Text' stamp: 'NicolaiHess 1/13/2015 12:34'! getPreciseDescent ^ self descent! ! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'tween 3/29/2007 13:32'! isSymbolFont "Answer true if the receiver is a Symbol font, false otherwise. The default is to answer false, subclasses can reimplement" ^false! ! !AbstractFont methodsFor: 'accessing' stamp: 'nk 4/2/2004 11:06'! baseKern ^0! ! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'ClementBera 7/26/2013 15:55'! widthAndKernedWidthOfLeft: leftCharacter right: rightCharacterOrNil into: aTwoElementArray "Set the first element of aTwoElementArray to the width of leftCharacter and the second element to the width of left character when kerned with rightCharacterOrNil. Answer aTwoElementArray" | w k | w := self widthOf: leftCharacter. rightCharacterOrNil ifNil: [ aTwoElementArray at: 1 put: w; at: 2 put: w] ifNotNil: [ k := self kerningLeft: leftCharacter right: rightCharacterOrNil. aTwoElementArray at: 1 put: w; at: 2 put: w+k]. ^ aTwoElementArray ! ! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'tween 3/29/2007 13:25'! hasGlyphsForAll: asciiString "Answer true if the receiver has glyphs for all the characters in asciiString, false otherwise. The default behaviour is to answer true, but subclasses may reimplement" ^true! ! !AbstractFont methodsFor: 'accessing' stamp: 'ar 5/19/2000 14:56'! characterToGlyphMap "Return the character to glyph mapping table. If the table is not provided the character scanner will query the font directly for the width of each individual character." ^nil! ! !AbstractFont methodsFor: '*Multilingual-OtherLanguages' stamp: 'tpr 10/3/2013 12:57'! scanMultibyteJapaneseCharactersFrom: startIndex to: stopIndex in: aWideString with: aCharacterScanner rightX: rightX "scan a multibyte Japanese character string" ^aCharacterScanner scanJapaneseCharactersFrom: startIndex to: stopIndex in: aWideString rightX: rightX ! ! !AbstractFont methodsFor: 'measuring' stamp: 'ar 5/19/2000 14:58'! widthOf: aCharacter "Return the width of the given character" ^self subclassResponsibility! ! !AbstractFont methodsFor: 'measuring' stamp: 'StephaneDucasse 12/29/2009 22:42'! widthOfString: aString from: firstIndex to: lastIndex "Measure the length of the given string between start and stop index" | resultX | resultX := 0. firstIndex to: lastIndex do: [ :i | resultX := resultX + (self widthOf: (aString at: i)) ]. ^ resultX! ! !AbstractFont methodsFor: 'accessing' stamp: 'yo 1/7/2005 11:20'! descent self subclassResponsibility. ! ! !AbstractFont methodsFor: '*FreeType-addition' stamp: 'tween 4/6/2007 12:58'! isSubPixelPositioned "Answer true if the receiver is currently using subpixel positioned glyphs, false otherwise. This affects how padded space sizes are calculated when composing text. Currently, only FreeTypeFonts are subPixelPositioned, and only when not Hinted" ^false ! ! !AbstractFont methodsFor: '*Text-Scanning' stamp: 'tpr 10/3/2013 12:42'! scanByteCharactersFrom: startIndex to: stopIndex in: aByteString with: aCharacterScanner rightX: rightX "scan a single byte character string" ^aCharacterScanner scanByteCharactersFrom: startIndex to: stopIndex in: aByteString rightX: rightX! ! !AbstractFont methodsFor: 'accessing' stamp: 'yo 1/7/2005 11:19'! basicDescentOf: aCharacter ^ self descent. ! ! !AbstractFont methodsFor: 'accessing' stamp: 'nk 4/1/2004 10:48'! pointSize self subclassResponsibility.! ! !AbstractFont methodsFor: 'accessing' stamp: 'yo 1/7/2005 11:18'! basicAscentOf: aCharacter ^ self ascent. ! ! !AbstractFont methodsFor: 'testing' stamp: 'nk 6/25/2003 12:54'! isTTCFont ^false! ! !AbstractFont class methodsFor: 'as yet unclassified' stamp: 'eem 6/11/2008 12:35'! emphasisStringFor: emphasisCode "Answer a translated string that represents the attributes given in emphasisCode." | emphases | emphasisCode = 0 ifTrue: [ ^'Normal' translated ]. emphases := (IdentityDictionary new) at: 1 put: 'Bold' translated; at: 2 put: 'Italic' translated; at: 4 put: 'Underlined' translated; at: 8 put: 'Narrow' translated; at: 16 put: 'StruckOut' translated; yourself. ^String streamContents: [ :s | | bit | bit := 1. [ bit < 32 ] whileTrue: [ | code | code := emphasisCode bitAnd: bit. code isZero ifFalse: [ s nextPutAll: (emphases at: code); space ]. bit := bit bitShift: 1 ]. s position isZero ifFalse: [ s skip: -1 ]. ]! ! !AbstractFont class methodsFor: 'class initialization' stamp: 'PavelKrivanek 6/1/2011 12:47'! initialize TextStyle addDependent: self.! ! !AbstractFont class methodsFor: 'updating' stamp: 'StephaneDucasse 6/2/2011 20:24'! update: anAspect anAspect == #textDPIChanged ifTrue: [ AbstractFont allSubInstancesDo: [ :font | font pixelsPerInchChanged ]].! ! !AbstractFont class methodsFor: '*system-settings-browser' stamp: 'alain.plantec 3/18/2009 14:49'! settingInputWidgetForNode: aSettingNode ^ aSettingNode inputWidgetForFont! ! !AbstractFontSelectorDialogWindow commentStamp: 'gvc 5/18/2007 13:04'! Dialog based font chooser with preview.! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/18/2007 13:07'! previewText: anObject "Set the value of previewText" previewText := anObject. self changed: #previewText! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 4/21/2009 17:07'! isUnderlined: anObject "Set the value of isUnderlined" isUnderlined := anObject. self changed: #isUnderlined! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 4/21/2009 17:21'! updateFromSelectedFont "Update our state based on the selected font." self subclassResponsibility! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 9/26/2008 15:35'! matchingFont "Answer the font that matches the selections." self subclassResponsibility! ! !AbstractFontSelectorDialogWindow methodsFor: 'actions' stamp: 'gvc 4/21/2009 17:48'! newContentMorph "Answer a new content morph." self textPreviewMorph: self newTextPreviewMorph. ^(self newColumn: { (self newRow: { self newGroupbox: 'Family' translated for: self newFontFamilyMorph. (self newColumn: { (self newGroupbox: 'Style' translated for: self newFontStyleButtonRowMorph) vResizing: #shrinkWrap. self newGroupbox: 'Point size' translated for: self newFontSizeMorph}) hResizing: #shrinkWrap}) vResizing: #spaceFill. (self newGroupbox: 'Preview' translated for: self textPreviewMorph) vResizing: #shrinkWrap}) minWidth: 350; minHeight: 400! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 15:19'! fontSizeIndex: anObject "Set the value of fontSizeIndex" fontSizeIndex := anObject. self updateSelectedFont! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 4/21/2009 17:33'! textEmphasisCode "Answer the current bitmask for the text emphasis." ^(((self isBold ifTrue: [1] ifFalse: [0]) bitOr: (self isItalic ifTrue: [2] ifFalse: [0])) bitOr: (self isUnderlined ifTrue: [4] ifFalse: [0])) bitOr: (self isStruckOut ifTrue: [16] ifFalse: [0])! ! !AbstractFontSelectorDialogWindow methodsFor: 'instance creation' stamp: 'gvc 8/7/2007 11:49'! newFontSizeMorph "Answer a list for the font size of the font." ^self newListFor: self list: #fontSizes selected: #fontSizeIndex changeSelected: #fontSizeIndex: help: nil! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 13:41'! textPreviewMorph "Answer the value of textPreviewMorph" ^ textPreviewMorph! ! !AbstractFontSelectorDialogWindow methodsFor: 'instance creation' stamp: 'gvc 5/3/2007 16:31'! newTextPreviewMorph "Answer a text entry morph for the preview of the font." ^(self newTextEditorFor: self getText: #previewText setText: nil getEnabled: nil) vResizing: #rigid; enabled: false; extent: 20@90! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 14:30'! fontSizeIndex "Answer the value of fontSizeIndex" ^ fontSizeIndex! ! !AbstractFontSelectorDialogWindow methodsFor: 'initialization' stamp: 'gvc 4/21/2009 17:22'! initialize "Initialize the receiver." self isBold: false; isItalic: false; isUnderlined: false; isStruckOut: false; previewText: self defaultPreviewText; fontFamilyIndex: 0; fontSizeIndex: 0. super initialize! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 15:19'! fontFamilyIndex: anObject "Set the value of fontFamilyIndex" fontFamilyIndex := anObject. self updateSelectedFont! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 15:12'! isStruckOut "Answer the value of isStruckOut" ^ isStruckOut! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 5/3/2007 15:31'! toggleStruckOut "Toggle the font struck out emphasis." self isStruckOut: self isStruckOut not. self updateSelectedFont! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 9/26/2008 15:49'! defaultFontFamilies "Answer the set of available fonts families that are supported in the font that they represent." self subclassResponsibility! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 4/21/2009 17:30'! previewText "Answer the value of previewText" ^previewText asText addAttribute: (TextEmphasis new emphasisCode: self textEmphasisCode)! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 15:12'! isItalic "Answer the value of isItalic" ^ isItalic! ! !AbstractFontSelectorDialogWindow methodsFor: 'instance creation' stamp: 'EstebanLorenzano 5/14/2013 09:44'! newStruckOutButtonMorph "Answer a button for the struck out emphasis of the font." ^self newButtonFor: self getState: #isStruckOut action: #toggleStruckOut arguments: nil getEnabled: nil labelForm: Smalltalk ui icons smallStrikeOutIcon help: 'Toggle struck-out font' translated! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 5/3/2007 15:31'! toggleItalic "Toggle the font italic emphasis." self isItalic: self isItalic not. self updateSelectedFont! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 15:40'! fontFamilies "Answer the set of available fonts families that are supported as Text objects in the font that they represent." ^fontFamilies ifNil: [ self fontFamilies: self defaultFontFamilies. fontFamilies]! ! !AbstractFontSelectorDialogWindow methodsFor: 'font description' stamp: 'gvc 5/3/2007 16:03'! fontSize "Answer the selected font size or nil if none." (self fontSizeIndex between: 1 and: self fontSizes size) ifFalse: [^nil]. ^self fontSizes at: self fontSizeIndex! ! !AbstractFontSelectorDialogWindow methodsFor: 'instance creation' stamp: 'EstebanLorenzano 5/14/2013 09:44'! newItalicButtonMorph "Answer a button for the italic emphasis of the font." ^self newButtonFor: self getState: #isItalic action: #toggleItalic arguments: nil getEnabled: nil labelForm: Smalltalk ui icons smallItalicIcon help: 'Toggle italic font' translated! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 13:41'! selectedFont "Answer the value of selectedFont" ^ selectedFont! ! !AbstractFontSelectorDialogWindow methodsFor: 'instance creation' stamp: 'EstebanLorenzano 5/14/2013 09:44'! newBoldButtonMorph "Answer a button for the boldness of the font." ^self newButtonFor: self getState: #isBold action: #toggleBold arguments: nil getEnabled: nil labelForm: Smalltalk ui icons smallBoldIcon help: 'Toggle bold font' translated! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 10/9/2007 14:19'! selectedFont: anObject "Set the value of selectedFont" selectedFont := anObject ifNil: [TextStyle defaultFont]. self updateFromSelectedFont! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 14:30'! fontFamilyIndex "Answer the value of fontFamilyIndex" ^ fontFamilyIndex! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 4/21/2009 17:07'! isStruckOut: anObject "Set the value of isStruckOut" isStruckOut := anObject. self changed: #isStruckOut! ! !AbstractFontSelectorDialogWindow methodsFor: 'instance creation' stamp: 'gvc 8/7/2007 11:49'! newFontFamilyMorph "Answer a list for the font family of the font." |highestFont| highestFont := self fontFamilies first fontAt: 1 withStyle: TextStyle default. self fontFamilies do: [:ff | |f| f := ff fontAt: 1 withStyle: TextStyle default. f height > highestFont height ifTrue: [highestFont := f]]. ^(self newListFor: self list: #fontFamilies selected: #fontFamilyIndex changeSelected: #fontFamilyIndex: help: nil) font: highestFont! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 5/3/2007 15:31'! toggleBold "Toggle the font bold emphasis." self isBold: self isBold not. self updateSelectedFont! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 15:47'! familyName "Answer the selected family name or nil if none." (self fontFamilyIndex between: 1 and: self fontFamilies size) ifFalse: [^nil]. ^(self fontFamilies at: self fontFamilyIndex) asString! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 4/21/2009 17:07'! isItalic: anObject "Set the value of isItalic" isItalic := anObject. self changed: #isItalic! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 9/26/2008 15:31'! defaultPreviewText "Answer the default text to use for the preview of the font." ^(33 to: 127) asByteArray asString! ! !AbstractFontSelectorDialogWindow methodsFor: 'instance creation' stamp: 'EstebanLorenzano 5/14/2013 09:44'! newUnderlinedButtonMorph "Answer a button for the italic emphasis of the font." ^self newButtonFor: self getState: #isUnderlined action: #toggleUnderlined arguments: nil getEnabled: nil labelForm: Smalltalk ui icons smallUnderlineIcon help: 'Toggle underlined font' translated! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 5/3/2007 14:31'! fontSizes "Answer the set of available fonts sizes that are supported." ^#(6 7 8 9 10 11 12 13 14 15 16 18 20 21 22 24 26 28 32 36 48)! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 15:02'! fontFamilies: anObject "Set the value of fontFamilies" fontFamilies := anObject! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 13:41'! textPreviewMorph: anObject "Set the value of textPreviewMorph" textPreviewMorph := anObject! ! !AbstractFontSelectorDialogWindow methodsFor: 'instance creation' stamp: 'gvc 4/21/2009 17:48'! newFontStyleButtonRowMorph "Answer a new font style button row morph." ^self newRow: { self newBoldButtonMorph. self newItalicButtonMorph. self newUnderlinedButtonMorph. self newStruckOutButtonMorph}! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 15:12'! isBold "Answer the value of isBold" ^ isBold! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 5/3/2007 15:12'! isUnderlined "Answer the value of isUnderlined" ^ isUnderlined! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 5/3/2007 15:31'! toggleUnderlined "Toggle the font underlined emphasis." self isUnderlined: self isUnderlined not. self updateSelectedFont! ! !AbstractFontSelectorDialogWindow methodsFor: 'as yet unclassified' stamp: 'gvc 5/4/2007 10:25'! updateSelectedFont "Update the selected font to reflect the choices." self selectedFont: self matchingFont! ! !AbstractFontSelectorDialogWindow methodsFor: 'accessing' stamp: 'gvc 4/21/2009 17:07'! isBold: anObject "Set the value of isBold" isBold := anObject. self changed: #isBold! ! !AbstractFontSelectorDialogWindow class methodsFor: '*Polymorph-TaskbarIcons' stamp: 'EstebanLorenzano 5/14/2013 09:44'! taskbarIcon "Answer the icon for the receiver in a task bar." ^ Smalltalk ui icons smallFontsIcon! ! !AbstractGroup commentStamp: ''! AbstractGroup is an abstraction of what a group is.! !AbstractGroup methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 3/18/2011 14:00'! beReadOnly readOnly := true! ! !AbstractGroup methodsFor: 'polymorphism' stamp: 'BenjaminVanRyseghem 3/28/2011 13:50'! blocks ^ { [ self elements ] }! ! !AbstractGroup methodsFor: 'queries' stamp: 'BenjaminVanRyseghem 2/25/2012 15:32'! protocolsFor: aClass ^ aClass protocols select: [:e | self methods anySatisfy: [:m | m category = e ]].! ! !AbstractGroup methodsFor: 'announcements registration' stamp: 'BernardoContreras 10/7/2014 11:52'! registerToMethodAnnouncements SystemAnnouncer uniqueInstance weak when: MethodModified send: #methodModified: to: self; when: MethodRemoved send: #methodRemoved: to: self.! ! !AbstractGroup methodsFor: '*Nautilus' stamp: 'EstebanLorenzano 10/10/2013 16:10'! asNautilusSelection ^ PackageTreeGroupSelection group: self! ! !AbstractGroup methodsFor: 'announcements registration' stamp: 'BernardoContreras 10/7/2014 11:51'! registerToClassAnnouncements SystemAnnouncer uniqueInstance weak when: ClassRemoved send: #classRemoved: to: self! ! !AbstractGroup methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 3/2/2012 17:07'! isFillable: aBoolean isFillable := aBoolean! ! !AbstractGroup methodsFor: 'queries' stamp: 'EstebanLorenzano 10/9/2013 17:23'! packages ^ (self classes collect: #package as: Set) asArray! ! !AbstractGroup methodsFor: 'announcements' stamp: 'BenjaminVanRyseghem 4/14/2012 12:22'! methodRemoved: anAnnouncement self subclassResponsibility! ! !AbstractGroup methodsFor: 'initialization' stamp: 'BenjaminVanRyseghem 4/14/2012 12:17'! initialize super initialize. readOnly := false. self registerToAnnouncements.! ! !AbstractGroup methodsFor: 'printing' stamp: 'BenjaminVanRyseghem 3/29/2011 11:20'! printOn: aStream | className article | className := self class name. article := className first isVowel ifTrue: ['an'] ifFalse: ['a']. aStream nextPutAll: article; nextPut: Character space; nextPutAll: className; nextPutAll: ' ( '; nextPutAll: self name asString; nextPutAll: ' )'.! ! !AbstractGroup methodsFor: 'queries' stamp: 'BenjaminVanRyseghem 2/25/2012 16:57'! methodsFor: aClass categorised: aSymbol aSymbol ifNil: [ "all" ^ self methodsFor: aClass ]. ^ self methods select: [:e | e methodClass = aClass and: [ e category = aSymbol ]].! ! !AbstractGroup methodsFor: 'private' stamp: 'BenjaminVanRyseghem 3/18/2011 16:57'! ifAllowed: aBlock ^ self ifAllowed: aBlock ifNot: []! ! !AbstractGroup methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 3/2/2012 17:14'! isFillable ^ isFillable ifNil: [ isFillable := false ]! ! !AbstractGroup methodsFor: '*Nautilus' stamp: 'NicolaiHess 4/2/2015 17:22'! asNautilusItemPath ^ Array with: self name! ! !AbstractGroup methodsFor: 'private' stamp: 'BenjaminVanRyseghem 3/24/2011 13:16'! sortBlock: aBlock sortBlock := aBlock! ! !AbstractGroup methodsFor: 'queries' stamp: 'BenjaminVanRyseghem 2/25/2012 15:26'! methods ^ self elements! ! !AbstractGroup methodsFor: 'testing' stamp: 'BenjaminVanRyseghem 3/24/2011 13:41'! removable ^ removable ifNil: [ removable := true ]! ! !AbstractGroup methodsFor: 'queries' stamp: 'BenjaminVanRyseghem 2/25/2012 15:28'! classes ^ self subclassResponsibility! ! !AbstractGroup methodsFor: '*Nautilus' stamp: 'GuillermoPolito 8/10/2014 13:14'! categoryName "This is the package name set if a class is intended to be created in this group" ^ 'Unknown'! ! !AbstractGroup methodsFor: 'announcements' stamp: 'BenjaminVanRyseghem 4/14/2012 12:22'! methodModified: anAnnouncement self subclassResponsibility! ! !AbstractGroup methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 3/24/2011 13:39'! removable: aBoolean removable := aBoolean! ! !AbstractGroup methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 3/18/2011 14:22'! elements ^ self subclassResponsibility! ! !AbstractGroup methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 3/18/2011 14:04'! name: aString self ifAllowed: [ name := aString ]! ! !AbstractGroup methodsFor: 'testing' stamp: 'BenjaminVanRyseghem 4/14/2011 21:55'! isReadOnly ^ readOnly == true! ! !AbstractGroup methodsFor: 'announcements' stamp: 'BenjaminVanRyseghem 4/14/2012 12:22'! classRemoved: anAnnouncement self subclassResponsibility! ! !AbstractGroup methodsFor: 'announcements registration' stamp: 'BenjaminVanRyseghem 4/14/2012 12:38'! registerToAnnouncements self registerToClassAnnouncements; registerToMethodAnnouncements! ! !AbstractGroup methodsFor: 'queries' stamp: 'BenjaminVanRyseghem 2/25/2012 15:38'! methodsFor: aClass ^ self methods select: [:e | e methodClass = aClass ].! ! !AbstractGroup methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 3/18/2011 14:03'! name ^ name! ! !AbstractGroup methodsFor: 'private' stamp: 'BenjaminVanRyseghem 3/18/2011 16:57'! ifAllowed: aBlock ifNot: anotherBlock ^ self isReadOnly ifTrue: anotherBlock ifFalse: aBlock! ! !AbstractGroup methodsFor: 'private' stamp: 'BenjaminVanRyseghem 3/24/2011 13:20'! sortBlock ^ sortBlock ifNil: [ sortBlock := [:a :b | a printString <= b printString ]]! ! !AbstractGroup class methodsFor: 'instance creation' stamp: 'StephaneDucasse 11/30/2013 17:23'! cleanUp self unsubscribeExistingGroups.! ! !AbstractGroup class methodsFor: 'instance creation' stamp: 'MarianoMartinezPeck 8/5/2012 15:56'! new | instance | instance := self basicNew initialize. GroupAnnouncer uniqueInstance announce: (AGroupHasBeenCreated group: instance). ^ instance! ! !AbstractGroup class methodsFor: 'instance creation' stamp: 'StephaneDucasse 11/30/2013 17:24'! unsubscribeExistingGroups "self unsubscribeExistingGroups" self allSubInstances do: [ :each | SystemAnnouncer uniqueInstance unsubscribe: each ]. ! ! !AbstractGroup class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 3/18/2011 14:06'! named: aString ^ self new name: aString! ! !AbstractGroupAnnouncement commentStamp: 'TorstenBergmann 2/4/2014 21:09'! Common superclass for group announcements! !AbstractGroupAnnouncement methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 4/14/2011 16:31'! holder ^ holder! ! !AbstractGroupAnnouncement methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 4/14/2011 16:31'! group ^ group! ! !AbstractGroupAnnouncement methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 4/14/2011 16:31'! group: anObject group := anObject! ! !AbstractGroupAnnouncement methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 4/14/2011 16:31'! holder: anObject holder := anObject! ! !AbstractGroupAnnouncement class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 4/14/2011 22:40'! group: aGroup ^ self new group: aGroup; yourself! ! !AbstractGroupAnnouncement class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 4/14/2011 16:32'! group: aGroup from: anHolder ^ self new group: aGroup; holder: anHolder; yourself! ! !AbstractKeyPressedPlugin commentStamp: 'StephaneDucasse 10/30/2014 07:36'! AbstractKeyPressedPlugin is an abstract plugin which reacts to key strokes by sending the message keyPressed to the plugin.! !AbstractKeyPressedPlugin methodsFor: 'registration' stamp: 'BernardoContreras 10/22/2014 19:11'! registerTo: aModel aModel announcer when: NautilusKeyPressed send: #keyPressed: to: self! ! !AbstractKeyPressedPlugin methodsFor: 'announcement' stamp: 'BenjaminVanRyseghem 5/4/2011 15:05'! keyPressed: anAnnouncement self subclassResponsibility! ! !AbstractKeymappingTest methodsFor: 'as yet unclassified' stamp: 'GuillermoPolito 5/31/2011 19:51'! eventKey: character ^ self eventKey: character alt: false ctrl: false command: false shift: false! ! !AbstractKeymappingTest methodsFor: 'as yet unclassified' stamp: 'GuillermoPolito 2/19/2011 18:44'! tearDown KMRepository default: default! ! !AbstractKeymappingTest methodsFor: 'as yet unclassified' stamp: 'GuillermoPolito 5/31/2011 19:52'! eventKey: character shift: aBoolean ^ self eventKey: character alt: false ctrl: false command: false shift: aBoolean! ! !AbstractKeymappingTest methodsFor: 'as yet unclassified' stamp: 'GuillermoPolito 5/31/2011 19:52'! eventKey: character command: aBoolean ^ self eventKey: character alt: false ctrl: false command: aBoolean shift: false! ! !AbstractKeymappingTest methodsFor: 'as yet unclassified' stamp: 'GuillermoPolito 5/31/2011 19:51'! eventKey: character ctrl: aBoolean ^ self eventKey: character alt: false ctrl: aBoolean command: false shift: false! ! !AbstractKeymappingTest methodsFor: 'as yet unclassified' stamp: 'GuillermoPolito 5/31/2011 19:51'! eventKey: character alt: aBoolean ^ self eventKey: character alt: aBoolean ctrl: false command: false shift: false! ! !AbstractKeymappingTest methodsFor: 'as yet unclassified' stamp: 'GuillermoPolito 2/19/2011 18:44'! setUp default := KMRepository default. KMRepository default: KMRepository new! ! !AbstractKeymappingTest methodsFor: 'as yet unclassified' stamp: 'GuillermoPolito 5/31/2011 19:51'! eventKey: character alt: useAlt ctrl: useCtrl command: useCommand shift: useShift | event modifier code | event := KeyboardEvent new. modifier := 0. useShift ifTrue: [ modifier := modifier + 8]. useCtrl ifTrue: [ modifier := modifier + 16]. useAlt ifTrue: [ modifier := modifier + 32]. useCommand ifTrue: [ modifier := modifier + 64]. code := character asInteger. event setType: #keystroke buttons: modifier position: 0@0 keyValue: code charCode: code hand: nil stamp: Time now. ^ event ! ! !AbstractLayout commentStamp: ''! I'm a container for slots. There are special cases of layouts without slots, like NilLayout or BitsLayout.! !AbstractLayout methodsFor: 'accessing' stamp: 'ToonVerwaest 4/7/2011 12:10'! resolveSlot: aName self flag: 'Signal rather than error'. self error: 'No slots found'! ! !AbstractLayout methodsFor: 'accessing' stamp: 'ToonVerwaest 4/1/2011 03:38'! instanceVariables ^ {}! ! !AbstractLayout methodsFor: 'testing' stamp: 'ToonVerwaest 4/1/2011 03:37'! hasFields ^ false! ! !AbstractLayout methodsFor: 'accessing' stamp: 'MarcusDenker 6/25/2014 12:56'! slots ^ {}! ! !AbstractLayout methodsFor: 'accessing' stamp: 'MartinDias 8/6/2012 22:31'! slotScope ^ LayoutEmptyScope instance! ! !AbstractLayout methodsFor: 'testing' stamp: 'ToonVerwaest 4/1/2011 03:37'! hasSlots ^ false! ! !AbstractLayout methodsFor: 'validation' stamp: 'MartinDias 7/8/2013 17:22'! checkIntegrity self checkSanity! ! !AbstractLayout methodsFor: 'accessing' stamp: 'ToonVerwaest 4/1/2011 03:37'! fieldSize ^ 0! ! !AbstractLayout methodsFor: 'api' stamp: 'MarcusDenker 4/9/2015 10:08'! hasSlot: aSlot ^ self allSlots identityIncludes: aSlot ! ! !AbstractLayout methodsFor: 'accessing' stamp: 'MarcusDenker 2/5/2015 15:47'! visibleSlots ^self slots select: [:slot | slot isVisible]! ! !AbstractLayout methodsFor: 'testing' stamp: 'ToonVerwaest 4/1/2011 03:37'! isVariable ^ false! ! !AbstractLayout methodsFor: 'accessing' stamp: 'MartinDias 8/7/2013 17:56'! host: aClass host := aClass! ! !AbstractLayout methodsFor: 'testing' stamp: 'ToonVerwaest 4/1/2011 03:37'! isWeak ^ false! ! !AbstractLayout methodsFor: 'accessing' stamp: 'ToonVerwaest 4/1/2011 01:52'! host ^ host! ! !AbstractLayout methodsFor: 'comparing' stamp: 'MartinDias 4/12/2013 13:20'! hash ^ self class hash! ! !AbstractLayout methodsFor: 'finalization' stamp: 'ToonVerwaest 4/7/2011 12:08'! finalize self allSlotsDo: [ :aSlot | aSlot finalize: self ]! ! !AbstractLayout methodsFor: 'enumerating' stamp: 'MartinDias 8/7/2012 00:42'! allSlotsDo: aBlock self slotScope allSlotsDo: aBlock! ! !AbstractLayout methodsFor: 'testing' stamp: 'ToonVerwaest 4/1/2011 03:37'! isBits ^ false! ! !AbstractLayout methodsFor: 'api' stamp: 'MarcusDenker 4/9/2015 10:08'! definesSlot: aSlot ^self slots identityIncludes: aSlot ! ! !AbstractLayout methodsFor: 'accessing' stamp: 'ToonVerwaest 4/3/2011 22:58'! allSlots ^ {}! ! !AbstractLayout methodsFor: 'comparing' stamp: 'MartinDias 4/12/2013 13:15'! = other ^ self class = other class! ! !AbstractLayout methodsFor: 'validation' stamp: 'ToonVerwaest 4/1/2011 03:38'! checkSanity host ifNil: [ self error: 'Host should not be nil' ].! ! !AbstractLayout methodsFor: '*Glamour-Morphic-Brick' stamp: 'AliakseiSyrel 1/22/2015 13:14'! slotsDictionary ^ Dictionary new! ! !AbstractLayout methodsFor: 'api' stamp: 'MarcusDenker 4/9/2015 10:08'! hasSlotNamed: aString ^self allSlots anySatisfy: [:slot | slot name = aString ]! ! !AbstractLayout methodsFor: 'accessing' stamp: 'ToonVerwaest 4/2/2011 19:07'! allVisibleSlots ^ {}! ! !AbstractMethodConverter commentStamp: ''! An AbstractMessageConverter is a wrapper used to switch which information to retrieve from a method. This way, you can avoid switch case, you just have to use set the correct filter! !AbstractMethodConverter methodsFor: 'accessing' stamp: ''! method ^ method! ! !AbstractMethodConverter methodsFor: 'accessing' stamp: ''! method: aMessage method := aMessage! ! !AbstractMethodConverter methodsFor: 'protocol' stamp: ''! getTextFor: aMethod method := aMethod. method ifNil: [ ^ '' ]. ^ self internalGetText! ! !AbstractMethodConverter methodsFor: 'initialization' stamp: ''! shouldShout ^ false! ! !AbstractMethodConverter methodsFor: 'private' stamp: ''! internalGetText ^ self subclassResponsibility! ! !AbstractMethodConverter methodsFor: 'protocol' stamp: ''! getText method ifNil: [ ^ '' ]. ^ self internalGetText! ! !AbstractMethodConverter class methodsFor: 'instance creation' stamp: ''! method: aMessage ^ self new method: aMessage; yourself! ! !AbstractMethodIconAction commentStamp: ''! AbstractMethodIconAction is the common super class for all the method icon actions. A method icon action is used to retrieve the correct icon the method in nautilus lists! !AbstractMethodIconAction methodsFor: 'order' stamp: 'BenjaminVanRyseghem 1/2/2013 12:41'! isActionHandled "Return true if the provided method fits this action requirement" ^ self subclassResponsibility! ! !AbstractMethodIconAction methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 1/2/2013 12:16'! method: aMethod method := aMethod! ! !AbstractMethodIconAction methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 1/2/2013 12:33'! browser: aBrowser browser := aBrowser! ! !AbstractMethodIconAction methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 1/2/2013 12:33'! browser ^ browser! ! !AbstractMethodIconAction methodsFor: 'order' stamp: 'BenjaminVanRyseghem 1/2/2013 12:53'! actionStateToCache "Return the state of the icon for caching purpose" ^ IconicButtonStateHolder forNautilus: icon! ! !AbstractMethodIconAction methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 1/2/2013 12:34'! method ^ method! ! !AbstractMethodIconAction methodsFor: 'order' stamp: 'BenjaminVanRyseghem 1/2/2013 12:50'! privateActionIcon ^ self subclassResponsibility! ! !AbstractMethodIconAction methodsFor: 'order' stamp: 'BenjaminVanRyseghem 1/2/2013 12:50'! actionIcon "Return the icon for this action" ^ icon := self privateActionIcon! ! !AbstractMethodIconAction methodsFor: 'order' stamp: 'BenjaminVanRyseghem 1/2/2013 12:24'! actionOrder "Return the priority of this action" ^ self subclassResponsibility! ! !AbstractMethodIconAction class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 1/2/2013 12:34'! for: aMethod in: aBrowser ^ self new method: aMethod; browser: aBrowser; yourself! ! !AbstractMethodReferenceConverter commentStamp: 'TorstenBergmann 2/20/2014 13:48'! Abstract wrapper for method references! !AbstractMethodReferenceConverter methodsFor: 'private' stamp: ''! priorVersionOfAMethod: aMethodReference | tempList | tempList := referencesList select:[:each | (each className = aMethodReference className) & (each name = aMethodReference name)]. ^ tempList detect: [:each | (self versionOfAMethod: each) = ((self versionOfAMethod: aMethodReference) -1)] ifNone: [aMethodReference].! ! !AbstractMethodReferenceConverter methodsFor: 'accessing' stamp: ''! referencesList: aListOfReferences referencesList := aListOfReferences! ! !AbstractMethodReferenceConverter methodsFor: 'initialization' stamp: 'CamilloBruni 7/17/2013 22:52'! initialize super initialize. referencesList := #()! ! !AbstractMethodReferenceConverter methodsFor: 'private' stamp: ''! versionOfAMethod: aMethodReference | tempList | tempList := referencesList select: [:each | (each className = aMethodReference className) & (each name = aMethodReference name)]. tempList := tempList sort: [:m1 :m2 | m1 timeStamp < m2 timeStamp]. ^ tempList identityIndexOf: aMethodReference ifAbsent: [0]! ! !AbstractMethodReferenceConverter class methodsFor: 'instance creation' stamp: 'MarcusDenker 8/13/2014 15:18'! methodReference: aMessage referencesList: aListOfReferences ^ (self method: aMessage) referencesList: aListOfReferences; yourself! ! !AbstractMethodUpdateStrategy commentStamp: ''! I am used to update compiled methods in response to class modifications. My sublcasses implement different strategies to update affected methods.! !AbstractMethodUpdateStrategy methodsFor: 'updating' stamp: 'MartinDias 7/30/2012 00:08'! transform: oldClass to: newClass using: aMethodModification self subclassResponsibility ! ! !AbstractMethodWidget commentStamp: ''! AbstractMethodWidget is an abstraction describing a widget used to manage methods! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! vScrollValue ^ self subclassResponsibility! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! selectedMethod ^ self model selectedMethod! ! !AbstractMethodWidget methodsFor: 'icon' stamp: 'EstebanLorenzano 5/14/2013 09:44'! buildUpAndDownArrowIcon: aMethod | container up down | container := Morph new. container extent: 12@12; color: Color transparent. up := IconicButton new target: self model; actionSelector: #arrowUp:; arguments: { aMethod }; labelGraphic: (Smalltalk ui icons iconNamed: #arrowDoubleUpIcon); color: Color transparent; extent: 12 @ 6; helpText: 'Browse overriden message'; borderWidth: 0. down := IconicButton new target: self model; actionSelector: #arrowDown:; arguments: { aMethod }; labelGraphic: (Smalltalk ui icons iconNamed: #arrowDoubleDownIcon); color: Color transparent; extent: 12 @ 6; helpText: 'Browse overriding messages'; borderWidth: 0. ^ (container changeTableLayout; listDirection: #topToBottom; addMorph: down; addMorph: up; yourself) -> {up. down}.! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 5/14/2012 11:57'! selectMethod: aMethod self subclassResponsibility! ! !AbstractMethodWidget methodsFor: 'icon' stamp: ''! rebuildUpAndDownArrowIconFrom: array | container up down | container := Morph new. container extent: 12@12; color: Color transparent. up := array first asIconTargetting: self model. down := array second asIconTargetting: self model. ^ container changeTableLayout; listDirection: #topToBottom; addMorph: down; addMorph: up; yourself! ! !AbstractMethodWidget methodsFor: 'item creation' stamp: ''! buildMethodsList ^ self subclassResponsibility! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 8/6/2012 19:41'! selectedMethod: aMethod "I check if it's ok here to work better with the drag/drop mechanism" self model selectedMethod: aMethod! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! selectedMethods ^ self subclassResponsibility! ! !AbstractMethodWidget methodsFor: 'initialization' stamp: ''! initialize super initialize. MethodsIconsCache ifNil: [ MethodsIconsCache := WeakIdentityKeyDictionary new ]! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: 'NicolaiHess 8/9/2014 21:08'! resetMethodSelection self subclassResponsibility ! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! getMethods ^ self model getMethods! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! label: aString ^ self subclassResponsibility! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! takeKeyboardFocus ^ self subclassResponsibility! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! elementsMenu: aMenuMorph shifted: aBoolean ^ self model elementsMenu: aMenuMorph shifted: aBoolean ! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 4/4/2012 16:05'! setIcon: icon for: method MethodsIconsCache at: method put: icon! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: 'NicolaiHess 8/9/2014 21:08'! resetMethodList self subclassResponsibility ! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! keyPressedOnElement: anEvent ^ self subclassResponsibility! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! removeAllFromMethodsIconsCache: aMethod ^ self subclassResponsibility! ! !AbstractMethodWidget methodsFor: 'drag and drop' stamp: 'NicolaiHess 7/28/2014 21:56'! dragPassengersFor: item inMorph: dragSource | transferType object | (dragSource isKindOf: PluggableListMorph) ifFalse: [^ nil ]. transferType := self dragTransferTypeForMorph: dragSource. transferType == #getMethodItem: ifFalse: [ ^ nil ]. object := item originalObject. ^ self selectedMethods ifEmpty: [ (self getMethods includes: object) ifTrue: [ { object } ]]! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! methodsSelection ^ self subclassResponsibility! ! !AbstractMethodWidget methodsFor: 'icon' stamp: ''! methodsIconsCache ^ MethodsIconsCache! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: 'NicolaiHess 8/9/2014 21:21'! updateMethodList self subclassResponsibility ! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! showInstance ^ self model showInstance! ! !AbstractMethodWidget methodsFor: 'icon' stamp: 'NicolaiHess 7/28/2014 21:56'! methodIconFor: aMethod | actions button action | button := nil. MethodsIconsCache at: aMethod ifPresent: [:icon | icon isArray ifTrue: [ ^ self rebuildUpAndDownArrowIconFrom: icon]. icon class == IconicButtonStateHolder ifFalse: [ ^ icon ]. ^ icon asIcon ]. actions := AbstractMethodIconAction allSubclasses collect: [:class | class for: aMethod in: self model ]. actions sort: [:a :b | a actionOrder < b actionOrder ]. action := actions detect: [:each | each isActionHandled ]. "actionIcon need to be invoked before actionStateToCache" button := action actionIcon. MethodsIconsCache at: aMethod put: action actionStateToCache. ^ button! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: ''! vScrollValue: aNumber ^ self subclassResponsibility! ! !AbstractMethodWidget methodsFor: 'updating' stamp: 'BenjaminVanRyseghem 4/17/2012 17:13'! okToChange ^ self model okToChange. ! ! !AbstractMethodWidget methodsFor: 'protocol' stamp: 'NicolaiHess 7/28/2014 21:57'! invalidateCacheEntryFor: aMethod self subclassResponsibility ! ! !AbstractMethodWidget class methodsFor: 'icon' stamp: 'CamilloBruni 5/7/2013 23:34'! resetMethodIconCache MethodsIconsCache removeAll! ! !AbstractMethodWidget class methodsFor: 'icon' stamp: 'BenjaminVanRyseghem 6/18/2013 15:57'! methodsIconsCache ^ MethodsIconsCache! ! !AbstractModification commentStamp: ''! Modifications to a high-level class have an impact on the related low-level structures. There are two modification models that transform the high-level model into concrete low-level modifications models, the method modification model and the instance modification model. Both models list for every field, whether it was added, removed, or shifted to a new position. Instance Variables: slotShift modificationMap <(Collection of: AbstractFieldModification)>! !AbstractModification methodsFor: 'accessing' stamp: 'ToonVerwaest 3/24/2011 12:18'! size ^ modificationMap size.! ! !AbstractModification methodsFor: 'accessing' stamp: 'ToonVerwaest 3/24/2011 11:37'! slotShift: aShift slotShift := aShift! ! !AbstractModification methodsFor: 'installing' stamp: 'ToonVerwaest 3/28/2011 17:12'! installAddedSlot: addedSlot self subclassResponsibility! ! !AbstractModification methodsFor: 'installing' stamp: 'ToonVerwaest 3/28/2011 17:12'! installRemovedSlot: removedSlot self subclassResponsibility! ! !AbstractModification methodsFor: 'initialize-release' stamp: 'ToonVerwaest 3/28/2011 19:46'! initialize: anInteger self initialize. modificationMap := Array new: anInteger.! ! !AbstractModification methodsFor: 'installing' stamp: 'ToonVerwaest 3/28/2011 17:12'! installModifiedSlot: modifiedSlot self subclassResponsibility! ! !AbstractModification methodsFor: 'accessing' stamp: 'ToonVerwaest 3/30/2011 13:52'! modificationAt: idx idx > modificationMap size ifTrue: [ ^ slotShift ]. ^ modificationMap at: idx! ! !AbstractModification methodsFor: 'installing' stamp: 'ToonVerwaest 3/28/2011 17:29'! installUnmodifiedSlot: unmodifiedSlot modificationMap at: unmodifiedSlot fieldIndex put: unmodifiedSlot! ! !AbstractModification class methodsFor: 'instance creation' stamp: 'ToonVerwaest 3/24/2011 12:17'! new: anInteger ^ self new initialize: anInteger ! ! !AbstractMorphicAdapter commentStamp: ''! I am an abstract class providing all the properties shared amongs all the morphic specific adapters! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:45'! hSpaceFill self widgetDo: [ :w | w hResizing: #spaceFill ]! ! !AbstractMorphicAdapter methodsFor: 'drag and drop - private' stamp: 'BenjaminVanRyseghem 9/25/2013 14:09'! acceptDroppingMorph: draggedMorph event: event inMorph: source ^ self acceptDropBlock cull: draggedMorph cull: event cull: source! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 15:28'! enabled ^ self model enabled! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:44'! hRigid self widgetDo: [ :w | w hResizing: #rigid ]! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:46'! vShrinkWrap self widgetDo: [ :w | w vResizing: #shrinkWrap ]! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 15:20'! layout: aLayout | layout | layout := aLayout asMorphicLayout. self widgetDo: [ :w | w layoutFrame: layout ]! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:45'! hShrinkWrap self widgetDo: [ :w | w hResizing: #shrinkWrap ]! ! !AbstractMorphicAdapter methodsFor: 'drag and drop' stamp: 'BenjaminVanRyseghem 9/25/2013 16:22'! dropEnabled: aBoolean self widget ifNotNil: [ :w | w dropEnabled: aBoolean ]! ! !AbstractMorphicAdapter methodsFor: 'protocol-shortcuts' stamp: 'BenjaminVanRyseghem 11/12/2013 16:15'! removeKeyCombination: aShortcut self widget ifNotNil: [ :w | w removeKeyCombination: aShortcut ]! ! !AbstractMorphicAdapter methodsFor: 'drag and drop' stamp: 'BenjaminVanRyseghem 9/25/2013 16:22'! dragEnabled: aBoolean self widget ifNotNil: [ :w | w dragEnabled: aBoolean ]! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 1/23/2014 16:12'! color: color self widgetDo: [ :w | w color: color ]! ! !AbstractMorphicAdapter methodsFor: 'drag and drop' stamp: 'BenjaminVanRyseghem 9/25/2013 15:28'! dropEnabled ^ self model dropEnabled! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:45'! removeSubWidgets self widgetDo: [ :w | w removeAllMorphs ]! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 15:28'! enable self model enabled: true! ! !AbstractMorphicAdapter methodsFor: 'protocol-shortcuts' stamp: 'BenjaminVanRyseghem 11/12/2013 10:47'! bindKeyCombination: aShortcut toAction: aBlock self widget ifNotNil: [ :w | w bindKeyCombination: aShortcut toAction: aBlock ]! ! !AbstractMorphicAdapter methodsFor: 'dispatch' stamp: 'BenjaminVanRyseghem 9/25/2013 18:19'! treeRenderOn: aCanvas bounds: drawBounds color: drawColor font: aFont from: aMorph "Specify how this object as a list item should be drawn" self widget ifNil: [ self buildWithSpec ]. self widget treeRenderOn: aCanvas bounds: drawBounds color: drawColor font: aFont from: aMorph! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 15:27'! disable self model enabled: false! ! !AbstractMorphicAdapter methodsFor: 'dispatch' stamp: 'BenjaminVanRyseghem 9/25/2013 18:19'! heightToDisplayInTree: aTree "Return the width of my representation as a list item" self extent ifNotNil: [:ex | ^ ex y ]. self initialExtent ifNotNil: [:ex | ^ ex y ]. self widget ifNil: [ self buildWithSpec ]. ^ self widget heightToDisplayInTree: aTree! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:46'! useProportionalLayout self widgetDo: [ :w | w changeProportionalLayout ]! ! !AbstractMorphicAdapter methodsFor: 'drag and drop' stamp: 'BenjaminVanRyseghem 9/25/2013 15:24'! acceptDropBlock ^ self model acceptDropBlock! ! !AbstractMorphicAdapter methodsFor: 'spec protocol' stamp: 'BenjaminVanRyseghem 12/1/2013 01:10'! setModal: aWindow self widgetDo: [ :w | w setModal: aWindow ]! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'CamilloBruni 10/15/2013 20:56'! extent ^ self widget extent! ! !AbstractMorphicAdapter methodsFor: 'spec protocol' stamp: 'BenjaminVanRyseghem 11/21/2013 10:20'! delete self widgetDo: [ :w | w delete ]! ! !AbstractMorphicAdapter methodsFor: 'testing' stamp: 'BenjaminVanRyseghem 10/10/2013 12:15'! isMorphicAdapter ^ true! ! !AbstractMorphicAdapter methodsFor: 'protocol-shortcuts' stamp: 'BenjaminVanRyseghem 11/12/2013 10:54'! bindMenuKeyCombination: aShortcut toAction: aBlock self widget ifNotNil: [ :w | w bindKeyCombination: aShortcut toAction: aBlock ]! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 15:29'! help ^ self model help! ! !AbstractMorphicAdapter methodsFor: 'drag and drop' stamp: 'BenjaminVanRyseghem 9/25/2013 15:29'! transferBlock ^ self model transferBlock! ! !AbstractMorphicAdapter methodsFor: 'dispatch' stamp: 'BenjaminVanRyseghem 9/25/2013 18:19'! widthToDisplayInTree: aTree "Return the width of my representation as a list item" self extent ifNotNil: [:ex | ^ ex x ]. self initialExtent ifNotNil: [:ex | ^ ex x ]. self widget ifNil: [ self buildWithSpec ]. ^ self widget widthToDisplayInTree: aTree! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 10/1/2013 13:14'! when: anAnnouncement do: aBlock self widgetDo: [ :w | w announcer when: anAnnouncement do: aBlock ]! ! !AbstractMorphicAdapter methodsFor: 'drag and drop' stamp: 'BenjaminVanRyseghem 9/25/2013 15:28'! dragTransformationBlock ^ self model dragTransformationBlock! ! !AbstractMorphicAdapter methodsFor: 'drag and drop - private' stamp: 'BenjaminVanRyseghem 9/25/2013 14:09'! wantsDroppedMorph: draggedMorph event: anEvent inMorph: source ^ self wantDropBlock cull: draggedMorph cull: anEvent cull:source! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 16:21'! setBalloonText: aString self widget ifNotNil: [ :w | w setBalloonText: aString ]! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:47'! vSpaceFill self widgetDo: [ :w | w vResizing: #spaceFill ]! ! !AbstractMorphicAdapter methodsFor: 'dispatch' stamp: 'BenjaminVanRyseghem 3/4/2014 17:25:06'! listRenderOn: aCanvas atRow: aRow bounds: drawBounds color: drawColor backgroundColor: backgroundColor from: aMorph "Specify how this object as a list item should be drawn" self widget ifNil: [ self buildWithSpec ]. self widget vResizing: #rigid; hResizing: #rigid. self widget listRenderOn: aCanvas atRow: aRow bounds: drawBounds color: drawColor backgroundColor: backgroundColor from: aMorph! ! !AbstractMorphicAdapter methodsFor: 'spec protocol' stamp: 'BenjaminVanRyseghem 11/27/2013 14:56'! changed ^ self widgetDo: [ :w | w changed ]! ! !AbstractMorphicAdapter methodsFor: 'drag and drop - private' stamp: 'BenjaminVanRyseghem 9/25/2013 15:29'! transferFor: passenger from: source ^ self transferBlock cull:passenger cull: source! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 16:21'! borderWidth: width self widget ifNotNil: [ :w | w borderWidth: width ]! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 13:42'! add: aWidget self widgetDo: [ :w | w ensureLayoutAndAddMorph: aWidget asWidget ]! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 15:24'! borderColor ^ self model borderColor! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 15:24'! borderWidth ^ self model borderWidth! ! !AbstractMorphicAdapter methodsFor: 'drag and drop - private' stamp: 'BenjaminVanRyseghem 9/25/2013 14:09'! dragPassengerFor: item inMorph: dragSource ^ self dragTransformationBlock cull: item cull: dragSource! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 16:21'! enabled: aBoolean self widget ifNotNil: [ :w | w enabled: aBoolean ]! ! !AbstractMorphicAdapter methodsFor: 'dispatch' stamp: 'BenjaminVanRyseghem 3/4/2014 17:25:06'! widthToDisplayInList: aList "Return the width of my representation as a list item" self model extent ifNotNil: [:ex | ^ ex x ]. self model initialExtent ifNotNil: [:ex | ^ ex x ]. self widget ifNil: [ self buildWithSpec ]. self widget vResizing: #rigid; hResizing: #rigid. ^ self widget widthToDisplayInList: aList! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/29/2013 12:46'! vRigid self widgetDo: [ :w | w vResizing: #rigid ]! ! !AbstractMorphicAdapter methodsFor: 'drag and drop - private' stamp: 'BenjaminVanRyseghem 9/25/2013 14:09'! dragPassengersFor: item inMorph: dragSource ^ { self dragTransformationBlock cull: item cull: dragSource }! ! !AbstractMorphicAdapter methodsFor: 'protocol-shortcuts' stamp: 'BenjaminVanRyseghem 11/12/2013 16:15'! removeMenuKeyCombination: aShortcut self widget ifNotNil: [ :w | w removeKeyCombination: aShortcut ]! ! !AbstractMorphicAdapter methodsFor: 'dispatch' stamp: 'BenjaminVanRyseghem 9/25/2013 18:19'! beginsWith: aString fromList: aMorph "This method is used bu the list for the search of elements when you are typing directly in the list" ^ false! ! !AbstractMorphicAdapter methodsFor: 'dispatch' stamp: 'BenjaminVanRyseghem 3/4/2014 17:25:06'! heightToDisplayInList: aList "Return the width of my representation as a list item" self model extent ifNotNil: [:ex | ^ ex y ]. self model initialExtent ifNotNil: [:ex | ^ ex y ]. self widget ifNil: [ self buildWithSpec ]. self widget vResizing: #rigid; hResizing: #rigid. ^ self widget heightToDisplayInList: aList! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 1/23/2014 16:12'! color ^ self model color! ! !AbstractMorphicAdapter methodsFor: 'drag and drop' stamp: 'BenjaminVanRyseghem 9/25/2013 15:29'! wantDropBlock ^ self model wantDropBlock! ! !AbstractMorphicAdapter methodsFor: 'drag and drop' stamp: 'BenjaminVanRyseghem 9/25/2013 15:27'! dragEnabled ^ self model dragEnabled! ! !AbstractMorphicAdapter methodsFor: 'protocol' stamp: 'BenjaminVanRyseghem 9/25/2013 16:21'! borderColor: color self widget ifNotNil: [ :w | w borderColor: color ]! ! !AbstractMorphicAdapter class methodsFor: 'specs' stamp: 'BenjaminVanRyseghem 9/25/2013 14:10'! defaultSpec ^ SpecLayout composed! ! !AbstractNautilusPlugin commentStamp: 'StephaneDucasse 10/30/2014 07:31'! I'm the root of Nautilus plugins. You can get the list of Nautilus plugin using the Plugin Manager that you can find in the window menu (right menu on the window itself) of the Nautilus browser window. !!!! How to create Nautilus-Plugins Here we will give some brief explanations on how to create your own plugin. There are only two requirements to create a Nautilus-Plugin: - the class should inherit from ==AbstractNautilusPlugin== - it should implement the method ==registerTo: aModel== [[[ AbstractNautilusPlugin ]]] !!!!!! Announcement subscription The method ==registerTo:== is used by the plugin to register itself to aModel announcements. [[[ MyPlugin>>registerTo: aModel aModel announcer when: NautilusKeyPressed send: #keyPressed: to: self ]]] In this example, the instance of ==MyPlugin== subscribes itself to ==NautilusKeyPressed==, and tell aModel's announcer to send the message ==keyPressed== to the instance. So each time a key will be pressed in a Nautilus window the method ==keyPressed:== will be called. !!!!!! Display If you want your plugin to add a graphical widget to Nautilus you should override the ==display== method. This method should return the Morphic element you want Nautilus to display. By default the method returns nil to notify Nautilus not to display anything. [[[ MyPlugin>>display morph := LabelMorph new contents: 'MyPlugin'; enabled: false; vResizing: #shrinkWrap; hResizing: #spaceFill; yourself. ^ morph ]]] You can also redefine the following methods on the class side: - ==defaultPosition== defines the default position of the morph. Possible values are =={#top, #middle, #bottom, #none}==. The default value is ==#none==. - ==possiblePositions== answers a collection of the possible positions the widget could adopt. !!!!!! Describing your plugin And finally you can redefine the ==pluginName== method to change the name displayed in the Nautilus Plugin Manager. [[[ MyPlugin class>>description ^ 'MyPlugin' ]]] [[[ MyPlugin class>>description ^ 'A super cool plugin' ]]] ! !AbstractNautilusPlugin methodsFor: 'registration' stamp: 'BenjaminVanRyseghem 5/4/2011 14:45'! registerTo: aModel self subclassResponsibility! ! !AbstractNautilusPlugin methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 5/4/2011 14:43'! model ^ model! ! !AbstractNautilusPlugin methodsFor: 'display' stamp: 'BenjaminVanRyseghem 8/25/2011 10:03'! position ^ position ifNil: [ position := self class defaultPosition ]! ! !AbstractNautilusPlugin methodsFor: 'display' stamp: 'BenjaminVanRyseghem 8/25/2011 09:49'! position: aPosition position := aPosition! ! !AbstractNautilusPlugin methodsFor: 'display' stamp: 'BenjaminVanRyseghem 5/2/2012 13:18'! name ^ self class name! ! !AbstractNautilusPlugin methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 5/4/2011 14:44'! model: anObject model := anObject. self registerTo: anObject! ! !AbstractNautilusPlugin methodsFor: 'display' stamp: 'StephaneDucasse 10/30/2014 07:11'! display " should answer a morphic object ready to be integrated into a NautilusWindow " ^ nil! ! !AbstractNautilusPlugin class methodsFor: 'display' stamp: 'BenjaminVanRyseghem 8/25/2011 14:18'! pluginName ^ self name! ! !AbstractNautilusPlugin class methodsFor: 'information' stamp: 'StephaneDucasse 10/30/2014 07:35'! possiblePositions "Return all the possible positions for a plugin. Subclasses are not intented to override this method." ^ { #top. #middle. #bottom. #none. }! ! !AbstractNautilusPlugin class methodsFor: 'information' stamp: 'StephaneDucasse 10/30/2014 07:28'! description ^ 'No description available'! ! !AbstractNautilusPlugin class methodsFor: 'position' stamp: 'StephaneDucasse 10/30/2014 07:29'! defaultPosition "Tells where in the Nautilus UI this plugin will appear. Pick an answer from #possiblePositions. By default a plugin does not have a visual representation so its position is none" ^ #none! ! !AbstractNautilusPlugin class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 5/4/2011 14:43'! model: aModel ^ self new model: aModel! ! !AbstractNautilusUI commentStamp: ''! An AbstractNautilusUI is an abstraction of the UI handling packages and classes. Instance Variables cachedHierarchy: classesSelection: commentButton: commentTextArea: currentDisplayChoice: firstColumn: groupsSelection: hierarchyClass: list: list2: model: packagesSelection: secondColumn: sourceCodeContainer: sourceCodePanel: sourceTextArea: sourceTextAreaLimit: window: ! !AbstractNautilusUI methodsFor: 'selection' stamp: 'NicolaiHess 8/9/2014 21:53'! resetMethodsListSelection self subclassResponsibility ! ! !AbstractNautilusUI methodsFor: 'menu builder' stamp: 'EstebanLorenzano 1/31/2013 19:24'! groupsMenu: aMenu shifted: aBoolean " Morphic's menus are filled up when pragma's one are returned from a method, so I have to substitute the morphic menu by the pragma one " ^ aMenu addAllFrom: (self groupMenuBuilder menu)! ! !AbstractNautilusUI methodsFor: 'focus' stamp: 'BenjaminVanRyseghem 6/22/2012 18:01'! giveFocusToSourceCode self giveFocusTo: sourceTextArea ! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'StephaneDucasse 8/2/2014 09:02'! findPackage "Search for a package from a pattern or from the recent list" | foundPackage | self okToChange ifFalse: [^ self ]. foundPackage := SearchFacade rPackageSearch chooseFromOwner: self window. foundPackage ifNil: [ ^self ]. self selectedPackage: foundPackage. self updatePackageViewAndMove. ! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 6/14/2012 17:33'! sourceCodePanel ^ sourceCodePanel! ! !AbstractNautilusUI methodsFor: 'group' stamp: 'BenjaminVanRyseghem 1/24/2013 18:06'! addPackageAsGroup ^ [ self addPackagesAsGroup: self selectedPackages ] on: GroupAlreadyExists do: [:ex | self alertGroupExisting: ex groupName. ^ nil ]! ! !AbstractNautilusUI methodsFor: 'announcement registration' stamp: ''! announce: anAnnouncement ^ self model announce: anAnnouncement! ! !AbstractNautilusUI methodsFor: 'system announcements' stamp: ''! methodRemoved: anAnnouncement ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'private' stamp: ''! ifGroups: aBlock ifNot: anotherBlock ^self showGroups ifTrue: aBlock ifFalse: anotherBlock! ! !AbstractNautilusUI methodsFor: 'selection' stamp: 'NicolaiHess 7/26/2014 13:13'! resetClassesListSelection self subclassResponsibility ! ! !AbstractNautilusUI methodsFor: 'system announcements' stamp: 'NicolaiHess 8/2/2014 21:53'! classReorganized: anAnnouncement window ifNil: [ ^ self ]. window isDisplayed ifFalse: [ ^ self ]. (self selectedClass = anAnnouncement classReorganized or: [ anAnnouncement classReorganized users includes: self selectedClass ]) ifTrue: [ self updatePackageGroupAndClassList ]! ! !AbstractNautilusUI methodsFor: 'initialization' stamp: 'NicolaiHess 7/31/2014 09:20'! initialize super initialize. shouldUpdateTitle := true. testSemaphore := Semaphore new. sourceTextAreas := OrderedCollection new. contentSelection := nil. acceptor := ClassDefinitionAcceptor model: self. classifier := MethodClassifier new. ! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'NicolaiHess 6/9/2014 00:04'! buildTearDownCodeFor: aClass ^ String streamContents: [:str | str << 'tearDown';cr. str tab << '"Tearing down code for '<>#', each selector ]. index := UIManager default chooseFrom: methodsNames. index = 0 ifTrue: [ ^ self ]. ^ self model class openOnMethod: (methods at: index) ! ! !AbstractNautilusUI methodsFor: 'SmalltalkEditor compatibility' stamp: ''! selectedBehavior ^ self selectedClass! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'MarcusDenker 9/27/2013 18:01'! copyMethod: aMethod toTheClass: aClass | newMethod | aMethod realClass = aClass ifTrue: [ ^ self ]. aClass methodDict at: aMethod selector ifPresent: [:sel | " here I have to fork to release the drag & drop " [ (self openDialogWouldYouInstall: sel into: aClass) ifTrue: [ newMethod := aClass compile: aMethod sourceCode classified: aMethod category ]] fork. ] ifAbsent: [ newMethod := aClass compile: aMethod sourceCode classified: aMethod category]! ! !AbstractNautilusUI methodsFor: 'build ui plugins' stamp: 'NicolaiHess 7/28/2014 21:19'! buildMiddlePlugins | middle container | middle := self model plugins select: [:each | each position = #middle ]. middle ifEmpty: [ ^ nil ]. middle size = 1 ifTrue: [ ^ middle first display ]. container := Morph new. self setShortcuts: #NautilusSourceCodeShortcuts to: container. container color: Color transparent; changeTableLayout; cellInset: 8; listDirection: #topToBottom; cellPositioning: #topLeft; hResizing: #shrinkWrap; vResizing: #shrinkWrap. middle reverse do: [:each | each display ifNotNil: [:morph | container addMorph: morph ]]. ^ container! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! browseMessages self browseMessagesFrom: self selectedMethod selector! ! !AbstractNautilusUI methodsFor: 'events handling' stamp: ''! doubleClickOnPackage self selectedPackage ifNil: [ ^ self ] ifNotNil:[:package | self model class openOnPackage: package ]! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: ''! showComment ^ self model showComment! ! !AbstractNautilusUI methodsFor: 'icon caches' stamp: ''! removeFromGroupsIconsCache: aClass " not used since the groups's icons are always the same " GroupsIconsCache removeKey: aClass ifAbsent: [].! ! !AbstractNautilusUI methodsFor: 'icon' stamp: 'EstebanLorenzano 5/14/2013 09:44'! groupIconFor: aGroup | icon | GroupsIconsCache at: aGroup ifPresent: [:ic | ic class == IconicButtonStateHolder ifFalse: [ ^ ic ]. ^ ic asIconTargetting: self ]. icon := IconicButton new target: self; actionSelector: #restrictedBrowseGroups:; arguments: {{aGroup}}; labelGraphic: (Smalltalk ui icons iconNamed: #groupIcon); color: Color transparent; extent: 15 @ 16; helpText: 'Browse restricted environment'; borderWidth: 0. GroupsIconsCache at: aGroup put: (IconicButtonStateHolder forNautilus: icon). ^ icon! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! moveMethodToPackage ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: ''! selectedClassComments ^ self selectedClass ifNil: [''] ifNotNil: [:class| class comment]! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! fullBrowse ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'announcement registration' stamp: 'BernardoContreras 10/21/2014 15:03'! registerToMCAnnouncements SystemAnnouncer uniqueInstance weak when: MCVersionCreated send: #newMCVersion: to: self; when: MCPackageModified send: #mcPackageModified: to: self; when: MCWorkingCopyCreated send: #mcWorkingCopyCreated: to: self; when: MCWorkingCopyDeleted send: #mcWorkingCopyDeleted: to: self. ! ! !AbstractNautilusUI methodsFor: 'menu builder' stamp: 'EstebanLorenzano 1/31/2013 19:24'! sourceCodeMenu: aMenu shifted: shifted " Morphic's menus are filled up when pragma's one are returned from a method, so I have to substitute the morphic menu by the pragma one " ^ aMenu addAllFrom: (self sourceCodeMenuBuilder menu)! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'EstebanLorenzano 10/9/2013 16:18'! parentOfClass: aClass ^ aClass package.! ! !AbstractNautilusUI methodsFor: 'build ui text' stamp: 'EstebanLorenzano 5/15/2014 17:45'! buildCommentPane commentTextArea := PluggableTextMorph on: self text: #getComments accept: #addComment:notifying: readSelection: nil menu: #codePaneMenu:shifted:. commentTextArea askBeforeDiscardingEdits: true; vResizing: #spaceFill; hResizing: #spaceFill. self setCommentShorcutsTo: commentTextArea. commentTextArea spaceFillWeight: 1. ^ commentTextArea! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: 'BenjaminVanRyseghem 10/18/2013 16:30'! pendingText: aString self sourceTextArea setText: aString; hasUnacceptedEdits: true! ! !AbstractNautilusUI methodsFor: 'announcement registration' stamp: ''! unregisterAllPlugins self announcer subscriptions reset! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! removeClassFromGroup self selectedClasses do: [:class | [ self groupsManager removeClass: class theNonMetaClass from: self selectedGroup. self updateClassView ] fork ]. self selectedClass: nil; updateClassView.! ! !AbstractNautilusUI methodsFor: 'build ui' stamp: 'NicolaiHess 7/28/2014 21:17'! buildColumns: aWindow height: height | delta | delta := StandardFonts defaultFont height + 15. aWindow addMorph: (self buildFirstColumn: aWindow) fullFrame: ((0 @ 0 corner: 0.25 @ 0.5) asLayoutFrame topOffset: height ). aWindow addMorph: (self buildSecondColumn: aWindow) fullFrame: ((0.25 @ 0 corner: 0.5 @ 0.5) asLayoutFrame topOffset: height ). aWindow addMorph: (self buildThirdColumn: aWindow) fullFrame: ( (0.5 @ 0 corner: 0.75 @ 0.5) asLayoutFrame topOffset: height ; bottomOffset: delta negated). aWindow addMorph: (self buildFourthColumn: aWindow) fullFrame: ( (0.75 @ 0 corner: 1 @ 0.5) asLayoutFrame topOffset: height; bottomOffset: delta negated). aWindow addMorph: self buildNavigationList fullFrame: ((0.5 @ 0.5 corner: 1 @ 0.5) asLayoutFrame topOffset: delta negated).! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: ''! selectedPackage ^ self model selectedPackage! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'NicolaiHess 7/27/2014 13:31'! enableSingleMenuItems ^ self packageWidget selectedPackages size <= 1! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'SebastianTleye 4/19/2013 15:57'! restrictedBrowseTraitUsers self selectedClass ifNil: [ ^ self ] ifNotNil: [ :class | self restrictedBrowseTraitUsers: class users ]! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'CamilloBruni 10/7/2012 22:30'! restrictedBrowsePackageRegex | regex | regex := self selectedPackages ifEmpty: [ '' ] ifNotEmpty: [ :packages | '^',(packages first name splitOn: $-) first , '-.*$']. regex := UIManager default request: 'Browse restricted on Packages matching:' regex: regex . regex ifNil: [ ^ self ]. self restrictedBrowsePackages: (self browsedEnvironment packages select: [ :package| regex matches: package name ] )! ! !AbstractNautilusUI methodsFor: 'displaying' stamp: 'BenjaminVanRyseghem 8/3/2012 16:18'! setWindowTitle | title | shouldUpdateTitle ifFalse: [ ^ self ]. title := self selectedClass ifNil: [ self selectedPackage ifNil: [ self title ] ifNotNil: [: p | p name ]] ifNotNil: [:class | self selectedMethod ifNil: [ class name asString ] ifNotNil: [:method | String streamContents: [:s | s << method methodClass name asString<< '>>#'<< method selector ]]]. self browsedEnvironment isSystem ifFalse: [ title := String streamContents: [:s | s << '--- ' << title << ' ---']]. window title: title.! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: 'MarcusDenker 8/10/2014 09:44'! sourceCode self removeSourceTextAreaLimit. ^self selectedClass ifNil: [ self defaultClassDescriptor] ifNotNil: [:class | self selectedMethod ifNil: [ self selectedCategory ifNotNil: [ self putSourceTextAreaLimit. class sourceCodeTemplate] ifNil: [ self selectedClassDescription]] ifNotNil: [ self putSourceTextAreaLimit. self selectedMethodSource]]. ! ! !AbstractNautilusUI methodsFor: 'group' stamp: 'StephaneDucasse 8/22/2013 23:21'! addPackagesAsGroups [ self addPackagesAsGroups: self selectedPackages ] on: GroupAlreadyExists do: [:ex | self alertGroupExisting: ex groupName ]! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: 'BenjaminVanRyseghem 8/6/2012 00:53'! unlockTextArea: source multipleMethodsEditor removeEditor: source! ! !AbstractNautilusUI methodsFor: 'displaying' stamp: ''! taskbarIcon ^ self class icon! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'NicolaiHess 8/2/2014 21:53'! mergeGroups | group | group := self mergeGroups: self packageWidget selectedGroups. group ifNotNil: [ self groupsManager addAGroup: group. self selectedGroup: group. self updatePackageGroupAndClassList] ! ! !AbstractNautilusUI methodsFor: 'buttons behavior' stamp: ''! commentButtonLabel ^ self commentLabel! ! !AbstractNautilusUI methodsFor: 'plugins announcements' stamp: 'CamilloBruni 1/16/2013 00:24'! openClass self openClass: self selectedClass! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'CamilloBruni 9/4/2013 21:16'! categorizeAllUncategorizedMethods "Categorize methods by looking in parent classes for a method category." self selectedClass ifNotNil: [ :aClass | | methods | methods := aClass uncategorizedSelectors collect: [ :selector| aClass >> selector ]. self classifier classifyAll: methods ]! ! !AbstractNautilusUI methodsFor: 'private' stamp: ''! groupsLabel ^ 'Groups'! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: ''! setStylerClass: aClass sourceTextArea ifNotNil: [ sourceTextArea classOrMetaClass: aClass ]! ! !AbstractNautilusUI methodsFor: 'build ui buttons' stamp: 'EstebanLorenzano 1/30/2013 14:43'! buildGroupsButton | button | button := (PluggableButtonMorph on: self getState: #groupsButtonState action: #groupsButtonAction label: #groupsButtonLabel) hResizing: #spaceFill; vResizing: #shrinkWrap. self setShortcuts: #NautilusGroupShortcuts to: button. ^ button! ! !AbstractNautilusUI methodsFor: 'monticello announcements' stamp: 'MarcusDenker 9/27/2013 17:59'! mcWorkingCopyCreated: anAnnouncement | package rpackage | window ifNil: [^ self ]. window isDisplayed ifFalse: [ ^ self ]. package := anAnnouncement package. package ifNil: [ ^ self ]. rpackage := RPackageOrganizer default packageNamed: package name. (self model packages includes: rpackage) ifTrue: [ PackagesIconsCache removeKey: rpackage ifAbsent: []. self updatePackageView ]! ! !AbstractNautilusUI methodsFor: 'browser compatibility' stamp: ''! sourceCode: aText self okToChange ifTrue: [ sourceTextArea setText: aText. sourceTextArea takeKeyboardFocus ]! ! !AbstractNautilusUI methodsFor: 'menu builder' stamp: ''! categoryMenuBuilder ^ PragmaMenuBuilder withAllPragmaKeywords: {self commonPragma. self categoryPragma} model: self! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: ''! compileAMethodFromCategory: aCategory withSource: aString notifying: aController ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'CamilloBruni 9/14/2012 01:49'! findClassInHierarchy "Search for a subclass of the selected class from a pattern or from the recent list" self selectedClass ifNotNil: [ :class| self findClass: (SearchFacade hierarchySearchFor: class theNonMetaClass)].! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'MarcusDenker 9/27/2013 17:59'! addSubclassesOf: aClass in: result withIndex: index fromRestrictedCollection: aCollection | classes | classes := aClass subclasses" intersection: self shownClasses". classes := classes intersection: aCollection. (classes sort: [:a :b| a name <= b name]) do: [:each | result at: each put: index. self addSubclassesOf: each in: result withIndex: index + 1 fromRestrictedCollection: aCollection ]! ! !AbstractNautilusUI methodsFor: 'updating' stamp: 'BenComan 2/16/2014 23:20'! okToChange sourceTextArea ifNil: [ ^ true ]. sourceTextArea text asString trimBoth = sourceTextArea getText asString trimBoth ifTrue: [ ^ true ]. sourceTextArea canDiscardEdits ifTrue: [ ^ true]. sourceTextArea update: #wantToChange. ^ sourceTextArea canDiscardEdits! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'BenjaminVanRyseghem 1/6/2013 16:02'! classLabel ^'Class' asText allBold asMorph lock! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! showUnreferencedInstVars "Search for all instance variables known to the selected class, and put up a list of those that have no references anywhere in the system. The search includes superclasses, so that you don't need to navigate your way to the class that defines each inst variable in order to determine whether it is unreferenced" self showUnreferencedInstVarsOf: self selectedClass! ! !AbstractNautilusUI methodsFor: 'system announcements' stamp: 'NicolaiHess 7/26/2014 11:20'! classDefinitionModified: anAnnouncement | class | window ifNil: [^ self ]. window isDisplayed ifFalse: [ ^ self ]. class := anAnnouncement oldClassDefinition. self removeClassFromMethodsIconsCache: class. ((self showGroups and: [ self selectedGroup notNil and: [ self selectedGroup elements includes: class ]]) or: [ self classWidget getClassesList includes: class ]) ifTrue: [ (model selectedClass = anAnnouncement oldClassDefinition) ifTrue: [ model selectedClass: anAnnouncement newClassDefinition ]. "Minimal change to fix Case13006. Further investigation required in Pharo 4 on Case13020" self updateClassView. self removeFromPackagesIconsCache: class package. sourceTextArea hasUnacceptedEdits ifFalse: [ self changed: #sourceCodeFrom: ]].! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'EstebanLorenzano 1/15/2013 17:07'! renameClass self okToChange ifFalse: [ ^ self ]. self selectedClass ifNil: [ ^ self ]. self basicRenameClass: self selectedClass theNonMetaClass. self changed: #sourceCodeFrom:.! ! !AbstractNautilusUI methodsFor: 'shortcuts' stamp: 'EstebanLorenzano 2/19/2013 14:43'! removeShortcuts: groupSymbol from: aMorph Nautilus useOldStyleKeys ifFalse: [ ^self ]. (aMorph kmDispatcher includesKeymapCategory: groupSymbol) ifTrue: [ aMorph detachKeymapCategory: groupSymbol targetting: self ] ! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: 'MarcusDenker 10/14/2014 08:03'! selectedMethodSource self selectedMethod ifNil: [ ^ '' ]. ^ self selectedMethod sourceCode! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! fileOutClass "Print a description of the selected class onto a file whose name is the category name followed by .st." self fileOutClasses: self selectedClasses! ! !AbstractNautilusUI methodsFor: 'widget class' stamp: 'NicolaiHess 7/28/2014 23:54'! classWidget self subclassResponsibility ! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: ''! doItContext ^ nil! ! !AbstractNautilusUI methodsFor: 'buttons behavior' stamp: 'NicolaiHess 9/7/2014 18:55'! hierarchyButtonLabel ^ self showHierarchy ifFalse: [ 'Hierarchy' ] ifTrue: [ 'Flat' ]! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! categorizeMethod ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'code panel' stamp: 'StephaneDucasse 12/19/2012 15:54'! buildCodePanelWithCommentOnTop | splitter delta | splitter := ProportionalSplitterMorph new beSplitsTopAndBottom. delta := 2. splitter addLeftOrTop: commentTextArea. splitter addRightOrBottom: multipleMethodsEditor. sourceCodePanel addMorph: commentTextArea fullFrame: ( (0@0 corner: 1@0.5) asLayoutFrame bottomRightOffset: 0@(delta negated)). sourceCodePanel addMorph: splitter fullFrame: ( (0@0.5 corner: 1@0.5) asLayoutFrame topLeftOffset: 0@(delta negated) ; bottomRightOffset: 0@delta). sourceCodePanel addMorph: multipleMethodsEditor fullFrame: ((0@0.5 corner: 1@1) asLayoutFrame topLeftOffset: (0@delta )).! ! !AbstractNautilusUI methodsFor: 'group' stamp: 'EstebanLorenzano 10/10/2013 13:14'! addPackageAsGroupAndBrowse self addPackageAsGroup ifNotNil: [:group | self selectedGroup: group. self showGroups: true] ifNil: [ | group | group := self model groupsManager groupNamed: self selectedPackage name. group ifNotNil: [ self selectedGroup: group. self showGroups: true ]]! ! !AbstractNautilusUI methodsFor: 'private' stamp: ''! systemNavigation ^ SystemNavigation new browsedEnvironment: self browsedEnvironment; yourself! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! browseInstVarRefs self browseInstVarRefsOf: self selectedClass! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'NicolaiHess 1/2/2014 22:37'! restrictedBrowseGroups: aCollection aCollection ifNotEmpty: [:groups || classes newEnvironment | classes := groups gather: [:group | group classes]. newEnvironment := self browsedEnvironment forClasses: classes. self model class openOnGroup: groups first inEnvironment: newEnvironment ]! ! !AbstractNautilusUI methodsFor: 'buttons behavior' stamp: 'MarcusDenker 12/6/2013 12:59'! instanceButtonLabel | label | label := 'Class side' asMorph emphasis: 2. ^self selectedClass ifNil: [label] ifNotNil: [:class | class theMetaClass hasMethods ifTrue: [label emphasis: 1] ifFalse:[label]] ! ! !AbstractNautilusUI methodsFor: 'buttons behavior' stamp: 'BenjaminVanRyseghem 12/20/2012 12:40'! instanceButtonState ^ "false" self showInstance not! ! !AbstractNautilusUI methodsFor: 'group announcements' stamp: 'NicolaiHess 1/19/2014 12:13'! aGroupHasBeenRenamed: anAnnouncement "(NautilusUI methodDict at: #aGroupHasBeenRegistered:) getSource" | group | window ifNil: [ ^ self ]. window isDisplayed ifFalse: [^ self ]. self groupsAreVisible ifFalse: [ ^ self ]. group := anAnnouncement group. (self groupsManager includes: group) ifTrue: [ self updateGroupView ]! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: ''! okToChangeComment commentTextArea canDiscardEdits ifTrue: [^ true]. commentTextArea update: #wantToChange. "Solicit cancel from view" ^ commentTextArea canDiscardEdits ! ! !AbstractNautilusUI methodsFor: 'menu pragmas' stamp: 'EstebanLorenzano 1/30/2013 17:30'! classPragma ^'nautilusGlobalClassMenu'! ! !AbstractNautilusUI methodsFor: 'widget method' stamp: ''! selectedMethod ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'build ui plugins' stamp: 'NicolaiHess 7/28/2014 21:19'! buildTopPlugins | top container | top := self model plugins select: [:each | each position = #top ]. top ifEmpty: [ ^ nil ]. top size = 1 ifTrue: [ ^ top first display ]. container := Morph new. container color: Color transparent; changeTableLayout; cellInset: 8; listDirection: #topToBottom; cellPositioning: #topLeft; hResizing: #shrinkWrap; vResizing: #shrinkWrap. top reverse do: [:each | each display ifNotNil: [:morph | container addMorph: morph ]]. ^ container! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'SebastianTleye 4/23/2013 13:11'! loadList ^ self ifGroups: [ self getGroupsKeyList ] ifNot:[ self getPackagesWithoutExtensionsList ]! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: ''! sourceCodeContainer ^ sourceCodeContainer! ! !AbstractNautilusUI methodsFor: 'group announcements' stamp: 'NicolaiHess 1/19/2014 12:16'! aGroupHasBeenUnregistered: anAnnouncement | group | window ifNil: [ ^ self ]. window isDisplayed ifFalse: [^ self ]. self groupsAreVisible ifFalse: [ ^ self ]. group := anAnnouncement group. (self groupsManager includes: group) ifTrue: [ self updateGroupView ]! ! !AbstractNautilusUI methodsFor: 'menus' stamp: 'StephaneDucasse 8/23/2014 19:46'! addModelItemsToWindowMenu: aMenu "Add model-related items to the window menu" aMenu addLine; add: 'Nautilus Plugins Manager' target: NautilusPluginManager new selector: #openInWorld. aMenu add: 'Shortcuts description' target: self selector: #openShortcutDescription.! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'MarcusDenker 10/15/2014 16:35'! inspectMethod self selectedMethod ifNil: [ ^ self ]. self selectedMethod inspect! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: 'NicolaiHess 10/1/2014 23:58'! showHierarchy ^ self model showHierarchy! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! fileOutPackage self fileOutPackages: self selectedPackages! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: 'NicolaiHess 1/19/2014 12:07'! groupsAreVisible ^ self showGroups! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! createInitializerWithInstVars "Create a default initializer on the class side for a chosen list of instance variables" self createInitializerWithInstVarsOf: (self showInstance ifTrue: [ self selectedClass theNonMetaClass ] ifFalse: [ self selectedClass theMetaClass ])! ! !AbstractNautilusUI methodsFor: 'group' stamp: ''! addClassesInGroup: aCollection (DialogGroupAdder new groups: self groupsManager; elementsToAdd: ((aCollection collect: #theNonMetaClass) asSet asArray sort: [:a :b | a name < b name])) open! ! !AbstractNautilusUI methodsFor: 'plugins announcements' stamp: ''! aKeyHasBeenPressed: aKey self announcer announce: (NautilusKeyPressed key: aKey )! ! !AbstractNautilusUI methodsFor: 'buttons behavior' stamp: ''! groupsButtonState ^ false! ! !AbstractNautilusUI methodsFor: 'browser compatibility' stamp: ''! codeTextMorph ^ sourceTextArea! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'MarcusDenker 1/17/2013 11:04'! restrictedBrowseClass self selectedClass ifNil: [ ^ self ] ifNotNil: [ :class | self restrictedBrowseClasses: {class} ]! ! !AbstractNautilusUI methodsFor: 'menu builder' stamp: ''! classMenuBuilder ^ PragmaMenuBuilder withAllPragmaKeywords: {self classFixPragma. self classPragma} model: self! ! !AbstractNautilusUI methodsFor: 'widget method' stamp: ''! methodsForCategory: aCategory ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'CamilloBruni 10/7/2012 22:00'! restrictedBrowsePackages: packages | newEnvironment | newEnvironment := self browsedEnvironment forPackages: packages. self model class openOnPackage: self selectedPackage inEnvironment: newEnvironment! ! !AbstractNautilusUI methodsFor: 'build ui lists' stamp: 'MarcusDenker 10/14/2014 08:01'! buildTextAreaButtonsColumn: aWindow | column | column := PanelMorph new. column changeTableLayout; listDirection: #topToBottom. { self buildBrowseInstVarsButton. self buildBrowseClassVarsButton} reverse do: [:each | column addMorph: each ]. column vResizing: #spaceFill; width: 24; hResizing: #rigid. ^ column! ! !AbstractNautilusUI methodsFor: 'icon caches' stamp: ''! removeFromClassesIconsCache: aClass " not used since the class's icons are always the same " ClassesIconsCache removeKey: aClass ifAbsent: []. self updateClassView.! ! !AbstractNautilusUI methodsFor: 'build ui buttons' stamp: 'NicolaiHess 7/31/2014 09:56'! buildHierarchyButton ^ (PluggableButtonMorph on: self getState: #hierarchyButtonState action: #hierarchyButtonAction label: #hierarchyButtonLabel) getEnabledSelector: #hierarchyButtonEnabled; hResizing: #spaceFill; vResizing: #shrinkWrap; enabled: (self model selectedClass notNil); yourself! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: 'NicolaiHess 10/2/2014 00:02'! showGroups: aBoolean self okToChange ifFalse: [ ^ self ]. self flag:#todo. "test if this is necessary" "self setShortcuts: #NautilusClassShortcuts to: self classWidget." aBoolean ifTrue: [ self packageWidget enabled: true. self packageWidget removeShortcuts: #NautilusPackageShortcuts. self packageWidget setShortcuts: #NautilusGroupShortcuts] ifFalse: [ self packageWidget removeShortcuts: #NautilusGroupShortcuts. self packageWidget setShortcuts: #NautilusPackageShortcuts]. self resetPackageGroupsList. self showHierarchy ifTrue: [ self showHierarchySilently: false ]. self selectedGroup ifNil: [ self selectedClass: nil ] ifNotNil: [:group | (group elements includes: self selectedClass) ifFalse: [ self resetClassesList. self selectedClass: nil ]. aBoolean ifTrue: [ self packageWidget selectGroup: group ] ifFalse: [ self packageWidget selectPackage: self selectedPackage ]]. self model showGroups: aBoolean. self changed: #groupsButtonLabel. self changed: #hierarchyButtonLabel. self changedLabels. self updatePackageGroupAndClassList! ! !AbstractNautilusUI methodsFor: 'buttons behavior' stamp: 'NicolaiHess 9/7/2014 18:55'! hierarchyButtonEnabled ^ self selectedClass notNil or: [ self showHierarchy ]! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: 'EstebanLorenzano 5/15/2014 17:45'! buildNewSourceTextArea sourceTextArea := self textMorphClass on: self text: #sourceCodeFrom: accept: #compileSource:notifying: readSelection: #contentsSelectionFrom: menu: #sourceCodeMenu:shifted:. sourceTextArea askBeforeDiscardingEdits: true; lockSelector: #lockTextArea:from:; canLockChangeSelector: #canChangeLockFor:; vResizing: #spaceFill; hResizing: #spaceFill; font: StandardFonts codeFont; spaceFillWeight: 3; on: #keyStroke send: #keyStroke:fromSourceCodeMorph: to: self; warningLimit: self warningLimit. self setSourceCodeShorcutsTo: sourceTextArea. sourceTextAreaLimit := sourceTextArea warningLimit. sourceTextArea warningLimit: -1. sourceTextAreas addFirst: (sourceTextArea -> nil). ^ sourceTextArea ! ! !AbstractNautilusUI methodsFor: 'system announcements' stamp: 'BenComan 3/23/2015 22:19'! classRenamed: anAnnouncement | class | class := anAnnouncement classRenamed. window ifNil: [ ^ self]. window isDisplayed ifFalse: [ ^ self ]. ((self showGroups and: [ self selectedGroup elements includes: class ]) or: [ self classWidget getClassesList includes: class ]) ifTrue: [ self updateClassView. sourceTextArea hasUnacceptedEdits ifFalse: [ self changed: #sourceCodeFrom: ] ]! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'CamilloBruni 9/14/2012 02:13'! findClass "Search for a class from a pattern or from the recent list" self findClass: (SearchFacade classSearchInEnvironment: self browsedEnvironment).! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'StephaneDucasse 9/26/2014 15:59'! runTestsOfClass: aClass notifying: aBoolean | methods blockToEvaluate | methods := aClass methods select: [ :method | method isTestMethod ] thenCollect: [:e | e selector ]. blockToEvaluate := [ |result | [ aClass resetHistory. result := (aClass addToSuite: TestSuite new fromMethods: methods) run. result updateResultsInHistory. ClassesIconsCache removeKey: aClass ifAbsent: []. testSemaphore signal. ] on: Exception do:[:e | testSemaphore signal . e defaultAction]]. aBoolean ifTrue: [ blockToEvaluate forkAt: Processor userBackgroundPriority ] ifFalse: [ blockToEvaluate value ]. testSemaphore initSignals; wait. aBoolean ifTrue: [ | color | color := Color gray. aClass hasPassedTest ifTrue: [ color := Color green ]. aClass hasFailedTest ifTrue: [ color := Color yellow ]. aClass hasErrorTest ifTrue: [ color := Color red ]. self notifyTitle: 'Test Finished' contents: 'Class: ', aClass name color: color ]! ! !AbstractNautilusUI methodsFor: 'menu pragmas' stamp: 'EstebanLorenzano 1/30/2013 17:23'! packageFixPragma ^ 'nautilusGlobalPackageFixMenu'! ! !AbstractNautilusUI methodsFor: 'selection' stamp: 'NicolaiHess 8/9/2014 23:13'! resetCategoriesList self subclassResponsibility ! ! !AbstractNautilusUI methodsFor: 'widget category' stamp: 'NicolaiHess 7/28/2014 23:54'! categoryWidget self subclassResponsibility ! ! !AbstractNautilusUI methodsFor: 'system announcements' stamp: 'NicolaiHess 7/26/2014 11:20'! classCommented: anAnnouncement " announcement handled when a class has been commented " | aClass | window ifNil: [ ^ self ]. window isDisplayed ifFalse: [ ^ self ]. aClass := anAnnouncement classCommented. (self classWidget getClassesList includes: aClass) ifTrue: [ self removeFromClassesIconsCache: aClass ]. ((self selectedClass = aClass) and: [ self showComment ]) ifTrue: [ self changed: #getComments ]! ! !AbstractNautilusUI methodsFor: 'build ui lists' stamp: 'NicolaiHess 7/28/2014 21:22'! buildSecondColumn: aWindow | buttons | buttons := PanelMorph new. buttons changeProportionalLayout; addMorph: self buildInstanceButton fullFrame: ( (0@0 corner: 0.5@0 ) asLayoutFrame bottomRightOffset: -2@25 ); addMorph: self buildCommentButton fullFrame: (( 0.5@0 corner: 1@0 ) asLayoutFrame topLeftOffset: 2@0 ; bottomRightOffset: 0@25 ); hResizing: #spaceFill; vResizing: #rigid; height: 25. ^PanelMorph new changeProportionalLayout; addMorph: self buildClassWidget fullFrame: (LayoutFrame identity bottomOffset: -29); addMorph: buttons fullFrame: ( (0@1 corner: 1@1 ) asLayoutFrame topOffset: -25); hResizing: #spaceFill; vResizing: #spaceFill; yourself.! ! !AbstractNautilusUI methodsFor: 'shortcuts' stamp: 'EstebanLorenzano 2/6/2013 14:00'! setGroupShorcutsTo: aList aList attachKeymapCategory: #NautilusGroupShortcuts targetting: self! ! !AbstractNautilusUI methodsFor: 'drag and drop' stamp: 'NicolaiHess 8/2/2014 21:53'! dropInAPackage: aCollection into: receiver aCollection do:[:aClass | self showGroups ifTrue: [ receiver addClasses: { aClass }. ActiveHand shiftPressed ifFalse: [ self selectedGroup removeClass: aClass. self updateClassView ]] ifFalse: [ receiver addClass: aClass theNonMetaClass. ActiveHand shiftPressed ifTrue: [ self selectedClass: nil. self updateClassView ] ifFalse:[ self selectedPackage: receiver. self selectedClass: aClass. self updatePackageGroupAndClassList ]]]! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'EstebanLorenzano 5/28/2013 14:13'! asYetUnclassifiedString ^ Protocol unclassified.! ! !AbstractNautilusUI methodsFor: 'announcement registration' stamp: 'NicolaiHess 9/30/2014 21:49'! registerToAnnouncements self registerToSystemAnnouncements. (Smalltalk at: #TestCase ifPresent: [ self registerToTestAnnouncements ]). self registerToMCAnnouncements. self registerToGroupAnnouncements. ! ! !AbstractNautilusUI methodsFor: 'icons behavior' stamp: 'MarcusDenker 9/27/2013 18:05'! saveDirtyPackages: aCollection aCollection isEmptyOrNil ifTrue: [ ^ self ]. aCollection do: [:package || workCopy browser | workCopy := MCWorkingCopy forPackage: (MCPackage named: package name). browser :=MCWorkingCopyBrowser new. browser show; workingCopy: workCopy. "wrap := MCDependentsWrapper with: workCopy model: browser. self halt. index := browser workingCopySelectionWrapper: wrap. browser workingCopyTreeMorph selectionIndex: index"] ! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'NicolaiHess 4/8/2014 21:00'! restrictedBrowseClasses: classes | newEnvironment | newEnvironment := self browsedEnvironment forClasses: (classes collect:#theNonMetaClass). self model class openOnClass:self selectedClass inEnvironment: newEnvironment ! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: 'NicolaiHess 7/27/2014 20:55'! model: anObject model := anObject. self registerToAnnouncements. model when: #historyChanged send: #historyChanged to: self. anObject selectedPackage ifNotNil: [:e | self packageWidget selectPackage: e]. anObject selectedGroup ifNotNil: [:p | self packageWidget selectGroup:p]. anObject selectedClass ifNotNil: [:p | self classWidget selectClass: p].! ! !AbstractNautilusUI methodsFor: 'code panel' stamp: 'StephaneDucasse 12/19/2012 15:56'! buildCodePanelWithoutComment sourceCodePanel addMorph: multipleMethodsEditor fullFrame: LayoutFrame identity! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: ''! putSourceTextAreaLimit sourceTextArea ifNotNil: [ sourceTextArea warningLimit: sourceTextAreaLimit ]! ! !AbstractNautilusUI methodsFor: 'private' stamp: ''! popUpTestsResult: aClass! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'BenjaminVanRyseghem 6/28/2012 14:45'! restrictedBrowse self showGroups ifTrue: [ ^ self restrictedBrowseGroup ]. self selectedClass ifNil: [ self restrictedBrowsePackage ] ifNotNil: [ self restrictedBrowseClass ].! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'BenjaminVanRyseghem 4/6/2012 16:33'! copyClasses | association | self okToChange ifFalse: [^ self]. association := self copyClasses: (self selectedClasses collect: [:e | e theNonMetaClass ]). association key ifTrue: [ self selectedClass: association value. self updateClassView]! ! !AbstractNautilusUI methodsFor: 'widget category' stamp: ''! selectedCategory ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'group announcements' stamp: 'NicolaiHess 1/19/2014 12:06'! aGroupHasBeenAdded: anAnnouncement "(NautilusUI methodDict at: #aGroupHasBeenRegistered:) getSource" | group | window ifNil: [ ^ self ]. window isDisplayed ifFalse: [^ self ]. self groupsAreVisible ifFalse: [ ^ self ]. group := anAnnouncement group. (self groupsManager includes: group) ifTrue: [ self updateGroupView ]! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'StephaneDucasse 1/31/2015 19:29'! removeClasses "Remove the selected classes from the system, at interactive user request. Make sure the user really wants to do this, since it is not reversible. Answer true if removal actually happened." | result scroll | self okToChange ifFalse: [^ false]. scroll := self classWidget vScrollValue. result := self removeClasses: (self selectedClasses collect: #theNonMetaClass). result ifTrue: [ self resetClassesListSelection. self selectedClass: nil ]. self classWidget vScrollValue: scroll. ^ result! ! !AbstractNautilusUI methodsFor: 'group' stamp: 'BenjaminVanRyseghem 4/6/2012 16:45'! addPackagesInGroup self addPackagesInGroup: self selectedPackages! ! !AbstractNautilusUI methodsFor: 'source text events' stamp: ''! keyStroke: anEvent fromSourceCodeMorph: aMorph ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 8/3/2012 18:48'! showComment: aBoolean self okToChangeComment ifFalse: [ ^ self ]. self model showComment: aBoolean. self updateCodePanel! ! !AbstractNautilusUI methodsFor: 'buttons behavior' stamp: 'NicolaiHess 9/7/2014 18:56'! hierarchyButtonState ^ self showHierarchy! ! !AbstractNautilusUI methodsFor: 'icons behavior' stamp: ''! runTestForAMethod: aMethod notifying: anObject ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: 'NicolaiHess 9/7/2014 00:22'! sortHierarchically ^ self model sortHierarchically! ! !AbstractNautilusUI methodsFor: 'system announcements' stamp: 'MarcusDenker 9/27/2013 18:08'! packageCreated: anAnnouncement window ifNil: [ ^ self ]. window isDisplayed ifFalse: [ ^ self ]. self showGroups ifFalse: [ self updatePackageView ]! ! !AbstractNautilusUI methodsFor: 'build ui lists' stamp: 'NicolaiHess 7/28/2014 21:22'! buildFourthColumn: aWindow ^ self buildMethodWidget! ! !AbstractNautilusUI methodsFor: 'shortcuts' stamp: ''! setClassShorcutsTo: aList aList attachKeymapCategory: #NautilusClassShortcuts targetting: self! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'NicolaiHess 8/9/2014 21:28'! updatePackageViewAndMove self resetPackageGroupsList. self changed: #getPackageItem:! ! !AbstractNautilusUI methodsFor: 'announcement registration' stamp: 'BernardoContreras 10/21/2014 15:02'! registerToTestAnnouncements "Since Test classes can be absent (in production, for instance, I use non-global references)" (Smalltalk at: #TestCase) historyAnnouncer weak when: (Smalltalk at: #TestCaseStarted) send: #testCaseStarted: to: self; when: (Smalltalk at: #TestSuiteEnded) send: #testRunned: to: self.! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: 'BenjaminVanRyseghem 8/3/2012 18:48'! updateCodePanel commentTextArea ifNil: [ self buildCommentPane ]. sourceCodePanel removeAllMorphs. self model showComment ifTrue: [ self buildCodePanelWithComment ] ifFalse: [ self buildCodePanelWithoutComment ]! ! !AbstractNautilusUI methodsFor: 'private' stamp: ''! packageLabel ^'Packages'! ! !AbstractNautilusUI methodsFor: 'system announcements' stamp: ''! methodRecategorized: anAnnouncement ^ self subclassResponsibility! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'vincentBlondeau 12/12/2014 13:59'! runTestsOfGroups: aCollection notifying: aBoolean | classes label | label := 'Group: '. aCollection size >1 ifTrue: [ label := 'Groups: ']. classes := aCollection gather:[:each | each elements ]. classes := classes select: [:class | class isTestCase ]. self runClassTests: classes notifying: false. aBoolean ifFalse: [ self notifyTitle: 'Test Finished' contents: label,((aCollection collect: #name) joinUsing: ', ') ]! ! !AbstractNautilusUI methodsFor: 'events handling' stamp: ''! doubleClickOnGroup self selectedGroup ifNil: [ ^self ] ifNotNil:[:group | self model class openOnGroup: group ]! ! !AbstractNautilusUI methodsFor: 'monticello announcements' stamp: 'EstebanLorenzano 4/14/2014 17:40'! mcPackageModified: anAnnouncement " handled when a package become dirty " | rpackages | window ifNil: [^ self ]. window isDisplayed ifFalse: [ ^ self ]. rpackages := anAnnouncement package packageSet packages. rpackages isEmptyOrNil ifTrue: [ ^ self ]. (self model packages includesAnyOf: rpackages ) ifTrue: [ rpackages do: [:rpackage | PackagesIconsCache removeKey: rpackage ifAbsent: []]. self updatePackageView ]! ! !AbstractNautilusUI methodsFor: 'buttons behavior' stamp: 'BenjaminVanRyseghem 8/1/2012 19:46'! toggleShowComment self showComment: self showComment not. self changed: #commentButtonState! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'MarcusDenker 9/27/2013 18:08'! getGroupsKeyList | env | env := self browsedEnvironment. ^ env isSystem ifTrue: [ self groupsManager groups ] ifFalse: [ self groupsManager groups reject: [ :g | (g classes intersection: self model classes) isEmpty ] ]! ! !AbstractNautilusUI methodsFor: 'group announcements' stamp: 'NicolaiHess 8/2/2014 21:54'! aGroupHasBeenRemoved: anAnnouncement "(NautilusUI methodDict at: #aGroupHasBeenRegistered:) getSource" window ifNil: [ ^ self ]. window isDisplayed ifFalse: [^ self ]. self groupsAreVisible ifFalse: [ ^ self ]. (self groupsManager = anAnnouncement holder) ifTrue: [ self selectedGroup = anAnnouncement group ifTrue: [ self selectedGroup: nil ]. self updateGroupView. self updateCategoryAndMethodList ]! ! !AbstractNautilusUI methodsFor: 'source code area' stamp: 'EstebanLorenzano 1/31/2013 19:24'! codePaneMenu: aMenu shifted: shifted "Note that unless we override perform:orSendTo:, PluggableTextController will respond to all menu items in a text pane" | donorMenu | donorMenu := shifted ifTrue: [SmalltalkEditor shiftedYellowButtonMenu] ifFalse: [SmalltalkEditor yellowButtonMenu]. ^ aMenu addAllFrom: donorMenu! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'NicolaiHess 8/9/2014 21:27'! updateGroupView self resetPackageGroupsList. self changed: #getPackageItem:! ! !AbstractNautilusUI methodsFor: 'build ui lists' stamp: 'NicolaiHess 7/28/2014 21:22'! buildThirdColumn: aWindow ^ self buildCategoryWidget! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'CamilloBruni 10/7/2012 22:02'! restrictedBrowseSuperclasses self selectedClass ifNil: [ ^ self ] ifNotNil: [ :class | self restrictedBrowseClasses: class withAllSuperclasses ]! ! !AbstractNautilusUI methodsFor: 'private' stamp: 'NicolaiHess 7/27/2014 13:25'! selectedPackages ^ self packageWidget selectedPackages! ! !AbstractNautilusUI methodsFor: 'code panel' stamp: 'StephaneDucasse 12/19/2012 15:47'! buildCodePanelWithCommentOnBottom | splitter delta | splitter := ProportionalSplitterMorph new beSplitsTopAndBottom. delta := 2. splitter addLeftOrTop: multipleMethodsEditor. splitter addRightOrBottom: commentTextArea. sourceCodePanel addMorph: multipleMethodsEditor fullFrame: ( (0@0 corner: 1@0.5) asLayoutFrame bottomOffset: delta negated). sourceCodePanel addMorph: splitter fullFrame: ( (0@0.5 corner: 1@0.5) asLayoutFrame topLeftOffset: 0@(delta negated) ; bottomRightOffset: 0@delta). sourceCodePanel addMorph: commentTextArea fullFrame: ( (0@0.5 corner: 1@1) asLayoutFrame topLeftOffset: (0@delta)).! ! !AbstractNautilusUI methodsFor: 'menu builder' stamp: 'EstebanLorenzano 1/31/2013 19:24'! classesMenu: aMenu shifted: aBoolean ^ aMenu addAllFrom: self classMenuBuilder menu.! ! !AbstractNautilusUI methodsFor: 'build ui buttons' stamp: 'EstebanLorenzano 5/14/2013 09:44'! buildBrowseClassVarsButton ^ ( PluggableThreePhaseButtonMorph on: self ) actionSelector: #browseClassVars; stateSelector: #isAClassSelected ; onImage: (Smalltalk ui icons iconNamed: #classVarsSelectedIcon); offImage: (Smalltalk ui icons iconNamed: #classVarsUnselectedIcon); pressedImage: (Smalltalk ui icons iconNamed: #classVarsPressedIcon); extent: 24@24; helpText: 'Show class variables'; yourself.! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'BenjaminVanRyseghem 4/14/2012 12:05'! addClass self selectedPackage ifNotNil: [:package | self addClassIn: package ]! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: 'NicolaiHess 8/2/2014 21:54'! showInstance: aBoolean self okToChange ifTrue:[ self model showInstance: aBoolean. self resetClassesListSelection. self selectedClass ifNotNil: [:class | aBoolean ifTrue: [self selectedClass: class theNonMetaClass. acceptor := ClassOrMethodDefinitionAcceptor model: self ] ifFalse: [self selectedClass: class theMetaClass. acceptor := ClassDefinitionAcceptor model: self ]]. self updateCategoryAndMethodList. self changed: #instanceButtonState. self changed: #instanceButtonLabel ]! ! !AbstractNautilusUI methodsFor: 'icons behavior' stamp: 'TorstenBergmann 8/23/2014 00:11'! runExampleMethod: aMethod "Perform the method as an example method" aMethod methodClass baseClass perform: aMethod selector! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: 'vincentBlondeau 12/12/2014 13:58'! forceGenerateInitialize self selectedClass ifNotNil: [:class || code index | (class isMeta not and: [class isTestCase]) ifTrue: [ index := 34. code := self buildSetUpCodeFor: class. class compile: code classified: 'initialization'. code := self buildTearDownCodeFor: class. class compile: code classified: 'initialization'. self selectedMethod: (class>>#setUp) ] ifFalse: [ index := 62. code := self buildInitializeCodeFor: class. class compile: code classified: 'initialization' . self selectedMethod: (class>>#initialize) ]. self updateCategoryAndMethodList. self giveFocusTo: sourceTextArea. sourceTextArea selectFrom: index+class name size to: index-1+class name size ].! ! !AbstractNautilusUI methodsFor: 'accessing' stamp: ''! sourceTextArea ^ sourceTextArea! ! !AbstractNautilusUI methodsFor: 'menus behavior' stamp: ''! browseUnusedMethods self browseUnusedMethodsOf: self selectedClass! ! !AbstractNautilusUI methodsFor: 'selection' stamp: 'NicolaiHess 8/9/2014 21:50'! resetClassesList self subclassResponsibility ! ! !AbstractNautilusUI methodsFor: 'group' stamp: 'NicolaiHess 1/19/2014 12:05'! addNewGroup [ self groupsManager createAnEmptyStaticGroup ] on: GroupAlreadyExists do:[ :ex | self alertGroupExisting: ex groupName ]. ! ! !AbstractNautilusUI methodsFor: 'icons behavior' stamp: 'TorstenBergmann 1/16/2015 20:24'! runScriptMethod: aMethod "Perform the method as a script method" "For each