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