diff -r 06a0015b6a5c -r 32ad0523b309 src/Stack.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Stack.cpp Tue Jul 24 23:53:34 2012 -0700 @@ -0,0 +1,321 @@ +/* vim: set ts=4 sw=4 tw=99 et: + * + * Copyright (C) 2012 David Anderson + * + * This file is part of JITCraft. + * + * JITCraft is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * JITCraft. If not, see http://www.gnu.org/licenses/. + */ +#include +#include +#include "Stack.h" +#include "Zone.h" +#include "Strings.h" +#include "Modules.h" +#include "Heap-inl.h" + +using namespace ke; + +Stack::Stack(Zone *zone) + : zone_(zone), + buffer_(NULL), + end_(NULL) +{ +} + +Stack::~Stack() +{ + free(buffer_); +} + +bool +Stack::initialize() +{ + buffer_ = (char *)malloc(STACK_SIZE); + if (!buffer_) + return false; + + top_.sp = reinterpret_cast(buffer_); + top_.pc = NULL; + top_.fp = NULL; + end_ = buffer_ + STACK_SIZE; + return true; +} + +InvokeArgs::~InvokeArgs() +{ + stack_->popInvokeFrame(*this); +} + +NativeArgs::~NativeArgs() +{ + stack_->popNativeFrame(*this); +} + +static inline size_t +SizeForCodeFrame(Code *code) +{ + return sizeof(Frame) + sizeof(LocalSlot) * (code->nlocals() + code->maxStackDepth()); +} + +bool +Stack::pushInvokeFrame(Handle fun, InvokeArgs &args) +{ + size_t nbytes = SizeForCodeFrame(fun->code()) + + sizeof(LocalSlot) * fun->nargs(); + if (reinterpret_cast(top_.sp) + nbytes >= end_) { + assert(false); + return false; + } + + memset(top_.sp, 0, sizeof(LocalSlot) * fun->nargs()); + args.args_ = top_.sp; + args.nargs_ = fun->nargs(); + args.stack_ = this; + top_.sp += fun->nargs(); + + Frame *frame = reinterpret_cast(top_.sp); + new (frame) Frame(top_.fp, top_.pc, fun, fun->code(), zone_->heap().lifoPosition()); + + top_.pc = frame->code()->start(); + top_.sp = frame->stackBase(); + top_.fp = frame; + + return true; +} + +bool +Stack::pushModuleFrame(Handle module, InvokeArgs &args) +{ + size_t nbytes = SizeForCodeFrame(module->code()); + if (reinterpret_cast(top_.sp) + nbytes >= end_) { + assert(false); + return false; + } + + args.args_ = top_.sp; + args.nargs_ = 0; + args.stack_ = this; + + Frame *frame = reinterpret_cast(top_.sp); + new (frame) Frame(top_.fp, top_.pc, NULL, module->code(), zone_->heap().lifoPosition()); + + top_.pc = frame->code()->start(); + top_.sp = frame->stackBase(); + top_.fp = frame; + + return true; +} + +bool +Stack::pushNativeFrame(Handle native, NativeArgs &args, unsigned argc) +{ + size_t nbytes = sizeof(intptr_t) * argc + sizeof(Frame); + if (reinterpret_cast(top_.sp) + nbytes >= end_) { + assert(false); + return false; + } + + memset(top_.sp, 0, sizeof(intptr_t) * argc); + args.argsBase_ = top_.sp; + args.stack_ = this; + top_.sp = reinterpret_cast(reinterpret_cast(top_.sp) + argc); + + Frame *frame = reinterpret_cast(top_.sp); + new (frame) Frame(top_.fp, top_.pc, native, zone_->heap().lifoPosition()); + + top_.pc = NULL; + top_.sp = reinterpret_cast(frame + 1); + top_.fp = frame; + + return true; +} + +Frame * +Stack::pushInlineFrame(Handle fun) +{ + Code *code = fun->code(); + size_t nbytes = SizeForCodeFrame(code); + if (reinterpret_cast(top_.sp) + nbytes >= end_) { + zone_->reportError(Message_TooMuchRecursion); + return NULL; + } + + Frame *frame = reinterpret_cast(top_.sp); + new (frame) Frame(top_.fp, top_.pc, fun, code, zone_->heap().lifoPosition()); + memset(frame->locals(), 0, sizeof(LocalSlot) * code->nlocals()); + + top_.pc = frame->code()->start(); + top_.sp = frame->stackBase(); + top_.fp = frame; + + return frame; +} + + +Frame * +Stack::popInlineFrame() +{ + zone_->heap().unwindLifo(top_.fp->lifoPosition()); + + Frame *prev = top_.fp->prev(); + Function *fun = top_.fp->fun(); + + top_.pc = top_.fp->prevpc(); + top_.sp = reinterpret_cast(top_.fp) - fun->nargs(); + top_.fp = prev; + return prev; +} + +void +Stack::popInvokeFrame(InvokeArgs &args) +{ + zone_->heap().unwindLifo(top_.fp->lifoPosition()); + + top_.pc = top_.fp->prevpc(); + top_.sp = args.args_; + top_.fp = top_.fp->prev(); +} + +void +Stack::popNativeFrame(NativeArgs &args) +{ + zone_->heap().unwindLifo(top_.fp->lifoPosition()); + + top_.pc = top_.fp->prevpc(); + top_.sp = args.argsBase_; + top_.fp = top_.fp->prev(); +} + +void +Frame::accept(VirtualObjectVisitor *visitor) +{ + visitor->visit(reinterpret_cast(&callee_)); + visitor->visit(reinterpret_cast(&code_)); +} + +static void +TraceFunctionFrame(VirtualObjectVisitor *visitor, Frame *fp, LocalSlot *sp, bytecode *pc) +{ + Code *code = fp->code(); + LocalSlot *slots = fp->locals(); + + // Trace local variables. + for (unsigned i = 0; i < code->nlocals(); i++) { + Type *type = code->localType(i); + if (type->isTraceable()) + visitor->visit(&slots[i].obj); + } + + // Trace arguments, if a function call. Note that this means we usually + // mark arguments twice, once on the caller side and once on the callee. + // This makes it easier to deal with invoke frames which have no caller. + if (Function *fun = fp->maybeFun()) { + for (unsigned i = 0; i < fun->nargs(); i++) { + Type *type = fun->argType(i); + if (type->isTraceable()) + visitor->visit(&fp->arg(i).obj); + } + } + + // Finally, trace stack slots. Not every gc-point in the bytecode will + // have a safepoint; since they are actually uncommon, we don't emit + // them unless at least one stack slot would be marked. + if (uint8 *safepoint = code->safepointAt(code->pcToOffset(pc))) { + LocalSlot *base = fp->stackBase(); + unsigned stackDepth = unsigned(sp - fp->stackBase()); + assert(stackDepth <= code->maxStackDepth()); + + for (unsigned i = 0; i < stackDepth; i++) { + if (safepoint[i / 8] & (1 << (i % 8))) + visitor->visit(&base[i].obj); + } + } +} + +void +Stack::accept(VirtualObjectVisitor *visitor) +{ + LocalSlot *sp = top_.sp; + bytecode *pc = top_.pc; + + for (Frame *frame = top_.fp; frame; frame = frame->prev()) { + if (!frame->isNative()) + TraceFunctionFrame(visitor, frame, sp, pc); + frame->accept(visitor); + + sp = reinterpret_cast(frame); + pc = frame->prevpc(); + } +} + +bool +Stack::isInCallStack(Handle module) +{ + for (Frame *frame = top_.fp; frame; frame = frame->prev()) { + if (frame->code()->module() == module) + return true; + } + return false; +} + +StackIter::StackIter(Zone *zone) + : pc_(zone->stack().top()->pc), + fp_(zone->stack().top()->fp) +{ +} + +bool +StackIter::done() const +{ + return !fp_; +} + +const char * +StackIter::function() const +{ + if (fp_->isNative()) + return fp_->native()->name()->chars(); + if (Function *fun = fp_->maybeFun()) + return fun->name()->chars(); + return ""; +} + +unsigned +StackIter::lineNumber() const +{ + if (fp_->isNative()) + return 0; + if (fp_->maybeFun()) { + unsigned offs = fp_->code()->pcToOffset(pc_); + return fp_->code()->pcToSource(offs).line; + } + return fp_->code()->lineNumber(); +} + +const char * +StackIter::source() const +{ + if (fp_->isNative()) + return ""; + return fp_->code()->module()->file() + ? fp_->code()->module()->file()->chars() + : "(anonymous)"; +} + +void +StackIter::prev() +{ + pc_ = fp_->prevpc(); + fp_ = fp_->prev(); +}