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