src/compiler/BytecodeEmitter.cpp
changeset 195 c1ba166f3fc4
parent 177 56f7e5b0243c
child 220 5df4a112967d
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/compiler/BytecodeEmitter.cpp	Sat Nov 17 18:41:01 2012 -0800
     1.3 @@ -0,0 +1,344 @@
     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 <stdlib.h>
    1.23 +#include <string.h>
    1.24 +#include "../Utility.h"
    1.25 +#include "../Types.h"
    1.26 +#include "../Zone.h"
    1.27 +#include "../Strings.h"
    1.28 +#include "../Zone.h"
    1.29 +#include "BytecodeEmitter.h"
    1.30 +#include "Symbols.h"
    1.31 +#include "Scopes.h"
    1.32 +#include "../Spaces-inl.h"
    1.33 +#include "../Heap-inl.h"
    1.34 +
    1.35 +using namespace ke;
    1.36 +
    1.37 +StringTable::StringTable()
    1.38 +  : set_(ZoneAllocatorPolicy()),
    1.39 +    initialized_(false)
    1.40 +{
    1.41 +}
    1.42 +
    1.43 +bool
    1.44 +StringTable::initialize()
    1.45 +{
    1.46 +    assert(!initialized_);
    1.47 +    initialized_ = true;
    1.48 +    if (!set_.init(16))
    1.49 +        return false;
    1.50 +    return true;
    1.51 +}
    1.52 +
    1.53 +bool
    1.54 +StringTable::add(Handle<String> name, unsigned *indexp)
    1.55 +{
    1.56 +    if (!initialized_ && !initialize())
    1.57 +        return false;
    1.58 +
    1.59 +    Set::Insert p = set_.findForAdd(*name);
    1.60 +    if (p.found()) {
    1.61 +        *indexp = p->index;
    1.62 +        return true;
    1.63 +    }
    1.64 +
    1.65 +    if (strings_.length() > INT_MAX) {
    1.66 +        ZONE()->reportAllocationOverflow();
    1.67 +        return false;
    1.68 +    }
    1.69 +
    1.70 +    Entry e(name, strings_.length());
    1.71 +    if (!strings_.append(e))
    1.72 +        return false;
    1.73 +
    1.74 +    if (!set_.add(p, e))
    1.75 +        return false;
    1.76 +
    1.77 +    *indexp = e.index;
    1.78 +
    1.79 +    return true;
    1.80 +}
    1.81 +
    1.82 +void
    1.83 +StringTable::accept(VirtualObjectVisitor *visitor)
    1.84 +{
    1.85 +    for (size_t i = 0; i < strings_.length(); i++)
    1.86 +        visitor->visit(reinterpret_cast<Object **>(&strings_[i].string));
    1.87 +}
    1.88 +
    1.89 +BytecodeEmitter::BytecodeEmitter(PoolAllocator &pool)
    1.90 +  : AutoRooted(ZONE()),
    1.91 +    pool_(pool),
    1.92 +    buffer_(inline_buffer_),
    1.93 +    buffer_pos_(buffer_),
    1.94 +    buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
    1.95 +    oom_(false),
    1.96 +    maxStackDepth_(0)
    1.97 +{
    1.98 +    lastCodePosition_ = 0;
    1.99 +    firstLine_ = 1;
   1.100 +}
   1.101 +
   1.102 +BytecodeEmitter::~BytecodeEmitter()
   1.103 +{
   1.104 +    for (size_t i = 0; i < oopRecords_.length(); i++)
   1.105 +        delete oopRecords_[i];
   1.106 +}
   1.107 +
   1.108 +void
   1.109 +BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
   1.110 +{
   1.111 +    for (size_t i = 0; i < objects_.length(); i++)
   1.112 +        visitor->visit(&objects_[i]);
   1.113 +
   1.114 +    strings_.accept(visitor);
   1.115 +}
   1.116 +
   1.117 +bool
   1.118 +BytecodeEmitter::growBuffer(size_t nbytes)
   1.119 +{
   1.120 +    if (oom_) {
   1.121 +        buffer_pos_ = buffer_;
   1.122 +        return false;
   1.123 +    }
   1.124 +
   1.125 +    size_t newSize = size_t((buffer_end_ - buffer_) * 2);
   1.126 +    if (newSize >= MAX_LENGTH) {
   1.127 +        oom_ = true;
   1.128 +        buffer_pos_ = buffer_;
   1.129 +        ZONE()->reportOutOfMemory();
   1.130 +        return false;
   1.131 +    }
   1.132 +
   1.133 +    bytecode *newBuffer;
   1.134 +    if (buffer_ == inline_buffer_)
   1.135 +        newBuffer = (bytecode *)malloc(newSize);
   1.136 +    else
   1.137 +        newBuffer = (bytecode *)realloc(buffer_, newSize);
   1.138 +
   1.139 +    // If we can't allocate a buffer, reset the buffer to the start and set
   1.140 +    // a flag to indicate out-of-memory.
   1.141 +    if (!newBuffer) {
   1.142 +        oom_ = true;
   1.143 +        buffer_pos_ = buffer_;
   1.144 +        ZONE()->reportOutOfMemory();
   1.145 +        return false;
   1.146 +    }
   1.147 +
   1.148 +    if (buffer_ == inline_buffer_)
   1.149 +        memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
   1.150 +
   1.151 +    buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
   1.152 +    buffer_ = newBuffer;
   1.153 +    buffer_end_ = buffer_ + newSize;
   1.154 +    assert(buffer_pos_ + nbytes < buffer_end_);
   1.155 +
   1.156 +    return true;
   1.157 +}
   1.158 +
   1.159 +void
   1.160 +BytecodeEmitter::recordOops()
   1.161 +{
   1.162 +    OopRecord *record = new OopRecord(oopMap_.length(), position());
   1.163 +
   1.164 +    if (!record->slots.ensure(record->depth)) {
   1.165 +        oom_ = true;
   1.166 +        return;
   1.167 +    }
   1.168 +
   1.169 +    bool hadOops = false;
   1.170 +    for (size_t i = 0; i < oopMap_.length(); i++) {
   1.171 +        bool bit = oopMap_[i];
   1.172 +        record->slots.infallibleAppend(bit);
   1.173 +        hadOops |= bit;
   1.174 +    }
   1.175 +
   1.176 +    if (!hadOops) {
   1.177 +        delete record;
   1.178 +        return;
   1.179 +    }
   1.180 +
   1.181 +    oom_ &= oopRecords_.append(record);
   1.182 +}
   1.183 +
   1.184 +void
   1.185 +BytecodeEmitter::note_position(const SourcePosition &pos)
   1.186 +{
   1.187 +    assert(pos.line > 0);
   1.188 +    assert(unsigned(pos.line) >= firstLine_);
   1.189 +
   1.190 +    unsigned lineDelta = unsigned(pos.line) - firstLine_;
   1.191 +    unsigned pcDelta = unsigned(position()) - lastCodePosition_;
   1.192 +
   1.193 +    sourcemap_.writeUint32(pcDelta);
   1.194 +    sourcemap_.writeUint32(lineDelta);
   1.195 +    sourcemap_.writeUint32(pos.col);
   1.196 +
   1.197 +    lastCodePosition_ = unsigned(position());
   1.198 +}
   1.199 +
   1.200 +void
   1.201 +BytecodeEmitter::getglobal(Symbol *sym)
   1.202 +{
   1.203 +    ensure(OP_GETGLOBAL_LENGTH);
   1.204 +    writeOp(OP_GETGLOBAL);
   1.205 +    writeUint32(addString(sym->name()));
   1.206 +    if (sym->type()->isTraceable())
   1.207 +        markOop(1);
   1.208 +}
   1.209 +void
   1.210 +BytecodeEmitter::setglobal(Symbol *sym)
   1.211 +{
   1.212 +    ensure(OP_SETGLOBAL_LENGTH);
   1.213 +    writeOp(OP_SETGLOBAL);
   1.214 +    writeUint32(addString(sym->name()));
   1.215 +    if (sym->type()->isTraceable())
   1.216 +        markOop(1);
   1.217 +}
   1.218 +
   1.219 +void
   1.220 +BytecodeEmitter::getlocal(VariableSymbol *var)
   1.221 +{
   1.222 +    ensure(OP_GETLOCAL_LENGTH);
   1.223 +    writeOp(OP_GETLOCAL);
   1.224 +    writeUint32(var->slot());
   1.225 +    if (var->type()->isTraceable())
   1.226 +        markOop(1);
   1.227 +}
   1.228 +
   1.229 +void
   1.230 +BytecodeEmitter::setlocal(VariableSymbol *var)
   1.231 +{
   1.232 +    ensure(OP_SETLOCAL_LENGTH);
   1.233 +    writeOp(OP_SETLOCAL);
   1.234 +    writeUint32(var->slot());
   1.235 +    if (var->type()->isTraceable())
   1.236 +        markOop(1);
   1.237 +}
   1.238 +
   1.239 +bool
   1.240 +BytecodeEmitter::allocate(VariableSymbol *sym)
   1.241 +{
   1.242 +    assert(sym->isVariable());
   1.243 +    assert(sym->scope()->kind() == Scope::BLOCK);
   1.244 +
   1.245 +    switch (sym->scope()->kind()) {
   1.246 +      case Scope::BLOCK:
   1.247 +      {
   1.248 +        // See overall comment on overflows.
   1.249 +        assert(locals_.length() < UINT_MAX);
   1.250 +        sym->allocate(VariableSymbol::Local, locals_.length());
   1.251 +        if (!locals_.append(sym))
   1.252 +            return false;
   1.253 +        break;
   1.254 +      }
   1.255 +
   1.256 +      default:
   1.257 +        assert(false);
   1.258 +        return false;
   1.259 +    }
   1.260 +
   1.261 +    return true;
   1.262 +}
   1.263 +
   1.264 +Code *
   1.265 +BytecodeEmitter::finish()
   1.266 +{
   1.267 +    stop();
   1.268 +
   1.269 +    Zone *zone = ZONE();
   1.270 +    if (oom() || zone->hasPendingException())
   1.271 +        return NULL;
   1.272 +
   1.273 +    Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
   1.274 +    if (!bytes)
   1.275 +        return NULL;
   1.276 +    memcpy(bytes->raw(), buffer(), length());
   1.277 +
   1.278 +    Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
   1.279 +    if (!objects)
   1.280 +        return NULL;
   1.281 +
   1.282 +    for (size_t i = 0; i < objects_.length(); i++)
   1.283 +        objects->set(zone, i, objects_[i]);
   1.284 +
   1.285 +    // If any stack slots hold gc pointers at potential failure points in the
   1.286 +    // bytecode, record them now. We do this by building a list of tuples;
   1.287 +    // each tuple contains the pc offset, and a bitset containing which stack
   1.288 +    // slots must be scanned by the gc.
   1.289 +    Local<ByteArray> safepoints(zone);
   1.290 +    if (oopRecords_.length()) {
   1.291 +        size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
   1.292 +        size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
   1.293 +        safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
   1.294 +        if (!safepoints)
   1.295 +            return NULL;
   1.296 +
   1.297 +        Address cursor = safepoints->raw();
   1.298 +        for (size_t i = 0; i < oopRecords_.length(); i++) {
   1.299 +            OopRecord *record = oopRecords_[i];
   1.300 +            assert(record->depth <= maxStackDepth());
   1.301 +
   1.302 +            *reinterpret_cast<unsigned *>(cursor) = record->offset;
   1.303 +
   1.304 +            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
   1.305 +            for (unsigned i = 0; i < record->depth; i++)
   1.306 +                bits[i / 8] |= (1 << (i % 8));
   1.307 +
   1.308 +            cursor += bytesPerSafepoint;
   1.309 +        }
   1.310 +
   1.311 +        assert(cursor == safepoints->raw() + gcmapSize);
   1.312 +    }
   1.313 +
   1.314 +    Local<ByteArray> sourcemap(zone);
   1.315 +    if (sourcemap_.length()) {
   1.316 +        sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
   1.317 +        if (!sourcemap)
   1.318 +            return NULL;
   1.319 +
   1.320 +        memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
   1.321 +    }
   1.322 +
   1.323 +    Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
   1.324 +    if (!strings)
   1.325 +        return NULL;
   1.326 +    for (size_t i = 0; i < strings_.stringCount(); i++)
   1.327 +        strings->set(zone, i, strings_.stringAt(i));
   1.328 +
   1.329 +    Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
   1.330 +    if (!locals)
   1.331 +        return NULL;
   1.332 +    for (size_t i = 0; i < locals_.length(); i++)
   1.333 +        locals->set(zone, i, locals_[i]->type());
   1.334 +
   1.335 +    Local<Code> code(zone);
   1.336 +
   1.337 +    code = Code::New(zone,
   1.338 +                     bytes,
   1.339 +                     locals,
   1.340 +                     objects,
   1.341 +                     strings,
   1.342 +                     maxStackDepth(),
   1.343 +                     safepoints,
   1.344 +                     sourcemap);
   1.345 +
   1.346 +    return code;
   1.347 +}