[Vm-dev] VM Maker: VMMaker.oscog-tpr.803.mcz

commits at source.squeak.org commits at source.squeak.org
Sat Jul 5 00:17:21 UTC 2014


tim Rowledge uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-tpr.803.mcz

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

Name: VMMaker.oscog-tpr.803
Author: tpr
Time: 3 July 2014, 11:13:54.112 pm
UUID: c45ecb48-3e6b-469d-9cb6-463e70ef2cce
Ancestors: VMMaker.oscog-eem.802

Changes that get us to compiling primitive 3 and needing all the floating point ARM stuff worked on.
Correct enilopmart used in activateCoggedNewMethod: avoids stack imbalance failure.
Fix genPushRegisterArgsForNumArgs: to push the receiverresultreg even when there are no args, just like the ia32 does.
Change to pushingthe substitue return address rather than putting it in the LR and leaving it to get smashed later.
Correct genEnilopmartFor:  [and: regArg2][ and: regArg3] called: to pop into the PC when appropriate. LR just doesn't do the job in this case.

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

Item was changed:
  ----- Method: CoInterpreter>>activateCoggedNewMethod: (in category 'message sending') -----
  activateCoggedNewMethod: inInterpreter
  	"Activate newMethod when newMethod has been cogged, i.e. create a machine-code frame and (re)enter machine-code."
  	| methodHeader cogMethod rcvr numTemps errorCode switched |
  	<var: #cogMethod type: #'CogMethod *'>
  
  	methodHeader := self rawHeaderOf: newMethod.
  	self assert: (self isCogMethodReference: methodHeader).
  
  	cogMethod := self cCoerceSimple: methodHeader to: #'CogMethod *'.
  	methodHeader := cogMethod methodHeader.
  	rcvr := self stackValue: cogMethod cmNumArgs. "could new rcvr be set at point of send?"
  	self push: instructionPointer.
  	cogMethod stackCheckOffset = 0 ifTrue:
  		["frameless method; nothing to activate..."
  		 cogit numRegArgs > 0 ifTrue: "dont use and: so as to get Slang to inline cogit numRegArgs > 0"
  			[cogMethod cmNumArgs <= cogit numRegArgs ifTrue:
  				[self callRegisterArgCogMethod: cogMethod at: cogit noCheckEntryOffset receiver: rcvr]].
  		 self push: cogMethod asInteger + cogit noCheckEntryOffset.
  		 self push: rcvr.
  		 cogit ceCallCogCodePopReceiverReg.
  		 self error: 'should not be reached'].
  	self push: framePointer.
  	framePointer := stackPointer.
  	self push: cogMethod asInteger.
  	self push: objectMemory nilObject. "FxThisContext field"
  	self push: rcvr.
  
  	"clear remaining temps to nil"
  	numTemps := self temporaryCountOfMethodHeader: methodHeader.
  	cogMethod cmNumArgs + 1 to: numTemps do:
  		[:i | self push: objectMemory nilObject].
  
  	(self methodHeaderHasPrimitive: methodHeader) ifTrue:
  		[| initialPC |
  		 "Store the error code if the method starts with a long store temp.  No instructionPointer skip because we're heading for machine code."
  		 initialPC := (self initialPCForHeader: methodHeader method: newMethod) + (self sizeOfCallPrimitiveBytecode: methodHeader).
  		 primFailCode ~= 0 ifTrue:
  			[(objectMemory byteAt: initialPC) = (self longStoreBytecodeForHeader: methodHeader) ifTrue:
  				[errorCode := self getErrorObjectFromPrimFailCode.
  				 self stackTopPut: errorCode "nil if primFailCode == 1, or primFailCode"].
  			 primFailCode := 0]].
  
  	"Now check for stack overflow or an event (interrupt, must scavenge, etc)."
  	stackPointer >= stackLimit ifTrue:
  		[self assert: cogMethod stackCheckOffset > cogit noCheckEntryOffset.
  		 self push: cogMethod asInteger + cogMethod stackCheckOffset.
  		 self push: rcvr.
+ 		 cogit ceEnterCogCodePopReceiverReg.
- 		 cogit ceCallCogCodePopReceiverReg.
  		 self error: 'should not be reached'].
  	instructionPointer := cogMethod asInteger + cogMethod stackCheckOffset.
  	switched := self handleStackOverflowOrEventAllowContextSwitch: (self canContextSwitchIfActivating: newMethod header: methodHeader).
  	self returnToExecutive: inInterpreter postContextSwitch: switched!

Item was changed:
  ----- Method: CogARMCompiler>>genAlignCStackSavingRegisters:numArgs:wordAlignment: (in category 'abi') -----
  genAlignCStackSavingRegisters: saveRegs numArgs: numArgs wordAlignment: alignment 
  	"ARM needs 8 byte stack alignment but it's hard to be sure where the stack is at this
  	 point due to the complexities of whether we push the return address or not.  So do
  	 a simple bitAnd to effectively round-down the SP - except the vagaries of the ARM
  	 instruction set means we actually need a BIC sp, sp, $7"
  
- 	cogit gen: BICCqR operand: 2r111 operand: SPReg.
  	^0!

Item was changed:
  ----- Method: CogARMCompiler>>genPushRegisterArgsForNumArgs: (in category 'smalltalk calling convention') -----
  genPushRegisterArgsForNumArgs: numArgs
  	"Ensure that the register args are pushed before the retpc for arity <= self numRegArgs."
  	"This is easy on a RISC like ARM because the return address is in the link register.  Putting
  	 the receiver and args above the return address means the CoInterpreter has a single
+ 	 machine-code frame format which saves us a lot of work
+ 	NOTA BENE: we do NOT push the return address here, which means it must be dealt with later."
- 	 machine-code frame format which saves us a lot of work."
  	numArgs <= cogit numRegArgs ifTrue:
  		[self assert: cogit numRegArgs <= 2.
+ 		 cogit PushR: ReceiverResultReg.
+ 		numArgs > 0 ifTrue:
+ 			[cogit PushR: Arg0Reg.
- 		 numArgs > 0 ifTrue:
- 			[cogit PushR: ReceiverResultReg.
- 			 cogit PushR: Arg0Reg.
  			 numArgs > 1 ifTrue:
  				[cogit PushR: Arg1Reg]]]!

Item was changed:
  ----- Method: CogARMCompiler>>genSubstituteReturnAddress: (in category 'abstract instructions') -----
  genSubstituteReturnAddress: retpc
  	<inline: true>
  	<returnTypeC: #'AbstractInstruction *'>
+ 	"This code needs to be tightly correlated across:-
+ 		GdbARMAlien>simulateJumpCallOf:memory:
+ 		GdbARMAlien>simulateCallOf:nextpc:memory:
+ 		GdbARMAlien>simulateReturnIn:
+ 		GdbARMAlien>retpcIn:
+ 		CogARMCompiler>genSubstituteReturnAddress:
+ 	Getting any one of them doing something different will cause much pain"
+ 	^cogit  PushCw: retpc!
- 	^cogit MoveCw: retpc R: LR!

Item was changed:
  ----- Method: CogARMCompilerTests>>testAdd (in category 'tests') -----
  testAdd
  	"self new testAdd"
  	
  	"the forms are valid, "
  	"test AddCqR"
  	self concreteCompilerClass registersWithNamesDo: [ :reg :regName |
  		#(0 16rF 16rFF) do:
  			[:n| | inst len |
  			inst := self gen: AddCqR operand: n operand: reg.
  			len := inst concretizeAt: 0.
  			self processor
  				disassembleInstructionAt: 0
  				In: inst machineCode object
  				into: [:str :sz| | plainJane herIntended |
  					plainJane := self strip: str.
  					herIntended := 'adds	', regName, ', ', regName, ', #', n asString.
  					self assert: (plainJane match: herIntended)]]].
  		
  	"test AddCwR"
  	self concreteCompilerClass registersWithNamesDo: [ :reg :regName |
  		#(16rFFFFFFFF 16r88888888 0) do:
  			[:n| | inst len |
  			inst := self gen: AddCwR operand: n operand: reg.
  			len := inst concretizeAt: 0.
  			self processor
  				disassembleInstructionAt: 0
  				In: inst machineCode object
  				into: [:str :sz| | plainJane herIntended |
  					plainJane := self strip: str.
+ 					herIntended := 'mov	sl, #', (n bitAnd: 16rFF << 24) asString.
- 					herIntended := 'mov	sl, #', (n bitAnd: 16rFF << 8) asString.
  					self assert: (plainJane match: herIntended)].
  			self processor
  				disassembleInstructionAt: 4
  				In: inst machineCode object
  				into: [:str :sz| | plainJane herIntended |
  					plainJane := self strip: str.
  					herIntended := 'orr	sl, sl, #', (n bitAnd: 16rFF << 16) asString.
  					self assert: (plainJane match: herIntended)].
  			self processor
  				disassembleInstructionAt: 8
  				In: inst machineCode object
  				into: [:str :sz| | plainJane herIntended |
  					plainJane := self strip: str.
+ 					herIntended := 'orr	sl, sl, #', (n bitAnd: 16rFF << 8) signedIntFromLong asString.
- 					herIntended := 'orr	sl, sl, #', (n bitAnd: 16rFF << 24) signedIntFromLong asString.
  					self assert: (plainJane match: herIntended)].
  			self processor
  				disassembleInstructionAt: 12
  				In: inst machineCode object
  				into: [:str :sz| | plainJane herIntended |
  					plainJane := self strip: str.
  					herIntended := 'orr	sl, sl, #', (n bitAnd: 16rFF) asString.
  					self assert: (plainJane match: herIntended)].
  			self processor
  				disassembleInstructionAt: 16
  				In: inst machineCode object
  				into: [:str :sz| | plainJane herIntended |
  					plainJane := self strip: str.
  					herIntended := 'adds	', regName, ', ', regName, ', sl'.
  					self assert: (plainJane match: herIntended)]]]
  !

Item was changed:
  ----- Method: Cogit>>compileAbort (in category 'compile abstract instructions') -----
  compileAbort
  	"The start of a CogMethod has a call to a run-time abort routine that either
  	 handles an in-line cache failure or a stack overflow.  The routine selects the
  	 path depending on ReceiverResultReg; if zero it takes the stack overflow
  	 path; if nonzero the in-line cache miss path.  Neither of these paths returns.
  	 The abort routine must be called;  In the callee the method is located by
  	 adding the relevant offset to the return address of the call."
  	stackOverflowCall := self MoveCq: 0 R: ReceiverResultReg.
  	backEnd hasLinkRegister
  		ifTrue:
+ 			["if we have a link register we will assume that it does not get automatically pushed onto the stack
+ 			and thus needs to be manually handled here"
+ 			sendMiss := self PushR: LinkReg.
- 			[sendMiss := self PushR: LinkReg.
  			 sendMissCall := self Call: (self methodAbortTrampolineFor: methodOrBlockNumArgs)]
  		ifFalse:
  			[sendMiss :=
  			 sendMissCall := self Call: (self methodAbortTrampolineFor: methodOrBlockNumArgs)]!

Item was changed:
  ----- Method: Cogit>>compilePICProlog: (in category 'in-line cacheing') -----
  compilePICProlog: numArgs
  	"The start of a PIC has a call to a run-time abort routine that either handles
  	 a dispatch to an interpreted method or a dispatch of an MNU case.  The
  	 routine selects the path depending on ClassReg; if zero it takes the MNU
  	 path; if nonzero the dispatch to interpreter path.  Neither of these paths
  	 returns. The abort routine must be called;  In the callee the PIC is located
  	 by adding the relevant offset to the return address of the call."
  	mnuCall := self MoveCq: 0 R: ClassReg.
  	backEnd hasLinkRegister
  		ifTrue:
+ 			["if we have a link register we will assume that it does not get automatically pushed onto the stack
+ 			and thus needs to be manually handled here"
+ 			 interpretLabel := self PushR: LinkReg.
- 			[interpretLabel := self PushR: LinkReg.
  			 interpretCall := self Call: (self picAbortTrampolineFor: numArgs)]
  		ifFalse:
  			[interpretLabel :=
  			 interpretCall := self Call: (self picAbortTrampolineFor: numArgs)].
  	^0!

Item was changed:
  ----- Method: Cogit>>genCheckForInterruptsTrampoline (in category 'initialization') -----
  genCheckForInterruptsTrampoline
  	opcodeIndex := 0.
+ 	"if we have a link register we will assume that it does not get automatically pushed onto the stack
+ 	and thus there is no need to pop it before saving to instructionPointerAddress"
  	backEnd hasLinkRegister
  		ifTrue:
  			[self MoveR: LinkReg Aw: coInterpreter instructionPointerAddress]
  		ifFalse:
  			[self PopR: TempReg. "instruction pointer"
  			 self MoveR: TempReg Aw: coInterpreter instructionPointerAddress].
  	^self genTrampolineFor: #ceCheckForInterrupts
  		called: 'ceCheckForInterruptsTrampoline'
  		numArgs: 0
  		arg: nil
  		arg: nil
  		arg: nil
  		arg: nil
  		saveRegs: false
  		pushLinkReg: false
  		resultReg: nil
  		appendOpcodes: true!

Item was changed:
  ----- Method: Cogit>>genEnilopmartFor:and:and:called: (in category 'initialization') -----
  genEnilopmartFor: regArg1 and: regArg2 and: regArg3 called: trampolineName
  	"An enilopmart (the reverse of a trampoline) is a piece of code that makes
  	 the system-call-like transition from the C runtime into generated machine
  	 code.  The desired arguments and entry-point are pushed on a stackPage's
  	 stack.  The enilopmart pops off the values to be loaded into registers and
  	 then executes a return instruction to pop off the entry-point and jump to it.
  
  						BEFORE				AFTER			(stacks grow down)
  						whatever			stackPointer ->	whatever
  						target address =>	reg1 = reg1val, etc
  						reg1val				pc = target address
  						reg2val
  		stackPointer ->	reg3val
  
  	C.F. genCallEnilopmartFor:and:and:called:"
  	<returnTypeC: 'void (*genEnilopmartForandandcalled(sqInt regArg1, sqInt regArg2, sqInt regArg3, char *trampolineName))(void)'>
  	| size endAddress enilopmart |
  	opcodeIndex := 0.
  	backEnd genLoadStackPointers.
  	self PopR: regArg3.
  	self PopR: regArg2.
  	self PopR: regArg1.
  	backEnd hasLinkRegister
  		ifTrue: [backEnd hasPCRegister
+ 					ifTrue: [self PopR: PCReg]
- 					ifTrue: [self PopR: LinkReg]
  					ifFalse: [self PopR: LinkReg; RetN: 0]]
  		ifFalse: [self RetN: 0].
  	self computeMaximumSizes.
  	size := self generateInstructionsAt: methodZoneBase.
  	endAddress := self outputInstructionsAt: methodZoneBase.
  	self assert: methodZoneBase + size = endAddress.
  	enilopmart := methodZoneBase.
  	methodZoneBase := self alignUptoRoutineBoundary: endAddress.
  	backEnd nopsFrom: endAddress to: methodZoneBase - 1.
  	self recordGeneratedRunTime: trampolineName address: enilopmart.
  	^self cCoerceSimple: enilopmart to: #'void (*)(void)'!

Item was changed:
  ----- Method: Cogit>>genEnilopmartFor:and:called: (in category 'initialization') -----
  genEnilopmartFor: regArg1 and: regArg2 called: trampolineName
  	"An enilopmart (the reverse of a trampoline) is a piece of code that makes
  	 the system-call-like transition from the C runtime into generated machine
  	 code.  The desired arguments and entry-point are pushed on a stackPage's
  	 stack.  The enilopmart pops off the values to be loaded into registers and
  	 then executes a return instruction to pop off the entry-point and jump to it.
  
  						BEFORE				AFTER			(stacks grow down)
  						whatever			stackPointer ->	whatever
  						target address =>	reg1 = reg1val, etc
  						reg1val				pc = target address
  		stackPointer ->	reg2val
  
  	C.F. genCallEnilopmartFor:and:and:called:"
  	<returnTypeC: 'void (*genEnilopmartForandandcalled(sqInt regArg1, sqInt regArg2, char *trampolineName))(void)'>
  	| size endAddress enilopmart |
  	opcodeIndex := 0.
  	backEnd genLoadStackPointers.
  	self PopR: regArg2.
  	self PopR: regArg1.
  	backEnd hasLinkRegister
  		ifTrue: [backEnd hasPCRegister
+ 					ifTrue: [self PopR: PCReg]
- 					ifTrue: [self PopR: LinkReg]
  					ifFalse: [self PopR: LinkReg; RetN: 0]]
  		ifFalse: [self RetN: 0].
  	self computeMaximumSizes.
  	size := self generateInstructionsAt: methodZoneBase.
  	endAddress := self outputInstructionsAt: methodZoneBase.
  	self assert: methodZoneBase + size = endAddress.
  	enilopmart := methodZoneBase.
  	methodZoneBase := self alignUptoRoutineBoundary: endAddress.
  	backEnd nopsFrom: endAddress to: methodZoneBase - 1.
  	self recordGeneratedRunTime: trampolineName address: enilopmart.
  	^self cCoerceSimple: enilopmart to: #'void (*)(void)'!

Item was changed:
  ----- Method: Cogit>>genEnilopmartFor:called: (in category 'initialization') -----
  genEnilopmartFor: regArg1 called: trampolineName
  	"An enilopmart (the reverse of a trampoline) is a piece of code that makes
  	 the system-call-like transition from the C runtime into generated machine
  	 code.  The desired arguments and entry-point are pushed on a stackPage's
  	 stack.  The enilopmart pops off the values to be loaded into registers and
  	 then executes a return instruction to pop off the entry-point and jump to it.
  
  						BEFORE				AFTER			(stacks grow down)
  						whatever			stackPointer ->	whatever
  						target address =>	reg1 = reg1val
  		stackPointer ->	reg1val				pc = target address
  
  	C.F. genCallEnilopmartFor:and:and:called:"
  	<returnTypeC: 'void (*genEnilopmartForandandcalled(sqInt regArg1, char *trampolineName))(void)'>
  	| size endAddress enilopmart |
  	opcodeIndex := 0.
  	backEnd genLoadStackPointers.
  	self PopR: regArg1.
  	backEnd hasLinkRegister
  		ifTrue: [backEnd hasPCRegister
+ 					ifTrue: [self PopR: PCReg]
- 					ifTrue: [self PopR: LinkReg]
  					ifFalse: [self PopR: LinkReg; RetN: 0]]
  		ifFalse: [self RetN: 0].
  	self computeMaximumSizes.
  	size := self generateInstructionsAt: methodZoneBase.
  	endAddress := self outputInstructionsAt: methodZoneBase.
  	self assert: methodZoneBase + size = endAddress.
  	enilopmart := methodZoneBase.
  	methodZoneBase := self alignUptoRoutineBoundary: endAddress.
  	backEnd nopsFrom: endAddress to: methodZoneBase - 1.
  	self recordGeneratedRunTime: trampolineName address: enilopmart.
  	^self cCoerceSimple: enilopmart to: #'void (*)(void)'!



More information about the Vm-dev mailing list