src/compiler/BytecodeEmitter.h
changeset 195 c1ba166f3fc4
parent 194 b029d63565a2
child 220 5df4a112967d
     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_