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