src/Stack.cpp
changeset 86 32ad0523b309
parent 85 06a0015b6a5c
child 91 5f4402180204
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/Stack.cpp	Tue Jul 24 23:53:34 2012 -0700
     1.3 @@ -0,0 +1,321 @@
     1.4 +/* vim: set ts=4 sw=4 tw=99 et:
     1.5 + *
     1.6 + * Copyright (C) 2012 David Anderson
     1.7 + *
     1.8 + * This file is part of JITCraft.
     1.9 + *
    1.10 + * JITCraft is free software: you can redistribute it and/or modify it under
    1.11 + * the terms of the GNU General Public License as published by the Free
    1.12 + * Software Foundation, either version 3 of the License, or (at your option)
    1.13 + * any later version.
    1.14 + * 
    1.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    1.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License along with
    1.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
    1.21 + */
    1.22 +#include <new>
    1.23 +#include <stdlib.h>
    1.24 +#include "Stack.h"
    1.25 +#include "Zone.h"
    1.26 +#include "Strings.h"
    1.27 +#include "Modules.h"
    1.28 +#include "Heap-inl.h"
    1.29 +
    1.30 +using namespace ke;
    1.31 +
    1.32 +Stack::Stack(Zone *zone)
    1.33 +  : zone_(zone),
    1.34 +    buffer_(NULL),
    1.35 +    end_(NULL)
    1.36 +{
    1.37 +}
    1.38 +
    1.39 +Stack::~Stack()
    1.40 +{
    1.41 +    free(buffer_);
    1.42 +}
    1.43 +
    1.44 +bool
    1.45 +Stack::initialize()
    1.46 +{
    1.47 +    buffer_ = (char *)malloc(STACK_SIZE);
    1.48 +    if (!buffer_)
    1.49 +        return false;
    1.50 +
    1.51 +    top_.sp = reinterpret_cast<LocalSlot *>(buffer_);
    1.52 +    top_.pc = NULL;
    1.53 +    top_.fp = NULL;
    1.54 +    end_ = buffer_ + STACK_SIZE;
    1.55 +    return true;
    1.56 +}
    1.57 +
    1.58 +InvokeArgs::~InvokeArgs()
    1.59 +{
    1.60 +    stack_->popInvokeFrame(*this);
    1.61 +}
    1.62 +
    1.63 +NativeArgs::~NativeArgs()
    1.64 +{
    1.65 +    stack_->popNativeFrame(*this);
    1.66 +}
    1.67 +
    1.68 +static inline size_t
    1.69 +SizeForCodeFrame(Code *code)
    1.70 +{
    1.71 +    return sizeof(Frame) + sizeof(LocalSlot) * (code->nlocals() + code->maxStackDepth());
    1.72 +}
    1.73 +
    1.74 +bool
    1.75 +Stack::pushInvokeFrame(Handle<Function> fun, InvokeArgs &args)
    1.76 +{
    1.77 +    size_t nbytes = SizeForCodeFrame(fun->code()) +
    1.78 +                    sizeof(LocalSlot) * fun->nargs();
    1.79 +    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
    1.80 +        assert(false);
    1.81 +        return false;
    1.82 +    }
    1.83 +
    1.84 +    memset(top_.sp, 0, sizeof(LocalSlot) * fun->nargs());
    1.85 +    args.args_ = top_.sp;
    1.86 +    args.nargs_ = fun->nargs();
    1.87 +    args.stack_ = this;
    1.88 +    top_.sp += fun->nargs();
    1.89 +    
    1.90 +    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
    1.91 +    new (frame) Frame(top_.fp, top_.pc, fun, fun->code(), zone_->heap().lifoPosition());
    1.92 +    
    1.93 +    top_.pc = frame->code()->start();
    1.94 +    top_.sp = frame->stackBase();
    1.95 +    top_.fp = frame;
    1.96 +
    1.97 +    return true;
    1.98 +}
    1.99 +
   1.100 +bool
   1.101 +Stack::pushModuleFrame(Handle<Module> module, InvokeArgs &args)
   1.102 +{
   1.103 +    size_t nbytes = SizeForCodeFrame(module->code());
   1.104 +    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
   1.105 +        assert(false);
   1.106 +        return false;
   1.107 +    }
   1.108 +
   1.109 +    args.args_ = top_.sp;
   1.110 +    args.nargs_ = 0;
   1.111 +    args.stack_ = this;
   1.112 +    
   1.113 +    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   1.114 +    new (frame) Frame(top_.fp, top_.pc, NULL, module->code(), zone_->heap().lifoPosition());
   1.115 +    
   1.116 +    top_.pc = frame->code()->start();
   1.117 +    top_.sp = frame->stackBase();
   1.118 +    top_.fp = frame;
   1.119 +
   1.120 +    return true;
   1.121 +}
   1.122 +
   1.123 +bool
   1.124 +Stack::pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc)
   1.125 +{
   1.126 +    size_t nbytes = sizeof(intptr_t) * argc + sizeof(Frame);
   1.127 +    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
   1.128 +        assert(false);
   1.129 +        return false;
   1.130 +    }
   1.131 +
   1.132 +    memset(top_.sp, 0, sizeof(intptr_t) * argc);
   1.133 +    args.argsBase_ = top_.sp;
   1.134 +    args.stack_ = this;
   1.135 +    top_.sp = reinterpret_cast<LocalSlot *>(reinterpret_cast<intptr_t *>(top_.sp) + argc);
   1.136 +
   1.137 +    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   1.138 +    new (frame) Frame(top_.fp, top_.pc, native, zone_->heap().lifoPosition());
   1.139 +
   1.140 +    top_.pc = NULL;
   1.141 +    top_.sp = reinterpret_cast<LocalSlot *>(frame + 1);
   1.142 +    top_.fp = frame;
   1.143 +
   1.144 +    return true;
   1.145 +}
   1.146 +
   1.147 +Frame *
   1.148 +Stack::pushInlineFrame(Handle<Function> fun)
   1.149 +{
   1.150 +    Code *code = fun->code();
   1.151 +    size_t nbytes = SizeForCodeFrame(code);
   1.152 +    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
   1.153 +        zone_->reportError(Message_TooMuchRecursion);
   1.154 +        return NULL;
   1.155 +    }
   1.156 +
   1.157 +    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   1.158 +    new (frame) Frame(top_.fp, top_.pc, fun, code, zone_->heap().lifoPosition());
   1.159 +    memset(frame->locals(), 0, sizeof(LocalSlot) * code->nlocals());
   1.160 +
   1.161 +    top_.pc = frame->code()->start();
   1.162 +    top_.sp = frame->stackBase();
   1.163 +    top_.fp = frame;
   1.164 +
   1.165 +    return frame;
   1.166 +}
   1.167 +
   1.168 +
   1.169 +Frame *
   1.170 +Stack::popInlineFrame()
   1.171 +{
   1.172 +    zone_->heap().unwindLifo(top_.fp->lifoPosition());
   1.173 +
   1.174 +    Frame *prev = top_.fp->prev();
   1.175 +    Function *fun = top_.fp->fun();
   1.176 +
   1.177 +    top_.pc = top_.fp->prevpc();
   1.178 +    top_.sp = reinterpret_cast<LocalSlot *>(top_.fp) - fun->nargs();
   1.179 +    top_.fp = prev;
   1.180 +    return prev;
   1.181 +}
   1.182 +
   1.183 +void
   1.184 +Stack::popInvokeFrame(InvokeArgs &args)
   1.185 +{
   1.186 +    zone_->heap().unwindLifo(top_.fp->lifoPosition());
   1.187 +
   1.188 +    top_.pc = top_.fp->prevpc();
   1.189 +    top_.sp = args.args_;
   1.190 +    top_.fp = top_.fp->prev();
   1.191 +}
   1.192 +
   1.193 +void
   1.194 +Stack::popNativeFrame(NativeArgs &args)
   1.195 +{
   1.196 +    zone_->heap().unwindLifo(top_.fp->lifoPosition());
   1.197 +
   1.198 +    top_.pc = top_.fp->prevpc();
   1.199 +    top_.sp = args.argsBase_;
   1.200 +    top_.fp = top_.fp->prev();
   1.201 +}
   1.202 +
   1.203 +void
   1.204 +Frame::accept(VirtualObjectVisitor *visitor)
   1.205 +{
   1.206 +    visitor->visit(reinterpret_cast<Object **>(&callee_));
   1.207 +    visitor->visit(reinterpret_cast<Object **>(&code_));
   1.208 +}
   1.209 +
   1.210 +static void
   1.211 +TraceFunctionFrame(VirtualObjectVisitor *visitor, Frame *fp, LocalSlot *sp, bytecode *pc)
   1.212 +{
   1.213 +    Code *code = fp->code();
   1.214 +    LocalSlot *slots = fp->locals();
   1.215 +
   1.216 +    // Trace local variables.
   1.217 +    for (unsigned i = 0; i < code->nlocals(); i++) {
   1.218 +        Type *type = code->localType(i);
   1.219 +        if (type->isTraceable())
   1.220 +            visitor->visit(&slots[i].obj);
   1.221 +    }
   1.222 +
   1.223 +    // Trace arguments, if a function call. Note that this means we usually
   1.224 +    // mark arguments twice, once on the caller side and once on the callee.
   1.225 +    // This makes it easier to deal with invoke frames which have no caller.
   1.226 +    if (Function *fun = fp->maybeFun()) {
   1.227 +        for (unsigned i = 0; i < fun->nargs(); i++) {
   1.228 +            Type *type = fun->argType(i);
   1.229 +            if (type->isTraceable())
   1.230 +                visitor->visit(&fp->arg(i).obj);
   1.231 +        }
   1.232 +    }
   1.233 +
   1.234 +    // Finally, trace stack slots. Not every gc-point in the bytecode will
   1.235 +    // have a safepoint; since they are actually uncommon, we don't emit
   1.236 +    // them unless at least one stack slot would be marked.
   1.237 +    if (uint8 *safepoint = code->safepointAt(code->pcToOffset(pc))) {
   1.238 +        LocalSlot *base = fp->stackBase();
   1.239 +        unsigned stackDepth = unsigned(sp - fp->stackBase());
   1.240 +        assert(stackDepth <= code->maxStackDepth());
   1.241 +
   1.242 +        for (unsigned i = 0; i < stackDepth; i++) {
   1.243 +            if (safepoint[i / 8] & (1 << (i % 8)))
   1.244 +                visitor->visit(&base[i].obj);
   1.245 +        }
   1.246 +    }
   1.247 +}
   1.248 +
   1.249 +void
   1.250 +Stack::accept(VirtualObjectVisitor *visitor)
   1.251 +{
   1.252 +    LocalSlot *sp = top_.sp;
   1.253 +    bytecode *pc = top_.pc;
   1.254 +
   1.255 +    for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
   1.256 +        if (!frame->isNative())
   1.257 +            TraceFunctionFrame(visitor, frame, sp, pc);
   1.258 +        frame->accept(visitor);
   1.259 +
   1.260 +        sp = reinterpret_cast<LocalSlot *>(frame);
   1.261 +        pc = frame->prevpc();
   1.262 +    }
   1.263 +}
   1.264 +
   1.265 +bool
   1.266 +Stack::isInCallStack(Handle<Module> module)
   1.267 +{
   1.268 +    for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
   1.269 +        if (frame->code()->module() == module)
   1.270 +            return true;
   1.271 +    }
   1.272 +    return false;
   1.273 +}
   1.274 +
   1.275 +StackIter::StackIter(Zone *zone)
   1.276 +  : pc_(zone->stack().top()->pc),
   1.277 +    fp_(zone->stack().top()->fp)
   1.278 +{
   1.279 +}
   1.280 +
   1.281 +bool
   1.282 +StackIter::done() const
   1.283 +{
   1.284 +    return !fp_;
   1.285 +}
   1.286 +
   1.287 +const char *
   1.288 +StackIter::function() const
   1.289 +{
   1.290 +    if (fp_->isNative())
   1.291 +        return fp_->native()->name()->chars();
   1.292 +    if (Function *fun = fp_->maybeFun())
   1.293 +        return fun->name()->chars();
   1.294 +    return "<toplevel>";
   1.295 +}
   1.296 +
   1.297 +unsigned
   1.298 +StackIter::lineNumber() const
   1.299 +{
   1.300 +    if (fp_->isNative())
   1.301 +        return 0;
   1.302 +    if (fp_->maybeFun()) {
   1.303 +        unsigned offs = fp_->code()->pcToOffset(pc_);
   1.304 +        return fp_->code()->pcToSource(offs).line;
   1.305 +    }
   1.306 +    return fp_->code()->lineNumber();
   1.307 +}
   1.308 +
   1.309 +const char *
   1.310 +StackIter::source() const
   1.311 +{
   1.312 +    if (fp_->isNative())
   1.313 +        return "<native>";
   1.314 +    return fp_->code()->module()->file()
   1.315 +           ? fp_->code()->module()->file()->chars()
   1.316 +           : "(anonymous)";
   1.317 +}
   1.318 +
   1.319 +void
   1.320 +StackIter::prev()
   1.321 +{
   1.322 +    pc_ = fp_->prevpc();
   1.323 +    fp_ = fp_->prev();
   1.324 +}