src/compiler/BytecodeEmitter.cpp
author David Anderson <dvander@alliedmods.net>
Mon Dec 24 16:43:22 2012 -0800 (2012-12-24)
changeset 237 c77540a61905
parent 230 fb3cd08bc7fb
child 262 c4b1341297e5
permissions -rw-r--r--
Don't allow declaring void variables.
dvander@47
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@47
     2
 *
dvander@0
     3
 * Copyright (C) 2012 David Anderson
dvander@0
     4
 *
dvander@0
     5
 * This file is part of JITCraft.
dvander@0
     6
 *
dvander@0
     7
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@0
     8
 * the terms of the GNU General Public License as published by the Free
dvander@0
     9
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@0
    10
 * any later version.
dvander@0
    11
 * 
dvander@0
    12
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@0
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@0
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@0
    15
 *
dvander@0
    16
 * You should have received a copy of the GNU General Public License along with
dvander@0
    17
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@0
    18
 */
dvander@0
    19
#include <stdlib.h>
dvander@177
    20
#include <string.h>
dvander@195
    21
#include "../Utility.h"
dvander@195
    22
#include "../Types.h"
dvander@195
    23
#include "../Zone.h"
dvander@195
    24
#include "../Strings.h"
dvander@195
    25
#include "../Zone.h"
dvander@0
    26
#include "BytecodeEmitter.h"
dvander@195
    27
#include "Symbols.h"
dvander@195
    28
#include "Scopes.h"
dvander@195
    29
#include "../Spaces-inl.h"
dvander@195
    30
#include "../Heap-inl.h"
dvander@0
    31
dvander@59
    32
using namespace ke;
dvander@0
    33
dvander@195
    34
StringTable::StringTable()
dvander@195
    35
  : set_(ZoneAllocatorPolicy()),
dvander@195
    36
    initialized_(false)
dvander@195
    37
{
dvander@195
    38
}
dvander@195
    39
dvander@195
    40
bool
dvander@195
    41
StringTable::initialize()
dvander@195
    42
{
dvander@195
    43
    assert(!initialized_);
dvander@195
    44
    initialized_ = true;
dvander@195
    45
    if (!set_.init(16))
dvander@195
    46
        return false;
dvander@195
    47
    return true;
dvander@195
    48
}
dvander@195
    49
dvander@195
    50
bool
dvander@195
    51
StringTable::add(Handle<String> name, unsigned *indexp)
dvander@195
    52
{
dvander@195
    53
    if (!initialized_ && !initialize())
dvander@195
    54
        return false;
dvander@195
    55
dvander@195
    56
    Set::Insert p = set_.findForAdd(*name);
dvander@195
    57
    if (p.found()) {
dvander@195
    58
        *indexp = p->index;
dvander@195
    59
        return true;
dvander@195
    60
    }
dvander@195
    61
dvander@195
    62
    if (strings_.length() > INT_MAX) {
dvander@195
    63
        ZONE()->reportAllocationOverflow();
dvander@195
    64
        return false;
dvander@195
    65
    }
dvander@195
    66
dvander@195
    67
    Entry e(name, strings_.length());
dvander@195
    68
    if (!strings_.append(e))
dvander@195
    69
        return false;
dvander@195
    70
dvander@195
    71
    if (!set_.add(p, e))
dvander@195
    72
        return false;
dvander@195
    73
dvander@195
    74
    *indexp = e.index;
dvander@195
    75
dvander@195
    76
    return true;
dvander@195
    77
}
dvander@195
    78
dvander@195
    79
void
dvander@195
    80
StringTable::accept(VirtualObjectVisitor *visitor)
dvander@195
    81
{
dvander@195
    82
    for (size_t i = 0; i < strings_.length(); i++)
dvander@195
    83
        visitor->visit(reinterpret_cast<Object **>(&strings_[i].string));
dvander@195
    84
}
dvander@195
    85
dvander@47
    86
BytecodeEmitter::BytecodeEmitter(PoolAllocator &pool)
dvander@195
    87
  : AutoRooted(ZONE()),
dvander@195
    88
    pool_(pool),
dvander@47
    89
    buffer_(inline_buffer_),
dvander@0
    90
    buffer_pos_(buffer_),
dvander@0
    91
    buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
dvander@0
    92
    oom_(false),
dvander@230
    93
    maxStackDepth_(0),
dvander@230
    94
    loopDepth_(0),
dvander@230
    95
    maxLoopDepth_(0)
dvander@0
    96
{
dvander@70
    97
    lastCodePosition_ = 0;
dvander@70
    98
    firstLine_ = 1;
dvander@0
    99
}
dvander@0
   100
dvander@195
   101
BytecodeEmitter::~BytecodeEmitter()
dvander@195
   102
{
dvander@195
   103
    for (size_t i = 0; i < oopRecords_.length(); i++)
dvander@195
   104
        delete oopRecords_[i];
dvander@195
   105
}
dvander@195
   106
dvander@195
   107
void
dvander@195
   108
BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
dvander@195
   109
{
dvander@195
   110
    for (size_t i = 0; i < objects_.length(); i++)
dvander@195
   111
        visitor->visit(&objects_[i]);
dvander@195
   112
dvander@195
   113
    strings_.accept(visitor);
dvander@195
   114
}
dvander@195
   115
dvander@0
   116
bool
dvander@0
   117
BytecodeEmitter::growBuffer(size_t nbytes)
dvander@0
   118
{
dvander@0
   119
    if (oom_) {
dvander@0
   120
        buffer_pos_ = buffer_;
dvander@0
   121
        return false;
dvander@0
   122
    }
dvander@0
   123
dvander@0
   124
    size_t newSize = size_t((buffer_end_ - buffer_) * 2);
dvander@0
   125
    if (newSize >= MAX_LENGTH) {
dvander@0
   126
        oom_ = true;
dvander@0
   127
        buffer_pos_ = buffer_;
dvander@69
   128
        ZONE()->reportOutOfMemory();
dvander@0
   129
        return false;
dvander@0
   130
    }
dvander@0
   131
dvander@0
   132
    bytecode *newBuffer;
dvander@0
   133
    if (buffer_ == inline_buffer_)
dvander@177
   134
        newBuffer = (bytecode *)malloc(newSize);
dvander@0
   135
    else
dvander@0
   136
        newBuffer = (bytecode *)realloc(buffer_, newSize);
dvander@0
   137
dvander@0
   138
    // If we can't allocate a buffer, reset the buffer to the start and set
dvander@0
   139
    // a flag to indicate out-of-memory.
dvander@0
   140
    if (!newBuffer) {
dvander@0
   141
        oom_ = true;
dvander@0
   142
        buffer_pos_ = buffer_;
dvander@69
   143
        ZONE()->reportOutOfMemory();
dvander@0
   144
        return false;
dvander@0
   145
    }
dvander@0
   146
dvander@177
   147
    if (buffer_ == inline_buffer_)
dvander@177
   148
        memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
dvander@177
   149
dvander@0
   150
    buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
dvander@0
   151
    buffer_ = newBuffer;
dvander@0
   152
    buffer_end_ = buffer_ + newSize;
dvander@177
   153
    assert(buffer_pos_ + nbytes < buffer_end_);
dvander@177
   154
dvander@0
   155
    return true;
dvander@0
   156
}
dvander@0
   157
dvander@47
   158
void
dvander@47
   159
BytecodeEmitter::recordOops()
dvander@47
   160
{
dvander@195
   161
    OopRecord *record = new OopRecord(oopMap_.length(), position());
dvander@47
   162
dvander@195
   163
    if (!record->slots.ensure(record->depth)) {
dvander@47
   164
        oom_ = true;
dvander@47
   165
        return;
dvander@47
   166
    }
dvander@47
   167
dvander@47
   168
    bool hadOops = false;
dvander@58
   169
    for (size_t i = 0; i < oopMap_.length(); i++) {
dvander@47
   170
        bool bit = oopMap_[i];
dvander@195
   171
        record->slots.infallibleAppend(bit);
dvander@47
   172
        hadOops |= bit;
dvander@47
   173
    }
dvander@47
   174
dvander@195
   175
    if (!hadOops) {
dvander@195
   176
        delete record;
dvander@47
   177
        return;
dvander@195
   178
    }
dvander@47
   179
dvander@58
   180
    oom_ &= oopRecords_.append(record);
dvander@47
   181
}
dvander@47
   182
dvander@70
   183
void
dvander@70
   184
BytecodeEmitter::note_position(const SourcePosition &pos)
dvander@70
   185
{
dvander@70
   186
    assert(pos.line > 0);
dvander@70
   187
    assert(unsigned(pos.line) >= firstLine_);
dvander@70
   188
dvander@70
   189
    unsigned lineDelta = unsigned(pos.line) - firstLine_;
dvander@70
   190
    unsigned pcDelta = unsigned(position()) - lastCodePosition_;
dvander@70
   191
dvander@70
   192
    sourcemap_.writeUint32(pcDelta);
dvander@70
   193
    sourcemap_.writeUint32(lineDelta);
dvander@70
   194
    sourcemap_.writeUint32(pos.col);
dvander@70
   195
dvander@70
   196
    lastCodePosition_ = unsigned(position());
dvander@70
   197
}
dvander@195
   198
dvander@195
   199
void
dvander@195
   200
BytecodeEmitter::getglobal(Symbol *sym)
dvander@195
   201
{
dvander@195
   202
    ensure(OP_GETGLOBAL_LENGTH);
dvander@195
   203
    writeOp(OP_GETGLOBAL);
dvander@195
   204
    writeUint32(addString(sym->name()));
dvander@195
   205
    if (sym->type()->isTraceable())
dvander@195
   206
        markOop(1);
dvander@195
   207
}
dvander@195
   208
void
dvander@195
   209
BytecodeEmitter::setglobal(Symbol *sym)
dvander@195
   210
{
dvander@195
   211
    ensure(OP_SETGLOBAL_LENGTH);
dvander@195
   212
    writeOp(OP_SETGLOBAL);
dvander@195
   213
    writeUint32(addString(sym->name()));
dvander@195
   214
    if (sym->type()->isTraceable())
dvander@195
   215
        markOop(1);
dvander@195
   216
}
dvander@195
   217
dvander@195
   218
void
dvander@195
   219
BytecodeEmitter::getlocal(VariableSymbol *var)
dvander@195
   220
{
dvander@220
   221
    assert(var->storage() == VariableSymbol::Local);
dvander@195
   222
    ensure(OP_GETLOCAL_LENGTH);
dvander@195
   223
    writeOp(OP_GETLOCAL);
dvander@195
   224
    writeUint32(var->slot());
dvander@195
   225
    if (var->type()->isTraceable())
dvander@195
   226
        markOop(1);
dvander@195
   227
}
dvander@195
   228
dvander@195
   229
void
dvander@195
   230
BytecodeEmitter::setlocal(VariableSymbol *var)
dvander@195
   231
{
dvander@220
   232
    assert(var->storage() == VariableSymbol::Local);
dvander@195
   233
    ensure(OP_SETLOCAL_LENGTH);
dvander@195
   234
    writeOp(OP_SETLOCAL);
dvander@195
   235
    writeUint32(var->slot());
dvander@195
   236
    if (var->type()->isTraceable())
dvander@195
   237
        markOop(1);
dvander@195
   238
}
dvander@195
   239
dvander@220
   240
void
dvander@220
   241
BytecodeEmitter::getarg(VariableSymbol *var)
dvander@220
   242
{
dvander@220
   243
    assert(var->storage() == VariableSymbol::Arg);
dvander@220
   244
    ensure(OP_GETARG_LENGTH);
dvander@220
   245
    writeOp(OP_GETARG);
dvander@220
   246
    writeUint32(var->slot());
dvander@220
   247
    if (var->type()->isTraceable())
dvander@220
   248
        markOop(1);
dvander@220
   249
}
dvander@220
   250
dvander@220
   251
void
dvander@220
   252
BytecodeEmitter::setarg(VariableSymbol *var)
dvander@220
   253
{
dvander@220
   254
    assert(var->storage() == VariableSymbol::Arg);
dvander@220
   255
    ensure(OP_SETARG_LENGTH);
dvander@220
   256
    writeOp(OP_SETARG);
dvander@220
   257
    writeUint32(var->slot());
dvander@220
   258
    if (var->type()->isTraceable())
dvander@220
   259
        markOop(1);
dvander@220
   260
}
dvander@220
   261
dvander@195
   262
bool
dvander@195
   263
BytecodeEmitter::allocate(VariableSymbol *sym)
dvander@195
   264
{
dvander@195
   265
    assert(sym->isVariable());
dvander@195
   266
    assert(sym->scope()->kind() == Scope::BLOCK);
dvander@195
   267
dvander@195
   268
    switch (sym->scope()->kind()) {
dvander@195
   269
      case Scope::BLOCK:
dvander@195
   270
      {
dvander@195
   271
        // See overall comment on overflows.
dvander@195
   272
        assert(locals_.length() < UINT_MAX);
dvander@195
   273
        sym->allocate(VariableSymbol::Local, locals_.length());
dvander@195
   274
        if (!locals_.append(sym))
dvander@195
   275
            return false;
dvander@195
   276
        break;
dvander@195
   277
      }
dvander@195
   278
dvander@195
   279
      default:
dvander@195
   280
        assert(false);
dvander@195
   281
        return false;
dvander@195
   282
    }
dvander@195
   283
dvander@195
   284
    return true;
dvander@195
   285
}
dvander@195
   286
dvander@222
   287
void
dvander@222
   288
BytecodeEmitter::newref(VariableSymbol *var)
dvander@222
   289
{
dvander@222
   290
    recordOops();
dvander@222
   291
    if (var->storage() == VariableSymbol::Local) {
dvander@222
   292
        ensure(OP_VARREF_LIFO_LENGTH);
dvander@222
   293
        writeOp(OP_VARREF_LIFO);
dvander@222
   294
    } else {
dvander@222
   295
        assert(var->storage() == VariableSymbol::Arg);
dvander@222
   296
        ensure(OP_ARGREF_LIFO_LENGTH);
dvander@222
   297
        writeOp(OP_ARGREF_LIFO);
dvander@222
   298
    }
dvander@222
   299
    writeUint32(var->slot());
dvander@222
   300
    markOop(1);
dvander@222
   301
}
dvander@222
   302
dvander@195
   303
Code *
dvander@195
   304
BytecodeEmitter::finish()
dvander@195
   305
{
dvander@195
   306
    stop();
dvander@195
   307
dvander@195
   308
    Zone *zone = ZONE();
dvander@195
   309
    if (oom() || zone->hasPendingException())
dvander@195
   310
        return NULL;
dvander@195
   311
dvander@195
   312
    Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
dvander@195
   313
    if (!bytes)
dvander@195
   314
        return NULL;
dvander@195
   315
    memcpy(bytes->raw(), buffer(), length());
dvander@195
   316
dvander@195
   317
    Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
dvander@195
   318
    if (!objects)
dvander@195
   319
        return NULL;
dvander@195
   320
dvander@195
   321
    for (size_t i = 0; i < objects_.length(); i++)
dvander@195
   322
        objects->set(zone, i, objects_[i]);
dvander@195
   323
dvander@195
   324
    // If any stack slots hold gc pointers at potential failure points in the
dvander@195
   325
    // bytecode, record them now. We do this by building a list of tuples;
dvander@195
   326
    // each tuple contains the pc offset, and a bitset containing which stack
dvander@195
   327
    // slots must be scanned by the gc.
dvander@195
   328
    Local<ByteArray> safepoints(zone);
dvander@195
   329
    if (oopRecords_.length()) {
dvander@195
   330
        size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
dvander@195
   331
        size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
dvander@195
   332
        safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
dvander@195
   333
        if (!safepoints)
dvander@195
   334
            return NULL;
dvander@195
   335
dvander@195
   336
        Address cursor = safepoints->raw();
dvander@195
   337
        for (size_t i = 0; i < oopRecords_.length(); i++) {
dvander@195
   338
            OopRecord *record = oopRecords_[i];
dvander@195
   339
            assert(record->depth <= maxStackDepth());
dvander@195
   340
dvander@195
   341
            *reinterpret_cast<unsigned *>(cursor) = record->offset;
dvander@195
   342
dvander@195
   343
            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
dvander@195
   344
            for (unsigned i = 0; i < record->depth; i++)
dvander@195
   345
                bits[i / 8] |= (1 << (i % 8));
dvander@195
   346
dvander@195
   347
            cursor += bytesPerSafepoint;
dvander@195
   348
        }
dvander@195
   349
dvander@195
   350
        assert(cursor == safepoints->raw() + gcmapSize);
dvander@195
   351
    }
dvander@195
   352
dvander@195
   353
    Local<ByteArray> sourcemap(zone);
dvander@195
   354
    if (sourcemap_.length()) {
dvander@195
   355
        sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
dvander@195
   356
        if (!sourcemap)
dvander@195
   357
            return NULL;
dvander@195
   358
dvander@195
   359
        memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
dvander@195
   360
    }
dvander@195
   361
dvander@195
   362
    Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
dvander@195
   363
    if (!strings)
dvander@195
   364
        return NULL;
dvander@195
   365
    for (size_t i = 0; i < strings_.stringCount(); i++)
dvander@195
   366
        strings->set(zone, i, strings_.stringAt(i));
dvander@195
   367
dvander@195
   368
    Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
dvander@195
   369
    if (!locals)
dvander@195
   370
        return NULL;
dvander@195
   371
    for (size_t i = 0; i < locals_.length(); i++)
dvander@195
   372
        locals->set(zone, i, locals_[i]->type());
dvander@195
   373
dvander@195
   374
    Local<Code> code(zone);
dvander@195
   375
dvander@195
   376
    code = Code::New(zone,
dvander@195
   377
                     bytes,
dvander@195
   378
                     locals,
dvander@195
   379
                     objects,
dvander@195
   380
                     strings,
dvander@195
   381
                     maxStackDepth(),
dvander@230
   382
                     maxLoopDepth_,
dvander@195
   383
                     safepoints,
dvander@195
   384
                     sourcemap);
dvander@195
   385
dvander@195
   386
    return code;
dvander@195
   387
}