Logo Search packages:      
Sourcecode: kaya version File versions  Download package

Heap.cc

/**
    Kaya run-time system
    Copyright (C) 2004, 2005 Edwin Brady

    This file is distributed under the terms of the GNU Lesser General
    Public Licence. See COPYING for licence.
*/

#include <gc/gc_allocator.h>

#include "sizes.h"
#include <iostream>
#include "Heap.h"
#include <wchar.h>
#include <stdio.h>
#include <assert.h>
#include "ValueFuns.h"
#include "stdfuns.h"
#include "Array.h"
#include "VMState.h"
#include "Closure.h"
#include "VM.h"

//extern int stacksize;
//extern int stackalloc;

// cached values
Value* zero = new Value((void*)0,KVT_INT);
Value* one = new Value((void*)1,KVT_INT);
Value* minusone = new Value((void*)(-1),KVT_INT);

/*
Value::Value(void* ptr, valtype ft):m_val(ptr),m_funtable(ft)
{
//    cout << "Created a value " << this << endl;
}*/

String* Value::getString()
{
    /// TODO - throw if it's not a string..
    if (m_val!=NULL)
      return (String*)m_val;
    else
      return new String(L"");
}

Exception* Value::getExcept()
{
    /// TODO - throw if it's not an exception.
    if (m_val!=NULL)
      return (Exception*)m_val;
    else {
      assert(false);
      return NULL;
    }
}

void Value::runClosure(VMState* vm)
{
//    cout << m_val << endl;
    ((Closure*)m_val)->run(vm);
//    ((func)m_val)(vm);
}

void Value::addClosureArgs(VMState *vm, int i)
{
    ((Closure*)m_val)->addArgs(vm,i);
}

Array* Value::getArray()
{
    /// TODO - throw if it's not an array.
    if (m_val!=NULL)
      return (Array*)m_val;
    else
      return new Array();
}

Union* Value::getUnion()
{
    /// TODO - throw if it's not a union.
    if (m_val!=NULL)
      return (Union*)m_val;
    assert(false);
    return NULL; // Can't happen.
}

void Value::int2str()
{
    int v=getInt();
    wchar_t buf[50]; // *Ick*
    SWPRINTF(buf,50,L"%d",v);
    setString(new String(buf));
}

void Value::real2str()
{
    double v=getReal();
    wchar_t buf[100]; // *Ick*
    SWPRINTF(buf,50,L"%g",v);
    setString(new String(buf));
    m_funtable = KVT_STRING;
}

void Value::str2int()
{
    String* s=getString();
    int val=(kint)(wcstol(s->getVal(),NULL,10));
    setInt(val);
    m_funtable = KVT_INT;
}

void Value::str2real()
{
    String* s=getString();
    double val=wcstod(s->getVal(),NULL);
    setReal(val);
    m_funtable = KVT_REAL;
}

void Value::chr2str()
{
  //CIM: wchar_t is an integer type storing the UCS position
    wchar_t v=(wchar_t)getInt();
    setString(new String(v));
    m_funtable = KVT_STRING;
}

void Value::bool2str()
{
    int v=getInt();
    if (v==1) { setString(new String(L"true")); }
    else { setString(new String(L"false")); }
}

void Value::str2chr()
{
    assert(false); // Makes no sense!
}

void Value::int2real()
{
    int v=getInt();
    setReal((double)v);
    m_funtable = KVT_REAL;
}

void Value::real2int()
{
    double v=getReal();
    setInt((kint)v);
    m_funtable = KVT_INT;
}

void Value::setReal(double v)
{
    m_val=(void*)(new Real(v));
    m_funtable = KVT_REAL;
}

void Value::setFunc(Closure* f)
{
    m_val=(void*)f;
    m_funtable = KVT_FUNC;
}

void Value::setArray(Array* a)
{
    m_val=(void*)a;
    m_funtable = KVT_ARRAY;
}

void Value::readString()
{
    char buf[255];
    fgets(buf,255,stdin);
    char *loc = strchr(buf,'\n');
    *loc = '\0';
    setString(new String(strtowc(buf)));
}

void Value::readInt()
{
    int v;
    scanf("%d",&v);
    setInt(v);
}

/*
void Value::setIdxPtr(Value* p,unsigned i)
{
//    cout << "Setting " << this << " to " << p->m_val << endl;
    Value* current=this;
    for(unsigned x=0;x<i;x++)
    {
      --stacksize;
      int idx = valstack[stacksize]->getInt();
//    int idx = stack.back()->getInt();
//    cout << idx << ",";
//    stack.pop_back();
      valstack[stacksize]=0;
      Value* next = current->lookup(idx);
      current = next;
    }
//    cout << endl;
    current->m_val=p->m_val;
    current->m_funtable=p->m_funtable;
}
*/

void Value::project(VMState* vm, int i)
{
    if (vm->topItem()->getType()!=KVT_UNION) {
      vm->kaya_throw(L"Attempt to project from non-Union",1);
    }

    Union* top=(Union*)(vm->topItem()->m_val);
    Value* arg=top->args[i];
    m_val=arg->m_val;
    m_funtable = arg->m_funtable;
}

/*
void Value::makeArray(int i,vector<Value*>& stack)
{
    int size=1;
    for(int x=0;x<i;x++)
    {
      int idx = stack.back()->getInt();
      stack.pop_back();
      size=size*idx;
    }
    m_val=(void*)(new Value*[size]);
    for(int j=0;j<size;j++) {
      ((Value**)m_val)[j] = new Value();
    }
}
*/

Value* Value::lookup(VMState* vm, int i)
{
#ifndef NOCHECK
    if (m_val && getType()!=KVT_ARRAY) {
//    cout << m_val << "," << getType() << endl;
      vm->kaya_throw(L"Attempt to lookup in non-Array",1);
    }
#endif
    if (i<0) {
      vm->kaya_throw(L"Attempt to lookup negative array index",1);
    }

    Array* v = (Array*)m_val;
    if (v==NULL)
    {
      v = new Array();
      m_val=v;
      m_funtable = KVT_ARRAY;
    }

    int extras = i-v->size();
    if (extras>=0) {
      v->expectedSize(i);
      Value* n = new Value(NULL, KVT_NULL);
      for(int l=0;l<extras;l++) {
          v->push_back(n);
          n = new Value(NULL, KVT_NULL);
      }
      v->push_back(n);
      return n; // rather than looking it up having just inserted it!
    }

    return v->lookup(i);
}

int Value::length()
{
    Array* v = (Array*)m_val;
    if (v==NULL)
    {
      v = new Array();
      m_val=v;
    }
    return v->size();
}

String::String(wchar_t* val)
{
    if (val!=NULL) {
      m_alloc = wcslen(val)*2;
      m_str=(wchar_t*)GC_MALLOC_ATOMIC(m_alloc*sizeof(wchar_t));
      wcscpy(m_str,val);
    }
    else {
      m_alloc = 128;
      m_str=(wchar_t*)GC_MALLOC_ATOMIC(m_alloc*sizeof(wchar_t));
//    strcpy(m_str,"(none)"); // Debugging purposes
      wcscpy(m_str,L"");
    }
}

String::String(wchar_t val)
{
    m_alloc = 16;
    m_str=(wchar_t*)GC_MALLOC_ATOMIC(m_alloc*sizeof(wchar_t));
    m_str[0]=val;
    m_str[1]='\0';
}

String::String(int len)
{
    m_alloc = len+1; // space for /0
    m_str=(wchar_t*)GC_MALLOC_ATOMIC(m_alloc*sizeof(wchar_t));
    m_str[0]='\0';
}

void String::append(String* s)
{
    // reallocation is safe with strings, because there will be no
    // references into the middle.
    int newlen = length() + s->length();
    if (newlen>=m_alloc) {
      m_alloc = (newlen+8)*2; //(newlen+10)*2;
//    cout << "Realloc " << m_alloc << " to " << wctostr(m_str) << " + " << wctostr(s->getVal()) << endl;
      wchar_t* newstr = (wchar_t*)GC_MALLOC_ATOMIC(sizeof(wchar_t)*m_alloc);
      wcscpy(newstr,m_str);
      m_str=newstr;
    }
    wcscat(m_str,s->getVal());
}

void String::append(wchar_t c)
{
    int newlen = length()+1;
    if (newlen>=m_alloc) {
      m_alloc = (newlen+8)*2; //(newlen+10)*2;
//    cout << "Realloc " << m_alloc << " to " << wctostr(m_str) << endl;
      wchar_t* newstr = (wchar_t*)GC_MALLOC_ATOMIC(sizeof(wchar_t)*m_alloc);
      wcscpy(newstr,m_str);
      m_str=newstr;
    }
    m_str[newlen-1]=c;
    m_str[newlen]='\0';
}

void String::append(wchar_t* s)
{
    int newlen = length() + wcslen(s);
    if (newlen>=m_alloc) {
      m_alloc = (newlen+8)*2; //(newlen+10)*2;
//    cout << "Realloc " << m_alloc << " to " << wctostr(m_str) << endl;
      wchar_t* newstr = (wchar_t*)GC_MALLOC_ATOMIC(sizeof(wchar_t)*m_alloc);
      wcscpy(newstr,m_str);
      m_str=newstr;
    }
    wcscat(m_str,s);
}

bool String::eq(String* s)
{
//    cout << "Comparing " << s->getVal() << " and " << m_str << "." << endl;
    return (wcscmp(m_str,s->getVal())==0);
}

bool String::eq(wchar_t* s)
{
    return (wcscmp(m_str,s)==0);
}

int String::cmp(String* s)
{
//    cout << "Comparing " << s->getVal() << " and " << m_str << "." << endl;
    return (wcscmp(m_str,s->getVal()));
}

int String::hash()
{
    int hash = 0;
    for(unsigned i=0;i<wcslen(m_str);i++) {
      hash = 131*hash+m_str[i];
    }
    return hash;
}

Union::Union(VMState* vm, int t,int ar, bool getargs)
    :tag_arity((t << 16) + ar)
{
    // Make space for the data, then take <arity> items off the stack and
    // put them into the structure.
//    cout << "Making union with tag " << t << " and arity " << ar << endl;
//    cout << "tag_arity = " << tag_arity << endl;
    if (ar > 0) {
      args = (Value**)GC_MALLOC_UNCOLLECTABLE(sizeof(Value*)*ar);
      if (getargs) {
      for(int i=0;i<ar;i++) {
        //      --stacksize;
        /// Create a *new* reference, or things break in confusing ways.
        args[i]=vm->doPop()->clone();
      }
      }
    } else {
      args = NULL;
    }
}

bool Union::eq(Union* x)
{
    if (THIS_TAG!=U_TAG(x)) return false;
    for(int i=0;i<THIS_ARITY;i++)
    {
      if (!funtable_eq(NULL,args[i],x->args[i])) { return false; }
    }
    return true;
}

int Union::cmp(Union* x)
{
    if (THIS_TAG<U_TAG(x)) return -1;
    if (THIS_TAG>U_TAG(x)) return 1;

    for(int i=0;i<THIS_ARITY;i++)
    {
      int cmp = funtable_compare(NULL,args[i],x->args[i]);
      if (cmp!=0) return cmp;
    }
    return 0;
}

Union* Union::copy(map<Value*,Value*>& done)
{
    Union* u = new Union(NULL,THIS_TAG,THIS_ARITY,false);
    for(int i=0;i<THIS_ARITY;i++) {
      Value* copied;
      Value* x = args[i];
      // if x is already copied, return the copied value
      if (done.find(x)!=done.end()) {
          copied = done[x];
      }
      else {
          copied = funtable_copy_aux(x, done);
      }
      u->args[i]=copied;
    }
    return u;
}

int Union::memusage()
{
    int size = sizeof(Union);
    for(int x=0;x<THIS_ARITY;++x) {
      size+=funtable_memusage(args[x]);
    }
    return size;
}

Exception::Exception(VMState* vm)
{
    Value* codeval = vm->doPop();
    Value* errval = vm->doPop();
    code = codeval->getInt();
    err = errval->getString();

    throwfile = vm->m_sourcefile;
    throwline = vm->m_lineno;

    CallStackEntry** c = vm->m_btptr-1;
    for(;(c>vm->m_backtrace);--c) {
      CallStackEntry nc(**c);
      backtrace.push_back(nc);
    }
}

void Exception::show()
{
    cout << wctostr(err->getVal()) << " (error code " << code << ")" << endl;
}

bool Exception::eq(Exception* x)
{
    /*   cout << "Comparing..." << endl;
    show();
    x->show();

    cout << ((err->eq(x->err)) && (code==x->code)) << endl;*/
    return (err->eq(x->err)) && (code==x->code);
}

int Exception::cmp(Exception* x)
{
    return (code-x->code);
}

void Exception::dumpBacktrace()
{
    vector<CallStackEntry>::iterator it = backtrace.begin();
    cout << wctostr(err->getVal()) << " (error code " << code << ")";
    if (throwline!=0) {
      cout << " thrown at " << wctostr(throwfile) << ":" << throwline << endl;
    }
    else {
      cout << " thrown" << endl;
    }
    for(int x=0;it!=backtrace.end() && x<=20;++it,++x) {
      if ((*it).line==-1) {
          cout << "lambda in " << wctostr((*it).fn_name);
      }
      else {
          cout << wctostr((*it).fn_name);
      }
      if ((it+1)==backtrace.end()) {
          cout << " [entry point]" << endl;
      }
      else {
          cout << " called from " << wctostr((*(it+1)).fn_name) << " at " 
             << wctostr((*it).call_file) << ":" 
             << (*it).call_line << endl;
      }
      if (x==20) {
          int num = backtrace.size()-20;
          cout << "[... " << num << " more elided...]" << endl;
      }
    }
}

Generated by  Doxygen 1.6.0   Back to index