[Vm-dev] VM Maker: VMMaker.oscog-cb.2177.mcz

commits at source.squeak.org commits at source.squeak.org
Thu Mar 23 22:08:49 UTC 2017


ClementBera uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-cb.2177.mcz

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

Name: VMMaker.oscog-cb.2177
Author: cb
Time: 23 March 2017, 3:07:49.777145 pm
UUID: ccb43e01-44ea-4871-8eab-ad0f1096abb7
Ancestors: VMMaker.oscog-eem.2176

Added and fixed a quite stable version of inlinedByteEqual.

Added experimental version of fillArray.

Temporary fix for inlined new (until I look at it seriously again - too busy on ByteEqual right now)

Fix lowCode primitives in Sista VM.

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

Item was added:
+ ----- Method: SistaCogit>>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 changed:
  ----- Method: SistaCogit>>genBinaryVarOpVarInlinePrimitive: (in category 'inline primitive generators') -----
  genBinaryVarOpVarInlinePrimitive: prim
  	"Var op var version of binary 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>>#binaryInlinePrimitive:"
  	<option: #SistaVM>
  	| ra rr adjust |
  	self allocateRegForStackTopTwoEntriesInto: [:rTop :rNext | ra := rTop. rr := rNext ].
  	self ssTop popToReg: ra.
  	self ssPop: 1.
  	self ssTop popToReg: rr.
  	self ssPop: 1.
  	prim caseOf: {
  		"0 through 6, +, -, *, /, //, \\, quo:, SmallInteger op SmallInteger => SmallInteger, no overflow"
  		[0]	->	[objectRepresentation genRemoveSmallIntegerTagsInScratchReg: ra.
  				 self AddR: ra R: rr].
  		[1]	->	[self SubR: ra R: rr.
  				 objectRepresentation genAddSmallIntegerTagsTo: rr].
  		[2]	->	[self genShiftAwaySmallIntegerTagsInScratchReg: rr.
  				 self genRemoveSmallIntegerTagsInScratchReg: ra.
  				 self MulR: ra R: rr.
  				 self genSetSmallIntegerTagsIn: rr].
+ 		"[4]	->	[].
+ 		[5]	->	[].
+ 		[6]	->	[]."
  
  		"2016 through 2020, bitAnd:, bitOr:, bitXor, bitShiftLeft:, bitShiftRight:, SmallInteger op SmallInteger => SmallInteger, no overflow"
  		[16] -> [ self AndR: ra R: rr ].
  		[17] -> [ self OrR: ra R: rr ].
  		[18] -> [objectRepresentation genRemoveSmallIntegerTagsInScratchReg: ra. 
  				self XorR: ra R: rr. ].
  		[19] -> [ objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.
  				 objectRepresentation genRemoveSmallIntegerTagsInScratchReg: rr.
  				 self LogicalShiftLeftR: ra R: rr.
  				 objectRepresentation genAddSmallIntegerTagsTo: rr].
  		[20] ->	[objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.
  				 self ArithmeticShiftRightR: ra R: rr.
  				 objectRepresentation genClearAndSetSmallIntegerTagsIn: rr.].
  
  
  		"2032	through 2037, >, <, >=, <=. =, ~=, SmallInteger op SmallInteger => Boolean (flags?? then in jump bytecodes if ssTop is a flags value, just generate the instruction!!!!)"
  		"CmpCqR is SubRCq so everything is reversed."
  		[32] -> [ self CmpR: ra R: rr.
  				self genBinaryInlineComparison: JumpGreater opFalse: JumpLessOrEqual destReg: rr ].
  		[33] -> [ self CmpR: ra R: rr.
  				self genBinaryInlineComparison: JumpLess opFalse: JumpGreaterOrEqual destReg: rr ].
  		[34] -> [ self CmpR: ra R: rr.
  				self genBinaryInlineComparison: JumpGreaterOrEqual opFalse: JumpLess destReg: rr ].
  		[35] -> [ self CmpR: ra R: rr.
  				self genBinaryInlineComparison: JumpLessOrEqual opFalse: JumpGreater destReg: rr ].
  		[36] -> [ self CmpR: ra R: rr.
  				self genBinaryInlineComparison: JumpZero opFalse: JumpNonZero destReg: rr ].
  		[37] -> [ self CmpR: ra R: rr.
  				self genBinaryInlineComparison: JumpNonZero opFalse: JumpZero destReg: rr ].
  
  		"2064	through 2068, Pointer Object>>at:, Byte Object>>at:, Short16 Word Object>>at: LongWord32 Object>>at: Quad64Word Object>>at:. obj op 0-rel SmallInteger => oop"
  		[64] ->	[objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.
  				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: ra. ]. 
  				self MoveXwr: ra R: rr R: rr ].
  		[65] ->	[objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.
  				adjust := objectMemory baseHeaderSize - 1. "shift by baseHeaderSize and then move from 1 relative to zero relative"
  				self AddCq: adjust R: ra.
  				self MoveXbr: ra R: rr R: rr.
  				objectRepresentation genConvertIntegerToSmallIntegerInReg: rr]
  
  	}
  	otherwise: [^EncounteredUnknownBytecode].
  	self ssPushRegister: rr.
  	^0!

Item was added:
+ ----- Method: SistaCogit>>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 adjust needjmpZeroSize needLoop unroll jmpZeroSize instr lenCst mask |
+ 	<var: #jmp type: #'AbstractInstruction *'>
+ 	<var: #instr type: #'AbstractInstruction *'>
+ 	<var: #jmp2 type: #'AbstractInstruction *'>
+ 	<var: #jmpZeroSize type: #'AbstractInstruction *'>
+ 1halt.
+ 	"--- 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 ] ].
+ 	lenCst := 7.
+ 	"--- 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).
+ 			  (self ssValue: 1) popToReg: str1Reg.
+ 			  (self ssValue: 2) popToReg: str2Reg.
+ 			  lenReg := self allocateRegForStackEntryAt: 0 notConflictingWith: (self registerMaskFor:str1Reg and: 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].
+ 	adjust := objectMemory baseHeaderSize >> objectMemory shiftForWord.
+ 	
+ 	"--- 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."
+ 			[ 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: adjust-1 R: lenReg. "first word of ByteObj, stop looping - in 64 bits adjust - 1 is 0, quicker."
+ 			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 added:
+ ----- Method: SistaCogit>>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 added:
+ ----- Method: SistaCogit>>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 changed:
  ----- Method: SistaCogit>>genCallPrimitiveBytecode (in category 'bytecode generators') -----
  genCallPrimitiveBytecode
  	"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>>#inlinePrimitiveBytecode:"
+ 	| prim primSet |
- 	| prim |
  	byte2 < 128 ifTrue:
  		[^bytecodePC = initialPC
  			ifTrue: [0]
  			ifFalse: [EncounteredUnknownBytecode]].
  	prim := byte2 - 128 << 8 + byte1.
+ 	primSet := prim >> 13 bitAnd: 3.
+ 	prim := prim bitAnd: 8191.
+ 	LowcodeVM
+ 		ifTrue:
+ 			[
+ 			primSet = 1 ifTrue: [
+ 				prim < 1000 ifTrue:
+ 					[^self genLowcodeNullaryInlinePrimitive: prim].
  
+ 				prim < 2000 ifTrue:
+ 					[^self genLowcodeUnaryInlinePrimitive: prim - 1000].
+ 				
+ 				prim < 3000 ifTrue:
+ 					[^ self genLowcodeBinaryInlinePrimitive: prim - 2000].
+ 
+ 				prim < 4000 ifTrue:
+ 					[^self genLowcodeTrinaryInlinePrimitive: prim - 3000].
+ 			]
+ 		].
+ 	
+ 	self assert: primSet = 0.
+ 	
  	prim < 1000 ifTrue:
  		[^self genNullaryInlinePrimitive: prim].
  
  	prim < 2000 ifTrue:
  		[^self genUnaryInlinePrimitive: prim - 1000].
  		
  	prim < 3000 ifTrue:
  		[self ssTop type = SSConstant ifTrue:
  			[^self genBinaryVarOpConstInlinePrimitive: prim - 2000].
  		 (self ssValue: 1) type = SSConstant ifTrue:
  			[^self genBinaryConstOpVarInlinePrimitive: prim - 2000].
  		 ^self genBinaryVarOpVarInlinePrimitive: prim - 2000].
  
  	prim < 4000 ifTrue:
  		[^self genTrinaryInlinePrimitive: prim - 3000].
+ 	
+ 	prim < 5000 ifTrue: 
+ 		[^self genQuaternaryInlinePrimitive: prim - 4000].
+ 	
+ 	prim < 6000 ifTrue: 
+ 		[^self genQuinaryInlinePrimitive: prim - 5000].
+ 		
- 
  	^EncounteredUnknownBytecode!

Item was added:
+ ----- Method: SistaCogit>>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 added:
+ ----- Method: SistaCogit>>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 changed:
  ----- Method: SistaCogit>>genTrinaryInlinePrimitive: (in category 'inline primitive generators') -----
  genTrinaryInlinePrimitive: prim
+ 	"trinary inline primitives."
- 	"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:"
+ 
+ 	prim < 10 ifTrue: [^ self genAtPutInlinePrimitive: prim].
+ 	prim = 21 ifTrue: [^ self genByteEqualsInlinePrimitive: prim].
+ 	^ EncounteredUnknownBytecode!
- 	| 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 changed:
  ----- Method: SistaCogit>>genUnaryInlinePrimitive: (in category 'inline primitive generators') -----
  genUnaryInlinePrimitive: 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>>#unaryInlinePrimitive:"
  	| rcvrReg resultReg |
  	rcvrReg := self allocateRegForStackEntryAt: 0.
  	resultReg := self allocateRegNotConflictingWith: (self registerMaskFor: rcvrReg).
  	prim
  		caseOf: {
  					"00		unchecked class"
  			[1] ->	"01		unchecked pointer numSlots"
  				[self ssTop popToReg: rcvrReg.
  				 self ssPop: 1.
  				 objectRepresentation
  					genGetNumSlotsOf: rcvrReg into: resultReg;
  					genConvertIntegerToSmallIntegerInReg: resultReg].
  					"02		unchecked pointer basicSize"
  			[3] ->	"03		unchecked byte numBytes"
  				[self ssTop popToReg: rcvrReg.
  				 self ssPop: 1.
  				 objectRepresentation
  					genGetNumBytesOf: rcvrReg into: resultReg;
  					genConvertIntegerToSmallIntegerInReg: resultReg].
  					"04		unchecked short16Type format numShorts"
  					"05		unchecked word32Type format numWords"
  					"06		unchecked doubleWord64Type format numDoubleWords"
  			[11] ->	"11		unchecked fixed pointer basicNew"
  				[self ssTop type ~= SSConstant ifTrue:
  					[^EncounteredUnknownBytecode].
  				 (objectRepresentation
  					genGetInstanceOf: self ssTop constant
  						into: resultReg
  							initializingIf: self extBSpecifiesInitializeInstance) ~= 0 ifTrue:
  					[^ShouldNotJIT]. "e.g. bad class"
  				 self ssPop: 1] .
  			[20] ->	"20 	identityHash"
  				[objectRepresentation genGetIdentityHash: rcvrReg resultReg: resultReg.
  				 self ssPop: 1] .
  					"21		identityHash (SmallInteger)"
  					"22		identityHash (Character)"
  					"23		identityHash (SmallFloat64)"
  					"24		identityHash (Behavior)"
  					"30 	immediateAsInteger (Character)
+ 					 31 	immediateAsInteger (SmallFloat64)
+ 					 35		immediateAsFloat 	  (SmallInteger)	"
- 					 31 	immediateAsInteger (SmallFloat64)"
  			[30] -> 
  				[self ssTop popToReg: resultReg.
  				 objectRepresentation genConvertCharacterToSmallIntegerInReg: resultReg.
+ 				 self ssPop: 1].
+ 			[35] -> 
+ 				[self assert: self processorHasDoublePrecisionFloatingPointSupport.
+ 				self MoveR: rcvrReg R: TempReg.
+ 				self genConvertSmallIntegerToIntegerInReg: TempReg.
+ 				self ConvertR: TempReg Rd: DPFPReg0.
+ 				self flag: #TODO. "Should never fail"
+ 				self
+ 					genAllocFloatValue: DPFPReg0
+ 					into: resultReg
+ 					scratchReg: TempReg
+ 					scratchReg: NoReg. "scratch2 for V3 only"]
- 				 self ssPop: 1]
  				  }
  				
  		otherwise:
  			[^EncounteredUnknownBytecode].
  	extB := 0.
  	numExtB := 0.
  	self ssPushRegister: resultReg.
  	^0!

Item was changed:
  ----- Method: StackInterpreter>>trinaryInlinePrimitive: (in category 'miscellaneous bytecodes') -----
  trinaryInlinePrimitive: primIndex
  	"SistaV1:	248		11111000 	iiiiiiii		mjjjjjjj		Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution."
  	<option: #SistaVM>
  	| result |
  	primIndex caseOf: {
  
  		"3000	unchecked Pointer Object>>at:put:.			The receiver is guaranteed to be a pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger"
  		[0]	->	[result := self internalStackTop.
  				 objectMemory
  					storePointer: (objectMemory integerValueOf: (self internalStackValue: 1)) - 1
  					ofObject: (self internalStackValue: 2)
  					withValue: result.
  				 self internalPop: 2; internalStackTopPut: result].
  		"3001	unchecked Byte Object>>at:put:.			The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 8 bits."
  		[1]	->	[result := self internalStackTop.
  				 objectMemory
  					storeByte: (objectMemory integerValueOf: (self internalStackValue: 1)) - 1
  					ofObject: (self internalStackValue: 2)
  					withValue: (objectMemory integerValueOf: result).
  				 self internalPop: 2; internalStackTopPut: result].
  		"3002	unchecked Word Object>>at:put:.			The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 16 bits."
  		[2]	->	[result := self internalStackTop.
  				 objectMemory
  					storeShort16: (objectMemory integerValueOf: (self internalStackValue: 1)) - 1
  					ofObject: (self internalStackValue: 2)
  					withValue: (objectMemory integerValueOf: result).
  				 self internalPop: 2; internalStackTopPut: result].
  		"3003	unchecked DoubleWord Object>>at:put:.	The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 32 bits."
  		[3]	->	[result := self internalStackTop.
  				 objectMemory
  					storeLong32: (objectMemory integerValueOf: (self internalStackValue: 1)) - 1
  					ofObject: (self internalStackValue: 2)
  					withValue: (objectMemory integerValueOf: result).
  				 self internalPop: 2; internalStackTopPut: result].
  		"3004	unchecked QuadWord Object>>at:put:.		The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 64 bits."
  		[4]	->	[result := self internalStackTop.
  				 objectMemory
  					storeLong64: (objectMemory integerValueOf: (self internalStackValue: 1)) - 1
  					ofObject: (self internalStackValue: 2)
  					withValue: (objectMemory integerValueOf: result).
+ 				 self internalPop: 2; internalStackTopPut: result].
+ 		"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."
+ 		[21]	->	[ | str1 str2 word1 word2 len |
+ 					  len := objectMemory integerValueOf: self internalStackTop.
+ 					  len = 0 ifTrue: [^self internalPop: 2; internalStackTopPut: objectMemory trueObject].
+ 					  str1 := self internalStackValue: 2.
+   					  str2 := self internalStackValue: 1.
+ 					  0 to: len - 1 >> objectMemory shiftForWord do: [:i |
+ 						word1 := objectMemory fetchPointer: i ofObject: str1.
+ 						word2 := objectMemory fetchPointer: i ofObject: str2. 
+ 						word1 = word2 ifFalse: [^self internalPop: 2; internalStackTopPut: objectMemory falseObject] ].
+ 					 self internalPop: 2; internalStackTopPut: objectMemory trueObject ] }
- 				 self internalPop: 2; internalStackTopPut: result] }
  	otherwise:
  		[localIP := localIP - 3.
  		 self respondToUnknownBytecode]!

Item was changed:
  ----- Method: StackInterpreter>>unaryInlinePrimitive: (in category 'miscellaneous bytecodes') -----
  unaryInlinePrimitive: primIndex
  	"SistaV1:	248		11111000 	iiiiiiii		mjjjjjjj		Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution."
  	<option: #SistaVM>
  	| result |
  	primIndex caseOf: {
  		"1000	unchecked class"
  		[0]	->	[result := objectMemory fetchClassOf: self internalStackTop.
  				 self internalStackTopPut: result].
  		"1001	unchecked pointer numSlots"
  		[1]	->	[result := objectMemory numSlotsOf: self internalStackTop.
  				 self internalStackTopPut: (objectMemory integerObjectOf: result)].
  		"1002	unchecked pointer basicSize"
  		[2]	->	[result := (objectMemory numSlotsOf: self internalStackTop)
  						- (objectMemory fixedFieldsOfClass: (objectMemory fetchClassOfNonImm: self internalStackTop)).
  				 self internalStackTopPut: (objectMemory integerObjectOf: result)].
  		"1003	unchecked byte8Type format numBytes (includes CompiledMethod)"
  		[3]	->	[result := objectMemory numBytesOf: self internalStackTop.
  				 self internalStackTopPut: (objectMemory integerObjectOf: result)].
  		"1004	unchecked short16Type format numShorts"
  		[4]	->	[result := objectMemory num16BitUnitsOf: self internalStackTop.
  				 self internalStackTopPut: (objectMemory integerObjectOf: result)].
  		"1005	unchecked word32Type format numWords"
  		[5]	->	[result := objectMemory num32BitUnitsOf: self internalStackTop.
  				 self internalStackTopPut: (objectMemory integerObjectOf: result)].
  		"1006	unchecked doubleWord64Type format numDoubleWords"
  		[6]	->	[result := objectMemory num64BitUnitsOf: self internalStackTop.
  				 self internalStackTopPut: (objectMemory integerObjectOf: result)].
  
  		"1011	unchecked fixed pointer basicNew"
  		[11] ->	[| classObj numSlots |
  				 classObj := self internalStackTop.
  				 numSlots := objectMemory instanceSizeOf: classObj.
+ 				 result := objectMemory instantiateClass: classObj.
+ 				" result := objectMemory eeInstantiateSmallClass: classObj numSlots: numSlots.
- 				 result := objectMemory eeInstantiateSmallClass: classObj numSlots: numSlots.
  				 (extB noMask: 1) ifTrue:
  					[0 to: numSlots - 1 do:
+ 						[:i| objectMemory storePointerUnchecked: i ofObject: result withValue: objectMemory nilObject]]."
- 						[:i| objectMemory storePointerUnchecked: i ofObject: result withValue: objectMemory nilObject]].
  				 extB := 0.
  				numExtB := 0.
  				 self internalStackTopPut: result].
  		"1020 	identityHash"
  		[20] ->	[result := objectMemory hashBitsOf: self internalStackTop.
  				 self internalStackTopPut: (objectMemory integerObjectOf: result)].
  		"1021		identityHash (SmallInteger)"
  		"1022		identityHash (Character)"
  		"1023		identityHash (SmallFloat64)"
  		"1024		identityHash (Behavior)"
  		"1030 	immediateAsInteger (Character)
  		 1031 	immediateAsInteger (SmallFloat64)"
  		[30] -> [ result := objectMemory characterValueOf: self internalStackTop.
  				 self internalStackTopPut: (objectMemory integerObjectOf: result)]
  		 }
  	otherwise:
  		[localIP := localIP - 3.
  		 self respondToUnknownBytecode]!



More information about the Vm-dev mailing list