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