src/Stack.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jul 25 00:13:02 2012 -0700 (2012-07-25)
changeset 88 fc3f34f928dd
parent 86 32ad0523b309
child 91 5f4402180204
permissions -rw-r--r--
Added AMBuild support.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include <new>
    20 #include <stdlib.h>
    21 #include "Stack.h"
    22 #include "Zone.h"
    23 #include "Strings.h"
    24 #include "Modules.h"
    25 #include "Heap-inl.h"
    26 
    27 using namespace ke;
    28 
    29 Stack::Stack(Zone *zone)
    30   : zone_(zone),
    31     buffer_(NULL),
    32     end_(NULL)
    33 {
    34 }
    35 
    36 Stack::~Stack()
    37 {
    38     free(buffer_);
    39 }
    40 
    41 bool
    42 Stack::initialize()
    43 {
    44     buffer_ = (char *)malloc(STACK_SIZE);
    45     if (!buffer_)
    46         return false;
    47 
    48     top_.sp = reinterpret_cast<LocalSlot *>(buffer_);
    49     top_.pc = NULL;
    50     top_.fp = NULL;
    51     end_ = buffer_ + STACK_SIZE;
    52     return true;
    53 }
    54 
    55 InvokeArgs::~InvokeArgs()
    56 {
    57     stack_->popInvokeFrame(*this);
    58 }
    59 
    60 NativeArgs::~NativeArgs()
    61 {
    62     stack_->popNativeFrame(*this);
    63 }
    64 
    65 static inline size_t
    66 SizeForCodeFrame(Code *code)
    67 {
    68     return sizeof(Frame) + sizeof(LocalSlot) * (code->nlocals() + code->maxStackDepth());
    69 }
    70 
    71 bool
    72 Stack::pushInvokeFrame(Handle<Function> fun, InvokeArgs &args)
    73 {
    74     size_t nbytes = SizeForCodeFrame(fun->code()) +
    75                     sizeof(LocalSlot) * fun->nargs();
    76     if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
    77         assert(false);
    78         return false;
    79     }
    80 
    81     memset(top_.sp, 0, sizeof(LocalSlot) * fun->nargs());
    82     args.args_ = top_.sp;
    83     args.nargs_ = fun->nargs();
    84     args.stack_ = this;
    85     top_.sp += fun->nargs();
    86     
    87     Frame *frame = reinterpret_cast<Frame *>(top_.sp);
    88     new (frame) Frame(top_.fp, top_.pc, fun, fun->code(), zone_->heap().lifoPosition());
    89     
    90     top_.pc = frame->code()->start();
    91     top_.sp = frame->stackBase();
    92     top_.fp = frame;
    93 
    94     return true;
    95 }
    96 
    97 bool
    98 Stack::pushModuleFrame(Handle<Module> module, InvokeArgs &args)
    99 {
   100     size_t nbytes = SizeForCodeFrame(module->code());
   101     if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
   102         assert(false);
   103         return false;
   104     }
   105 
   106     args.args_ = top_.sp;
   107     args.nargs_ = 0;
   108     args.stack_ = this;
   109     
   110     Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   111     new (frame) Frame(top_.fp, top_.pc, NULL, module->code(), zone_->heap().lifoPosition());
   112     
   113     top_.pc = frame->code()->start();
   114     top_.sp = frame->stackBase();
   115     top_.fp = frame;
   116 
   117     return true;
   118 }
   119 
   120 bool
   121 Stack::pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc)
   122 {
   123     size_t nbytes = sizeof(intptr_t) * argc + sizeof(Frame);
   124     if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
   125         assert(false);
   126         return false;
   127     }
   128 
   129     memset(top_.sp, 0, sizeof(intptr_t) * argc);
   130     args.argsBase_ = top_.sp;
   131     args.stack_ = this;
   132     top_.sp = reinterpret_cast<LocalSlot *>(reinterpret_cast<intptr_t *>(top_.sp) + argc);
   133 
   134     Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   135     new (frame) Frame(top_.fp, top_.pc, native, zone_->heap().lifoPosition());
   136 
   137     top_.pc = NULL;
   138     top_.sp = reinterpret_cast<LocalSlot *>(frame + 1);
   139     top_.fp = frame;
   140 
   141     return true;
   142 }
   143 
   144 Frame *
   145 Stack::pushInlineFrame(Handle<Function> fun)
   146 {
   147     Code *code = fun->code();
   148     size_t nbytes = SizeForCodeFrame(code);
   149     if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
   150         zone_->reportError(Message_TooMuchRecursion);
   151         return NULL;
   152     }
   153 
   154     Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   155     new (frame) Frame(top_.fp, top_.pc, fun, code, zone_->heap().lifoPosition());
   156     memset(frame->locals(), 0, sizeof(LocalSlot) * code->nlocals());
   157 
   158     top_.pc = frame->code()->start();
   159     top_.sp = frame->stackBase();
   160     top_.fp = frame;
   161 
   162     return frame;
   163 }
   164 
   165 
   166 Frame *
   167 Stack::popInlineFrame()
   168 {
   169     zone_->heap().unwindLifo(top_.fp->lifoPosition());
   170 
   171     Frame *prev = top_.fp->prev();
   172     Function *fun = top_.fp->fun();
   173 
   174     top_.pc = top_.fp->prevpc();
   175     top_.sp = reinterpret_cast<LocalSlot *>(top_.fp) - fun->nargs();
   176     top_.fp = prev;
   177     return prev;
   178 }
   179 
   180 void
   181 Stack::popInvokeFrame(InvokeArgs &args)
   182 {
   183     zone_->heap().unwindLifo(top_.fp->lifoPosition());
   184 
   185     top_.pc = top_.fp->prevpc();
   186     top_.sp = args.args_;
   187     top_.fp = top_.fp->prev();
   188 }
   189 
   190 void
   191 Stack::popNativeFrame(NativeArgs &args)
   192 {
   193     zone_->heap().unwindLifo(top_.fp->lifoPosition());
   194 
   195     top_.pc = top_.fp->prevpc();
   196     top_.sp = args.argsBase_;
   197     top_.fp = top_.fp->prev();
   198 }
   199 
   200 void
   201 Frame::accept(VirtualObjectVisitor *visitor)
   202 {
   203     visitor->visit(reinterpret_cast<Object **>(&callee_));
   204     visitor->visit(reinterpret_cast<Object **>(&code_));
   205 }
   206 
   207 static void
   208 TraceFunctionFrame(VirtualObjectVisitor *visitor, Frame *fp, LocalSlot *sp, bytecode *pc)
   209 {
   210     Code *code = fp->code();
   211     LocalSlot *slots = fp->locals();
   212 
   213     // Trace local variables.
   214     for (unsigned i = 0; i < code->nlocals(); i++) {
   215         Type *type = code->localType(i);
   216         if (type->isTraceable())
   217             visitor->visit(&slots[i].obj);
   218     }
   219 
   220     // Trace arguments, if a function call. Note that this means we usually
   221     // mark arguments twice, once on the caller side and once on the callee.
   222     // This makes it easier to deal with invoke frames which have no caller.
   223     if (Function *fun = fp->maybeFun()) {
   224         for (unsigned i = 0; i < fun->nargs(); i++) {
   225             Type *type = fun->argType(i);
   226             if (type->isTraceable())
   227                 visitor->visit(&fp->arg(i).obj);
   228         }
   229     }
   230 
   231     // Finally, trace stack slots. Not every gc-point in the bytecode will
   232     // have a safepoint; since they are actually uncommon, we don't emit
   233     // them unless at least one stack slot would be marked.
   234     if (uint8 *safepoint = code->safepointAt(code->pcToOffset(pc))) {
   235         LocalSlot *base = fp->stackBase();
   236         unsigned stackDepth = unsigned(sp - fp->stackBase());
   237         assert(stackDepth <= code->maxStackDepth());
   238 
   239         for (unsigned i = 0; i < stackDepth; i++) {
   240             if (safepoint[i / 8] & (1 << (i % 8)))
   241                 visitor->visit(&base[i].obj);
   242         }
   243     }
   244 }
   245 
   246 void
   247 Stack::accept(VirtualObjectVisitor *visitor)
   248 {
   249     LocalSlot *sp = top_.sp;
   250     bytecode *pc = top_.pc;
   251 
   252     for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
   253         if (!frame->isNative())
   254             TraceFunctionFrame(visitor, frame, sp, pc);
   255         frame->accept(visitor);
   256 
   257         sp = reinterpret_cast<LocalSlot *>(frame);
   258         pc = frame->prevpc();
   259     }
   260 }
   261 
   262 bool
   263 Stack::isInCallStack(Handle<Module> module)
   264 {
   265     for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
   266         if (frame->code()->module() == module)
   267             return true;
   268     }
   269     return false;
   270 }
   271 
   272 StackIter::StackIter(Zone *zone)
   273   : pc_(zone->stack().top()->pc),
   274     fp_(zone->stack().top()->fp)
   275 {
   276 }
   277 
   278 bool
   279 StackIter::done() const
   280 {
   281     return !fp_;
   282 }
   283 
   284 const char *
   285 StackIter::function() const
   286 {
   287     if (fp_->isNative())
   288         return fp_->native()->name()->chars();
   289     if (Function *fun = fp_->maybeFun())
   290         return fun->name()->chars();
   291     return "<toplevel>";
   292 }
   293 
   294 unsigned
   295 StackIter::lineNumber() const
   296 {
   297     if (fp_->isNative())
   298         return 0;
   299     if (fp_->maybeFun()) {
   300         unsigned offs = fp_->code()->pcToOffset(pc_);
   301         return fp_->code()->pcToSource(offs).line;
   302     }
   303     return fp_->code()->lineNumber();
   304 }
   305 
   306 const char *
   307 StackIter::source() const
   308 {
   309     if (fp_->isNative())
   310         return "<native>";
   311     return fp_->code()->module()->file()
   312            ? fp_->code()->module()->file()->chars()
   313            : "(anonymous)";
   314 }
   315 
   316 void
   317 StackIter::prev()
   318 {
   319     pc_ = fp_->prevpc();
   320     fp_ = fp_->prev();
   321 }