jitcraft/Stack.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jul 11 01:12:54 2012 -0700 (2012-07-11)
changeset 69 dfce0539a77d
parent 68 b40b0e18a918
child 70 1aec996cde2d
permissions -rw-r--r--
Added error reporting API and fixed all known error paths.
dvander@62
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@62
     2
 *
dvander@62
     3
 * Copyright (C) 2012 David Anderson
dvander@62
     4
 *
dvander@62
     5
 * This file is part of JITCraft.
dvander@62
     6
 *
dvander@62
     7
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@62
     8
 * the terms of the GNU General Public License as published by the Free
dvander@62
     9
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@62
    10
 * any later version.
dvander@62
    11
 * 
dvander@62
    12
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@62
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@62
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@62
    15
 *
dvander@62
    16
 * You should have received a copy of the GNU General Public License along with
dvander@62
    17
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@62
    18
 */
dvander@62
    19
#include <new>
dvander@62
    20
#include <stdlib.h>
dvander@62
    21
#include "Stack.h"
dvander@62
    22
#include "Zone.h"
dvander@62
    23
#include "Heap-inl.h"
dvander@69
    24
#include "Strings.h"
dvander@62
    25
dvander@62
    26
using namespace ke;
dvander@62
    27
dvander@69
    28
Stack::Stack(Zone *zone)
dvander@69
    29
  : zone_(zone),
dvander@69
    30
    buffer_(NULL),
dvander@65
    31
    end_(NULL)
dvander@62
    32
{
dvander@62
    33
}
dvander@62
    34
dvander@62
    35
Stack::~Stack()
dvander@62
    36
{
dvander@62
    37
    free(buffer_);
dvander@62
    38
}
dvander@62
    39
dvander@62
    40
bool
dvander@62
    41
Stack::initialize()
dvander@62
    42
{
dvander@62
    43
    buffer_ = (char *)malloc(STACK_SIZE);
dvander@62
    44
    if (!buffer_)
dvander@62
    45
        return false;
dvander@62
    46
dvander@65
    47
    top_.sp = reinterpret_cast<LocalSlot *>(buffer_);
dvander@65
    48
    top_.pc = NULL;
dvander@65
    49
    top_.fp = NULL;
dvander@62
    50
    end_ = buffer_ + STACK_SIZE;
dvander@62
    51
    return true;
dvander@62
    52
}
dvander@62
    53
dvander@65
    54
InvokeArgs::~InvokeArgs()
dvander@65
    55
{
dvander@65
    56
    stack_->popInvokeFrame(*this);
dvander@65
    57
}
dvander@65
    58
dvander@68
    59
NativeArgs::~NativeArgs()
dvander@68
    60
{
dvander@68
    61
    stack_->popNativeFrame(*this);
dvander@68
    62
}
dvander@68
    63
dvander@62
    64
static inline size_t
dvander@62
    65
SizeForCodeFrame(Code *code)
dvander@62
    66
{
dvander@62
    67
    return sizeof(Frame) + sizeof(LocalSlot) * (code->nlocals() + code->maxStackDepth());
dvander@62
    68
}
dvander@62
    69
dvander@65
    70
bool
dvander@65
    71
Stack::pushInvokeFrame(Handle<Function> fun, InvokeArgs &args)
dvander@65
    72
{
dvander@65
    73
    size_t nbytes = SizeForCodeFrame(fun->code()) +
dvander@65
    74
                    sizeof(LocalSlot) * fun->nargs();
dvander@65
    75
    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
dvander@65
    76
        assert(false);
dvander@65
    77
        return false;
dvander@65
    78
    }
dvander@65
    79
dvander@65
    80
    memset(top_.sp, 0, sizeof(LocalSlot) * fun->nargs());
dvander@65
    81
    args.args_ = top_.sp;
dvander@65
    82
    args.nargs_ = fun->nargs();
dvander@65
    83
    args.stack_ = this;
dvander@65
    84
    top_.sp += fun->nargs();
dvander@65
    85
    
dvander@65
    86
    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
dvander@69
    87
    new (frame) Frame(top_.fp, top_.pc, fun, fun->code(), zone_->heap().lifoPosition());
dvander@65
    88
    
dvander@65
    89
    top_.pc = frame->code()->start();
dvander@65
    90
    top_.sp = frame->stackBase();
dvander@65
    91
    top_.fp = frame;
dvander@65
    92
dvander@65
    93
    return true;
dvander@65
    94
}
dvander@65
    95
dvander@68
    96
bool
dvander@68
    97
Stack::pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc)
dvander@68
    98
{
dvander@68
    99
    size_t nbytes = sizeof(intptr_t) * argc + sizeof(Frame);
dvander@68
   100
    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
dvander@68
   101
        assert(false);
dvander@68
   102
        return false;
dvander@68
   103
    }
dvander@68
   104
dvander@68
   105
    memset(top_.sp, 0, sizeof(intptr_t) * argc);
dvander@68
   106
    args.argsBase_ = top_.sp;
dvander@68
   107
    args.stack_ = this;
dvander@68
   108
    top_.sp = reinterpret_cast<LocalSlot *>(reinterpret_cast<intptr_t *>(top_.sp) + argc);
dvander@68
   109
dvander@68
   110
    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
dvander@69
   111
    new (frame) Frame(top_.fp, top_.pc, native, zone_->heap().lifoPosition());
dvander@68
   112
dvander@68
   113
    top_.pc = NULL;
dvander@68
   114
    top_.sp = reinterpret_cast<LocalSlot *>(frame + 1);
dvander@68
   115
    top_.fp = frame;
dvander@68
   116
dvander@68
   117
    return true;
dvander@68
   118
}
dvander@68
   119
dvander@62
   120
Frame *
dvander@65
   121
Stack::pushInlineFrame(Handle<Function> fun)
dvander@62
   122
{
dvander@62
   123
    Code *code = fun->code();
dvander@62
   124
    size_t nbytes = SizeForCodeFrame(code);
dvander@65
   125
    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
dvander@69
   126
        zone_->reportError(Message_TooMuchRecursion);
dvander@62
   127
        return NULL;
dvander@65
   128
    }
dvander@62
   129
dvander@65
   130
    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
dvander@69
   131
    new (frame) Frame(top_.fp, top_.pc, fun, code, zone_->heap().lifoPosition());
dvander@62
   132
    memset(frame->locals(), 0, sizeof(LocalSlot) * code->nlocals());
dvander@62
   133
dvander@65
   134
    top_.pc = frame->code()->start();
dvander@65
   135
    top_.sp = frame->stackBase();
dvander@65
   136
    top_.fp = frame;
dvander@62
   137
dvander@62
   138
    return frame;
dvander@62
   139
}
dvander@62
   140
dvander@62
   141
dvander@62
   142
Frame *
dvander@65
   143
Stack::popInlineFrame()
dvander@62
   144
{
dvander@69
   145
    zone_->heap().unwindLifo(top_.fp->lifoPosition());
dvander@62
   146
dvander@65
   147
    Frame *prev = top_.fp->prev();
dvander@69
   148
    Function *fun = top_.fp->fun();
dvander@62
   149
dvander@65
   150
    top_.pc = top_.fp->prevpc();
dvander@69
   151
    top_.sp = reinterpret_cast<LocalSlot *>(top_.fp) - fun->nargs();
dvander@65
   152
    top_.fp = prev;
dvander@62
   153
    return prev;
dvander@62
   154
}
dvander@62
   155
dvander@62
   156
void
dvander@65
   157
Stack::popInvokeFrame(InvokeArgs &args)
dvander@65
   158
{
dvander@69
   159
    zone_->heap().unwindLifo(top_.fp->lifoPosition());
dvander@65
   160
dvander@65
   161
    top_.pc = top_.fp->prevpc();
dvander@65
   162
    top_.sp = args.args_;
dvander@65
   163
    top_.fp = top_.fp->prev();
dvander@65
   164
}
dvander@65
   165
dvander@65
   166
void
dvander@68
   167
Stack::popNativeFrame(NativeArgs &args)
dvander@68
   168
{
dvander@69
   169
    zone_->heap().unwindLifo(top_.fp->lifoPosition());
dvander@68
   170
dvander@68
   171
    top_.pc = top_.fp->prevpc();
dvander@68
   172
    top_.sp = args.argsBase_;
dvander@68
   173
    top_.fp = top_.fp->prev();
dvander@68
   174
}
dvander@68
   175
dvander@68
   176
void
dvander@62
   177
Frame::accept(VirtualObjectVisitor *visitor)
dvander@62
   178
{
dvander@68
   179
    visitor->visit(reinterpret_cast<Object **>(&callee_));
dvander@62
   180
    visitor->visit(reinterpret_cast<Object **>(&code_));
dvander@62
   181
}
dvander@62
   182
dvander@62
   183
static void
dvander@68
   184
TraceFunctionFrame(VirtualObjectVisitor *visitor, Frame *fp, LocalSlot *sp, bytecode *pc)
dvander@62
   185
{
dvander@62
   186
    Code *code = fp->code();
dvander@62
   187
    LocalSlot *slots = fp->locals();
dvander@62
   188
dvander@62
   189
    // Trace local variables.
dvander@62
   190
    for (unsigned i = 0; i < code->nlocals(); i++) {
dvander@62
   191
        Type *type = code->localType(i);
dvander@62
   192
        if (type->isTraceable())
dvander@62
   193
            visitor->visit(&slots[i].obj);
dvander@62
   194
    }
dvander@62
   195
dvander@65
   196
    // Trace arguments, if a function call. Note that this means we usually
dvander@65
   197
    // mark arguments twice, once on the caller side and once on the callee.
dvander@65
   198
    // This makes it easier to deal with invoke frames which have no caller.
dvander@62
   199
    if (Function *fun = fp->maybeFun()) {
dvander@62
   200
        for (unsigned i = 0; i < fun->nargs(); i++) {
dvander@62
   201
            Type *type = fun->argType(i);
dvander@62
   202
            if (type->isTraceable())
dvander@62
   203
                visitor->visit(&fp->arg(i).obj);
dvander@62
   204
        }
dvander@62
   205
    }
dvander@62
   206
dvander@62
   207
    // Finally, trace stack slots. Not every gc-point in the bytecode will
dvander@62
   208
    // have a safepoint; since they are actually uncommon, we don't emit
dvander@62
   209
    // them unless at least one stack slot would be marked.
dvander@62
   210
    if (uint8 *safepoint = code->safepointAt(code->pcToOffset(pc))) {
dvander@62
   211
        LocalSlot *base = fp->stackBase();
dvander@62
   212
        unsigned stackDepth = unsigned(sp - fp->stackBase());
dvander@62
   213
        assert(stackDepth <= code->maxStackDepth());
dvander@62
   214
dvander@62
   215
        for (unsigned i = 0; i < stackDepth; i++) {
dvander@62
   216
            if (safepoint[i / 8] & (1 << (i % 8)))
dvander@62
   217
                visitor->visit(&base[i].obj);
dvander@62
   218
        }
dvander@62
   219
    }
dvander@62
   220
}
dvander@62
   221
dvander@62
   222
void
dvander@62
   223
Stack::accept(VirtualObjectVisitor *visitor)
dvander@62
   224
{
dvander@65
   225
    LocalSlot *sp = top_.sp;
dvander@65
   226
    bytecode *pc = top_.pc;
dvander@62
   227
dvander@65
   228
    for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
dvander@68
   229
        if (!frame->isNative())
dvander@68
   230
            TraceFunctionFrame(visitor, frame, sp, pc);
dvander@68
   231
        frame->accept(visitor);
dvander@68
   232
dvander@62
   233
        sp = reinterpret_cast<LocalSlot *>(frame);
dvander@62
   234
        pc = frame->prevpc();
dvander@62
   235
    }
dvander@62
   236
}
dvander@62
   237
dvander@62
   238
bool
dvander@62
   239
Stack::isInCallStack(Handle<Module> module)
dvander@62
   240
{
dvander@65
   241
    for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
dvander@62
   242
        if (frame->code()->module() == module)
dvander@62
   243
            return true;
dvander@62
   244
    }
dvander@62
   245
    return false;
dvander@62
   246
}
dvander@65
   247
dvander@69
   248
StackIter::StackIter(Zone *zone)
dvander@69
   249
  : pc_(zone->stack().top()->pc),
dvander@69
   250
    fp_(zone->stack().top()->fp)
dvander@69
   251
{
dvander@69
   252
}
dvander@69
   253
dvander@69
   254
bool
dvander@69
   255
StackIter::done() const
dvander@69
   256
{
dvander@69
   257
    return !fp_;
dvander@69
   258
}
dvander@69
   259
dvander@69
   260
const char *
dvander@69
   261
StackIter::function() const
dvander@69
   262
{
dvander@69
   263
    if (fp_->isNative())
dvander@69
   264
        return fp_->native()->name()->chars();
dvander@69
   265
    if (Function *fun = fp_->maybeFun())
dvander@69
   266
        return fun->name()->chars();
dvander@69
   267
    return "<toplevel>";
dvander@69
   268
}
dvander@69
   269
dvander@69
   270
unsigned
dvander@69
   271
StackIter::lineNumber() const
dvander@69
   272
{
dvander@69
   273
    return 0;
dvander@69
   274
}
dvander@69
   275
dvander@69
   276
const char *
dvander@69
   277
StackIter::source() const
dvander@69
   278
{
dvander@69
   279
    if (fp_->isNative())
dvander@69
   280
        return "<native>";
dvander@69
   281
    return "unknown";
dvander@69
   282
}
dvander@69
   283
dvander@69
   284
void
dvander@69
   285
StackIter::prev()
dvander@69
   286
{
dvander@69
   287
    pc_ = fp_->prevpc();
dvander@69
   288
    fp_ = fp_->prev();
dvander@69
   289
}