[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