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

VMState.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 "VMState.h"
#include "VM.h"
#include "ValueFuns.h"
#include "KayaAPI.h"
#include "stdfuns.h"

#include <assert.h>
#include <ext/hash_map>

/// function map is global to all threads.
func* m_funmap[1];
int m_funmapsize;

void initFunMap(int sz)
{
    func* funcs = (func*)malloc(sizeof(func)*sz);
    m_funmap[0] = funcs;
    m_funmapsize = sz;
}

void addToFunMap(int id, func fn)
{
  (m_funmap[0])[id] = fn;
}

func getFn(int id)
{
  // should add bounds checking here
    return (m_funmap[0])[id];
}

int getFnID(func fn)
{
    int i;
    for (i=1;i<m_funmapsize;i++) {
      if (m_funmap[0][i] == fn) { return i; }
    }
    return -1;
}

VMState::VMState(bool panic):m_return(NULL,KVT_NULL) {
    m_stackalloc=100;
    m_globalloc=100;
    if (!panic) {
      m_valstack = (Value**)GC_MALLOC_UNCOLLECTABLE(sizeof(Value*)*m_stackalloc);
      // Make sure stack is clear.
      memset(m_valstack,0,sizeof(Value*)*m_stackalloc);
      m_maxmem = 0;
      m_backtrace = (CallStackEntry**)GC_MALLOC_UNCOLLECTABLE(sizeof(CallStackEntry*)*m_stackalloc*10);
      // Allocate space all at once (max out at <m_stackalloc*10>)
      for(int i=0;i<m_stackalloc*10;++i) {
          m_backtrace[i]=new CallStackEntry;
      }
    }
    else {
      m_valstack = (Value**)malloc(100); // Tiny, if we're panicking.
      m_backtrace = (CallStackEntry**)malloc(100); // Tiny, if we're panicking.
      for(int i=0;i<5;++i) {
          m_backtrace[i]=new CallStackEntry;
      }
    }
    m_stackptr=m_valstack;
    m_btptr=m_backtrace;
    lineno(L"START",0);
}

void VMState::finish()
{
    if (!emptyStack()) {
      cerr << "Warning: Stack size is non-zero (" << m_stackptr << "," << m_valstack << ")" << endl;
    }
#ifndef NOCHECK
    if (m_btptr!=m_backtrace) {
      cerr << "Warning: Call stack size is non-zero (" << m_btptr << "," << m_backtrace << ")" << endl;
    }
#endif
}

bool VMState::emptyStack()
{
    return m_stackptr==m_valstack;
}

void VMState::push2(Value* val, Value* val2)
{
    // FIXME: Grow stack if necessary? Might be quite an overhead... maybe 
    // make it an option.
    *(m_stackptr++)=val;
    *(m_stackptr++)=val2;
}

void VMState::push3(Value* val, Value* val2, Value* val3)
{
    // FIXME: Grow stack if necessary? Might be quite an overhead... maybe 
    // make it an option.
    *(m_stackptr++)=val;
    *(m_stackptr++)=val2;
    *(m_stackptr++)=val3;
}

void VMState::push4(Value* val, Value* val2, Value* val3, Value* val4)
{
    // FIXME: Grow stack if necessary? Might be quite an overhead... maybe 
    // make it an option.
    *(m_stackptr++)=val;
    *(m_stackptr++)=val2;
    *(m_stackptr++)=val3;
    *(m_stackptr++)=val4;
}

int VMState::tag()
{
#ifndef NOCHECK
    if ((*(m_stackptr-1))->getType()!=KVT_UNION) {
      kaya_throw("Attempt to get tag from non-Union",1);
    }
#endif
    return (*(m_stackptr-1))->getTag();
}

void VMState::readInt()
{
    Value* v=new Value(NULL,KVT_INT);
    v->readInt();
    push(v);
}

void VMState::readStr()
{
    Value* v=new Value(NULL,KVT_STRING);
    v->readString();
    push(v);
}

void VMState::doAppend()
{
    Value* str2=doPop();
    Value* str1=doPop();
    String* str=new String(str1->getString()->getVal());
    str->append(str2->getString());
    push(new Value((void*)str,KVT_STRING));
}

void VMState::doAppendChar(wchar_t x)
{
    // append x onto top stack item
    (*(m_stackptr-1))->getString()->append(x);

//    Value* str2=doPop();
//    Value* str1=doPop();
//    String* str=new String(str1->getString()->getVal());
//    str->append(x);
//    push(new Value((void*)str,stringtable));
}

void VMState::doAppendStr(wchar_t* x)
{
    // append x onto top stack item
    (*(m_stackptr-1))->getString()->append(x);

//    Value* str1=doPop();
//    String* str=new String(str1->getString()->getVal());
//    str->append(x);
//    push(new Value((void*)str,stringtable));
}

void VMState::doAppendStr(char* x)
{
    // append x onto top stack item
//    (*(m_stackptr-1))->getString()->append(x); unsound!
  VMState::doAppendStr(strtowc(x));
}

void VMState::doEqExcept(bool inv)
{
    Value* e2=doPop();
    Value* e1=doPop();
    bool eq = (e2->getExcept()->eq(e1->getExcept()));
    if (inv) { eq = !eq; }
    if (eq) {  push(one); }
    else {  push(zero); }
}

void VMState::doEqString(bool inv)
{
    Value* e2=doPop();
    Value* e1=doPop();
    bool eq = (e2->getString()->eq(e1->getString()));
    if (inv) { eq = !eq; }
    if (eq) {  push(one); }
    else {  push(zero); }
}

void VMState::doEqString(bool inv, wchar_t* str)
{
    Value* e1=doPop();
    bool eq = (e1->getString()->eq(str));
    if (inv) { eq = !eq; }
    if (eq) {  push(one); }
    else {  push(zero); }
}

void VMState::doEqString(bool inv, char* str)
{
  return VMState::doEqString(inv,strtowc(str));
}


bool VMState::doTopStrEq(wchar_t* str)
{
    wchar_t* topstr = (*(m_stackptr-1))->getString()->getVal();
    return (!wcscmp(topstr,str));
}

bool VMState::doTopStrEq(char* str)
{
  return VMState::doTopStrEq(strtowc(str));
}


void VMState::int2str()
{
    // Need to do this on a copy or we break types.
    Value* x = new Value(NULL,KVT_NULL);
    x->setInt(doPop()->getInt());
    x->int2str();
    push(x);
}

void VMState::real2str()
{
    // Need to do this on a copy or we break types.
    Value* x = new Value(NULL,KVT_NULL);
    x->setReal(doPop()->getReal());
    x->real2str();
    push(x);
}

void VMState::str2int()
{
    // Need to do this on a copy or we break types.
    Value* x = new Value(doPop()->getRaw(),KVT_INT);
    x->str2int();
    push(x);
}

void VMState::str2real()
{
    // Need to do this on a copy or we break types.
    Value* x = new Value(doPop()->getRaw(),KVT_REAL);
    x->str2real();
    push(x);
}

void VMState::chr2str()
{
    // Need to do this on a copy or we break types.
    Value* x = new Value(doPop()->getRaw(),KVT_STRING);
    x->chr2str();
    push(x);
}

void VMState::bool2str()
{
    // Need to do this on a copy or we break types.
    Value* x = new Value(doPop()->getRaw(),KVT_STRING);
    x->bool2str();
    push(x);
}

void VMState::str2chr()
{
//    valstack[stacksize-1]->str2chr();
    assert(false);
}

void VMState::real2int()
{
    // Need to do this on a copy or we break types.
    Value* x = new Value(NULL,KVT_NULL);
    x->setReal(doPop()->getReal());
    x->real2int();
    push(x);
}

void VMState::int2real()
{
    // Need to do this on a copy or we break types.
    Value* x = new Value(NULL,KVT_NULL);
    x->setInt(doPop()->getInt());
    x->int2real();
    push(x);
}

void VMState::mkArray(int i)
{
    Array* array = new Array(i*2);
    // leave a bit of room for expansion (costs a little memory)
    while(i>0) {
      Value* v= doPop();
      array->push_back(v);
      i--;
    }

    push(new Value(array,KVT_ARRAY));
}

void VMState::goToIndex()
{
    --m_stackptr;
    int idx = (*m_stackptr)->getInt();
    (*(m_stackptr-1)) = (*(m_stackptr-1))->lookup(this,idx);
}

void VMState::pushglobal(Value**& globtable, int i)
{
    if (globtable == NULL) {
      globtable = (Value**)GC_MALLOC_UNCOLLECTABLE(sizeof(Value*)*m_globalloc);
      for(int i=0;i<m_globalloc;i++) { //TMP HACK
          globtable[i]=new Value(0,KVT_INT);
      }
    }

    push(globtable[i]);
}

void VMState::createglobal(wchar_t* modid, int i)
{
    cerr << "Do not run this function again" << endl;
    exit(1);
//     Value** mglobs;
//     if (m_globs.find(modid)==m_globs.end()) {
//    mglobs = (Value**)GC_MALLOC_UNCOLLECTABLE(sizeof(Value*)*m_globalloc);
//    for(int i=0;i<m_globalloc;i++) { //TMP HACK
//        mglobs[i]=new Value(0,NULL);
//    }
//    m_globs[modid]=mglobs;
//     }
//     else {
//    mglobs = m_globs[modid];
//     }
//     if (i>=m_globalloc)
//     {
//    Value** newglobs = (Value**)GC_MALLOC_UNCOLLECTABLE(sizeof(Value*)*m_globalloc*2);
//    for(int i=0;i<m_globalloc;i++)
//        newglobs[i]=mglobs[i];
//    mglobs=newglobs;
//    m_globalloc*=2;
//    m_globs[modid]=mglobs;
//     }
}

void VMState::newjmp_buf()
{
    jmp_buf* b = new jmp_buf[1];
    m_except_stack.push(b);
//    stackdata *s = new stackdata();
//    s->data = valstack;
//    s->size = stacksize;
    StackData d;
    d.stackptr = m_stackptr;
    d.csptr = m_btptr;
    m_stack_stack.push(d);

//    cout << "Inside " << except_stack.size() << " tries" << endl;
}

void VMState::kaya_throw(wchar_t* msg,int code)
{
    push(mkstr(msg));
    push(mkint((void*)code));
    push(new Value((void*)(new Exception(this)), KVT_EXCEPTION));
    throw_ex();
}

void VMState::kaya_throw(char* msg,int code)
{
  // CIM: call the wchar_t version to make it easier to put strings in code
  kaya_throw(strtowc(msg),code);
}

void VMState::throw_ex()
{
    longjmp(*(m_except_stack.top()),2);
}

jmp_buf* VMState::top_ex()
{
    return m_except_stack.top();
}

void VMState::tried()
{
    delete m_except_stack.top(); 
    m_except_stack.pop(); 
    m_stack_stack.pop();
}

void VMState::restore()
{
    m_stackptr = m_stack_stack.top().stackptr;
    m_btptr = m_stack_stack.top().csptr;
}

void VMState::getindex()
{
    int idx = doPop()->getInt();
    Value* array = doPop();
    Value* el = array->lookup(this,idx);
    push(el);
}

Value* VMState::mkstr(wchar_t* str)
{
    return new Value((void*)(new String(str)),KVT_STRING);
}

Value* VMState::mkint(void* i)
{
    return new Value(i,KVT_INT);
}

void VMState::lineno(char* src, int ln) {
  VMState::lineno(strtowc(src),ln);
}

void VMState::lineno(wchar_t* src, int ln)
{
#ifndef NOCHECK
    m_sourcefile = src; //(char*)KayaAlloc(strlen(src)+1);
//    strcpy(m_sourcefile,src);
    m_lineno = ln;
#endif
}

void VMState::pushBT(char* fn, char* mod, int ln) {
  VMState::pushBT(strtowc(fn),strtowc(mod),ln);
}

void VMState::pushBT(wchar_t* fn, wchar_t* mod, int ln)
{
#ifndef NOCHECK
    CallStackEntry* c = *m_btptr;

    c->fn_name = fn; //(char*)KayaAlloc(strlen(fn)+1);
    c->file = mod; //(char*)KayaAlloc(strlen(mod)+1);
    c->call_file = m_sourcefile; // already gcmalloced
    c->line = ln;
    c->call_line = m_lineno;

    m_btptr++;
    if ((m_btptr-m_backtrace)>=m_stackalloc*10) {
      kaya_throw("Call stack overflow",1);
    }
#endif
}

void VMState::popBT()
{
#ifndef NOCHECK
//    cout << "pop backtrace!" << endl;
    if (m_btptr==m_backtrace) {
      cout << "Warning! Call stack underflow!" << endl;
    }
    --m_btptr;
//    *m_btptr = NULL; // set end marker
#endif
}

void VMState::memstat()
{
#ifndef NOCHECK
    int mem = GC_get_heap_size();
    if (mem>m_maxmem) m_maxmem=mem;
#endif
}

void VMState::writestdout()
{
    wchar_t* str=doPop()->getString()->getVal();
    write(1,wctostr(str),strlen(wctostr(str)));
#ifndef WIN32
    fsync(1);
#endif
}

Generated by  Doxygen 1.6.0   Back to index