Exemple #1
0
// Uses object identity to locate the next occurrence of the argument in the receiver from
// the specified index to the specified index
Oop* __fastcall Interpreter::primitiveStringSearch()
{
	Oop* const sp = m_registers.m_stackPointer;
	Oop integerPointer = *sp;
	if (!ObjectMemoryIsIntegerObject(integerPointer))
		return primitiveFailure(0);				// startingAt not an integer
	const SMALLINTEGER startingAt = ObjectMemoryIntegerValueOf(integerPointer);

	Oop oopSubString = *(sp-1);
	BytesOTE* oteReceiver = reinterpret_cast<BytesOTE*>(*(sp-2));

	if (ObjectMemory::fetchClassOf(oopSubString) != oteReceiver->m_oteClass)
		return primitiveFailure(2);

	// We know it can't be a SmallInteger because it has the same class as the receiver
	BytesOTE* oteSubString = reinterpret_cast<BytesOTE*>(oopSubString);

	VariantByteObject* bytesPattern = oteSubString->m_location;
	VariantByteObject* bytesReceiver = oteReceiver->m_location;
	const int M = oteSubString->bytesSize();
	const int N = oteReceiver->bytesSize();

	// Check 'startingAt' is in range
	if (startingAt < 1 || startingAt > N)
		return primitiveFailure(1);	// out of bounds

	int nOffset = M == 0 || ((startingAt + M) - 1 > N)
					? -1 
					: stringSearch(bytesReceiver->m_fields, N, bytesPattern->m_fields, M, startingAt - 1);
	
	*(sp-2) = ObjectMemoryIntegerObjectOf(nOffset+1);
	return sp-2;
}
Exemple #2
0
// Locate the next occurrence of the given character in the receiver between the specified indices.
BOOL __fastcall Interpreter::primitiveStringNextIndexOfFromTo()
{
	Oop integerPointer = stackTop();
	if (!ObjectMemoryIsIntegerObject(integerPointer))
		return primitiveFailure(0);				// to not an integer
	const SMALLINTEGER to = ObjectMemoryIntegerValueOf(integerPointer);

	integerPointer = stackValue(1);
	if (!ObjectMemoryIsIntegerObject(integerPointer))
		return primitiveFailure(1);				// from not an integer
	SMALLINTEGER from = ObjectMemoryIntegerValueOf(integerPointer);

	Oop valuePointer = stackValue(2);

	StringOTE* receiverPointer = reinterpret_cast<StringOTE*>(stackValue(3));

	Oop answer = ZeroPointer;
	if ((ObjectMemory::fetchClassOf(valuePointer) == Pointers.ClassCharacter) && to >= from)
	{
		ASSERT(!receiverPointer->isPointers());

		// Search a byte object

		const SMALLINTEGER length = receiverPointer->bytesSize();
		// We can only be in here if to>=from, so if to>=1, then => from >= 1
		// furthermore if to <= length then => from <= length
		if (from < 1 || to > length)
			return primitiveFailure(2);

		// Search is in bounds, lets do it
		CharOTE* oteChar = reinterpret_cast<CharOTE*>(valuePointer);
		Character* charObj = oteChar->m_location;
		const char charValue = static_cast<char>(ObjectMemoryIntegerValueOf(charObj->m_asciiValue));

		String* chars = receiverPointer->m_location;

		from--;
		while (from < to)
		{
			if (chars->m_characters[from++] == charValue)
			{
				answer = ObjectMemoryIntegerObjectOf(from);
				break;
			}
		}
	}

	stackValue(3) = answer;
	pop(3);
	return primitiveSuccess();
}
Exemple #3
0
// This primitive handles PositionableStream>>nextSDWORD, but only for byte-arrays
// Unary message, so does not modify stack pointer
BOOL __fastcall Interpreter::primitiveNextSDWORD()
{
	PosStreamOTE* streamPointer = reinterpret_cast<PosStreamOTE*>(stackTop());		// Access receiver
	PositionableStream* readStream = streamPointer->m_location;

	// Ensure valid stream - unusually this validity check is included in the Blue Book spec
	// and appears to be implemented in most Smalltalks, so we implement here too.
	if (!ObjectMemoryIsIntegerObject(readStream->m_index) ||
		!ObjectMemoryIsIntegerObject(readStream->m_readLimit))
		return primitiveFailure(0);	// Receiver fails invariant check

	SMALLINTEGER index = ObjectMemoryIntegerValueOf(readStream->m_index);
	SMALLINTEGER limit = ObjectMemoryIntegerValueOf(readStream->m_readLimit);

	// Is the current index within the limits of the collection?
	// Remember that the index is 1 based (it's a Smalltalk index), and we're 0 based,
	// so we don't need to increment it until after we've got the next object
	if (index < 0 || index >= limit)
		return primitiveFailure(2);		// No, fail it

	OTE* oteBuf = readStream->m_array;
	BehaviorOTE* bufClass = oteBuf->m_oteClass;
	
	if (bufClass != Pointers.ClassByteArray)
		return primitiveFailure(1);		// Collection cannot be handled by primitive, rely on Smalltalk code

	ByteArrayOTE* oteBytes = reinterpret_cast<ByteArrayOTE*>(oteBuf);

	const int newIndex = index + sizeof(SDWORD);
	if (MWORD(newIndex) > oteBytes->bytesSize())
		return primitiveFailure(3);

	const Oop oopNewIndex = ObjectMemoryIntegerObjectOf(newIndex);
	if (int(oopNewIndex) < 0)
		return primitiveFailure(4);	// index overflowed SmallInteger range

	// When incrementing the index we must allow for it overflowing a SmallInteger, even though
	// this is extremely unlikely in practice
	readStream->m_index = oopNewIndex;

	// Receiver is overwritten
	ByteArray* byteArray = oteBytes->m_location;
	replaceStackTopWithNew(Integer::NewSigned32(*reinterpret_cast<SDWORD*>(byteArray->m_elements+index)));

	return primitiveSuccess();									// Succeed
}
Exemple #4
0
// Uses object identity to locate the next occurrence of the argument in the receiver from
// the specified index to the specified index
Oop* __fastcall Interpreter::primitiveNextIndexOfFromTo()
{
	Oop integerPointer = stackTop();
	if (!ObjectMemoryIsIntegerObject(integerPointer))
		return primitiveFailure(0);				// to not an integer
	const SMALLINTEGER to = ObjectMemoryIntegerValueOf(integerPointer);

	integerPointer = stackValue(1);
	if (!ObjectMemoryIsIntegerObject(integerPointer))
		return primitiveFailure(1);				// from not an integer
	SMALLINTEGER from = ObjectMemoryIntegerValueOf(integerPointer);

	Oop valuePointer = stackValue(2);
	OTE* receiverPointer = reinterpret_cast<OTE*>(stackValue(3));

//	#ifdef _DEBUG
		if (ObjectMemoryIsIntegerObject(receiverPointer))
			return primitiveFailure(2);				// Not valid for SmallIntegers
//	#endif

	Oop answer = ZeroPointer;
	if (to >= from)
	{
		if (!receiverPointer->isPointers())
		{
			// Search a byte object
			BytesOTE* oteBytes = reinterpret_cast<BytesOTE*>(receiverPointer);

			if (ObjectMemoryIsIntegerObject(valuePointer))// Arg MUST be an Integer to be a member
			{
				const MWORD byteValue = ObjectMemoryIntegerValueOf(valuePointer);
				if (byteValue < 256)	// Only worth looking for 0..255
				{
					const SMALLINTEGER length = oteBytes->bytesSize();
					// We can only be in here if to>=from, so if to>=1, then => from >= 1
					// furthermore if to <= length then => from <= length
					if (from < 1 || to > length)
						return primitiveFailure(2);

					// Search is in bounds, lets do it
			
					VariantByteObject* bytes = oteBytes->m_location;

					from--;
					while (from < to)
						if (bytes->m_fields[from++] == byteValue)
						{
							answer = ObjectMemoryIntegerObjectOf(from);
							break;
						}
				}
			}
		}
		else
		{
			// Search a pointer object - but only the indexable vars
			
			PointersOTE* oteReceiver = reinterpret_cast<PointersOTE*>(receiverPointer);
			VariantObject* receiver = oteReceiver->m_location;
			Behavior* behavior = receiverPointer->m_oteClass->m_location;
			const MWORD length = oteReceiver->pointersSize();
			const MWORD fixedFields = behavior->m_instanceSpec.m_fixedFields;

			// Similar reasoning with to/from as for byte objects, but here we need to
			// take account of the fixed fields.
			if (from < 1 || (to + fixedFields > length))
				return primitiveFailure(2);	// Out of bounds

			Oop* indexedFields = receiver->m_fields + fixedFields;
			from--;
			while (from < to)
				if (indexedFields[from++] == valuePointer)
				{
					answer = ObjectMemoryIntegerObjectOf(from);
					break;
				}
		}

	}
	else
		answer = ZeroPointer; 		// Range is non-inclusive, cannot be there

	stackValue(3) = answer;
	return primitiveSuccess(3);
}
Exemple #5
0
// This primitive handles PositionableStream>>next, but only for Arrays, Strings and ByteArrays
// Unary message, so does not modify stack pointer, and is therefore called directly from the ASM 
// primitive table without indirection through an ASM thunk.
BOOL __fastcall Interpreter::primitiveNext()
{
	PosStreamOTE* streamPointer = reinterpret_cast<PosStreamOTE*>(stackTop());		// Access receiver
	
	// Only works for subclasses of PositionableStream (or look alikes)
	//ASSERT(!ObjectMemoryIsIntegerObject(streamPointer) && ObjectMemory::isKindOf(streamPointer, Pointers.ClassPositionableStream));
	
	PositionableStream* readStream = streamPointer->m_location;
	
	// Ensure valid stream - unusually this validity check is included in the Blue Book spec
	// and appears to be implemented in most Smalltalks, so we implement here too.
	if (!ObjectMemoryIsIntegerObject(readStream->m_index) ||
		!ObjectMemoryIsIntegerObject(readStream->m_readLimit))
		return primitiveFailure(0);	// Receiver fails invariant check

	SMALLINTEGER index = ObjectMemoryIntegerValueOf(readStream->m_index);
	SMALLINTEGER limit = ObjectMemoryIntegerValueOf(readStream->m_readLimit);

	// Is the current index within the limits of the collection?
	// Remember that the index is 1 based (it's a Smalltalk index), and we're 0 based,
	// so we don't need to increment it until after we've got the next object
	if (index < 0 || index >= limit)
		return primitiveFailure(2);		// No, fail it

	OTE* oteBuf = readStream->m_array;
	BehaviorOTE* bufClass = oteBuf->m_oteClass;
	
	if (bufClass == Pointers.ClassString)
	{
		StringOTE* oteString = reinterpret_cast<StringOTE*>(oteBuf);

		// A sanity check - ensure within bounds of object too (again in Blue Book spec)
		if (MWORD(index) >= oteString->bytesSize())
			return primitiveFailure(3);

		String* buf = oteString->m_location;
		stackTop() = reinterpret_cast<Oop>(Character::New(buf->m_characters[index]));
	}
	// We also support ByteArrays in our primitiveNext (unlike BB).
	else if (bufClass == Pointers.ClassByteArray)
	{
		ByteArrayOTE* oteBytes = reinterpret_cast<ByteArrayOTE*>(oteBuf);

		if (MWORD(index) >= oteBytes->bytesSize())
			return primitiveFailure(3);

		ByteArray* buf = oteBytes->m_location;
		stackTop() = ObjectMemoryIntegerObjectOf(buf->m_elements[index]);
	}
	else if (bufClass == Pointers.ClassArray)
	{
		ArrayOTE* oteArray = reinterpret_cast<ArrayOTE*>(oteBuf);
		if (MWORD(index) >= oteArray->pointersSize())
			return primitiveFailure(3);

		Array* buf = oteArray->m_location;
		stackTop() = buf->m_elements[index];
	}
	else
		return primitiveFailure(1);		// Collection cannot be handled by primitive, rely on Smalltalk code
	
	// When incrementing the index we must allow for it overflowing a SmallInteger, even though
	// this is extremely unlikely in practice
	readStream->m_index = Integer::NewSigned32WithRef(index+1);

	return primitiveSuccess();									// Succeed
}
Exemple #6
0
void Process::PostLoadFix(ProcessOTE* oteThis)
{
	// Any overlapped call running when the image was saved is no longer valid, so
	// we must clear down the "pointer" and remove the back reference
	if (m_thread != reinterpret_cast<Oop>(Pointers.Nil))
	{
		m_thread = reinterpret_cast<Oop>(Pointers.Nil);
		oteThis->countDown();
	}

	// Patch any badly created or corrupted processes
	if (!ObjectMemoryIsIntegerObject(m_fpControl))
	{
		m_fpControl = ObjectMemoryIntegerObjectOf(_DN_SAVE | _RC_NEAR | _PC_64 | _EM_INEXACT | _EM_UNDERFLOW | _EM_OVERFLOW | _EM_DENORMAL);
	}

	Oop* pFramePointer = &m_suspendedFrame;
	Oop framePointer = *pFramePointer;
	const void* stackBase = m_stack;
	const void* stackEnd = reinterpret_cast<BYTE*>(this) + oteThis->getSize() - 1;

	// Wind down the stack adjusting references to self as we go
	// Start with the suspended context
	const int delta = m_callbackDepth - 1;
	while (isIntegerObject(framePointer) && framePointer != ZeroPointer)
	{
		framePointer += delta;
		if (framePointer < Oop(stackBase) || framePointer > Oop(stackEnd))
		{
			trace(L"Warning: Process at %#x has corrupt frame pointer at %#x which will be nilled\n", this, pFramePointer);
			*pFramePointer = Oop(Pointers.Nil);
			break;
		}
		else
			*pFramePointer += delta;

		StackFrame* pFrame = StackFrame::FromFrameOop(*pFramePointer);
		if (isIntegerObject(pFrame->m_bp))
		{
			pFrame->m_bp += delta;
		}

		ASSERT(reinterpret_cast<void*>(pFrame->m_bp) > stackBase && reinterpret_cast<void*>(pFrame->m_bp) < stackEnd);

		// If a stack only frame, then adjust the BP
		if (!isIntegerObject(pFrame->m_environment))
		{
			// The frame has an object context, we need to adjust
			// its back pointer to the frame if it is a MethodContext
			// The context objects contain no other addresses any more
			OTE* oteContext = reinterpret_cast<OTE*>(pFrame->m_environment);
			if (ObjectMemory::isAContext(oteContext))
			{
				Context* ctx = static_cast<Context*>(oteContext->m_location);
				if (isIntegerObject(ctx->m_frame) && ctx->m_frame != ZeroPointer)
				{
					ctx->m_frame += delta;
					ASSERT(reinterpret_cast<void*>(ctx->m_frame) > stackBase && reinterpret_cast<void*>(ctx->m_frame) < stackEnd);
				}
			}
		}

		// Adjust the contexts SP
		if (isIntegerObject(pFrame->m_sp))
		{
			pFrame->m_sp += delta;
			ASSERT(reinterpret_cast<void*>(pFrame->m_sp) >= stackBase && reinterpret_cast<void*>(pFrame->m_sp) <= stackEnd);
		}

		pFramePointer = &pFrame->m_caller;
		framePointer = *pFramePointer;
	}

	framePointer = SuspendedFrame();
	if (isIntegerObject(framePointer) && framePointer != ZeroPointer)
	{
		// The size of the process should exactly correspond with that required to
		// hold up to the SP of the suspended frame
		StackFrame* pFrame = StackFrame::FromFrameOop(framePointer);
		int size = (pFrame->m_sp - 1) - reinterpret_cast<DWORD>(this) + sizeof(Oop);
		if (size > 0 && unsigned(size) < oteThis->getSize())
		{
			TRACE(L"WARNING: Resizing process %p from %u to %u\n", oteThis, oteThis->getSize(), size);
			oteThis->setSize(size);
		}
	}
	// else its dead or not started yet

	// Later we'll use this slot to count the callback depth
	m_callbackDepth = ZeroPointer;
}