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