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