1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/compiler/BytecodeEmitter.h Sat Nov 17 18:41:01 2012 -0800
1.3 @@ -0,0 +1,737 @@
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 +#ifndef _include_bytecode_emitter_h_
1.23 +#define _include_bytecode_emitter_h_
1.24 +
1.25 +#include <assert.h>
1.26 +#include <limits.h>
1.27 +#include "../Opcodes.h"
1.28 +#include "../Handles.h"
1.29 +#include "../CompactBuffer.h"
1.30 +#include "../Array.h"
1.31 +#include "../HashTable.h"
1.32 +#include "../VirtualObjectVisitor.h"
1.33 +
1.34 +namespace ke {
1.35 +
1.36 +// An overarching note on overflows: Though we should use CheckedInt, we rely
1.37 +// on a source-length cap covering all possible overflow checks. As long as
1.38 +// the source length is capped to INT_MAX, the number of AST nodes will be
1.39 +// strictly beneath that cap, and so to will most things generated by the
1.40 +// AST. For example, local and argument counts, number of functions, fields
1.41 +// in a struct, et cetera. Not everything can be covered by this cap: the
1.42 +// stack depth, number of bytecodes for example. In these cases we explicitly
1.43 +// test for overflow of INT_MAX and in other cases we assert.
1.44 +//
1.45 +// In the future, we should of course use a checked int wrapper.
1.46 +
1.47 +class Type;
1.48 +class Map;
1.49 +class ArrayMap;
1.50 +class Symbol;
1.51 +class VariableSymbol;
1.52 +
1.53 +struct OopRecord
1.54 +{
1.55 + unsigned depth;
1.56 + unsigned offset;
1.57 + Vector<bool> slots;
1.58 +
1.59 + OopRecord(unsigned length, unsigned offset)
1.60 + : depth(length),
1.61 + offset(offset)
1.62 + {
1.63 + }
1.64 +};
1.65 +
1.66 +class StringTable
1.67 +{
1.68 + struct Entry
1.69 + {
1.70 + String *string;
1.71 + unsigned index;
1.72 +
1.73 + Entry()
1.74 + : string(NULL),
1.75 + index(0)
1.76 + {
1.77 + }
1.78 +
1.79 + Entry(String *string, unsigned index)
1.80 + : string(string),
1.81 + index(index)
1.82 + {
1.83 + }
1.84 + };
1.85 +
1.86 + struct Policy
1.87 + {
1.88 + typedef Entry Payload;
1.89 +
1.90 + static uint32 hash(String *string) {
1.91 + return HashPointer(string);
1.92 + }
1.93 +
1.94 + static bool matches(String *key, Entry &e) {
1.95 + return key == e.string;
1.96 + }
1.97 + };
1.98 +
1.99 + typedef HashTable<Policy, ZoneAllocatorPolicy> Set;
1.100 +
1.101 + public:
1.102 + StringTable();
1.103 + bool initialize();
1.104 + void accept(VirtualObjectVisitor *visitor);
1.105 +
1.106 + bool add(Handle<String> name, unsigned *indexp);
1.107 + size_t stringCount() const {
1.108 + return strings_.length();
1.109 + }
1.110 + String *stringAt(size_t i) const {
1.111 + return strings_[i].string;
1.112 + }
1.113 +
1.114 + private:
1.115 + Set set_;
1.116 + Vector<Entry> strings_;
1.117 + bool initialized_;
1.118 +};
1.119 +
1.120 +// The bytecode emitter assists in building Code objects, by emitting opcodes
1.121 +// and tracking stack information. Since the SemA creates temporary pool/root
1.122 +// scopes, we cannot use ScopedRoot or PoolObjects. Instead, BCE gets a
1.123 +// special marking function.
1.124 +class BytecodeEmitter : public AutoRooted
1.125 +{
1.126 + private:
1.127 + PoolAllocator &pool_;
1.128 +
1.129 + bytecode *buffer_;
1.130 + bytecode *buffer_pos_;
1.131 + bytecode *buffer_end_;
1.132 + bytecode inline_buffer_[512];
1.133 + bool oom_;
1.134 + unsigned maxStackDepth_;
1.135 + Vector<bool> oopMap_;
1.136 + Vector<OopRecord *> oopRecords_;
1.137 + CompactBufferWriter sourcemap_;
1.138 + unsigned lastCodePosition_;
1.139 + unsigned firstLine_;
1.140 + StringTable strings_;
1.141 + Vector<Symbol *> locals_;
1.142 + Vector<Object *> objects_;
1.143 +
1.144 + private:
1.145 + // The maximum size of a code object must be such that the distance between
1.146 + // two instructions fits into a signed, 31-bit integer. This ensures that
1.147 + // all code-bounded buffers (like the number of object literals or
1.148 + // safepoints) does not need to be bounds checked. It also means we can add
1.149 + // any two offsets and be guaranteed that they don't overflow.
1.150 + static const size_t MAX_LENGTH = INT_MAX / 2;
1.151 +
1.152 + private:
1.153 + bool growBuffer(size_t bytes);
1.154 +
1.155 + // Checking the return value is not necessary, since the inline buffer is
1.156 + // used as a ballast.
1.157 + bool ensure(size_t bytes) {
1.158 + if (buffer_pos_ + bytes > buffer_end_)
1.159 + return growBuffer(bytes);
1.160 + return true;
1.161 + }
1.162 +
1.163 + void writeUint8(unsigned value) {
1.164 + assert(value <= UCHAR_MAX);
1.165 + *buffer_pos_++ = value;
1.166 + }
1.167 + void writeFloat(float value) {
1.168 + *(float *)buffer_pos_ = value;
1.169 + buffer_pos_ += sizeof(float);
1.170 + }
1.171 + void writeInt32(int value) {
1.172 + *(int *)buffer_pos_ = value;
1.173 + buffer_pos_ += sizeof(int);
1.174 + }
1.175 + void writeUint32(unsigned value) {
1.176 + *(unsigned *)buffer_pos_ = value;
1.177 + buffer_pos_ += sizeof(unsigned);
1.178 + }
1.179 + void writeOp(Opcode op) {
1.180 + if (oom_)
1.181 + return;
1.182 +
1.183 + writeUint8(op);
1.184 + for (int i = 0; i < OpcodeInfo[op].nuses; i++)
1.185 + oopMap_.pop();
1.186 + for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
1.187 + oopMap_.append(false);
1.188 + if (oopMap_.length() > maxStackDepth_)
1.189 + maxStackDepth_ = oopMap_.length();
1.190 + }
1.191 + void writeObject(Object *obj) {
1.192 + writeUint32(objects_.length());
1.193 + ScopedRoot<Object> root(obj);
1.194 + if (!objects_.append(root))
1.195 + oom_ = true;
1.196 + }
1.197 +
1.198 + int position() const {
1.199 + assert(buffer_pos_ - buffer_ < INT_MAX / 2);
1.200 + return int(buffer_pos_ - buffer_);
1.201 + }
1.202 +
1.203 + public:
1.204 + BytecodeEmitter(PoolAllocator &pool);
1.205 + ~BytecodeEmitter();
1.206 +
1.207 + void accept(VirtualObjectVisitor *visitor);
1.208 +
1.209 + bytecode *buffer() const {
1.210 + return buffer_;
1.211 + }
1.212 + unsigned length() const {
1.213 + return unsigned(buffer_pos_ - buffer_);
1.214 + }
1.215 + bool oom() const {
1.216 + return oom_ || sourcemap_.oom();
1.217 + }
1.218 + unsigned stackDepth() const {
1.219 + return oopMap_.length();
1.220 + }
1.221 + unsigned maxStackDepth() const {
1.222 + return maxStackDepth_;
1.223 + }
1.224 +
1.225 + void drop(unsigned amt) {
1.226 + assert(amt <= stackDepth());
1.227 + for (unsigned i = 0; i < amt; i++)
1.228 + oopMap_.pop();
1.229 + }
1.230 +
1.231 + void note_position(const SourcePosition &pos);
1.232 + void setFirstLine(unsigned line) {
1.233 + assert(!sourcemap_.length());
1.234 + firstLine_ = line;
1.235 + }
1.236 +
1.237 + public:
1.238 + // A label represents a local control-flow target in the bytecode. A label
1.239 + // may be in three states:
1.240 + //
1.241 + // (1) Empty - the label is not used yet.
1.242 + // (2) Pending - the label has incoming jumps, but the actual location of
1.243 + // is not yet known. The list of jumps is threaded through
1.244 + // the four bytes reserved for each emitted jump target. In
1.245 + // this case, the offset field is the location of the most
1.246 + // recently emitted incoming jump.
1.247 + // (3) Bound - the label's position has been pinned.
1.248 + //
1.249 + // A jump can be emitted to a label in any state. Binding a label
1.250 + // immediately backpatches all pending incoming jumps. A label must be
1.251 + // bound if it is used.
1.252 + class Label
1.253 + {
1.254 + int offset_ : 31;
1.255 + bool bound_ : 1;
1.256 +
1.257 + void setOffset(int offset) {
1.258 + offset_ = offset;
1.259 + assert(offset_ == offset);
1.260 + }
1.261 +
1.262 + public:
1.263 + static const int INVALID_OFFSET = -1;
1.264 +
1.265 + public:
1.266 + Label()
1.267 + : offset_(INVALID_OFFSET),
1.268 + bound_(false)
1.269 + {
1.270 + }
1.271 + ~Label()
1.272 + {
1.273 + assert(bound_ || offset_ == INVALID_OFFSET);
1.274 + }
1.275 +
1.276 + bool bound() const {
1.277 + return bound_;
1.278 + }
1.279 + int offset() const {
1.280 + return offset_;
1.281 + }
1.282 + void bind(int offset) {
1.283 + assert(!bound_);
1.284 + setOffset(offset);
1.285 + bound_ = true;
1.286 + }
1.287 + int link(int offset) {
1.288 + assert(!bound_);
1.289 + int old = offset_;
1.290 + setOffset(offset);
1.291 + return old;
1.292 + }
1.293 + };
1.294 +
1.295 + private:
1.296 + int patchJumpAt(int at, int to) {
1.297 + assert(at >= 0 && at < position());
1.298 + int old = *(int *)(buffer_ + at + 1);
1.299 + *(int *)(buffer_ + at + 1) = (to - at);
1.300 + return old;
1.301 + }
1.302 +
1.303 + void singleByteOp(Opcode op) {
1.304 + assert(OpcodeInfo[op].length == 1);
1.305 + ensure(OpcodeInfo[op].length);
1.306 + writeOp(op);
1.307 + }
1.308 +
1.309 + // Mark a stack slot as having an object pointer.
1.310 + void markOop(unsigned depth, bool oop = true) {
1.311 + if (oom_)
1.312 + return;
1.313 + oopMap_[oopMap_.length() - depth] = oop;
1.314 + }
1.315 + bool getOop(unsigned depth) {
1.316 + if (oom_)
1.317 + return false;
1.318 + return oopMap_[oopMap_.length() - depth];
1.319 + }
1.320 +
1.321 + // Mark the current bytecode position as either re-entrant (meaning, it
1.322 + // can leave the interpreter or call to another function), or causing GC.
1.323 + // This will record which stack slots have objects and associate that
1.324 + // information with the current pc.
1.325 + void recordOops();
1.326 +
1.327 + public:
1.328 + void int_(int value) {
1.329 + ensure(OP_INT);
1.330 + writeOp(OP_INT);
1.331 + writeInt32(value);
1.332 + }
1.333 + void return_() {
1.334 + ensure(OP_RETURN);
1.335 + writeOp(OP_RETURN);
1.336 + }
1.337 + void getlocal(VariableSymbol *var);
1.338 + void setlocal(VariableSymbol *var);
1.339 +#if 0
1.340 + void getarg(Variable *var) {
1.341 + ensure(OP_GETARG_LENGTH);
1.342 + writeOp(OP_GETARG);
1.343 + writeUint32(var->slot());
1.344 +
1.345 + if (var->type()->isTraceable())
1.346 + markOop(1);
1.347 + }
1.348 + void setarg(Variable *var) {
1.349 + ensure(OP_SETARG_LENGTH);
1.350 + writeOp(OP_SETARG);
1.351 + writeUint32(var->slot());
1.352 +
1.353 + if (var->type()->isTraceable())
1.354 + markOop(1);
1.355 + }
1.356 +#endif
1.357 +
1.358 + void j(Opcode op, Label *label) {
1.359 + // Since jumps can skip around the stream, do not try to do anything
1.360 + // in a potentially truncated state.
1.361 + if (oom())
1.362 + return;
1.363 +
1.364 + assert(op == OP_JT || op == OP_JF || op == OP_JUMP);
1.365 + ensure(OP_JUMP_LENGTH);
1.366 +
1.367 + if (label->bound()) {
1.368 + // We can immediately emit this jump.
1.369 + int distance = label->offset() - position();
1.370 + writeOp(op);
1.371 + writeInt32(distance);
1.372 + } else {
1.373 + // We can't emit this jump yet. Add a placeholder.
1.374 + int old = label->link(position());
1.375 + writeOp(op);
1.376 + writeInt32(old);
1.377 + }
1.378 + }
1.379 + void bind(Label *label) {
1.380 + if (oom())
1.381 + return;
1.382 +
1.383 + assert(!label->bound());
1.384 +
1.385 + int offset = label->offset();
1.386 + while (offset != Label::INVALID_OFFSET)
1.387 + offset = patchJumpAt(offset, position());
1.388 +
1.389 + label->bind(position());
1.390 + }
1.391 + void jump(Label *label) {
1.392 + j(OP_JUMP, label);
1.393 + }
1.394 +
1.395 + void binary(Opcode op) {
1.396 + singleByteOp(op);
1.397 + }
1.398 + void unary(Opcode op) {
1.399 + singleByteOp(op);
1.400 + }
1.401 +
1.402 + void pop() {
1.403 + singleByteOp(OP_POP);
1.404 + }
1.405 + void stop() {
1.406 + singleByteOp(OP_STOP);
1.407 + }
1.408 + void call(Handle<FunctionType> fun, unsigned argc) {
1.409 + recordOops();
1.410 +
1.411 + if (fun->isNative()) {
1.412 + ensure(OP_CALLNATIVE_LENGTH);
1.413 + writeOp(OP_CALLNATIVE);
1.414 + writeUint32(argc);
1.415 + drop(argc + 1);
1.416 + } else {
1.417 + ensure(OP_CALL_LENGTH);
1.418 + writeOp(OP_CALL);
1.419 + drop(argc + 1);
1.420 +
1.421 + if (fun->returnType()->isVoid())
1.422 + drop(1);
1.423 + else if (fun->returnType()->isTraceable())
1.424 + markOop(1);
1.425 + }
1.426 + }
1.427 +
1.428 + void getelem(Type *type) {
1.429 + singleByteOp(OP_GETELEM);
1.430 +
1.431 + if (type->isTraceable())
1.432 + markOop(1);
1.433 + }
1.434 + void setelem(Type *type) {
1.435 + singleByteOp(OP_SETELEM);
1.436 + }
1.437 +
1.438 + void getfield(unsigned index, Type *type) {
1.439 + ensure(OP_GETFIELD_LENGTH);
1.440 + writeOp(OP_GETFIELD);
1.441 + writeUint32(index);
1.442 +
1.443 + if (type->isTraceable())
1.444 + markOop(1);
1.445 + }
1.446 + void setfield(unsigned index, Type *type) {
1.447 + ensure(OP_SETFIELD_LENGTH);
1.448 + writeOp(OP_SETFIELD);
1.449 + writeUint32(index);
1.450 +
1.451 + if (type->isTraceable())
1.452 + markOop(1);
1.453 + }
1.454 +
1.455 +#if 0
1.456 + void getglobal(Variable *var) {
1.457 + ensure(OP_GETGLOBAL_F_LENGTH);
1.458 + if (var->type()->isPrimitive()) {
1.459 + switch (var->type()->primitive()) {
1.460 + case PrimitiveType_Float:
1.461 + writeOp(OP_GETGLOBAL_F);
1.462 + break;
1.463 + default:
1.464 + assert(var->type()->primitive() == PrimitiveType_Int32);
1.465 + writeOp(OP_GETGLOBAL_I);
1.466 + break;
1.467 + }
1.468 + } else {
1.469 + writeOp(OP_GETGLOBAL_O);
1.470 + markOop(1);
1.471 + }
1.472 + writeUint32(var->slot());
1.473 + }
1.474 + void setglobal(Variable *var) {
1.475 + ensure(OP_SETGLOBAL_F_LENGTH);
1.476 + if (var->type()->isPrimitive()) {
1.477 + switch (var->type()->primitive()) {
1.478 + case PrimitiveType_Float:
1.479 + writeOp(OP_SETGLOBAL_F);
1.480 + break;
1.481 + default:
1.482 + assert(var->type()->primitive() == PrimitiveType_Int32);
1.483 + writeOp(OP_SETGLOBAL_I);
1.484 + break;
1.485 + }
1.486 + } else {
1.487 + writeOp(OP_SETGLOBAL_O);
1.488 + }
1.489 + writeUint32(var->slot());
1.490 + }
1.491 +#endif
1.492 +
1.493 + void float_(float value) {
1.494 + ensure(OP_FLOAT_LENGTH);
1.495 + writeOp(OP_FLOAT);
1.496 + writeFloat(value);
1.497 + }
1.498 + void cvt_i2f() {
1.499 + singleByteOp(OP_CVT_I2F);
1.500 + }
1.501 + void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
1.502 + assert(op == OP_NEWFIXED ||
1.503 + op == OP_NEWEMPTY ||
1.504 + op == OP_NEWSIZED);
1.505 +
1.506 + recordOops();
1.507 + ensure(OpcodeInfo[op].length);
1.508 + writeOp(op);
1.509 + writeUint8(tenure);
1.510 + writeObject(map);
1.511 +
1.512 + if (op == OP_NEWSIZED)
1.513 + drop(map->type()->levels());
1.514 +
1.515 + markOop(1);
1.516 + }
1.517 + void newstruct(Handle<Map> map, Heap::Tenure tenure) {
1.518 + recordOops();
1.519 + ensure(OP_NEWSTRUCT_LENGTH);
1.520 + writeOp(OP_NEWSTRUCT);
1.521 + writeUint8(tenure);
1.522 + writeObject(map);
1.523 + markOop(1);
1.524 + }
1.525 + void savelifo(unsigned slot) {
1.526 + ensure(OP_SAVELIFO_LENGTH);
1.527 + writeOp(OP_SAVELIFO);
1.528 + writeUint32(slot);
1.529 + }
1.530 + void unwindlifo(unsigned slot) {
1.531 + ensure(OP_UNWINDLIFO_LENGTH);
1.532 + writeOp(OP_UNWINDLIFO);
1.533 + writeUint32(slot);
1.534 + }
1.535 +#if 0
1.536 + void newref(Variable *var) {
1.537 + recordOops();
1.538 + if (var->location() == Variable::STACK) {
1.539 + ensure(OP_VARREF_LIFO_LENGTH);
1.540 + writeOp(OP_VARREF_LIFO);
1.541 + } else {
1.542 + assert(var->location() == Variable::PARAMETER);
1.543 + ensure(OP_ARGREF_LIFO_LENGTH);
1.544 + writeOp(OP_ARGREF_LIFO);
1.545 + }
1.546 + writeUint32(var->slot());
1.547 + markOop(1);
1.548 + }
1.549 +#endif
1.550 +
1.551 + void slotref_lifo() {
1.552 + recordOops();
1.553 + singleByteOp(OP_SLOTREF_LIFO);
1.554 + markOop(1);
1.555 + }
1.556 + void getref(Type *type) {
1.557 + if (type->pod() == PrimitiveType_Int32) {
1.558 + singleByteOp(OP_GETREF_I);
1.559 + } else {
1.560 + assert(type->pod() == PrimitiveType_Float);
1.561 + singleByteOp(OP_GETREF_F);
1.562 + }
1.563 + }
1.564 + void setref(Type *type) {
1.565 + if (type->pod() == PrimitiveType_Int32) {
1.566 + singleByteOp(OP_SETREF_I);
1.567 + } else {
1.568 + assert(type->pod() == PrimitiveType_Float);
1.569 + singleByteOp(OP_SETREF_F);
1.570 + }
1.571 + }
1.572 + void object(Handle<Object> obj) {
1.573 + ensure(OP_OBJECT_LENGTH);
1.574 + writeOp(OP_OBJECT);
1.575 + writeObject(obj);
1.576 + markOop(1);
1.577 + }
1.578 + void copyarray() {
1.579 + singleByteOp(OP_COPYARRAY);
1.580 + markOop(1);
1.581 + }
1.582 + void copystruct() {
1.583 + singleByteOp(OP_COPYSTRUCT);
1.584 + markOop(1);
1.585 + }
1.586 + void sizeof_() {
1.587 + singleByteOp(OP_SIZEOF);
1.588 + }
1.589 +
1.590 + void dup() {
1.591 + bool oop = getOop(1);
1.592 + singleByteOp(OP_DUP);
1.593 + markOop(1, oop);
1.594 + }
1.595 + void dup2() {
1.596 + bool oop2 = getOop(2);
1.597 + bool oop1 = getOop(1);
1.598 +
1.599 + singleByteOp(OP_DUP2);
1.600 +
1.601 + markOop(2, oop2);
1.602 + markOop(1, oop1);
1.603 + }
1.604 + void swap() {
1.605 + bool oop2 = getOop(2);
1.606 + bool oop1 = getOop(1);
1.607 +
1.608 + singleByteOp(OP_SWAP);
1.609 +
1.610 + markOop(2, oop1);
1.611 + markOop(1, oop2);
1.612 + }
1.613 + void roll3() {
1.614 + bool oop3 = getOop(3);
1.615 + bool oop2 = getOop(2);
1.616 + bool oop1 = getOop(1);
1.617 +
1.618 + singleByteOp(OP_ROLL3);
1.619 +
1.620 + markOop(3, oop2);
1.621 + markOop(2, oop1);
1.622 + markOop(1, oop3);
1.623 + }
1.624 + void pick2() {
1.625 + bool oop2 = getOop(2);
1.626 + bool oop1 = getOop(1);
1.627 +
1.628 + singleByteOp(OP_PICK2);
1.629 +
1.630 + markOop(3, oop2);
1.631 + markOop(2, oop1);
1.632 + markOop(1, oop2);
1.633 + }
1.634 + void pick3() {
1.635 + bool oop3 = getOop(3);
1.636 + bool oop2 = getOop(2);
1.637 + bool oop1 = getOop(1);
1.638 +
1.639 + singleByteOp(OP_PICK3);
1.640 +
1.641 + markOop(4, oop3);
1.642 + markOop(3, oop2);
1.643 + markOop(2, oop1);
1.644 + markOop(1, oop3);
1.645 + }
1.646 +
1.647 + void returnvoid() {
1.648 + singleByteOp(OP_RETURNVOID);
1.649 + }
1.650 + void bitnot() {
1.651 + singleByteOp(OP_BITNOT);
1.652 + }
1.653 + void not_() {
1.654 + singleByteOp(OP_NOT);
1.655 + }
1.656 + void not_f() {
1.657 + singleByteOp(OP_NOT_F);
1.658 + }
1.659 + void neg() {
1.660 + singleByteOp(OP_NEG);
1.661 + }
1.662 + void neg_f() {
1.663 + singleByteOp(OP_NEG_F);
1.664 + }
1.665 + void bits_i2f() {
1.666 + singleByteOp(OP_BITS_I2F);
1.667 + }
1.668 + void bits_f2i() {
1.669 + singleByteOp(OP_BITS_F2I);
1.670 + }
1.671 + void true_() {
1.672 + singleByteOp(OP_TRUE);
1.673 + }
1.674 + void false_() {
1.675 + singleByteOp(OP_FALSE);
1.676 + }
1.677 +
1.678 + unsigned addString(Handle<String> name) {
1.679 + unsigned index;
1.680 + if (!strings_.add(name, &index)) {
1.681 + oom_ |= true;
1.682 + return 0;
1.683 + }
1.684 + return index;
1.685 + }
1.686 +
1.687 + void getglobal(Symbol *sym);
1.688 + void setglobal(Symbol *sym);
1.689 +
1.690 + void public_() {
1.691 + recordOops();
1.692 + singleByteOp(OP_PUBLIC);
1.693 + }
1.694 +
1.695 + void tableswitch(int low, int high, Label *def, Label **labels) {
1.696 + unsigned tablesize = TableSwitchEntries(low, high);
1.697 + assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
1.698 +
1.699 + ensure(OP_TABLESWITCH_LENGTH);
1.700 + writeOp(OP_TABLESWITCH);
1.701 + writeInt32(low);
1.702 + writeInt32(high);
1.703 + jump(def);
1.704 +
1.705 + // When labels are patched, we assume each position is a jump. Rather
1.706 + // than hack position offsets to make labels work without actual
1.707 + // incoming jumps, we emit a jump inline.
1.708 + for (unsigned i = 0; i < tablesize; i++)
1.709 + jump(labels[i]);
1.710 + }
1.711 +
1.712 + bool allocate(VariableSymbol *sym);
1.713 +
1.714 + Code *finish();
1.715 +
1.716 + // Helpers.
1.717 +#if 0
1.718 + void get(Variable *var) {
1.719 + if (var->location() == Variable::STACK) {
1.720 + getlocal(var);
1.721 + } else {
1.722 + assert(var->location() == Variable::PARAMETER);
1.723 + getarg(var);
1.724 + }
1.725 + }
1.726 + void set(Variable *var) {
1.727 + assert(!var->type()->isReference());
1.728 + if (var->location() == Variable::STACK) {
1.729 + setlocal(var);
1.730 + } else {
1.731 + assert(var->location() == Variable::PARAMETER);
1.732 + setarg(var);
1.733 + }
1.734 + }
1.735 +#endif
1.736 +};
1.737 +
1.738 +}
1.739 +
1.740 +#endif // _include_bytecode_emitter_h_