Skip to content

Commit

Permalink
Add primitiveCopyFromTo
Browse files Browse the repository at this point in the history
  • Loading branch information
blairmcg committed Jun 12, 2018
1 parent 90531df commit 711e508
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 25 deletions.
7 changes: 4 additions & 3 deletions Interprt.h
Expand Up @@ -659,6 +659,7 @@ class Interpreter
static Oop* __fastcall primitiveIndirectReplaceBytes(Oop* const sp, unsigned argCount);
static Oop* __fastcall primitiveReplacePointers(Oop* const sp, unsigned argCount);
static Oop* __fastcall primitiveStringConcatenate(Oop* const sp, unsigned argCount);
static Oop* __fastcall primitiveCopyFromTo(Oop* const sp, unsigned argCount);

static Oop* __fastcall primitiveHashBytes(Oop* const sp, unsigned argCount);
static Oop* __fastcall primitiveStringSearch(Oop* const sp, unsigned argCount);
Expand All @@ -670,9 +671,9 @@ class Interpreter
static Oop* __fastcall primitiveStringEqual(Oop* const sp, unsigned argCount);
static Oop* __fastcall primitiveBytesEqual(Oop* const sp, unsigned argCount);

static Oop* __fastcall Interpreter::primitiveStringAsUtf16String(Oop* const sp, unsigned argCount);
static Oop* __fastcall Interpreter::primitiveStringAsUtf8String(Oop* const sp, unsigned argCount);
static Oop* __fastcall Interpreter::primitiveStringAsByteString(Oop* const sp, unsigned argCount);
static Oop* __fastcall primitiveStringAsUtf16String(Oop* const sp, unsigned argCount);
static Oop* __fastcall primitiveStringAsUtf8String(Oop* const sp, unsigned argCount);
static Oop* __fastcall primitiveStringAsByteString(Oop* const sp, unsigned argCount);

// Stream Primitives
static Oop* __fastcall primitiveNext(Oop* const sp, unsigned argCount);
Expand Down
2 changes: 1 addition & 1 deletion PrimitivesTable.cpp
Expand Up @@ -53,7 +53,7 @@ Interpreter::PrimitiveFp Interpreter::primitivesTable[256] = {
Interpreter::primitiveFloatEqual , // case 47 Float>>#= in Smalltalk-80
Interpreter::primitiveAsyncDLL32CallThunk , // case 48 Float>>#~= in Smalltalk-80
Interpreter::unusedPrimitive , // case 49 Float>>#* in Smalltalk-80
Interpreter::unusedPrimitive , // case 50 Float>>#/ in Smalltalk-80
Interpreter::primitiveCopyFromTo , // case 50 Float>>#/ in Smalltalk-80
Interpreter::primitiveStringCmp , // case 51 Float>>#truncated
Interpreter::primitiveStringNextIndexOfFromTo , // case 52 Float>>#fractionPart in Smalltalk-80
Interpreter::primitiveQuo , // case 53 Float>>#exponent in Smalltalk-80
Expand Down
108 changes: 107 additions & 1 deletion alloc.cpp
Expand Up @@ -388,14 +388,18 @@ template <bool MaybeZ, bool Initialized> BytesOTE* ObjectMemory::newByteObject(B

switch (reinterpret_cast<const StringClass&>(byteClass).Encoding)
{
case StringEncoding::Ansi:
case StringEncoding::Utf8:
objectSize = elementCount * sizeof(AnsiString::CU);
break;
case StringEncoding::Utf16:
objectSize = elementCount * sizeof(Utf16String::CU);
break;
case StringEncoding::Utf32:
objectSize = elementCount * sizeof(Utf32String::CU);
break;
default:
objectSize = elementCount * sizeof(AnsiString::CU);
__assume(false);
break;
}

Expand All @@ -416,6 +420,11 @@ template <bool MaybeZ, bool Initialized> BytesOTE* ObjectMemory::newByteObject(B
ZeroMemory(newBytes->m_fields, _ROUND2(objectSize, sizeof(DWORD)));
classPointer->countUp();
}
else
{
// We still want to ensure the null terminator is set, even if not initializing the rest of the object
*reinterpret_cast<NULLTERMTYPE*>(&newBytes->m_fields[objectSize - NULLTERMSIZE]) = 0;
}

ote->m_oteClass = classPointer;
ote->beNullTerminated();
Expand Down Expand Up @@ -458,6 +467,103 @@ Oop* __fastcall Interpreter::primitiveNewPinned(Oop* const sp, unsigned)
}
}

OTE* ObjectMemory::CopyElements(OTE* oteObj, MWORD startingAt, MWORD count)
{
// Note that startingAt is expected to be a zero-based index
ASSERT(startingAt >= 0);
OTE* oteSlice;

if (oteObj->isBytes())
{
BytesOTE* oteBytes = reinterpret_cast<BytesOTE*>(oteObj);
size_t elementSize = ObjectMemory::GetBytesElementSize(oteBytes);

if (count == 0 || ((startingAt + count) * elementSize <= oteBytes->bytesSize()))
{
MWORD objectSize = elementSize * count;

if (oteBytes->m_flags.m_weakOrZ)
{
// TODO: Allocate the correct number of null term bytes based on the encoding
auto newBytes = static_cast<VariantByteObject*>(allocObject(objectSize + NULLTERMSIZE, oteSlice));
// When copying strings, the slices has the same string class
(oteSlice->m_oteClass = oteBytes->m_oteClass)->countUp();
memcpy(newBytes->m_fields, oteBytes->m_location->m_fields + (startingAt * elementSize), objectSize);
*reinterpret_cast<NULLTERMTYPE*>(&newBytes->m_fields[objectSize]) = 0;
oteSlice->beNullTerminated();
return oteSlice;
}
else
{
VariantByteObject* newBytes = static_cast<VariantByteObject*>(allocObject(objectSize, oteSlice));
// When copying bytes, the slice is always a ByteArray
oteSlice->m_oteClass = Pointers.ClassByteArray;
oteSlice->beBytes();
memcpy(newBytes->m_fields, oteBytes->m_location->m_fields + (startingAt * elementSize), objectSize);
return oteSlice;
}
}
}
else
{
// Pointers
PointersOTE* otePointers = reinterpret_cast<PointersOTE*>(oteObj);
BehaviorOTE* oteClass = otePointers->m_oteClass;
InstanceSpecification instSpec = oteClass->m_location->m_instanceSpec;
startingAt += instSpec.m_fixedFields;

if (count == 0 || (startingAt + count) <= otePointers->pointersSize())
{
MWORD objectSize = SizeOfPointers(count);
auto pSlice = static_cast<VariantObject*>(allocObject(objectSize, oteSlice));
// When copying pointers, the slice is always an Array
oteSlice->m_oteClass = Pointers.ClassArray;
VariantObject* pSrc = otePointers->m_location;
for (MWORD i = 0; i < count; i++)
{
countUp(pSlice->m_fields[i] = pSrc->m_fields[startingAt + i]);
}
return oteSlice;
}
}

return nullptr;
}

Oop* Interpreter::primitiveCopyFromTo(Oop* const sp, unsigned)
{
Oop oopToArg = *sp;
Oop oopFromArg = *(sp - 1);
OTE* oteReceiver = reinterpret_cast<OTE*>(*(sp - 2));
if (ObjectMemoryIsIntegerObject(oopToArg) && ObjectMemoryIsIntegerObject(oopFromArg))
{
SMALLINTEGER from = ObjectMemoryIntegerValueOf(oopFromArg);
SMALLINTEGER to = ObjectMemoryIntegerValueOf(oopToArg);

if (from > 0)
{
SMALLINTEGER count = to - from + 1;
if (count >= 0)
{
OTE* oteAnswer = ObjectMemory::CopyElements(oteReceiver, from - 1, count);
if (oteAnswer != nullptr)
{
*(sp - 2) = (Oop)oteAnswer;
ObjectMemory::AddToZct(oteAnswer);
return sp - 2;
}
}
}
// Bounds error
return primitiveFailure(1);
}
else
{
// Non-SmallInteger from and/or to
return primitiveFailure(0);
}
}

BytesOTE* __fastcall ObjectMemory::shallowCopy(BytesOTE* ote)
{
ASSERT(ote->isBytes());
Expand Down
24 changes: 23 additions & 1 deletion objmem.h
Expand Up @@ -84,7 +84,7 @@ class ObjectMemory
static ArrayOTE* __stdcall referencesTo(Oop referencedObjectPointer, bool includeWeakRefs);
static ArrayOTE* __fastcall instancesOf(BehaviorOTE* classPointer);
static ArrayOTE* __fastcall subinstancesOf(BehaviorOTE* classPointer);
static ArrayOTE* __fastcall ObjectMemory::instanceCounts(ArrayOTE* oteClasses);
static ArrayOTE* __fastcall instanceCounts(ArrayOTE* oteClasses);
static void deallocateByteObject(OTE*);

// Class pointer access
Expand All @@ -105,6 +105,7 @@ class ObjectMemory
template <bool MaybeZ, bool Initialize> static BytesOTE* newByteObject(BehaviorOTE* classPointer, MWORD instanceByteSize);
template <class T> static TOTE<T>* newUninitializedNullTermObject(MWORD instanceByteSize);
static BytesOTE* __fastcall newByteObject(BehaviorOTE* classPointer, MWORD instanceByteSize, const void* pBytes);
static OTE* CopyElements(OTE* oteObj, MWORD startingAt, MWORD countfrom);

// Resizing objects (RAW - assumes no. ref counting to be done)
template <size_t extra> static POBJECT basicResize(OTE* ote, size_t byteSize /*should include header*/);
Expand Down Expand Up @@ -1097,3 +1098,24 @@ inline ArrayOTE* ST::Array::NewUninitialized(unsigned size)
return reinterpret_cast<ArrayOTE*>(ObjectMemory::newUninitializedPointerObject(Pointers.ClassArray, size));
}

///////////////////////////////////////////////////////////////////////////////

#include "STClassDesc.h"

inline size_t ObjectMemory::GetBytesElementSize(BytesOTE* ote)
{
ASSERT(ote->isBytes());

// TODO: Should be using revised InstanceSpec here, not string encoding
if (ote->m_flags.m_weakOrZ)
{
switch (reinterpret_cast<const StringClass*>(ote->m_oteClass->m_location)->Encoding)
{
case StringEncoding::Utf16:
return sizeof(uint16_t);
case StringEncoding::Utf32:
return sizeof(uint32_t);
}
}
return sizeof(uint8_t);
}
19 changes: 0 additions & 19 deletions primitiv.cpp
Expand Up @@ -111,25 +111,6 @@ Oop* __fastcall Interpreter::primitiveIdentical(Oop* const sp, unsigned)
return sp - 1;
}


size_t ObjectMemory::GetBytesElementSize(BytesOTE* ote)
{
ASSERT(ote->isBytes());

// TODO: Should be using revised InstanceSpec here, not string encoding
if (ote->m_flags.m_weakOrZ)
{
switch (reinterpret_cast<const StringClass*>(ote->m_oteClass->m_location)->Encoding)
{
case StringEncoding::Utf16:
return sizeof(uint16_t);
case StringEncoding::Utf32:
return sizeof(uint32_t);
}
}
return sizeof(uint8_t);
}

// This primitive is unusual(like primitiveClass) in that it cannot fail
// Essentially same code as shortSpecialSendBasicSize
Oop* __fastcall Interpreter::primitiveSize(Oop* const sp, unsigned)
Expand Down

0 comments on commit 711e508

Please sign in to comment.