jitcraft/Stack.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jul 12 00:38:00 2012 -0700 (2012-07-12)
changeset 70 1aec996cde2d
parent 69 dfce0539a77d
child 85 06a0015b6a5c
permissions -rw-r--r--
Add support for line and file information in backtraces.
     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::pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc)
    99 {
   100     size_t nbytes = sizeof(intptr_t) * argc + sizeof(Frame);
   101     if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
   102         assert(false);
   103         return false;
   104     }
   105 
   106     memset(top_.sp, 0, sizeof(intptr_t) * argc);
   107     args.argsBase_ = top_.sp;
   108     args.stack_ = this;
   109     top_.sp = reinterpret_cast<LocalSlot *>(reinterpret_cast<intptr_t *>(top_.sp) + argc);
   110 
   111     Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   112     new (frame) Frame(top_.fp, top_.pc, native, zone_->heap().lifoPosition());
   113 
   114     top_.pc = NULL;
   115     top_.sp = reinterpret_cast<LocalSlot *>(frame + 1);
   116     top_.fp = frame;
   117 
   118     return true;
   119 }
   120 
   121 Frame *
   122 Stack::pushInlineFrame(Handle<Function> fun)
   123 {
   124     Code *code = fun->code();
   125     size_t nbytes = SizeForCodeFrame(code);
   126     if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
   127         zone_->reportError(Message_TooMuchRecursion);
   128         return NULL;
   129     }
   130 
   131     Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   132     new (frame) Frame(top_.fp, top_.pc, fun, code, zone_->heap().lifoPosition());
   133     memset(frame->locals(), 0, sizeof(LocalSlot) * code->nlocals());
   134 
   135     top_.pc = frame->code()->start();
   136     top_.sp = frame->stackBase();
   137     top_.fp = frame;
   138 
   139     return frame;
   140 }
   141 
   142 
   143 Frame *
   144 Stack::popInlineFrame()
   145 {
   146     zone_->heap().unwindLifo(top_.fp->lifoPosition());
   147 
   148     Frame *prev = top_.fp->prev();
   149     Function *fun = top_.fp->fun();
   150 
   151     top_.pc = top_.fp->prevpc();
   152     top_.sp = reinterpret_cast<LocalSlot *>(top_.fp) - fun->nargs();
   153     top_.fp = prev;
   154     return prev;
   155 }
   156 
   157 void
   158 Stack::popInvokeFrame(InvokeArgs &args)
   159 {
   160     zone_->heap().unwindLifo(top_.fp->lifoPosition());
   161 
   162     top_.pc = top_.fp->prevpc();
   163     top_.sp = args.args_;
   164     top_.fp = top_.fp->prev();
   165 }
   166 
   167 void
   168 Stack::popNativeFrame(NativeArgs &args)
   169 {
   170     zone_->heap().unwindLifo(top_.fp->lifoPosition());
   171 
   172     top_.pc = top_.fp->prevpc();
   173     top_.sp = args.argsBase_;
   174     top_.fp = top_.fp->prev();
   175 }
   176 
   177 void
   178 Frame::accept(VirtualObjectVisitor *visitor)
   179 {
   180     visitor->visit(reinterpret_cast<Object **>(&callee_));
   181     visitor->visit(reinterpret_cast<Object **>(&code_));
   182 }
   183 
   184 static void
   185 TraceFunctionFrame(VirtualObjectVisitor *visitor, Frame *fp, LocalSlot *sp, bytecode *pc)
   186 {
   187     Code *code = fp->code();
   188     LocalSlot *slots = fp->locals();
   189 
   190     // Trace local variables.
   191     for (unsigned i = 0; i < code->nlocals(); i++) {
   192         Type *type = code->localType(i);
   193         if (type->isTraceable())
   194             visitor->visit(&slots[i].obj);
   195     }
   196 
   197     // Trace arguments, if a function call. Note that this means we usually
   198     // mark arguments twice, once on the caller side and once on the callee.
   199     // This makes it easier to deal with invoke frames which have no caller.
   200     if (Function *fun = fp->maybeFun()) {
   201         for (unsigned i = 0; i < fun->nargs(); i++) {
   202             Type *type = fun->argType(i);
   203             if (type->isTraceable())
   204                 visitor->visit(&fp->arg(i).obj);
   205         }
   206     }
   207 
   208     // Finally, trace stack slots. Not every gc-point in the bytecode will
   209     // have a safepoint; since they are actually uncommon, we don't emit
   210     // them unless at least one stack slot would be marked.
   211     if (uint8 *safepoint = code->safepointAt(code->pcToOffset(pc))) {
   212         LocalSlot *base = fp->stackBase();
   213         unsigned stackDepth = unsigned(sp - fp->stackBase());
   214         assert(stackDepth <= code->maxStackDepth());
   215 
   216         for (unsigned i = 0; i < stackDepth; i++) {
   217             if (safepoint[i / 8] & (1 << (i % 8)))
   218                 visitor->visit(&base[i].obj);
   219         }
   220     }
   221 }
   222 
   223 void
   224 Stack::accept(VirtualObjectVisitor *visitor)
   225 {
   226     LocalSlot *sp = top_.sp;
   227     bytecode *pc = top_.pc;
   228 
   229     for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
   230         if (!frame->isNative())
   231             TraceFunctionFrame(visitor, frame, sp, pc);
   232         frame->accept(visitor);
   233 
   234         sp = reinterpret_cast<LocalSlot *>(frame);
   235         pc = frame->prevpc();
   236     }
   237 }
   238 
   239 bool
   240 Stack::isInCallStack(Handle<Module> module)
   241 {
   242     for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
   243         if (frame->code()->module() == module)
   244             return true;
   245     }
   246     return false;
   247 }
   248 
   249 StackIter::StackIter(Zone *zone)
   250   : pc_(zone->stack().top()->pc),
   251     fp_(zone->stack().top()->fp)
   252 {
   253 }
   254 
   255 bool
   256 StackIter::done() const
   257 {
   258     return !fp_;
   259 }
   260 
   261 const char *
   262 StackIter::function() const
   263 {
   264     if (fp_->isNative())
   265         return fp_->native()->name()->chars();
   266     if (Function *fun = fp_->maybeFun())
   267         return fun->name()->chars();
   268     return "<toplevel>";
   269 }
   270 
   271 unsigned
   272 StackIter::lineNumber() const
   273 {
   274     if (fp_->isNative())
   275         return 0;
   276     if (fp_->maybeFun()) {
   277         unsigned offs = fp_->code()->pcToOffset(pc_);
   278         return fp_->code()->pcToSource(offs).line;
   279     }
   280     return fp_->code()->lineNumber();
   281 }
   282 
   283 const char *
   284 StackIter::source() const
   285 {
   286     if (fp_->isNative())
   287         return "<native>";
   288     return fp_->code()->module()->file()
   289            ? fp_->code()->module()->file()->chars()
   290            : "(anonymous)";
   291 }
   292 
   293 void
   294 StackIter::prev()
   295 {
   296     pc_ = fp_->prevpc();
   297     fp_ = fp_->prev();
   298 }