src/compiler/BytecodeEmitter.h
author David Anderson <dvander@alliedmods.net>
Fri Dec 28 17:13:51 2012 -0800 (2012-12-28)
changeset 247 7721042bdb67
parent 245 9371f058625a
child 256 3c184218462d
permissions -rw-r--r--
Implement dependent char arrays.
dvander@33
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@33
     2
 *
dvander@0
     3
 * Copyright (C) 2012 David Anderson
dvander@0
     4
 *
dvander@0
     5
 * This file is part of JITCraft.
dvander@0
     6
 *
dvander@0
     7
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@0
     8
 * the terms of the GNU General Public License as published by the Free
dvander@0
     9
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@0
    10
 * any later version.
dvander@0
    11
 * 
dvander@0
    12
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@0
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@0
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@0
    15
 *
dvander@0
    16
 * You should have received a copy of the GNU General Public License along with
dvander@0
    17
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@0
    18
 */
dvander@0
    19
#ifndef _include_bytecode_emitter_h_
dvander@0
    20
#define _include_bytecode_emitter_h_
dvander@0
    21
dvander@0
    22
#include <assert.h>
dvander@0
    23
#include <limits.h>
dvander@195
    24
#include "../Opcodes.h"
dvander@195
    25
#include "../Handles.h"
dvander@195
    26
#include "../CompactBuffer.h"
dvander@195
    27
#include "../Array.h"
dvander@195
    28
#include "../HashTable.h"
dvander@195
    29
#include "../VirtualObjectVisitor.h"
dvander@0
    30
dvander@59
    31
namespace ke {
dvander@0
    32
dvander@195
    33
// An overarching note on overflows: Though we should use CheckedInt, we rely
dvander@195
    34
// on a source-length cap covering all possible overflow checks. As long as
dvander@195
    35
// the source length is capped to INT_MAX, the number of AST nodes will be
dvander@195
    36
// strictly beneath that cap, and so to will most things generated by the
dvander@195
    37
// AST. For example, local and argument counts, number of functions, fields
dvander@195
    38
// in a struct, et cetera. Not everything can be covered by this cap: the
dvander@195
    39
// stack depth, number of bytecodes for example. In these cases we explicitly
dvander@195
    40
// test for overflow of INT_MAX and in other cases we assert.
dvander@195
    41
//
dvander@195
    42
// In the future, we should of course use a checked int wrapper.
dvander@195
    43
dvander@0
    44
class Type;
dvander@12
    45
class Map;
dvander@187
    46
class ArrayMap;
dvander@195
    47
class Symbol;
dvander@195
    48
class VariableSymbol;
dvander@0
    49
dvander@195
    50
struct OopRecord
dvander@47
    51
{
dvander@47
    52
    unsigned depth;
dvander@47
    53
    unsigned offset;
dvander@195
    54
    Vector<bool> slots;
dvander@47
    55
dvander@47
    56
    OopRecord(unsigned length, unsigned offset)
dvander@47
    57
      : depth(length),
dvander@195
    58
        offset(offset)
dvander@47
    59
    {
dvander@47
    60
    }
dvander@47
    61
};
dvander@47
    62
dvander@195
    63
class StringTable
dvander@195
    64
{
dvander@195
    65
    struct Entry
dvander@195
    66
    {
dvander@195
    67
        String *string;
dvander@195
    68
        unsigned index;
dvander@195
    69
dvander@195
    70
        Entry()
dvander@195
    71
          : string(NULL),
dvander@195
    72
            index(0)
dvander@195
    73
        {
dvander@195
    74
        }
dvander@195
    75
dvander@195
    76
        Entry(String *string, unsigned index)
dvander@195
    77
          : string(string),
dvander@195
    78
            index(index)
dvander@195
    79
        {
dvander@195
    80
        }
dvander@195
    81
    };
dvander@195
    82
dvander@195
    83
    struct Policy
dvander@195
    84
    {
dvander@195
    85
        typedef Entry Payload;
dvander@195
    86
dvander@195
    87
        static uint32 hash(String *string) {
dvander@195
    88
            return HashPointer(string);
dvander@195
    89
        }
dvander@195
    90
        
dvander@195
    91
        static bool matches(String *key, Entry &e) {
dvander@195
    92
            return key == e.string;
dvander@195
    93
        }
dvander@195
    94
    };
dvander@195
    95
dvander@195
    96
    typedef HashTable<Policy, ZoneAllocatorPolicy> Set;
dvander@195
    97
dvander@195
    98
  public:
dvander@195
    99
    StringTable();
dvander@195
   100
    bool initialize();
dvander@195
   101
    void accept(VirtualObjectVisitor *visitor);
dvander@195
   102
dvander@195
   103
    bool add(Handle<String> name, unsigned *indexp);
dvander@195
   104
    size_t stringCount() const {
dvander@195
   105
        return strings_.length();
dvander@195
   106
    }
dvander@195
   107
    String *stringAt(size_t i) const {
dvander@195
   108
        return strings_[i].string;
dvander@195
   109
    }
dvander@195
   110
dvander@195
   111
  private:
dvander@195
   112
    Set set_;
dvander@195
   113
    Vector<Entry> strings_;
dvander@195
   114
    bool initialized_;
dvander@195
   115
};
dvander@195
   116
dvander@195
   117
// The bytecode emitter assists in building Code objects, by emitting opcodes
dvander@195
   118
// and tracking stack information. Since the SemA creates temporary pool/root
dvander@195
   119
// scopes, we cannot use ScopedRoot or PoolObjects. Instead, BCE gets a
dvander@195
   120
// special marking function.
dvander@195
   121
class BytecodeEmitter : public AutoRooted
dvander@0
   122
{
dvander@47
   123
  private:
dvander@47
   124
    PoolAllocator &pool_;
dvander@47
   125
dvander@0
   126
    bytecode *buffer_;
dvander@0
   127
    bytecode *buffer_pos_;
dvander@0
   128
    bytecode *buffer_end_;
dvander@0
   129
    bytecode inline_buffer_[512];
dvander@0
   130
    bool oom_;
dvander@0
   131
    unsigned maxStackDepth_;
dvander@195
   132
    Vector<bool> oopMap_;
dvander@195
   133
    Vector<OopRecord *> oopRecords_;
dvander@70
   134
    CompactBufferWriter sourcemap_;
dvander@70
   135
    unsigned lastCodePosition_;
dvander@70
   136
    unsigned firstLine_;
dvander@195
   137
    StringTable strings_;
dvander@195
   138
    Vector<Symbol *> locals_;
dvander@195
   139
    Vector<Object *> objects_;
dvander@230
   140
    unsigned loopDepth_;
dvander@230
   141
    unsigned maxLoopDepth_;
dvander@0
   142
dvander@0
   143
  private:
dvander@47
   144
    // The maximum size of a code object must be such that the distance between
dvander@47
   145
    // two instructions fits into a signed, 31-bit integer. This ensures that
dvander@47
   146
    // all code-bounded buffers (like the number of object literals or
dvander@47
   147
    // safepoints) does not need to be bounds checked. It also means we can add
dvander@47
   148
    // any two offsets and be guaranteed that they don't overflow.
dvander@0
   149
    static const size_t MAX_LENGTH = INT_MAX / 2;
dvander@0
   150
dvander@0
   151
  private:
dvander@0
   152
    bool growBuffer(size_t bytes);
dvander@0
   153
dvander@0
   154
    // Checking the return value is not necessary, since the inline buffer is
dvander@0
   155
    // used as a ballast.
dvander@0
   156
    bool ensure(size_t bytes) {
dvander@0
   157
        if (buffer_pos_ + bytes > buffer_end_)
dvander@0
   158
            return growBuffer(bytes);
dvander@0
   159
        return true;
dvander@0
   160
    }
dvander@0
   161
dvander@0
   162
    void writeUint8(unsigned value) {
dvander@47
   163
        assert(value <= UCHAR_MAX);
dvander@0
   164
        *buffer_pos_++ = value;
dvander@0
   165
    }
dvander@4
   166
    void writeFloat(float value) {
dvander@4
   167
        *(float *)buffer_pos_ = value;
dvander@4
   168
        buffer_pos_ += sizeof(float);
dvander@4
   169
    }
dvander@0
   170
    void writeInt32(int value) {
dvander@0
   171
        *(int *)buffer_pos_ = value;
dvander@0
   172
        buffer_pos_ += sizeof(int);
dvander@0
   173
    }
dvander@0
   174
    void writeUint32(unsigned value) {
dvander@0
   175
        *(unsigned *)buffer_pos_ = value;
dvander@0
   176
        buffer_pos_ += sizeof(unsigned);
dvander@0
   177
    }
dvander@0
   178
    void writeOp(Opcode op) {
dvander@47
   179
        if (oom_)
dvander@47
   180
            return;
dvander@47
   181
dvander@0
   182
        writeUint8(op);
dvander@47
   183
        for (int i = 0; i < OpcodeInfo[op].nuses; i++)
dvander@58
   184
            oopMap_.pop();
dvander@47
   185
        for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
dvander@58
   186
            oopMap_.append(false);
dvander@58
   187
        if (oopMap_.length() > maxStackDepth_)
dvander@58
   188
            maxStackDepth_ = oopMap_.length();
dvander@0
   189
    }
dvander@21
   190
    void writeObject(Object *obj) {
dvander@234
   191
        assert(obj);
dvander@234
   192
dvander@58
   193
        writeUint32(objects_.length());
dvander@234
   194
        if (!objects_.append(obj))
dvander@70
   195
            oom_ = true;
dvander@12
   196
    }
dvander@0
   197
dvander@0
   198
    int position() const {
dvander@0
   199
        assert(buffer_pos_ - buffer_ < INT_MAX / 2);
dvander@0
   200
        return int(buffer_pos_ - buffer_);
dvander@0
   201
    }
dvander@0
   202
dvander@0
   203
  public:
dvander@47
   204
    BytecodeEmitter(PoolAllocator &pool);
dvander@195
   205
    ~BytecodeEmitter();
dvander@195
   206
dvander@195
   207
    void accept(VirtualObjectVisitor *visitor);
dvander@0
   208
dvander@0
   209
    bytecode *buffer() const {
dvander@0
   210
        return buffer_;
dvander@0
   211
    }
dvander@0
   212
    unsigned length() const {
dvander@0
   213
        return unsigned(buffer_pos_ - buffer_);
dvander@0
   214
    }
dvander@0
   215
    bool oom() const {
dvander@70
   216
        return oom_ || sourcemap_.oom();
dvander@0
   217
    }
dvander@0
   218
    unsigned stackDepth() const {
dvander@58
   219
        return oopMap_.length();
dvander@0
   220
    }
dvander@0
   221
    unsigned maxStackDepth() const {
dvander@0
   222
        return maxStackDepth_;
dvander@0
   223
    }
dvander@0
   224
dvander@46
   225
    void drop(unsigned amt) {
dvander@47
   226
        assert(amt <= stackDepth());
dvander@47
   227
        for (unsigned i = 0; i < amt; i++)
dvander@58
   228
            oopMap_.pop();
dvander@46
   229
    }
dvander@46
   230
dvander@70
   231
    void note_position(const SourcePosition &pos);
dvander@70
   232
    void setFirstLine(unsigned line) {
dvander@70
   233
        assert(!sourcemap_.length());
dvander@70
   234
        firstLine_ = line;
dvander@70
   235
    }
dvander@70
   236
dvander@0
   237
  public:
dvander@0
   238
    // A label represents a local control-flow target in the bytecode. A label
dvander@0
   239
    // may be in three states:
dvander@0
   240
    //
dvander@0
   241
    // (1) Empty - the label is not used yet.
dvander@0
   242
    // (2) Pending - the label has incoming jumps, but the actual location of
dvander@0
   243
    //               is not yet known. The list of jumps is threaded through
dvander@0
   244
    //               the four bytes reserved for each emitted jump target. In
dvander@0
   245
    //               this case, the offset field is the location of the most
dvander@0
   246
    //               recently emitted incoming jump.
dvander@0
   247
    // (3) Bound   - the label's position has been pinned.
dvander@0
   248
    //
dvander@0
   249
    // A jump can be emitted to a label in any state. Binding a label
dvander@0
   250
    // immediately backpatches all pending incoming jumps. A label must be
dvander@0
   251
    // bound if it is used.
dvander@0
   252
    class Label
dvander@0
   253
    {
dvander@0
   254
        int offset_ : 31;
dvander@0
   255
        bool bound_ : 1;
dvander@0
   256
dvander@0
   257
        void setOffset(int offset) {
dvander@0
   258
            offset_ = offset;
dvander@0
   259
            assert(offset_ == offset);
dvander@0
   260
        }
dvander@0
   261
dvander@0
   262
      public:
dvander@0
   263
        static const int INVALID_OFFSET = -1;
dvander@0
   264
dvander@0
   265
      public:
dvander@0
   266
        Label()
dvander@0
   267
          : offset_(INVALID_OFFSET),
dvander@0
   268
            bound_(false)
dvander@0
   269
        {
dvander@0
   270
        }
dvander@0
   271
        ~Label()
dvander@0
   272
        {
dvander@0
   273
            assert(bound_ || offset_ == INVALID_OFFSET);
dvander@0
   274
        }
dvander@0
   275
        
dvander@0
   276
        bool bound() const {
dvander@0
   277
            return bound_;
dvander@0
   278
        }
dvander@0
   279
        int offset() const {
dvander@0
   280
            return offset_;
dvander@0
   281
        }
dvander@0
   282
        void bind(int offset) {
dvander@0
   283
            assert(!bound_);
dvander@0
   284
            setOffset(offset);
dvander@0
   285
            bound_ = true;
dvander@0
   286
        }
dvander@0
   287
        int link(int offset) {
dvander@0
   288
            assert(!bound_);
dvander@0
   289
            int old = offset_;
dvander@0
   290
            setOffset(offset);
dvander@0
   291
            return old;
dvander@0
   292
        }
dvander@0
   293
    };
dvander@0
   294
dvander@0
   295
  private:
dvander@0
   296
    int patchJumpAt(int at, int to) {
dvander@0
   297
        assert(at >= 0 && at < position());
dvander@0
   298
        int old = *(int *)(buffer_ + at + 1);
dvander@0
   299
        *(int *)(buffer_ + at + 1) = (to - at);
dvander@0
   300
        return old;
dvander@0
   301
    }
dvander@0
   302
dvander@0
   303
    void singleByteOp(Opcode op) {
dvander@0
   304
        assert(OpcodeInfo[op].length == 1);
dvander@0
   305
        ensure(OpcodeInfo[op].length);
dvander@0
   306
        writeOp(op);
dvander@0
   307
    }
dvander@0
   308
dvander@47
   309
    // Mark a stack slot as having an object pointer.
dvander@47
   310
    void markOop(unsigned depth, bool oop = true) {
dvander@47
   311
        if (oom_)
dvander@47
   312
            return;
dvander@58
   313
        oopMap_[oopMap_.length() - depth] = oop;
dvander@47
   314
    }
dvander@47
   315
    bool getOop(unsigned depth) {
dvander@47
   316
        if (oom_)
dvander@47
   317
            return false;
dvander@58
   318
        return oopMap_[oopMap_.length() - depth];
dvander@47
   319
    }
dvander@47
   320
dvander@47
   321
    // Mark the current bytecode position as either re-entrant (meaning, it
dvander@47
   322
    // can leave the interpreter or call to another function), or causing GC.
dvander@47
   323
    // This will record which stack slots have objects and associate that
dvander@47
   324
    // information with the current pc.
dvander@47
   325
    void recordOops();
dvander@47
   326
dvander@0
   327
  public:
dvander@0
   328
    void int_(int value) {
dvander@0
   329
        ensure(OP_INT);
dvander@0
   330
        writeOp(OP_INT);
dvander@0
   331
        writeInt32(value);
dvander@0
   332
    }
dvander@0
   333
    void return_() {
dvander@0
   334
        ensure(OP_RETURN);
dvander@0
   335
        writeOp(OP_RETURN);
dvander@0
   336
    }
dvander@195
   337
    void getlocal(VariableSymbol *var);
dvander@195
   338
    void setlocal(VariableSymbol *var);
dvander@220
   339
    void getarg(VariableSymbol *var);
dvander@220
   340
    void setarg(VariableSymbol *var);
dvander@0
   341
dvander@0
   342
    void j(Opcode op, Label *label) {
dvander@0
   343
        // Since jumps can skip around the stream, do not try to do anything
dvander@0
   344
        // in a potentially truncated state.
dvander@0
   345
        if (oom())
dvander@0
   346
            return;
dvander@0
   347
dvander@230
   348
        assert(op == OP_JT || op == OP_JF || op == OP_JUMP ||
dvander@230
   349
               op == OP_CONTINUE || op == OP_BREAK);
dvander@0
   350
        ensure(OP_JUMP_LENGTH);
dvander@0
   351
dvander@0
   352
        if (label->bound()) {
dvander@0
   353
            // We can immediately emit this jump.
dvander@0
   354
            int distance = label->offset() - position();
dvander@0
   355
            writeOp(op);
dvander@0
   356
            writeInt32(distance);
dvander@0
   357
        } else {
dvander@0
   358
            // We can't emit this jump yet. Add a placeholder.
dvander@0
   359
            int old = label->link(position());
dvander@0
   360
            writeOp(op);
dvander@0
   361
            writeInt32(old);
dvander@0
   362
        }
dvander@0
   363
    }
dvander@0
   364
    void bind(Label *label) {
dvander@0
   365
        if (oom())
dvander@0
   366
            return;
dvander@0
   367
dvander@0
   368
        assert(!label->bound());
dvander@0
   369
dvander@0
   370
        int offset = label->offset();
dvander@0
   371
        while (offset != Label::INVALID_OFFSET)
dvander@0
   372
            offset = patchJumpAt(offset, position());
dvander@0
   373
dvander@0
   374
        label->bind(position());
dvander@0
   375
    }
dvander@0
   376
    void jump(Label *label) {
dvander@0
   377
        j(OP_JUMP, label);
dvander@0
   378
    }
dvander@0
   379
dvander@0
   380
    void binary(Opcode op) {
dvander@0
   381
        singleByteOp(op);
dvander@0
   382
    }
dvander@195
   383
    void unary(Opcode op) {
dvander@195
   384
        singleByteOp(op);
dvander@195
   385
    }
dvander@0
   386
dvander@0
   387
    void pop() {
dvander@0
   388
        singleByteOp(OP_POP);
dvander@0
   389
    }
dvander@0
   390
    void stop() {
dvander@0
   391
        singleByteOp(OP_STOP);
dvander@0
   392
    }
dvander@195
   393
    void call(Handle<FunctionType> fun, unsigned argc) {
dvander@47
   394
        recordOops();
dvander@72
   395
dvander@195
   396
        if (fun->isNative()) {
dvander@195
   397
            ensure(OP_CALLNATIVE_LENGTH);
dvander@195
   398
            writeOp(OP_CALLNATIVE);
dvander@195
   399
            writeUint32(argc);
dvander@195
   400
            drop(argc + 1);
dvander@195
   401
        } else {
dvander@195
   402
            ensure(OP_CALL_LENGTH);
dvander@195
   403
            writeOp(OP_CALL);
dvander@195
   404
            drop(argc + 1);
dvander@195
   405
dvander@195
   406
            if (fun->returnType()->isVoid())
dvander@195
   407
                drop(1);
dvander@195
   408
            else if (fun->returnType()->isTraceable())
dvander@195
   409
                markOop(1);
dvander@195
   410
        }
dvander@68
   411
    }
dvander@85
   412
dvander@157
   413
    void getelem(Type *type) {
dvander@157
   414
        singleByteOp(OP_GETELEM);
dvander@154
   415
dvander@157
   416
        if (type->isTraceable())
dvander@157
   417
            markOop(1);
dvander@0
   418
    }
dvander@157
   419
    void setelem(Type *type) {
dvander@157
   420
        singleByteOp(OP_SETELEM);
dvander@7
   421
    }
dvander@85
   422
dvander@147
   423
    void getfield(unsigned index, Type *type) {
dvander@147
   424
        ensure(OP_GETFIELD_LENGTH);
dvander@147
   425
        writeOp(OP_GETFIELD);
dvander@147
   426
        writeUint32(index);
dvander@147
   427
dvander@147
   428
        if (type->isTraceable())
dvander@147
   429
            markOop(1);
dvander@147
   430
    }
dvander@147
   431
    void setfield(unsigned index, Type *type) {
dvander@147
   432
        ensure(OP_SETFIELD_LENGTH);
dvander@147
   433
        writeOp(OP_SETFIELD);
dvander@147
   434
        writeUint32(index);
dvander@147
   435
dvander@147
   436
        if (type->isTraceable())
dvander@147
   437
            markOop(1);
dvander@147
   438
    }
dvander@147
   439
dvander@230
   440
    int enterloop() {
dvander@230
   441
        int offset = position();
dvander@230
   442
dvander@230
   443
        ensure(OP_ENTERLOOP);
dvander@230
   444
        writeOp(OP_ENTERLOOP);
dvander@230
   445
        writeUint8(0);
dvander@230
   446
dvander@230
   447
        loopDepth_++;
dvander@230
   448
        if (loopDepth_ > maxLoopDepth_)
dvander@230
   449
            maxLoopDepth_ = loopDepth_;
dvander@230
   450
dvander@230
   451
        return offset;
dvander@85
   452
    }
dvander@230
   453
    void leaveloop() {
dvander@230
   454
        singleByteOp(OP_LEAVELOOP);
dvander@230
   455
dvander@230
   456
        assert(loopDepth_);
dvander@230
   457
        loopDepth_--;
dvander@85
   458
    }
dvander@230
   459
    void setLoopUsesLifoStack(int pos) {
dvander@230
   460
        assert(pos >= 0 && pos < position());
dvander@230
   461
        assert(*(buffer() + pos) == OP_ENTERLOOP);
dvander@230
   462
        *(buffer() + pos + 1) = 1;
dvander@230
   463
    }
dvander@85
   464
dvander@4
   465
    void float_(float value) {
dvander@4
   466
        ensure(OP_FLOAT_LENGTH);
dvander@4
   467
        writeOp(OP_FLOAT);
dvander@4
   468
        writeFloat(value);
dvander@4
   469
    }
dvander@4
   470
    void cvt_i2f() {
dvander@4
   471
        singleByteOp(OP_CVT_I2F);
dvander@4
   472
    }
dvander@187
   473
    void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
dvander@185
   474
        assert(op == OP_NEWFIXED ||
dvander@185
   475
               op == OP_NEWEMPTY ||
dvander@185
   476
               op == OP_NEWSIZED);
dvander@185
   477
dvander@47
   478
        recordOops();
dvander@185
   479
        ensure(OpcodeInfo[op].length);
dvander@185
   480
        writeOp(op);
dvander@85
   481
        writeUint8(tenure);
dvander@21
   482
        writeObject(map);
dvander@187
   483
dvander@187
   484
        if (op == OP_NEWSIZED)
dvander@187
   485
            drop(map->type()->levels());
dvander@187
   486
dvander@47
   487
        markOop(1);
dvander@12
   488
    }
dvander@147
   489
    void newstruct(Handle<Map> map, Heap::Tenure tenure) {
dvander@147
   490
        recordOops();
dvander@147
   491
        ensure(OP_NEWSTRUCT_LENGTH);
dvander@147
   492
        writeOp(OP_NEWSTRUCT);
dvander@147
   493
        writeUint8(tenure);
dvander@147
   494
        writeObject(map);
dvander@147
   495
        markOop(1);
dvander@147
   496
    }
dvander@247
   497
    void deparray(ArrayMap *map) {
dvander@247
   498
        recordOops();
dvander@247
   499
        ensure(OP_DEPARRAY_LENGTH);
dvander@247
   500
        writeOp(OP_DEPARRAY);
dvander@247
   501
        writeObject(map);
dvander@247
   502
        markOop(1);
dvander@247
   503
    }
dvander@12
   504
    void savelifo(unsigned slot) {
dvander@12
   505
        ensure(OP_SAVELIFO_LENGTH);
dvander@12
   506
        writeOp(OP_SAVELIFO);
dvander@12
   507
        writeUint32(slot);
dvander@12
   508
    }
dvander@12
   509
    void unwindlifo(unsigned slot) {
dvander@12
   510
        ensure(OP_UNWINDLIFO_LENGTH);
dvander@12
   511
        writeOp(OP_UNWINDLIFO);
dvander@12
   512
        writeUint32(slot);
dvander@12
   513
    }
dvander@222
   514
dvander@222
   515
    void newref(VariableSymbol *var);
dvander@47
   516
dvander@14
   517
    void slotref_lifo() {
dvander@47
   518
        recordOops();
dvander@14
   519
        singleByteOp(OP_SLOTREF_LIFO);
dvander@47
   520
        markOop(1);
dvander@14
   521
    }
dvander@145
   522
    void getref(Type *type) {
dvander@145
   523
        if (type->pod() == PrimitiveType_Int32) {
dvander@22
   524
            singleByteOp(OP_GETREF_I);
dvander@22
   525
        } else {
dvander@145
   526
            assert(type->pod() == PrimitiveType_Float);
dvander@22
   527
            singleByteOp(OP_GETREF_F);
dvander@22
   528
        }
dvander@14
   529
    }
dvander@145
   530
    void setref(Type *type) {
dvander@145
   531
        if (type->pod() == PrimitiveType_Int32) {
dvander@22
   532
            singleByteOp(OP_SETREF_I);
dvander@22
   533
        } else {
dvander@145
   534
            assert(type->pod() == PrimitiveType_Float);
dvander@22
   535
            singleByteOp(OP_SETREF_F);
dvander@22
   536
        }
dvander@14
   537
    }
dvander@33
   538
    void object(Handle<Object> obj) {
dvander@234
   539
        assert(obj);
dvander@234
   540
dvander@21
   541
        ensure(OP_OBJECT_LENGTH);
dvander@21
   542
        writeOp(OP_OBJECT);
dvander@21
   543
        writeObject(obj);
dvander@47
   544
        markOop(1);
dvander@21
   545
    }
dvander@234
   546
    void duparray() {
dvander@234
   547
        singleByteOp(OP_DUPARRAY);
dvander@234
   548
        markOop(1);
dvander@234
   549
    }
dvander@152
   550
    void copyarray() {
dvander@152
   551
        singleByteOp(OP_COPYARRAY);
dvander@152
   552
        markOop(1);
dvander@152
   553
    }
dvander@152
   554
    void copystruct() {
dvander@152
   555
        singleByteOp(OP_COPYSTRUCT);
dvander@47
   556
        markOop(1);
dvander@21
   557
    }
dvander@194
   558
    void sizeof_() {
dvander@194
   559
        singleByteOp(OP_SIZEOF);
dvander@194
   560
    }
dvander@47
   561
dvander@22
   562
    void dup() {
dvander@47
   563
        bool oop = getOop(1);
dvander@22
   564
        singleByteOp(OP_DUP);
dvander@47
   565
        markOop(1, oop);
dvander@22
   566
    }
dvander@22
   567
    void dup2() {
dvander@47
   568
        bool oop2 = getOop(2);
dvander@47
   569
        bool oop1 = getOop(1);
dvander@47
   570
dvander@22
   571
        singleByteOp(OP_DUP2);
dvander@47
   572
dvander@47
   573
        markOop(2, oop2);
dvander@47
   574
        markOop(1, oop1);
dvander@22
   575
    }
dvander@23
   576
    void swap() {
dvander@47
   577
        bool oop2 = getOop(2);
dvander@47
   578
        bool oop1 = getOop(1);
dvander@47
   579
dvander@23
   580
        singleByteOp(OP_SWAP);
dvander@47
   581
dvander@47
   582
        markOop(2, oop1);
dvander@47
   583
        markOop(1, oop2);
dvander@23
   584
    }
dvander@23
   585
    void roll3() {
dvander@47
   586
        bool oop3 = getOop(3);
dvander@47
   587
        bool oop2 = getOop(2);
dvander@47
   588
        bool oop1 = getOop(1);
dvander@47
   589
dvander@23
   590
        singleByteOp(OP_ROLL3);
dvander@47
   591
dvander@47
   592
        markOop(3, oop2);
dvander@47
   593
        markOop(2, oop1);
dvander@47
   594
        markOop(1, oop3);
dvander@23
   595
    }
dvander@23
   596
    void pick2() {
dvander@47
   597
        bool oop2 = getOop(2);
dvander@47
   598
        bool oop1 = getOop(1);
dvander@47
   599
dvander@23
   600
        singleByteOp(OP_PICK2);
dvander@47
   601
dvander@47
   602
        markOop(3, oop2);
dvander@47
   603
        markOop(2, oop1);
dvander@47
   604
        markOop(1, oop2);
dvander@23
   605
    }
dvander@23
   606
    void pick3() {
dvander@47
   607
        bool oop3 = getOop(3);
dvander@47
   608
        bool oop2 = getOop(2);
dvander@47
   609
        bool oop1 = getOop(1);
dvander@47
   610
dvander@23
   611
        singleByteOp(OP_PICK3);
dvander@47
   612
dvander@47
   613
        markOop(4, oop3);
dvander@47
   614
        markOop(3, oop2);
dvander@47
   615
        markOop(2, oop1);
dvander@47
   616
        markOop(1, oop3);
dvander@47
   617
    }
dvander@47
   618
dvander@72
   619
    void returnvoid() {
dvander@72
   620
        singleByteOp(OP_RETURNVOID);
dvander@72
   621
    }
dvander@78
   622
    void bitnot() {
dvander@78
   623
        singleByteOp(OP_BITNOT);
dvander@78
   624
    }
dvander@79
   625
    void not_() {
dvander@79
   626
        singleByteOp(OP_NOT);
dvander@79
   627
    }
dvander@79
   628
    void not_f() {
dvander@79
   629
        singleByteOp(OP_NOT_F);
dvander@79
   630
    }
dvander@80
   631
    void neg() {
dvander@80
   632
        singleByteOp(OP_NEG);
dvander@80
   633
    }
dvander@80
   634
    void neg_f() {
dvander@80
   635
        singleByteOp(OP_NEG_F);
dvander@80
   636
    }
dvander@143
   637
    void true_() {
dvander@143
   638
        singleByteOp(OP_TRUE);
dvander@143
   639
    }
dvander@143
   640
    void false_() {
dvander@143
   641
        singleByteOp(OP_FALSE);
dvander@143
   642
    }
dvander@195
   643
    
dvander@195
   644
    unsigned addString(Handle<String> name) {
dvander@195
   645
        unsigned index;
dvander@195
   646
        if (!strings_.add(name, &index)) {
dvander@195
   647
            oom_ |= true;
dvander@195
   648
            return 0;
dvander@195
   649
        }
dvander@195
   650
        return index;
dvander@195
   651
    }
dvander@195
   652
dvander@195
   653
    void getglobal(Symbol *sym);
dvander@195
   654
    void setglobal(Symbol *sym);
dvander@195
   655
dvander@195
   656
    void public_() {
dvander@195
   657
        recordOops();
dvander@195
   658
        singleByteOp(OP_PUBLIC);
dvander@195
   659
    }
dvander@72
   660
dvander@245
   661
    void bitcast(Type *type) {
dvander@245
   662
        ensure(OP_BITCAST_LENGTH);
dvander@245
   663
        writeOp(OP_BITCAST);
dvander@245
   664
        writeObject(type);
dvander@245
   665
    }
dvander@245
   666
dvander@172
   667
    void tableswitch(int low, int high, Label *def, Label **labels) {
dvander@172
   668
        unsigned tablesize = TableSwitchEntries(low, high);
dvander@172
   669
        assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
dvander@172
   670
dvander@172
   671
        ensure(OP_TABLESWITCH_LENGTH);
dvander@172
   672
        writeOp(OP_TABLESWITCH);
dvander@172
   673
        writeInt32(low);
dvander@172
   674
        writeInt32(high);
dvander@172
   675
        jump(def);
dvander@172
   676
dvander@172
   677
        // When labels are patched, we assume each position is a jump. Rather
dvander@172
   678
        // than hack position offsets to make labels work without actual
dvander@172
   679
        // incoming jumps, we emit a jump inline.
dvander@172
   680
        for (unsigned i = 0; i < tablesize; i++)
dvander@172
   681
            jump(labels[i]);
dvander@172
   682
    }
dvander@172
   683
dvander@195
   684
    bool allocate(VariableSymbol *sym);
dvander@195
   685
dvander@195
   686
    Code *finish();
dvander@195
   687
dvander@47
   688
    // Helpers.
dvander@195
   689
#if 0
dvander@47
   690
    void get(Variable *var) {
dvander@47
   691
        if (var->location() == Variable::STACK) {
dvander@47
   692
            getlocal(var);
dvander@47
   693
        } else {
dvander@47
   694
            assert(var->location() == Variable::PARAMETER);
dvander@47
   695
            getarg(var);
dvander@47
   696
        }
dvander@47
   697
    }
dvander@47
   698
    void set(Variable *var) {
dvander@47
   699
        assert(!var->type()->isReference());
dvander@47
   700
        if (var->location() == Variable::STACK) {
dvander@47
   701
            setlocal(var);
dvander@47
   702
        } else {
dvander@47
   703
            assert(var->location() == Variable::PARAMETER);
dvander@47
   704
            setarg(var);
dvander@47
   705
        }
dvander@23
   706
    }
dvander@195
   707
#endif
dvander@0
   708
};
dvander@0
   709
dvander@0
   710
}
dvander@0
   711
dvander@0
   712
#endif // _include_bytecode_emitter_h_