/* Automatically generated by
	SmartSyntaxPluginCodeGenerator VMMaker.oscog-eem.2495 uuid: fcbf4c90-4c50-4ff3-8690-0edfded4f9c4
   from
	LargeIntegersPlugin VMMaker.oscog-eem.2495 uuid: fcbf4c90-4c50-4ff3-8690-0edfded4f9c4
 */
static char __buildInfo[] = "LargeIntegersPlugin VMMaker.oscog-eem.2495 uuid: fcbf4c90-4c50-4ff3-8690-0edfded4f9c4 " __DATE__ ;



#include "config.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Default EXPORT macro that does nothing (see comment in sq.h): */
#define EXPORT(returnType) returnType

/* Do not include the entire sq.h file but just those parts needed. */
#include "sqConfig.h"			/* Configuration options */
#include "virtualMachine.h"	/*  The virtual machine proxy definition */
#include "sqPlatformSpecific.h"	/* Platform specific definitions */

#define true 1
#define false 0
#define null 0  /* using 'null' because nil is predefined in Think C */
#ifdef SQUEAK_BUILTIN_PLUGIN
# undef EXPORT
# define EXPORT(returnType) static returnType
#endif

#include "memoryAccess.h"


/*** Constants ***/
#define PrimErrBadArgument 3
#define PrimErrNoMemory 9


/*** Function Prototypes ***/
static sqInt anyBitOfLargeIntfromto(sqInt anOop, sqInt start, sqInt stopArg);
static sqInt cDigitComparewithlen(unsigned int *pFirst, unsigned int *pSecond, sqInt len);
static sqInt cDigitHighBitlen(unsigned int *pUint32, sqInt len);
static unsigned int cDigitOfat(unsigned int *cPointer, sqInt zeroBasedDigitIndex);
static sqInt cHighBit32(unsigned int anUnsignedInt32);
static sqInt createLargeFromSmallInteger(sqInt anOop);
static sqInt digitBitLogicwithopIndex(sqInt firstInteger, sqInt secondInteger, sqInt opIx);
static sqInt digitLshift(sqInt anOop, sqInt shiftCount);
static sqInt digitRshiftlookfirst(sqInt anOop, sqInt shiftCount, sqInt a);
EXPORT(const char*) getModuleName(void);
static sqInt isNormalized(sqInt aLargeInteger);
static sqInt largeIntgrowTo(sqInt aBytesObject, sqInt newByteLen);
static sqInt normalizeNegative(sqInt aLargeNegativeInteger);
static sqInt normalizePositive(sqInt aLargePositiveInteger);
EXPORT(sqInt) primAnyBitFromTo(void);
EXPORT(sqInt) primDigitAdd(void);
EXPORT(sqInt) primDigitBitAnd(void);
EXPORT(sqInt) primDigitBitOr(void);
EXPORT(sqInt) primDigitBitShiftMagnitude(void);
EXPORT(sqInt) primDigitBitXor(void);
EXPORT(sqInt) primDigitCompare(void);
EXPORT(sqInt) primDigitDivNegative(void);
EXPORT(sqInt) primDigitMultiplyNegative(void);
EXPORT(sqInt) primDigitSubtract(void);
EXPORT(sqInt) primGetModuleName(void);
EXPORT(sqInt) primMontgomeryDigitLength(void);
EXPORT(sqInt) primMontgomeryTimesModulo(void);
EXPORT(sqInt) primNormalizeNegative(void);
EXPORT(sqInt) primNormalizePositive(void);
EXPORT(sqInt) setInterpreter(struct VirtualMachine *anInterpreter);
static unsigned char unsafeByteOfLargeIntat(sqInt bytesObj, sqInt ix);


/*** Variables ***/
static const int  andOpIndex = 0;

#if defined(SQUEAK_BUILTIN_PLUGIN)

# define isIntegerObject(oop) ((oop) & 1)

extern sqInt classIndexOf(sqInt);
#	define LargeNegativeIntegerClassIndex 32
#	define LargePositiveIntegerClassIndex 33
#	if BytesPerOop == 4
#	  define isImmediate(oop) ((oop) & 3)
#	else
#	  define isImmediate(oop) ((oop) & 7)
#	endif
#	define isKindOfInteger(oop) (isImmediate(oop) ? isIntegerObject(oop) : (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)
#	define isLargeIntegerObject(oop) (!isImmediate(oop) && (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)
#	define isLargeNegativeIntegerObject(oop) (!isImmediate(oop) && classIndexOf(oop) == LargeNegativeIntegerClassIndex)
#	define isLargePositiveIntegerObject(oop) (!isImmediate(oop) && classIndexOf(oop) == LargePositiveIntegerClassIndex)
#endif /* defined(SQUEAK_BUILTIN_PLUGIN) */

#if !defined(isKindOfInteger)
# define isLargeNegativeIntegerObject(oop) (fetchClassOf(oop) == classLargeNegativeInteger())
# define isLargePositiveIntegerObject(oop) (fetchClassOf(oop) == classLargePositiveInteger())
# define isLargeIntegerObject(oop) (isLargeNegativeIntegerObject(oop) || isLargePositiveIntegerObject(oop))
# define isKindOfInteger(oop) (isIntegerObject(oop) || isLargeNegativeIntegerObject(oop) || isLargePositiveIntegerObject(oop))
#endif

#if !defined(SQUEAK_BUILTIN_PLUGIN)
static sqInt (*booleanValueOf)(sqInt obj);
static sqInt (*classArray)(void);
static sqInt (*classLargeNegativeInteger)(void);
static sqInt (*classLargePositiveInteger)(void);
static sqInt (*classString)(void);
static sqInt (*failed)(void);
static sqInt (*falseObject)(void);
static sqInt (*fetchClassOf)(sqInt oop);
static void * (*firstIndexableField)(sqInt oop);
static sqInt (*instantiateClassindexableSize)(sqInt classPointer, sqInt size);
static sqInt (*integerObjectOf)(sqInt value);
static sqInt (*integerValueOf)(sqInt oop);
static sqInt (*isBooleanObject)(sqInt oop);
static sqInt (*isIntegerObject)(sqInt objectPointer);
static void (*popthenPush)(sqInt nItems, sqInt oop);
static sqInt (*popRemappableOop)(void);
static unsigned int (*positive32BitValueOf)(sqInt oop);
static sqInt (*primitiveFail)(void);
static sqInt (*primitiveFailFor)(sqInt reasonCode);
static void (*pushRemappableOop)(sqInt oop);
static sqInt (*slotSizeOf)(sqInt oop);
static sqInt (*stObjectatput)(sqInt array, sqInt index, sqInt value);
static sqInt (*stackIntegerValue)(sqInt offset);
static sqInt (*stackValue)(sqInt offset);
static sqInt (*success)(sqInt aBoolean);
static sqInt (*trueObject)(void);
#else /* !defined(SQUEAK_BUILTIN_PLUGIN) */
extern sqInt booleanValueOf(sqInt obj);
extern sqInt classArray(void);
extern sqInt classLargeNegativeInteger(void);
extern sqInt classLargePositiveInteger(void);
extern sqInt classString(void);
extern sqInt failed(void);
extern sqInt falseObject(void);
extern sqInt fetchClassOf(sqInt oop);
extern void * firstIndexableField(sqInt oop);
extern sqInt instantiateClassindexableSize(sqInt classPointer, sqInt size);
extern sqInt integerObjectOf(sqInt value);
extern sqInt integerValueOf(sqInt oop);
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 15)
extern sqInt isBooleanObject(sqInt oop);
#else
# define isBooleanObject(oop) 0
#endif
#if !defined(isIntegerObject)
extern sqInt isIntegerObject(sqInt objectPointer);
#endif
extern void popthenPush(sqInt nItems, sqInt oop);
extern sqInt popRemappableOop(void);
extern unsigned int positive32BitValueOf(sqInt oop);
extern sqInt primitiveFail(void);
extern sqInt primitiveFailFor(sqInt reasonCode);
extern void pushRemappableOop(sqInt oop);
extern sqInt slotSizeOf(sqInt oop);
extern sqInt stObjectatput(sqInt array, sqInt index, sqInt value);
extern sqInt stackIntegerValue(sqInt offset);
extern sqInt stackValue(sqInt offset);
extern sqInt success(sqInt aBoolean);
extern sqInt trueObject(void);
extern
#endif
struct VirtualMachine* interpreterProxy;
static const char *moduleName =
#ifdef SQUEAK_BUILTIN_PLUGIN
	"LargeIntegers v2.0 VMMaker.oscog-eem.2495 (i)"
#else
	"LargeIntegers v2.0 VMMaker.oscog-eem.2495 (e)"
#endif
;
static const int  orOpIndex = 1;
static const int  xorOpIndex = 2;



/*	Argument has to be a Large Integer! */
/*	Tests for any magnitude bits in the interval from start to stopArg. */

	/* LargeIntegersPlugin>>#anyBitOfLargeInt:from:to: */
static sqInt
anyBitOfLargeIntfromto(sqInt anOop, sqInt start, sqInt stopArg)
{
	unsigned int *cPointer;
	unsigned int digit;
	usqInt firstDigitIx;
	unsigned int firstMask;
	usqInt ix;
	usqInt lastDigitIx;
	unsigned int lastMask;
	sqInt magnitude;
	sqInt stop;
	sqInt zeroBasedDigitIndex;

	/* missing DebugCode */;
	if ((start < 1) || (stopArg < 1)) {
		return primitiveFail();
	}
	magnitude = anOop;
	stop = ((stopArg < (cDigitHighBitlen(((unsigned int *) (firstIndexableField(magnitude))), ((slotSizeOf(magnitude)) + 3) / 4))) ? stopArg : (cDigitHighBitlen(((unsigned int *) (firstIndexableField(magnitude))), ((slotSizeOf(magnitude)) + 3) / 4)));
	if (start > stop) {
		return 0;
	}
	firstDigitIx = ((start - 1) / 32) + 1;
	lastDigitIx = ((stop - 1) / 32) + 1;

	/* Note asUnsignedLong required to avoid ULLL suffix bug */
	firstMask = (((unsigned long)0xFFFFFFFFU)) << ((start - 1) & 0x1F);
	lastMask = ((usqInt) 0xFFFFFFFFU) >> (0x1F - ((stop - 1) & 0x1F));
	if (firstDigitIx == lastDigitIx) {
		/* begin cDigitOf:at: */
		cPointer = ((unsigned int *) (firstIndexableField(magnitude)));
		zeroBasedDigitIndex = firstDigitIx - 1;
		digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((cPointer[zeroBasedDigitIndex]));
		return (digit & (firstMask & lastMask)) != 0;
	}
	if (((cDigitOfat(((unsigned int *) (firstIndexableField(magnitude))), firstDigitIx - 1)) & firstMask) != 0) {
		return 1;
	}
	for (ix = (firstDigitIx + 1); ix < lastDigitIx; ix += 1) {
		if ((cDigitOfat(((unsigned int *) (firstIndexableField(magnitude))), ix - 1)) != 0) {
			return 1;
		}
	}
	if (((cDigitOfat(((unsigned int *) (firstIndexableField(magnitude))), lastDigitIx - 1)) & lastMask) != 0) {
		return 1;
	}
	return 0;
}


/*	Answer the number of bytes required to represent the value of a
	C-SmallInteger. 
 */

/*	pWordRes len = longLen; returns over.. */

/*	Precondition: pFirst len = pSecond len. */

	/* LargeIntegersPlugin>>#cDigitCompare:with:len: */
static sqInt
cDigitComparewithlen(unsigned int *pFirst, unsigned int *pSecond, sqInt len)
{
	unsigned int firstDigit;
	sqInt ix;
	unsigned int secondDigit;

	ix = len - 1;
	while (ix >= 0) {
		if (((secondDigit = pSecond[ix])) != ((firstDigit = pFirst[ix]))) {
			if ((SQ_SWAP_4_BYTES_IF_BIGENDIAN(secondDigit)) < (SQ_SWAP_4_BYTES_IF_BIGENDIAN(firstDigit))) {
				return 1;
			}
			else {
				return -1;
			}
		}
		ix -= 1;
	}
	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. Work with 32 bits digits. */

	/* LargeIntegersPlugin>>#cDigitHighBit:len: */
static sqInt
cDigitHighBitlen(unsigned int *pUint32, sqInt len)
{
	unsigned int lastDigit;
	sqInt realLength;

	realLength = len;
	do {
		if (realLength == 0) {
			return 0;
		}
	} while(((lastDigit = cDigitOfat(pUint32, (realLength -= 1)))) == 0);
	return (cHighBit32(lastDigit)) + (32 * realLength);
}


/*	C indexed! */

	/* LargeIntegersPlugin>>#cDigitOf:at: */
static unsigned int
cDigitOfat(unsigned int *cPointer, sqInt zeroBasedDigitIndex)
{
	return SQ_SWAP_4_BYTES_IF_BIGENDIAN((cPointer[zeroBasedDigitIndex]));
}

/*	pWordRes len = longLen.
	NOTE: we don't bother with endianness here, those bit opes are
	endian-neutral 
 */


/*	C indexed! */


/*	Answer the index of the high order bit of the argument, or zero if the 
	argument is zero. */

	/* LargeIntegersPlugin>>#cHighBit32: */
static sqInt
cHighBit32(unsigned int anUnsignedInt32)
{
	sqInt bitNo;
	unsigned int shifted;

	shifted = anUnsignedInt32;
	bitNo = 0;
	if (!(shifted < (1U << 16))) {
		shifted = ((usqInt) shifted) >> 16;
		bitNo += 16;
	}
	if (!(shifted < (1U << 8))) {
		shifted = ((usqInt) shifted) >> 8;
		bitNo += 8;
	}
	if (!(shifted < (1U << 4))) {
		shifted = ((usqInt) shifted) >> 4;
		bitNo += 4;
	}
	if (!(shifted < (1U << 2))) {
		shifted = ((usqInt) shifted) >> 2;
		bitNo += 2;
	}
	if (!(shifted < (1U << 1))) {
		shifted = ((usqInt) shifted) >> 1;
		bitNo += 1;
	}
	return bitNo + shifted;
}


/*	anOop has to be a SmallInteger! */

	/* LargeIntegersPlugin>>#createLargeFromSmallInteger: */
static sqInt
createLargeFromSmallInteger(sqInt anOop)
{
	unsigned int aValue;
	sqInt byteSize;
	sqInt digitSize;
	sqInt ix;
	unsigned int *pDigit;
	sqInt res;
	sqInt val;

	val = integerValueOf(anOop);
	/* begin byteSizeOfCSI: */
	if (val >= 0) {
		if (val < 256) {
			byteSize = 1;
			goto l2;
		}
		if (val < 65536) {
			byteSize = 2;
			goto l2;
		}
		if (val < 0x1000000) {
			byteSize = 3;
			goto l2;
		}
		
#    if BytesPerOop == 4
		byteSize = 4;
		goto l2;
#    else /* BytesPerOop == 4 */
		if (val < 0x100000000LL) {
			byteSize = 4;
			goto l2;
		}
		if (val < 0x10000000000LL) {
			byteSize = 5;
			goto l2;
		}
		if (val < 0x1000000000000LL) {
			byteSize = 6;
			goto l2;
		}
		if (val < 0x100000000000000LL) {
			byteSize = 7;
			goto l2;
		}
		byteSize = 8;
		goto l2;
#    endif /* BytesPerOop == 4 */
	}
	if (val > -256) {
		byteSize = 1;
		goto l2;
	}
	if (val > -65536) {
		byteSize = 2;
		goto l2;
	}
	if (val > -16777216) {
		byteSize = 3;
		goto l2;
	}
	
#  if BytesPerOop == 4
	byteSize = 4;
	goto l2;
#  else /* BytesPerOop == 4 */
	if (val > -4294967296LL) {
		byteSize = 4;
		goto l2;
	}
	if (val > -1099511627776LL) {
		byteSize = 5;
		goto l2;
	}
	if (val > -281474976710656LL) {
		byteSize = 6;
		goto l2;
	}
	if (val > -72057594037927936LL) {
		byteSize = 7;
		goto l2;
	}
	byteSize = 8;
	goto l2;
#  endif /* BytesPerOop == 4 */
	l2:	/* end byteSizeOfCSI: */;
	res = instantiateClassindexableSize((val < 0
		? classLargeNegativeInteger()
		: classLargePositiveInteger()), byteSize);
	pDigit = ((unsigned int *) (firstIndexableField(res)));
	digitSize = (byteSize + 3) / 4;
	for (ix = 1; ix <= digitSize; ix += 1) {
		/* begin cDigitOf:at:put: */
		aValue = ((unsigned int) (((usqInt) ((val < 0
	? 0 - val
	: val))) >> ((ix - 1) * 32)));
		pDigit[ix - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(aValue));
	}
	return res;
}


/*	Does not need to normalize! */

/*	Bit logic here is only implemented for positive integers or Zero;
	if rec or arg is negative, it fails. */

	/* LargeIntegersPlugin>>#digitBitLogic:with:opIndex: */
static sqInt
digitBitLogicwithopIndex(sqInt firstInteger, sqInt secondInteger, sqInt opIx)
{
	sqInt firstLarge;
	sqInt firstLen;
	sqInt i;
	sqInt limit;
	sqInt longLarge;
	sqInt longLen;
	unsigned int *pWordLong;
	unsigned int *pWordRes;
	unsigned int *pWordShort;
	sqInt result;
	sqInt secondLarge;
	sqInt secondLen;
	sqInt shortLarge;
	sqInt shortLen;

	if (isIntegerObject(firstInteger)) {
		if ((integerValueOf(firstInteger)) < 0) {
			return primitiveFail();
		}
		
		firstLarge = createLargeFromSmallInteger(firstInteger);

	}
	else {
		if (!(isLargePositiveIntegerObject(firstInteger))) {
			return primitiveFail();
		}
		firstLarge = firstInteger;
	}
	if (isIntegerObject(secondInteger)) {
		if ((integerValueOf(secondInteger)) < 0) {
			return primitiveFail();
		}
		
		secondLarge = createLargeFromSmallInteger(secondInteger);
	}
	else {
		if (!(isLargePositiveIntegerObject(secondInteger))) {
			return primitiveFail();
		}
		secondLarge = secondInteger;
	}
	/* begin byteSizeOfLargeInt: */
	firstLen = slotSizeOf(firstLarge);
	/* begin byteSizeOfLargeInt: */
	secondLen = slotSizeOf(secondLarge);
	if (firstLen < secondLen) {
		shortLen = firstLen;
		shortLarge = firstLarge;
		longLen = secondLen;
		longLarge = secondLarge;
	}
	else {
		shortLen = secondLen;
		shortLarge = secondLarge;
		longLen = firstLen;
		longLarge = firstLarge;
	}
	
	result = instantiateClassindexableSize(classLargePositiveInteger(), longLen);

	if (!(result)) {
		return primitiveFailFor(PrimErrNoMemory);
	}
	/* begin cDigitOp:short:len:long:len:into: */
	pWordShort = ((unsigned int *) (firstIndexableField(shortLarge)));
	pWordLong = ((unsigned int *) (firstIndexableField(longLarge)));
	pWordRes = ((unsigned int *) (firstIndexableField(result)));
	limit = ((shortLen + 3) / 4) - 1;
	if (opIx == andOpIndex) {
		for (i = 0; i <= limit; i += 1) {
			pWordRes[i] = ((pWordShort[i]) & (pWordLong[i]));
		}
		limit = ((longLen + 3) / 4) - 1;
		for (i = ((shortLen + 3) / 4); i <= limit; i += 1) {
			pWordRes[i] = 0;
		}
		goto l3;
	}
	if (opIx == orOpIndex) {
		for (i = 0; i <= limit; i += 1) {
			pWordRes[i] = ((pWordShort[i]) | (pWordLong[i]));
		}
		limit = ((longLen + 3) / 4) - 1;
		for (i = ((shortLen + 3) / 4); i <= limit; i += 1) {
			pWordRes[i] = (pWordLong[i]);
		}
		goto l3;
	}
	if (opIx == xorOpIndex) {
		for (i = 0; i <= limit; i += 1) {
			pWordRes[i] = ((pWordShort[i]) ^ (pWordLong[i]));
		}
		limit = ((longLen + 3) / 4) - 1;
		for (i = ((shortLen + 3) / 4); i <= limit; i += 1) {
			pWordRes[i] = (pWordLong[i]);
		}
		goto l3;
	}
	primitiveFail();
	l3:	/* end cDigitOp:short:len:long:len:into: */;
	if (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 */

/*	Does not normalize. */
/*	Division by zero has to be checked in caller. */

/*	Normalizes. */

/*	Answer the value of a 32 bits digit in a C-SmallInteger. */
/*	ST indexed! */

/*	Argument has to be aLargeInteger! */

/*	Answer the number of 32-bits fields of a C-SmallInteger. This value is 
	the same as the largest legal subscript. */

/*	answer number of 32 bits digits of a Large Integer */


/*	Normalizes. */

/*	Attention: this method invalidates all oop's! Only newOop is valid at
	return. 
 */
/*	Does not normalize. */

	/* LargeIntegersPlugin>>#digit:Lshift: */
static sqInt
digitLshift(sqInt anOop, sqInt shiftCount)
{
	sqInt bitShift;
	unsigned int carry;
	unsigned int digit;
	sqInt digitShift;
	sqInt highBit;
	sqInt i;
	sqInt i1;
	sqInt limit;
	sqInt newByteLen;
	sqInt newDigitLen;
	sqInt newOop;
	sqInt oldDigitLen;
	unsigned int *pFrom;
	unsigned int *pTo;
	sqInt rshift;

	/* begin digitSizeOfLargeInt: */
	oldDigitLen = ((slotSizeOf(anOop)) + 3) / 4;
	if (((highBit = cDigitHighBitlen(((unsigned int *) (firstIndexableField(anOop))), oldDigitLen))) == 0) {
		return instantiateClassindexableSize(fetchClassOf(anOop), 1);
	}
	newByteLen = ((highBit + shiftCount) + 7) / 8;
	
	newOop = instantiateClassindexableSize(fetchClassOf(anOop), newByteLen);

	if (!(newOop)) {
		primitiveFailFor(PrimErrNoMemory);
		return null;
	}
	newDigitLen = (newByteLen + 3) / 4;
	/* begin cDigitLshift:from:len:to:len: */
	pFrom = ((unsigned int *) (firstIndexableField(anOop)));
	pTo = ((unsigned int *) (firstIndexableField(newOop)));
	digitShift = shiftCount / 32;
	bitShift = shiftCount % 32;

	/* Note: 0 is endian neutral, use direct access */
	limit = digitShift - 1;
	for (i = 0; i <= limit; i += 1) {
		pTo[i] = 0;
	}
	if (bitShift == 0) {

		/* Fast version for digit-aligned shifts */
		/* C indexed! */
		/* begin cDigitCopyFrom:to:len: */
		for (i1 = 0; i1 < (((newDigitLen - 1) - digitShift) + 1); i1 += 1) {
			(pTo + digitShift)[i1] = ((pFrom)[i1]);
		}
		goto l2;
	}
	rshift = 32 - bitShift;
	carry = 0;
	limit = oldDigitLen - 1;
	for (i = 0; i <= limit; i += 1) {
		digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFrom[i]));
		pTo[i + digitShift] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(((carry | (((usqInt)(digit) << bitShift))) & 0xFFFFFFFFU)));
		carry = ((usqInt) digit) >> rshift;
	}
	if (!(carry == 0)) {
		pTo[newDigitLen - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(carry));
	}
	l2:	/* end cDigitLshift:from:len:to:len: */;
	return newOop;
}


/*	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. */

	/* LargeIntegersPlugin>>#digit:Rshift:lookfirst: */
static sqInt
digitRshiftlookfirst(sqInt anOop, sqInt shiftCount, sqInt a)
{
	sqInt bitShift;
	unsigned int carry;
	unsigned int digit;
	sqInt digitShift;
	sqInt i;
	sqInt j;
	unsigned int lastDigit;
	sqInt leftShift;
	sqInt limit;
	sqInt newBitLen;
	sqInt newByteLen;
	sqInt newDigitLen;
	sqInt newOop;
	sqInt oldBitLen;
	sqInt oldDigitLen;
	unsigned int *pFrom;
	unsigned int *pTo;
	unsigned int *pUint32;
	sqInt realLength;
	sqInt start;

	/* begin cDigitHighBit:len: */
	pUint32 = ((unsigned int *) (firstIndexableField(anOop)));
	realLength = a;
	do {
		if (realLength == 0) {
			oldBitLen = 0;
			goto l5;
		}
	} while(((lastDigit = cDigitOfat(pUint32, (realLength -= 1)))) == 0);
	oldBitLen = (cHighBit32(lastDigit)) + (32 * realLength);
	l5:	/* end cDigitHighBit:len: */;
	oldDigitLen = (oldBitLen + 0x1F) / 32;
	newBitLen = oldBitLen - shiftCount;
	if (newBitLen <= 0) {

		/* All bits lost */
		return instantiateClassindexableSize(fetchClassOf(anOop), 0);
	}
	newByteLen = (newBitLen + 7) / 8;
	newDigitLen = (newByteLen + 3) / 4;
	
	newOop = instantiateClassindexableSize(fetchClassOf(anOop), newByteLen);

	if (!(newOop)) {
		return primitiveFailFor(PrimErrNoMemory);
	}
	/* begin cDigitRshift:from:len:to:len: */
	pFrom = ((unsigned int *) (firstIndexableField(anOop)));
	pTo = ((unsigned int *) (firstIndexableField(newOop)));
	digitShift = shiftCount / 32;
	bitShift = shiftCount % 32;
	if (bitShift == 0) {

		/* Fast version for digit-aligned shifts */
		/* C indexed! */
		/* begin cDigitReplace:from:to:with:startingAt: */
		for (i = 0; i < (((newDigitLen - 1)) + 1); i += 1) {
			(pTo)[i] = ((pFrom + digitShift)[i]);
		}
		goto l4;
	}
	leftShift = 32 - bitShift;
	carry = ((usqInt) (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFrom[digitShift])))) >> bitShift;
	start = digitShift + 1;
	limit = oldDigitLen - 1;
	for (j = start; j <= limit; j += 1) {
		/* begin cDigitOf:at: */
		digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFrom[j]));
		/* begin cDigitOf:at:put: */
		pTo[j - start] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(((carry | (((usqInt)(digit) << leftShift))) & 0xFFFFFFFFU)));
		carry = ((usqInt) digit) >> bitShift;
	}
	if (!(carry == 0)) {
		/* begin cDigitOf:at:put: */
		pTo[newDigitLen - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(carry));
	}
	l4:	/* end cDigitRshift:from:len:to:len: */;
	return newOop;
}


/*	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! */

	/* InterpreterPlugin>>#getModuleName */
EXPORT(const char*)
getModuleName(void)
{
	return moduleName;
}

/*	Check for leading zero of LargeInteger */

	/* LargeIntegersPlugin>>#isNormalized: */
static sqInt
isNormalized(sqInt aLargeInteger)
{
	sqInt len;

	/* begin byteSizeOfLargeInt: */
	len = slotSizeOf(aLargeInteger);
	if (len == 0) {
		return 0;
	}
	if ((unsafeByteOfLargeIntat(aLargeInteger, len)) == 0) {
		return 0;
	}
	return 1;
}


/*	Attention: this method invalidates all oop's! Only newBytes is valid at
	return. 
 */
/*	Does not normalize. */

	/* LargeIntegersPlugin>>#largeInt:growTo: */
static sqInt
largeIntgrowTo(sqInt aBytesObject, sqInt newByteLen)
{
	sqInt copyLen;
	sqInt i;
	sqInt newBytes;
	sqInt newDigitLen;
	sqInt oldDigitLen;
	unsigned int *pFrom;
	unsigned int *pTo;

	newBytes = instantiateClassindexableSize(fetchClassOf(aBytesObject), newByteLen);
	if (!(newBytes)) {
		primitiveFailFor(PrimErrNoMemory);
		return null;
	}

	newDigitLen = (newByteLen + 3) / 4;
	/* begin digitSizeOfLargeInt: */
	oldDigitLen = ((slotSizeOf(aBytesObject)) + 3) / 4;
	copyLen = (oldDigitLen < newDigitLen
		? oldDigitLen
		: newDigitLen);
	/* begin cDigitCopyFrom:to:len: */
	pFrom = ((unsigned int *) (firstIndexableField(aBytesObject)));
	pTo = ((unsigned int *) (firstIndexableField(newBytes)));
	for (i = 0; i < copyLen; i += 1) {
		pTo[i] = (pFrom[i]);
	}
	return newBytes;
}


/*	Check for leading zeroes and return shortened copy if so. */
/*	First establish len = significant length. */

	/* LargeIntegersPlugin>>#normalizeNegative: */
static sqInt
normalizeNegative(sqInt aLargeNegativeInteger)
{
	sqInt byteLen;
	unsigned int *cPointer;
	sqInt digitLen;
	usqInt minVal;
	sqInt oldByteLen;
	int sLen;
	usqInt val;
	usqInt val2;

	/* begin digitSizeOfLargeInt: */
	digitLen = ((slotSizeOf(aLargeNegativeInteger)) + 3) / 4;
	while ((digitLen != 0)
	 && ((cDigitOfat(((unsigned int *) (firstIndexableField(aLargeNegativeInteger))), digitLen - 1)) == 0)) {
		digitLen -= 1;
	}
	if (digitLen == 0) {
		return integerObjectOf(0);
	}
	/* begin cDigitOf:at: */
	cPointer = ((unsigned int *) (firstIndexableField(aLargeNegativeInteger)));
	val = SQ_SWAP_4_BYTES_IF_BIGENDIAN((cPointer[digitLen - 1]));

	/* SmallInteger minVal digitLength */
	sLen = ((MinSmallInteger) < -1073741824LL
		? 2
		: 1);
	if (digitLen <= sLen) {
		minVal = 0 - (MinSmallInteger);
		val2 = val;
		if (digitLen > 1) {
			val2 = (val2 << 32) + (cDigitOfat(((unsigned int *) (firstIndexableField(aLargeNegativeInteger))), 1 - 1));
		}
		if (val2 <= minVal) {
			return integerObjectOf((0 - val2));
		}
	}
	byteLen = digitLen * 4;
	if (val <= 0xFFFF) {
		byteLen -= 2;
	}
	else {
		val = ((usqInt) val) >> 16;
	}
	if (val <= 0xFF) {
		byteLen -= 1;
	}
	/* begin byteSizeOfLargeInt: */
	oldByteLen = slotSizeOf(aLargeNegativeInteger);
	if (byteLen < oldByteLen) {
		return largeIntgrowTo(aLargeNegativeInteger, byteLen);
	}
	else {
		return aLargeNegativeInteger;
	}
}


/*	Check for leading zeroes and return shortened copy if so. */
/*	First establish len = significant length. */

	/* LargeIntegersPlugin>>#normalizePositive: */
static sqInt
normalizePositive(sqInt aLargePositiveInteger)
{
	sqInt byteLen;
	unsigned int *cPointer;
	sqInt digitLen;
	usqInt maxVal;
	sqInt oldByteLen;
	int sLen;
	usqInt val;
	usqInt val2;

	/* begin digitSizeOfLargeInt: */
	digitLen = ((slotSizeOf(aLargePositiveInteger)) + 3) / 4;
	while ((digitLen != 0)
	 && ((cDigitOfat(((unsigned int *) (firstIndexableField(aLargePositiveInteger))), digitLen - 1)) == 0)) {
		digitLen -= 1;
	}
	if (digitLen == 0) {
		return integerObjectOf(0);
	}
	/* begin cDigitOf:at: */
	cPointer = ((unsigned int *) (firstIndexableField(aLargePositiveInteger)));
	val = SQ_SWAP_4_BYTES_IF_BIGENDIAN((cPointer[digitLen - 1]));

	/* SmallInteger maxVal digitLength */
	sLen = ((MaxSmallInteger) > 0x3FFFFFFF
		? 2
		: 1);
	if (digitLen <= sLen) {
		maxVal = MaxSmallInteger;
		val2 = val;
		if (digitLen > 1) {

			/* Note: asUnsignedLongLong is not necessary because this branch is for 64 bits only.
			   but we want to avoid a C Compiler warning on 32 bits */
			val2 = ((((unsigned long long)val2)) << 32) + (cDigitOfat(((unsigned int *) (firstIndexableField(aLargePositiveInteger))), 1 - 1));
		}
		if (val2 <= maxVal) {
			return integerObjectOf(val2);
		}
	}
	byteLen = digitLen * 4;
	if (val <= 0xFFFF) {
		byteLen -= 2;
	}
	else {
		val = ((usqInt) val) >> 16;
	}
	if (val <= 0xFF) {
		byteLen -= 1;
	}
	/* begin byteSizeOfLargeInt: */
	oldByteLen = slotSizeOf(aLargePositiveInteger);
	if (byteLen < oldByteLen) {
		return largeIntgrowTo(aLargePositiveInteger, byteLen);
	}
	else {
		return aLargePositiveInteger;
	}
}


/*	Check for leading zeroes and return shortened copy if so. */

	/* LargeIntegersPlugin>>#primAnyBitFrom:to: */
EXPORT(sqInt)
primAnyBitFromTo(void)
{
	sqInt from;
	sqInt integer;
	sqInt large;
	sqInt to;
	sqInt _return_value;

	if (!((isIntegerObject(stackValue(1)))
		 && (isIntegerObject(stackValue(0))))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	from = stackIntegerValue(1);
	to = stackIntegerValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(2)));
	integer = stackValue(2);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(integer)) {

		/* convert it to a not normalized LargeInteger */
		large = createLargeFromSmallInteger(integer);
	}
	else {
		large = integer;
	}
	if (!(failed())) {
		_return_value = (((anyBitOfLargeIntfromto(large, from, to))) ? trueObject() : falseObject());
		if (!(failed())) {
			popthenPush(3, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primDigitAdd: */
EXPORT(sqInt)
primDigitAdd(void)
{
	unsigned long long accum;
	unsigned int *cPointer;
	sqInt firstDigitLen;
	sqInt firstInteger;
	sqInt firstLarge;
	sqInt i;
	sqInt i1;
	sqInt longDigitLen;
	sqInt longInt;
	sqInt neg;
	sqInt newSum;
	unsigned int over;
	unsigned int *pFrom;
	unsigned int *pTo;
	unsigned int *pWordLong;
	unsigned int *pWordRes;
	unsigned int *pWordShort;
	sqInt secondDigitLen;
	sqInt secondInteger;
	sqInt secondLarge;
	sqInt shortDigitLen;
	sqInt shortInt;
	sqInt sum;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(firstInteger)) {

		/* convert it to a not normalized LargeInteger */
		firstLarge = createLargeFromSmallInteger(firstInteger);
	}
	else {
		firstLarge = firstInteger;
	}
	if (isIntegerObject(secondInteger)) {

		/* convert it to a not normalized LargeInteger */
		
		secondLarge = createLargeFromSmallInteger(secondInteger);
	}
	else {
		secondLarge = secondInteger;
	}
	if (!(failed())) {
		/* begin digitAddLarge:with: */
		firstDigitLen = ((slotSizeOf(firstLarge)) + 3) / 4;
		secondDigitLen = ((slotSizeOf(secondLarge)) + 3) / 4;
		neg = isLargeNegativeIntegerObject(firstLarge);
		if (firstDigitLen <= secondDigitLen) {
			shortInt = firstLarge;
			shortDigitLen = firstDigitLen;
			longInt = secondLarge;
			longDigitLen = secondDigitLen;
		}
		else {
			shortInt = secondLarge;
			shortDigitLen = secondDigitLen;
			longInt = firstLarge;
			longDigitLen = firstDigitLen;
		}
		
		/* begin createLargeIntegerNeg:digitLength: */
		sum = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), longDigitLen * 4);

		if (!(sum)) {
			_return_value = primitiveFailFor(PrimErrNoMemory);
			goto l6;
		}
		/* begin cDigitAdd:len:with:len:into: */
		pWordShort = ((unsigned int *) (firstIndexableField(shortInt)));
		pWordLong = ((unsigned int *) (firstIndexableField(longInt)));
		pWordRes = ((unsigned int *) (firstIndexableField(sum)));
		accum = 0;
		for (i1 = 0; i1 < shortDigitLen; i1 += 1) {
			accum = ((accum >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordShort[i1])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[i1])));
			pWordRes[i1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
		}
		for (i1 = shortDigitLen; i1 < longDigitLen; i1 += 1) {
			accum = (accum >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[i1])));
			pWordRes[i1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
		}
		over = accum >> 32;
		if (over > 0) {

			/* sum := sum growby: 1. */
			
			/* begin createLargeIntegerNeg:byteLength: */
			newSum = instantiateClassindexableSize((neg
				? classLargeNegativeInteger()
				: classLargePositiveInteger()), (longDigitLen * 4) + 1);

			if (!(newSum)) {
				_return_value = primitiveFailFor(PrimErrNoMemory);
				goto l6;
			}
			/* begin cDigitCopyFrom:to:len: */
			pFrom = ((unsigned int *) (firstIndexableField(sum)));
			pTo = ((unsigned int *) (firstIndexableField(newSum)));
			for (i = 0; i < longDigitLen; i += 1) {
				pTo[i] = (pFrom[i]);
			}

			/* C index! */
			sum = newSum;
			/* begin cDigitOf:at:put: */
			cPointer = ((unsigned int *) (firstIndexableField(sum)));
			cPointer[longDigitLen] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(over));
		}
		else {
			sum = (neg
				? normalizeNegative(sum)
				: normalizePositive(sum));
		}
		_return_value = sum;
	l6:	/* end digitAddLarge:with: */;
		if (!(failed())) {
			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. */

	/* LargeIntegersPlugin>>#primDigitBitAnd: */
EXPORT(sqInt)
primDigitBitAnd(void)
{
	sqInt firstInteger;
	sqInt secondInteger;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (!(failed())) {
		_return_value = digitBitLogicwithopIndex(firstInteger, secondInteger, andOpIndex);
		if (!(failed())) {
			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. */

	/* LargeIntegersPlugin>>#primDigitBitOr: */
EXPORT(sqInt)
primDigitBitOr(void)
{
	sqInt firstInteger;
	sqInt secondInteger;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (!(failed())) {
		_return_value = digitBitLogicwithopIndex(firstInteger, secondInteger, orOpIndex);
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primDigitBitShiftMagnitude: */
EXPORT(sqInt)
primDigitBitShiftMagnitude(void)
{
	sqInt aLarge;
	sqInt aLargeInteger;
	sqInt anInteger;
	sqInt rShift;
	sqInt shiftCount;
	sqInt _return_value;

	if (!(isIntegerObject(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	shiftCount = stackIntegerValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	anInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(anInteger)) {

		/* convert it to a not normalized LargeInteger */
		aLarge = createLargeFromSmallInteger(anInteger);
	}
	else {
		aLarge = anInteger;
	}
	if (shiftCount >= 0) {
		_return_value = digitLshift(aLarge, shiftCount);
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
		return null;
	}
	else {
		rShift = 0 - shiftCount;
		if (!(failed())) {
			/* begin normalize: */
			aLargeInteger = digitRshiftlookfirst(aLarge, rShift, ((slotSizeOf(aLarge)) + 3) / 4);
			/* missing DebugCode */;
			if (isLargePositiveIntegerObject(aLargeInteger)) {
				_return_value = normalizePositive(aLargeInteger);
				goto l1;
			}
			else {
				_return_value = normalizeNegative(aLargeInteger);
				goto l1;
			}
	l1:	/* end normalize: */;
			if (!(failed())) {
				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. */

	/* LargeIntegersPlugin>>#primDigitBitXor: */
EXPORT(sqInt)
primDigitBitXor(void)
{
	sqInt firstInteger;
	sqInt secondInteger;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (!(failed())) {
		_return_value = digitBitLogicwithopIndex(firstInteger, secondInteger, xorOpIndex);
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
	}
	return null;
}


/*	Compare the magnitude of self with that of arg. 
	Answer a code of 1, 0, -1 for self >, = , < arg */

	/* LargeIntegersPlugin>>#primDigitCompare: */
EXPORT(sqInt)
primDigitCompare(void)
{
	sqInt firstDigitLen;
	sqInt firstInteger;
	sqInt firstVal;
	sqInt secondDigitLen;
	sqInt secondInteger;
	sqInt secondVal;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(firstInteger)) {
		if (isIntegerObject(secondInteger)) {
			firstVal = integerValueOf(firstInteger);

			/* Compute their magnitudes.  Since SmallIntegers are tagged they have
			   fewer bits than an integer on the platform; therefore in computing their
			   magnitude they cannot overflow. */
			secondVal = integerValueOf(secondInteger);
			if (firstVal < 0) {
				firstVal = 0 - firstVal;
			}
			if (secondVal < 0) {
				secondVal = 0 - secondVal;
			}
			if (!(failed())) {
				_return_value = (firstVal == secondVal
					? integerObjectOf(0)
					: (firstVal < secondVal
							? integerObjectOf(-1)
							: integerObjectOf(1)));
				if (!(failed())) {
					popthenPush(2, _return_value);
				}
			}
			return null;
		}
		if (!(failed())) {
			_return_value = integerObjectOf(-1);
			if (!(failed())) {
				popthenPush(2, _return_value);
			}
		}
		return null;
	}
	if (isIntegerObject(secondInteger)) {
		_return_value = integerObjectOf(1);
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
		return null;
	}
	if (!(failed())) {
		/* begin digitCompareLarge:with: */
		firstDigitLen = ((slotSizeOf(firstInteger)) + 3) / 4;
		secondDigitLen = ((slotSizeOf(secondInteger)) + 3) / 4;
		if (secondDigitLen != firstDigitLen) {
			if (secondDigitLen > firstDigitLen) {
				_return_value = integerObjectOf(-1);
				goto l1;
			}
			else {
				_return_value = integerObjectOf(1);
				goto l1;
			}
		}
		_return_value = integerObjectOf((cDigitComparewithlen(((unsigned int *) (firstIndexableField(firstInteger))), ((unsigned int *) (firstIndexableField(secondInteger))), firstDigitLen)));
	l1:	/* end digitCompareLarge:with: */;
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
	}
	return null;
}


/*	Answer the result of dividing firstInteger by secondInteger. 
	Fail if parameters are not integers, not normalized or secondInteger is 
	zero. */

	/* LargeIntegersPlugin>>#primDigitDiv:negative: */
EXPORT(sqInt)
primDigitDivNegative(void)
{
	unsigned long long a;
	unsigned long long b;
	sqInt cond;
	sqInt d;
	unsigned int dh;
	sqInt div;
	sqInt divLen;
	sqInt dl;
	unsigned int dnh;
	sqInt firstAsLargeInteger;
	sqInt firstDigitLen;
	sqInt firstInteger;
	unsigned long long hi;
	sqInt i;
	sqInt j;
	sqInt k;
	sqInt l;
	unsigned long long lo;
	unsigned long long mul;
	sqInt neg;
	unsigned int *pDiv;
	unsigned int *pQuo;
	unsigned int *pRem;
	unsigned long long q;
	sqInt ql;
	sqInt quo;
	sqInt quoDigitLen;
	sqInt quoLen;
	unsigned long long r1r2;
	unsigned int r3;
	sqInt rem;
	sqInt remLen;
	sqInt result;
	sqInt secondAsLargeInteger;
	sqInt secondDigitLen;
	sqInt secondInteger;
	unsigned long long t;
	sqInt _return_value;

	if (!((isKindOfInteger(stackValue(1)))
		 && (isBooleanObject(stackValue(0))))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(1);
	neg = booleanValueOf(stackValue(0));
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(2)));
	firstInteger = stackValue(2);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(firstInteger)) {

		/* convert to LargeInteger */
		
#if SPURVM
		firstAsLargeInteger = createLargeFromSmallInteger(firstInteger);

#else /* SPURVM */
		pushRemappableOop(secondInteger);
		firstAsLargeInteger = createLargeFromSmallInteger(firstInteger);
		secondInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {

		/* Avoid crashes in case of getting unnormalized args. */
		if (!(isNormalized(firstInteger))) {
			/* missing DebugCode */;
			primitiveFail();
			return null;
		}
		firstAsLargeInteger = firstInteger;
	}
	if (isIntegerObject(secondInteger)) {

		/* check for zerodivide and convert to LargeInteger */
		if ((integerValueOf(secondInteger)) == 0) {
			primitiveFail();
			return null;
		}
		
#if SPURVM
		secondAsLargeInteger = createLargeFromSmallInteger(secondInteger);

#else /* SPURVM */
		pushRemappableOop(firstAsLargeInteger);
		secondAsLargeInteger = createLargeFromSmallInteger(secondInteger);
		firstAsLargeInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {

		/* Avoid crashes in case of getting unnormalized args. */
		if (!(isNormalized(secondInteger))) {
			/* missing DebugCode */;
			primitiveFail();
			return null;
		}
		secondAsLargeInteger = secondInteger;
	}
	if (!(failed())) {
		/* begin digitDivLarge:with:negative: */
		firstDigitLen = ((slotSizeOf(firstAsLargeInteger)) + 3) / 4;
		secondDigitLen = ((slotSizeOf(secondAsLargeInteger)) + 3) / 4;
		quoDigitLen = (firstDigitLen - secondDigitLen) + 1;
		if (quoDigitLen <= 0) {
			
#if SPURVM
			result = instantiateClassindexableSize(classArray(), 2);

#else /* SPURVM */
			pushRemappableOop(firstAsLargeInteger);
			result = instantiateClassindexableSize(classArray(), 2);
			firstAsLargeInteger = popRemappableOop()
#endif /* SPURVM */
;
			if (!(result == null)) {
				stObjectatput(result, 1, integerObjectOf(0));
				stObjectatput(result, 2, firstAsLargeInteger);
			}
			_return_value = result;
			goto l3;
		}
		d = 32 - (cHighBit32(cDigitOfat(((unsigned int *) (firstIndexableField(secondAsLargeInteger))), secondDigitLen - 1)));
		
#if SPURVM
		div = digitLshift(secondAsLargeInteger, d);
		if (!(div == null)) {
			div = largeIntgrowTo(div, ((((slotSizeOf(div)) + 3) / 4) + 1) * 4);
		}
		if (!(div)) {
			_return_value = div;
			goto l3;
		}

#else /* SPURVM */
		pushRemappableOop(firstAsLargeInteger);
		div = digitLshift(secondAsLargeInteger, d);
		if (!(div == null)) {
			div = largeIntgrowTo(div, ((((slotSizeOf(div)) + 3) / 4) + 1) * 4);
		}
		if (!(div)) {
			_return_value = div;
			goto l3;
		}
		firstAsLargeInteger = popRemappableOop()
#endif /* SPURVM */
;
		
#if SPURVM
		rem = digitLshift(firstAsLargeInteger, d);
		if (!(rem == null)) {
			if ((((slotSizeOf(rem)) + 3) / 4) == firstDigitLen) {
				rem = largeIntgrowTo(rem, (firstDigitLen + 1) * 4);
			}
		}
		if (!(rem)) {
			_return_value = rem;
			goto l3;
		}

#else /* SPURVM */
		pushRemappableOop(div);
		rem = digitLshift(firstAsLargeInteger, d);
		if (!(rem == null)) {
			if ((((slotSizeOf(rem)) + 3) / 4) == firstDigitLen) {
				rem = largeIntgrowTo(rem, (firstDigitLen + 1) * 4);
			}
		}
		if (!(rem)) {
			_return_value = rem;
			goto l3;
		}
		div = popRemappableOop()
#endif /* SPURVM */
;
		
#if SPURVM
		/* begin createLargeIntegerNeg:digitLength: */
		quo = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), quoDigitLen * 4);

#else /* SPURVM */
		pushRemappableOop(div);
		pushRemappableOop(rem);
		/* begin createLargeIntegerNeg:digitLength: */
		quo = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), quoDigitLen * 4);
		rem = popRemappableOop();
		div = popRemappableOop()
#endif /* SPURVM */
;
		/* begin cDigitDiv:len:rem:len:quo:len: */
		pDiv = ((unsigned int *) (firstIndexableField(div)));
		divLen = ((slotSizeOf(div)) + 3) / 4;
		pRem = ((unsigned int *) (firstIndexableField(rem)));
		remLen = ((slotSizeOf(rem)) + 3) / 4;
		pQuo = ((unsigned int *) (firstIndexableField(quo)));
		quoLen = ((slotSizeOf(quo)) + 3) / 4;

		/* Last actual byte of data (ST ix) */
		dl = divLen - 1;
		ql = quoLen;
		dh = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[dl - 1]));
		if (dl == 1) {
			dnh = 0;
		}
		else {
			dnh = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[dl - 2]));
		}
		for (k = 1; k <= ql; k += 1) {

			/* maintain quo*arg+rem=self */
			/* Estimate rem/div by dividing the leading two unint32 of rem by dh. */
			/* The estimate is q = qhi*16r100000000+qlo, where qhi and qlo are uint32. */

			/* r1 := rem digitAt: j. */
			j = (remLen + 1) - k;
			if ((SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 1]))) == dh) {
				q = 0xFFFFFFFFU;
			}
			else {

				/* Compute q = (r1,r2)//dh, t = (r1,r2)\\dh.
				   Note that r1,r2 are uint64, not uint32. */
				/* r2 := (rem digitAt: j - 2). */
				r1r2 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 1]));
				r1r2 = (r1r2 << 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 2])));
				t = r1r2 % dh;

				/* Next compute (hi,lo) := q*dnh */
				q = r1r2 / dh;
				mul = q * dnh;
				hi = mul >> 32;

				/* Correct overestimate of q.
				   Max of 2 iterations through loop -- see Knuth vol. 2 */
				lo = mul & 0xFFFFFFFFU;
				if (j < 3) {
					r3 = 0;
				}
				else {
					r3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 3]));
				}
				while (1) {
					if ((t < hi)
					 || ((t == hi)
					 && (r3 < lo))) {

						/* i.e. (t,r3) < (hi,lo) */
						q -= 1;
						if (hi == 0) {

							/* since hi is unsigned we must have this guard */
							cond = 0;
						}
						else {
							if (lo < dnh) {
								hi -= 1;
								lo = (lo + 0x100000000LL) - dnh;
							}
							else {
								lo -= dnh;
							}
							cond = hi >= dh;
						}
					}
					else {
						cond = 0;
					}
					if (!(cond)) break;
					hi -= dh;
				}
			}
			l = j - dl;
			a = 0;
			for (i = 1; i <= divLen; i += 1) {
				hi = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1]))) * (q >> 32);
				lo = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1]))) * (q & 0xFFFFFFFFU);
				b = ((SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[l - 1]))) - a) - (lo & 0xFFFFFFFFU);
				pRem[l - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((b & 0xFFFFFFFFU)));
				b = (b >> 32) | ((0 - (b >> 0x3F)) & 0xFFFFFFFF00000000ULL);
				a = (hi + (lo >> 32)) - b;
				l += 1;
			}
			if (a > 0) {

				/* Add div back into rem, decrease q by 1 */
				q -= 1;
				l = j - dl;
				a = 0;
				for (i = 1; i <= divLen; i += 1) {
					a = ((a >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[l - 1])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1])));
					pRem[l - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((a & 0xFFFFFFFFU)));
					l += 1;
				}
			}
			pQuo[quoLen - k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) q))));
		}
		
#if SPURVM
		rem = digitRshiftlookfirst(rem, d, (((slotSizeOf(div)) + 3) / 4) - 1);

#else /* SPURVM */
		pushRemappableOop(quo);
		rem = digitRshiftlookfirst(rem, d, (((slotSizeOf(div)) + 3) / 4) - 1);
		quo = popRemappableOop()
#endif /* SPURVM */
;
		
#if SPURVM
		result = instantiateClassindexableSize(classArray(), 2);

#else /* SPURVM */
		pushRemappableOop(quo);
		pushRemappableOop(rem);
		result = instantiateClassindexableSize(classArray(), 2);
		rem = popRemappableOop();
		quo = popRemappableOop()
#endif /* SPURVM */
;
		if (!(result == null)) {
			stObjectatput(result, 1, quo);
			stObjectatput(result, 2, rem);
		}
		_return_value = result;
	l3:	/* end digitDivLarge:with:negative: */;
		if (!(failed())) {
			popthenPush(3, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primDigitMultiply:negative: */
EXPORT(sqInt)
primDigitMultiplyNegative(void)
{
	unsigned long long ab;
	unsigned int carry;
	unsigned int digit;
	sqInt firstInteger;
	sqInt firstLarge;
	sqInt firstLen;
	sqInt i;
	sqInt j;
	sqInt k;
	sqInt limitLong;
	sqInt limitShort;
	sqInt longInt;
	sqInt longLen;
	sqInt neg;
	sqInt prod;
	unsigned int *pWordLong;
	unsigned int *pWordRes;
	unsigned int *pWordShort;
	sqInt secondInteger;
	sqInt secondLarge;
	sqInt secondLen;
	sqInt shortInt;
	sqInt shortLen;
	sqInt _return_value;

	if (!((isKindOfInteger(stackValue(1)))
		 && (isBooleanObject(stackValue(0))))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(1);
	neg = booleanValueOf(stackValue(0));
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(2)));
	firstInteger = stackValue(2);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(firstInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		firstLarge = createLargeFromSmallInteger(firstInteger);

#else /* SPURVM */
		pushRemappableOop(secondInteger);
		firstLarge = createLargeFromSmallInteger(firstInteger);
		secondInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		firstLarge = firstInteger;
	}
	if (isIntegerObject(secondInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		secondLarge = createLargeFromSmallInteger(secondInteger);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		secondLarge = createLargeFromSmallInteger(secondInteger);
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		secondLarge = secondInteger;
	}
	if (!(failed())) {
		/* begin digitMultiplyLarge:with:negative: */
		firstLen = slotSizeOf(firstLarge);
		/* begin byteSizeOfLargeInt: */
		secondLen = slotSizeOf(secondLarge);
		if (firstLen <= secondLen) {
			shortInt = firstLarge;
			shortLen = firstLen;
			longInt = secondLarge;
			longLen = secondLen;
		}
		else {
			shortInt = secondLarge;
			shortLen = secondLen;
			longInt = firstLarge;
			longLen = firstLen;
		}
		
#if SPURVM
		/* begin createLargeIntegerNeg:byteLength: */
		prod = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), longLen + shortLen);

#else /* SPURVM */
		pushRemappableOop(shortInt);
		pushRemappableOop(longInt);
		/* begin createLargeIntegerNeg:byteLength: */
		prod = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), longLen + shortLen);
		longInt = popRemappableOop();
		shortInt = popRemappableOop()
#endif /* SPURVM */
;
		if (!(prod)) {
			_return_value = primitiveFailFor(PrimErrNoMemory);
			goto l5;
		}
		/* begin cDigitMultiply:len:with:len:into:len: */
		pWordShort = ((unsigned int *) (firstIndexableField(shortInt)));
		pWordLong = ((unsigned int *) (firstIndexableField(longInt)));
		pWordRes = ((unsigned int *) (firstIndexableField(prod)));
		if ((((shortLen + 3) / 4) == 1)
		 && ((pWordShort[0]) == 0)) {
			goto l4;
		}
		if ((((longLen + 3) / 4) == 1)
		 && ((pWordLong[0]) == 0)) {
			goto l4;
		}
		limitShort = ((shortLen + 3) / 4) - 1;
		limitLong = ((longLen + 3) / 4) - 1;
		for (i = 0; i <= limitShort; i += 1) {
			if (((digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordShort[i])))) != 0) {
				k = i;

				/* Loop invariant: 0<=carry<=16rFFFFFFFF, k=i+j-1 (ST) */
				/* -> Loop invariant: 0<=carry<=16rFFFFFFFF, k=i+j (C) (?) */
				carry = 0;
				for (j = 0; j <= limitLong; j += 1) {
					ab = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[j]));
					ab = ((ab * digit) + carry) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordRes[k])));
					carry = ab >> 32;
					pWordRes[k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((ab & 0xFFFFFFFFU)));
					k += 1;
				}
				if (k < (((longLen + shortLen) + 3) / 4)) {
					pWordRes[k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(carry));
				}
			}
		}
	l4:	/* end cDigitMultiply:len:with:len:into:len: */;
		_return_value = (neg
			? normalizeNegative(prod)
			: normalizePositive(prod));
	l5:	/* end digitMultiplyLarge:with:negative: */;
		if (!(failed())) {
			popthenPush(3, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primDigitSubtract: */
EXPORT(sqInt)
primDigitSubtract(void)
{
	sqInt firstDigitLen;
	sqInt firstInteger;
	sqInt firstLarge;
	sqInt firstNeg;
	sqInt i;
	sqInt largeDigitLen;
	sqInt larger;
	int neg;
	unsigned int *pWordLarge;
	unsigned int *pWordRes;
	unsigned int *pWordSmall;
	sqInt res;
	sqInt resDigitLen;
	sqInt secondDigitLen;
	sqInt secondInteger;
	sqInt secondLarge;
	sqInt smaller;
	sqInt smallerDigitLen;
	unsigned long long z;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(firstInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		firstLarge = createLargeFromSmallInteger(firstInteger);

#else /* SPURVM */
		pushRemappableOop(secondInteger);
		firstLarge = createLargeFromSmallInteger(firstInteger);
		secondInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		firstLarge = firstInteger;
	}
	if (isIntegerObject(secondInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		secondLarge = createLargeFromSmallInteger(secondInteger);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		secondLarge = createLargeFromSmallInteger(secondInteger);
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		secondLarge = secondInteger;
	}
	if (!(failed())) {
		/* begin digitSubLarge:with: */
		firstNeg = isLargeNegativeIntegerObject(firstLarge);
		/* begin digitSizeOfLargeInt: */
		firstDigitLen = ((slotSizeOf(firstLarge)) + 3) / 4;
		/* begin digitSizeOfLargeInt: */
		secondDigitLen = ((slotSizeOf(secondLarge)) + 3) / 4;
		if (firstDigitLen == secondDigitLen) {
			while ((firstDigitLen > 1)
			 && ((cDigitOfat(((unsigned int *) (firstIndexableField(firstLarge))), firstDigitLen - 1)) == (cDigitOfat(((unsigned int *) (firstIndexableField(secondLarge))), firstDigitLen - 1)))) {
				firstDigitLen -= 1;
			}
			secondDigitLen = firstDigitLen;
		}
		if ((firstDigitLen < secondDigitLen)
		 || ((firstDigitLen == secondDigitLen)
		 && ((cDigitOfat(((unsigned int *) (firstIndexableField(firstLarge))), firstDigitLen - 1)) < (cDigitOfat(((unsigned int *) (firstIndexableField(secondLarge))), firstDigitLen - 1))))) {
			larger = secondLarge;
			largeDigitLen = secondDigitLen;
			smaller = firstLarge;
			smallerDigitLen = firstDigitLen;
			neg = firstNeg == 0;
		}
		else {
			larger = firstLarge;
			largeDigitLen = firstDigitLen;
			smaller = secondLarge;
			smallerDigitLen = secondDigitLen;
			neg = firstNeg;
		}
		resDigitLen = largeDigitLen;
		
#if SPURVM
		/* begin createLargeIntegerNeg:digitLength: */
		res = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), resDigitLen * 4);

#else /* SPURVM */
		pushRemappableOop(smaller);
		pushRemappableOop(larger);
		/* begin createLargeIntegerNeg:digitLength: */
		res = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), resDigitLen * 4);
		larger = popRemappableOop();
		smaller = popRemappableOop()
#endif /* SPURVM */
;
		if (!(res)) {
			_return_value = primitiveFailFor(PrimErrNoMemory);
			goto l7;
		}
		/* begin cDigitSub:len:with:len:into: */
		pWordSmall = ((unsigned int *) (firstIndexableField(smaller)));
		pWordLarge = ((unsigned int *) (firstIndexableField(larger)));
		pWordRes = ((unsigned int *) (firstIndexableField(res)));
		z = 0;
		for (i = 0; i < smallerDigitLen; i += 1) {
			z = (z + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLarge[i])))) - (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordSmall[i])));
			/* begin cDigitOf:at:put: */
			pWordRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) (z & 0xFFFFFFFFU)))));
			z = 0 - (z >> 0x3F);
		}
		for (i = smallerDigitLen; i < largeDigitLen; i += 1) {
			z += SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLarge[i]));
			/* begin cDigitOf:at:put: */
			pWordRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) (z & 0xFFFFFFFFU)))));
			z = 0 - (z >> 0x3F);
		}
		_return_value = (neg
			? normalizeNegative(res)
			: normalizePositive(res));
	l7:	/* end digitSubLarge:with: */;
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
	}
	return null;
}


/*	If calling this primitive fails, then C module does not exist. */

	/* LargeIntegersPlugin>>#primGetModuleName */
EXPORT(sqInt)
primGetModuleName(void)
{
	sqInt strLen;
	sqInt strOop;

	/* missing DebugCode */;
	strLen = strlen(getModuleName());
	strOop = instantiateClassindexableSize(classString(), strLen);
	strncpy(firstIndexableField(strOop), getModuleName(), strLen);
	if (!(failed())) {
		popthenPush(1, strOop);
	}
	return null;
}

	/* LargeIntegersPlugin>>#primMontgomeryDigitLength */
EXPORT(sqInt)
primMontgomeryDigitLength(void)
{
	sqInt _return_value;

	/* missing DebugCode */;
	if (!(failed())) {
		_return_value = integerObjectOf(32);
		if (!(failed())) {
			popthenPush(1, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primMontgomeryTimes:modulo:mInvModB: */
EXPORT(sqInt)
primMontgomeryTimesModulo(void)
{
	unsigned long long accum;
	unsigned long long accum2;
	unsigned long long accum3;
	sqInt firstInteger;
	sqInt firstLarge;
	sqInt firstLen;
	sqInt i;
	sqInt k;
	unsigned int lastDigit;
	sqInt limit1;
	sqInt limit2;
	sqInt limit3;
	unsigned int mInv;
	sqInt mInverseInteger;
	unsigned int *pFirst;
	unsigned int *pRes;
	sqInt prod;
	unsigned int *pSecond;
	unsigned int *pThird;
	sqInt secondLarge;
	sqInt secondLen;
	sqInt secondOperandInteger;
	sqInt thirdLarge;
	sqInt thirdLen;
	sqInt thirdModuloInteger;
	unsigned long long u;
	sqInt _return_value;

	if (!((isKindOfInteger(stackValue(2)))
		 && ((isKindOfInteger(stackValue(1)))
		 && (isKindOfInteger(stackValue(0)))))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondOperandInteger = stackValue(2);
	thirdModuloInteger = stackValue(1);
	mInverseInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(3)));
	firstInteger = stackValue(3);
	if (failed()) {
		return null;
	}
	mInv = positive32BitValueOf(mInverseInteger);
	if (isIntegerObject(firstInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		firstLarge = createLargeFromSmallInteger(firstInteger);

#else /* SPURVM */
		pushRemappableOop(secondOperandInteger);
		pushRemappableOop(thirdModuloInteger);
		firstLarge = createLargeFromSmallInteger(firstInteger);
		thirdModuloInteger = popRemappableOop();
		secondOperandInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		firstLarge = firstInteger;
	}
	if (isIntegerObject(secondOperandInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		secondLarge = createLargeFromSmallInteger(secondOperandInteger);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		pushRemappableOop(thirdModuloInteger);
		secondLarge = createLargeFromSmallInteger(secondOperandInteger);
		thirdModuloInteger = popRemappableOop();
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		secondLarge = secondOperandInteger;
	}
	if (isIntegerObject(thirdModuloInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		thirdLarge = createLargeFromSmallInteger(thirdModuloInteger);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		pushRemappableOop(secondLarge);
		thirdLarge = createLargeFromSmallInteger(thirdModuloInteger);
		secondLarge = popRemappableOop();
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		thirdLarge = thirdModuloInteger;
	}
	if (!(failed())) {
		/* begin digitMontgomery:times:modulo:mInvModB: */
		firstLen = ((slotSizeOf(firstLarge)) + 3) / 4;
		secondLen = ((slotSizeOf(secondLarge)) + 3) / 4;
		thirdLen = ((slotSizeOf(thirdLarge)) + 3) / 4;
		if (!((firstLen <= thirdLen)
			 && (secondLen <= thirdLen))) {
			_return_value = primitiveFail();
			goto l2;
		}
		
#if SPURVM
		prod = instantiateClassindexableSize(classLargePositiveInteger(), thirdLen * 4);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		pushRemappableOop(secondLarge);
		pushRemappableOop(thirdLarge);
		prod = instantiateClassindexableSize(classLargePositiveInteger(), thirdLen * 4);
		thirdLarge = popRemappableOop();
		secondLarge = popRemappableOop();
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
		if (!(prod)) {
			_return_value = primitiveFailFor(PrimErrNoMemory);
			goto l2;
		}
		/* begin cDigitMontgomery:len:times:len:modulo:len:mInvModB:into: */
		pFirst = ((unsigned int *) (firstIndexableField(firstLarge)));
		pSecond = ((unsigned int *) (firstIndexableField(secondLarge)));
		pThird = ((unsigned int *) (firstIndexableField(thirdLarge)));
		pRes = ((unsigned int *) (firstIndexableField(prod)));
		limit1 = firstLen - 1;
		limit2 = secondLen - 1;
		limit3 = thirdLen - 1;
		lastDigit = 0;
		for (i = 0; i <= limit1; i += 1) {
			accum3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFirst[i]));
			accum3 = (accum3 * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pSecond[0])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[0])));
			u = (accum3 * mInv) & 0xFFFFFFFFU;
			accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[0])));
			accum = (accum2 & 0xFFFFFFFFU) + (accum3 & 0xFFFFFFFFU);
			accum = ((accum >> 32) + (accum2 >> 32)) + (accum3 >> 32);
			for (k = 1; k <= limit2; k += 1) {
				accum3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFirst[i]));
				accum3 = (accum3 * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pSecond[k])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])));
				accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
				accum = (accum + (accum2 & 0xFFFFFFFFU)) + (accum3 & 0xFFFFFFFFU);
				pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
				accum = ((accum >> 32) + (accum2 >> 32)) + (accum3 >> 32);
			}
			for (k = secondLen; k <= limit3; k += 1) {
				accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
				accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])))) + (accum2 & 0xFFFFFFFFU);
				pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
				accum = (accum >> 32) + (accum2 >> 32);
			}
			accum += lastDigit;
			pRes[limit3] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			lastDigit = accum >> 32;
		}
		for (i = firstLen; i <= limit3; i += 1) {
			accum = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[0]));
			u = (accum * mInv) & 0xFFFFFFFFU;
			accum += u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[0])));
			accum = accum >> 32;
			for (k = 1; k <= limit3; k += 1) {
				accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
				accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])))) + (accum2 & 0xFFFFFFFFU);
				pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
				accum = (accum >> 32) + (accum2 >> 32);
			}
			accum += lastDigit;
			pRes[limit3] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			lastDigit = accum >> 32;
		}
		if (!((lastDigit == 0)
			 && ((cDigitComparewithlen(pThird, pRes, thirdLen)) == 1))) {

			/* self cDigitSub: pThird len: thirdLen with: pRes len: thirdLen into: pRes */
			accum = 0;
			for (i = 0; i <= limit3; i += 1) {
				accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[i])))) - (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[i])));
				pRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
				accum = 0 - (accum >> 0x3F);
			}
		}
		_return_value = normalizePositive(prod);
	l2:	/* end digitMontgomery:times:modulo:mInvModB: */;
		if (!(failed())) {
			popthenPush(4, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primNormalizeNegative */
EXPORT(sqInt)
primNormalizeNegative(void)
{
	sqInt rcvr;
	sqInt _return_value;

	/* missing DebugCode */;
	success(isLargeNegativeIntegerObject(stackValue(0)));
	rcvr = stackValue(0);
	if (failed()) {
		return null;
	}
	if (!(failed())) {
		_return_value = normalizeNegative(rcvr);
		if (!(failed())) {
			popthenPush(1, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primNormalizePositive */
EXPORT(sqInt)
primNormalizePositive(void)
{
	sqInt rcvr;
	sqInt _return_value;

	/* missing DebugCode */;
	success(isLargePositiveIntegerObject(stackValue(0)));
	rcvr = stackValue(0);
	if (failed()) {
		return null;
	}
	if (!(failed())) {
		_return_value = normalizePositive(rcvr);
		if (!(failed())) {
			popthenPush(1, _return_value);
		}
	}
	return null;
}


/*	Note: This is coded so that it can be run in Squeak. */

	/* InterpreterPlugin>>#setInterpreter: */
EXPORT(sqInt)
setInterpreter(struct VirtualMachine *anInterpreter)
{
	sqInt ok;

	interpreterProxy = anInterpreter;
	ok = ((interpreterProxy->majorVersion()) == (VM_PROXY_MAJOR))
	 && ((interpreterProxy->minorVersion()) >= (VM_PROXY_MINOR));
	if (ok) {
		
#if !defined(SQUEAK_BUILTIN_PLUGIN)
		booleanValueOf = interpreterProxy->booleanValueOf;
		classArray = interpreterProxy->classArray;
		classLargeNegativeInteger = interpreterProxy->classLargeNegativeInteger;
		classLargePositiveInteger = interpreterProxy->classLargePositiveInteger;
		classString = interpreterProxy->classString;
		failed = interpreterProxy->failed;
		falseObject = interpreterProxy->falseObject;
		fetchClassOf = interpreterProxy->fetchClassOf;
		firstIndexableField = interpreterProxy->firstIndexableField;
		instantiateClassindexableSize = interpreterProxy->instantiateClassindexableSize;
		integerObjectOf = interpreterProxy->integerObjectOf;
		integerValueOf = interpreterProxy->integerValueOf;
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 15)
		isBooleanObject = interpreterProxy->isBooleanObject;
#else
#if !defined(isBooleanObject)
		isBooleanObject = 0;
#endif
#endif
		isIntegerObject = interpreterProxy->isIntegerObject;
		popthenPush = interpreterProxy->popthenPush;
		popRemappableOop = interpreterProxy->popRemappableOop;
		positive32BitValueOf = interpreterProxy->positive32BitValueOf;
		primitiveFail = interpreterProxy->primitiveFail;
		primitiveFailFor = interpreterProxy->primitiveFailFor;
		pushRemappableOop = interpreterProxy->pushRemappableOop;
		slotSizeOf = interpreterProxy->slotSizeOf;
		stObjectatput = interpreterProxy->stObjectatput;
		stackIntegerValue = interpreterProxy->stackIntegerValue;
		stackValue = interpreterProxy->stackValue;
		success = interpreterProxy->success;
		trueObject = interpreterProxy->trueObject;
#endif /* !defined(SQUEAK_BUILTIN_PLUGIN) */
	}
	return ok;
}

/*	Argument bytesObj must not be aSmallInteger! */

	/* LargeIntegersPlugin>>#unsafeByteOfLargeInt:at: */
static unsigned char
unsafeByteOfLargeIntat(sqInt bytesObj, sqInt ix)
{
	return (((unsigned char *) (firstIndexableField(bytesObj))))[ix - 1];
}


#ifdef SQUEAK_BUILTIN_PLUGIN

static char _m[] = "LargeIntegers";
void* LargeIntegers_exports[][3] = {
	{(void*)_m, "getModuleName", (void*)getModuleName},
	{(void*)_m, "primAnyBitFromTo\000\001", (void*)primAnyBitFromTo},
	{(void*)_m, "primDigitAdd\000\001", (void*)primDigitAdd},
	{(void*)_m, "primDigitBitAnd\000\001", (void*)primDigitBitAnd},
	{(void*)_m, "primDigitBitOr\000\001", (void*)primDigitBitOr},
	{(void*)_m, "primDigitBitShiftMagnitude\000\003", (void*)primDigitBitShiftMagnitude},
	{(void*)_m, "primDigitBitXor\000\001", (void*)primDigitBitXor},
	{(void*)_m, "primDigitCompare\000\000", (void*)primDigitCompare},
	{(void*)_m, "primDigitDivNegative\000\002", (void*)primDigitDivNegative},
	{(void*)_m, "primDigitMultiplyNegative\000\001", (void*)primDigitMultiplyNegative},
	{(void*)_m, "primDigitSubtract\000\001", (void*)primDigitSubtract},
	{(void*)_m, "primGetModuleName\000\377", (void*)primGetModuleName},
	{(void*)_m, "primMontgomeryDigitLength\000\377", (void*)primMontgomeryDigitLength},
	{(void*)_m, "primMontgomeryTimesModulo\000\001", (void*)primMontgomeryTimesModulo},
	{(void*)_m, "primNormalizeNegative\000\001", (void*)primNormalizeNegative},
	{(void*)_m, "primNormalizePositive\000\001", (void*)primNormalizePositive},
	{(void*)_m, "setInterpreter", (void*)setInterpreter},
	{NULL, NULL, NULL}
};

#else /* ifdef SQ_BUILTIN_PLUGIN */

EXPORT(signed char) primAnyBitFromToAccessorDepth = 1;
EXPORT(signed char) primDigitAddAccessorDepth = 1;
EXPORT(signed char) primDigitBitAndAccessorDepth = 1;
EXPORT(signed char) primDigitBitOrAccessorDepth = 1;
EXPORT(signed char) primDigitBitShiftMagnitudeAccessorDepth = 3;
EXPORT(signed char) primDigitBitXorAccessorDepth = 1;
EXPORT(signed char) primDigitCompareAccessorDepth = 0;
EXPORT(signed char) primDigitDivNegativeAccessorDepth = 2;
EXPORT(signed char) primDigitMultiplyNegativeAccessorDepth = 1;
EXPORT(signed char) primDigitSubtractAccessorDepth = 1;
EXPORT(signed char) primMontgomeryTimesModuloAccessorDepth = 1;
EXPORT(signed char) primNormalizeNegativeAccessorDepth = 1;
EXPORT(signed char) primNormalizePositiveAccessorDepth = 1;

#endif /* ifdef SQ_BUILTIN_PLUGIN */
