[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