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