inline stack::vars_t make_globalframe(size_t size)
{
assert(size > 0);
#ifdef SIMPLE_FRAME
// The global frame is an indirect frame. It holds one item, which is the
// link to another frame.
stack::vars_t direct = new item[1];
stack::vars_t indirect = new item[size];
direct[0] = indirect;
return direct;
#else
return BASEFRAME(size, 0, 0, "<globals>");
#if 0
#ifdef DEBUG_FRAME
stack::vars_t vars = new frame("<pushed frame>", 0, size);
#else
stack::vars_t vars = new frame(size);
#endif
return vars;
#endif
#endif
// Move arguments from stack to frame.
void stack::marshall(size_t args, stack::vars_t vars)
{
for (size_t i = args; i > 0; --i) {
# ifdef SIMPLE_FRAME
vars[i-1] = pop();
# else
(*vars)[i-1] = pop();
# endif
}
}
#ifdef PROFILE
#ifndef DEBUG_FRAME
#pragma message("WARNING: profiler needs DEBUG_FRAME for function names")
#endif
#ifndef DEBUG_BLTIN
#pragma message("WARNING: profiler needs DEBUG_BLTIN for builtin function names")
#endif
profiler prof;
void dumpProfile() {
std::ofstream out("asyprof");
if (!out.fail())
prof.dump(out);
}
#endif
void assessClosure(lambda *body) {
// If we have already determined if it needs closure, just return.
if (body->closureReq != lambda::MAYBE_NEEDS_CLOSURE)
return;
for (program::label l = body->code->begin(); l != body->code->end(); ++l)
if (l->op == inst::pushclosure ||
l->op == inst::pushframe) {
body->closureReq = lambda::NEEDS_CLOSURE;
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(auto 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::runWithOrWithoutClosure(lambda *l, vars_t vars, vars_t parent)
{
// The size of the frame (when running without closure).
size_t frameSize = l->parentIndex;
#ifdef SIMPLE_FRAME
// Link to the variables, be they in a closure or on the stack.
vmFrame *varlink;
# define SET_VARLINK assert(vars); varlink = vars;
# define VAR(n) ( (varlink)[(n) + frameStart] )
# define FRAMEVAR(frame,n) (frame[(n)])
#else
// Link to the variables, be they in a closure or on the stack.
mem::vector<item> *varlink=NULL;
// Set up the closure, if necessary.
if (vars == 0)
{
#ifndef SIMPLE_FRAME
assessClosure(l);
if (l->closureReq == lambda::NEEDS_CLOSURE)
#endif
{
/* make new activation record */
vars = vm::make_frame(l, parent);
assert(vars);
}
#ifndef SIMPLE_FRAME
else
{
assert(l->closureReq == lambda::DOESNT_NEED_CLOSURE);
// Use the stack to store variables.
varlink = &theStack;
// Record where the parameters start on the stack.
frameStart = theStack.size() - frameSize;
// Add the parent's closure to the frame.
push(parent);
++frameSize;
/* start the new function */
program::label ip = l->code->begin();
processDataStruct& P=processData();
position& topPos=P.topPos;
string& fileName=P.fileName;
unsigned int offset=P.xmapCount;
switch (i.op)
{
case inst::varpush:
push(VAR(get<Int>(i)));
break;
case inst::varsave:
VAR(get<Int>(i)) = top();
break;
#ifdef COMBO
case inst::varpop:
VAR(get<Int>(i)) = pop();
break;
#endif
case inst::ret: {
if (vars == 0)
// Delete the frame from the stack.
// TODO: Optimize for common cases.
theStack.erase(theStack.begin() + frameStart,
theStack.begin() + frameStart + frameSize);
return;
}
case inst::pushframe:
{
assert(vars);
Int size = get<Int>(i);
vars=make_pushframe(size, vars);
SET_VARLINK;
break;
}
case inst::popframe:
{
assert(vars);
vars=get<vmFrame *>(VAR(0));
SET_VARLINK;
break;
}
case inst::pushclosure:
assert(vars);
push(vars);
break;
case inst::nop:
break;
case inst::pop:
pop();
break;
case inst::intpush:
case inst::constpush:
push(i.ref);
break;
case inst::fieldpush: {
vars_t frame = pop<vars_t>();
if (!frame)
error(dereferenceNullPointer);
push(FRAMEVAR(frame, get<Int>(i)));
break;
}
case inst::fieldsave: {
vars_t frame = pop<vars_t>();
if (!frame)
error(dereferenceNullPointer);
FRAMEVAR(frame, get<Int>(i)) = top();
break;
}
#if COMBO
case inst::fieldpop: {
#error NOT REIMPLEMENTED
vars_t frame = pop<vars_t>();
if (!frame)
error(dereferenceNullPointer);
FRAMEVAR(get<Int>(i)) = pop();
break;
}
#endif
out << "operands:";
stack_t::const_iterator left = theStack.begin();
if (theStack.size() > MAX_ITEMS) {
left = theStack.end()-MAX_ITEMS;
out << " ...";
}
else
out << " ";
while (left != theStack.end())
{
if (left != theStack.begin())
out << " | " ;
out << *left;
left++;
}
out << "\n";
}