1.1 --- a/src/compiler/BytecodeEmitter.cpp Mon Jun 10 00:46:29 2013 +0100
1.2 +++ b/src/compiler/BytecodeEmitter.cpp Mon Jun 10 01:04:43 2013 +0100
1.3 @@ -1,386 +1,386 @@
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()
1.90 - : AutoRooted(ZONE()),
1.91 - buffer_(inline_buffer_),
1.92 - buffer_pos_(buffer_),
1.93 - buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
1.94 - oom_(false),
1.95 - maxStackDepth_(0),
1.96 - loopDepth_(0),
1.97 - maxLoopDepth_(0)
1.98 -{
1.99 - lastCodePosition_ = 0;
1.100 - firstLine_ = 1;
1.101 -}
1.102 -
1.103 -BytecodeEmitter::~BytecodeEmitter()
1.104 -{
1.105 - for (size_t i = 0; i < oopRecords_.length(); i++)
1.106 - delete oopRecords_[i];
1.107 -}
1.108 -
1.109 -void
1.110 -BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
1.111 -{
1.112 - for (size_t i = 0; i < objects_.length(); i++)
1.113 - visitor->visit(&objects_[i]);
1.114 -
1.115 - strings_.accept(visitor);
1.116 -}
1.117 -
1.118 -bool
1.119 -BytecodeEmitter::growBuffer(size_t nbytes)
1.120 -{
1.121 - if (oom_) {
1.122 - buffer_pos_ = buffer_;
1.123 - return false;
1.124 - }
1.125 -
1.126 - size_t newSize = size_t((buffer_end_ - buffer_) * 2);
1.127 - if (newSize >= MAX_LENGTH) {
1.128 - oom_ = true;
1.129 - buffer_pos_ = buffer_;
1.130 - ZONE()->reportOutOfMemory();
1.131 - return false;
1.132 - }
1.133 -
1.134 - bytecode *newBuffer;
1.135 - if (buffer_ == inline_buffer_)
1.136 - newBuffer = (bytecode *)malloc(newSize);
1.137 - else
1.138 - newBuffer = (bytecode *)realloc(buffer_, newSize);
1.139 -
1.140 - // If we can't allocate a buffer, reset the buffer to the start and set
1.141 - // a flag to indicate out-of-memory.
1.142 - if (!newBuffer) {
1.143 - oom_ = true;
1.144 - buffer_pos_ = buffer_;
1.145 - ZONE()->reportOutOfMemory();
1.146 - return false;
1.147 - }
1.148 -
1.149 - if (buffer_ == inline_buffer_)
1.150 - memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
1.151 -
1.152 - buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
1.153 - buffer_ = newBuffer;
1.154 - buffer_end_ = buffer_ + newSize;
1.155 - assert(buffer_pos_ + nbytes < buffer_end_);
1.156 -
1.157 - return true;
1.158 -}
1.159 -
1.160 -void
1.161 -BytecodeEmitter::recordOops()
1.162 -{
1.163 - OopRecord *record = new OopRecord(oopMap_.length(), position());
1.164 -
1.165 - if (!record->slots.ensure(record->depth)) {
1.166 - oom_ = true;
1.167 - return;
1.168 - }
1.169 -
1.170 - bool hadOops = false;
1.171 - for (size_t i = 0; i < oopMap_.length(); i++) {
1.172 - bool bit = oopMap_[i];
1.173 - record->slots.infallibleAppend(bit);
1.174 - hadOops |= bit;
1.175 - }
1.176 -
1.177 - if (!hadOops) {
1.178 - delete record;
1.179 - return;
1.180 - }
1.181 -
1.182 - oom_ &= oopRecords_.append(record);
1.183 -}
1.184 -
1.185 -void
1.186 -BytecodeEmitter::note_position(const SourcePosition &pos)
1.187 -{
1.188 - assert(pos.line > 0);
1.189 - assert(unsigned(pos.line) >= firstLine_);
1.190 -
1.191 - unsigned lineDelta = unsigned(pos.line) - firstLine_;
1.192 - unsigned pcDelta = unsigned(position()) - lastCodePosition_;
1.193 -
1.194 - sourcemap_.writeUint32(pcDelta);
1.195 - sourcemap_.writeUint32(lineDelta);
1.196 - sourcemap_.writeUint32(pos.col);
1.197 -
1.198 - lastCodePosition_ = unsigned(position());
1.199 -}
1.200 -
1.201 -void
1.202 -BytecodeEmitter::getglobal(Symbol *sym)
1.203 -{
1.204 - ensure(OP_GETGLOBAL_LENGTH);
1.205 - writeOp(OP_GETGLOBAL);
1.206 - writeUint32(addString(sym->name()));
1.207 - if (sym->type()->isTraceable())
1.208 - markOop(1);
1.209 -}
1.210 -void
1.211 -BytecodeEmitter::setglobal(Symbol *sym)
1.212 -{
1.213 - ensure(OP_SETGLOBAL_LENGTH);
1.214 - writeOp(OP_SETGLOBAL);
1.215 - writeUint32(addString(sym->name()));
1.216 - if (sym->type()->isTraceable())
1.217 - markOop(1);
1.218 -}
1.219 -
1.220 -void
1.221 -BytecodeEmitter::getlocal(VariableSymbol *var)
1.222 -{
1.223 - assert(var->storage() == VariableSymbol::Local);
1.224 - ensure(OP_GETLOCAL_LENGTH);
1.225 - writeOp(OP_GETLOCAL);
1.226 - writeUint32(var->slot());
1.227 - if (var->type()->isTraceable())
1.228 - markOop(1);
1.229 -}
1.230 -
1.231 -void
1.232 -BytecodeEmitter::setlocal(VariableSymbol *var)
1.233 -{
1.234 - assert(var->storage() == VariableSymbol::Local);
1.235 - ensure(OP_SETLOCAL_LENGTH);
1.236 - writeOp(OP_SETLOCAL);
1.237 - writeUint32(var->slot());
1.238 - if (var->type()->isTraceable())
1.239 - markOop(1);
1.240 -}
1.241 -
1.242 -void
1.243 -BytecodeEmitter::getarg(VariableSymbol *var)
1.244 -{
1.245 - assert(var->storage() == VariableSymbol::Arg);
1.246 - ensure(OP_GETARG_LENGTH);
1.247 - writeOp(OP_GETARG);
1.248 - writeUint32(var->slot());
1.249 - if (var->type()->isTraceable())
1.250 - markOop(1);
1.251 -}
1.252 -
1.253 -void
1.254 -BytecodeEmitter::setarg(VariableSymbol *var)
1.255 -{
1.256 - assert(var->storage() == VariableSymbol::Arg);
1.257 - ensure(OP_SETARG_LENGTH);
1.258 - writeOp(OP_SETARG);
1.259 - writeUint32(var->slot());
1.260 - if (var->type()->isTraceable())
1.261 - markOop(1);
1.262 -}
1.263 -
1.264 -bool
1.265 -BytecodeEmitter::allocate(VariableSymbol *sym)
1.266 -{
1.267 - assert(sym->isVariable());
1.268 - assert(sym->scope()->kind() == Scope::BLOCK);
1.269 -
1.270 - switch (sym->scope()->kind()) {
1.271 - case Scope::BLOCK:
1.272 - {
1.273 - // See overall comment on overflows.
1.274 - assert(locals_.length() < UINT_MAX);
1.275 - sym->allocate(VariableSymbol::Local, locals_.length());
1.276 - if (!locals_.append(sym))
1.277 - return false;
1.278 - break;
1.279 - }
1.280 -
1.281 - default:
1.282 - assert(false);
1.283 - return false;
1.284 - }
1.285 -
1.286 - return true;
1.287 -}
1.288 -
1.289 -void
1.290 -BytecodeEmitter::newref(VariableSymbol *var)
1.291 -{
1.292 - recordOops();
1.293 - if (var->storage() == VariableSymbol::Local) {
1.294 - ensure(OP_VARREF_LIFO_LENGTH);
1.295 - writeOp(OP_VARREF_LIFO);
1.296 - } else {
1.297 - assert(var->storage() == VariableSymbol::Arg);
1.298 - ensure(OP_ARGREF_LIFO_LENGTH);
1.299 - writeOp(OP_ARGREF_LIFO);
1.300 - }
1.301 - writeUint32(var->slot());
1.302 - markOop(1);
1.303 -}
1.304 -
1.305 -Code *
1.306 -BytecodeEmitter::finish()
1.307 -{
1.308 - stop();
1.309 -
1.310 - Zone *zone = ZONE();
1.311 - if (oom() || zone->hasPendingException())
1.312 - return NULL;
1.313 -
1.314 - Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
1.315 - if (!bytes)
1.316 - return NULL;
1.317 - memcpy(bytes->raw(), buffer(), length());
1.318 -
1.319 - Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
1.320 - if (!objects)
1.321 - return NULL;
1.322 -
1.323 - for (size_t i = 0; i < objects_.length(); i++)
1.324 - objects->set(zone, i, objects_[i]);
1.325 -
1.326 - // If any stack slots hold gc pointers at potential failure points in the
1.327 - // bytecode, record them now. We do this by building a list of tuples;
1.328 - // each tuple contains the pc offset, and a bitset containing which stack
1.329 - // slots must be scanned by the gc.
1.330 - Local<ByteArray> safepoints(zone);
1.331 - if (oopRecords_.length()) {
1.332 - size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
1.333 - size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
1.334 - safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
1.335 - if (!safepoints)
1.336 - return NULL;
1.337 -
1.338 - Address cursor = safepoints->raw();
1.339 - for (size_t i = 0; i < oopRecords_.length(); i++) {
1.340 - OopRecord *record = oopRecords_[i];
1.341 - assert(record->depth <= maxStackDepth());
1.342 -
1.343 - *reinterpret_cast<unsigned *>(cursor) = record->offset;
1.344 -
1.345 - unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
1.346 - for (unsigned i = 0; i < record->depth; i++)
1.347 - bits[i / 8] |= (1 << (i % 8));
1.348 -
1.349 - cursor += bytesPerSafepoint;
1.350 - }
1.351 -
1.352 - assert(cursor == safepoints->raw() + gcmapSize);
1.353 - }
1.354 -
1.355 - Local<ByteArray> sourcemap(zone);
1.356 - if (sourcemap_.length()) {
1.357 - sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
1.358 - if (!sourcemap)
1.359 - return NULL;
1.360 -
1.361 - memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
1.362 - }
1.363 -
1.364 - Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
1.365 - if (!strings)
1.366 - return NULL;
1.367 - for (size_t i = 0; i < strings_.stringCount(); i++)
1.368 - strings->set(zone, i, strings_.stringAt(i));
1.369 -
1.370 - Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
1.371 - if (!locals)
1.372 - return NULL;
1.373 - for (size_t i = 0; i < locals_.length(); i++)
1.374 - locals->set(zone, i, locals_[i]->type());
1.375 -
1.376 - Local<Code> code(zone);
1.377 -
1.378 - code = Code::New(zone,
1.379 - bytes,
1.380 - locals,
1.381 - objects,
1.382 - strings,
1.383 - maxStackDepth(),
1.384 - maxLoopDepth_,
1.385 - safepoints,
1.386 - sourcemap);
1.387 -
1.388 - return code;
1.389 -}
1.390 +/* vim: set ts=4 sw=4 tw=99 et:
1.391 + *
1.392 + * Copyright (C) 2012 David Anderson
1.393 + *
1.394 + * This file is part of JITCraft.
1.395 + *
1.396 + * JITCraft is free software: you can redistribute it and/or modify it under
1.397 + * the terms of the GNU General Public License as published by the Free
1.398 + * Software Foundation, either version 3 of the License, or (at your option)
1.399 + * any later version.
1.400 + *
1.401 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
1.402 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.403 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
1.404 + *
1.405 + * You should have received a copy of the GNU General Public License along with
1.406 + * JITCraft. If not, see http://www.gnu.org/licenses/.
1.407 + */
1.408 +#include <stdlib.h>
1.409 +#include <string.h>
1.410 +#include "../Utility.h"
1.411 +#include "../Types.h"
1.412 +#include "../Zone.h"
1.413 +#include "../Strings.h"
1.414 +#include "../Zone.h"
1.415 +#include "BytecodeEmitter.h"
1.416 +#include "Symbols.h"
1.417 +#include "Scopes.h"
1.418 +#include "../Spaces-inl.h"
1.419 +#include "../Heap-inl.h"
1.420 +
1.421 +using namespace ke;
1.422 +
1.423 +StringTable::StringTable()
1.424 + : set_(ZoneAllocatorPolicy()),
1.425 + initialized_(false)
1.426 +{
1.427 +}
1.428 +
1.429 +bool
1.430 +StringTable::initialize()
1.431 +{
1.432 + assert(!initialized_);
1.433 + initialized_ = true;
1.434 + if (!set_.init(16))
1.435 + return false;
1.436 + return true;
1.437 +}
1.438 +
1.439 +bool
1.440 +StringTable::add(Handle<String> name, unsigned *indexp)
1.441 +{
1.442 + if (!initialized_ && !initialize())
1.443 + return false;
1.444 +
1.445 + Set::Insert p = set_.findForAdd(*name);
1.446 + if (p.found()) {
1.447 + *indexp = p->index;
1.448 + return true;
1.449 + }
1.450 +
1.451 + if (strings_.length() > INT_MAX) {
1.452 + ZONE()->reportAllocationOverflow();
1.453 + return false;
1.454 + }
1.455 +
1.456 + Entry e(name, strings_.length());
1.457 + if (!strings_.append(e))
1.458 + return false;
1.459 +
1.460 + if (!set_.add(p, e))
1.461 + return false;
1.462 +
1.463 + *indexp = e.index;
1.464 +
1.465 + return true;
1.466 +}
1.467 +
1.468 +void
1.469 +StringTable::accept(VirtualObjectVisitor *visitor)
1.470 +{
1.471 + for (size_t i = 0; i < strings_.length(); i++)
1.472 + visitor->visit(reinterpret_cast<Object **>(&strings_[i].string));
1.473 +}
1.474 +
1.475 +BytecodeEmitter::BytecodeEmitter()
1.476 + : AutoRooted(ZONE()),
1.477 + buffer_(inline_buffer_),
1.478 + buffer_pos_(buffer_),
1.479 + buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
1.480 + oom_(false),
1.481 + maxStackDepth_(0),
1.482 + loopDepth_(0),
1.483 + maxLoopDepth_(0)
1.484 +{
1.485 + lastCodePosition_ = 0;
1.486 + firstLine_ = 1;
1.487 +}
1.488 +
1.489 +BytecodeEmitter::~BytecodeEmitter()
1.490 +{
1.491 + for (size_t i = 0; i < oopRecords_.length(); i++)
1.492 + delete oopRecords_[i];
1.493 +}
1.494 +
1.495 +void
1.496 +BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
1.497 +{
1.498 + for (size_t i = 0; i < objects_.length(); i++)
1.499 + visitor->visit(&objects_[i]);
1.500 +
1.501 + strings_.accept(visitor);
1.502 +}
1.503 +
1.504 +bool
1.505 +BytecodeEmitter::growBuffer(size_t nbytes)
1.506 +{
1.507 + if (oom_) {
1.508 + buffer_pos_ = buffer_;
1.509 + return false;
1.510 + }
1.511 +
1.512 + size_t newSize = size_t((buffer_end_ - buffer_) * 2);
1.513 + if (newSize >= MAX_LENGTH) {
1.514 + oom_ = true;
1.515 + buffer_pos_ = buffer_;
1.516 + ZONE()->reportOutOfMemory();
1.517 + return false;
1.518 + }
1.519 +
1.520 + bytecode *newBuffer;
1.521 + if (buffer_ == inline_buffer_)
1.522 + newBuffer = (bytecode *)malloc(newSize);
1.523 + else
1.524 + newBuffer = (bytecode *)realloc(buffer_, newSize);
1.525 +
1.526 + // If we can't allocate a buffer, reset the buffer to the start and set
1.527 + // a flag to indicate out-of-memory.
1.528 + if (!newBuffer) {
1.529 + oom_ = true;
1.530 + buffer_pos_ = buffer_;
1.531 + ZONE()->reportOutOfMemory();
1.532 + return false;
1.533 + }
1.534 +
1.535 + if (buffer_ == inline_buffer_)
1.536 + memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
1.537 +
1.538 + buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
1.539 + buffer_ = newBuffer;
1.540 + buffer_end_ = buffer_ + newSize;
1.541 + assert(buffer_pos_ + nbytes < buffer_end_);
1.542 +
1.543 + return true;
1.544 +}
1.545 +
1.546 +void
1.547 +BytecodeEmitter::recordOops()
1.548 +{
1.549 + OopRecord *record = new OopRecord(oopMap_.length(), position());
1.550 +
1.551 + if (!record->slots.ensure(record->depth)) {
1.552 + oom_ = true;
1.553 + return;
1.554 + }
1.555 +
1.556 + bool hadOops = false;
1.557 + for (size_t i = 0; i < oopMap_.length(); i++) {
1.558 + bool bit = oopMap_[i];
1.559 + record->slots.infallibleAppend(bit);
1.560 + hadOops |= bit;
1.561 + }
1.562 +
1.563 + if (!hadOops) {
1.564 + delete record;
1.565 + return;
1.566 + }
1.567 +
1.568 + oom_ &= oopRecords_.append(record);
1.569 +}
1.570 +
1.571 +void
1.572 +BytecodeEmitter::note_position(const SourcePosition &pos)
1.573 +{
1.574 + assert(pos.line > 0);
1.575 + assert(unsigned(pos.line) >= firstLine_);
1.576 +
1.577 + unsigned lineDelta = unsigned(pos.line) - firstLine_;
1.578 + unsigned pcDelta = unsigned(position()) - lastCodePosition_;
1.579 +
1.580 + sourcemap_.writeUint32(pcDelta);
1.581 + sourcemap_.writeUint32(lineDelta);
1.582 + sourcemap_.writeUint32(pos.col);
1.583 +
1.584 + lastCodePosition_ = unsigned(position());
1.585 +}
1.586 +
1.587 +void
1.588 +BytecodeEmitter::getglobal(Symbol *sym)
1.589 +{
1.590 + ensure(OP_GETGLOBAL_LENGTH);
1.591 + writeOp(OP_GETGLOBAL);
1.592 + writeUint32(addString(sym->name()));
1.593 + if (sym->type()->isTraceable())
1.594 + markOop(1);
1.595 +}
1.596 +void
1.597 +BytecodeEmitter::setglobal(Symbol *sym)
1.598 +{
1.599 + ensure(OP_SETGLOBAL_LENGTH);
1.600 + writeOp(OP_SETGLOBAL);
1.601 + writeUint32(addString(sym->name()));
1.602 + if (sym->type()->isTraceable())
1.603 + markOop(1);
1.604 +}
1.605 +
1.606 +void
1.607 +BytecodeEmitter::getlocal(VariableSymbol *var)
1.608 +{
1.609 + assert(var->storage() == VariableSymbol::Local);
1.610 + ensure(OP_GETLOCAL_LENGTH);
1.611 + writeOp(OP_GETLOCAL);
1.612 + writeUint32(var->slot());
1.613 + if (var->type()->isTraceable())
1.614 + markOop(1);
1.615 +}
1.616 +
1.617 +void
1.618 +BytecodeEmitter::setlocal(VariableSymbol *var)
1.619 +{
1.620 + assert(var->storage() == VariableSymbol::Local);
1.621 + ensure(OP_SETLOCAL_LENGTH);
1.622 + writeOp(OP_SETLOCAL);
1.623 + writeUint32(var->slot());
1.624 + if (var->type()->isTraceable())
1.625 + markOop(1);
1.626 +}
1.627 +
1.628 +void
1.629 +BytecodeEmitter::getarg(VariableSymbol *var)
1.630 +{
1.631 + assert(var->storage() == VariableSymbol::Arg);
1.632 + ensure(OP_GETARG_LENGTH);
1.633 + writeOp(OP_GETARG);
1.634 + writeUint32(var->slot());
1.635 + if (var->type()->isTraceable())
1.636 + markOop(1);
1.637 +}
1.638 +
1.639 +void
1.640 +BytecodeEmitter::setarg(VariableSymbol *var)
1.641 +{
1.642 + assert(var->storage() == VariableSymbol::Arg);
1.643 + ensure(OP_SETARG_LENGTH);
1.644 + writeOp(OP_SETARG);
1.645 + writeUint32(var->slot());
1.646 + if (var->type()->isTraceable())
1.647 + markOop(1);
1.648 +}
1.649 +
1.650 +bool
1.651 +BytecodeEmitter::allocate(VariableSymbol *sym)
1.652 +{
1.653 + assert(sym->isVariable());
1.654 + assert(sym->scope()->kind() == Scope::BLOCK);
1.655 +
1.656 + switch (sym->scope()->kind()) {
1.657 + case Scope::BLOCK:
1.658 + {
1.659 + // See overall comment on overflows.
1.660 + assert(locals_.length() < UINT_MAX);
1.661 + sym->allocate(VariableSymbol::Local, locals_.length());
1.662 + if (!locals_.append(sym))
1.663 + return false;
1.664 + break;
1.665 + }
1.666 +
1.667 + default:
1.668 + assert(false);
1.669 + return false;
1.670 + }
1.671 +
1.672 + return true;
1.673 +}
1.674 +
1.675 +void
1.676 +BytecodeEmitter::newref(VariableSymbol *var)
1.677 +{
1.678 + recordOops();
1.679 + if (var->storage() == VariableSymbol::Local) {
1.680 + ensure(OP_VARREF_LIFO_LENGTH);
1.681 + writeOp(OP_VARREF_LIFO);
1.682 + } else {
1.683 + assert(var->storage() == VariableSymbol::Arg);
1.684 + ensure(OP_ARGREF_LIFO_LENGTH);
1.685 + writeOp(OP_ARGREF_LIFO);
1.686 + }
1.687 + writeUint32(var->slot());
1.688 + markOop(1);
1.689 +}
1.690 +
1.691 +Code *
1.692 +BytecodeEmitter::finish()
1.693 +{
1.694 + stop();
1.695 +
1.696 + Zone *zone = ZONE();
1.697 + if (oom() || zone->hasPendingException())
1.698 + return NULL;
1.699 +
1.700 + Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
1.701 + if (!bytes)
1.702 + return NULL;
1.703 + memcpy(bytes->raw(), buffer(), length());
1.704 +
1.705 + Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
1.706 + if (!objects)
1.707 + return NULL;
1.708 +
1.709 + for (size_t i = 0; i < objects_.length(); i++)
1.710 + objects->set(zone, i, objects_[i]);
1.711 +
1.712 + // If any stack slots hold gc pointers at potential failure points in the
1.713 + // bytecode, record them now. We do this by building a list of tuples;
1.714 + // each tuple contains the pc offset, and a bitset containing which stack
1.715 + // slots must be scanned by the gc.
1.716 + Local<ByteArray> safepoints(zone);
1.717 + if (oopRecords_.length()) {
1.718 + size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
1.719 + size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
1.720 + safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
1.721 + if (!safepoints)
1.722 + return NULL;
1.723 +
1.724 + Address cursor = safepoints->raw();
1.725 + for (size_t i = 0; i < oopRecords_.length(); i++) {
1.726 + OopRecord *record = oopRecords_[i];
1.727 + assert(record->depth <= maxStackDepth());
1.728 +
1.729 + *reinterpret_cast<unsigned *>(cursor) = record->offset;
1.730 +
1.731 + unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
1.732 + for (unsigned i = 0; i < record->depth; i++)
1.733 + bits[i / 8] |= (1 << (i % 8));
1.734 +
1.735 + cursor += bytesPerSafepoint;
1.736 + }
1.737 +
1.738 + assert(cursor == safepoints->raw() + gcmapSize);
1.739 + }
1.740 +
1.741 + Local<ByteArray> sourcemap(zone);
1.742 + if (sourcemap_.length()) {
1.743 + sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
1.744 + if (!sourcemap)
1.745 + return NULL;
1.746 +
1.747 + memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
1.748 + }
1.749 +
1.750 + Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
1.751 + if (!strings)
1.752 + return NULL;
1.753 + for (size_t i = 0; i < strings_.stringCount(); i++)
1.754 + strings->set(zone, i, strings_.stringAt(i));
1.755 +
1.756 + Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
1.757 + if (!locals)
1.758 + return NULL;
1.759 + for (size_t i = 0; i < locals_.length(); i++)
1.760 + locals->set(zone, i, locals_[i]->type());
1.761 +
1.762 + Local<Code> code(zone);
1.763 +
1.764 + code = Code::New(zone,
1.765 + bytes,
1.766 + locals,
1.767 + objects,
1.768 + strings,
1.769 + maxStackDepth(),
1.770 + maxLoopDepth_,
1.771 + safepoints,
1.772 + sourcemap);
1.773 +
1.774 + return code;
1.775 +}