[Vm-dev] VM Maker: VMMaker.oscog-EstebanLorenzano.2273.mcz

commits at source.squeak.org commits at source.squeak.org
Mon Oct 16 12:37:16 UTC 2017


Esteban Lorenzano uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-EstebanLorenzano.2273.mcz

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

Name: VMMaker.oscog-EstebanLorenzano.2273
Author: EstebanLorenzano
Time: 16 October 2017, 2:36:10.432545 pm
UUID: 52109b4e-0757-4034-96bd-315af49be0fc
Ancestors: VMMaker.oscog-cb.2271

fix incorrect SistaCogitClone removal 

=============== Diff against VMMaker.oscog-cb.2271 ===============

Item was removed:
- ----- Method: SistaCogitClone class>>methodZoneClass (in category 'accessing class hierarchy') -----
- methodZoneClass
- 	^SistaMethodZone!

Item was removed:
- ----- Method: SistaCogitClone>>defaultCogCodeSize (in category 'accessing') -----
- defaultCogCodeSize
- 	"Return the default number of bytes to allocate for native code at startup.
- 	 The actual value can be set via vmParameterAt: and/or a preference in the ini file."
- 	<api>
- 	^2 * backEnd getDefaultCogCodeSize!

Item was removed:
- ----- Method: SistaCogitClone>>genAtPutInlinePrimitive: (in category 'inline primitive generators') -----
- genAtPutInlinePrimitive: prim
- 	"Unary inline primitives."
- 	"SistaV1: 248		11111000 	iiiiiiii		mjjjjjjj		Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.
- 	 See EncoderForSistaV1's class comment and StackInterpreter>>#trinaryInlinePrimitive:"
- 	| ra1 ra2 rr adjust needsStoreCheck |
- 	"The store check requires rr to be ReceiverResultReg"
- 	needsStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
- 	self 
- 		allocateRegForStackTopThreeEntriesInto: [:rTop :rNext :rThird | ra2 := rTop. ra1 := rNext. rr := rThird ] 
- 		thirdIsReceiver: (prim = 0 and: [ needsStoreCheck ]).
- 	self assert: (rr ~= ra1 and: [rr ~= ra2 and: [ra1 ~= ra2]]).
- 	self ssTop popToReg: ra2.
- 	self ssPop: 1.
- 	self ssTop popToReg: ra1.
- 	self ssPop: 1.
- 	self ssTop popToReg: rr.
- 	self ssPop: 1.
- 	objectRepresentation genConvertSmallIntegerToIntegerInReg: ra1.
- 	"Now: ra is the variable object, rr is long, TempReg holds the value to store."
- 	self flag: #TODO. "This is not really working as the immutability and store check needs to be present. "
- 	prim caseOf: {
- 		"0 - 1 pointerAt:put: and byteAt:Put:"
- 		[0] ->	[ adjust := (objectMemory baseHeaderSize >> objectMemory shiftForWord) - 1. "shift by baseHeaderSize and then move from 1 relative to zero relative"
- 				adjust ~= 0 ifTrue: [ self AddCq: adjust R: ra1. ]. 
- 				self MoveR: ra2 Xwr: ra1 R: rr.
- 				"I added needsStoreCheck so if you initialize an array with a Smi such as 0 or a boolean you don't need the store check"
- 				needsStoreCheck ifTrue: 
- 					[ self assert: needsFrame. 
- 					objectRepresentation genStoreCheckReceiverReg: rr valueReg: ra2 scratchReg: TempReg inFrame: true] ].
- 		[1] ->	[ objectRepresentation genConvertSmallIntegerToIntegerInReg: ra2.
- 				adjust := objectMemory baseHeaderSize - 1. "shift by baseHeaderSize and then move from 1 relative to zero relative"
- 				self AddCq: adjust R: ra1.
- 				self MoveR: ra2 Xbr: ra1 R: rr.
- 				objectRepresentation genConvertIntegerToSmallIntegerInReg: ra2. ].
- 	}
- 	otherwise: [^EncounteredUnknownBytecode].
- 	self ssPushRegister: ra2.
- 	^0!

Item was removed:
- ----- Method: SistaCogitClone>>genByteEqualsInlinePrimitive: (in category 'inline primitive generators') -----
- genByteEqualsInlinePrimitive: prim
- 
- 	"3021	Byte Object >> equals:length:	
- 	The receiver and the arguments are both byte objects and have both the same size (length in bytes). 
- 	The length argument is a smallinteger. 
- 	Answers true if all fields are equal, false if not. 
- 	Comparison is bulked to word comparison."
- 	
- 	"Overview: 
- 	 1.	The primitive is called like that: [byteObj1 equals: byteObj2 length: length].
- 	  	In the worst case we use 5 registers including TempReg 
- 		and we produce a loop bulk comparing words.
- 	 2.	The common case is a comparison against a cst: [byteString = 'foo'].
- 		which produces in Scorch [byteString equals: 'foo' length: 3].
- 		We try to generate fast code for this case with 3 heuristics:
- 		- specific fast code if len is a constant
- 		- unroll the loop if len < 2 * wordSize
- 		- compile-time reads if str1 or str2 is a constant and loop is unrolled.
- 		We use 3 registers including TempReg in the common case. 
- 		We could use 1 less reg if the loop is unrolled, the instr is followed by a branch
- 		AND one operand is a constant, but this is complicated enough.
- 	3.	We ignore the case where all operands are constants 
- 		(We assume Scorch simplifies it, it works but it is not optimised)"
- 		
- 	| str1Reg str2Reg lenReg extraReg jmp jmp2 needjmpZeroSize needLoop unroll jmpZeroSize instr lenCst mask |
- 	<var: #jmp type: #'AbstractInstruction *'>
- 	<var: #instr type: #'AbstractInstruction *'>
- 	<var: #jmp2 type: #'AbstractInstruction *'>
- 	<var: #jmpZeroSize type: #'AbstractInstruction *'>
- 
- 	"--- quick path for empty string---"
- 	"This path does not allocate registers and right shift on negative int later in the code.
- 	 Normally this is resolved by Scorch but we keep it for correctness and consistency"
- 	self ssTop type = SSConstant ifTrue: 
- 		[ lenCst := objectMemory integerValueOf: self ssTop constant.
- 		  lenCst = 0 ifTrue: [ self ssPop: 3. self ssPushConstant: objectMemory trueObject. ^ 0 ] ].
- 
- 	"--- Allocating & loading registers --- "
- 	needLoop := (self ssTop type = SSConstant and: [ lenCst <= (objectMemory wordSize * 2) ]) not.
- 	unroll := needLoop not and: [lenCst > objectMemory wordSize ].
- 	needLoop 
- 		ifTrue: 
- 			[ str1Reg := self allocateRegForStackEntryAt: 1 notConflictingWith: self emptyRegisterMask.
- 			  str2Reg := self allocateRegForStackEntryAt: 2 notConflictingWith: (self registerMaskFor: str1Reg).
- 			  lenReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor:str1Reg and: str2Reg).
- 			  (self ssValue: 1) popToReg: str1Reg.
- 			  (self ssValue: 2) popToReg: str2Reg.
- 			  extraReg := self allocateRegNotConflictingWith: (self registerMaskFor: str1Reg and: str2Reg and: lenReg)]
- 		ifFalse: 
- 			[ mask := self emptyRegisterMask.
- 			  (self ssValue: 1) type = SSConstant ifFalse: 
- 				[ str1Reg := self allocateRegForStackEntryAt: 1 notConflictingWith: mask.
- 				  (self ssValue: 1) popToReg: str1Reg.
- 				  mask := mask bitOr: (self registerMaskFor: str1Reg) ].
- 			  (self ssValue: 2) type = SSConstant ifFalse: 
- 				[ str2Reg := self allocateRegForStackEntryAt: 2 notConflictingWith: mask.
- 				  (self ssValue: 2) popToReg: str2Reg.
- 				  mask := mask bitOr: (self registerMaskFor: str2Reg) ].
- 			  extraReg := self allocateRegNotConflictingWith: mask].
- 	
- 	"--- Loading LenReg (or statically resolving it) --- "
- 	"LenReg is loaded with (lenInBytes + objectMemory baseHeaderSize - 1 >> shiftForWord)
- 	 LenReg is the index for the last word to compare with MoveXwr:r:R:.
- 	 The loop iterates from LenReg to first word of ByteObj"
- 	self ssTop type = SSConstant 
- 		ifTrue: "common case, str = 'foo'. We can precompute lenReg."
- 			[ lenCst := lenCst + objectMemory baseHeaderSize - 1 >> objectMemory shiftForWord.
- 			  needLoop ifTrue: [self MoveCq: lenCst R: lenReg ].
- 			  needjmpZeroSize := false] 
- 		ifFalse: "uncommon case, str = str2. lenReg in word computed at runtime."
- 			[ self ssTop popToReg: lenReg.
- 			  objectRepresentation genConvertSmallIntegerToIntegerInReg: lenReg.
- 			  self CmpCq: 0 R: lenReg.
- 			  jmpZeroSize := self JumpZero: 0.
- 			  needjmpZeroSize := true.
- 			  self AddCq: objectMemory baseHeaderSize - 1 R: lenReg.
- 			  self ArithmeticShiftRightCq: objectMemory shiftForWord R: lenReg ].
- 	
- 	"--- Comparing the strings --- "
- 	"LenReg has the index of the last word to read (unless no loop). 
- 	 We decrement it to adjust -1 (0 in 64 bits) while comparing"
- 	needLoop 
- 		ifTrue:
- 			[instr := self MoveXwr: lenReg R: str1Reg R: extraReg.
- 			self MoveXwr: lenReg R: str2Reg R: TempReg.
- 			self CmpR: extraReg R: TempReg.
- 			jmp := self JumpNonZero: 0. "then string are not equal (jmp target)"
- 			self AddCq: -1 R: lenReg.
- 			self CmpCq: (objectMemory baseHeaderSize >> objectMemory shiftForWord) - 1 R: lenReg. "first word of ByteObj, stop looping."
- 			self JumpNonZero: instr]
- 		ifFalse: "Common case, only 1 or 2 word to check: no lenReg allocation, cst micro optimisations"
- 			[self genByteEqualsInlinePrimitiveCmp: str1Reg with: str2Reg scratch1: extraReg scratch2: TempReg field: 0.
- 			jmp := self JumpNonZero: 0. "then string are not equal (jmp target)"
- 			unroll ifTrue: "unrolling more than twice generate more instructions than the loop so we don't do it"
- 				[self genByteEqualsInlinePrimitiveCmp: str1Reg with: str2Reg scratch1: extraReg scratch2: TempReg field: 1.
- 				jmp2 := self JumpNonZero: 0. "then string are not equal (jmp target)"]].
- 	needjmpZeroSize ifTrue: [ jmpZeroSize jmpTarget: self Label ].
- 	"fall through, strings are equal"
- 	
- 	"--- Pushing the result or pipelining a branch --- "	
- 	self ssPop: 3.
- 	self genByteEqualsInlinePrimitiveResult: jmp returnReg: extraReg.
- 	unroll ifTrue: [jmp2 jmpTarget: jmp getJmpTarget].
- 	^0!

Item was removed:
- ----- Method: SistaCogitClone>>genByteEqualsInlinePrimitiveCmp:with:scratch1:scratch2:field: (in category 'inline primitive generators') -----
- genByteEqualsInlinePrimitiveCmp: str1Reg with: str2Reg scratch1: scratch1Reg scratch2: scratch2Reg field: index
- 	| shift |
- 	<inline: true>
- 	shift := objectMemory baseHeaderSize + (index * objectMemory wordSize).
- 	(self ssValue: 1) type = SSConstant 
- 		ifTrue: [self MoveCq: (objectMemory fetchPointer: index ofObject: (self ssValue: 1) constant) R: scratch1Reg]
- 		ifFalse: [self MoveMw: shift r: str1Reg R: scratch1Reg].
- 	 (self ssValue: 2) type = SSConstant 
- 		ifTrue: [self MoveCq: (objectMemory fetchPointer: index ofObject: (self ssValue: 2) constant) R: scratch2Reg]
- 		ifFalse: [self MoveMw: shift r: str2Reg R: scratch2Reg].
- 	self CmpR: scratch1Reg R: scratch2Reg.!

Item was removed:
- ----- Method: SistaCogitClone>>genByteEqualsInlinePrimitiveResult:returnReg: (in category 'inline primitive generators') -----
- genByteEqualsInlinePrimitiveResult: jmp returnReg: reg
- 	"Byte equal is falling through if the result is true, or jumping using jmp if the result is false.
- 	 The method is required to set the jump target of jmp.
- 	 We look ahead for a branch and pipeline the jumps if possible..
- 	 ReturnReg is used only if not followed immediately by a branch."
- 	| branchDescriptor nextPC postBranchPC targetBytecodePC localJump canElide |
- 	<var: #localJump type: #'AbstractInstruction *'>
- 	<var: #branchDescriptor type: #'BytecodeDescriptor *'>
- 	self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target | 
- 		branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
- 	
- 	"Case 1 - not followed by a branch"
- 	(branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse])
- 		ifFalse: 
- 			[self genMoveTrueR: reg.
- 			 localJump := self Jump: 0.
- 			 jmp jmpTarget: (self genMoveFalseR: reg).
- 			 localJump jmpTarget: self Label.
- 			 self ssPushRegister: reg.
- 			^ 0].
- 
- 	"Case 2 - followed by a branch"
- 	(self fixupAt: nextPC) notAFixup
- 		ifTrue: "The next instruction is dead.  we can skip it."
- 			[deadCode := true.
- 		 	 self ensureFixupAt: targetBytecodePC.
- 			 self ensureFixupAt: postBranchPC ]
- 		ifFalse:
- 			[self ssPushConstant: objectMemory trueObject]. "dummy value"
- 	"We can only elide the jump if the pc after nextPC is the same as postBranchPC.
- 	 Branch following means it may not be."
- 	self nextDescriptorExtensionsAndNextPCInto:
- 		[:iguana1 :iguana2 :iguana3 :followingPC| nextPC := followingPC].
- 	canElide := deadCode and: [nextPC = postBranchPC].
- 	 branchDescriptor isBranchTrue
- 		ifTrue: 
- 			[ self Jump: (self ensureNonMergeFixupAt: targetBytecodePC).
- 			  canElide 
- 					ifFalse: [ jmp jmpTarget: (self ensureNonMergeFixupAt: postBranchPC) ]
- 					ifTrue: [ jmp jmpTarget: self Label ] ]
- 		ifFalse: [ canElide ifFalse: [ self Jump: (self ensureNonMergeFixupAt: postBranchPC).
- 				 jmp jmpTarget: (self ensureNonMergeFixupAt: targetBytecodePC) ] ].
- 	^0!

Item was removed:
- ----- Method: SistaCogitClone>>genQuaternaryInlinePrimitive: (in category 'inline primitive generators') -----
- genQuaternaryInlinePrimitive: prim
- 	"Quaternary inline primitives."
- 	"SistaV1: 248		11111000 	iiiiiiii		mjjjjjjj		Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.
- 	 See EncoderForSistaV1's class comment and StackInterpreter>>#quaternaryInlinePrimitive:"
- 	| needStoreCheck sourceReg stopReg objReg adjust jmp cmp isStartCst isStopCst startCst stopCst iteratorReg |
- 	<var: #jmp type: #'AbstractInstruction *'>
- 	<var: #cmp type: #'AbstractInstruction *'>
- 	prim = 0 ifFalse: [^EncounteredUnknownBytecode].
- 	
- 	"4000	Pointer Object>> fillFrom:to:with: The receiver is a Pointer object. the middle two arguments are smallintegers. Last argument is any object. Fills the object in between the two indexes with last argument. Receiver is guaranteed to be mutable. The pointer accesses are raw (no inst var check). If ExtB is set to 1, no store check is present. Else a single store check is done for the bulk operation. Answers the receiver."
- 	needStoreCheck := self sistaNeedsStoreCheck.
- 	extB := numExtB := 0.
- 	
- 	"Allocate reg for src, objToStore, iterator and stop."
- 	sourceReg := needStoreCheck 
- 		ifTrue: [	self ssAllocateRequiredReg: ReceiverResultReg.
- 				self voidReceiverResultRegContainsSelf.
- 				ReceiverResultReg ]
- 		ifFalse: [ self allocateRegForStackEntryAt: 3 notConflictingWith: self emptyRegisterMask ].
- 	(self ssValue: 3) popToReg: sourceReg.
- 	objReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor: sourceReg).
- 	self ssTop popToReg: objReg.
- 	
- 	"Set up iterator to first index to write and stop to last index to write"
- 	adjust := (objectMemory baseHeaderSize >> objectMemory shiftForWord) - 1. "shift by baseHeaderSize and then move from 1 relative to zero relative"
- 	isStartCst := (self ssValue: 2) type = SSConstant.
- 	isStopCst := (self ssValue: 1) type = SSConstant.
- 	isStartCst ifTrue: [startCst := adjust + (objectMemory integerValueOf: (self ssValue: 2) constant)].
- 	isStopCst ifTrue: [stopCst := adjust + (objectMemory integerValueOf: (self ssValue: 1) constant)].
- 	
- 	(isStartCst
- 	and: [isStopCst
- 	and: [stopCst - startCst < 7 ]]) "The other path generates at least 7 instructions"
- 		ifTrue: ["unroll"
- 				startCst
- 					to: stopCst
- 					do: [ :i | self MoveMw: i r: sourceReg R: objReg ] ]
- 		ifFalse: ["loop"
- 				stopReg := self allocateRegNotConflictingWith: (self registerMaskFor: sourceReg and: objReg).
- 				iteratorReg := self allocateRegNotConflictingWith: (self registerMaskFor: sourceReg and: objReg and: stopReg).
- 				isStartCst 
- 					ifTrue: [ self MoveCq: startCst R: iteratorReg ]
- 					ifFalse: [ (self ssValue: 2) popToReg: iteratorReg. 
- 							 adjust ~= 0 ifTrue: [ self AddCq: adjust R: iteratorReg ] ].
- 				isStopCst 
- 					ifTrue: [ self MoveCq: stopCst R: stopReg ]
- 					ifFalse: [ (self ssValue: 1) popToReg: stopReg. 
- 							 adjust ~= 0 ifTrue: [ self AddCq: adjust R: stopReg ] ].
- 				cmp := self CmpR: stopReg R: iteratorReg.
- 				jmp := self JumpAbove: 0.
- 				self MoveR: objReg Xwr: iteratorReg R: sourceReg.
- 				self AddCq: 1 R: iteratorReg.
- 				self Jump: cmp.
- 				jmp jmpTarget: self Label].
- 			
- 	needStoreCheck ifTrue: [objectRepresentation genStoreCheckReceiverReg: sourceReg valueReg: objReg scratchReg: TempReg inFrame: true].
- 	
- 	self ssPop: 4.
- 	self ssPushRegister: sourceReg.
- 	 ^0!

Item was removed:
- ----- Method: SistaCogitClone>>genQuinaryInlinePrimitive: (in category 'inline primitive generators') -----
- genQuinaryInlinePrimitive: prim
- 	"SistaV1: 248		11111000 	iiiiiiii		mjjjjjjj		Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.
- 	 See EncoderForSistaV1's class comment and StackInterpreter>>#quaternaryInlinePrimitive:"
- 	^EncounteredUnknownBytecode!

Item was removed:
- ----- Method: SistaCogitClone>>isTrapAt: (in category 'simulation only') -----
- isTrapAt: retpc
- 	"For stack depth checking."
- 	<doNotGenerate>
- 	^(backEnd isCallPrecedingReturnPC: retpc)
- 	 and: [(backEnd callTargetFromReturnAddress: retpc) = ceTrapTrampoline]!

Item was removed:
- ----- Method: SistaCogitClone>>setCogCodeZoneThreshold: (in category 'accessing') -----
- setCogCodeZoneThreshold: threshold
- 	<doNotGenerate>
- 	^methodZone setCogCodeZoneThreshold: threshold!

Item was changed:
  ----- Method: ThreadedX64SysVFFIPlugin>>ffiPushStructure:ofSize:typeSpec:ofLength:in: (in category 'marshalling') -----
  ffiPushStructure: pointer ofSize: structSize typeSpec: argSpec ofLength: argSpecSize in: calloutState
  	<var: #pointer type: #'void *'>
  	<var: #argSpec type: #'sqInt *'>
  	<var: #calloutState type: #'CalloutState *'>
  	<inline: true>
  	| roundedSize doubleType floatType numDoubleRegisters numIntegerRegisters passField0InXmmReg passField1InXmmReg |
  	structSize <= 16 ifTrue:
  		["See sec 3.2.3 of http://people.freebsd.org/~obrien/amd64-elf-abi.pdf. (dravft version 0.90).
  		  All of the folowing are passed in registers:
  			typedef struct { long a; } s0;
  			typedef struct { double a; } s1;
  			typedef struct { long a; double b; } s2;
  			typedef struct { int a; int b; double c; } s2a;
  			typedef struct { short a; short b; short c; short d; double e; } s2b;
  			typedef struct { long a; float b; } s2f;
  			typedef struct { long a; float b; float c; } s2g;
  		  but not ones like this:
  			typedef struct { int a; float b; int c; float d; } s2h;"
  		 doubleType := FFITypeDoubleFloat << FFIAtomicTypeShift + FFITypeDoubleFloat.
  		 floatType := FFITypeDoubleFloat << FFIAtomicTypeShift + FFITypeSingleFloat.
  		 passField0InXmmReg := doubleType = ((self cCoerce: argSpec to: #'int *') at: 1) "0th field is struct type and size"
  								or: [floatType = ((self cCoerce: argSpec to: #'int *') at: 1)
  									and: [floatType = ((self cCoerce: argSpec to: #'int *') at: 2)]].
  		 structSize <= 8
  			ifTrue:
  				[numDoubleRegisters := passField0InXmmReg ifTrue: [1] ifFalse: [0].
  				 numIntegerRegisters := 1 - numDoubleRegisters]
  			ifFalse:
  				[passField1InXmmReg := doubleType = ((self cCoerce: argSpec to: #'int *') at: argSpecSize - 1) "Nth field is last field of struct"
  										or: [floatType = ((self cCoerce: argSpec to: #'int *') at: argSpecSize - 2)
  											and: [floatType = ((self cCoerce: argSpec to: #'int *') at: argSpecSize - 1)]].
  				 numDoubleRegisters := (passField0InXmmReg ifTrue: [1] ifFalse: [0]) + (passField1InXmmReg ifTrue: [1] ifFalse: [0]).
  				 numIntegerRegisters := 2 - numDoubleRegisters].
  		 (calloutState floatRegisterIndex + numDoubleRegisters <= NumFloatRegArgs
  		  and: [calloutState integerRegisterIndex + numIntegerRegisters <= NumIntRegArgs]) ifTrue:
  			[passField0InXmmReg
  				ifTrue: [self ffiPushDoubleFloat: ((self cCoerceSimple: pointer to: #'double *') at: 0) in: calloutState]
  				ifFalse: [self ffiPushSignedLongLong: ((self cCoerceSimple: pointer to: #'long long *') at: 0) in: calloutState].
  			 structSize > 8 ifTrue:
  				[passField1InXmmReg
  					ifTrue: [self ffiPushDoubleFloat: ((self cCoerceSimple: pointer to: #'double *') at: 1) in: calloutState]
  					ifFalse: [self ffiPushSignedLongLong: ((self cCoerceSimple: pointer to: #'long long *') at: 1) in: calloutState]].
+ 			 ^0] ].
- 			 ^0].
  
  	roundedSize := structSize + 7 bitClear: 7.
  	calloutState currentArg + roundedSize > calloutState limit ifTrue:
  		 [^FFIErrorCallFrameTooBig].
  	self mem: calloutState currentArg cp: (self cCoerceSimple: pointer to: 'char *') y: structSize.
+ 	calloutState currentArg: calloutState currentArg + roundedSize.
- 	calloutState currentArg: calloutState currentArg + roundedSize].
  	^0!



More information about the Vm-dev mailing list