[Vm-dev] VM Maker: VMMaker.oscog-eem.1498.mcz

commits at source.squeak.org commits at source.squeak.org
Wed Oct 21 22:52:44 UTC 2015


Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.1498.mcz

==================== Summary ====================

Name: VMMaker.oscog-eem.1498
Author: eem
Time: 21 October 2015, 3:50:58.285 pm
UUID: 48806953-dab0-4898-a699-fb076d884b77
Ancestors: VMMaker.oscog-eem.1497

x64 Cogit:

Add barely tested support for supporting the System V and MSVC ABIs for x64 (they used to be the same :-( Looks like Microsoft have ARMified their x64 ABI)..

Fix bugs in x64's is32BitSignedImmediate:, setting of CStack/FramePointer & disassembly at pc..

Comments and comment typos.

Needs Cog-eem.287

=============== Diff against VMMaker.oscog-eem.1497 ===============

Item was changed:
  ----- Method: CogVMSimulator>>utilitiesMenu: (in category 'UI') -----
  utilitiesMenu: aMenuMorph
  	aMenuMorph
  		add: 'toggle transcript' action: #toggleTranscript;
  		add: 'clone VM' action: #cloneSimulationWindow;
  		addLine;
  		add: 'print ext head frame' action: #printExternalHeadFrame;
  		add: 'print int head frame' action: #printHeadFrame;
  		add: 'print mc/cog frame' action: [self printFrame: cogit processor fp WithSP: cogit processor sp];
  		add: 'short print ext frame & callers' action: [self shortPrintFrameAndCallers: framePointer];
  		add: 'short print int frame & callers' action: [self shortPrintFrameAndCallers: localFP];
  		add: 'short print mc/cog frame & callers' action: [self shortPrintFrameAndCallers: cogit processor fp];
  		add: 'long print ext frame & callers' action: [self printFrameAndCallers: framePointer SP: stackPointer];
  		add: 'long print int frame & callers' action: [self printFrameAndCallers: localFP SP: localSP];
  		add: 'long print mc/cog frame & callers' action: [self printFrameAndCallers: cogit processor fp SP: cogit processor sp];
  		add: 'print frame...' action: [(self promptHex: 'print frame') ifNotNil: [:fp| self printFrame: fp]];
  		add: 'print call stack' action: #printCallStack;
  		add: 'print stack call stack' action: #printStackCallStack;
  		add: 'print stack call stack of...' action: [(self promptHex: 'frame') ifNotNil: [:fp| self printStackCallStackOf: fp]];
  		add: 'print call stack of...' action: [(self promptHex: 'context or process oop') ifNotNil: [:obj| self printCallStackOf: obj]];
  		add: 'print call stack of frame...' action: [(self promptHex: 'frame') ifNotNil: [:fp| self printCallStackFP: fp]];
  		add: 'print all stacks' action: #printAllStacks;
  		add: 'write back local ptrs' action: [stackPointer := localSP. framePointer := localFP. instructionPointer := localIP.
  											self writeBackHeadFramePointers];
  		add: 'write back mc ptrs' action: [stackPointer := cogit processor sp. framePointer := cogit processor fp. instructionPointer := cogit processor eip.
  											self writeBackHeadFramePointers];
  		addLine;
  		add: 'print rump C stack' action: [objectMemory printMemoryFrom: cogit processor sp to: cogit getCStackPointer];
  		add: 'print registers' action: [cogit processor printRegistersOn: transcript];
  		add: 'print register map' action: [cogit printRegisterMapOn: transcript];
  		add: 'disassemble method/trampoline...' action: [(self promptHex: 'pc') ifNotNil: [:pc| cogit disassembleCodeAt: pc]];
  		add: 'disassemble method/trampoline at pc' action:
+ 			[cogit disassembleCodeAt: (((cogit codeEntryFor: cogit processor pc) isNil
+ 										  and: [(cogit methodZone methodFor: cogit processor pc) = 0])
- 			[cogit disassembleCodeAt: ((cogit methodZone methodFor: cogit processor pc) = 0
  											ifTrue: [instructionPointer]
  											ifFalse: [cogit processor pc])];
  		add: 'disassemble ext head frame method' action: [cogit disassembleMethod: (self frameMethod: framePointer)];
  		add: 'print oop...' action: [(self promptHex: 'print oop') ifNotNil: [:oop| self printOop: oop]];
  		add: 'long print oop...' action: [(self promptHex: 'print oop') ifNotNil: [:oop| self longPrintOop: oop]];
  		add: 'print context...' action: [(self promptHex: 'print context') ifNotNil: [:oop| self printContext: oop]];
  		addLine;
  		add: 'inspect object memory' target: objectMemory action: #inspect;
  		add: 'run leak checker' action: [Cursor execute showWhile: [self runLeakChecker]];
  		add: 'inspect cointerpreter' action: #inspect;
  		add: 'inspect cogit' target: cogit action: #inspect;
  		add: 'inspect method zone' target: cogit methodZone action: #inspect.
  	self isThreadedVM ifTrue:
  		[aMenuMorph add: 'inspect thread manager' target: self threadManager action: #inspect].
  	aMenuMorph
  		addLine;
  		add: 'print cog methods' target: cogMethodZone action: #printCogMethods;
  		add: 'print cog methods with prim...' action: [(self promptNum: 'prim index') ifNotNil: [:pix| cogMethodZone printCogMethodsWithPrimitive: pix]];
  		add: 'print cog methods with selector...' action:
  			[|s| s := UIManager default request: 'selector'.
  			s notEmpty ifTrue:
  				[s = 'nil' ifTrue: [s := nil].
  				 cogMethodZone methodsDo:
  					[:m|
  					(s ifNil: [m selector = objectMemory nilObject]
  					 ifNotNil: [(objectMemory numBytesOf: m selector) = s size
  							and: [(self str: s
  									n: (m selector + objectMemory baseHeaderSize)
  									cmp: (objectMemory numBytesOf: m selector)) = 0]]) ifTrue:
  						[cogit printCogMethod: m]]]];
  		add: 'print cog method for...' action: [(self promptHex: 'pc') ifNotNil: [:pc| cogit printCogMethodFor: pc]];
  		add: 'print cog method header for...' action: [(self promptHex: 'pc') ifNotNil: [:pc| cogit printCogMethodHeaderFor: pc]];
  		add: 'print trampoline table' target: cogit action: #printTrampolineTable;
  		add: 'print prim trace log' action: #dumpPrimTraceLog;
  		add: 'report recent instructions' target: cogit action: #reportLastNInstructions;
  		add: 'set break pc (', (cogit breakPC isInteger ifTrue: [cogit breakPC hex] ifFalse: [cogit breakPC printString]), ')...' action: [(self promptHex: 'break pc') ifNotNil: [:bpc| cogit breakPC: bpc]];
  		add: (cogit singleStep
  				ifTrue: ['no single step']
  				ifFalse: ['single step'])
  			action: [cogit singleStep: cogit singleStep not];
  		add: (cogit printRegisters
  				ifTrue: ['no print registers each instruction']
  				ifFalse: ['print registers each instruction'])
  			action: [cogit printRegisters: cogit printRegisters not];
  		add: (cogit printInstructions
  				ifTrue: ['no print instructions each instruction']
  				ifFalse: ['print instructions each instruction'])
  			action: [cogit printInstructions: cogit printInstructions not];
  		addLine;
  		add: 'click step' action: [cogit setClickStepBreakBlock];
  		add: 'set break count...' action: [|s| s := UIManager default request: 'break count (dec)'.
  											s notEmpty ifTrue: [breakCount := Integer readFrom: s readStream]];
  		add: 'set break selector...' action: [|s| s := UIManager default request: 'break selector'.
  											s notEmpty ifTrue: [self setBreakSelector: s]];
  		add: 'set break block...' action: [|s| s := UIManager default request: 'break block' initialAnswer: '[:theCogit| false]'.
  											s notEmpty ifTrue: [self setBreakBlockFromString: s]];
  		add: 'set cogit break method...' action: [(self promptHex: 'cogit breakMethod') ifNotNil: [:bm| cogit setBreakMethod: bm]];
  		add: (printBytecodeAtEachStep
  				ifTrue: ['no print bytecode each bytecode']
  				ifFalse: ['print bytecode each bytecode'])
  			action: [self ensureDebugAtEachStepBlock.
  					printBytecodeAtEachStep := printBytecodeAtEachStep not];
  		add: (printFrameAtEachStep
  				ifTrue: ['no print frame each bytecode']
  				ifFalse: ['print frame each bytecode'])
  			action: [self ensureDebugAtEachStepBlock.
  					printFrameAtEachStep := printFrameAtEachStep not].
  	^aMenuMorph!

Item was changed:
  CogAbstractInstruction subclass: #CogX64Compiler
  	instanceVariableNames: ''
+ 	classVariableNames: 'ABI CDQ CMPXCHGAwR CMPXCHGMwrR CPUID IDIVR IMULRR LFENCE LOCK MFENCE ModReg ModRegInd ModRegIndDisp32 ModRegIndSIB ModRegRegDisp32 ModRegRegDisp8 R10 R11 R12 R13 R14 R15 R8 R9 RAX RBP RBX RCX RDI RDX RSI RSP SFENCE SIB1 SIB2 SIB4 SIB8 XCHGAwR XCHGMwrR XCHGRR XMM0H XMM0L XMM1H XMM1L XMM2H XMM2L XMM3H XMM3L XMM4H XMM4L XMM5H XMM5L XMM6H XMM6L XMM7H XMM7L'
- 	classVariableNames: 'CDQ CMPXCHGAwR CMPXCHGMwrR CPUID IDIVR IMULRR LFENCE LOCK MFENCE ModReg ModRegInd ModRegIndDisp32 ModRegIndSIB ModRegRegDisp32 ModRegRegDisp8 R10 R11 R12 R13 R14 R15 R8 R9 RAX RBP RBX RCX RDI RDX RSI RSP SFENCE SIB1 SIB2 SIB4 SIB8 XCHGAwR XCHGMwrR XCHGRR XMM0H XMM0L XMM1H XMM1L XMM2H XMM2L XMM3H XMM3L XMM4H XMM4L XMM5H XMM5L XMM6H XMM6L XMM7H XMM7L'
  	poolDictionaries: ''
  	category: 'VMMaker-JIT'!
  
  !CogX64Compiler commentStamp: 'eem 9/14/2015 17:12' prior: 0!
  I generate x64 (x86-64) instructions from CogAbstractInstructions.  For reference see
  1. IA-32 Intel® Architecture Software Developer's Manual Volume 2A: Instruction Set Reference, A-M
  2. IA-32 Intel® Architecture Software Developer's Manual Volume 2A: Instruction Set Reference, N-Z
  	http://www.intel.com/products/processor/manuals/
  or
  AMD64 Architecture Programmer's Manual Volume 3: General-Purpose and System Instructions
  AMD64 Architecture Programmer's Manual Volume 4: 128-bit Media Instructions
  AMD64 Architecture Programmer's Manual Volume 5: 64-bit Media and x87 Floating Point Instructions
  	http://developer.amd.com/resources/documentation-articles/developer-guides-manuals/
  (® is supposed to be the Unicode "registered  sign").!

Item was added:
+ ----- Method: CogX64Compiler class>>ABI (in category 'accessing') -----
+ ABI
+ 	"Answer the name of the supported ABI, #SysV or #MSVC"
+ 	^ABI!

Item was changed:
  ----- Method: CogX64Compiler class>>initialize (in category 'class initialization') -----
  initialize
  	"Initialize various x64 instruction-related constants.
  	 [1] IA-32 Intel® Architecture Software Developer's Manual Volume 2A: Instruction Set Reference, A-M"
  
  	"CogX64Compiler initialize"
  
  	| specificOpcodes refs |
  	self ~~ CogX64Compiler ifTrue: [^self].
  
+ 	ABI ifNil:
+ 		[ABI := #SysV]. "Default ABI; other choice is #MSVC"
+ 
  	RAX := 0.
  	RCX := 1.  "Were they completely mad or simply sadistic?"
  	RDX := 2.
  	RBX := 3.
  	RSP := 4.
  	RBP := 5.
  	RSI := 6.
  	RDI := 7.
  	R8 := 8.
  	R9 := 9.
  	R10 := 10.
  	R11 := 11.
  	R12 := 12.
  	R13 := 13.
  	R14 := 14.
  	R15 := 15.
  
  	XMM0L := 0.
  	XMM1L := 2.
  	XMM2L := 4.
  	XMM3L := 6.
  	XMM4L := 8.
  	XMM5L := 10.
  	XMM6L := 12.
  	XMM7L := 14.
  
  	XMM0H := 1.
  	XMM1H := 3.
  	XMM2H := 5.
  	XMM3H := 7.
  	XMM4H := 9.
  	XMM5H := 11.
  	XMM6H := 13.
  	XMM7H := 15.
  
  	"Mod R/M Mod fields.  See [1] Sec 2.4, 2.5 & 2.6 & Table 2-2"
  	ModRegInd := 0.
  		ModRegIndSIB := 4.
  		ModRegIndDisp32 := 5.
  	ModRegRegDisp8 := 1.
  	ModRegRegDisp32 := 2.
  	ModReg := 3.
  
  	"SIB Scaled Index modes.  See [1] Sec 2.4, 2.5 & 2.6 & Table 2-3"
  	SIB1 := 0.
  	SIB2 := 1.
  	SIB4 := 2.
  	SIB8 := 3.
  
  	"Specific instructions"
  	LastRTLCode ifNil:
  		[CogRTLOpcodes initialize].
  	specificOpcodes := #(CDQ IDIVR IMULRR CPUID LFENCE MFENCE SFENCE LOCK CMPXCHGAwR CMPXCHGMwrR XCHGAwR XCHGMwrR XCHGRR).
  	refs := (thisContext method literals select: [:l| l isVariableBinding and: [classPool includesKey: l key]]) collect:
  				[:ea| ea key].
  	(classPool keys reject: [:k| (specificOpcodes includes: k) or: [refs includes: k]]) do:
  		[:k|
  		Undeclared declare: k from: classPool].
  	specificOpcodes withIndexDo:
  		[:classVarName :value|
  		self classPool
  			declare: classVarName from: Undeclared;
  			at: classVarName put: value + LastRTLCode - 1]!

Item was changed:
  ----- Method: CogX64Compiler>>genMarshallNArgs:arg:arg:arg:arg: (in category 'abi') -----
  genMarshallNArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3
  	"Generate the code to pass up to four arguments in a C run-time call.  Hack: each argument is either a
  	 negative number, that of an abstract register, or a non-negative number, that of a constant parameter.
  
  	 Run-time calls have no more than four arguments, so chosen so that on ARM, where in its C ABI the
  	 first four integer arguments are passed in registers, all arguments can be passed in registers.  We
+ 	 defer to the back end to generate this code not so much that the back end knows whether it uses
- 	 defer to the back end to generate this code not so much that teh back end knows whether it uses
  	 the stack or registers to pass arguments (it does, but...). In fact we defer for an extremely evil reason.
  	 Doing so allows the x64 (where up to 6 args are passed) to assign the register arguments in an order
+ 	 that allows some of the argument registers to be used for specific abstract  registers, specifically
- 	 that allows some of the argument registers to be used for specificabstract  registers, specifically
  	 ReceiverResultReg and ClassReg.  This is evil, evil, evil, but also its really nice to keep using the old
  	 register assignments the principal author has grown accustomed to.
  
  	 How can this possibly work?  Look at Cogit class>>runtime for a list of the run-time calls and their
  	 arguments, including which arguments are passed in which registers.  Look at CogX64Compiler's
  	 subclass implementations of concreteRegister:.  There are no calls in which ReceiverResultReg (RDX)
  	 and/or ClassReg (RCX) are passed along with Arg0Reg and Arg1Reg, and none in which the use of
  	 either ReceiverResultReg or ClassReg conflict for args 3 & 4.  So if args are assigned in order, the
  	 registers do not get overwritten.  Yes, this is evil, but it's so nice to continue to use RCX & RDX."
  	<inline: true>
  	numArgs = 0 ifTrue: [^self].
  	regOrConst0 >= 0
  		ifTrue: [cogit MoveCq: regOrConst0 R: RDI]
  		ifFalse:
  			[(self concreteRegister: regOrConst0) ~= RDI ifTrue:
  				[cogit MoveR: regOrConst0 R: RDI]].
  	numArgs = 1 ifTrue: [^self].
  	regOrConst1 >= 0
  		ifTrue: [cogit MoveCq: regOrConst1 R: RSI]
  		ifFalse:
  			[(self concreteRegister: regOrConst1) ~= RSI ifTrue:
  				[cogit MoveR: regOrConst1 R: RSI]].
  	numArgs = 2 ifTrue: [^self].
+ 	self cppIf: ABI == #SysV ifTrue:
+ 		[regOrConst2 >= 0
+ 			ifTrue: [cogit MoveCq: regOrConst2 R: RDX]
+ 			ifFalse:
+ 				[(self concreteRegister: regOrConst2) ~= RDX ifTrue:
+ 					[cogit MoveR: regOrConst2 R: RDX]].
+ 		 numArgs = 3 ifTrue: [^self].
+ 		 regOrConst3 >= 0
+ 				ifTrue: [cogit MoveCq: regOrConst3 R: RCX]
+ 				ifFalse:
+ 					[(self concreteRegister: regOrConst3) ~= RCX ifTrue:
+ 						[cogit MoveR: regOrConst3 R: RCX]]].
+ 	self cppIf: ABI == #MSVC ifTrue:
+ 		[regOrConst2 >= 0
+ 			ifTrue: [cogit MoveCq: regOrConst2 R: R8]
+ 			ifFalse:
+ 				[(self concreteRegister: regOrConst2) ~= R8 ifTrue:
+ 					[cogit MoveR: regOrConst2 R: R8]].
+ 		 numArgs = 3 ifTrue: [^self].
+ 		 regOrConst3 >= 0
+ 				ifTrue: [cogit MoveCq: regOrConst3 R: R9]
+ 				ifFalse:
+ 					[(self concreteRegister: regOrConst3) ~= R9 ifTrue:
+ 						[cogit MoveR: regOrConst3 R: R9]]].
+ 	self assert: numArgs <= 4!
- 	regOrConst2 >= 0
- 		ifTrue: [cogit MoveCq: regOrConst2 R: RDX]
- 		ifFalse:
- 			[(self concreteRegister: regOrConst2) ~= RDX ifTrue:
- 				[cogit MoveR: regOrConst2 R: RDX]].
- 	numArgs = 3 ifTrue: [^self].
- 	regOrConst3 >= 0
- 		ifTrue: [cogit MoveCq: regOrConst3 R: RCX]
- 		ifFalse:
- 			[(self concreteRegister: regOrConst3) ~= RCX ifTrue:
- 				[cogit MoveR: regOrConst3 R: RCX]]!

Item was changed:
  ----- Method: CogX64Compiler>>is32BitSignedImmediate: (in category 'testing') -----
  is32BitSignedImmediate: a64BitUnsignedOperand
+ 	^self cCode: [(self cCoerceSimple: a64BitUnsignedOperand to: #int) = (self cCoerceSimple: a64BitUnsignedOperand to: #long)]
+ 		inSmalltalk: [((a64BitUnsignedOperand >> 32) signedIntFromLong between: -1 and: 0)
+ 					and: [(a64BitUnsignedOperand >> 31) signedIntFromLong between: -1 and: 0]]!
- 	^(a64BitUnsignedOperand >> 31) signedIntFromLong between: -1 and: 0!

Item was changed:
  ----- Method: CogX64Compiler>>mod:RM:RO: (in category 'encoding') -----
  mod: mod RM: regMode RO: regOpcode
+ 	"See ModR/M byte & opcode syntax
+ 	 In addition to the notation shown above in 'Mnemonic Syntax' on page 43,
+ 	 the following notation indicates the size and type of operands in the syntax of an instruction opcode:
+ 		/digit	Indicates that the ModRM byte specifies only one register or memory (r/m) operand.
+ 				The digit is specified by the ModRM reg field and is used as an instruction-opcode extension.
+ 				Valid digit values range from 0 to 7.
+ 		/r		Indicates that the ModRM byte specifies both a register operand and a reg/mem (register or memory) operand."
  	^mod << 6 + ((regOpcode bitAnd: 7) << 3) + (regMode bitAnd: 7)!

Item was changed:
  ----- Method: CogX64CompilerTests>>varBaseAddress (in category 'accessing') -----
  varBaseAddress
+ 	"Answer a value that should be sufficiently high that var base relative addressing is never generated."
- 	"Answer a value that should be sufficiently high that var bare relative addressing is never generated."
  	^1 << 60!

Item was changed:
  ----- Method: Cogit>>handleReadSimulationTrap: (in category 'simulation only') -----
  handleReadSimulationTrap: aProcessorSimulationTrap
+ 	"Try to read the value of a variable given its fake address in simulatedVariableGetters.
+ 	 simulatedVariableGetters maps to an evaluable that yields the variable's actual value.
+ 	 To support the x64, also gracefully accept an address which is in simulatedTrampolines,
+ 	 in which case no mapping is necessary."
  	<doNotGenerate>
+ 	| address variableValue accessor |
+ 	address := aProcessorSimulationTrap address.
+ 	variableValue := (simulatedVariableGetters
+ 						at: address
+ 						ifAbsent:
+ 							[(simulatedTrampolines includesKey: address)
+ 								ifTrue: [address]
+ 								ifFalse: [simulatedVariableGetters errorKeyNotFound]]) value asInteger.
- 	| variableValue accessor |
- 	variableValue := (simulatedVariableGetters at: aProcessorSimulationTrap address) value asInteger.
  	accessor := aProcessorSimulationTrap registerAccessor.
  	processor
  		perform: accessor
+ 		with: (variableValue == address
+ 				ifTrue: [address]
+ 				ifFalse: [processor convertIntegerToInternal: variableValue]).
- 		with: variableValue signedIntToLong.
  	accessor ~~ #pc: ifTrue:
  		[processor pc: aProcessorSimulationTrap nextpc]!

Item was changed:
  ----- Method: Cogit>>setCFramePointer: (in category 'accessing') -----
  setCFramePointer: aFramePointer
  	<api>
  	<cmacro: '(theFP) (CFramePointer = (void *)(theFP))'>
  	"and in the simulator we use..."
  	^(backEnd wantsNearAddressFor: #CFramePointer)
+ 		ifTrue: [CFramePointer := aFramePointer]
- 		ifTrue: [CFramePointer]
  		ifFalse: [objectMemory
  					longAt: coInterpreter inMemoryCFramePointerAddress
  					put: aFramePointer]!

Item was changed:
  ----- Method: Cogit>>setCStackPointer: (in category 'accessing') -----
  setCStackPointer: aStackPointer
  	<api>
  	<cmacro: '(theSP) (CStackPointer = (void *)(theSP))'>
  	"and in the simulator we use..."
  	^(backEnd wantsNearAddressFor: #CStackPointer)
+ 		ifTrue: [CStackPointer := aStackPointer]
- 		ifTrue: [CStackPointer]
  		ifFalse: [objectMemory
  					longAt: coInterpreter inMemoryCStackPointerAddress
  					put: aStackPointer]!



More information about the Vm-dev mailing list