src/compiler/BytecodeEmitter.cpp
author David Anderson <dvander@alliedmods.net>
Wed Dec 26 17:20:55 2012 -0800 (2012-12-26)
changeset 244 3c57bbf22aa2
parent 230 fb3cd08bc7fb
child 262 c4b1341297e5
permissions -rw-r--r--
Fix clang bustage.
     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     loopDepth_(0),
    95     maxLoopDepth_(0)
    96 {
    97     lastCodePosition_ = 0;
    98     firstLine_ = 1;
    99 }
   100 
   101 BytecodeEmitter::~BytecodeEmitter()
   102 {
   103     for (size_t i = 0; i < oopRecords_.length(); i++)
   104         delete oopRecords_[i];
   105 }
   106 
   107 void
   108 BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
   109 {
   110     for (size_t i = 0; i < objects_.length(); i++)
   111         visitor->visit(&objects_[i]);
   112 
   113     strings_.accept(visitor);
   114 }
   115 
   116 bool
   117 BytecodeEmitter::growBuffer(size_t nbytes)
   118 {
   119     if (oom_) {
   120         buffer_pos_ = buffer_;
   121         return false;
   122     }
   123 
   124     size_t newSize = size_t((buffer_end_ - buffer_) * 2);
   125     if (newSize >= MAX_LENGTH) {
   126         oom_ = true;
   127         buffer_pos_ = buffer_;
   128         ZONE()->reportOutOfMemory();
   129         return false;
   130     }
   131 
   132     bytecode *newBuffer;
   133     if (buffer_ == inline_buffer_)
   134         newBuffer = (bytecode *)malloc(newSize);
   135     else
   136         newBuffer = (bytecode *)realloc(buffer_, newSize);
   137 
   138     // If we can't allocate a buffer, reset the buffer to the start and set
   139     // a flag to indicate out-of-memory.
   140     if (!newBuffer) {
   141         oom_ = true;
   142         buffer_pos_ = buffer_;
   143         ZONE()->reportOutOfMemory();
   144         return false;
   145     }
   146 
   147     if (buffer_ == inline_buffer_)
   148         memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
   149 
   150     buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
   151     buffer_ = newBuffer;
   152     buffer_end_ = buffer_ + newSize;
   153     assert(buffer_pos_ + nbytes < buffer_end_);
   154 
   155     return true;
   156 }
   157 
   158 void
   159 BytecodeEmitter::recordOops()
   160 {
   161     OopRecord *record = new OopRecord(oopMap_.length(), position());
   162 
   163     if (!record->slots.ensure(record->depth)) {
   164         oom_ = true;
   165         return;
   166     }
   167 
   168     bool hadOops = false;
   169     for (size_t i = 0; i < oopMap_.length(); i++) {
   170         bool bit = oopMap_[i];
   171         record->slots.infallibleAppend(bit);
   172         hadOops |= bit;
   173     }
   174 
   175     if (!hadOops) {
   176         delete record;
   177         return;
   178     }
   179 
   180     oom_ &= oopRecords_.append(record);
   181 }
   182 
   183 void
   184 BytecodeEmitter::note_position(const SourcePosition &pos)
   185 {
   186     assert(pos.line > 0);
   187     assert(unsigned(pos.line) >= firstLine_);
   188 
   189     unsigned lineDelta = unsigned(pos.line) - firstLine_;
   190     unsigned pcDelta = unsigned(position()) - lastCodePosition_;
   191 
   192     sourcemap_.writeUint32(pcDelta);
   193     sourcemap_.writeUint32(lineDelta);
   194     sourcemap_.writeUint32(pos.col);
   195 
   196     lastCodePosition_ = unsigned(position());
   197 }
   198 
   199 void
   200 BytecodeEmitter::getglobal(Symbol *sym)
   201 {
   202     ensure(OP_GETGLOBAL_LENGTH);
   203     writeOp(OP_GETGLOBAL);
   204     writeUint32(addString(sym->name()));
   205     if (sym->type()->isTraceable())
   206         markOop(1);
   207 }
   208 void
   209 BytecodeEmitter::setglobal(Symbol *sym)
   210 {
   211     ensure(OP_SETGLOBAL_LENGTH);
   212     writeOp(OP_SETGLOBAL);
   213     writeUint32(addString(sym->name()));
   214     if (sym->type()->isTraceable())
   215         markOop(1);
   216 }
   217 
   218 void
   219 BytecodeEmitter::getlocal(VariableSymbol *var)
   220 {
   221     assert(var->storage() == VariableSymbol::Local);
   222     ensure(OP_GETLOCAL_LENGTH);
   223     writeOp(OP_GETLOCAL);
   224     writeUint32(var->slot());
   225     if (var->type()->isTraceable())
   226         markOop(1);
   227 }
   228 
   229 void
   230 BytecodeEmitter::setlocal(VariableSymbol *var)
   231 {
   232     assert(var->storage() == VariableSymbol::Local);
   233     ensure(OP_SETLOCAL_LENGTH);
   234     writeOp(OP_SETLOCAL);
   235     writeUint32(var->slot());
   236     if (var->type()->isTraceable())
   237         markOop(1);
   238 }
   239 
   240 void
   241 BytecodeEmitter::getarg(VariableSymbol *var)
   242 {
   243     assert(var->storage() == VariableSymbol::Arg);
   244     ensure(OP_GETARG_LENGTH);
   245     writeOp(OP_GETARG);
   246     writeUint32(var->slot());
   247     if (var->type()->isTraceable())
   248         markOop(1);
   249 }
   250 
   251 void
   252 BytecodeEmitter::setarg(VariableSymbol *var)
   253 {
   254     assert(var->storage() == VariableSymbol::Arg);
   255     ensure(OP_SETARG_LENGTH);
   256     writeOp(OP_SETARG);
   257     writeUint32(var->slot());
   258     if (var->type()->isTraceable())
   259         markOop(1);
   260 }
   261 
   262 bool
   263 BytecodeEmitter::allocate(VariableSymbol *sym)
   264 {
   265     assert(sym->isVariable());
   266     assert(sym->scope()->kind() == Scope::BLOCK);
   267 
   268     switch (sym->scope()->kind()) {
   269       case Scope::BLOCK:
   270       {
   271         // See overall comment on overflows.
   272         assert(locals_.length() < UINT_MAX);
   273         sym->allocate(VariableSymbol::Local, locals_.length());
   274         if (!locals_.append(sym))
   275             return false;
   276         break;
   277       }
   278 
   279       default:
   280         assert(false);
   281         return false;
   282     }
   283 
   284     return true;
   285 }
   286 
   287 void
   288 BytecodeEmitter::newref(VariableSymbol *var)
   289 {
   290     recordOops();
   291     if (var->storage() == VariableSymbol::Local) {
   292         ensure(OP_VARREF_LIFO_LENGTH);
   293         writeOp(OP_VARREF_LIFO);
   294     } else {
   295         assert(var->storage() == VariableSymbol::Arg);
   296         ensure(OP_ARGREF_LIFO_LENGTH);
   297         writeOp(OP_ARGREF_LIFO);
   298     }
   299     writeUint32(var->slot());
   300     markOop(1);
   301 }
   302 
   303 Code *
   304 BytecodeEmitter::finish()
   305 {
   306     stop();
   307 
   308     Zone *zone = ZONE();
   309     if (oom() || zone->hasPendingException())
   310         return NULL;
   311 
   312     Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
   313     if (!bytes)
   314         return NULL;
   315     memcpy(bytes->raw(), buffer(), length());
   316 
   317     Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
   318     if (!objects)
   319         return NULL;
   320 
   321     for (size_t i = 0; i < objects_.length(); i++)
   322         objects->set(zone, i, objects_[i]);
   323 
   324     // If any stack slots hold gc pointers at potential failure points in the
   325     // bytecode, record them now. We do this by building a list of tuples;
   326     // each tuple contains the pc offset, and a bitset containing which stack
   327     // slots must be scanned by the gc.
   328     Local<ByteArray> safepoints(zone);
   329     if (oopRecords_.length()) {
   330         size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
   331         size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
   332         safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
   333         if (!safepoints)
   334             return NULL;
   335 
   336         Address cursor = safepoints->raw();
   337         for (size_t i = 0; i < oopRecords_.length(); i++) {
   338             OopRecord *record = oopRecords_[i];
   339             assert(record->depth <= maxStackDepth());
   340 
   341             *reinterpret_cast<unsigned *>(cursor) = record->offset;
   342 
   343             unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
   344             for (unsigned i = 0; i < record->depth; i++)
   345                 bits[i / 8] |= (1 << (i % 8));
   346 
   347             cursor += bytesPerSafepoint;
   348         }
   349 
   350         assert(cursor == safepoints->raw() + gcmapSize);
   351     }
   352 
   353     Local<ByteArray> sourcemap(zone);
   354     if (sourcemap_.length()) {
   355         sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
   356         if (!sourcemap)
   357             return NULL;
   358 
   359         memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
   360     }
   361 
   362     Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
   363     if (!strings)
   364         return NULL;
   365     for (size_t i = 0; i < strings_.stringCount(); i++)
   366         strings->set(zone, i, strings_.stringAt(i));
   367 
   368     Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
   369     if (!locals)
   370         return NULL;
   371     for (size_t i = 0; i < locals_.length(); i++)
   372         locals->set(zone, i, locals_[i]->type());
   373 
   374     Local<Code> code(zone);
   375 
   376     code = Code::New(zone,
   377                      bytes,
   378                      locals,
   379                      objects,
   380                      strings,
   381                      maxStackDepth(),
   382                      maxLoopDepth_,
   383                      safepoints,
   384                      sourcemap);
   385 
   386     return code;
   387 }