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 +}