Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2266.mcz ==================== Summary ==================== Name: VMMaker.oscog-eem.2266 Author: eem Time: 31 August 2017, 12:20:30.681037 pm UUID: 0501d71a-3185-4bdb-a99c-76a5fbbeee22 Ancestors: VMMaker.oscog-eem.2265 Spur: Simplify cleverSwapHeaders:and:copyHashFlag: via xor. Fix the type of currentAllocatedBytes given the Slang changes below. Slang: Fix a regression caused by the Slang fixes in VMMaker.oscog-eem.2243. Since inferTypesForImplicitlyTypedVariablesIn: no longer sets the types of locals as it goes along (which was incorrect) we can no longer default the types of untyped variables to sqInt for the purposes of returnTypeForSend:in:ifNil:. To allow returnTypeForSend:in:ifNil: to answer nil for arithmetic on untyped expressions typeForArithmetic:in: uses TParseNode>>typeOrNilFrom:in: instead of CCodeGenerator>>typeFor:in: to avoid the defaulting. returnTypeForSend:in:ifNil: has been refactored to use the more direct TParseNode>>typeFrom:in: instead of CCodeGenerator>>typeFor:in: for clarity. Teh regression caused Slang to fail to infer the types of remembered1/2 & hash1/2 in cleverSwapHeaders:and:copyHashFlag:. The new code correctly infers the types of remembered & hashBits as sqLong. SoundPlugin: Eliminate a couple of warnings by using 0 instead of NULL. =============== Diff against VMMaker.oscog-eem.2265 =============== Item was changed: ----- Method: CCodeGenerator>>returnTypeForSend:in:ifNil: (in category 'type inference') ----- returnTypeForSend: sendNode in: aTMethod ifNil: typeIfNil "Answer the return type for a send. Unbound sends default to typeIfNil. Methods with types as yet unknown have a type determined either by the kernelReturnTypes or the table below, or, if they are in neither set, then nil. The inferred type should match as closely as possible the C type of generated expessions so that inlining would not change the expression. If there is a method for sel but its return type is as yet unknown it mustn't be defaulted, since on a subsequent pass its type may be computable." | sel methodOrNil | methodOrNil := self anyMethodNamed: (sel := sendNode selector). (methodOrNil notNil and: [methodOrNil returnType notNil]) ifTrue: [^self baseTypeForType: methodOrNil returnType]. ^kernelReturnTypes at: sel ifAbsent: [sel caseOf: { [#integerValueOf:] -> [#sqInt]. [#isIntegerObject:] -> [#int]. + [#negated] -> [self promoteArithmeticTypes: (sendNode receiver typeFrom: self in: aTMethod) and: #int]. - [#negated] -> [self promoteArithmeticTypes: (self typeFor: sendNode receiver in: aTMethod) and: #int]. [#+] -> [self typeForArithmetic: sendNode in: aTMethod]. [#-] -> [self typeForArithmetic: sendNode in: aTMethod]. [#*] -> [self typeForArithmetic: sendNode in: aTMethod]. [#/] -> [self typeForArithmetic: sendNode in: aTMethod]. [#//] -> [self typeForArithmetic: sendNode in: aTMethod]. [#\\] -> [self typeForArithmetic: sendNode in: aTMethod]. [#rem:] -> [self typeForArithmetic: sendNode in: aTMethod]. [#quo:] -> [self typeForArithmetic: sendNode in: aTMethod]. "C99 Sec Bitwise shift operators ... 3 Sematics ... The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand..." + [#>>] -> [sendNode receiver typeFrom: self in: aTMethod]. + [#<<] -> [sendNode receiver typeFrom: self in: aTMethod]. + [#addressOf:] -> [(sendNode receiver typeFrom: self in: aTMethod) - [#>>] -> [self typeFor: sendNode receiver in: aTMethod]. - [#<<] -> [self typeFor: sendNode receiver in: aTMethod]. - [#addressOf:] -> [(self typeFor: sendNode receiver in: aTMethod) ifNil: [#sqInt] ifNotNil: [:type| type, (type last isLetter ifTrue: [' *'] ifFalse: ['*'])]]. [#at:] -> [self typeForDereference: sendNode in: aTMethod]. [#bitAnd:] -> [self typeForArithmetic: sendNode in: aTMethod]. [#bitOr:] -> [self typeForArithmetic: sendNode in: aTMethod]. [#bitXor:] -> [self typeForArithmetic: sendNode in: aTMethod]. [#bitClear:] -> [self typeForArithmetic: sendNode in: aTMethod]. [#bitInvert32] -> [#'unsigned int']. + [#bitInvert64] -> [self promoteArithmeticTypes: (sendNode receiver typeFrom: self in: aTMethod) and: #int]. - [#bitInvert64] -> [self promoteArithmeticTypes: (self typeFor: sendNode receiver in: aTMethod) and: #int]. [#byteSwap32] -> [#'unsigned int']. [#byteSwap64] -> [#'unsigned long long']. [#byteSwapped32IfBigEndian:] -> [#'unsigned int']. [#byteSwapped64IfBigEndian:] -> [#'unsigned long long']. [#=] -> [#int]. [#~=] -> [#int]. [#==] -> [#int]. [#~~] -> [#int]. [#<] -> [#int]. [#<=] -> [#int]. [#>] -> [#int]. [#>=] -> [#int]. [#between:and:] -> [#int]. [#anyMask:] -> [#int]. [#allMask:] -> [#int]. [#noMask:] -> [#int]. [#isNil] -> [#int]. [#notNil] -> [#int]. [#&] -> [#int]. [#|] -> [#int]. [#not] -> [#int]. [#asFloat] -> [#double]. [#atan] -> [#double]. [#exp] -> [#double]. [#log] -> [#double]. [#sin] -> [#double]. [#sqrt] -> [#double]. [#asLong] -> [#long]. [#asInteger] -> [#sqInt]. [#asIntegerPtr] -> [#'sqIntptr_t']. [#asUnsignedInteger] -> [#usqInt]. [#asUnsignedIntegerPtr]-> [#'usqIntptr_t']. [#asUnsignedLong] -> [#'unsigned long']. [#asUnsignedLongLong] -> [#'unsigned long long']. [#asVoidPointer] -> [#'void *']. [#signedIntToLong] -> [#usqInt]. "c.f. generateSignedIntToLong:on:indent:" [#signedIntToShort] -> [#usqInt]. "c.f. generateSignedIntToShort:on:indent:" [#cCoerce:to:] -> [sendNode args last value]. [#cCoerceSimple:to:] -> [sendNode args last value]. [#sizeof:] -> [#'usqIntptr_t']. "Technically it's a size_t but it matches on target architectures so far..." [#ifTrue:ifFalse:] -> [self typeForConditional: sendNode in: aTMethod]. [#ifFalse:ifTrue:] -> [self typeForConditional: sendNode in: aTMethod]. [#ifTrue:] -> [self typeForConditional: sendNode in: aTMethod]. [#ifFalse:] -> [self typeForConditional: sendNode in: aTMethod]. [#and:] -> [#sqInt]. [#or:] -> [#sqInt]. [#caseOf:] -> [self typeFor: sendNode args first in: aTMethod] } otherwise: "If there /is/ a method for sel but its return type is as yet unknown it /mustn't/ be defaulted, since on a subsequent pass its type may be computable. Only default unbound selectors." [methodOrNil ifNotNil: [nil] ifNil: [typeIfNil]]]! Item was changed: ----- Method: CCodeGenerator>>typeForArithmetic:in: (in category 'type inference') ----- typeForArithmetic: sendNode in: aTMethod "Answer the return type for an arithmetic sendThis is so that the inliner can still inline simple expressions. Deal with pointer arithmetic, floating point arithmetic and promotion." + | rcvrType argType arg | + rcvrType := sendNode receiver typeOrNilFrom: self in: aTMethod. + argType := (arg := sendNode args first) typeOrNilFrom: self in: aTMethod. - | rcvrType argType arg promotedType | - rcvrType := self typeFor: sendNode receiver in: aTMethod. - argType := self typeFor: (arg := sendNode args first) in: aTMethod. "deal with pointer arithmetic" ((rcvrType notNil and: [rcvrType last == $*]) or: [argType notNil and: [argType last == $*]]) ifTrue: [(rcvrType isNil or: [argType isNil]) ifTrue: [^nil]. (rcvrType last == $* and: [argType last == $*]) ifTrue: [sendNode selector == #- ifTrue: [^#int]. self error: 'invalid pointer arithmetic']. ^rcvrType last == $* ifTrue: [rcvrType] ifFalse: [argType]]. + ^(self promoteArithmeticTypes: rcvrType and: argType) ifNotNil: + [:promotedType| + "We have to be very careful with subtraction. The difference between two unsigned types is signed. + But we don't want unsigned - constant to be signed. We almost always want this to stay unsigned." + (sendNode selector == #- and: [promotedType first == $u and: [(arg isConstant and: [arg value isInteger]) not]]) + ifTrue: [promotedType allButFirst: ((promotedType beginsWith: 'unsigned') ifTrue: [9] ifFalse: [1])] + ifFalse: [promotedType]]! - promotedType := self promoteArithmeticTypes: rcvrType and: argType. - "We have to be very careful with subtraction. The difference between two unsigned types is signed. - But we don't want unsigned - constant to be signed. We almost always want this to stay unsigned." - ^(sendNode selector == #- and: [promotedType first == $u and: [(arg isConstant and: [arg value isInteger]) not]]) - ifTrue: [promotedType allButFirst: ((promotedType beginsWith: 'unsigned') ifTrue: [9] ifFalse: [1])] - ifFalse: [promotedType]! Item was changed: ----- Method: SoundPlugin>>primitiveSetDefaultSoundPlayer (in category 'primitives') ----- primitiveSetDefaultSoundPlayer "Tell the operating system to use the specified device name as the output device for sound." "arg at top of stack is the String" | deviceName obj srcPtr sz | <export: true> <var: 'deviceName' declareC: 'char deviceName[257]'> <var: 'srcPtr' type: #'char *'> "Parse arguments" interpreterProxy methodArgumentCount = 1 ifFalse: [^interpreterProxy primitiveFail]. obj := interpreterProxy stackValue: 0. (interpreterProxy isBytes: obj) ifFalse: [^interpreterProxy primitiveFail]. (sz := interpreterProxy byteSizeOf: obj) <= 256 ifFalse: [^interpreterProxy primitiveFail]. srcPtr := interpreterProxy firstIndexableField: obj. self touch: srcPtr. self touch: deviceName. self touch: sz. self cCode: 'strncpy(deviceName, srcPtr, sz)'. + self cCode: 'deviceName[sz] = 0'. - self cCode: 'deviceName[sz] = NULL'. "do the work" self cCode: 'setDefaultSoundPlayer(deviceName)'. interpreterProxy failed ifFalse: "pop arg, leave receiver" [interpreterProxy pop: 1]! Item was changed: ----- Method: SoundPlugin>>primitiveSetDefaultSoundRecorder (in category 'primitives') ----- primitiveSetDefaultSoundRecorder "Tell the operating system to use the specified device name as the input device for sound." "arg at top of stack is the String" | deviceName obj srcPtr sz | <export: true> <var: 'deviceName' declareC: 'char deviceName[257]'> <var: 'srcPtr' type: #'char *'> "Parse arguments" interpreterProxy methodArgumentCount = 1 ifFalse: [^interpreterProxy primitiveFail]. obj := interpreterProxy stackValue: 0. (interpreterProxy isBytes: obj) ifFalse: [^interpreterProxy primitiveFail]. (sz := interpreterProxy byteSizeOf: obj) <= 256 ifFalse: [^interpreterProxy primitiveFail]. srcPtr := interpreterProxy firstIndexableField: obj. self touch: srcPtr. self touch: deviceName. self touch: sz. self cCode: 'strncpy(deviceName, srcPtr, sz)'. + self cCode: 'deviceName[sz] = 0'. - self cCode: 'deviceName[sz] = NULL'. "do the work" self cCode: 'setDefaultSoundRecorder(deviceName)'. interpreterProxy failed ifFalse: "pop arg, leave receiver" [interpreterProxy pop: 1]! Item was changed: ----- Method: SpurMemoryManager>>cleverSwapHeaders:and:copyHashFlag: (in category 'become implementation') ----- cleverSwapHeaders: obj1 and: obj2 copyHashFlag: copyHashFlag "swap headers, but swapping headers swaps remembered bits and hashes; remembered bits must be unswapped and hashes may be unswapped if copyHash is false." "This variant doesn't tickle a compiler bug in gcc and clang. See naiveSwapHeaders:and:copyHashFlag:" <inline: true> + | header1 header2 remembered | - | header1 header2 remembered1 remembered2 | header1 := self long64At: obj1. header2 := self long64At: obj2. + remembered := (header1 bitXor: header2) bitAnd: 1 << self rememberedBitShift. + remembered ~= 0 ifTrue: + [header1 := header1 bitXor: remembered. + header2 := header2 bitXor: remembered]. - remembered1 := header1 bitAnd: 1 << self rememberedBitShift. - remembered2 := header2 bitAnd: 1 << self rememberedBitShift. - remembered1 ~= remembered2 ifTrue: - [header1 := header1 - remembered1 + remembered2. - header2 := header2 - remembered2 + remembered1]. "swapping headers swaps hash; if not copyHashFlag then unswap hash" copyHashFlag ifFalse: + [| hashBits | + hashBits := (header1 bitXor: header2) bitAnd: self identityHashFullWordMask. + hashBits ~= 0 ifTrue: + [header1 := header1 bitXor: hashBits. + header2 := header2 bitXor: hashBits]]. - [| hash1 hash2 | - hash1 := header1 bitAnd: self identityHashFullWordMask. - hash2 := header2 bitAnd: self identityHashFullWordMask. - hash1 ~= hash2 ifTrue: - [header1 := header1 - hash1 + hash2. - header2 := header2 - hash2 + hash1]]. self long64At: obj1 put: header2. self long64At: obj2 put: header1! Item was changed: ----- Method: SpurMemoryManager>>currentAllocatedBytes (in category 'allocation accounting') ----- currentAllocatedBytes "Compute the current allocated bytes since last set. This is the cumulative total in statAllocatedBytes plus the allocation since the last scavenge." | use | + "Slang infers the type of the difference between two unsigned variables as signed. + In this case we want it to be unsigned." + <var: 'use' type: #usqInt> use := segmentManager totalOldSpaceCapacity - totalFreeOldSpace. ^statAllocatedBytes + (freeStart - scavenger eden start) + (use - oldSpaceUsePriorToScavenge)! |
2017-08-31 21:21 GMT+02:00 <[hidden email]>:
OK, the differences seem a bit germane at first glance, but I can try to understand better: So CCodeGenerator>>typeFor:in: / TParseNode>>typeFrom:in: do default to #sqInt rather than nil,. This did cause a premature typing of some local variables. So it was better to use typeOrNilFrom:in:in some place. But If we forget to replace some occurrence by typeOrNilFrom:in: , then we might chain a type inference returning nil with with a type inference returning default #sqInt value, and thus we will bypass the correct type inferencing. Was it the scenario of the problem? SoundPlugin: +1 for this one, much more clever as the selector tells AND much more robust (previous signed arithmetic could overflow, which might work but is UB). - remembered1 := header1 bitAnd: 1 << self rememberedBitShift. |
Hi Nicolas,
|
Free forum by Nabble | Edit this page |