<file_sep>/*
 *
 *
Copyright (c) 2007 <NAME>, <NAME>, <NAME>
Software Architecture Group, Hasso Plattner Institute, Potsdam, Germany
http://www.hpi.uni-potsdam.de/swa/

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
  */


#include "VMFrame.h"
#include "VMMethod.h"
#include "VMObject.h"
#include "VMInteger.h"
#include "VMClass.h"
#include "VMSymbol.h"

#include "../vm/Universe.h"

//when doesNotUnderstand or UnknownGlobal is sent, additional stack slots might
//be necessary, as these cases are not taken into account when the stack
//depth is calculated. In that case this method is called.
pVMFrame VMFrame::EmergencyFrameFrom( pVMFrame from, int extraLength ) {
    int length = from->GetNumberOfIndexableFields() + extraLength;
    int additionalBytes = length * sizeof(pVMObject);
    pVMFrame result = new (_HEAP, additionalBytes) VMFrame(length);
    
    result->SetClass(from->GetClass());
    //copy arguments, locals and the stack
    from->CopyIndexableFieldsTo(result);

    //set Frame members
    result->SetPreviousFrame(from->GetPreviousFrame());
    result->SetMethod(from->GetMethod());
    result->SetContext(from->GetContext());
    result->stackPointer = from->GetStackPointer();
    result->bytecodeIndex = from->bytecodeIndex;
    result->localOffset = from->localOffset;

    return result;
}


const int VMFrame::VMFrameNumberOfFields = 6; 

VMFrame::VMFrame(int size, int nof) : VMArray(size, 
                                              nof + VMFrameNumberOfFields) {
    _HEAP->StartUninterruptableAllocation();
    this->localOffset = _UNIVERSE->NewInteger(0);
    this->bytecodeIndex = _UNIVERSE->NewInteger(0);
    this->stackPointer = _UNIVERSE->NewInteger(0);
    _HEAP->EndUninterruptableAllocation();
}

pVMMethod VMFrame::GetMethod() const {
  
    return this->method;
}

void      VMFrame::SetMethod(pVMMethod method) {
    this->method = method;
}

bool     VMFrame::HasPreviousFrame() const {
    return this->previousFrame != nilObject;
}




bool     VMFrame::HasContext() const {
    return this->context !=  nilObject; 
}


pVMFrame VMFrame::GetContextLevel(int lvl) {
    pVMFrame current = this;
    while (lvl > 0) {
        current = current->GetContext();
        --lvl;
    }
    return current;
}


pVMFrame VMFrame::GetOuterContext() {
    pVMFrame current = this;
    while (current->HasContext()) {
        current = current->GetContext();
    }
    return current;
}



int VMFrame::RemainingStackSize() const {
    // - 1 because the stack pointer points at the top entry,
    // so the next entry would be put at stackPointer+1
    return this->GetNumberOfIndexableFields() - 
           stackPointer->GetEmbeddedInteger() - 1;
}

pVMObject VMFrame::Pop() {
    int32_t sp = this->stackPointer->GetEmbeddedInteger();
    this->stackPointer->SetEmbeddedInteger(sp-1);
    return (*this)[sp];
}


void      VMFrame::Push(pVMObject obj) {
    int32_t sp = this->stackPointer->GetEmbeddedInteger() + 1;
    this->stackPointer->SetEmbeddedInteger(sp);
    (*this)[sp] = obj; 
}


void VMFrame::PrintStack() const {
    cout << "SP: " << this->stackPointer->GetEmbeddedInteger() << endl;
    for (int i = 0; i < this->GetNumberOfIndexableFields()+1; ++i) {
        pVMObject vmo = (*this)[i];
        cout << i << ": ";
        if (vmo == NULL) 
            cout << "NULL" << endl;
        if (vmo == nilObject) 
            cout << "NIL_OBJECT" << endl;
        if (vmo->GetClass() == NULL) 
            cout << "VMObject with Class == NULL" << endl;
        if (vmo->GetClass() == nilObject) 
            cout << "VMObject with Class == NIL_OBJECT" << endl;
        else 
            cout << "index: " << i << " object:" 
                 << vmo->GetClass()->GetName()->GetChars() << endl;
    }
}


void      VMFrame::ResetStackPointer() {
    // arguments are stored in front of local variables
    pVMMethod meth = this->GetMethod();
    size_t lo = meth->GetNumberOfArguments();
    this->localOffset->SetEmbeddedInteger(lo);
  
    // Set the stack pointer to its initial value thereby clearing the stack
    size_t numLocals = meth->GetNumberOfLocals();
    this->stackPointer->SetEmbeddedInteger(lo + numLocals - 1);
}


int       VMFrame::GetBytecodeIndex() const {
    return this->bytecodeIndex->GetEmbeddedInteger();
}


void      VMFrame::SetBytecodeIndex(int index) {
    this->bytecodeIndex->SetEmbeddedInteger(index);
}


pVMObject VMFrame::GetStackElement(int index) const {
    int sp = this->stackPointer->GetEmbeddedInteger();
    return (*this)[sp-index];
}


void      VMFrame::SetStackElement(int index, pVMObject obj) {
    int sp = this->stackPointer->GetEmbeddedInteger();
    (*this)[sp-index] = obj; 
}


pVMObject VMFrame::GetLocal(int index, int contextLevel) {
    pVMFrame context = this->GetContextLevel(contextLevel);
    int32_t lo = context->localOffset->GetEmbeddedInteger();
    return (*context)[lo+index];
}


void      VMFrame::SetLocal(int index, int contextLevel, pVMObject value) {
    pVMFrame context = this->GetContextLevel(contextLevel);
    size_t lo = context->localOffset->GetEmbeddedInteger();
    (*context)[lo+index] = value; 
}



pVMObject VMFrame::GetArgument(int index, int contextLevel) {
    // get the context
    pVMFrame context = this->GetContextLevel(contextLevel);
    return (*context)[index];
}


void      VMFrame::SetArgument(int index, int contextLevel, pVMObject value) {
    pVMFrame context = this->GetContextLevel(contextLevel);
    (*context)[index] = value; 
}


void      VMFrame::PrintStackTrace() const {
    //TODO
}

int       VMFrame::ArgumentStackIndex(int index) const {
    pVMMethod meth = this->GetMethod();
    return meth->GetNumberOfArguments() - index - 1;
}


void      VMFrame::CopyArgumentsFrom(pVMFrame frame) {
    // copy arguments from frame:
    // - arguments are at the top of the stack of frame.
    // - copy them into the argument area of the current frame
    pVMMethod meth = this->GetMethod();
    int num_args = meth->GetNumberOfArguments();
    for(int i=0; i < num_args; ++i) {
        pVMObject stackElem = frame->GetStackElement(num_args - 1 - i);
        (*this)[i] = stackElem;
    }
}


void VMFrame::MarkReferences() {
    if (gcfield) return;
     VMArray::MarkReferences();
}
<file_sep># SOM++
This project is for SOM++ project on Mac. The target of this project is to enable the 64bit mode works on mac.
Base code is coming from http://www.hpi.uni-potsdam.de/hirschfeld/projects/som/

<file_sep>/*
 *
 *
Copyright (c) 2007 <NAME>, <NAME>, <NAME>
Software Architecture Group, Hasso Plattner Institute, Potsdam, Germany
http://www.hpi.uni-potsdam.de/swa/

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
  */


#include <iostream>
#include <stdlib.h>
#include <string.h>

#include "Heap.h"

#include "../vmobjects/VMObject.h"
#include "../vmobjects/VMFreeObject.h"

#include "../vm/Universe.h"

/*
 * macro for padding - only word-aligned memory must be allocated
 */
#define PAD_BYTES(N) ((sizeof(void*) - ((N) % sizeof(void*))) % sizeof(void*))

Heap* Heap::theHeap = NULL;

Heap* Heap::GetHeap() {
    if (!theHeap) {
        _UNIVERSE->ErrorExit("Trying to access uninitialized Heap");
    }
    return theHeap;
}

void Heap::InitializeHeap( int objectSpaceSize ) {
    if (theHeap) {
        cout << "Warning, reinitializing already initialized Heap, " 
             << "all data will be lost!" << endl;
        delete theHeap;
    }
    theHeap = new Heap(objectSpaceSize);
}

void Heap::DestroyHeap() {
    if (theHeap) delete theHeap;
}



Heap::Heap(int objectSpaceSize) {
	objectSpace = malloc(objectSpaceSize);
	if (!objectSpace) {
		std::cout << "Failed to allocate the initial "<< objectSpaceSize 
                  << " bytes for the Heap. Panic.\n" << std::endl;
		exit(1);
	}
	memset(objectSpace, 0, objectSpaceSize);
	sizeOfFreeHeap = objectSpaceSize;
	this->objectSpaceSize = objectSpaceSize;
	this->buffersizeForUninterruptable = (int) (objectSpaceSize * 0.1);
    
    uninterruptableCounter = 0;
	numAlloc = 0;
    spcAlloc = 0;
    numAllocTotal = 0;
    freeListStart = (VMFreeObject*) objectSpace;
    freeListStart->SetObjectSize(objectSpaceSize);
    freeListStart->SetNext(NULL);
    freeListStart->SetPrevious(NULL);
    freeListStart->SetGCField(-1);
	/*freeListStart = (FreeListEntry*) objectSpace;
	freeListStart->size = objectSpaceSize;
	freeListStart->next = NULL;*/
	gc = new GarbageCollector(this);
}

Heap::~Heap() {
    if (gcVerbosity > 0) {
        cout << "-- Heap statistics --" << endl;
        cout << "Total number of allocations: " << numAllocTotal << endl;
        cout << "Number of allocations since last collection: " 
             << numAlloc << endl;
        std::streamsize p = cout.precision();
        cout.precision(3);
        cout << "Used memory: " << spcAlloc << "/" 
             << this->objectSpaceSize << " (" 
             << ((double)spcAlloc/(double)this->objectSpaceSize)*100 << "%)" << endl;
        cout.precision(p);
        gc->PrintGCStat();
    }
	free(objectSpace);
    
}

VMObject* Heap::AllocateObject(size_t size) {
    //add padding, so objects are word aligned
    size_t paddedSize = size + PAD_BYTES(size);
    VMObject* vmo = (VMObject*) Allocate(paddedSize);

    ++numAlloc;
    ++numAllocTotal;
    spcAlloc += paddedSize;
    return vmo;
}

void* Heap::Allocate(size_t size) {
	if (size == 0) return NULL;
    if (size < sizeof(VMObject))  {
        //this will never happen, as all allocation is done for VMObjects
        return internalAllocate(size);
    }
#ifdef HEAPDEBUG 
    std::cout << "allocating: " << (int)size << "bytes" << std::endl;
#endif
    //if there is not enough free heap size and we are not inside an uninterruptable
    //section of allocation, start garbage collection
	if (sizeOfFreeHeap <= buffersizeForUninterruptable &&
		uninterruptableCounter <= 0)  {
#ifdef HEAPDEBUG
        cout << "Not enough free memory, only: " << sizeOfFreeHeap 
             << " bytes left." << endl
             << "Starting Garbage Collection" << endl;
#endif
		gc->Collect();
        
        //
        //reset allocation stats
        //
        numAlloc = 0;
        spcAlloc = 0;
	}
	
	VMObject* result = NULL;
    VMFreeObject* cur = freeListStart;
    VMFreeObject* last = NULL;
    while(cur->GetObjectSize() != size &&
          cur->GetObjectSize() < size+sizeof(VMObject) &&
          cur->GetNext() != NULL) {
              last = cur;
              cur = cur->GetNext();
    }
    if (cur->GetObjectSize() == size) {
        //perfect fit
        if (cur == freeListStart) {
            freeListStart = cur->GetNext();
            freeListStart->SetPrevious(NULL);
        } else {
            last->SetNext(cur->GetNext());
            cur->GetNext()->SetPrevious(last);
        }
        result = cur;
    } else if (cur->GetObjectSize() >= size + sizeof(VMFreeObject)) {
        //found an entry that is big enough
        int oldSize = cur->GetObjectSize();
        VMFreeObject* oldNext = cur->GetNext();
        result = cur;
        VMFreeObject* replaceEntry = (VMFreeObject*) ((uintptr_t)cur + size);
        replaceEntry->SetObjectSize(oldSize - size);
        replaceEntry->SetGCField(-1);
        replaceEntry->SetNext(oldNext);
        if (cur == freeListStart) {
            freeListStart = replaceEntry;
            freeListStart->SetPrevious(NULL);
        } else {
            last->SetNext(replaceEntry);
            replaceEntry->SetPrevious(last);
        }
    } else {
        //problem... might lose data here
        cout << "Not enough heap, data loss is possible" << endl;
        gc->Collect();
        this->numAlloc = 0;
        this->spcAlloc = 0;
        result = (VMObject*)this->Allocate(size);
    }

    if (result == NULL) {
        cout << "alloc failed" << endl;
        PrintFreeList();
        _UNIVERSE->ErrorExit("Failed to allocate");
    }

    memset((void *)result, 0, size);
    result->SetObjectSize(size);
    this->sizeOfFreeHeap -= size;

    return result;
    
}

void Heap::PrintFreeList() {
    VMFreeObject* curEntry = freeListStart;
    int i =0;
    while (curEntry != NULL) {
        cout << "i: " << curEntry->GetObjectSize() << endl;
        ++i;
        curEntry = curEntry->GetNext();
    }
}

void Heap::FullGC() {
    gc->Collect();
}

void Heap::Free(void* ptr) {
    if ( ((uintptr_t)ptr < (uintptr_t) this->objectSpace) &&
        ((uintptr_t)ptr > (uintptr_t) this->objectSpace + this->objectSpaceSize)) {
        internalFree(ptr);
    }
}

void Heap::Destroy(VMObject* _object) {
    
    int freedBytes = _object->GetObjectSize();
    memset((void *)_object, 0, freedBytes);
    VMFreeObject* object = (VMFreeObject*) _object;

    //see if there's an adjoining unused object behind this object
    VMFreeObject* next = (VMFreeObject*)((uintptr_t)object + (int)freedBytes);
    if (next->GetGCField() == -1) {
        //yes, there is, so we can join them
        object->SetObjectSize(next->GetObjectSize() + freedBytes);
        object->SetNext(next->GetNext());
        next->GetNext()->SetPrevious(object);
        VMFreeObject* previous = next->GetPrevious();
        object->SetPrevious(previous);
        memset((void *)next, 0, next->GetObjectSize());
    } else {
        //no, there is not, so we just put the new unused object as the new freeListStart
        object->SetObjectSize(freedBytes);
        object->SetNext(freeListStart);
        freeListStart->SetPrevious(object);
        freeListStart = object;
    }
    //TODO: find a way to merge unused objects that are before this object
}

void Heap::internalFree(void* ptr) {
    free(ptr);
}

void* Heap::internalAllocate(size_t size) {
    if (size == 0) return NULL;
    void* result = malloc(size);
    if(!result) {
        cout << "Failed to allocate " << size << " Bytes." << endl;
        _UNIVERSE->Quit(-1);
    }
    memset(result, 0, size);
    return result;
}
