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 +}