VM Maker: VMMaker.oscog-eem.2266.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

VM Maker: VMMaker.oscog-eem.2266.mcz

commits-2
 
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)!

Reply | Threaded
Open this post in threaded view
|

Re: VM Maker: VMMaker.oscog-eem.2266.mcz

Nicolas Cellier
 


2017-08-31 21:21 GMT+02:00 <[hidden email]>:

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?

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)!


Reply | Threaded
Open this post in threaded view
|

Re: VM Maker: VMMaker.oscog-eem.2266.mcz

Eliot Miranda-2
 
Hi Nicolas,


On Sep 3, 2017, at 6:38 AM, Nicolas Cellier <[hidden email]> wrote:



2017-08-31 21:21 GMT+02:00 <[hidden email]>:

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)!