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

commits at source.squeak.org commits at source.squeak.org
Tue Jun 7 02:23:40 UTC 2016


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

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

Name: VMMaker.oscog-eem.1883
Author: eem
Time: 6 June 2016, 7:21:31.312947 pm
UUID: a87f979f-7e5b-44d1-804d-fc8403bde06d
Ancestors: VMMaker.oscog-eem.1882

Slang:
Fix a bad bug in type inferrence as exemplified by primitiveTimesTwoPower and its arg temporary.  A variable cannot be typed in the current pass if it is first assigned the result of an as-yet-to-be-typed send.  If it is assigned the result of a subsequent send then the first assignment will be ignored, possibly leading to a badly inferred type.  For example in primitiveTimesTwoPower arg is assigned a few times:
	arg := self stackTop.
...
	arg := objectMemory integerValueOf: arg.
...
	arg := twiceMaxExponent negated
...
	arg := twiceMaxExponent
and the type of twiceMaxExponent is #int.  If arg's type is inferred from twiceMaxExponent because stackTop & integerValueOf: are as yet untyped, then it will be inferred to be #int.  Whereas it should be defined as #sqInt from both stackTop & integerValueOf:, since merging #int & #sqInt yields #sqInt.

Eliminate a stale var:type:.

In 1883  the Adventures of Pinocchio by Carlo Collodi is first published complete in book form in Italy, Robert Louis Stevenson's children's pirate adventure novel Treasure Island is first published in book format, in London, and .oxygen is liquefied for the very first time.

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

Item was changed:
  ----- Method: CCodeGenerator>>returnTypeOrNilForSend:in: (in category 'type inference') -----
  returnTypeOrNilForSend: sendNode in: aTMethod
  	"Answer the return type for a send.  Sends of known but as-yet-untyped methods answer nil."
  	| sel |
  	(self anyMethodNamed: (sel := sendNode selector)) ifNotNil:
  		[:m|
+ 		^m returnType ifNotNil: [:type| self baseTypeForType: type]].
- 		^m returnType ifNotNil: [:type| ^self baseTypeForType: type]].
  	^self returnTypeForSend: sendNode in: aTMethod!

Item was changed:
  ----- Method: CogObjectRepresentationForSpur>>maybeCompileRetryOnPrimitiveFail: (in category 'primitive generators') -----
  maybeCompileRetryOnPrimitiveFail: primIndex
- 	<var: #retryInst type: #'AbstractInstruction *'>
  	"If primIndex has an accessorDepth and fails, or it is external and fails with PrimErrNoMemory,
  	 call ceCheckAndMaybeRetryPrimitive if so  If ceCheck.... answers true, retry the primitive."
  	| jmp |
  	<var: #jmp type: #'AbstractInstruction *'>
  	(coInterpreter accessorDepthForPrimitiveIndex: primIndex) >= 0
  		ifTrue:
  			[jmp := cogit
  				MoveAw: coInterpreter primFailCodeAddress R: TempReg;
  				CmpCq: 0 R: TempReg;
  				JumpZero: 0]
  		ifFalse:
  			[coInterpreter primNumberExternalCall ~= primIndex ifTrue:
  				[^0].
  			 jmp := cogit
  				MoveAw: coInterpreter primFailCodeAddress R: TempReg;
  				CmpCq: PrimErrNoMemory R: TempReg;
  				JumpNonZero: 0].
  	cogit
  		compileCallFor: #ceCheckAndMaybeRetryPrimitive:
  		numArgs: 1
  		arg: (cogit trampolineArgConstant: primIndex)
  		arg: nil
  		arg: nil
  		arg: nil
  		resultReg: TempReg
  		regsToSave: cogit emptyRegisterMask.
  	jmp jmpTarget: cogit Label.
  	^0!

Item was changed:
  ----- Method: StackInterpreter>>retryPrimitiveOnFailure (in category 'primitive support') -----
  retryPrimitiveOnFailure
+ 	"In Spur two cases of primitive failure are handled specially.  A primitive may fail due to validation
- 	"In Spur two cases of pirmitive failure are handled specially.  A primitive may fail due to validation
  	 encountering a forwarder. On failure, check the accessorDepth for the primitive and if non-negative
  	 scan the args to the depth, following any forwarders.  Retry the primitive if any are found.  Hence
  	 lazily and transparently following forwarders on primtiive failure.  Additionally a prmitive might fail
  	 due to an allocation failing.  Retry if external primitives have failed with PrimErrNoMemory after running
  	 first the scavenger and then on a subsequent failure, the global mark-sweep collector.  Hence lazily
  	 and transparently GC on memory exhaustion."
+ 	<inline: false>
- 	<inline: true>
  	| gcDone followDone canRetry retry retried |
  	gcDone := 0.
  	followDone := canRetry := retried := false.
  	[retry := false.
  	 primFailCode = PrimErrNoMemory
  		ifTrue:
  			[(gcDone := gcDone + 1) = 1 ifTrue:
  				[canRetry := self isExternalPrimitiveCall: newMethod].
  			 canRetry ifTrue:
  				 [gcDone = 1 ifTrue:
  					[objectMemory scavengingGC].
  				 gcDone = 2 ifTrue:
  					[objectMemory fullGC].
  				 retry := gcDone <= 2]]
  		 ifFalse:
  			[followDone ifFalse:
  				[followDone := true.
  				 retry := self checkForAndFollowForwardedPrimitiveState]].
  	 retry] whileTrue:
  		[self assert: primFailCode ~= 0.
  		 retried := true.
  		 self initPrimCall.
  		 self cCode: [] inSmalltalk:
  			[self maybeMapPrimitiveFunctionPointerBackToSomethingEvaluable].
  		 self dispatchFunctionPointer: primitiveFunctionPointer].
  	^retried!

Item was changed:
  ----- Method: TMethod>>addTypesFor:to:in: (in category 'type inference') -----
  addTypesFor: node to: typeSet in: aCodeGen
  	"Add the value types for the node to typeSet.
  	 Answer if any type was derived from an as-yet-untyped method, which allows us to abort
  	 inferReturnTypeFromReturnsIn: if the return type depends on a yet-to-be-typed method."
  	| expr |
  	expr := node.
  	[expr isAssignment or: [expr isStmtList]] whileTrue:
  		[expr isAssignment ifTrue:
  			[expr := expr variable].
  		 expr isStmtList ifTrue:
  			[expr := expr statements last]].
  	expr isSend ifTrue:
  		[(#(ifTrue: ifFalse: ifTrue:ifFalse: ifFalse:ifTrue:) includes: expr selector) ifTrue:
  			[^expr args
  				inject: false
  				into: [:asYetUntyped :block|
  					asYetUntyped | (self addTypesFor: block to: typeSet in: aCodeGen)]].
+ 		(aCodeGen returnTypeOrNilForSend: expr in: self)
- 		(expr typeOrNilFrom: aCodeGen in: self)
  			ifNil: [^(aCodeGen methodNamed: expr selector) notNil and: [expr selector ~~ selector]]
  			ifNotNil:
  				[:type |
  				typeSet add: type.
  				^false].].
  	expr isVariable ifTrue:
  		[(aCodeGen typeOfVariable: expr name)
  			ifNotNil: [:type| typeSet add: type]
  			ifNil: [typeSet add: (expr name = 'self'
  										ifTrue: [#void]
  										ifFalse: [#sqInt])]].
  	expr isConstant ifTrue:
  		[(expr typeOrNilFrom: aCodeGen in: self)
  			ifNotNil: [:type | typeSet add: type]]..
  	^false!

Item was changed:
  ----- Method: TMethod>>inferTypesForImplicitlyTypedVariablesIn: (in category 'type inference') -----
  inferTypesForImplicitlyTypedVariablesIn: aCodeGen
  	"infer types for untyped variables from assignments and arithmetic uses.
  	 For debugging answer a Dictionary from var to the nodes that determined types
  	 This for debugging:
  		(self copy inferTypesForImplicitlyTypedVariablesIn: aCodeGen)"
+ 	| alreadyExplicitlyTypedOrNotToBeTyped effectiveNodes |
- 	| alreadyExplicitlyTyped effectiveNodes |
  	aCodeGen maybeBreakForTestToInline: selector in: self.
+ 	alreadyExplicitlyTypedOrNotToBeTyped := declarations keys asSet.
- 	alreadyExplicitlyTyped := declarations keys asSet.
  	effectiveNodes := Dictionary new. "this for debugging"
  	parseTree nodesDo:
  		[:node| | type var |
  		"If there is something of the form i >= 0, then i should be signed, not unsigned."
  		(node isSend
  		 and: [(locals includes: (var := node receiver variableNameOrNil))
+ 		 and: [(alreadyExplicitlyTypedOrNotToBeTyped includes: var) not "don't be fooled by inferred unsigned types"
- 		 and: [(alreadyExplicitlyTyped includes: var) not "don't be fooled by inferred unsigned types"
  		 and: [(#(<= < >= >) includes: node selector)
  		 and: [node args first isConstant
  		 and: [node args first value = 0
  		 and: [(type := self typeFor: var in: aCodeGen) notNil
  		 and: [type first == $u]]]]]]]) ifTrue:
  			[self declarationAt: var put: (aCodeGen signedTypeForIntegralType: type), ' ', var.
  			 effectiveNodes at: var put: { declarations at: var. node }].
  		"if an assignment to an untyped local of a known type, set the local's type to that type.
  		 Only observe known sends (methods in the current set) and typed local variables."
  		(node isAssignment
  		 and: [(locals includes: (var := node variable name))
+ 		 and: [(alreadyExplicitlyTypedOrNotToBeTyped includes: var) not]]) ifTrue: "don't be fooled by previously inferred types"
+ 		 	[type := node expression isSend
- 		 and: [(alreadyExplicitlyTyped includes: var) not "don't be fooled by previously inferred types"
- 		 and: [(type := node expression isSend
  						ifTrue: [aCodeGen returnTypeOrNilForSend: node expression in: self]
+ 						ifFalse: [self typeFor: node expression in: aCodeGen].
+ 			 type "If untyped, then cannot type the variable yet. A subsequent assignment may assign a subtype of what this type ends up being"
+ 				ifNil: [alreadyExplicitlyTypedOrNotToBeTyped add: var] 
+ 				ifNotNil: "Merge simple types; complex types must be defined by the programmer."
+ 					[(aCodeGen isSimpleType: type) ifTrue:
+ 						[aCodeGen mergeTypeOf: var in: declarations with: type method: self.
+ 						 effectiveNodes at: var put: { declarations at: var. node }, (effectiveNodes at: var ifAbsent: [#()])]]]].
- 						ifFalse: [self typeFor: node expression in: aCodeGen]) notNil
- 		 and: [aCodeGen isSimpleType: type]]]]) ifTrue:
- 			[aCodeGen mergeTypeOf: var in: declarations with: type method: self.
- 			 effectiveNodes at: var put: { declarations at: var. node }, (effectiveNodes at: var ifAbsent: [#()])]].
  	^effectiveNodes!

Item was changed:
  ----- Method: TSendNode>>typeOrNilFrom:in: (in category 'type inference') -----
  typeOrNilFrom: aCodeGenerator in: aTMethod
+ 	^aCodeGenerator returnTypeOrNilForSend: self in: aTMethod!
- 	^aCodeGenerator returnTypeForSend: self in: aTMethod!



More information about the Vm-dev mailing list