diff options
Diffstat (limited to 'Build/source/utils/asymptote/stack.cc')
-rw-r--r-- | Build/source/utils/asymptote/stack.cc | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/stack.cc b/Build/source/utils/asymptote/stack.cc new file mode 100644 index 00000000000..ffec3d9b056 --- /dev/null +++ b/Build/source/utils/asymptote/stack.cc @@ -0,0 +1,370 @@ +/***** + * stack.cc + * Andy Hammerlindl 2002/06/27 + * + * The general stack machine used to run compiled camp code. + *****/ + +#include <sstream> + +#include "stack.h" +#include "program.h" +#include "callable.h" +#include "errormsg.h" +#include "util.h" +#include "runtime.h" + +//#define DEBUG_STACK + +#ifdef DEBUG_STACK +#include <iostream> + +namespace vm { +void draw(ostream& out, frame *v); +} +#endif + +namespace run { +void breakpoint(vm::stack *Stack, absyntax::runnable *r); +} + +namespace vm { + +mem::list<bpinfo> bplist; + +namespace { +position curPos = nullPos; +const program::label nulllabel; +} + +inline stack::vars_t stack::make_frame(size_t size, vars_t closure) +{ + vars_t vars = new frame(1+size); + (*vars)[0] = closure; + return vars; +} + +void run(lambda *l) +{ + func f; + f.body = l; + stack s; + s.run(&f); +} + +void stack::marshall(size_t args, vars_t vars) +{ + for (size_t i = args; i > 0; --i) + (*vars)[i] = pop(); +} + +void stack::run(func *f) +{ + lambda *body = f->body; + +#ifdef DEBUG_STACK + cout << "running lambda: \n"; + print(cout, body->code); + cout << endl; +#endif + + /* make new activation record */ + vars_t vars = make_frame(body->params, f->closure); + marshall(body->params, vars); + + run(body->code, vars); +} + +void stack::breakpoint(absyntax::runnable *r) +{ + lastPos=curPos; + indebugger=true; + ::run::breakpoint(this,r); + string s=vm::pop<string>(this); + debugOp=(s.length() > 0) ? s[0] : (char) 0; + indebugger=false; +} + +void stack::debug() +{ + if(!curPos) return; + if(indebugger) {em.clear(); return;} + + switch(debugOp) { + case 'i': // inst + breakpoint(); + break; + case 's': // step + if((!curPos.match(lastPos.filename()) || !curPos.match(lastPos.Line()))) + breakpoint(); + break; + case 'n': // next + if(curPos.match(lastPos.filename()) && !curPos.match(lastPos.Line())) + breakpoint(); + break; + case 'f': // file + if(!curPos.match(lastPos.filename())) + breakpoint(); + break; + case 'r': // return + if(curPos.match(breakPos.filename())) + breakpoint(); + break; + case 'c': // continue + default: + for(mem::list<bpinfo>::iterator p=bplist.begin(); p != bplist.end(); ++p) { + if(curPos.match(p->f.name()) && curPos.match(p->f.line()) && + (newline || !curPos.match(breakPos.filename()) || + !curPos.match(breakPos.Line()))) { + breakPos=curPos; + breakpoint(p->r); + newline=false; + break; + } + if(!newline && + (curPos.match(lastPos.filename()) && !curPos.match(lastPos.Line()))) + newline=true; + } + break; + } +} + +void stack::run(program *code, vars_t vars) +{ + /* start the new function */ + program::label ip = code->begin(); + + try { + for (;;) { + const inst &i = *ip; + curPos = i.pos; + +#ifdef DEBUG_STACK + cerr << curPos << "\n"; + printInst(cerr, ip, body->code->begin()); + cerr << "\n"; +#endif + + if(settings::verbose > 4) em.trace(curPos); + + if(!bplist.empty()) debug(); + + if(errorstream::interrupt) throw interrupted(); + + switch (i.op) + { + case inst::pop: + pop(); + break; + + case inst::intpush: + case inst::constpush: + push(i.ref); + break; + + case inst::varpush: + push((*vars)[get<Int>(i)]); + break; + + case inst::varsave: + (*vars)[get<Int>(i)] = top(); + break; + + case inst::fieldpush: { + vars_t frame = pop<vars_t>(); + if (!frame) + error("dereference of null pointer"); + push((*frame)[get<Int>(i)]); + break; + } + + case inst::fieldsave: { + vars_t frame = pop<vars_t>(); + if (!frame) + error("dereference of null pointer"); + (*frame)[get<Int>(i)] = top(); + break; + } + + case inst::builtin: { + bltin func = get<bltin>(i); + func(this); + break; + } + + case inst::jmp: + ip = get<program::label>(i); + continue; + + case inst::cjmp: + if (pop<bool>()) { ip = get<program::label>(i); continue; } + break; + + case inst::njmp: + if (!pop<bool>()) { ip = get<program::label>(i); continue; } + break; + + case inst::popcall: { + /* get the function reference off of the stack */ + callable* f = pop<callable*>(); + f->call(this); + break; + } + + case inst::pushclosure: + push(vars); + break; + + case inst::makefunc: { + func *f = new func; + f->closure = pop<vars_t>(); + f->body = get<lambda*>(i); + + push((callable*)f); + break; + } + + case inst::ret: { + return; + } + + case inst::alloc: { + vars->extend(get<Int>(i)); + break; + } + + case inst::pushframe: { + vars=make_frame(0, vars); + break; + } + + case inst::popframe: { + vars=get<frame *>((*vars)[0]); + break; + } + + default: + error("Internal VM error: Bad stack operand"); + } + +#ifdef DEBUG_STACK + draw(cerr); + vm::draw(cerr,vars); + cerr << "\n"; +#endif + + ++ip; + } + } catch (bad_item_value&) { + error("Trying to use uninitialized value."); + } +} + +void stack::load(string index) { + frame *inst=instMap[index]; + if (inst) + push(inst); + else { + func f; + assert(initMap); + f.body=(*initMap)[index]; + assert(f.body); + run(&f); + instMap[index]=get<frame *>(top()); + } +} + + +#ifdef DEBUG_STACK +#if __GNUC__ +#include <cxxabi.h> +string demangle(const char *s) +{ + int status; + char *demangled = abi::__cxa_demangle(s,NULL,NULL,&status); + if (status == 0 && demangled) { + string str(demangled); + free(demangled); + return str; + } else if (status == -2) { + free(demangled); + return s; + } else { + free(demangled); + return string("Unknown(") + s + ")"; + } +}; +#else +string demangle(const char* s) +{ + return s; +} +#endif + +void stack::draw(ostream& out) +{ +// out.setf(out.hex); + + out << "operands:"; + stack_t::const_iterator left = theStack.begin(); + if (theStack.size() > 10) { + left = theStack.end()-10; + out << " ..."; + } + + while (left != theStack.end()) + { + out << " " << demangle(left->type().name()); + left++; + } + out << "\n"; +} + +void draw(ostream& out, frame* v) +{ + out << "vars: "; + + if (!!v) { + out << (!get<frame*>((*v)[0]) ? " 0" : " link"); + for (size_t i = 1; i < 10 && i < v->size(); i++) + out << " " << demangle((*v)[i].type().name()); + if (v->size() > 10) + out << "..."; + out << "\n"; + } + else + out << "\n"; +} +#endif // DEBUG_STACK + +position getPos() { + return curPos; +} + +void errornothrow(const char* message) +{ + em.error(curPos); + em << message; + em.sync(); +} + +void error(const char* message) +{ + errornothrow(message); + throw handled_error(); +} + +void error(const ostringstream& message) +{ + error(message.str().c_str()); +} + +interactiveStack::interactiveStack() + : globals(new frame(1)) {} + +void interactiveStack::run(lambda *codelet) { + stack::run(codelet->code, globals); +} + +} // namespace vm + |