jitcraft/Stack.cpp
author David Anderson <dvander@alliedmods.net>
Tue Jul 10 02:11:13 2012 -0700 (2012-07-10)
changeset 68 b40b0e18a918
parent 65 7c942b5adebc
child 69 dfce0539a77d
permissions -rw-r--r--
Added support for ISourcePawnEngine natives.
     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 "Heap-inl.h"
    24 
    25 using namespace ke;
    26 
    27 Stack::Stack()
    28   : buffer_(NULL),
    29     end_(NULL)
    30 {
    31 }
    32 
    33 Stack::~Stack()
    34 {
    35     free(buffer_);
    36 }
    37 
    38 bool
    39 Stack::initialize()
    40 {
    41     buffer_ = (char *)malloc(STACK_SIZE);
    42     if (!buffer_)
    43         return false;
    44 
    45     top_.sp = reinterpret_cast<LocalSlot *>(buffer_);
    46     top_.pc = NULL;
    47     top_.fp = NULL;
    48     end_ = buffer_ + STACK_SIZE;
    49     return true;
    50 }
    51 
    52 InvokeArgs::~InvokeArgs()
    53 {
    54     stack_->popInvokeFrame(*this);
    55 }
    56 
    57 NativeArgs::~NativeArgs()
    58 {
    59     stack_->popNativeFrame(*this);
    60 }
    61 
    62 static inline size_t
    63 SizeForCodeFrame(Code *code)
    64 {
    65     return sizeof(Frame) + sizeof(LocalSlot) * (code->nlocals() + code->maxStackDepth());
    66 }
    67 
    68 bool
    69 Stack::pushInvokeFrame(Handle<Function> fun, InvokeArgs &args)
    70 {
    71     size_t nbytes = SizeForCodeFrame(fun->code()) +
    72                     sizeof(LocalSlot) * fun->nargs();
    73     if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
    74         assert(false);
    75         return false;
    76     }
    77 
    78     memset(top_.sp, 0, sizeof(LocalSlot) * fun->nargs());
    79     args.args_ = top_.sp;
    80     args.nargs_ = fun->nargs();
    81     args.stack_ = this;
    82     top_.sp += fun->nargs();
    83     
    84     Frame *frame = reinterpret_cast<Frame *>(top_.sp);
    85     new (frame) Frame(top_.fp, top_.pc, fun, fun->code(), ZONE()->heap().lifoPosition());
    86     
    87     top_.pc = frame->code()->start();
    88     top_.sp = frame->stackBase();
    89     top_.fp = frame;
    90 
    91     return true;
    92 }
    93 
    94 bool
    95 Stack::pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc)
    96 {
    97     size_t nbytes = sizeof(intptr_t) * argc + sizeof(Frame);
    98     if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
    99         assert(false);
   100         return false;
   101     }
   102 
   103     memset(top_.sp, 0, sizeof(intptr_t) * argc);
   104     args.argsBase_ = top_.sp;
   105     args.stack_ = this;
   106     top_.sp = reinterpret_cast<LocalSlot *>(reinterpret_cast<intptr_t *>(top_.sp) + argc);
   107 
   108     Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   109     new (frame) Frame(top_.fp, top_.pc, native, ZONE()->heap().lifoPosition());
   110 
   111     top_.pc = NULL;
   112     top_.sp = reinterpret_cast<LocalSlot *>(frame + 1);
   113     top_.fp = frame;
   114 
   115     return true;
   116 }
   117 
   118 Frame *
   119 Stack::pushInlineFrame(Handle<Function> fun)
   120 {
   121     Code *code = fun->code();
   122     size_t nbytes = SizeForCodeFrame(code);
   123     if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
   124         assert(false);
   125         return NULL;
   126     }
   127 
   128     Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   129     new (frame) Frame(top_.fp, top_.pc, fun, code, ZONE()->heap().lifoPosition());
   130     memset(frame->locals(), 0, sizeof(LocalSlot) * code->nlocals());
   131 
   132     top_.pc = frame->code()->start();
   133     top_.sp = frame->stackBase();
   134     top_.fp = frame;
   135 
   136     return frame;
   137 }
   138 
   139 
   140 Frame *
   141 Stack::popInlineFrame()
   142 {
   143     ZONE()->heap().unwindLifo(top_.fp->lifoPosition());
   144 
   145     Frame *prev = top_.fp->prev();
   146     Function *fun = top_.fp->maybeFun();
   147     Code *code = top_.fp->code();
   148 
   149     size_t nbytes = sizeof(LocalSlot) * code->nlocals() +
   150                     sizeof(Frame) +
   151                     sizeof(LocalSlot) * (fun ? fun->nargs() : 0);
   152 
   153     top_.pc = top_.fp->prevpc();
   154     top_.sp = reinterpret_cast<LocalSlot *>(reinterpret_cast<char *>(top_.sp) - nbytes);
   155     top_.fp = prev;
   156     return prev;
   157 }
   158 
   159 void
   160 Stack::popInvokeFrame(InvokeArgs &args)
   161 {
   162     ZONE()->heap().unwindLifo(top_.fp->lifoPosition());
   163 
   164     top_.pc = top_.fp->prevpc();
   165     top_.sp = args.args_;
   166     top_.fp = top_.fp->prev();
   167 }
   168 
   169 void
   170 Stack::popNativeFrame(NativeArgs &args)
   171 {
   172     ZONE()->heap().unwindLifo(top_.fp->lifoPosition());
   173 
   174     top_.pc = top_.fp->prevpc();
   175     top_.sp = args.argsBase_;
   176     top_.fp = top_.fp->prev();
   177 }
   178 
   179 void
   180 Frame::accept(VirtualObjectVisitor *visitor)
   181 {
   182     visitor->visit(reinterpret_cast<Object **>(&callee_));
   183     visitor->visit(reinterpret_cast<Object **>(&code_));
   184 }
   185 
   186 static void
   187 TraceFunctionFrame(VirtualObjectVisitor *visitor, Frame *fp, LocalSlot *sp, bytecode *pc)
   188 {
   189     Code *code = fp->code();
   190     LocalSlot *slots = fp->locals();
   191 
   192     // Trace local variables.
   193     for (unsigned i = 0; i < code->nlocals(); i++) {
   194         Type *type = code->localType(i);
   195         if (type->isTraceable())
   196             visitor->visit(&slots[i].obj);
   197     }
   198 
   199     // Trace arguments, if a function call. Note that this means we usually
   200     // mark arguments twice, once on the caller side and once on the callee.
   201     // This makes it easier to deal with invoke frames which have no caller.
   202     if (Function *fun = fp->maybeFun()) {
   203         for (unsigned i = 0; i < fun->nargs(); i++) {
   204             Type *type = fun->argType(i);
   205             if (type->isTraceable())
   206                 visitor->visit(&fp->arg(i).obj);
   207         }
   208     }
   209 
   210     // Finally, trace stack slots. Not every gc-point in the bytecode will
   211     // have a safepoint; since they are actually uncommon, we don't emit
   212     // them unless at least one stack slot would be marked.
   213     if (uint8 *safepoint = code->safepointAt(code->pcToOffset(pc))) {
   214         LocalSlot *base = fp->stackBase();
   215         unsigned stackDepth = unsigned(sp - fp->stackBase());
   216         assert(stackDepth <= code->maxStackDepth());
   217 
   218         for (unsigned i = 0; i < stackDepth; i++) {
   219             if (safepoint[i / 8] & (1 << (i % 8)))
   220                 visitor->visit(&base[i].obj);
   221         }
   222     }
   223 }
   224 
   225 void
   226 Stack::accept(VirtualObjectVisitor *visitor)
   227 {
   228     LocalSlot *sp = top_.sp;
   229     bytecode *pc = top_.pc;
   230 
   231     for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
   232         if (!frame->isNative())
   233             TraceFunctionFrame(visitor, frame, sp, pc);
   234         frame->accept(visitor);
   235 
   236         sp = reinterpret_cast<LocalSlot *>(frame);
   237         pc = frame->prevpc();
   238     }
   239 }
   240 
   241 bool
   242 Stack::isInCallStack(Handle<Module> module)
   243 {
   244     for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
   245         if (frame->code()->module() == module)
   246             return true;
   247     }
   248     return false;
   249 }
   250 
   251