[prev in list] [next in list] [prev in thread] [next in thread]
List: squeak-vm-dev
Subject: Re: [Vm-dev] VM Maker: VMMaker.oscog-eem.2266.mcz
From: Eliot Miranda <eliot.miranda () gmail ! com>
Date: 2017-09-16 12:21:23
Message-ID: 7524F1C8-5458-46C3-B77C-4E1BB88C544D () gmail ! com
[Download RAW message or body]
[Attachment #2 (text/plain)]
[Attachment #3 (multipart/alternative)]
Hi Nicolas,
> On Sep 3, 2017, at 6:38 AM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> \
> wrote:
>
>
> 2017-08-31 21:21 GMT+02:00 <commits@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)!
> >
>
[Attachment #6 (text/html)]
<html><head><meta http-equiv="content-type" content="text/html; \
charset=utf-8"></head><body dir="auto"><div>Hi Nicolas,<br><br></div><div><br>On Sep \
3, 2017, at 6:38 AM, Nicolas Cellier <<a \
href="mailto:nicolas.cellier.aka.nice@gmail.com">nicolas.cellier.aka.nice@gmail.com</a>> \
wrote:<br><br></div><blockquote \
type="cite"><div><span></span></div></blockquote><blockquote type="cite"><div><div \
dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">2017-08-31 21:21 \
GMT+02:00 <span dir="ltr"><<a href="mailto:commits@source.squeak.org" \
target="_blank">commits@source.squeak.org</a>></span>:<br><blockquote \
class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid \
rgb(204,204,204);padding-left:1ex"><br> Eliot Miranda uploaded a new version of \
VMMaker to project VM Maker:<br> <a \
href="http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2266.mcz" rel="noreferrer" \
target="_blank">http://source.squeak.org/VMMak<wbr>er/VMMaker.oscog-eem.2266.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: VMMaker.oscog-eem.2266<br>
Author: eem<br>
Time: 31 August 2017, 12:20:30.681037 pm<br>
UUID: 0501d71a-3185-4bdb-a99c-76a5fb<wbr>beee22<br>
Ancestors: VMMaker.oscog-eem.2265<br>
<br>
Spur:<br>
Simplify cleverSwapHeaders:and:copyHash<wbr>Flag: via xor.<br>
Fix the type of currentAllocatedBytes given the Slang changes below.<br>
<br>
Slang:<br>
Fix a regression caused by the Slang fixes in VMMaker.oscog-eem.2243.<br>
Since inferTypesForImplicitlyTypedVa<wbr>riablesIn: 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.<br> Teh regression caused Slang to fail to infer the types of remembered1/2 \
& hash1/2 in cleverSwapHeaders:and:copyHash<wbr>Flag:. The new code \
correctly infers the types of remembered & hashBits as sqLong.<br> \
<br></blockquote><div><br></div><div>OK, the differences seem a bit germane at first \
glance, but I can try to understand better:<br></div><div><br></div><div>So \
CCodeGenerator>>typeFor:in: / TParseNode>>typeFrom:in: do default to \
#sqInt rather than nil,.</div><div>This did cause a premature typing of some local \
variables.</div><div>So it was better to use typeOrNilFrom:in:in some \
place.<br></div><div><br></div><div>But If we forget to replace some occurrence by \
typeOrNilFrom:in: ,</div><div>then we might chain a type inference returning nil with \
with a type inference returning default #sqInt value,</div><div>and thus we will \
bypass the correct type inferencing.</div><div>Was it the scenario of the \
problem?<br></div></div></div></div></div></blockquote><div><br></div>Yes. \
(Sorry, I missed your message)<div><br><blockquote type="cite"><div><div \
dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> \
<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px \
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> SoundPlugin:<br>
Eliminate a couple of warnings by using 0 instead of NULL.<br>
<br>
=============== Diff against VMMaker.oscog-eem.2265 ===============<br>
<br>
Item was changed:<br>
----- Method: CCodeGenerator>>returnTypeForS<wbr>end:in:ifNil: (in \
category 'type inference') -----<br> returnTypeForSend: sendNode in: aTMethod \
ifNil: typeIfNil<br> "Answer the return type for a \
send. Unbound sends default to typeIfNil.<br> \
Methods with types as yet unknown have a type determined either by the<br> \
kernelReturnTypes or the table below, or, if they \
are in neither set, then nil.<br> The inferred type \
should match as closely as possible the C type of<br> \
generated expessions so that inlining would not change the expression.<br> \
If there is a method for sel but its return type is \
as yet unknown it mustn't<br> be defaulted, since \
on a subsequent pass its type may be computable."<br> | \
sel methodOrNil |<br> methodOrNil := self anyMethodNamed: \
(sel := sendNode selector).<br> (methodOrNil notNil and: \
[methodOrNil returnType notNil]) ifTrue:<br> \
[^self baseTypeForType: methodOrNil returnType].<br> \
^kernelReturnTypes<br> \
at: sel<br> \
ifAbsent:<br> \
[sel<br> \
caseOf: {<br> \
\
[#integerValueOf:] -> \
[#sqInt].<br> \
[#isIntegerObject:] \
-> [#int].<br> \
+ \
[#negated] \
-> \
[self promoteArithmeticTypes: (sendNode receiver typeFrom: self in: aTMethod) and: \
#int].<br>
- \
[#negated] \
-> \
[self promoteArithmeticTypes: (self typeFor: sendNode receiver in: aTMethod) and: \
#int].<br> \
[#+] \
\
-> [self typeForArithmetic: sendNode in: aTMethod].<br> \
\
[#-] \
\
-> [self typeForArithmetic: sendNode in: \
aTMethod].<br> \
[#*] \
\
-> [self typeForArithmetic: sendNode in: aTMethod].<br> \
\
[#/] \
\
-> [self typeForArithmetic: sendNode in: \
aTMethod].<br> \
[#//] \
\
-> [self typeForArithmetic: sendNode in: aTMethod].<br> \
\
[#\\] \
\
-> [self typeForArithmetic: sendNode in: aTMethod].<br> \
\
[#rem:] \
-> \
[self typeForArithmetic: sendNode in: aTMethod].<br> \
\
[#quo:] \
-> \
[self typeForArithmetic: sendNode in: aTMethod].<br> \
\
"C99 Sec Bitwise shift operators ... 3 Sematics ...<br> \
\
The integer promotions are performed on each of the operands. The type of the \
result is that of the promoted left operand..."<br> + \
\
[#>>] \
-> \
[sendNode receiver typeFrom: self in: aTMethod].<br> + \
\
[#<<] \
-> \
[sendNode receiver typeFrom: self in: aTMethod].<br> + \
\
[#addressOf:] \
-> [(sendNode receiver typeFrom: self \
in: aTMethod)<br>
- \
[#>>] \
\
-> [self typeFor: sendNode receiver in: \
aTMethod].<br>
- \
[#<<] \
\
-> [self typeFor: sendNode receiver in: \
aTMethod].<br>
- \
[#addressOf:] \
-> [(self typeFor: sendNode \
receiver in: aTMethod)<br> \
\
\
\
ifNil: [#sqInt]<br> \
\
\
\
ifNotNil: [:type| type, (type last \
isLetter ifTrue: [' *'] ifFalse: ['*'])]].<br> \
\
[#at:] \
-> [self \
typeForDereference: sendNode in: aTMethod].<br> \
\
[#bitAnd:] \
-> [self typeForArithmetic: \
sendNode in: aTMethod].<br> \
[#bitOr:] \
\
-> [self typeForArithmetic: sendNode in: aTMethod].<br> \
\
[#bitXor:] \
-> \
[self typeForArithmetic: sendNode in: aTMethod].<br> \
\
[#bitClear:] \
-> [self typeForArithmetic: \
sendNode in: aTMethod].<br> \
[#bitInvert32] \
-> \
[#'unsigned int'].<br> + \
[#bitInvert64] \
-> [self \
promoteArithmeticTypes: (sendNode receiver typeFrom: self in: aTMethod) and: \
#int].<br>
- \
[#bitInvert64] \
-> [self promoteArithmeticTypes: (self \
typeFor: sendNode receiver in: aTMethod) and: #int].<br> \
\
[#byteSwap32] \
-> [#'unsigned int'].<br> \
\
[#byteSwap64] \
-> [#'unsigned long long'].<br> \
\
[#byteSwapped32IfBigEndian:] -> \
[#'unsigned int'].<br> \
[#byteSwapped64IfBigEndian:] \
-> [#'unsigned long long'].<br> \
\
[#=] \
-> \
[#int].<br> \
[#~=] \
\
-> [#int].<br> \
[#==] \
\
-> [#int].<br> \
\
[#~~] \
-> \
[#int].<br> \
[#<] \
\
-> [#int].<br> \
\
[#<=] \
-> [#int].<br> \
\
[#>] \
\
-> [#int].<br> \
[#>=] \
\
-> [#int].<br> \
\
[#between:and:] -> \
[#int].<br> \
[#anyMask:] \
\
-> [#int].<br> \
\
[#allMask:] \
-> [#int].<br> \
\
[#noMask:] \
-> \
[#int].<br> \
[#isNil] \
\
-> [#int].<br> \
\
[#notNil] \
-> [#int].<br> \
\
[#&] \
-> \
[#int].<br> \
[#|] \
\
-> \
[#int].<br> \
[#not] \
\
-> [#int].<br> \
\
[#asFloat] \
-> [#double].<br> \
\
[#atan] \
-> \
[#double].<br> \
[#exp] \
\
-> [#double].<br> \
\
[#log] \
-> [#double].<br> \
\
[#sin] \
-> \
[#double].<br> \
[#sqrt] \
\
-> [#double].<br> \
\
[#asLong] \
-> [#long].<br> \
\
[#asInteger] \
-> [#sqInt].<br> \
\
[#asIntegerPtr] \
-> [#'sqIntptr_t'].<br> \
\
[#asUnsignedInteger] -> [#usqInt].<br> \
\
[#asUnsignedIntegerPtr]-> \
[#'usqIntptr_t'].<br> \
[#asUnsignedLong] \
-> [#'unsigned \
long'].<br> \
[#asUnsignedLongLong] \
-> [#'unsigned long long'].<br> \
\
[#asVoidPointer] \
-> [#'void *'].<br> \
\
[#signedIntToLong] -> \
[#usqInt]. "c.f. generateSignedIntToLong:on:ind<wbr>ent:"<br> \
\
[#signedIntToShort] -> \
[#usqInt]. "c.f. generateSignedIntToShort:on:in<wbr>dent:"<br> \
\
[#cCoerce:to:] \
-> [sendNode args last value].<br> \
\
[#cCoerceSimple:to:] -> [sendNode args last \
value].<br> \
[#sizeof:] \
\
-> [#'usqIntptr_t']. "Technically it's a size_t but it matches \
on target architectures so far..."<br> \
\
[#ifTrue:ifFalse:] -> \
[self typeForConditional: sendNode in: aTMethod].<br> \
\
[#ifFalse:ifTrue:] -> \
[self typeForConditional: sendNode in: aTMethod].<br> \
\
[#ifTrue:] \
-> [self \
typeForConditional: sendNode in: aTMethod].<br> \
\
[#ifFalse:] \
-> [self typeForConditional: \
sendNode in: aTMethod].<br> \
[#and:] \
\
-> [#sqInt].<br> \
\
[#or:] \
-> [#sqInt].<br> \
\
[#caseOf:] \
-> \
[self typeFor: sendNode args first in: aTMethod] }<br> \
\
otherwise: "If there /is/ a method for sel but its return type is as yet \
unknown it /mustn't/ be defaulted,<br> \
\
since on a \
subsequent pass its type may be computable. Only default unbound \
selectors."<br> \
[methodOrNil \
ifNotNil: [nil] ifNil: [typeIfNil]]]!<br> <br>
Item was changed:<br>
----- Method: CCodeGenerator>>typeForArithme<wbr>tic:in: (in category \
'type inference') -----<br> typeForArithmetic: sendNode in: aTMethod<br>
"Answer the return type for an arithmetic sendThis is so \
that the inliner can still<br> inline simple \
expressions. Deal with pointer arithmetic, floating point arithmetic<br> \
and promotion."<br> + | rcvrType \
argType arg |<br> + rcvrType := sendNode receiver \
typeOrNilFrom: self in: aTMethod.<br> + argType := (arg := \
sendNode args first) typeOrNilFrom: self in: aTMethod.<br>
- | rcvrType argType arg promotedType |<br>
- rcvrType := self typeFor: sendNode receiver in: \
aTMethod.<br>
- argType := self typeFor: (arg := sendNode args first) in: \
aTMethod.<br> "deal with pointer arithmetic"<br>
((rcvrType notNil and: [rcvrType last == $*]) or: \
[argType notNil and: [argType last == $*]]) ifTrue:<br> \
[(rcvrType isNil or: [argType isNil]) ifTrue:<br> \
\
[^nil].<br> (rcvrType \
last == $* and: [argType last == $*]) ifTrue:<br> \
[sendNode selector == #- ifTrue:<br> \
\
[^#int].<br> \
self error: 'invalid pointer \
arithmetic'].<br> \
^rcvrType last == $*<br> \
ifTrue: [rcvrType]<br> \
ifFalse: [argType]].<br> \
+ ^(self promoteArithmeticTypes: rcvrType and: argType) \
ifNotNil:<br> + \
[:promotedType|<br> + \
"We have to be very careful with subtraction. The difference between two \
unsigned types is signed.<br> + \
But we don't want unsigned - constant to be signed. We almost \
always want this to stay unsigned."<br> + \
(sendNode selector == #- and: [promotedType first == $u and: [(arg \
isConstant and: [arg value isInteger]) not]])<br> + \
ifTrue: [promotedType allButFirst: \
((promotedType beginsWith: 'unsigned') ifTrue: [9] ifFalse: [1])]<br> + \
ifFalse: \
[promotedType]]!<br>
- promotedType := self promoteArithmeticTypes: rcvrType \
and: argType.<br>
- "We have to be very careful with subtraction. The \
difference between two unsigned types is signed.<br>
- But we don't want unsigned - constant to be \
signed. We almost always want this to stay unsigned."<br>
- ^(sendNode selector == #- and: [promotedType first == $u \
and: [(arg isConstant and: [arg value isInteger]) not]])<br>
- ifTrue: [promotedType \
allButFirst: ((promotedType beginsWith: 'unsigned') ifTrue: [9] \
ifFalse: [1])]<br>
- ifFalse: [promotedType]!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSetDefau<wbr>ltSoundPlayer (in \
category 'primitives') -----<br> primitiveSetDefaultSoundPlayer<br>
"Tell the operating system to use the specified device \
name as the output device for sound."<br> "arg at top of \
stack is the String"<br> | deviceName obj srcPtr sz |<br>
<export: true><br>
<var: 'deviceName' declareC: 'char \
deviceName[257]'><br> <var: 'srcPtr' type: #'char \
*'><br> <br>
"Parse arguments"<br>
interpreterProxy methodArgumentCount = 1 ifFalse:<br>
[^interpreterProxy \
primitiveFail].<br> obj := interpreterProxy stackValue: \
0.<br> (interpreterProxy isBytes: obj) ifFalse:<br>
[^interpreterProxy \
primitiveFail].<br> (sz := interpreterProxy byteSizeOf: \
obj) <= 256 ifFalse:<br> \
[^interpreterProxy primitiveFail].<br> srcPtr := \
interpreterProxy firstIndexableField: obj.<br> self \
touch: srcPtr.<br> self touch: deviceName.<br>
self touch: sz.<br>
self cCode: 'strncpy(deviceName, srcPtr, sz)'.<br>
+ self cCode: 'deviceName[sz] = 0'.<br>
- self cCode: 'deviceName[sz] = NULL'.<br>
<br>
"do the work"<br>
self cCode: 'setDefaultSoundPlayer(deviceN<wbr>ame)'.<br>
interpreterProxy failed ifFalse: "pop arg, leave \
receiver"<br> \
[interpreterProxy pop: 1]!<br> <br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSetDefau<wbr>ltSoundRecorder (in \
category 'primitives') -----<br> primitiveSetDefaultSoundRecord<wbr>er<br>
"Tell the operating system to use the specified device \
name as the input device for sound."<br> "arg at top of \
stack is the String"<br> | deviceName obj srcPtr sz |<br>
<export: true><br>
<var: 'deviceName' declareC: 'char \
deviceName[257]'><br> <var: 'srcPtr' type: #'char \
*'><br> <br>
"Parse arguments"<br>
interpreterProxy methodArgumentCount = 1 ifFalse:<br>
[^interpreterProxy \
primitiveFail].<br> obj := interpreterProxy stackValue: \
0.<br> (interpreterProxy isBytes: obj) ifFalse:<br>
[^interpreterProxy \
primitiveFail].<br> (sz := interpreterProxy byteSizeOf: \
obj) <= 256 ifFalse:<br> \
[^interpreterProxy primitiveFail].<br> srcPtr := \
interpreterProxy firstIndexableField: obj.<br> self \
touch: srcPtr.<br> self touch: deviceName.<br>
self touch: sz.<br>
self cCode: 'strncpy(deviceName, srcPtr, sz)'.<br>
+ self cCode: 'deviceName[sz] = 0'.<br>
- self cCode: 'deviceName[sz] = NULL'.<br>
<br>
"do the work"<br>
self cCode: \
'setDefaultSoundRecorder(devic<wbr>eName)'.<br> \
interpreterProxy failed ifFalse: "pop arg, leave receiver"<br> \
[interpreterProxy pop: 1]!<br> <br>
Item was changed:<br>
----- Method: \
SpurMemoryManager>>cleverSwapH<wbr>eaders:and:copyHashFlag: (in category \
'become implementation') -----<br> cleverSwapHeaders: obj1 and: obj2 \
copyHashFlag: copyHashFlag<br> "swap headers, but \
swapping headers swaps remembered bits and hashes;<br> \
remembered bits must be unswapped and hashes may be unswapped if<br> \
copyHash is false."<br> "This \
variant doesn't tickle a compiler bug in gcc and clang. See \
naiveSwapHeaders:and:copyHashF<wbr>lag:"<br> <inline: \
true><br> + | header1 header2 remembered |<br>
- | header1 header2 remembered1 remembered2 |<br>
header1 := self long64At: obj1.<br>
header2 := self long64At: obj2.<br>
+ remembered := (header1 bitXor: header2) bitAnd: 1 \
<< self rememberedBitShift.<br> + remembered ~= 0 \
ifTrue:<br> + [header1 := \
header1 bitXor: remembered.<br> + \
header2 := header2 bitXor: remembered].<br></blockquote><div><br></div><div>+1 \
for this one, much more clever as the selector tells AND much more \
robust</div><div>(previous signed arithmetic could overflow, which might work but is \
UB).</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px \
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
- remembered1 := header1 bitAnd: 1 << self \
rememberedBitShift.<br>
- remembered2 := header2 bitAnd: 1 << self \
rememberedBitShift.<br>
- remembered1 ~= remembered2 ifTrue:<br>
- [header1 := header1 - \
remembered1 + remembered2.<br>
- header2 := header2 - \
remembered2 + remembered1].<br> "swapping headers swaps \
hash; if not copyHashFlag then unswap hash"<br> \
copyHashFlag ifFalse:<br> + [| \
hashBits |<br> + hashBits := \
(header1 bitXor: header2) bitAnd: self identityHashFullWordMask.<br> + \
hashBits ~= 0 ifTrue:<br> + \
[header1 := \
header1 bitXor: hashBits.<br> + \
header2 := header2 bitXor: \
hashBits]].<br>
- [| hash1 hash2 |<br>
- hash1 := header1 bitAnd: \
self identityHashFullWordMask.<br>
- hash2 := header2 bitAnd: \
self identityHashFullWordMask.<br>
- hash1 ~= hash2 ifTrue:<br>
- \
[header1 := header1 - hash1 + hash2.<br>
- \
header2 := header2 - hash2 + hash1]].<br> self long64At: \
obj1 put: header2.<br> self long64At: obj2 put: \
header1!<br> <br>
Item was changed:<br>
----- Method: SpurMemoryManager>>currentAllo<wbr>catedBytes (in category \
'allocation accounting') -----<br> currentAllocatedBytes<br>
"Compute the current allocated bytes since last set.<br>
This is the cumulative total in statAllocatedBytes \
plus the allocation since the last scavenge."<br> | use \
|<br> + "Slang infers the type of the difference between \
two unsigned variables as signed.<br> + In this case we \
want it to be unsigned."<br> + <var: 'use' type: \
#usqInt><br> use := segmentManager \
totalOldSpaceCapacity - totalFreeOldSpace.<br> \
^statAllocatedBytes<br> + (freeStart - scavenger \
eden start)<br> + (use - \
oldSpaceUsePriorToScavenge)!<br> <br>
</blockquote></div><br></div></div>
</div></blockquote></div></body></html>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic