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