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

Eliot Miranda eliot.miranda at gmail.com
Sat Sep 16 12:21:23 UTC 2017


Hi Nicolas,


> On Sep 3, 2017, at 6:38 AM, Nicolas Cellier <nicolas.cellier.aka.nice at gmail.com> wrote:
> 
> 
> 
> 2017-08-31 21:21 GMT+02:00 <commits at source.squeak.org>:
>> 
>> 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.
>> 
> 
> 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?

Yes.  (Sorry, I missed your message)

> 
>> 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].
> 
> +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.
>> -       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)!
>> 
> 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20170916/671c04c1/attachment-0001.html>


More information about the Vm-dev mailing list