summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/stack.cc
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2011-05-28 02:18:52 +0000
committerKarl Berry <karl@freefriends.org>2011-05-28 02:18:52 +0000
commitc59fe5fe4739f0c61560f05d4e42b4e552219b27 (patch)
tree8cf79e85e394b3177a28d374415840a4e0a025ad /Build/source/utils/asymptote/stack.cc
parent771db15706dbf3f4af8b630dcb15646a3e5fda00 (diff)
asy 2.10
git-svn-id: svn://tug.org/texlive/trunk@22633 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/stack.cc')
-rw-r--r--Build/source/utils/asymptote/stack.cc430
1 files changed, 338 insertions, 92 deletions
diff --git a/Build/source/utils/asymptote/stack.cc b/Build/source/utils/asymptote/stack.cc
index b1651d2c424..31eab91106e 100644
--- a/Build/source/utils/asymptote/stack.cc
+++ b/Build/source/utils/asymptote/stack.cc
@@ -5,6 +5,7 @@
* The general stack machine used to run compiled camp code.
*****/
+#include <fstream>
#include <sstream>
#include "stack.h"
@@ -14,6 +15,8 @@
#include "util.h"
#include "runtime.h"
+#include "profiler.h"
+
#ifdef DEBUG_STACK
#include <iostream>
@@ -35,22 +38,96 @@ position curPos = nullPos;
const program::label nulllabel;
}
+inline stack::vars_t make_frame(lambda *l, stack::vars_t closure)
+{
+#ifdef SIMPLE_FRAME
+ stack::vars_t vars = new item[l->framesize];
+ vars[l->parentIndex] = closure;
+#else
#ifdef DEBUG_FRAME
-inline stack::vars_t stack::make_frame(string name,
- size_t size, vars_t closure)
+ assert(!l->name.empty());
+ stack::vars_t vars = new frame(l->name, l->parentIndex, l->framesize);
+#else
+ stack::vars_t vars = new frame(l->framesize);
+#endif
+
+ // The closure is stored after the parameters.
+ (*vars)[l->parentIndex] = closure;
+#endif
+
+ return vars;
+}
+
+inline stack::vars_t make_pushframe(size_t size, stack::vars_t closure)
{
- vars_t vars = new frame(name, 1+size);
+ assert(size >= 1);
+#if SIMPLE_FRAME
+ stack::vars_t vars = new item[size];
+ vars[0] = closure;
+#else
+#ifdef DEBUG_FRAME
+ stack::vars_t vars = new frame("<pushed frame>", 0, size);
+#else
+ stack::vars_t vars = new frame(size);
+#endif
(*vars)[0] = closure;
+#endif
+
return vars;
}
+
+stack::vars_t make_dummyframe(string name)
+{
+#if SIMPLE_FRAME
+ stack::vars_t vars = new item[1];
#else
-inline stack::vars_t stack::make_frame(size_t size, vars_t closure)
+#ifdef DEBUG_FRAME
+ stack::vars_t vars = new frame("<dummy frame for "+name+">", 0, 1);
+#else
+ stack::vars_t vars = new frame(1);
+#endif
+#endif
+
+ return vars;
+}
+
+inline stack::vars_t make_globalframe(size_t size)
{
- vars_t vars = new frame(1+size);
- (*vars)[0] = closure;
+ assert(size > 0);
+#if 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
+#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
+
}
+
+inline void resize_frame(frame *f, size_t oldsize, size_t newsize)
+{
+ //assert("Need to fix this" == 0);
+ assert(newsize > oldsize);
+#if SIMPLE_FRAME
+ frame *old_indirect = get<frame *>(f[0]);
+ frame *new_indirect = new item[newsize];
+ std::copy(old_indirect, old_indirect+oldsize, new_indirect);
+ f[0] = new_indirect;
+#else
+ f->extend(newsize);
#endif
+}
+
+
+
void run(lambda *l)
{
@@ -60,16 +137,58 @@ void run(lambda *l)
s.run(&f);
}
-void stack::marshall(size_t args, vars_t vars)
+// Move arguments from stack to frame.
+void stack::marshall(size_t args, stack::vars_t vars)
{
for (size_t i = args; i > 0; --i)
- (*vars)[i] = pop();
+#if SIMPLE_FRAME
+ vars[i-1] = pop();
+#else
+ (*vars)[i-1] = pop();
+#endif
+}
+
+#ifdef PROFILE
+
+#ifndef DEBUG_FRAME
+#warning "profiler needs DEBUG_FRAME for function names"
+#endif
+#ifndef DEBUG_BLTIN
+#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;
+ }
+
+ body->closureReq = lambda::DOESNT_NEED_CLOSURE;
}
void stack::run(func *f)
{
lambda *body = f->body;
+#ifdef PROFILE
+ prof.beginFunction(body);
+#endif
+
#ifdef DEBUG_STACK
#ifdef DEBUG_FRAME
cout << "running lambda " + body->name + ": \n";
@@ -79,17 +198,12 @@ void stack::run(func *f)
print(cout, body->code);
cout << endl;
#endif
-
- /* make new activation record */
-#ifdef DEBUG_FRAME
- assert(!body->name.empty());
- vars_t vars = make_frame(body->name, body->params, f->closure);
-#else
- vars_t vars = make_frame(body->params, f->closure);
-#endif
- marshall(body->params, vars);
- run(body->code, vars);
+ runWithOrWithoutClosure(body, 0, f->closure);
+
+#ifdef PROFILE
+ prof.endFunction(body);
+#endif
}
void stack::breakpoint(absyntax::runnable *r)
@@ -145,25 +259,90 @@ void stack::debug()
break;
}
}
-
-void stack::run(program *code, vars_t vars)
+
+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.
+ frame *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;
+
+# define SET_VARLINK assert(vars); varlink = &vars->vars
+# define VAR(n) ( (*varlink)[(n) + frameStart] )
+# define FRAMEVAR(frame,n) ((*frame)[(n)])
+#endif
+
+ size_t frameStart = 0;
+
+ // 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;
+
+ size_t newFrameSize = (size_t)l->framesize;
+
+ if (newFrameSize > frameSize) {
+ theStack.resize(frameStart + newFrameSize);
+ frameSize = newFrameSize;
+ }
+ }
+#endif
+ }
+
+ if (vars) {
+ marshall(l->parentIndex, vars);
+
+ SET_VARLINK;
+ }
+
/* start the new function */
- program::label ip = code->begin();
+ program::label ip = l->code->begin();
try {
for (;;) {
const inst &i = *ip;
curPos = i.pos;
-#if 0
- //printInst(cout, ip, code->begin());
- cout << i.pos << "\n";
+#ifdef PROFILE
+ prof.recordInstruction();
#endif
+
#ifdef DEBUG_STACK
- cerr << curPos << "\n";
- printInst(cerr, ip, code->begin());
- cerr << "\n";
+ printInst(cout, ip, l->code->begin());
+ cout << " (";
+ i.pos.printTerse(cout);
+ cout << ")\n";
#endif
if(settings::verbose > 4) em.trace(curPos);
@@ -174,42 +353,72 @@ void stack::run(program *code, vars_t vars)
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)]);
+ push(VAR(get<Int>(i)));
break;
case inst::varsave:
- (*vars)[get<Int>(i)] = top();
+ VAR(get<Int>(i)) = top();
break;
#ifdef COMBO
case inst::varpop:
- (*vars)[get<Int>(i)] = pop();
+ 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;
- case inst::fieldpop: {
- vars_t frame = pop<vars_t>();
- if (!frame)
- error("dereference of null pointer");
- (*frame)[get<Int>(i)] = pop();
break;
}
-#endif
+
+ case inst::popframe:
+ {
+ assert(vars);
+ vars=get<frame *>(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("dereference of null pointer");
- push((*frame)[get<Int>(i)]);
+ push(FRAMEVAR(frame, get<Int>(i)));
break;
}
@@ -217,13 +426,31 @@ void stack::run(program *code, vars_t vars)
vars_t frame = pop<vars_t>();
if (!frame)
error("dereference of null pointer");
- (*frame)[get<Int>(i)] = top();
+ FRAMEVAR(frame, get<Int>(i)) = top();
break;
}
+
+#if COMBO
+ case inst::fieldpop: {
+#error NOT REIMPLEMENTED
+ vars_t frame = pop<vars_t>();
+ if (!frame)
+ error("dereference of null pointer");
+ FRAMEVAR(get<Int>(i)) = pop();
+ break;
+ }
+#endif
+
case inst::builtin: {
bltin func = get<bltin>(i);
+#ifdef PROFILE
+ prof.beginFunction(func);
+#endif
func(this);
+#ifdef PROFILE
+ prof.endFunction(func);
+#endif
break;
}
@@ -239,6 +466,10 @@ void stack::run(program *code, vars_t vars)
if (!pop<bool>()) { ip = get<program::label>(i); continue; }
break;
+ case inst::jump_if_not_default:
+ if (!isdefault(pop())) { ip = get<program::label>(i); continue; }
+ break;
+
#ifdef COMBO
case inst::gejmp: {
Int y = pop<Int>();
@@ -247,8 +478,30 @@ void stack::run(program *code, vars_t vars)
{ ip = get<program::label>(i); continue; }
break;
}
+
+#if 0
+ case inst::jump_if_func_eq: {
+ callable * b=pop<callable *>();
+ callable * a=pop<callable *>();
+ if (a->compare(b))
+ { ip = get<program::label>(i); continue; }
+ break;
+ }
+
+ case inst::jump_if_func_neq: {
+ callable * b=pop<callable *>();
+ callable * a=pop<callable *>();
+ if (!a->compare(b))
+ { ip = get<program::label>(i); continue; }
+ break;
+ }
+#endif
#endif
+ case inst::push_default:
+ push(Default);
+ break;
+
case inst::popcall: {
/* get the function reference off of the stack */
callable* f = pop<callable*>();
@@ -256,10 +509,6 @@ void stack::run(program *code, vars_t vars)
break;
}
- case inst::pushclosure:
- push(vars);
- break;
-
case inst::makefunc: {
func *f = new func;
f->closure = pop<vars_t>();
@@ -269,29 +518,6 @@ void stack::run(program *code, vars_t vars)
break;
}
- case inst::ret: {
- return;
- }
-
- case inst::alloc: {
- vars->extend(get<Int>(i));
- break;
- }
-
- case inst::pushframe: {
-#ifdef DEBUG_FRAME
- vars=make_frame("<pushed frame>", 0, vars);
-#else
- vars=make_frame(0, vars);
-#endif
- break;
- }
-
- case inst::popframe: {
- vars=get<frame *>((*vars)[0]);
- break;
- }
-
default:
error("Internal VM error: Bad stack operand");
}
@@ -307,6 +533,10 @@ void stack::run(program *code, vars_t vars)
} catch (bad_item_value&) {
error("Trying to use uninitialized value.");
}
+
+#undef SET_VARLINK
+#undef VAR
+#undef FRAMEVAR
}
void stack::load(string index) {
@@ -356,24 +586,39 @@ void draw(ostream& out, frame* v)
out << "vars:" << endl;
while (!!v) {
- out << " " << v->getName() << ":";
+ item link=(*v)[v->getParentIndex()];
- frame *parent=0;
- item link=(*v)[0];
- try {
- parent = get<frame *>(link);
- out << (parent ? " link" : " ----");
- } catch (bad_item_value&) {
- out << " " << (*v)[0];
- }
+ out << " " << v->getName() << ": ";
- for (size_t i = 1; i < MAX_ITEMS && i < v->size(); i++) {
- out << " | " << i << ": " << (*v)[i];
+ for (size_t i = 0; i < MAX_ITEMS && i < v->size(); i++) {
+ if (i > 0)
+ out << " | ";
+ out << i << ": ";
+
+ if (i == v->getParentIndex()) {
+ try {
+ frame *parent = get<frame *>(link);
+ out << (parent ? "link" : "----");
+ } catch (bad_item_value&) {
+ out << "non-link " << (*v)[0];
+ }
+ } else {
+ out << (*v)[i];
+ }
}
+
if (v->size() > MAX_ITEMS)
out << "...";
out << "\n";
+
+ frame *parent;
+ try {
+ parent = get<frame *>(link);
+ } catch (bad_item_value&) {
+ parent = 0;
+ }
+
v = parent;
}
}
@@ -401,16 +646,17 @@ void error(const ostringstream& message)
error(message.str().c_str());
}
+const size_t STARTING_GLOBALS_SIZE = 1;
interactiveStack::interactiveStack()
-#ifdef DEBUG_FRAME
- : globals(new frame("globals", 0)) {}
-#else
- : globals(new frame(0)) {}
-#endif
-
+ : globals(make_globalframe(STARTING_GLOBALS_SIZE)),
+ globals_size(STARTING_GLOBALS_SIZE) {}
void interactiveStack::run(lambda *codelet) {
- stack::run(codelet->code, globals);
+ if (globals_size < codelet->framesize) {
+ resize_frame(globals, globals_size, codelet->framesize);
+ globals_size = codelet->framesize;
+ }
+ stack::runWithOrWithoutClosure(codelet, globals, 0);
}
} // namespace vm