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