<div dir="ltr">Hi Levente,<br><div><br></div><div>    I'll get #1 done by the end of the day</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Jun 24, 2020 at 12:05 PM Levente Uzonyi <<a href="mailto:leves@caesar.elte.hu">leves@caesar.elte.hu</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"> <br>
Hi Eliot,<br>
<br>
On Wed, 24 Jun 2020, <a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a> wrote:<br>
<br>
> <br>
> Eliot Miranda uploaded a new version of VMMaker to project VM Maker:<br>
> <a href="http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2761.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2761.mcz</a><br>
><br>
> ==================== Summary ====================<br>
><br>
> Name: VMMaker.oscog-eem.2761<br>
> Author: eem<br>
> Time: 24 June 2020, 11:15:52.846414 am<br>
> UUID: 34b29eae-6069-4cb7-8a89-7365fb398dfb<br>
> Ancestors: VMMaker.oscog-eem.2760<br>
><br>
> Cherry Picking from various recent commits, but avoiding the extremely desirable, but as yet unfinished, VMMaker.oscog-nice.2761 transformInAssignmentTo: changes.the "thisContext method includes: 42" crash.<br>
><br>
> MiscPrimitivePlugin: fix several uses of sizeOfSTArrayFromCPrimitive: that don''t check for potential failure if e.g. invoked on a CompiledMethod.  Returning from a primitive normally when the primtiive has failed leads to disaster since the stack gets cu back but shouldn't be.  For CompiledMethod isBytes: is true but isWordsOrBytes: is false.  sizeOfSTArrayFromCPrimitive: checks for isWordsOrBytes:.  The primtiives check that the argument is isBytes: but don't check if sizeOfSTArrayFromCPrimitive: fails.  More general fixes, such as fixing isBytes: to be false for CompiledMethod, or introducing isPureBytes: and using it, are not quick fixes.  hence this limited fix here.<br>
><br>
> Primitive infrastructure: consequently guard the various methodReturnXXX''s with an assert to check that a primitive has not failed.<br>
><br>
> Also make sure that the SpurNBitCoMemoryManagers do not follow any reference to a Cog method in the first field of a CompiledMethod.<br>
><br>
> Cosmetic changes for ThreadedFFIPlugins from VMMaker.oscog-nice.2762<br>
><br>
> Do not try to generate SHA256Plugin, it's obsolete and absent from latest cryptography packages. This from VMMaker.oscog-nice.2761.<br>
<br>
While it's true that SHA256Plugin is now obsolete, simply removing it is <br>
not a solution. Its replacement, SHA2Plugin along with fixes to the other <br>
plugins is available in CryptographyPlugins-ul.22.<br>
IMO 3 steps are required to have the plugins built and shipped with the <br>
VM:<br>
1. Use CryptographyPlugins-ul.22 to generate the plugin sources, and push <br>
the generated files to the git repository.<br>
2. Apply the change from VMMaker.oscog-ul.2763.mcz. It's in the VMMaker <br>
Inbox[1].<br>
3. Update plugins.ext across the git repository to include all the <br>
plugins.<br>
<br>
I can do 2, I can create a pull request for 3, but I can't do 1.<br>
<br>
<br>
Levente<br>
<br>
[1] <a href="http://lists.squeakfoundation.org/pipermail/vm-dev/2020-June/034065.html" rel="noreferrer" target="_blank">http://lists.squeakfoundation.org/pipermail/vm-dev/2020-June/034065.html</a><br>
<br>
><br>
> Slang:<br>
> Fix TParseNode>>isSameAs: implementations to incluyde an identity check.  TReturnNode always answered false to this in the past.<br>
><br>
> Optimize inlineFunctionCall:in: to avoid a rewrite of the copied parse tree being inlined if the actuals match the formals.  Uses the improved bindVariablesIn:.<br>
><br>
> Use a setter for variable & expression in TAssignmentNode to ease breakpointing/debugging.<br>
><br>
> =============== Diff against VMMaker.oscog-eem.2760 ===============<br>
><br>
> Item was changed:<br>
>  ----- Method: CogARMCompiler>>concretizeAndCqRR (in category 'generate machine code - concretize') -----<br>
>  concretizeAndCqRR<br>
>       "Will get inlined into concretizeAt: switch."<br>
>       "AND is very important since it's used to mask all sorts of flags in the jit. We take special care to try to find compact ways to make the masks"<br>
>       <inline: true><br>
>       | val srcReg dstReg |<br>
>       val := operands at: 0.<br>
>       srcReg := operands at: 1.<br>
>       dstReg := operands at: 2.<br>
>       self rotateable8bitBitwiseImmediate: val<br>
>               ifTrue:<br>
>                       [:rot :immediate :invert|<br>
>                       self machineCodeAt: 0 put: (invert<br>
>                                                                                       ifTrue: [self bics: dstReg rn: srcReg imm: immediate ror: rot]<br>
>                                                                                       ifFalse: [self ands: dstReg rn: srcReg imm: immediate ror: rot]).<br>
>                       ^4]<br>
>               ifFalse:<br>
>                       [| hb |<br>
>                       hb := (operands at: 0) highBit.<br>
>                       "First see if the constant can be made from a simple shift of 0xFFFFFFFF"<br>
>                       1 << hb = (val +1) ifTrue: "MVN temp reg, 0, making 0xffffffff"<br>
>                               [self machineCodeAt: 0 put:(self mvn: ConcreteIPReg imm: 0 ror: 0).<br>
>                               "Then AND reg, temp reg, lsr #(32-hb)"<br>
>                                self machineCodeAt: 4 put: (self dataOpType: AndOpcode rd: dstReg rn: srcReg rm: ConcreteIPReg lsr: 32 - hb).<br>
> +                             ^8]].<br>
> +     ^self concretizeDataOperationCwR: AndOpcode R: dstReg!<br>
> -                             ^8].<br>
> -                     ^self concretizeDataOperationCwR: AndOpcode R: dstReg]!<br>
><br>
> Item was added:<br>
> + ----- Method: Float32Array class>>ccg:prolog:expr:index: (in category '*VMMaker-plugin generation') -----<br>
> + ccg: cg prolog: aBlock expr: aString index: anInteger<br>
> + <br>
> +     ^cg ccgLoad: aBlock expr: aString asWBFloatPtrFrom: anInteger!<br>
><br>
> Item was added:<br>
> + ----- Method: Float32Array class>>ccgDeclareCForVar: (in category '*VMMaker-plugin generation') -----<br>
> + ccgDeclareCForVar: aSymbolOrString<br>
> + <br>
> +     ^'float *', aSymbolOrString!<br>
><br>
> Item was removed:<br>
> - ----- Method: FloatArray class>>ccg:prolog:expr:index: (in category '*VMMaker-plugin generation') -----<br>
> - ccg: cg prolog: aBlock expr: aString index: anInteger<br>
> - <br>
> -     ^cg ccgLoad: aBlock expr: aString asWBFloatPtrFrom: anInteger!<br>
><br>
> Item was removed:<br>
> - ----- Method: FloatArray class>>ccgDeclareCForVar: (in category '*VMMaker-plugin generation') -----<br>
> - ccgDeclareCForVar: aSymbolOrString<br>
> - <br>
> -     ^'float *', aSymbolOrString!<br>
><br>
> Item was changed:<br>
>  ----- Method: InterpreterProxy>>methodReturnBool: (in category 'stack access') -----<br>
>  methodReturnBool: boolean<br>
>       "Sets the return value for a method"<br>
> +     self deny: self failed.<br>
>       self pop: argumentCount+1 thenPushBool: boolean.<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: InterpreterProxy>>methodReturnFloat: (in category 'stack access') -----<br>
>  methodReturnFloat: aFloat<br>
>       "Sets the return value for a method"<br>
>       <var: 'aFloat' type: #double><br>
> +     self deny: self failed.<br>
>       self pop: argumentCount+1 thenPushFloat: aFloat.<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: InterpreterProxy>>methodReturnInteger: (in category 'stack access') -----<br>
>  methodReturnInteger: integer<br>
>       "Sets the return value for a method"<br>
> +     self deny: self failed.<br>
>       self pop: argumentCount+1 thenPushInteger: integer.<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: InterpreterProxy>>methodReturnReceiver (in category 'stack access') -----<br>
>  methodReturnReceiver<br>
>       "Sets the return value for a method"<br>
> +     self deny: self failed.<br>
>       self pop: argumentCount.<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: InterpreterProxy>>methodReturnString: (in category 'stack access') -----<br>
>  methodReturnString: aCString<br>
>       "Attempt to answer a ByteString for a given C string as the result of a primitive."<br>
>       <var: 'aCString' type: #'char *'><br>
> +     self deny: self failed.<br>
>       aCString<br>
>               ifNil: [primFailCode := PrimErrOperationFailed]<br>
>               ifNotNil:<br>
>                       [(self stringForCString: aCString)<br>
>                               ifNil: [primFailCode := PrimErrNoMemory]<br>
>                               ifNotNil: [:result| self pop: argumentCount+1 thenPush: result]].<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: InterpreterProxy>>methodReturnValue: (in category 'stack access') -----<br>
>  methodReturnValue: oop<br>
>       "Sets the return value for a method"<br>
> +     self deny: self failed.<br>
>       self pop: argumentCount+1 thenPush: oop.<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: MiscPrimitivePlugin>>primitiveCompareString (in category 'primitives') -----<br>
>  primitiveCompareString<br>
>       "ByteString (class) compare: string1 with: string2 collated: order"<br>
>       <export: true><br>
>       | len1 len2 order string1 string2 orderOop string1Oop string2Oop |<br>
><br>
>       <var: 'order' type: #'unsigned char *'><br>
>       <var: 'string1' type: #'unsigned char *'><br>
>       <var: 'string2' type: #'unsigned char *'><br>
>       orderOop := interpreterProxy stackValue: 0.<br>
>       string2Oop := interpreterProxy stackValue: 1.<br>
>       string1Oop := interpreterProxy stackValue: 2.<br>
>       ((interpreterProxy isBytes: orderOop)<br>
>       and: [(interpreterProxy isBytes: string2Oop)<br>
>       and: [interpreterProxy isBytes: string1Oop]]) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       order := interpreterProxy firstIndexableField: orderOop.<br>
>       (interpreterProxy sizeOfSTArrayFromCPrimitive: order) < 256 ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       string1 := interpreterProxy firstIndexableField: string1Oop.<br>
>       string2 := interpreterProxy firstIndexableField: string2Oop.<br>
>       len1 := interpreterProxy sizeOfSTArrayFromCPrimitive: string1.<br>
>       len2 := interpreterProxy sizeOfSTArrayFromCPrimitive: string2.<br>
> +     interpreterProxy failed ifTrue: "the sizeOfSTArrayFromCPrimitive:'s fail for e.g. CompiledMethod"<br>
> +             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       0 to: (len1 min: len2) - 1 do:<br>
>               [ :i | | c1 c2 |<br>
>               c1 := order at: (string1 at: i).<br>
>               c2 := order at: (string2 at: i).<br>
>               c1 = c2 ifFalse:<br>
>                       [^interpreterProxy methodReturnInteger: (c1 < c2 ifTrue: [1] ifFalse: [3])]].<br>
>       interpreterProxy methodReturnInteger:<br>
>               (len1 = len2 ifTrue: [2] ifFalse: [len1 < len2 ifTrue: [1] ifFalse: [3]])!<br>
><br>
> Item was changed:<br>
>  ----- Method: MiscPrimitivePlugin>>primitiveCompressToByteArray (in category 'primitives') -----<br>
>  primitiveCompressToByteArray<br>
>       "Bitmap compress: bm toByteArray: ba"<br>
>       <export: true><br>
>       | bm ba eqBytes i j k lowByte size destSize word |<br>
>       <var: 'ba' type: #'unsigned char *'><br>
>       <var: 'bm' type: #'int *'><br>
>       bm := self cCode: [interpreterProxy arrayValueOf: (interpreterProxy stackValue: 1)]<br>
>                               inSmalltalk: [interpreterProxy<br>
>                                                               cCoerce: (interpreterProxy arrayValueOf: (interpreterProxy stackValue: 1))<br>
>                                                               to: #'int *'].<br>
>       interpreterProxy failed ifTrue: [^nil].<br>
>       (interpreterProxy isBytes: (interpreterProxy stackValue: 0)) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       (interpreterProxy isOopImmutable: (interpreterProxy stackValue: 0)) ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrNoModification].<br>
>       ba := interpreterProxy firstIndexableField: (interpreterProxy stackValue: 0).<br>
>       size := interpreterProxy sizeOfSTArrayFromCPrimitive: bm.<br>
>       destSize := interpreterProxy sizeOfSTArrayFromCPrimitive: ba.<br>
> +     interpreterProxy failed ifTrue: "the sizeOfSTArrayFromCPrimitive:'s fail for e.g. CompiledMethod"<br>
> +             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       destSize < ((size * 4) + 7 + (size // 1984 * 3)) ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrUnsupported]. "Size may be OK but we don't know, hence fail with unsupported"<br>
>       i := self encodeInt: size in: ba at: 0.<br>
>       k := 0.<br>
>       [k < size] whileTrue:<br>
>               [word := bm at: k.<br>
>               lowByte := word bitAnd: 255.<br>
>               eqBytes := (word >> 8 bitAnd: 255) = lowByte and: [(word >> 16 bitAnd: 255) = lowByte and: [(word >> 24 bitAnd: 255) = lowByte]].<br>
>               j := k.<br>
>               [j + 1 < size and: [word = (bm at: j + 1)]] whileTrue: [j := j + 1].<br>
>               j > k<br>
>                       ifTrue:<br>
>                               [eqBytes<br>
>                                       ifTrue:<br>
>                                               [i := self encodeInt: j - k + 1 * 4 + 1 in: ba at: i.<br>
>                                               ba at: i put: lowByte.<br>
>                                               i := i + 1]<br>
>                                       ifFalse:<br>
>                                               [i := self encodeInt: j - k + 1 * 4 + 2 in: ba at: i.<br>
>                                               i := self encodeBytesOf: word in: ba at: i].<br>
>                               k := j + 1]<br>
>                       ifFalse:<br>
>                               [eqBytes<br>
>                                       ifTrue:<br>
>                                               [i := self encodeInt: 1 * 4 + 1 in: ba at: i.<br>
>                                               ba at: i put: lowByte.<br>
>                                               i := i + 1.<br>
>                                               k := k + 1]<br>
>                                       ifFalse:<br>
>                                               [[j + 1 < size and: [(bm at: j) ~= (bm at: j + 1)]] whileTrue: [j := j + 1].<br>
>                                               j + 1 = size ifTrue: [j := j + 1].<br>
>                                               i := self encodeInt: j - k * 4 + 3 in: ba at: i.<br>
>                                               k to: j - 1 by: 1 do: [ :m | i := self encodeBytesOf: (bm at: m) in: ba at: i].<br>
>                                               k := j]]].<br>
>       interpreterProxy methodReturnInteger: i!<br>
><br>
> Item was changed:<br>
>  ----- Method: MiscPrimitivePlugin>>primitiveConvert8BitSigned (in category 'primitives') -----<br>
>  primitiveConvert8BitSigned<br>
>       "SampledSound (class) convert8bitSignedFrom: aByteArray to16Bit: aSoundBuffer"<br>
>       <export: true><br>
>       | aByteArray aSoundBuffer arraySize byteArrayOop soundBufferOop |<br>
><br>
>       <var: 'aByteArray' type: #'unsigned char *'><br>
>       <var: 'aSoundBuffer' type: #'unsigned short *'><br>
>       byteArrayOop := interpreterProxy stackValue: 1.<br>
>       (interpreterProxy isBytes: byteArrayOop) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       aByteArray := interpreterProxy firstIndexableField: byteArrayOop.<br>
>       soundBufferOop := interpreterProxy stackValue: 0.<br>
> +     (interpreterProxy isOopImmutable: soundBufferOop) ifTrue:<br>
> +             [^interpreterProxy primitiveFailFor: PrimErrNoModification].<br>
>       aSoundBuffer := self<br>
>                                               cCode: [interpreterProxy arrayValueOf: soundBufferOop]<br>
>                                               inSmalltalk: [interpreterProxy<br>
>                                                                               cCoerce: (interpreterProxy arrayValueOf: soundBufferOop)<br>
>                                                                               to: #'unsigned short *'].<br>
> -     interpreterProxy failed ifTrue: [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
> -     (interpreterProxy isOopImmutable: soundBufferOop) ifTrue:<br>
> -             [^interpreterProxy primitiveFailFor: PrimErrNoModification].<br>
>       arraySize := interpreterProxy sizeOfSTArrayFromCPrimitive: aByteArray.<br>
> +     interpreterProxy failed ifTrue:<br>
> +             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       (interpreterProxy byteSizeOf: soundBufferOop) < (2 * arraySize) ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       0 to: arraySize - 1 do:<br>
>               [ :i | | s |<br>
>               s := aByteArray at: i.<br>
>               aSoundBuffer<br>
>                       at: i<br>
>                       put: (s > 127<br>
>                                       ifTrue: [s - 256 bitShift: 8]<br>
>                                       ifFalse: [s bitShift: 8])].<br>
>       interpreterProxy methodReturnReceiver!<br>
><br>
> Item was changed:<br>
>  ----- Method: MiscPrimitivePlugin>>primitiveDecompressFromByteArray (in category 'primitives') -----<br>
>  primitiveDecompressFromByteArray<br>
>       "Bitmap decompress: bm fromByteArray: ba at: index"<br>
>       <export: true><br>
>       | bm ba index i anInt code data end k n pastEnd |<br>
>       <var: 'ba' type: #'unsigned char *'><br>
>       <var: 'bm' type: #'int *'><br>
>       <var: 'anInt' type: #'unsigned int'><br>
>       <var: 'code' type: #'unsigned int'><br>
>       <var: 'data' type: #'unsigned int'><br>
>       <var: 'n' type: #'unsigned int'><br>
>       bm := self cCode: [interpreterProxy arrayValueOf: (interpreterProxy stackValue: 2)]<br>
>                               inSmalltalk: [interpreterProxy<br>
>                                                               cCoerce: (interpreterProxy arrayValueOf: (interpreterProxy stackValue: 2))<br>
>                                                               to: #'int *'].<br>
>       (interpreterProxy isOopImmutable: (interpreterProxy stackValue: 2)) ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrNoModification].<br>
>       (interpreterProxy isBytes: (interpreterProxy stackValue: 1)) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       ba := interpreterProxy firstIndexableField: (interpreterProxy stackValue: 1).<br>
>       index := interpreterProxy stackIntegerValue: 0.<br>
> -     interpreterProxy failed ifTrue: [^nil].<br>
> -     i := index - 1.<br>
> -     k := 0.<br>
>       end := interpreterProxy sizeOfSTArrayFromCPrimitive: ba.<br>
>       pastEnd := interpreterProxy sizeOfSTArrayFromCPrimitive: bm.<br>
> +     interpreterProxy failed ifTrue:<br>
> +             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
> +     i := index - 1.<br>
> +     k := 0.<br>
>       [i < end] whileTrue:<br>
>               [anInt := ba at: i.<br>
>               i := i + 1.<br>
>               anInt <= 223 ifFalse:<br>
>                       [anInt <= 254<br>
>                               ifTrue:<br>
>                                       [anInt := anInt - 224 * 256 + (ba at: i).<br>
>                                       i := i + 1]<br>
>                               ifFalse:<br>
>                                       [anInt := 0.<br>
>                                       1 to: 4 by: 1 do:<br>
>                                               [ :j | anInt := (anInt bitShift: 8) + (ba at: i).<br>
>                                               i := i + 1]]].<br>
>               n := anInt >> 2.<br>
>               k + n > pastEnd ifTrue:<br>
>                       [^interpreterProxy primitiveFailFor: PrimErrBadIndex].<br>
>               code := anInt bitAnd: 3.<br>
>               "code = 0 ifTrue: [nil]."<br>
>               code = 1 ifTrue:<br>
>                       [data := ba at: i.<br>
>                       i := i + 1.<br>
>                       data := data bitOr: (data bitShift: 8).<br>
>                       data := data bitOr: (data bitShift: 16).<br>
>                       1 to: n do:<br>
>                               [ :j |<br>
>                               bm at: k put: data.<br>
>                               k := k + 1]].<br>
>               code = 2 ifTrue:<br>
>                       [data := 0.<br>
>                       1 to: 4 do:<br>
>                               [ :j |<br>
>                               data := (data bitShift: 8) bitOr: (ba at: i).<br>
>                               i := i + 1].<br>
>                       1 to: n do:<br>
>                               [ :j |<br>
>                               bm at: k put: data.<br>
>                               k := k + 1]].<br>
>               code = 3 ifTrue:<br>
>                       [1 to: n do:<br>
>                               [ :m |<br>
>                               data := 0.<br>
>                               1 to: 4 do:<br>
>                                       [ :j |<br>
>                                       data := (data bitShift: 8) bitOr: (ba at: i).<br>
>                                       i := i + 1].<br>
>                               bm at: k put: data.<br>
>                               k := k + 1]]].<br>
>       interpreterProxy pop: interpreterProxy methodArgumentCount!<br>
><br>
> Item was changed:<br>
>  ----- Method: MiscPrimitivePlugin>>primitiveFindFirstInString (in category 'primitives') -----<br>
>  primitiveFindFirstInString<br>
>       "ByteString (class) findFirstInString: aString inSet: inclusionMap  startingAt: start"<br>
>       <export: true><br>
><br>
>       |  aString i inclusionMap stringSize aStringOop inclusionMapOop |<br>
>       <var: 'aString' type: #'unsigned char *'><br>
>       <var: 'inclusionMap' type: #'unsigned char *'><br>
>       aStringOop := interpreterProxy stackValue: 2.<br>
>       (interpreterProxy isBytes: aStringOop) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       inclusionMapOop :=  interpreterProxy stackValue: 1.<br>
>       (interpreterProxy isBytes: inclusionMapOop) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       i := interpreterProxy stackIntegerValue: 0.<br>
> +     interpreterProxy failed ifTrue:<br>
> +             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
> -     interpreterProxy failed ifTrue: [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       i := i - 1. "Convert to 0-based index."<br>
>       i < 0 ifTrue: [^interpreterProxy primitiveFailFor: PrimErrBadIndex].<br>
>       inclusionMap := interpreterProxy firstIndexableField: inclusionMapOop.<br>
>       (interpreterProxy sizeOfSTArrayFromCPrimitive: inclusionMap) ~= 256 ifTrue:<br>
>               [^interpreterProxy methodReturnInteger: 0].<br>
>       aString := interpreterProxy firstIndexableField: aStringOop.<br>
>       stringSize := interpreterProxy sizeOfSTArrayFromCPrimitive: aString.<br>
> +     interpreterProxy failed ifTrue: "the sizeOfSTArrayFromCPrimitive:'s fail for e.g. CompiledMethod"<br>
> +             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       [i < stringSize and: [(inclusionMap at: (aString at: i)) = 0]] whileTrue:<br>
>               [i := i + 1].<br>
>       interpreterProxy methodReturnInteger: (i >= stringSize ifTrue: [0] ifFalse: [i + 1])!<br>
><br>
> Item was changed:<br>
>  ----- Method: MiscPrimitivePlugin>>primitiveFindSubstring (in category 'primitives') -----<br>
>  primitiveFindSubstring<br>
>       "ByteString findSubstring: key in: body startingAt: start matchTable: matchTable"<br>
>       <export: true><br>
> <br>
> +     | body key keySize bodySize matchTable start bodyOop keyOop matchTableOop |<br>
> -     | body key keySize matchTable start bodyOop keyOop matchTableOop |<br>
>       <var: #key type: #'unsigned char *'><br>
>       <var: #body type: #'unsigned char *'><br>
>       <var: #matchTable type: #'unsigned char *'><br>
>       keyOop := interpreterProxy stackValue: 3.<br>
>       (interpreterProxy isBytes: keyOop) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       bodyOop := interpreterProxy stackValue: 2.<br>
>       (interpreterProxy isBytes: bodyOop) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       start := interpreterProxy stackIntegerValue: 1.<br>
>       interpreterProxy failed ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       matchTableOop := interpreterProxy stackValue: 0.<br>
>       (interpreterProxy isBytes: matchTableOop) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       matchTable := interpreterProxy firstIndexableField: matchTableOop.<br>
>       (interpreterProxy sizeOfSTArrayFromCPrimitive: matchTable) < 256 ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       key := interpreterProxy firstIndexableField: keyOop.<br>
>       (keySize := interpreterProxy sizeOfSTArrayFromCPrimitive: key) > 0 ifTrue:<br>
>               [keySize := keySize - 1. "adjust for zero relative indexes"<br>
>               start := start - 1 max: 0. "adjust for zero relative indexes"<br>
> +             body := interpreterProxy firstIndexableField: bodyOop.<br>
> +             bodySize := interpreterProxy sizeOfSTArrayFromCPrimitive: body.<br>
> +             interpreterProxy failed ifTrue: "the sizeOfSTArrayFromCPrimitive:'s fail for e.g. CompiledMethod"<br>
> +                     [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
> +             start to: bodySize - 1 - keySize do: <br>
> -             body := interpreterProxy firstIndexableField: bodyOop. <br>
> -             start to: (interpreterProxy sizeOfSTArrayFromCPrimitive: body) - 1 - keySize do:<br>
>                       [ :startIndex | | index |<br>
>                       index := 0.<br>
>                       [(matchTable at: (body at: startIndex + index)) = (matchTable at: (key at: index))] whileTrue:<br>
>                               [index = keySize ifTrue:<br>
>                                       [^interpreterProxy methodReturnInteger: startIndex + 1].<br>
>                               index := index + 1]]].<br>
>       ^interpreterProxy methodReturnInteger: 0!<br>
><br>
> Item was changed:<br>
>  ----- Method: MiscPrimitivePlugin>>primitiveIndexOfAsciiInString (in category 'primitives') -----<br>
>  primitiveIndexOfAsciiInString<br>
>       "ByteString indexOfAscii: anInteger inString: aString startingAt: start"<br>
>       <export: true><br>
> <br>
> +     | integerOop startOop anInteger aString start stringSize stringOop |<br>
> -     | anInteger aString start stringSize aStringOop |<br>
>       <var: #aString type: #'unsigned char *'><br>
> +     integerOop := interpreterProxy stackValue: 2.<br>
> +     stringOop := interpreterProxy stackValue: 1.<br>
> +     startOop := interpreterProxy stackValue: 0.<br>
> +     ((interpreterProxy isIntegerObject: integerOop)<br>
> +      and: [(interpreterProxy isIntegerObject: startOop)<br>
> +      and: [(interpreterProxy isBytes: stringOop)<br>
> +      and: [interpreterProxy isWordsOrBytes: stringOop]]]) ifFalse: "sizeOfSTArrayFromCPrimitive: is defined only for words or bytes"<br>
> -     anInteger := interpreterProxy stackIntegerValue: 2.<br>
> -     interpreterProxy failed ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
> +     (start := interpreterProxy integerValueOf: startOop) >= 1 ifFalse:<br>
> +             [^interpreterProxy primitiveFailFor: PrimErrBadIndex].<br>
> +     anInteger := interpreterProxy integerValueOf: integerOop.<br>
> +     aString := interpreterProxy firstIndexableField: stringOop.<br>
> -     aStringOop := interpreterProxy stackValue: 1.<br>
> -     (interpreterProxy isBytes: aStringOop) ifFalse:<br>
> -             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
> -     start := interpreterProxy stackIntegerValue: 0. <br>
> -     interpreterProxy failed ifTrue: <br>
> -             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
> -     start >= 1 ifFalse: [^interpreterProxy primitiveFailFor: PrimErrBadIndex].<br>
> -     aString := interpreterProxy firstIndexableField: aStringOop.<br>
>       stringSize := interpreterProxy sizeOfSTArrayFromCPrimitive: aString.<br>
>       start - 1 to: stringSize - 1 do:<br>
> +             [:pos |<br>
> -             [ :pos |<br>
>               (aString at: pos) = anInteger ifTrue:<br>
>                       [^interpreterProxy methodReturnInteger: pos + 1]].<br>
>       ^interpreterProxy methodReturnInteger: 0!<br>
><br>
> Item was changed:<br>
>  ----- Method: MiscPrimitivePlugin>>primitiveStringHash (in category 'primitives') -----<br>
>  primitiveStringHash<br>
>       "ByteArray (class) hashBytes: aByteArray startingWith: speciesHash"<br>
>       <export: true><br>
><br>
>       | aByteArray hash byteArrayOop |<br>
>       <var: 'aByteArray' type: #'unsigned char *'><br>
>       <var: 'hash' type: #'unsigned int'><br>
>       hash := interpreterProxy stackIntegerValue: 0.<br>
>       interpreterProxy failed ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       byteArrayOop := interpreterProxy stackValue: 1.<br>
> +     ((interpreterProxy isBytes: byteArrayOop)<br>
> +     and: [interpreterProxy isWordsOrBytes: byteArrayOop]) ifFalse: "filters out CompiledMethods"<br>
> -     (interpreterProxy isBytes: byteArrayOop) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       aByteArray := interpreterProxy firstIndexableField: byteArrayOop.<br>
>       0 to: (interpreterProxy sizeOfSTArrayFromCPrimitive: aByteArray) - 1 do:<br>
>               [ :pos |<br>
>               hash := hash + (aByteArray at: pos) * 16r19660D ].<br>
>       interpreterProxy methodReturnInteger: (hash bitAnd: 16r0FFFFFFF)!<br>
><br>
> Item was changed:<br>
>  ----- Method: MiscPrimitivePlugin>>primitiveTranslateStringWithTable (in category 'primitives') -----<br>
>  primitiveTranslateStringWithTable<br>
>       "ByteString (class) translate: aString from: start to: stop table: table"<br>
>       <export: true><br>
><br>
>       | aString start stop table aStringOop tableOop |<br>
>       <var: #table type: #'unsigned char *'><br>
>       <var: #aString type: #'unsigned char *'><br>
>       aStringOop := interpreterProxy stackValue: 3.<br>
>       (interpreterProxy isBytes: aStringOop) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       (interpreterProxy isOopImmutable: aStringOop) ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrNoModification].<br>
>       start := interpreterProxy stackIntegerValue: 2.<br>
> -     interpreterProxy failed ifTrue:<br>
> -             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       stop := interpreterProxy stackIntegerValue: 1.<br>
>       interpreterProxy failed ifTrue:<br>
> +             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
> -             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       tableOop := interpreterProxy stackValue: 0.<br>
>       (interpreterProxy isBytes: tableOop) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       aString := interpreterProxy firstIndexableField: aStringOop.<br>
>       (start >= 1 and: [stop <= (interpreterProxy sizeOfSTArrayFromCPrimitive: aString)]) ifFalse:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadIndex].<br>
>       table := interpreterProxy firstIndexableField: tableOop.<br>
>       (interpreterProxy sizeOfSTArrayFromCPrimitive: table) < 256 ifTrue:<br>
>               [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
> +     interpreterProxy failed ifTrue:<br>
> +             [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
>       start - 1 to: stop - 1 do: [ :i | aString at: i put: (table at: (aString at: i))].<br>
>       interpreterProxy methodReturnReceiver!<br>
><br>
> Item was added:<br>
> + ----- Method: Spur32BitCoMemoryManager>>followForwardedObjectFields:toDepth: (in category 'forwarding') -----<br>
> + followForwardedObjectFields: objOop toDepth: depth<br>
> +     "Follow pointers in the object to depth.<br>
> +      Answer if any forwarders were found.<br>
> +      How to avoid cyclic structures?? A temporary mark bit? eem 6/22/2020 no need since depth is always finite."<br>
> +     <api><br>
> +     <inline: false><br>
> +     | found fmt numSlots |<br>
> +     found := false.<br>
> +     self assert: ((self isPointers: objOop) or: [self isOopCompiledMethod: objOop]).<br>
> +     fmt := self formatOf: objOop.<br>
> +     numSlots := self numPointerSlotsOf: objOop format: fmt.<br>
> +     "It is essential to skip the first field of a method because it may be a<br>
> +      reference to a Cog method in the method zone, not a real object at all."<br>
> +     ((self isCompiledMethodFormat: fmt)<br>
> +                     ifTrue: [1]<br>
> +                     ifFalse: [0])<br>
> +             to: numSlots - 1<br>
> +             do: [:i| | oop |<br>
> +                     oop := self fetchPointer: i ofObject: objOop.<br>
> +                     (self isNonImmediate: oop) ifTrue:<br>
> +                             [(self isForwarded: oop) ifTrue:<br>
> +                                     [found := true.<br>
> +                                      oop := self followForwarded: oop.<br>
> +                                      self storePointer: i ofObject: objOop withValue: oop].<br>
> +                             (depth > 0<br>
> +                              and: [(self hasPointerFields: oop)<br>
> +                              and: [self followForwardedObjectFields: oop toDepth: depth - 1]]) ifTrue:<br>
> +                                     [found := true]]].<br>
> +     ^found!<br>
><br>
> Item was added:<br>
> + ----- Method: Spur64BitCoMemoryManager>>followForwardedObjectFields:toDepth: (in category 'forwarding') -----<br>
> + followForwardedObjectFields: objOop toDepth: depth<br>
> +     "Follow pointers in the object to depth.<br>
> +      Answer if any forwarders were found.<br>
> +      How to avoid cyclic structures?? A temporary mark bit? eem 6/22/2020 no need since depth is always finite."<br>
> +     <api><br>
> +     <inline: false><br>
> +     | found fmt numSlots |<br>
> +     found := false.<br>
> +     self assert: ((self isPointers: objOop) or: [self isOopCompiledMethod: objOop]).<br>
> +     fmt := self formatOf: objOop.<br>
> +     numSlots := self numPointerSlotsOf: objOop format: fmt.<br>
> +     "It is essential to skip the first field of a method because it may be a<br>
> +      reference to a Cog method in the method zone, not a real object at all."<br>
> +     ((self isCompiledMethodFormat: fmt)<br>
> +                     ifTrue: [1]<br>
> +                     ifFalse: [0])<br>
> +             to: numSlots - 1<br>
> +             do: [:i| | oop |<br>
> +                     oop := self fetchPointer: i ofObject: objOop.<br>
> +                     (self isNonImmediate: oop) ifTrue:<br>
> +                             [(self isForwarded: oop) ifTrue:<br>
> +                                     [found := true.<br>
> +                                      oop := self followForwarded: oop.<br>
> +                                      self storePointer: i ofObject: objOop withValue: oop].<br>
> +                             (depth > 0<br>
> +                              and: [(self hasPointerFields: oop)<br>
> +                              and: [self followForwardedObjectFields: oop toDepth: depth - 1]]) ifTrue:<br>
> +                                     [found := true]]].<br>
> +     ^found!<br>
><br>
> Item was changed:<br>
>  ----- Method: SpurMemoryManager>>followForwardedObjectFields:toDepth: (in category 'forwarding') -----<br>
>  followForwardedObjectFields: objOop toDepth: depth<br>
>       "Follow pointers in the object to depth.<br>
>        Answer if any forwarders were found.<br>
> +      How to avoid cyclic structures?? A temporary mark bit? eem 6/22/2020 no need since depth is always finite."<br>
> -      How to avoid cyclic structures?? A temproary mark bit?"<br>
>       <api><br>
>       <inline: false><br>
> +     | found numSlots |<br>
> -     | oop found |<br>
>       found := false.<br>
>       self assert: ((self isPointers: objOop) or: [self isOopCompiledMethod: objOop]).<br>
> +     numSlots  := self numPointerSlotsOf: objOop.<br>
> +     0 to: numSlots - 1 do:<br>
> +             [:i| | oop |<br>
> -     0 to: (self numPointerSlotsOf: objOop) - 1 do:<br>
> -             [:i|<br>
>                oop := self fetchPointer: i ofObject: objOop.<br>
>                (self isNonImmediate: oop) ifTrue:<br>
>                       [(self isForwarded: oop) ifTrue:<br>
>                               [found := true.<br>
>                                oop := self followForwarded: oop.<br>
>                                self storePointer: i ofObject: objOop withValue: oop].<br>
>                       (depth > 0<br>
>                        and: [(self hasPointerFields: oop)<br>
>                        and: [self followForwardedObjectFields: oop toDepth: depth - 1]]) ifTrue:<br>
>                               [found := true]]].<br>
>       ^found!<br>
><br>
> Item was changed:<br>
>  ----- Method: SpurMemoryManager>>numPointerSlotsOf: (in category 'object access') -----<br>
>  numPointerSlotsOf: objOop<br>
>       "Answer the number of pointer fields in the given object.<br>
>        Works with CompiledMethods, as well as ordinary objects."<br>
>       <api><br>
>       <inline: true><br>
> +     | fmt |<br>
> -     | fmt contextSize numLiterals header |<br>
>       fmt := self formatOf: objOop.<br>
> +     ^self numPointerSlotsOf: objOop format: fmt!<br>
> -     fmt <= self lastPointerFormat ifTrue:<br>
> -             [(fmt = self indexablePointersFormat<br>
> -               and: [self isContextNonImm: objOop]) ifTrue:<br>
> -                     ["contexts end at the stack pointer"<br>
> -                     contextSize := coInterpreter fetchStackPointerOf: objOop.<br>
> -                     ^CtxtTempFrameStart + contextSize].<br>
> -             ^self numSlotsOf: objOop  "all pointers"].<br>
> -     fmt = self forwardedFormat ifTrue: [^1].<br>
> -     fmt < self firstCompiledMethodFormat ifTrue: [^0]. "no pointers"<br>
> - <br>
> -     "CompiledMethod: contains both pointers and bytes"<br>
> -     header := self methodHeaderOf: objOop.<br>
> -     numLiterals := self literalCountOfMethodHeader: header.<br>
> -     ^numLiterals + LiteralStart!<br>
><br>
> Item was added:<br>
> + ----- Method: SpurMemoryManager>>numPointerSlotsOf:format: (in category 'object access') -----<br>
> + numPointerSlotsOf: objOop format: fmt<br>
> +     "Answer the number of pointer fields in the given object.<br>
> +      Works with CompiledMethods, as well as ordinary objects."<br>
> +     <inline: #always><br>
> +     | contextSize numLiterals header |<br>
> +     fmt <= self lastPointerFormat ifTrue:<br>
> +             [(fmt = self indexablePointersFormat<br>
> +               and: [self isContextNonImm: objOop]) ifTrue:<br>
> +                     ["contexts end at the stack pointer"<br>
> +                     contextSize := coInterpreter fetchStackPointerOf: objOop.<br>
> +                     ^CtxtTempFrameStart + contextSize].<br>
> +             ^self numSlotsOf: objOop  "all pointers"].<br>
> +     fmt = self forwardedFormat ifTrue: [^1].<br>
> +     fmt < self firstCompiledMethodFormat ifTrue: [^0]. "no pointers"<br>
> + <br>
> +     "CompiledMethod: contains both pointers and bytes"<br>
> +     header := self methodHeaderOf: objOop.<br>
> +     numLiterals := self literalCountOfMethodHeader: header.<br>
> +     ^numLiterals + LiteralStart!<br>
><br>
> Item was changed:<br>
>  ----- Method: StackInterpreter>>methodReturnBool: (in category 'plugin primitive support') -----<br>
>  methodReturnBool: boolean<br>
>       "Sets the return value for a method.  In the CoInterpreter we replace the cumbersome<br>
>        primResult machinery."<br>
> +     self deny: self failed.<br>
>       self pop: argumentCount+1 thenPushBool: boolean.<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: StackInterpreter>>methodReturnFloat: (in category 'plugin primitive support') -----<br>
>  methodReturnFloat: aFloat<br>
>       "Sets the return value for a method."<br>
>       <var: 'aFloat' type: #double><br>
> +     self deny: self failed.<br>
>       self pop: argumentCount+1 thenPushFloat: aFloat.<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: StackInterpreter>>methodReturnInteger: (in category 'plugin primitive support') -----<br>
>  methodReturnInteger: integer<br>
>       "Sets the return value for a method.  In the CoInterpreter we replace the cumbersome<br>
>        primResult machinery."<br>
> +     self deny: self failed.<br>
>       self pop: argumentCount+1 thenPushInteger: integer.<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: StackInterpreter>>methodReturnReceiver (in category 'plugin primitive support') -----<br>
>  methodReturnReceiver<br>
>       "Sets the return value for a method"<br>
> +     self deny: self failed.<br>
>       self pop: argumentCount.<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: StackInterpreter>>methodReturnString: (in category 'plugin primitive support') -----<br>
>  methodReturnString: aCString<br>
>       "Attempt to answer a ByteString for a given C string as the result of a primitive."<br>
>       <var: 'aCString' type: #'char *'><br>
> +     self deny: self failed.<br>
>       aCString<br>
>               ifNil: [primFailCode := PrimErrOperationFailed]<br>
>               ifNotNil:<br>
>                       [(self stringForCString: aCString)<br>
>                               ifNil: [primFailCode := PrimErrNoMemory]<br>
>                               ifNotNil: [:result| self pop: argumentCount+1 thenPush: result]].<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: StackInterpreter>>methodReturnValue: (in category 'plugin primitive support') -----<br>
>  methodReturnValue: oop<br>
>       "Sets the return value for a method.  In the CoInterpreter we replace the cumbersome<br>
>        primResult machinery."<br>
> +     self deny: self failed.<br>
>       self pop: argumentCount+1 thenPush: oop.<br>
>       ^0!<br>
><br>
> Item was changed:<br>
>  ----- Method: TAssignmentNode>>bindVariablesIn: (in category 'transformations') -----<br>
>  bindVariablesIn: aDictionary<br>
> <br>
> +     self setVar: (variable bindVariablesIn: aDictionary)<br>
> +             exp: (expression bindVariablesIn: aDictionary)!<br>
> -     variable := variable bindVariablesIn: aDictionary.<br>
> -     expression := expression bindVariablesIn: aDictionary.!<br>
><br>
> Item was changed:<br>
>  ----- Method: TAssignmentNode>>isSameAs: (in category 'testing') -----<br>
>  isSameAs: aTParseNode<br>
> +     ^self == aTParseNode<br>
> +      or: [aTParseNode isAssignment<br>
> +              and: [(variable isSameAs: aTParseNode variable)<br>
> +              and: [expression isSameAs: aTParseNode expression]]]!<br>
> -     ^aTParseNode isAssignment<br>
> -      and: [(variable isSameAs: aTParseNode variable)<br>
> -      and: [expression isSameAs: aTParseNode expression]]!<br>
><br>
> Item was changed:<br>
>  ----- Method: TAssignmentNode>>postCopy (in category 'copying') -----<br>
>  postCopy<br>
> <br>
> +     self setVar: variable copy exp: expression copy!<br>
> -     variable := variable copy.<br>
> -     expression := expression copy!<br>
><br>
> Item was changed:<br>
>  ----- Method: TAssignmentNode>>replaceNodesIn: (in category 'transformations') -----<br>
>  replaceNodesIn: aDictionary<br>
> <br>
> +     ^aDictionary<br>
> +             at: self<br>
> +             ifAbsent:<br>
> +                     [self setVar: (variable replaceNodesIn: aDictionary)<br>
> +                             exp: (expression replaceNodesIn: aDictionary)]!<br>
> -     ^aDictionary at: self ifAbsent: [<br>
> -             variable := variable replaceNodesIn: aDictionary.<br>
> -             expression := expression replaceNodesIn: aDictionary.<br>
> -             self]!<br>
><br>
> Item was added:<br>
> + ----- Method: TAssignmentNode>>setVar:exp: (in category 'private') -----<br>
> + setVar: varNode exp: expressionNode<br>
> +     "This is a private setter, just for breakpointing..."<br>
> +     variable := varNode.<br>
> +     expression := expressionNode!<br>
><br>
> Item was changed:<br>
>  ----- Method: TConstantNode>>isSameAs: (in category 'comparing') -----<br>
>  isSameAs: aTParseNode<br>
> +     ^self == aTParseNode<br>
> +      or: [aTParseNode isConstant<br>
> +              and: [value class == aTParseNode value class<br>
> +              and: [value = aTParseNode value]]]!<br>
> -     ^aTParseNode isConstant<br>
> -      and: [value class == aTParseNode value class<br>
> -      and: [value = aTParseNode value]]!<br>
><br>
> Item was changed:<br>
>  ----- Method: TDefineNode>>isSameAs: (in category 'comparing') -----<br>
>  isSameAs: aTParseNode<br>
> +     ^self == aTParseNode<br>
> +      or: [self class == aTParseNode class<br>
> +               and: [value class == aTParseNode value class<br>
> +               and: [value = aTParseNode value<br>
> +               and: [name = aTParseNode nameOrValue]]]]!<br>
> -     ^self class == aTParseNode class<br>
> -       and: [value class == aTParseNode value class<br>
> -       and: [value = aTParseNode value<br>
> -       and: [name = aTParseNode nameOrValue]]]!<br>
><br>
> Item was changed:<br>
>  ----- Method: TMethod>>deny: (in category 'error handling') -----<br>
>  deny: aBooleanOrBlock<br>
> -     <doNotGenerate><br>
>       aBooleanOrBlock value ifTrue: [AssertionFailure signal: 'Assertion failed']!<br>
><br>
> Item was changed:<br>
>  ----- Method: TMethod>>inlineFunctionCall:in: (in category 'inlining') -----<br>
>  inlineFunctionCall: aSendNode in: aCodeGen<br>
>       "Answer the body of the called function, substituting the actual<br>
>        parameters for the formal argument variables in the method body.<br>
>        Assume caller has established that:<br>
>               1. the method arguments are all substitutable nodes, and<br>
>               2. the method to be inlined contains no additional embedded returns."<br>
><br>
>       | sel meth doNotRename argsForInlining substitutionDict |<br>
> +     aCodeGen maybeBreakForInlineOf: aSendNode in: self.<br>
>       sel := aSendNode selector.<br>
>       meth := (aCodeGen methodNamed: sel) copy.<br>
>       meth ifNil:<br>
>               [^self inlineBuiltin: aSendNode in: aCodeGen].<br>
>       doNotRename := Set withAll: args.<br>
>       argsForInlining := aSendNode argumentsForInliningCodeGenerator: aCodeGen.<br>
>       meth args with: argsForInlining do:<br>
>               [ :argName :exprNode |<br>
>               exprNode isLeaf ifTrue:<br>
>                       [doNotRename add: argName]].<br>
>       (meth statements size = 2<br>
>       and: [meth statements first isSend<br>
>       and: [meth statements first selector == #flag:]]) ifTrue:<br>
>               [meth statements removeFirst].<br>
>       meth renameVarsForInliningInto: self except: doNotRename in: aCodeGen.<br>
>       meth renameLabelsForInliningInto: self.<br>
>       self addVarsDeclarationsAndLabelsOf: meth except: doNotRename.<br>
>       substitutionDict := Dictionary new: meth args size * 2.<br>
>       meth args with: argsForInlining do:<br>
>               [ :argName :exprNode |<br>
> +             (exprNode isVariable and: [exprNode name = argName]) ifFalse:<br>
> +                     [substitutionDict at: argName put: exprNode].<br>
> -             substitutionDict at: argName put: exprNode.<br>
>               (doNotRename includes: argName) ifFalse:<br>
>                       [locals remove: argName]].<br>
>       meth parseTree bindVariablesIn: substitutionDict.<br>
>       ^meth parseTree endsWithReturn<br>
>               ifTrue: [meth parseTree copyWithoutReturn]<br>
>               ifFalse: [meth parseTree]!<br>
><br>
> Item was added:<br>
> + ----- Method: TParseNode>>deny: (in category 'as yet unclassified') -----<br>
> + deny: aBooleanOrBlock<br>
> +     aBooleanOrBlock value ifTrue: [AssertionFailure signal: 'Assertion failed']!<br>
><br>
> Item was changed:<br>
>  ----- Method: TParseNode>>isSameAs: (in category 'comparing') -----<br>
>  isSameAs: aTParseNode<br>
>       "Answer if the ParseTree rooted at this node is the same as aTParseNode.<br>
>        By default answer false and have subclasses override as appropriate."<br>
> +     ^self == aTParseNode!<br>
> -     ^false!<br>
><br>
> Item was added:<br>
> + ----- Method: TReturnNode>>isSameAs: (in category 'comparing') -----<br>
> + isSameAs: aTParseNode<br>
> +     ^self == aTParseNode<br>
> +      or: [aTParseNode isReturn<br>
> +              and: [expression isSameAs: aTParseNode expression]]!<br>
><br>
> Item was changed:<br>
>  ----- Method: TSendNode>>isSameAs: (in category 'comparing') -----<br>
>  isSameAs: aTParseNode<br>
> +     self == aTParseNode ifTrue: [^true].<br>
>       (aTParseNode isSend<br>
>        and: [selector == aTParseNode selector<br>
>        and: [receiver isSameAs: aTParseNode receiver]]) ifFalse:<br>
>               [^false].<br>
>       arguments with: aTParseNode args do:<br>
>               [:a :b|<br>
>               (a isSameAs: b) ifFalse:<br>
>                       [^false]].<br>
>       ^true!<br>
><br>
> Item was changed:<br>
>  ----- Method: TStmtListNode>>bindVariablesIn: (in category 'transformations') -----<br>
>  bindVariablesIn: aDictionary<br>
> <br>
> +     aDictionary notEmpty ifTrue:<br>
> +             [statements := statements collect: [:s| s bindVariablesIn: aDictionary]]!<br>
> -     statements := statements collect: [ :s | s bindVariablesIn: aDictionary ].!<br>
><br>
> Item was changed:<br>
>  ----- Method: TStmtListNode>>isSameAs: (in category 'testing') -----<br>
>  isSameAs: aTParseNode<br>
> +     self == aTParseNode ifTrue: [^true].<br>
>       (aTParseNode isStmtList<br>
>        and: [statements size = aTParseNode statements size]) ifFalse:<br>
>               [^false].<br>
>       statements with: aTParseNode statements do:<br>
>               [:mine :theirs|<br>
>                (mine isSameAs: theirs) ifFalse:<br>
>                       [^false]].<br>
>       ^true!<br>
><br>
> Item was changed:<br>
>  ----- Method: TVariableNode>>isSameAs: (in category 'comparing') -----<br>
>  isSameAs: aTParseNode<br>
> +     ^self == aTParseNode<br>
> +      or: [aTParseNode isVariable<br>
> +              and: [name = aTParseNode name]]!<br>
> -     ^aTParseNode isVariable<br>
> -      and: [name = aTParseNode name]!<br>
><br>
> Item was changed:<br>
> + ----- Method: ThreadedFFIPlugin>>canReturnInRegistersStructOfSize: (in category 'marshalling-struct') -----<br>
> - ----- Method: ThreadedFFIPlugin>>canReturnInRegistersStructOfSize: (in category 'marshalling') -----<br>
>  canReturnInRegistersStructOfSize: returnStructSize<br>
>       "Answer if a struct result of a given size can be returned via registers or not.<br>
>       Size is a necessary condition, but it might not be a sufficient condition.<br>
>       For example, SysV X64 also require that struct fields be properly aligned."<br>
>       ^self subclassResponsibility!<br>
><br>
> Item was changed:<br>
> + ----- Method: ThreadedFFIPlugin>>ffiPushSignedLongLongOop:in: (in category 'marshalling') -----<br>
> - ----- Method: ThreadedFFIPlugin>>ffiPushSignedLongLongOop:in: (in category 'callout support') -----<br>
>  ffiPushSignedLongLongOop: oop in: calloutState<br>
>       <var: #calloutState type: #'CalloutState *'><br>
>       "Push a longlong type (e.g., a 64bit integer).<br>
>       Note: Coercions from float are *not* supported."<br>
>       | value |<br>
>       <var: #value type: #sqLong><br>
>       (oop = interpreterProxy nilObject<br>
>        or: [oop = interpreterProxy falseObject])<br>
>               ifTrue:[value := 0] ifFalse:<br>
>       [oop = interpreterProxy trueObject<br>
>               ifTrue:[value := 1] ifFalse:<br>
>       [value := interpreterProxy signed64BitValueOf: oop.<br>
>        interpreterProxy failed ifTrue:<br>
>               [^FFIErrorCoercionFailed]]].<br>
>       ^self ffiPushSignedLongLong: value in: calloutState!<br>
><br>
> Item was changed:<br>
> + ----- Method: ThreadedFFIPlugin>>ffiPushStructure:ofSize:typeSpec:ofLength:in: (in category 'marshalling-struct') -----<br>
> - ----- Method: ThreadedFFIPlugin>>ffiPushStructure:ofSize:typeSpec:ofLength:in: (in category 'marshalling') -----<br>
>  ffiPushStructure: pointer ofSize: structSize typeSpec: argSpec ofLength: argSpecSize in: calloutState<br>
>       <var: #pointer type: #'void *'><br>
>       <var: #argSpec type: #'sqInt *'><br>
>       <var: #calloutState type: #'CalloutState *'><br>
>       <inline: true><br>
>       self subclassResponsibility!<br>
><br>
> Item was changed:<br>
> + ----- Method: ThreadedFFIPlugin>>ffiPushStructureContentsOf:in: (in category 'marshalling-struct') -----<br>
> - ----- Method: ThreadedFFIPlugin>>ffiPushStructureContentsOf:in: (in category 'callout support') -----<br>
>  ffiPushStructureContentsOf: oop in: calloutState<br>
>       <var: #calloutState type: #'CalloutState *'><br>
>       "Push the contents of the given external structure"<br>
>       | ptrClass ptrAddress |<br>
>       <inline: true><br>
>       ptrClass := interpreterProxy fetchClassOf: oop.<br>
>       ptrClass = interpreterProxy classExternalAddress ifTrue: "ExternalAddress is bytes"<br>
>               [ptrAddress := (interpreterProxy fetchPointer: 0 ofObject: oop) asVoidPointer.<br>
>               "There is no way we can make sure the structure is valid.<br>
>               But we can at least check for attempts to pass pointers to ST memory."<br>
>               (interpreterProxy isInMemory: ptrAddress) ifTrue:<br>
>                       [^FFIErrorInvalidPointer].<br>
>               ^self ffiPushStructure: ptrAddress<br>
>                       ofSize: (calloutState ffiArgHeader bitAnd: FFIStructSizeMask)<br>
>                       typeSpec: calloutState ffiArgSpec<br>
>                       ofLength: calloutState ffiArgSpecSize<br>
>                       in: calloutState].<br>
>       ptrClass = interpreterProxy classByteArray ifTrue:<br>
>               ["The following is a somewhat pessimistic test but I like being sure..."<br>
>               (interpreterProxy byteSizeOf: oop) = (calloutState ffiArgHeader bitAnd: FFIStructSizeMask)<br>
>                       ifFalse:[^FFIErrorStructSize].<br>
>               ptrAddress := interpreterProxy firstIndexableField: oop.<br>
>               (calloutState ffiArgHeader anyMask: FFIFlagPointer) ifFalse:<br>
>                       "Since this involves passing the address of the first indexable field we need to fail<br>
>                         the call if it is threaded and the object is young, since it may move during the call."<br>
>                       [self cppIf: COGMTVM ifTrue:<br>
>                        [((calloutState callFlags anyMask: FFICallFlagThreaded)<br>
>                        and: [interpreterProxy isYoung: oop]) ifTrue:<br>
>                               [^PrimErrObjectMayMove negated]].<br>
>                       ^self ffiPushStructure: ptrAddress<br>
>                               ofSize: (calloutState ffiArgHeader bitAnd: FFIStructSizeMask)<br>
>                               typeSpec: calloutState ffiArgSpec<br>
>                               ofLength: calloutState ffiArgSpecSize<br>
>                               in: calloutState].<br>
>               "If FFIFlagPointer + FFIFlagStructure is set use ffiPushPointer on the contents"<br>
>               (calloutState ffiArgHeader bitAnd: FFIStructSizeMask) = BytesPerWord ifFalse:<br>
>                       [^FFIErrorStructSize].<br>
>               ptrAddress := (interpreterProxy fetchPointer: 0 ofObject: oop) asVoidPointer.<br>
>               (interpreterProxy isInMemory: ptrAddress) ifTrue:<br>
>                       [^FFIErrorInvalidPointer].<br>
>               ^self ffiPushPointer: ptrAddress in: calloutState].<br>
>       ^FFIErrorBadArg!<br>
><br>
> Item was changed:<br>
> + ----- Method: ThreadedFFIPlugin>>ffiPushUnsignedLongLongOop:in: (in category 'marshalling') -----<br>
> - ----- Method: ThreadedFFIPlugin>>ffiPushUnsignedLongLongOop:in: (in category 'callout support') -----<br>
>  ffiPushUnsignedLongLongOop: oop in: calloutState<br>
>       <var: #calloutState type: #'CalloutState *'><br>
>       "Push an unsigned longlong type (e.g., a 64bit integer).<br>
>       Note: Coercions from float are *not* supported."<br>
>       | value |<br>
>       <var: #value type: #usqLong><br>
>       (oop = interpreterProxy nilObject<br>
>        or: [oop = interpreterProxy falseObject])<br>
>               ifTrue:[value := 0] ifFalse:<br>
>       [oop = interpreterProxy trueObject<br>
>               ifTrue:[value := 1] ifFalse:<br>
>       [value := interpreterProxy positive64BitValueOf: oop.<br>
>        interpreterProxy failed ifTrue:<br>
>               [^FFIErrorCoercionFailed]]].<br>
>       ^self ffiPushUnsignedLongLong: value in: calloutState!<br>
><br>
> Item was changed:<br>
> + ----- Method: ThreadedFFIPlugin>>ffiPushVoid:in: (in category 'marshalling') -----<br>
> - ----- Method: ThreadedFFIPlugin>>ffiPushVoid:in: (in category 'callout support') -----<br>
>  ffiPushVoid: ignored in: calloutState<br>
>       <var: #calloutState type: #'CalloutState *'><br>
>       "This is a fallback in case somebody tries to pass a 'void' value.<br>
>       We could simply ignore the argument but I think it's better to let<br>
>       the caller know what he did"<br>
>       ^FFIErrorAttemptToPassVoid!<br>
><br>
> Item was changed:<br>
> + ----- Method: ThreadedFFIPlugin>>nonRegisterStructReturnIsViaImplicitFirstArgument (in category 'marshalling-struct') -----<br>
> - ----- Method: ThreadedFFIPlugin>>nonRegisterStructReturnIsViaImplicitFirstArgument (in category 'marshalling') -----<br>
>  nonRegisterStructReturnIsViaImplicitFirstArgument<br>
>       "Answer if a struct returned in memory is returned to the<br>
>        referent of a pointer passed as an implciit first argument.<br>
>        It almost always is.  Subclasses can override if not."<br>
>       ^true!<br>
><br>
> Item was changed:<br>
> + ----- Method: ThreadedFFIPlugin>>returnStructInRegisters: (in category 'marshalling-struct') -----<br>
> - ----- Method: ThreadedFFIPlugin>>returnStructInRegisters: (in category 'marshalling') -----<br>
>  returnStructInRegisters: calloutState<br>
>       "Answer if struct result is returned in registers or not.<br>
>       Use the OS specific encoding stored in structReturnType.<br>
>       Since it is OS dependent, leave the responsibility to subclass"<br>
>       <var: #calloutState type: #'CalloutState *'><br>
>       ^self subclassResponsibility!<br>
><br>
> Item was changed:<br>
>  ----- Method: ThreadedX64SysVFFIPlugin>>registerType:ForUnionSpecs:OfLength:StartingAt:ByteOffset:EightbyteOffset: (in category 'marshalling') -----<br>
>  registerType: initialRegisterType ForUnionSpecs: specs OfLength: specSize StartingAt: indexPtr ByteOffset: byteOffset EightbyteOffset: eightbyteOffset<br>
>       "Answer with a number characterizing the register type for passing a union of size <= 16 bytes.<br>
>       On input, the index points to the structure header (the one with FFIFlagStructure + structSize)<br>
>       On output, the index points to the structure trailer (the FFIFlagStructure)."<br>
><br>
>       <var: #specs type: #'unsigned int*'><br>
>       <var: #indexPtr type: #'unsigned int*'><br>
> -     <var: #subIndex type: #'unsigned int'><br>
>       <inline: false><br>
>       | registerType spec atomic isInt recurse subLevel |<br>
>       registerType := initialRegisterType.<br>
>       [indexPtr at: 0 put: (indexPtr at: 0) + 1.<br>
>       subLevel := 0.<br>
>       (indexPtr at: 0) < specSize]<br>
>               whileTrue:<br>
>                       [spec := specs at: (indexPtr at: 0).<br>
>                       isInt := false.<br>
>                       recurse := false.<br>
>                       spec = FFIFlagStructure "this marks end of structure/union"<br>
>                               ifTrue:<br>
>                                       [subLevel = 0 ifTrue: [^registerType].<br>
>                                       subLevel := subLevel - 1]<br>
>                               ifFalse:<br>
>                                       [(spec anyMask: FFIFlagPointer)<br>
>                                               ifTrue:<br>
>                                                       [isInt := true]<br>
>                                               ifFalse:<br>
>                                                       [(spec bitAnd: FFIFlagStructure + FFIFlagAtomic)<br>
>                                                               caseOf:<br>
>                                                                       {[FFIFlagStructure] -><br>
>                                                                               [recurse := (self isUnionSpec: specs OfLength: specSize StartingAt: (indexPtr at: 0))not.<br>
>                                                                               recurse ifFalse: [subLevel := subLevel + 1]].<br>
>                                                                       [FFIFlagAtomic] -><br>
>                                                                               [atomic := self atomicTypeOf: spec.<br>
>                                                                               isInt := (atomic >> 1) ~= (FFITypeSingleFloat >> 1)]}<br>
>                                                               otherwise: ["invalid spec" ^-1]].<br>
>                                       isInt<br>
>                                               ifTrue:<br>
>                                                       ["If this eightbyte contains an int field, then we must use an int register"<br>
>                                                       registerType := registerType bitOr: 1 << eightbyteOffset].<br>
>                                       recurse ifTrue:<br>
>                                               ["struct in union require a recursive form, because we handle byteOffset/eightbyteOffset differently"<br>
>                                               registerType := self<br>
>                                                               registerType: registerType<br>
>                                                               ForStructSpecs: specs<br>
>                                                               OfLength: specSize<br>
>                                                               StartingAt: indexPtr<br>
>                                                               ByteOffset: byteOffset<br>
>                                                               EightbyteOffset: eightbyteOffset]]].<br>
>       self assert: subLevel = 0.<br>
>       ^registerType!<br>
><br>
> Item was changed:<br>
>  ----- Method: ThreadedX64SysVFFIPlugin>>registerTypeForStructSpecs:OfLength: (in category 'marshalling') -----<br>
>  registerTypeForStructSpecs: specs OfLength: specSize<br>
>       "Answer with a number characterizing the register type for passing a struct of size <= 16 bytes.<br>
>       The bit at offset i of registerType is set to 1 if eightbyte at offset i is a int register (RAX ...)<br>
>       The bit at offset 2 indicates if there is a single eightbyte (struct size <= 8)<br>
>       * 2r00 for float float (XMM0 XMM1)<br>
>       * 2r01 for int float (RAX XMM0)<br>
>       * 2r10 for float int (XMM0 RAX)<br>
>       * 2r11 for int int (RAX RDX)<br>
>       * 2r100 for float (XMM0)<br>
>       * 2r101 for int (RAX)<br>
>       * 2r110 INVALID (not aligned)<br>
>       Beware, the bits must be read from right to left for decoding register type.<br>
>       Note: this method reconstructs the struct layout according to X64 alignment rules.<br>
>       Therefore, it will not work for packed struct or other exotic alignment."<br>
><br>
>       <var: #specs type: #'unsigned int*'><br>
> -     <var: #subIndex type: #'unsigned int'><br>
>       <inline: false><br>
>       | index byteSize registerType |<br>
>       index := 0.<br>
>       byteSize := (specs at: index) bitAnd: FFIStructSizeMask.<br>
>       byteSize > 16 ifTrue: [^2r110].<br>
>       (self checkAlignmentOfStructSpec: specs OfLength: specSize StartingAt: index)<br>
>               ifFalse: [^2r110].<br>
>       registerType := byteSize <= 8 ifTrue: [2r100] ifFalse: [0].<br>
>       ^(self isUnionSpec: specs OfLength: specSize StartingAt: 0)<br>
>               ifTrue: [ self<br>
>                       registerType: registerType<br>
>                       ForUnionSpecs: specs<br>
>                       OfLength: specSize<br>
>                       StartingAt: (self addressOf: index)<br>
>                       ByteOffset: 0<br>
>                       EightbyteOffset: 0 ]<br>
>               ifFalse: [ self<br>
>                       registerType: registerType<br>
>                       ForStructSpecs: specs<br>
>                       OfLength: specSize<br>
>                       StartingAt: (self addressOf: index)<br>
>                       ByteOffset: 0<br>
>                       EightbyteOffset: 0 ]!<br>
><br>
> Item was changed:<br>
>  ----- Method: VMMaker class>>generateVMPlugins (in category 'configurations') -----<br>
>  generateVMPlugins<br>
>       ^VMMaker<br>
>               generatePluginsTo: self sourceTree, '/src'<br>
>               options: #()<br>
>               platformDir: self sourceTree, '/platforms'<br>
>               including:#(ADPCMCodecPlugin AsynchFilePlugin<br>
>                                       BalloonEnginePlugin B3DAcceleratorPlugin B3DEnginePlugin BMPReadWriterPlugin BitBltSimulation<br>
>                                       BochsIA32Plugin BochsX64Plugin GdbARMv6Plugin GdbARMv8Plugin<br>
>                                       CameraPlugin CroquetPlugin DeflatePlugin DropPlugin<br>
> +                                     "Cryptography Plugins:" DESPlugin DSAPlugin MD5Plugin<br>
> -                                     "Cryptography Plugins:" DESPlugin DSAPlugin MD5Plugin SHA256Plugin<br>
>                                       "FT2Plugin" FFTPlugin FileCopyPlugin FilePlugin FileAttributesPlugin Float64ArrayPlugin FloatArrayPlugin FloatMathPlugin<br>
>                                       GeniePlugin HostWindowPlugin IA32ABIPlugin ImmX11Plugin InternetConfigPlugin<br>
>                                       JPEGReadWriter2Plugin JPEGReaderPlugin JoystickTabletPlugin KlattSynthesizerPlugin<br>
>                                       LargeIntegersPlugin LocalePlugin MIDIPlugin MacMenubarPlugin Matrix2x3Plugin<br>
>                                       MiscPrimitivePlugin Mpeg3Plugin QuicktimePlugin RePlugin<br>
>                                       ScratchPlugin SecurityPlugin SerialPlugin SocketPlugin<br>
>                                       SoundCodecPlugin SoundGenerationPlugin SoundPlugin SqueakSSLPlugin StarSqueakPlugin<br>
>                                       ThreadedFFIPlugin ThreadedARM32FFIPlugin ThreadedARM64FFIPlugin ThreadedIA32FFIPlugin<br>
>                                       ThreadedX64SysVFFIPlugin ThreadedX64Win64FFIPlugin<br>
>                                       UnicodePlugin UnixAioPlugin UUIDPlugin UnixOSProcessPlugin<br>
>                                       Win32OSProcessPlugin VMProfileLinuxSupportPlugin VMProfileMacSupportPlugin WeDoPlugin<br>
>                                       XDisplayControlPlugin)!<br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div>