[Vm-dev] VM Maker: VMMaker.oscog-eem.1878.mcz

Ben Coman btc at openinworld.com
Thu Jun 2 13:14:47 UTC 2016


On Thu, Jun 2, 2016 at 5:38 PM, Eliot Miranda <eliot.miranda at gmail.com> wrote:
>
> Ben,
>
>> On Jun 1, 2016, at 10:35 PM, Ben Coman <btc at openinworld.com> wrote:
>>
>>
>>> On Thu, Jun 2, 2016 at 8:57 AM,  <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.1878.mcz
>>>
>>> ==================== Summary ====================
>>>
>>> Name: VMMaker.oscog-eem.1878
>>> Author: eem
>>> Time: 1 June 2016, 5:56:53.625028 pm
>>> UUID: 71f5bdb3-74c3-4a8c-bbb9-c78c327e4823
>>> Ancestors: VMMaker.oscog-eem.1877
>>>
>>> Check for allocation failure in the LargeIntegersPlugin and fail primitives when space runs out.
>>>
>>> This is clearly unsatisfactory;. the ciode fails to slow Smalltalk code.  We'd like to run the GC but Spur's style is not to GC in primitives.
>>
>> Hi Eliot,
>>
>> Does "not to GC *in* primitives" mean from the Image's or VM's perspective?
>>
>> Naively I wonder if your approach to primitives failing due to forwarders
>> would apply here.  If the primitive runs out of space, set a flag
>> before failing,
>> and at the same point you test and resolve forwarders, then retry the primitive,
>> you could check for this flag, run a GC (outside of the primitive from
>> the VM's perspective?),
>> then retry the primitive ??
>
> that...is an excellent idea! Beautiful and very easy to implement.  The primitive error code can be tested and if it is PrimErrNoMemory the check-for-failure handler can run the GC before retrying.  I shall implement this tomorrow.  Thanks /very/ much.

Call it payback for time invested in my newbie VM questions :) :)
Yes, open source is cool! Many eyeballs and all that jazz.

cheers -ben

>
>> cheers -ben
>>
>>> If we change the plugin to do GC in primitives we lose the speed advantage of the no-GC style of code.  One approach might be to estimate the memory needed as early as possible, and run a GC if not enough memory is available for the result, recomputing base pointers if GC is run.  This would avoid the awful remapOop:in: style whioch is pessimistic; it puts things in a stack and takes them back out whether a GC is needed or not.  We shoudl use an optimistic algorithm; especially for something as performance sensitive as large integer arithmetic.
>>>
>>> =============== Diff against VMMaker.oscog-eem.1877 ===============
>>>
>>> Item was changed:
>>>  ----- Method: LargeIntegersPlugin>>digit:Lshift: (in category 'oop functions') -----
>>>  digit: anOop Lshift: shiftCount
>>>        "Attention: this method invalidates all oop's!! Only newOop is valid at return."
>>>        "Does not normalize."
>>>        | newOop highBit newDigitLen newByteLen oldDigitLen |
>>>        oldDigitLen := self digitSizeOfLargeInt: anOop.
>>>        (highBit := self cDigitHighBit: (self pointerToFirstDigitOfLargeInt: anOop)
>>>                                len: oldDigitLen) = 0 ifTrue: [^  interpreterProxy instantiateClass: (interpreterProxy fetchClassOf: anOop) indexableSize: 1].
>>>        newByteLen := highBit + shiftCount + 7 // 8.
>>> +       self remapOop: anOop in:
>>> +               [newOop := interpreterProxy
>>> +                                               instantiateClass: (interpreterProxy fetchClassOf: anOop)
>>> +                                               indexableSize: newByteLen].
>>> +       newOop ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory].
>>> -       self remapOop: anOop in: [newOop := interpreterProxy instantiateClass: (interpreterProxy fetchClassOf: anOop)
>>> -                                       indexableSize: newByteLen].
>>>        newDigitLen := newByteLen + 3 // 4.
>>>        self
>>>                cDigitLshift: shiftCount
>>>                from: (self pointerToFirstDigitOfLargeInt: anOop)
>>>                len: oldDigitLen
>>>                to: (self pointerToFirstDigitOfLargeInt: newOop)
>>>                len: newDigitLen.
>>>        ^ newOop!
>>>
>>> Item was changed:
>>>  ----- Method: LargeIntegersPlugin>>digit:Rshift:lookfirst: (in category 'oop functions') -----
>>>  digit: anOop Rshift: shiftCount lookfirst: a
>>>        "Attention: this method invalidates all oop's!! Only newBytes is valid at return."
>>>        "Shift right 32*digitShift+bitShift bits, 0<=bitShift<32.
>>>        Discard all digits beyond a, and all zeroes at or below a."
>>>        "Does not normalize."
>>>        | newByteLen newOop oldBitLen newBitLen oldDigitLen newDigitLen |
>>>        oldBitLen := self cDigitHighBit: (self pointerToFirstDigitOfLargeInt: anOop) len: a.
>>>        oldDigitLen := oldBitLen + 31 // 32.
>>>        newBitLen := oldBitLen - shiftCount.
>>>        newBitLen <= 0 ifTrue: ["All bits lost"
>>>                ^ interpreterProxy
>>>                        instantiateClass: (interpreterProxy fetchClassOf: anOop)
>>>                        indexableSize: 0].
>>>        newByteLen := newBitLen + 7 // 8.
>>>        newDigitLen := newByteLen + 3 // 4.
>>> +       self remapOop: anOop in:
>>> +               [newOop := interpreterProxy
>>> +                                               instantiateClass: (interpreterProxy fetchClassOf: anOop)
>>> +                                               indexableSize: newByteLen].
>>> +       newOop ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory].
>>> -       self remapOop: anOop in: [newOop := interpreterProxy instantiateClass: (interpreterProxy fetchClassOf: anOop)
>>> -                                       indexableSize: newByteLen].
>>>        self
>>>                cDigitRshift: shiftCount
>>>                from: (self pointerToFirstDigitOfLargeInt: anOop)
>>>                len: oldDigitLen
>>>                to: (self pointerToFirstDigitOfLargeInt: newOop)
>>>                len: newDigitLen.
>>>        ^ newOop!
>>>
>>> Item was changed:
>>>  ----- Method: LargeIntegersPlugin>>digitAddLarge:with: (in category 'oop functions') -----
>>>  digitAddLarge: firstInteger with: secondInteger
>>>        "Does not need to normalize!!"
>>>        | over firstDigitLen secondDigitLen shortInt shortDigitLen longInt longDigitLen sum newSum neg |
>>>        <var: #over type: #'unsigned int'>
>>>        firstDigitLen := self digitSizeOfLargeInt: firstInteger.
>>>        secondDigitLen := self digitSizeOfLargeInt: secondInteger.
>>>        neg := interpreterProxy isLargeNegativeIntegerObject: firstInteger.
>>>        firstDigitLen <= secondDigitLen
>>>                ifTrue:
>>>                        [shortInt := firstInteger.
>>>                        shortDigitLen := firstDigitLen.
>>>                        longInt := secondInteger.
>>>                        longDigitLen := secondDigitLen]
>>>                ifFalse:
>>>                        [shortInt := secondInteger.
>>>                        shortDigitLen := secondDigitLen.
>>>                        longInt := firstInteger.
>>>                        longDigitLen := firstDigitLen].
>>>        "       sum := Integer new: len neg: firstInteger negative."
>>>        self remapOop: #(shortInt longInt ) in: [sum := self createLargeIntegerNeg: neg digitLength: longDigitLen].
>>> +       sum ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory].
>>>        over := self
>>>                                cDigitAdd: (self pointerToFirstDigitOfLargeInt: shortInt)
>>>                                len: shortDigitLen
>>>                                with: (self pointerToFirstDigitOfLargeInt: longInt)
>>>                                len: longDigitLen
>>>                                into: (self pointerToFirstDigitOfLargeInt: sum).
>>>        over > 0
>>>                ifTrue:
>>>                        ["sum := sum growby: 1."
>>>                        self remapOop: sum in: [newSum := self createLargeIntegerNeg: neg byteLength: longDigitLen * 4 + 1].
>>> +                       newSum ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory].
>>>                        self
>>>                                cDigitCopyFrom: (self pointerToFirstDigitOfLargeInt: sum)
>>>                                to: (self pointerToFirstDigitOfLargeInt: newSum)
>>>                                len: longDigitLen.
>>>                        sum := newSum.
>>>                        "C index!!"
>>>                        self cDigitOf: (self pointerToFirstDigitOfLargeInt: sum)
>>>                                at: longDigitLen put: over]
>>>                ifFalse:
>>>                        [sum := neg
>>>                                ifTrue: [self normalizeNegative: sum]
>>>                                ifFalse: [self normalizePositive: sum]].
>>>        ^ sum!
>>>
>>> Item was changed:
>>>  ----- Method: LargeIntegersPlugin>>digitBitLogic:with:opIndex: (in category 'oop functions') -----
>>>  digitBitLogic: firstInteger with: secondInteger opIndex: opIx
>>>        "Bit logic here is only implemented for positive integers or Zero;
>>>        if rec or arg is negative, it fails."
>>>        | firstLarge secondLarge firstLen secondLen shortLen shortLarge longLen longLarge result |
>>>        (interpreterProxy isIntegerObject: firstInteger)
>>>                ifTrue:
>>> +                       [(interpreterProxy integerValueOf: firstInteger) < 0 ifTrue:
>>> +                               [^ interpreterProxy primitiveFail].
>>> -                       [(interpreterProxy integerValueOf: firstInteger)
>>> -                               < 0 ifTrue: [^ interpreterProxy primitiveFail].
>>>                        "convert it to a not normalized LargeInteger"
>>>                        self remapOop: secondInteger in: [firstLarge := self createLargeFromSmallInteger: firstInteger]]
>>>                ifFalse:
>>>                        [(interpreterProxy isLargePositiveIntegerObject: firstInteger) ifFalse: [^ interpreterProxy primitiveFail].
>>>                        firstLarge := firstInteger].
>>>        (interpreterProxy isIntegerObject: secondInteger)
>>>                ifTrue:
>>> +                       [(interpreterProxy integerValueOf: secondInteger) < 0 ifTrue:
>>> +                               [^ interpreterProxy primitiveFail].
>>> -                       [(interpreterProxy integerValueOf: secondInteger)
>>> -                               < 0 ifTrue: [^ interpreterProxy primitiveFail].
>>>                        "convert it to a not normalized LargeInteger"
>>>                        self remapOop: firstLarge in: [secondLarge := self createLargeFromSmallInteger: secondInteger]]
>>>                ifFalse:
>>>                        [(interpreterProxy isLargePositiveIntegerObject: secondInteger) ifFalse: [^ interpreterProxy primitiveFail].
>>>                        secondLarge := secondInteger].
>>>        firstLen := self byteSizeOfLargeInt: firstLarge.
>>>        secondLen := self byteSizeOfLargeInt: secondLarge.
>>>        firstLen < secondLen
>>>                ifTrue:
>>>                        [shortLen := firstLen.
>>>                        shortLarge := firstLarge.
>>>                        longLen := secondLen.
>>>                        longLarge := secondLarge]
>>>                ifFalse:
>>>                        [shortLen := secondLen.
>>>                        shortLarge := secondLarge.
>>>                        longLen := firstLen.
>>>                        longLarge := firstLarge].
>>> +       self remapOop: #(shortLarge longLarge) in:
>>> +               [result := interpreterProxy instantiateClass: interpreterProxy classLargePositiveInteger indexableSize: longLen].
>>> +       result ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory].
>>> -       self remapOop: #(shortLarge longLarge ) in: [result := interpreterProxy instantiateClass: interpreterProxy classLargePositiveInteger indexableSize: longLen].
>>>        self
>>>                cDigitOp: opIx
>>>                short: (self pointerToFirstDigitOfLargeInt: shortLarge)
>>>                len: shortLen + 3 // 4
>>>                long: (self pointerToFirstDigitOfLargeInt: longLarge)
>>>                len: longLen + 3 // 4
>>>                into: (self pointerToFirstDigitOfLargeInt: result).
>>>        interpreterProxy failed ifTrue: [^ 0].
>>> +       ^self normalizePositive: result!
>>> -       ^ self normalizePositive: result!
>>>
>>> Item was changed:
>>>  ----- Method: LargeIntegersPlugin>>digitMontgomery:times:modulo:mInvModB: (in category 'oop functions') -----
>>>  digitMontgomery: firstLarge times: secondLarge modulo: thirdLarge mInvModB: mInv
>>>        <var: #mInv type: #'unsigned int'>
>>>        | firstLen secondLen thirdLen prod |
>>>        firstLen := self digitSizeOfLargeInt: firstLarge.
>>>        secondLen := self digitSizeOfLargeInt: secondLarge.
>>>        thirdLen := self digitSizeOfLargeInt: thirdLarge.
>>>        (firstLen <= thirdLen and: [secondLen <= thirdLen]) ifFalse: [^interpreterProxy primitiveFail].
>>>
>>>        self remapOop: #(firstLarge secondLarge thirdLarge)
>>>                in: [prod := interpreterProxy instantiateClass: interpreterProxy classLargePositiveInteger indexableSize: thirdLen * 4].
>>> +       prod ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory].
>>>        self
>>>                cDigitMontgomery: (self pointerToFirstDigitOfLargeInt: firstLarge)
>>>                len: firstLen
>>>                times: (self pointerToFirstDigitOfLargeInt: secondLarge)
>>>                len: secondLen
>>>                modulo: (self pointerToFirstDigitOfLargeInt: thirdLarge)
>>>                len: thirdLen
>>>                mInvModB: mInv
>>>                into: (self pointerToFirstDigitOfLargeInt: prod).
>>>        ^self normalizePositive: prod!
>>>
>>> Item was changed:
>>>  ----- Method: LargeIntegersPlugin>>digitMultiplyLarge:with:negative: (in category 'oop functions') -----
>>>  digitMultiplyLarge: firstInteger with: secondInteger negative: neg
>>>        "Normalizes."
>>>        | firstLen secondLen shortInt shortLen longInt longLen prod |
>>>        firstLen := self byteSizeOfLargeInt: firstInteger.
>>>        secondLen := self byteSizeOfLargeInt: secondInteger.
>>>        firstLen <= secondLen
>>>                ifTrue:
>>>                        [shortInt := firstInteger.
>>>                        shortLen := firstLen.
>>>                        longInt := secondInteger.
>>>                        longLen := secondLen]
>>>                ifFalse:
>>>                        [shortInt := secondInteger.
>>>                        shortLen := secondLen.
>>>                        longInt := firstInteger.
>>>                        longLen := firstLen].
>>>        self remapOop: #(shortInt longInt) in: [prod := self createLargeIntegerNeg: neg byteLength: longLen + shortLen].
>>> +       prod ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory].
>>>        self
>>>                cDigitMultiply: (self pointerToFirstDigitOfLargeInt: shortInt)
>>>                len: shortLen + 3 // 4
>>>                with: (self pointerToFirstDigitOfLargeInt: longInt)
>>>                len: longLen + 3 // 4
>>>                into: (self pointerToFirstDigitOfLargeInt: prod)
>>>                len: longLen + shortLen + 3 // 4.
>>>        ^neg
>>>                ifTrue: [self normalizeNegative: prod]
>>>                ifFalse: [self normalizePositive: prod]!
>>>
>>> Item was changed:
>>>  ----- Method: LargeIntegersPlugin>>digitSubLarge:with: (in category 'oop functions') -----
>>>  digitSubLarge: firstInteger with: secondInteger
>>>        "Normalizes."
>>>        | firstDigitLen secondDigitLen larger largeDigitLen smaller smallerDigitLen neg resDigitLen res firstNeg |
>>>        firstNeg := interpreterProxy isLargeNegativeIntegerObject: firstInteger.
>>>        firstDigitLen := self digitSizeOfLargeInt: firstInteger.
>>>        secondDigitLen := self digitSizeOfLargeInt: secondInteger.
>>>        firstDigitLen = secondDigitLen ifTrue:
>>>                [[firstDigitLen > 1
>>>                  and: [(self unsafeDigitOfLargeInt: firstInteger at: firstDigitLen) = (self unsafeDigitOfLargeInt: secondInteger at: firstDigitLen)]]
>>>                        whileTrue: [firstDigitLen := firstDigitLen - 1].
>>>                secondDigitLen := firstDigitLen].
>>>        (firstDigitLen < secondDigitLen
>>>         or: [firstDigitLen = secondDigitLen
>>>                 and: [(self unsafeDigitOfLargeInt: firstInteger at: firstDigitLen) < (self unsafeDigitOfLargeInt: secondInteger at: firstDigitLen)]])
>>>                ifTrue:
>>>                        [larger := secondInteger.
>>>                        largeDigitLen := secondDigitLen.
>>>                        smaller := firstInteger.
>>>                        smallerDigitLen := firstDigitLen.
>>>                        neg := firstNeg == false]
>>>                ifFalse:
>>>                        [larger := firstInteger.
>>>                        largeDigitLen := firstDigitLen.
>>>                        smaller := secondInteger.
>>>                        smallerDigitLen := secondDigitLen.
>>>                        neg := firstNeg].
>>>        resDigitLen := largeDigitLen.
>>>        self remapOop: #(smaller larger)
>>>                in: [res := self createLargeIntegerNeg: neg digitLength: resDigitLen].
>>> +       res ifNil: [^interpreterProxy primitiveFailFor: PrimErrNoMemory].
>>>        self
>>>                cDigitSub: (self pointerToFirstDigitOfLargeInt: smaller)
>>>                len: smallerDigitLen
>>>                with: (self pointerToFirstDigitOfLargeInt: larger)
>>>                len: largeDigitLen
>>>                into: (self pointerToFirstDigitOfLargeInt: res).
>>>        ^neg
>>>                ifTrue: [self normalizeNegative: res]
>>>                ifFalse: [self normalizePositive: res]!
>>>


More information about the Vm-dev mailing list