Spaces:
Running
Running
/* Smalltalk from Squeak4.5 with VMMaker 4.13.6 translated as JS source on 3 November 2014 1:52:21 pm */ | |
/* Automatically generated by | |
JSSmartSyntaxPluginCodeGenerator VMMakerJS-bf.15 uuid: fd4e10f2-3773-4e80-8bb5-c4b471a014e5 | |
from | |
LargeIntegersPlugin VMMaker-bf.353 uuid: 8ae25e7e-8d2c-451e-8277-598b30e9c002 | |
*/ | |
(function LargeIntegers() { | |
; | |
var VM_PROXY_MAJOR = 1; | |
var VM_PROXY_MINOR = 11; | |
/*** Functions ***/ | |
function CLASSOF(obj) { return typeof obj === "number" ? interpreterProxy.classSmallInteger() : obj.sqClass } | |
function SIZEOF(obj) { return obj.pointers ? obj.pointers.length : obj.words ? obj.words.length : obj.bytes ? obj.bytes.length : 0 } | |
function BYTESIZEOF(obj) { return obj.bytes ? obj.bytes.length : obj.words ? obj.words.length * 4 : 0 } | |
function DIV(a, b) { return Math.floor(a / b) | 0; } // integer division | |
function MOD(a, b) { return a - DIV(a, b) * b | 0; } // signed modulus | |
function SHL(a, b) { return b > 31 ? 0 : a << b; } // fix JS shift | |
function SHR(a, b) { return b > 31 ? 0 : a >>> b; } // fix JS shift | |
function SHIFT(a, b) { return b < 0 ? (b < -31 ? 0 : a >>> (0-b) ) : (b > 31 ? 0 : a << b); } | |
/*** Variables ***/ | |
var andOpIndex = 0; | |
var interpreterProxy = null; | |
var moduleName = "LargeIntegers v1.5 (e)"; | |
var orOpIndex = 1; | |
var xorOpIndex = 2; | |
/* Argument has to be aBytesOop! */ | |
/* Tests for any magnitude bits in the interval from start to stopArg. */ | |
function anyBitOfBytesfromto(aBytesOop, start, stopArg) { | |
var lastByteIx; | |
var digit; | |
var magnitude; | |
var leftShift; | |
var rightShift; | |
var firstByteIx; | |
var stop; | |
var mask; | |
var ix; | |
// missing DebugCode; | |
if ((start < 1) || (stopArg < 1)) { | |
return interpreterProxy.primitiveFail(); | |
} | |
magnitude = aBytesOop; | |
stop = Math.min(stopArg, highBitOfBytes(magnitude)); | |
if (start > stop) { | |
return false; | |
} | |
firstByteIx = ((start - 1) >> 3) + 1; | |
lastByteIx = ((stop - 1) >> 3) + 1; | |
rightShift = MOD((start - 1), 8); | |
leftShift = 7 - (MOD((stop - 1), 8)); | |
if (firstByteIx === lastByteIx) { | |
mask = (SHL(255, rightShift)) & (SHR(255, leftShift)); | |
digit = digitOfBytesat(magnitude, firstByteIx); | |
return (digit & mask) !== 0; | |
} | |
if ((SHR(digitOfBytesat(magnitude, firstByteIx), rightShift)) !== 0) { | |
return true; | |
} | |
for (ix = (firstByteIx + 1); ix <= (lastByteIx - 1); ix++) { | |
if (digitOfBytesat(magnitude, ix) !== 0) { | |
return true; | |
} | |
} | |
if (((SHL(digitOfBytesat(magnitude, lastByteIx), leftShift)) & 255) !== 0) { | |
return true; | |
} | |
return false; | |
} | |
/* Precondition: bytesOop is not anInteger and a bytes object. */ | |
/* Function #byteSizeOf: is used by the interpreter, be careful with name | |
clashes... */ | |
function byteSizeOfBytes(bytesOop) { | |
return SIZEOF(bytesOop); | |
} | |
/* Attention: this method invalidates all oop's! Only newBytes is valid at return. */ | |
/* Does not normalize. */ | |
function bytesgrowTo(aBytesObject, newLen) { | |
var oldLen; | |
var copyLen; | |
var newBytes; | |
newBytes = interpreterProxy.instantiateClassindexableSize(CLASSOF(aBytesObject), newLen); | |
; | |
oldLen = BYTESIZEOF(aBytesObject); | |
if (oldLen < newLen) { | |
copyLen = oldLen; | |
} else { | |
copyLen = newLen; | |
} | |
cDigitCopyFromtolen(aBytesObject.bytes, newBytes.bytes, copyLen); | |
return newBytes; | |
} | |
/* Attention: this method invalidates all oop's! Only newBytes is valid at return. */ | |
function bytesOrIntgrowTo(oop, len) { | |
var sq_class; | |
var val; | |
var newBytes; | |
if (typeof oop === "number") { | |
val = oop; | |
if (val < 0) { | |
sq_class = interpreterProxy.classLargeNegativeInteger(); | |
} else { | |
sq_class = interpreterProxy.classLargePositiveInteger(); | |
} | |
newBytes = interpreterProxy.instantiateClassindexableSize(sq_class, len); | |
cCopyIntValtoBytes(val, newBytes); | |
} else { | |
newBytes = bytesgrowTo(oop, len); | |
} | |
return newBytes; | |
} | |
function cCopyIntValtoBytes(val, bytes) { | |
var pByte; | |
var ix; | |
var ixLimiT; | |
pByte = bytes.bytes; | |
for (ix = 1, ixLimiT = cDigitLengthOfCSI(val); ix <= ixLimiT; ix++) { | |
pByte[ix - 1] = cDigitOfCSIat(val, ix); | |
} | |
} | |
/* pByteRes len = longLen; returns over.. */ | |
function cDigitAddlenwithleninto(pByteShort, shortLen, pByteLong, longLen, pByteRes) { | |
var i; | |
var limit; | |
var accum; | |
accum = 0; | |
limit = shortLen - 1; | |
for (i = 0; i <= limit; i++) { | |
accum = ((accum >>> 8) + pByteShort[i]) + pByteLong[i]; | |
pByteRes[i] = (accum & 255); | |
} | |
limit = longLen - 1; | |
for (i = shortLen; i <= limit; i++) { | |
accum = (accum >>> 8) + pByteLong[i]; | |
pByteRes[i] = (accum & 255); | |
} | |
return accum >>> 8; | |
} | |
/* Precondition: pFirst len = pSecond len. */ | |
function cDigitComparewithlen(pFirst, pSecond, len) { | |
var firstDigit; | |
var secondDigit; | |
var ix; | |
ix = len - 1; | |
while (ix >= 0) { | |
if (((secondDigit = pSecond[ix])) !== ((firstDigit = pFirst[ix]))) { | |
if (secondDigit < firstDigit) { | |
return 1; | |
} else { | |
return -1; | |
} | |
} | |
--ix; | |
} | |
return 0; | |
} | |
function cDigitCopyFromtolen(pFrom, pTo, len) { | |
var limit; | |
var i; | |
; | |
limit = len - 1; | |
for (i = 0; i <= limit; i++) { | |
pTo[i] = pFrom[i]; | |
} | |
return 0; | |
} | |
function cDigitDivlenremlenquolen(pDiv, divLen, pRem, remLen, pQuo, quoLen) { | |
var b; | |
var q; | |
var a; | |
var dnh; | |
var lo; | |
var hi; | |
var r3; | |
var mul; | |
var cond; | |
var l; | |
var k; | |
var j; | |
var i; | |
var dl; | |
var ql; | |
var r1r2; | |
var dh; | |
var t; | |
/* Last actual byte of data (ST ix) */ | |
dl = divLen - 1; | |
ql = quoLen; | |
dh = pDiv[dl - 1]; | |
if (dl === 1) { | |
dnh = 0; | |
} else { | |
dnh = pDiv[dl - 2]; | |
} | |
for (k = 1; k <= ql; k++) { | |
/* maintain quo*arg+rem=self */ | |
/* Estimate rem/div by dividing the leading two digits of rem by dh. */ | |
/* The estimate is q = qhi*16r100+qlo, where qhi and qlo are unsigned char. */ | |
/* r1 := rem digitAt: j. */ | |
j = (remLen + 1) - k; | |
if (pRem[j - 1] === dh) { | |
q = 255; | |
} else { | |
/* Compute q = (r1,r2)//dh, t = (r1,r2)\\dh. */ | |
/* r2 := (rem digitAt: j - 2). */ | |
r1r2 = pRem[j - 1]; | |
r1r2 = (r1r2 << 8) + pRem[j - 2]; | |
t = MOD(r1r2, dh); | |
/* Next compute (hi,lo) := q*dnh */ | |
q = DIV(r1r2, dh); | |
mul = q * dnh; | |
hi = mul >>> 8; | |
/* Correct overestimate of q. | |
Max of 2 iterations through loop -- see Knuth vol. 2 */ | |
lo = mul & 255; | |
if (j < 3) { | |
r3 = 0; | |
} else { | |
r3 = pRem[j - 3]; | |
} | |
while (true) { | |
if ((t < hi) || ((t === hi) && (r3 < lo))) { | |
/* i.e. (t,r3) < (hi,lo) */ | |
--q; | |
if (lo < dnh) { | |
--hi; | |
lo = (lo + 256) - dnh; | |
} else { | |
lo -= dnh; | |
} | |
cond = hi >= dh; | |
} else { | |
cond = false; | |
} | |
if (!(cond)) break; | |
hi -= dh; | |
} | |
} | |
l = j - dl; | |
a = 0; | |
for (i = 1; i <= divLen; i++) { | |
hi = pDiv[i - 1] * (q >>> 8); | |
lo = pDiv[i - 1] * (q & 255); | |
b = (pRem[l - 1] - a) - (lo & 255); | |
pRem[l - 1] = (b & 255); | |
/* This is a possible replacement to simulate arithmetic shift (preserving sign of b) */ | |
/* b := b >> 8 bitOr: (0 - (b >> ((interpreterProxy sizeof: b)*8 */ | |
/* CHAR_BIT */ | |
/* -1)) << 8). */ | |
b = b >> 8; | |
a = (hi + (lo >>> 8)) - b; | |
++l; | |
} | |
if (a > 0) { | |
/* Add div back into rem, decrease q by 1 */ | |
--q; | |
l = j - dl; | |
a = 0; | |
for (i = 1; i <= divLen; i++) { | |
a = ((a >>> 8) + pRem[l - 1]) + pDiv[i - 1]; | |
pRem[l - 1] = (a & 255); | |
++l; | |
} | |
} | |
pQuo[quoLen - k] = q; | |
} | |
return 0; | |
} | |
/* Answer the index (in bits) of the high order bit of the receiver, or zero if the | |
receiver is zero. This method is allowed (and needed) for | |
LargeNegativeIntegers as well, since Squeak's LargeIntegers are | |
sign/magnitude. */ | |
function cDigitHighBitlen(pByte, len) { | |
var lastDigit; | |
var realLength; | |
realLength = len; | |
while (((lastDigit = pByte[realLength - 1])) === 0) { | |
if (((--realLength)) === 0) { | |
return 0; | |
} | |
} | |
return cHighBit(lastDigit) + (8 * (realLength - 1)); | |
} | |
/* Answer the number of indexable fields of a CSmallInteger. This value is | |
the same as the largest legal subscript. */ | |
function cDigitLengthOfCSI(csi) { | |
if ((csi < 256) && (csi > -256)) { | |
return 1; | |
} | |
if ((csi < 65536) && (csi > -65536)) { | |
return 2; | |
} | |
if ((csi < 16777216) && (csi > -16777216)) { | |
return 3; | |
} | |
return 4; | |
} | |
/* C indexed! */ | |
function cDigitLshiftfromlentolen(shiftCount, pFrom, lenFrom, pTo, lenTo) { | |
var digitShift; | |
var carry; | |
var digit; | |
var i; | |
var bitShift; | |
var rshift; | |
var limit; | |
digitShift = shiftCount >> 3; | |
bitShift = MOD(shiftCount, 8); | |
limit = digitShift - 1; | |
for (i = 0; i <= limit; i++) { | |
pTo[i] = 0; | |
} | |
if (bitShift === 0) { | |
/* Fast version for digit-aligned shifts */ | |
/* C indexed! */ | |
return cDigitReplacefromtowithstartingAt(pTo, digitShift, lenTo - 1, pFrom, 0); | |
} | |
rshift = 8 - bitShift; | |
carry = 0; | |
limit = lenFrom - 1; | |
for (i = 0; i <= limit; i++) { | |
digit = pFrom[i]; | |
pTo[i + digitShift] = ((carry | (SHL(digit, bitShift))) & 255); | |
carry = SHR(digit, rshift); | |
} | |
if (carry !== 0) { | |
pTo[lenTo - 1] = carry; | |
} | |
return 0; | |
} | |
function cDigitMontgomerylentimeslenmodulolenmInvModBinto(pBytesFirst, firstLen, pBytesSecond, secondLen, pBytesThird, thirdLen, mInv, pBytesRes) { | |
var k; | |
var i; | |
var lastByte; | |
var limit3; | |
var limit2; | |
var limit1; | |
var u; | |
var accum; | |
limit1 = firstLen - 1; | |
limit2 = secondLen - 1; | |
limit3 = thirdLen - 1; | |
lastByte = 0; | |
for (i = 0; i <= limit1; i++) { | |
accum = pBytesRes[0] + (pBytesFirst[i] * pBytesSecond[0]); | |
u = (accum * mInv) & 255; | |
accum += u * pBytesThird[0]; | |
for (k = 1; k <= limit2; k++) { | |
accum = (((accum >>> 8) + pBytesRes[k]) + (pBytesFirst[i] * pBytesSecond[k])) + (u * pBytesThird[k]); | |
pBytesRes[k - 1] = (accum & 255); | |
} | |
for (k = secondLen; k <= limit3; k++) { | |
accum = ((accum >>> 8) + pBytesRes[k]) + (u * pBytesThird[k]); | |
pBytesRes[k - 1] = (accum & 255); | |
} | |
accum = (accum >>> 8) + lastByte; | |
pBytesRes[limit3] = (accum & 255); | |
lastByte = accum >>> 8; | |
} | |
for (i = firstLen; i <= limit3; i++) { | |
accum = pBytesRes[0]; | |
u = (accum * mInv) & 255; | |
accum += u * pBytesThird[0]; | |
for (k = 1; k <= limit3; k++) { | |
accum = ((accum >>> 8) + pBytesRes[k]) + (u * pBytesThird[k]); | |
pBytesRes[k - 1] = (accum & 255); | |
} | |
accum = (accum >>> 8) + lastByte; | |
pBytesRes[limit3] = (accum & 255); | |
lastByte = accum >>> 8; | |
} | |
if (!((lastByte === 0) && (cDigitComparewithlen(pBytesThird, pBytesRes, thirdLen) === 1))) { | |
/* self cDigitSub: pBytesThird len: thirdLen with: pBytesRes len: thirdLen into: pBytesRes */ | |
accum = 0; | |
for (i = 0; i <= limit3; i++) { | |
accum = (accum + pBytesRes[i]) - pBytesThird[i]; | |
pBytesRes[i] = (accum & 255); | |
accum = accum >> 8; | |
} | |
} | |
} | |
function cDigitMultiplylenwithleninto(pByteShort, shortLen, pByteLong, longLen, pByteRes) { | |
var ab; | |
var j; | |
var digit; | |
var carry; | |
var i; | |
var limitLong; | |
var k; | |
var limitShort; | |
if ((shortLen === 1) && (pByteShort[0] === 0)) { | |
return 0; | |
} | |
if ((longLen === 1) && (pByteLong[0] === 0)) { | |
return 0; | |
} | |
limitShort = shortLen - 1; | |
limitLong = longLen - 1; | |
for (i = 0; i <= limitShort; i++) { | |
if (((digit = pByteShort[i])) !== 0) { | |
k = i; | |
/* Loop invariant: 0<=carry<=0377, k=i+j-1 (ST) */ | |
/* -> Loop invariant: 0<=carry<=0377, k=i+j (C) (?) */ | |
carry = 0; | |
for (j = 0; j <= limitLong; j++) { | |
ab = pByteLong[j]; | |
ab = ((ab * digit) + carry) + pByteRes[k]; | |
carry = ab >>> 8; | |
pByteRes[k] = (ab & 255); | |
++k; | |
} | |
pByteRes[k] = carry; | |
} | |
} | |
return 0; | |
} | |
/* Answer the value of an indexable field in the receiver. | |
LargePositiveInteger uses bytes of base two number, and each is a | |
'digit' base 256. */ | |
/* ST indexed! */ | |
function cDigitOfCSIat(csi, ix) { | |
if (ix < 1) { | |
interpreterProxy.primitiveFail(); | |
} | |
if (ix > 4) { | |
return 0; | |
} | |
if (csi < 0) { | |
; | |
return (SHR((0 - csi), ((ix - 1) * 8))) & 255; | |
} else { | |
return (SHR(csi, ((ix - 1) * 8))) & 255; | |
} | |
} | |
/* pByteRes len = longLen. */ | |
function cDigitOpshortlenlongleninto(opIndex, pByteShort, shortLen, pByteLong, longLen, pByteRes) { | |
var i; | |
var limit; | |
limit = shortLen - 1; | |
if (opIndex === andOpIndex) { | |
for (i = 0; i <= limit; i++) { | |
pByteRes[i] = (pByteShort[i] & pByteLong[i]); | |
} | |
limit = longLen - 1; | |
for (i = shortLen; i <= limit; i++) { | |
pByteRes[i] = 0; | |
} | |
return 0; | |
} | |
if (opIndex === orOpIndex) { | |
for (i = 0; i <= limit; i++) { | |
pByteRes[i] = (pByteShort[i] | pByteLong[i]); | |
} | |
limit = longLen - 1; | |
for (i = shortLen; i <= limit; i++) { | |
pByteRes[i] = pByteLong[i]; | |
} | |
return 0; | |
} | |
if (opIndex === xorOpIndex) { | |
for (i = 0; i <= limit; i++) { | |
pByteRes[i] = (pByteShort[i] ^ pByteLong[i]); | |
} | |
limit = longLen - 1; | |
for (i = shortLen; i <= limit; i++) { | |
pByteRes[i] = pByteLong[i]; | |
} | |
return 0; | |
} | |
return interpreterProxy.primitiveFail(); | |
} | |
/* C indexed! */ | |
function cDigitReplacefromtowithstartingAt(pTo, start, stop, pFrom, repStart) { | |
return function() { | |
// inlining self cDigitCopyFrom: pFrom + repStart to: pTo + start len: stop - start + 1 | |
var len = stop - start + 1; | |
for (var i = 0; i < len; i++) { | |
pTo[i + start] = pFrom[i + repStart]; | |
} | |
return 0; | |
}(); | |
; | |
} | |
function cDigitRshiftfromlentolen(shiftCount, pFrom, fromLen, pTo, toLen) { | |
var j; | |
var digitShift; | |
var carry; | |
var digit; | |
var bitShift; | |
var leftShift; | |
var limit; | |
var start; | |
digitShift = shiftCount >> 3; | |
bitShift = MOD(shiftCount, 8); | |
if (bitShift === 0) { | |
/* Fast version for byte-aligned shifts */ | |
/* C indexed! */ | |
return cDigitReplacefromtowithstartingAt(pTo, 0, toLen - 1, pFrom, digitShift); | |
} | |
leftShift = 8 - bitShift; | |
carry = SHR(pFrom[digitShift], bitShift); | |
start = digitShift + 1; | |
limit = fromLen - 1; | |
for (j = start; j <= limit; j++) { | |
digit = pFrom[j]; | |
pTo[j - start] = ((carry | (SHL(digit, leftShift))) & 255); | |
carry = SHR(digit, bitShift); | |
} | |
if (carry !== 0) { | |
pTo[toLen - 1] = carry; | |
} | |
return 0; | |
} | |
function cDigitSublenwithleninto(pByteSmall, smallLen, pByteLarge, largeLen, pByteRes) { | |
var i; | |
var z; | |
/* Loop invariant is -1<=z<=0 */ | |
z = 0; | |
for (i = 0; i <= (smallLen - 1); i++) { | |
z = (z + pByteLarge[i]) - pByteSmall[i]; | |
pByteRes[i] = (z & 255); | |
z = z >> 8; | |
} | |
for (i = smallLen; i <= (largeLen - 1); i++) { | |
z += pByteLarge[i]; | |
pByteRes[i] = (z & 255); | |
z = z >> 8; | |
} | |
} | |
/* Answer the index of the high order bit of the argument, or zero if the | |
argument is zero. */ | |
/* For 64 bit uints there could be added a 32-shift. */ | |
function cHighBit(uint) { | |
var shifted; | |
var bitNo; | |
shifted = uint; | |
bitNo = 0; | |
if (!(shifted < (1 << 16))) { | |
shifted = shifted >>> 16; | |
bitNo += 16; | |
} | |
if (!(shifted < (1 << 8))) { | |
shifted = shifted >>> 8; | |
bitNo += 8; | |
} | |
if (!(shifted < (1 << 4))) { | |
shifted = shifted >>> 4; | |
bitNo += 4; | |
} | |
if (!(shifted < (1 << 2))) { | |
shifted = shifted >>> 2; | |
bitNo += 2; | |
} | |
if (!(shifted < (1 << 1))) { | |
shifted = shifted >>> 1; | |
++bitNo; | |
} | |
return bitNo + shifted; | |
} | |
/* anOop has to be a SmallInteger! */ | |
function createLargeFromSmallInteger(anOop) { | |
var size; | |
var res; | |
var pByte; | |
var ix; | |
var sq_class; | |
var val; | |
val = anOop; | |
if (val < 0) { | |
sq_class = interpreterProxy.classLargeNegativeInteger(); | |
} else { | |
sq_class = interpreterProxy.classLargePositiveInteger(); | |
} | |
size = cDigitLengthOfCSI(val); | |
res = interpreterProxy.instantiateClassindexableSize(sq_class, size); | |
pByte = res.bytes; | |
for (ix = 1; ix <= size; ix++) { | |
pByte[ix - 1] = cDigitOfCSIat(val, ix); | |
} | |
return res; | |
} | |
/* Attention: this method invalidates all oop's! Only newBytes is valid at return. */ | |
/* Does not normalize. */ | |
function digitLshift(aBytesOop, shiftCount) { | |
var newLen; | |
var oldLen; | |
var newBytes; | |
var highBit; | |
oldLen = BYTESIZEOF(aBytesOop); | |
if (((highBit = cDigitHighBitlen(aBytesOop.bytes, oldLen))) === 0) { | |
return 0; | |
} | |
newLen = ((highBit + shiftCount) + 7) >> 3; | |
newBytes = interpreterProxy.instantiateClassindexableSize(CLASSOF(aBytesOop), newLen); | |
; | |
cDigitLshiftfromlentolen(shiftCount, aBytesOop.bytes, oldLen, newBytes.bytes, newLen); | |
return newBytes; | |
} | |
/* Attention: this method invalidates all oop's! Only newBytes is valid at return. */ | |
/* Shift right shiftCount bits, 0<=shiftCount. | |
Discard all digits beyond a, and all zeroes at or below a. */ | |
/* Does not normalize. */ | |
function digitRshiftlookfirst(aBytesOop, shiftCount, a) { | |
var newOop; | |
var oldDigitLen; | |
var newByteLen; | |
var newBitLen; | |
var oldBitLen; | |
oldBitLen = cDigitHighBitlen(aBytesOop.bytes, a); | |
oldDigitLen = (oldBitLen + 7) >> 3; | |
newBitLen = oldBitLen - shiftCount; | |
if (newBitLen <= 0) { | |
/* All bits lost */ | |
return interpreterProxy.instantiateClassindexableSize(CLASSOF(aBytesOop), 0); | |
} | |
newByteLen = (newBitLen + 7) >> 3; | |
newOop = interpreterProxy.instantiateClassindexableSize(CLASSOF(aBytesOop), newByteLen); | |
; | |
cDigitRshiftfromlentolen(shiftCount, aBytesOop.bytes, oldDigitLen, newOop.bytes, newByteLen); | |
return newOop; | |
} | |
/* Does not need to normalize! */ | |
function digitAddLargewith(firstInteger, secondInteger) { | |
var sum; | |
var shortLen; | |
var over; | |
var shortInt; | |
var resClass; | |
var newSum; | |
var longLen; | |
var firstLen; | |
var secondLen; | |
var longInt; | |
firstLen = BYTESIZEOF(firstInteger); | |
secondLen = BYTESIZEOF(secondInteger); | |
resClass = CLASSOF(firstInteger); | |
if (firstLen <= secondLen) { | |
shortInt = firstInteger; | |
shortLen = firstLen; | |
longInt = secondInteger; | |
longLen = secondLen; | |
} else { | |
shortInt = secondInteger; | |
shortLen = secondLen; | |
longInt = firstInteger; | |
longLen = firstLen; | |
} | |
sum = interpreterProxy.instantiateClassindexableSize(resClass, longLen); | |
; | |
over = cDigitAddlenwithleninto(shortInt.bytes, shortLen, longInt.bytes, longLen, sum.bytes); | |
if (over > 0) { | |
/* sum := sum growby: 1. */ | |
newSum = interpreterProxy.instantiateClassindexableSize(resClass, longLen + 1); | |
; | |
cDigitCopyFromtolen(sum.bytes, newSum.bytes, longLen); | |
/* C index! */ | |
sum = newSum; | |
sum.bytes[longLen] = over; | |
} | |
return sum; | |
} | |
/* Bit logic here is only implemented for positive integers or Zero; | |
if rec or arg is negative, it fails. */ | |
function digitBitLogicwithopIndex(firstInteger, secondInteger, opIx) { | |
var shortLen; | |
var shortLarge; | |
var firstLarge; | |
var secondLarge; | |
var longLen; | |
var longLarge; | |
var firstLen; | |
var secondLen; | |
var result; | |
if (typeof firstInteger === "number") { | |
if (firstInteger < 0) { | |
return interpreterProxy.primitiveFail(); | |
} | |
firstLarge = createLargeFromSmallInteger(firstInteger); | |
; | |
} else { | |
if (CLASSOF(firstInteger) === interpreterProxy.classLargeNegativeInteger()) { | |
return interpreterProxy.primitiveFail(); | |
} | |
firstLarge = firstInteger; | |
} | |
if (typeof secondInteger === "number") { | |
if (secondInteger < 0) { | |
return interpreterProxy.primitiveFail(); | |
} | |
secondLarge = createLargeFromSmallInteger(secondInteger); | |
; | |
} else { | |
if (CLASSOF(secondInteger) === interpreterProxy.classLargeNegativeInteger()) { | |
return interpreterProxy.primitiveFail(); | |
} | |
secondLarge = secondInteger; | |
} | |
firstLen = BYTESIZEOF(firstLarge); | |
secondLen = BYTESIZEOF(secondLarge); | |
if (firstLen < secondLen) { | |
shortLen = firstLen; | |
shortLarge = firstLarge; | |
longLen = secondLen; | |
longLarge = secondLarge; | |
} else { | |
shortLen = secondLen; | |
shortLarge = secondLarge; | |
longLen = firstLen; | |
longLarge = firstLarge; | |
} | |
result = interpreterProxy.instantiateClassindexableSize(interpreterProxy.classLargePositiveInteger(), longLen); | |
; | |
cDigitOpshortlenlongleninto(opIx, shortLarge.bytes, shortLen, longLarge.bytes, longLen, result.bytes); | |
if (interpreterProxy.failed()) { | |
return 0; | |
} | |
return normalizePositive(result); | |
} | |
/* Compare the magnitude of firstInteger with that of secondInteger. | |
Return a code of 1, 0, -1 for firstInteger >, = , < secondInteger */ | |
function digitCompareLargewith(firstInteger, secondInteger) { | |
var secondLen; | |
var firstLen; | |
firstLen = BYTESIZEOF(firstInteger); | |
secondLen = BYTESIZEOF(secondInteger); | |
if (secondLen !== firstLen) { | |
if (secondLen > firstLen) { | |
return -1; | |
} else { | |
return 1; | |
} | |
} | |
return cDigitComparewithlen(firstInteger.bytes, secondInteger.bytes, firstLen); | |
} | |
/* Does not normalize. */ | |
/* Division by zero has to be checked in caller. */ | |
function digitDivLargewithnegative(firstInteger, secondInteger, neg) { | |
var resultClass; | |
var result; | |
var rem; | |
var div; | |
var quo; | |
var d; | |
var l; | |
var secondLen; | |
var firstLen; | |
firstLen = BYTESIZEOF(firstInteger); | |
secondLen = BYTESIZEOF(secondInteger); | |
if (neg) { | |
resultClass = interpreterProxy.classLargeNegativeInteger(); | |
} else { | |
resultClass = interpreterProxy.classLargePositiveInteger(); | |
} | |
l = (firstLen - secondLen) + 1; | |
if (l <= 0) { | |
result = interpreterProxy.instantiateClassindexableSize(interpreterProxy.classArray(), 2); | |
; | |
interpreterProxy.stObjectatput(result,1,0); | |
interpreterProxy.stObjectatput(result,2,firstInteger); | |
return result; | |
} | |
d = 8 - cHighBit(unsafeByteOfat(secondInteger, secondLen)); | |
div = digitLshift(secondInteger, d); | |
div = bytesOrIntgrowTo(div, digitLength(div) + 1); | |
; | |
rem = digitLshift(firstInteger, d); | |
if (digitLength(rem) === firstLen) { | |
rem = bytesOrIntgrowTo(rem, firstLen + 1); | |
} | |
; | |
quo = interpreterProxy.instantiateClassindexableSize(resultClass, l); | |
; | |
cDigitDivlenremlenquolen(div.bytes, digitLength(div), rem.bytes, digitLength(rem), quo.bytes, digitLength(quo)); | |
rem = digitRshiftlookfirst(rem, d, digitLength(div) - 1); | |
; | |
result = interpreterProxy.instantiateClassindexableSize(interpreterProxy.classArray(), 2); | |
; | |
interpreterProxy.stObjectatput(result,1,quo); | |
interpreterProxy.stObjectatput(result,2,rem); | |
return result; | |
} | |
function digitLength(oop) { | |
if (typeof oop === "number") { | |
return cDigitLengthOfCSI(oop); | |
} else { | |
return BYTESIZEOF(oop); | |
} | |
} | |
function digitMontgomerytimesmodulomInvModB(firstLarge, secondLarge, thirdLarge, mInv) { | |
var prod; | |
var thirdLen; | |
var firstLen; | |
var secondLen; | |
firstLen = BYTESIZEOF(firstLarge); | |
secondLen = BYTESIZEOF(secondLarge); | |
thirdLen = BYTESIZEOF(thirdLarge); | |
if (!(firstLen <= thirdLen)) { | |
return interpreterProxy.primitiveFail(); | |
} | |
if (!(secondLen <= thirdLen)) { | |
return interpreterProxy.primitiveFail(); | |
} | |
if (!((mInv >= 0) && (mInv <= 255))) { | |
return interpreterProxy.primitiveFail(); | |
} | |
prod = interpreterProxy.instantiateClassindexableSize(interpreterProxy.classLargePositiveInteger(), thirdLen); | |
; | |
cDigitMontgomerylentimeslenmodulolenmInvModBinto(firstLarge.bytes, firstLen, secondLarge.bytes, secondLen, thirdLarge.bytes, thirdLen, mInv, prod.bytes); | |
return normalizePositive(prod); | |
} | |
/* Normalizes. */ | |
function digitMultiplyLargewithnegative(firstInteger, secondInteger, neg) { | |
var longInt; | |
var resultClass; | |
var shortLen; | |
var shortInt; | |
var longLen; | |
var prod; | |
var secondLen; | |
var firstLen; | |
firstLen = BYTESIZEOF(firstInteger); | |
secondLen = BYTESIZEOF(secondInteger); | |
if (firstLen <= secondLen) { | |
shortInt = firstInteger; | |
shortLen = firstLen; | |
longInt = secondInteger; | |
longLen = secondLen; | |
} else { | |
shortInt = secondInteger; | |
shortLen = secondLen; | |
longInt = firstInteger; | |
longLen = firstLen; | |
} | |
if (neg) { | |
resultClass = interpreterProxy.classLargeNegativeInteger(); | |
} else { | |
resultClass = interpreterProxy.classLargePositiveInteger(); | |
} | |
prod = interpreterProxy.instantiateClassindexableSize(resultClass, longLen + shortLen); | |
; | |
cDigitMultiplylenwithleninto(shortInt.bytes, shortLen, longInt.bytes, longLen, prod.bytes); | |
return normalize(prod); | |
} | |
/* Argument has to be aLargeInteger! */ | |
function digitOfBytesat(aBytesOop, ix) { | |
if (ix > BYTESIZEOF(aBytesOop)) { | |
return 0; | |
} else { | |
return unsafeByteOfat(aBytesOop, ix); | |
} | |
} | |
/* Normalizes. */ | |
function digitSubLargewith(firstInteger, secondInteger) { | |
var smallerLen; | |
var larger; | |
var res; | |
var smaller; | |
var resLen; | |
var largerLen; | |
var firstNeg; | |
var firstLen; | |
var secondLen; | |
var neg; | |
firstNeg = CLASSOF(firstInteger) === interpreterProxy.classLargeNegativeInteger(); | |
firstLen = BYTESIZEOF(firstInteger); | |
secondLen = BYTESIZEOF(secondInteger); | |
if (firstLen === secondLen) { | |
while ((firstLen > 1) && (digitOfBytesat(firstInteger, firstLen) === digitOfBytesat(secondInteger, firstLen))) { | |
--firstLen; | |
} | |
secondLen = firstLen; | |
} | |
if ((firstLen < secondLen) || ((firstLen === secondLen) && (digitOfBytesat(firstInteger, firstLen) < digitOfBytesat(secondInteger, firstLen)))) { | |
larger = secondInteger; | |
largerLen = secondLen; | |
smaller = firstInteger; | |
smallerLen = firstLen; | |
neg = firstNeg === false; | |
} else { | |
larger = firstInteger; | |
largerLen = firstLen; | |
smaller = secondInteger; | |
smallerLen = secondLen; | |
neg = firstNeg; | |
} | |
resLen = largerLen; | |
res = interpreterProxy.instantiateClassindexableSize((neg | |
? interpreterProxy.classLargeNegativeInteger() | |
: interpreterProxy.classLargePositiveInteger()), resLen); | |
; | |
cDigitSublenwithleninto(smaller.bytes, smallerLen, larger.bytes, largerLen, res.bytes); | |
return (neg | |
? normalizeNegative(res) | |
: normalizePositive(res)); | |
} | |
/* Note: This is hardcoded so it can be run from Squeak. | |
The module name is used for validating a module *after* | |
it is loaded to check if it does really contain the module | |
we're thinking it contains. This is important! */ | |
function getModuleName() { | |
return moduleName; | |
} | |
function halt() { | |
; | |
} | |
function highBitOfBytes(aBytesOop) { | |
return cDigitHighBitlen(aBytesOop.bytes, BYTESIZEOF(aBytesOop)); | |
} | |
function isNormalized(anInteger) { | |
var ix; | |
var len; | |
var sLen; | |
var minVal; | |
var maxVal; | |
if (typeof anInteger === "number") { | |
return true; | |
} | |
len = digitLength(anInteger); | |
if (len === 0) { | |
return false; | |
} | |
if (unsafeByteOfat(anInteger, len) === 0) { | |
return false; | |
} | |
/* maximal digitLength of aSmallInteger */ | |
sLen = 4; | |
if (len > sLen) { | |
return true; | |
} | |
if (len < sLen) { | |
return false; | |
} | |
if (CLASSOF(anInteger) === interpreterProxy.classLargePositiveInteger()) { | |
/* SmallInteger maxVal */ | |
/* all bytes of maxVal but the highest one are just FF's */ | |
maxVal = 1073741823; | |
return unsafeByteOfat(anInteger, sLen) > cDigitOfCSIat(maxVal, sLen); | |
} else { | |
/* SmallInteger minVal */ | |
/* all bytes of minVal but the highest one are just 00's */ | |
minVal = -1073741824; | |
if (unsafeByteOfat(anInteger, sLen) < cDigitOfCSIat(minVal, sLen)) { | |
return false; | |
} else { | |
/* if just one digit differs, then anInteger < minval (the corresponding digit byte is greater!) | |
and therefore a LargeNegativeInteger */ | |
for (ix = 1; ix <= sLen; ix++) { | |
if (unsafeByteOfat(anInteger, ix) !== cDigitOfCSIat(minVal, ix)) { | |
return true; | |
} | |
} | |
} | |
} | |
return false; | |
} | |
function msg(s) { | |
console.log(moduleName + ": " + s); | |
} | |
/* Check for leading zeroes and return shortened copy if so. */ | |
function normalize(aLargeInteger) { | |
// missing DebugCode; | |
if (CLASSOF(aLargeInteger) === interpreterProxy.classLargePositiveInteger()) { | |
return normalizePositive(aLargeInteger); | |
} else { | |
return normalizeNegative(aLargeInteger); | |
} | |
} | |
/* Check for leading zeroes and return shortened copy if so. */ | |
/* First establish len = significant length. */ | |
function normalizeNegative(aLargeNegativeInteger) { | |
var i; | |
var len; | |
var sLen; | |
var minVal; | |
var oldLen; | |
var val; | |
len = (oldLen = digitLength(aLargeNegativeInteger)); | |
while ((len !== 0) && (unsafeByteOfat(aLargeNegativeInteger, len) === 0)) { | |
--len; | |
} | |
if (len === 0) { | |
return 0; | |
} | |
/* SmallInteger minVal digitLength */ | |
sLen = 4; | |
if (len <= sLen) { | |
/* SmallInteger minVal */ | |
minVal = -1073741824; | |
if ((len < sLen) || (digitOfBytesat(aLargeNegativeInteger, sLen) < cDigitOfCSIat(minVal, sLen))) { | |
/* If high digit less, then can be small */ | |
val = 0; | |
for (i = len; i >= 1; i += -1) { | |
val = (val * 256) - unsafeByteOfat(aLargeNegativeInteger, i); | |
} | |
return val; | |
} | |
for (i = 1; i <= sLen; i++) { | |
/* If all digits same, then = minVal (sr: minVal digits 1 to 3 are | |
0) */ | |
if (digitOfBytesat(aLargeNegativeInteger, i) !== cDigitOfCSIat(minVal, i)) { | |
/* Not so; return self shortened */ | |
if (len < oldLen) { | |
/* ^ self growto: len */ | |
return bytesgrowTo(aLargeNegativeInteger, len); | |
} else { | |
return aLargeNegativeInteger; | |
} | |
} | |
} | |
return minVal; | |
} | |
if (len < oldLen) { | |
/* ^ self growto: len */ | |
return bytesgrowTo(aLargeNegativeInteger, len); | |
} else { | |
return aLargeNegativeInteger; | |
} | |
} | |
/* Check for leading zeroes and return shortened copy if so. */ | |
/* First establish len = significant length. */ | |
function normalizePositive(aLargePositiveInteger) { | |
var i; | |
var len; | |
var sLen; | |
var val; | |
var oldLen; | |
len = (oldLen = digitLength(aLargePositiveInteger)); | |
while ((len !== 0) && (unsafeByteOfat(aLargePositiveInteger, len) === 0)) { | |
--len; | |
} | |
if (len === 0) { | |
return 0; | |
} | |
/* SmallInteger maxVal digitLength. */ | |
sLen = 4; | |
if ((len <= sLen) && (digitOfBytesat(aLargePositiveInteger, sLen) <= cDigitOfCSIat(1073741823, sLen))) { | |
/* If so, return its SmallInt value */ | |
val = 0; | |
for (i = len; i >= 1; i += -1) { | |
val = (val * 256) + unsafeByteOfat(aLargePositiveInteger, i); | |
} | |
return val; | |
} | |
if (len < oldLen) { | |
/* ^ self growto: len */ | |
return bytesgrowTo(aLargePositiveInteger, len); | |
} else { | |
return aLargePositiveInteger; | |
} | |
} | |
function primAnyBitFromTo() { | |
var integer; | |
var large; | |
var from; | |
var to; | |
var _return_value; | |
from = interpreterProxy.stackIntegerValue(1); | |
to = interpreterProxy.stackIntegerValue(0); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(2))); | |
integer = interpreterProxy.stackValue(2); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof integer === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
large = createLargeFromSmallInteger(integer); | |
} else { | |
large = integer; | |
} | |
_return_value = (anyBitOfBytesfromto(large, from, to)? interpreterProxy.trueObject() : interpreterProxy.falseObject()); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} | |
/* Converts a SmallInteger into a - non normalized! - LargeInteger; | |
aLargeInteger will be returned unchanged. */ | |
/* Do not check for forced fail, because we need this conversion to test the | |
plugin in ST during forced fail, too. */ | |
function primAsLargeInteger() { | |
var anInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
anInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof anInteger === "number") { | |
_return_value = createLargeFromSmallInteger(anInteger); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} else { | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, anInteger); | |
return null; | |
} | |
} | |
/* If calling this primitive fails, then C module does not exist. Do not check for forced fail, because we want to know if module exists during forced fail, too. */ | |
function primCheckIfCModuleExists() { | |
var _return_value; | |
_return_value = (true? interpreterProxy.trueObject() : interpreterProxy.falseObject()); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(1, _return_value); | |
return null; | |
} | |
function _primDigitBitShift() { | |
var rShift; | |
var aLarge; | |
var anInteger; | |
var shiftCount; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
anInteger = interpreterProxy.stackValue(1); | |
shiftCount = interpreterProxy.stackIntegerValue(0); | |
// missing DebugCode; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof anInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
aLarge = createLargeFromSmallInteger(anInteger); | |
} else { | |
aLarge = anInteger; | |
} | |
if (shiftCount >= 0) { | |
_return_value = digitLshift(aLarge, shiftCount); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} else { | |
rShift = 0 - shiftCount; | |
_return_value = normalize(digitRshiftlookfirst(aLarge, rShift, BYTESIZEOF(aLarge))); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} | |
} | |
function primDigitAdd() { | |
var firstLarge; | |
var firstInteger; | |
var secondLarge; | |
var secondInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
secondInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
firstInteger = interpreterProxy.stackValue(1); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
firstLarge = createLargeFromSmallInteger(firstInteger); | |
; | |
} else { | |
firstLarge = firstInteger; | |
} | |
if (typeof secondInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
secondLarge = createLargeFromSmallInteger(secondInteger); | |
; | |
} else { | |
secondLarge = secondInteger; | |
} | |
_return_value = digitAddLargewith(firstLarge, secondLarge); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
function primDigitAddWith() { | |
var firstLarge; | |
var secondLarge; | |
var firstInteger; | |
var secondInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
firstInteger = interpreterProxy.stackValue(1); | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
secondInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
firstLarge = createLargeFromSmallInteger(firstInteger); | |
; | |
} else { | |
firstLarge = firstInteger; | |
} | |
if (typeof secondInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
secondLarge = createLargeFromSmallInteger(secondInteger); | |
; | |
} else { | |
secondLarge = secondInteger; | |
} | |
_return_value = digitAddLargewith(firstLarge, secondLarge); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} | |
/* Bit logic here is only implemented for positive integers or Zero; if rec | |
or arg is negative, it fails. */ | |
function primDigitBitAnd() { | |
var firstInteger; | |
var secondInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
secondInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
firstInteger = interpreterProxy.stackValue(1); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
_return_value = digitBitLogicwithopIndex(firstInteger, secondInteger, andOpIndex); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
/* Bit logic here is only implemented for positive integers or Zero; if any arg is negative, it fails. */ | |
function primDigitBitLogicWithOp() { | |
var firstInteger; | |
var secondInteger; | |
var opIndex; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(2))); | |
firstInteger = interpreterProxy.stackValue(2); | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
secondInteger = interpreterProxy.stackValue(1); | |
opIndex = interpreterProxy.stackIntegerValue(0); | |
// missing DebugCode; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
_return_value = digitBitLogicwithopIndex(firstInteger, secondInteger, opIndex); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(4, _return_value); | |
return null; | |
} | |
/* Bit logic here is only implemented for positive integers or Zero; if rec | |
or arg is negative, it fails. */ | |
function primDigitBitOr() { | |
var firstInteger; | |
var secondInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
secondInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
firstInteger = interpreterProxy.stackValue(1); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
_return_value = digitBitLogicwithopIndex(firstInteger, secondInteger, orOpIndex); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
function primDigitBitShift() { | |
var aLarge; | |
var rShift; | |
var anInteger; | |
var shiftCount; | |
var _return_value; | |
shiftCount = interpreterProxy.stackIntegerValue(0); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
anInteger = interpreterProxy.stackValue(1); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof anInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
aLarge = createLargeFromSmallInteger(anInteger); | |
} else { | |
aLarge = anInteger; | |
} | |
if (shiftCount >= 0) { | |
_return_value = digitLshift(aLarge, shiftCount); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} else { | |
rShift = 0 - shiftCount; | |
_return_value = normalize(digitRshiftlookfirst(aLarge, rShift, BYTESIZEOF(aLarge))); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
} | |
function primDigitBitShiftMagnitude() { | |
var aLarge; | |
var rShift; | |
var anInteger; | |
var shiftCount; | |
var _return_value; | |
shiftCount = interpreterProxy.stackIntegerValue(0); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
anInteger = interpreterProxy.stackValue(1); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof anInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
aLarge = createLargeFromSmallInteger(anInteger); | |
} else { | |
aLarge = anInteger; | |
} | |
if (shiftCount >= 0) { | |
_return_value = digitLshift(aLarge, shiftCount); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} else { | |
rShift = 0 - shiftCount; | |
_return_value = normalize(digitRshiftlookfirst(aLarge, rShift, BYTESIZEOF(aLarge))); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
} | |
/* Bit logic here is only implemented for positive integers or Zero; if rec | |
or arg is negative, it fails. */ | |
function primDigitBitXor() { | |
var firstInteger; | |
var secondInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
secondInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
firstInteger = interpreterProxy.stackValue(1); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
_return_value = digitBitLogicwithopIndex(firstInteger, secondInteger, xorOpIndex); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
function primDigitCompare() { | |
var firstVal; | |
var firstInteger; | |
var secondVal; | |
var secondInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
secondInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
firstInteger = interpreterProxy.stackValue(1); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* first */ | |
if (typeof secondInteger === "number") { | |
/* second */ | |
if (((firstVal = firstInteger)) > ((secondVal = secondInteger))) { | |
_return_value = 1; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} else { | |
if (firstVal < secondVal) { | |
_return_value = -1; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} else { | |
_return_value = 0; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
} | |
} else { | |
/* SECOND */ | |
_return_value = -1; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
} else { | |
/* FIRST */ | |
if (typeof secondInteger === "number") { | |
/* second */ | |
_return_value = 1; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} else { | |
/* SECOND */ | |
_return_value = digitCompareLargewith(firstInteger, secondInteger); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
} | |
} | |
function primDigitCompareWith() { | |
var firstVal; | |
var secondVal; | |
var firstInteger; | |
var secondInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
firstInteger = interpreterProxy.stackValue(1); | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
secondInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* first */ | |
if (typeof secondInteger === "number") { | |
/* second */ | |
if (((firstVal = firstInteger)) > ((secondVal = secondInteger))) { | |
_return_value = 1; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} else { | |
if (firstVal < secondVal) { | |
_return_value = -1; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} else { | |
_return_value = 0; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} | |
} | |
} else { | |
/* SECOND */ | |
_return_value = -1; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} | |
} else { | |
/* FIRST */ | |
if (typeof secondInteger === "number") { | |
/* second */ | |
_return_value = 1; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} else { | |
/* SECOND */ | |
_return_value = digitCompareLargewith(firstInteger, secondInteger); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} | |
} | |
} | |
/* Answer the result of dividing firstInteger by secondInteger. | |
Fail if parameters are not integers, not normalized or secondInteger is | |
zero. */ | |
function primDigitDivNegative() { | |
var firstAsLargeInteger; | |
var firstInteger; | |
var secondAsLargeInteger; | |
var secondInteger; | |
var neg; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
secondInteger = interpreterProxy.stackValue(1); | |
neg = interpreterProxy.booleanValueOf(interpreterProxy.stackValue(0)); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(2))); | |
firstInteger = interpreterProxy.stackValue(2); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (!isNormalized(firstInteger)) { | |
// missing DebugCode; | |
interpreterProxy.primitiveFail(); | |
return null; | |
} | |
if (!isNormalized(secondInteger)) { | |
// missing DebugCode; | |
interpreterProxy.primitiveFail(); | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* convert to LargeInteger */ | |
firstAsLargeInteger = createLargeFromSmallInteger(firstInteger); | |
; | |
} else { | |
firstAsLargeInteger = firstInteger; | |
} | |
if (typeof secondInteger === "number") { | |
/* check for zerodivide and convert to LargeInteger */ | |
if (secondInteger === 0) { | |
interpreterProxy.primitiveFail(); | |
return null; | |
} | |
secondAsLargeInteger = createLargeFromSmallInteger(secondInteger); | |
; | |
} else { | |
secondAsLargeInteger = secondInteger; | |
} | |
_return_value = digitDivLargewithnegative(firstAsLargeInteger, secondAsLargeInteger, neg); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} | |
/* Answer the result of dividing firstInteger by secondInteger. | |
Fail if parameters are not integers or secondInteger is zero. */ | |
function primDigitDivWithNegative() { | |
var firstAsLargeInteger; | |
var secondAsLargeInteger; | |
var firstInteger; | |
var secondInteger; | |
var neg; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(2))); | |
firstInteger = interpreterProxy.stackValue(2); | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
secondInteger = interpreterProxy.stackValue(1); | |
neg = interpreterProxy.booleanValueOf(interpreterProxy.stackValue(0)); | |
// missing DebugCode; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* convert to LargeInteger */ | |
firstAsLargeInteger = createLargeFromSmallInteger(firstInteger); | |
; | |
} else { | |
firstAsLargeInteger = firstInteger; | |
} | |
if (typeof secondInteger === "number") { | |
/* check for zerodivide and convert to LargeInteger */ | |
if (secondInteger === 0) { | |
interpreterProxy.primitiveFail(); | |
return null; | |
} | |
secondAsLargeInteger = createLargeFromSmallInteger(secondInteger); | |
; | |
} else { | |
secondAsLargeInteger = secondInteger; | |
} | |
_return_value = digitDivLargewithnegative(firstAsLargeInteger, secondAsLargeInteger, neg); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(4, _return_value); | |
return null; | |
} | |
function primDigitMultiplyNegative() { | |
var firstLarge; | |
var firstInteger; | |
var secondLarge; | |
var secondInteger; | |
var neg; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
secondInteger = interpreterProxy.stackValue(1); | |
neg = interpreterProxy.booleanValueOf(interpreterProxy.stackValue(0)); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(2))); | |
firstInteger = interpreterProxy.stackValue(2); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
firstLarge = createLargeFromSmallInteger(firstInteger); | |
; | |
} else { | |
firstLarge = firstInteger; | |
} | |
if (typeof secondInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
secondLarge = createLargeFromSmallInteger(secondInteger); | |
; | |
} else { | |
secondLarge = secondInteger; | |
} | |
_return_value = digitMultiplyLargewithnegative(firstLarge, secondLarge, neg); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} | |
function primDigitMultiplyWithNegative() { | |
var firstLarge; | |
var secondLarge; | |
var firstInteger; | |
var secondInteger; | |
var neg; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(2))); | |
firstInteger = interpreterProxy.stackValue(2); | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
secondInteger = interpreterProxy.stackValue(1); | |
neg = interpreterProxy.booleanValueOf(interpreterProxy.stackValue(0)); | |
// missing DebugCode; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
firstLarge = createLargeFromSmallInteger(firstInteger); | |
; | |
} else { | |
firstLarge = firstInteger; | |
} | |
if (typeof secondInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
secondLarge = createLargeFromSmallInteger(secondInteger); | |
; | |
} else { | |
secondLarge = secondInteger; | |
} | |
_return_value = digitMultiplyLargewithnegative(firstLarge, secondLarge, neg); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(4, _return_value); | |
return null; | |
} | |
function primDigitSubtract() { | |
var firstLarge; | |
var firstInteger; | |
var secondLarge; | |
var secondInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
secondInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
firstInteger = interpreterProxy.stackValue(1); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
firstLarge = createLargeFromSmallInteger(firstInteger); | |
; | |
} else { | |
firstLarge = firstInteger; | |
} | |
if (typeof secondInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
secondLarge = createLargeFromSmallInteger(secondInteger); | |
; | |
} else { | |
secondLarge = secondInteger; | |
} | |
_return_value = digitSubLargewith(firstLarge, secondLarge); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
function primDigitSubtractWith() { | |
var firstLarge; | |
var secondLarge; | |
var firstInteger; | |
var secondInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
firstInteger = interpreterProxy.stackValue(1); | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
secondInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
firstLarge = createLargeFromSmallInteger(firstInteger); | |
; | |
} else { | |
firstLarge = firstInteger; | |
} | |
if (typeof secondInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
secondLarge = createLargeFromSmallInteger(secondInteger); | |
; | |
} else { | |
secondLarge = secondInteger; | |
} | |
_return_value = digitSubLargewith(firstLarge, secondLarge); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(3, _return_value); | |
return null; | |
} | |
/* If calling this primitive fails, then C module does not exist. */ | |
function primGetModuleName() { | |
var strPtr; | |
var strLen; | |
var i; | |
var strOop; | |
// missing DebugCode; | |
strLen = getModuleName().length; | |
strOop = interpreterProxy.instantiateClassindexableSize(interpreterProxy.classString(), strLen); | |
strPtr = strOop.bytes; | |
for (i = 0; i <= (strLen - 1); i++) { | |
strPtr[i] = getModuleName()[i]; | |
} | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(1, strOop); | |
return null; | |
} | |
function primMontgomeryTimesModulo() { | |
var firstLarge; | |
var secondLarge; | |
var firstInteger; | |
var thirdLarge; | |
var secondOperandInteger; | |
var thirdModuloInteger; | |
var smallInverseInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(2))); | |
secondOperandInteger = interpreterProxy.stackValue(2); | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(1))); | |
thirdModuloInteger = interpreterProxy.stackValue(1); | |
smallInverseInteger = interpreterProxy.stackIntegerValue(0); | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(3))); | |
firstInteger = interpreterProxy.stackValue(3); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof firstInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
firstLarge = createLargeFromSmallInteger(firstInteger); | |
; | |
} else { | |
firstLarge = firstInteger; | |
} | |
if (typeof secondOperandInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
secondLarge = createLargeFromSmallInteger(secondOperandInteger); | |
; | |
} else { | |
secondLarge = secondOperandInteger; | |
} | |
if (typeof thirdModuloInteger === "number") { | |
/* convert it to a not normalized LargeInteger */ | |
thirdLarge = createLargeFromSmallInteger(thirdModuloInteger); | |
; | |
} else { | |
thirdLarge = thirdModuloInteger; | |
} | |
_return_value = digitMontgomerytimesmodulomInvModB(firstLarge, secondLarge, thirdLarge, smallInverseInteger); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(4, _return_value); | |
return null; | |
} | |
/* Parameter specification #(Integer) doesn't convert! */ | |
function primNormalize() { | |
var anInteger; | |
var _return_value; | |
interpreterProxy.success(interpreterProxy.isKindOfInteger(interpreterProxy.stackValue(0))); | |
anInteger = interpreterProxy.stackValue(0); | |
// missing DebugCode; | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
if (typeof anInteger === "number") { | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, anInteger); | |
return null; | |
} | |
_return_value = normalize(anInteger); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(2, _return_value); | |
return null; | |
} | |
function primNormalizeNegative() { | |
var rcvr; | |
var _return_value; | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.stackValue(0).sqClass === interpreterProxy.classLargeNegativeInteger()); | |
rcvr = interpreterProxy.stackValue(0); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
_return_value = normalizeNegative(rcvr); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(1, _return_value); | |
return null; | |
} | |
function primNormalizePositive() { | |
var rcvr; | |
var _return_value; | |
// missing DebugCode; | |
interpreterProxy.success(interpreterProxy.stackValue(0).sqClass === interpreterProxy.classLargePositiveInteger()); | |
rcvr = interpreterProxy.stackValue(0); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
_return_value = normalizePositive(rcvr); | |
if (interpreterProxy.failed()) { | |
return null; | |
} | |
interpreterProxy.popthenPush(1, _return_value); | |
return null; | |
} | |
/* Note: This is coded so that is can be run from Squeak. */ | |
function setInterpreter(anInterpreter) { | |
var ok; | |
interpreterProxy = anInterpreter; | |
ok = interpreterProxy.majorVersion() == VM_PROXY_MAJOR; | |
if (ok === false) { | |
return false; | |
} | |
ok = interpreterProxy.minorVersion() >= VM_PROXY_MINOR; | |
return ok; | |
} | |
/* Argument bytesOop must not be aSmallInteger! */ | |
function unsafeByteOfat(bytesOop, ix) { | |
var pointer; | |
return ((pointer = bytesOop.bytes))[ix - 1]; | |
} | |
function registerPlugin() { | |
if (typeof Squeak === "object" && Squeak.registerExternalModule) { | |
Squeak.registerExternalModule("LargeIntegers", { | |
primDigitAddWith: primDigitAddWith, | |
primDigitBitShiftMagnitude: primDigitBitShiftMagnitude, | |
primGetModuleName: primGetModuleName, | |
primDigitBitLogicWithOp: primDigitBitLogicWithOp, | |
primCheckIfCModuleExists: primCheckIfCModuleExists, | |
primDigitCompare: primDigitCompare, | |
primDigitMultiplyNegative: primDigitMultiplyNegative, | |
primDigitBitShift: primDigitBitShift, | |
primNormalizePositive: primNormalizePositive, | |
primDigitSubtractWith: primDigitSubtractWith, | |
_primDigitBitShift: _primDigitBitShift, | |
primDigitMultiplyWithNegative: primDigitMultiplyWithNegative, | |
primDigitSubtract: primDigitSubtract, | |
primDigitDivNegative: primDigitDivNegative, | |
primNormalizeNegative: primNormalizeNegative, | |
primDigitBitOr: primDigitBitOr, | |
primMontgomeryTimesModulo: primMontgomeryTimesModulo, | |
primDigitBitAnd: primDigitBitAnd, | |
primDigitDivWithNegative: primDigitDivWithNegative, | |
setInterpreter: setInterpreter, | |
primNormalize: primNormalize, | |
primDigitBitXor: primDigitBitXor, | |
primDigitCompareWith: primDigitCompareWith, | |
primDigitAdd: primDigitAdd, | |
getModuleName: getModuleName, | |
primAsLargeInteger: primAsLargeInteger, | |
primAnyBitFromTo: primAnyBitFromTo, | |
}); | |
} else self.setTimeout(registerPlugin, 100); | |
} | |
registerPlugin(); | |
})(); // Register module/plugin | |