src/BytecodeEmitter.h
author David Anderson <dvander@alliedmods.net>
Sat Sep 15 18:25:54 2012 -0700 (2012-09-15)
changeset 185 10936f3a2ba3
parent 184 387d76b1e981
child 187 9308d52205a0
permissions -rw-r--r--
Added support for declaring empty-length 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@0
    24
#include "Opcodes.h"
dvander@14
    25
#include "NameBinding.h"
dvander@33
    26
#include "Handles.h"
dvander@70
    27
#include "CompactBuffer.h"
dvander@0
    28
dvander@59
    29
namespace ke {
dvander@0
    30
dvander@0
    31
class Type;
dvander@12
    32
class Map;
dvander@0
    33
danderson@91
    34
typedef PoolList<ScopedRoot<Object> > ObjectList;
dvander@33
    35
dvander@47
    36
struct OopRecord : public PoolObject
dvander@47
    37
{
dvander@47
    38
    unsigned depth;
dvander@47
    39
    unsigned offset;
dvander@47
    40
    bool *slots;
dvander@47
    41
dvander@47
    42
    OopRecord(unsigned length, unsigned offset)
dvander@47
    43
      : depth(length),
dvander@47
    44
        offset(offset),
dvander@47
    45
        slots(NULL)
dvander@47
    46
    {
dvander@47
    47
    }
dvander@47
    48
};
dvander@47
    49
dvander@0
    50
class BytecodeEmitter
dvander@0
    51
{
dvander@47
    52
  private:
dvander@47
    53
    PoolAllocator &pool_;
dvander@47
    54
dvander@0
    55
    bytecode *buffer_;
dvander@0
    56
    bytecode *buffer_pos_;
dvander@0
    57
    bytecode *buffer_end_;
dvander@0
    58
    bytecode inline_buffer_[512];
dvander@0
    59
    bool oom_;
dvander@0
    60
    unsigned maxStackDepth_;
dvander@33
    61
    ObjectList objects_;
dvander@58
    62
    PoolList<bool> oopMap_;
dvander@58
    63
    PoolList<OopRecord *> oopRecords_;
dvander@70
    64
    CompactBufferWriter sourcemap_;
dvander@70
    65
    unsigned lastCodePosition_;
dvander@70
    66
    unsigned firstLine_;
dvander@0
    67
dvander@0
    68
  private:
dvander@47
    69
    // The maximum size of a code object must be such that the distance between
dvander@47
    70
    // two instructions fits into a signed, 31-bit integer. This ensures that
dvander@47
    71
    // all code-bounded buffers (like the number of object literals or
dvander@47
    72
    // safepoints) does not need to be bounds checked. It also means we can add
dvander@47
    73
    // any two offsets and be guaranteed that they don't overflow.
dvander@0
    74
    static const size_t MAX_LENGTH = INT_MAX / 2;
dvander@0
    75
dvander@0
    76
  private:
dvander@0
    77
    bool growBuffer(size_t bytes);
dvander@0
    78
dvander@0
    79
    // Checking the return value is not necessary, since the inline buffer is
dvander@0
    80
    // used as a ballast.
dvander@0
    81
    bool ensure(size_t bytes) {
dvander@0
    82
        if (buffer_pos_ + bytes > buffer_end_)
dvander@0
    83
            return growBuffer(bytes);
dvander@0
    84
        return true;
dvander@0
    85
    }
dvander@0
    86
dvander@0
    87
    void writeUint8(unsigned value) {
dvander@47
    88
        assert(value <= UCHAR_MAX);
dvander@0
    89
        *buffer_pos_++ = value;
dvander@0
    90
    }
dvander@4
    91
    void writeFloat(float value) {
dvander@4
    92
        *(float *)buffer_pos_ = value;
dvander@4
    93
        buffer_pos_ += sizeof(float);
dvander@4
    94
    }
dvander@0
    95
    void writeInt32(int value) {
dvander@0
    96
        *(int *)buffer_pos_ = value;
dvander@0
    97
        buffer_pos_ += sizeof(int);
dvander@0
    98
    }
dvander@0
    99
    void writeUint32(unsigned value) {
dvander@0
   100
        *(unsigned *)buffer_pos_ = value;
dvander@0
   101
        buffer_pos_ += sizeof(unsigned);
dvander@0
   102
    }
dvander@0
   103
    void writeOp(Opcode op) {
dvander@47
   104
        if (oom_)
dvander@47
   105
            return;
dvander@47
   106
dvander@0
   107
        writeUint8(op);
dvander@47
   108
        for (int i = 0; i < OpcodeInfo[op].nuses; i++)
dvander@58
   109
            oopMap_.pop();
dvander@47
   110
        for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
dvander@58
   111
            oopMap_.append(false);
dvander@58
   112
        if (oopMap_.length() > maxStackDepth_)
dvander@58
   113
            maxStackDepth_ = oopMap_.length();
dvander@0
   114
    }
dvander@21
   115
    void writeObject(Object *obj) {
dvander@58
   116
        writeUint32(objects_.length());
dvander@64
   117
        ScopedRoot<Object> root(obj);
dvander@70
   118
        if (!objects_.append(root))
dvander@70
   119
            oom_ = true;
dvander@12
   120
    }
dvander@0
   121
dvander@0
   122
    int position() const {
dvander@0
   123
        assert(buffer_pos_ - buffer_ < INT_MAX / 2);
dvander@0
   124
        return int(buffer_pos_ - buffer_);
dvander@0
   125
    }
dvander@0
   126
dvander@0
   127
  public:
dvander@47
   128
    BytecodeEmitter(PoolAllocator &pool);
dvander@0
   129
dvander@0
   130
    bytecode *buffer() const {
dvander@0
   131
        return buffer_;
dvander@0
   132
    }
dvander@0
   133
    unsigned length() const {
dvander@0
   134
        return unsigned(buffer_pos_ - buffer_);
dvander@0
   135
    }
dvander@0
   136
    bool oom() const {
dvander@70
   137
        return oom_ || sourcemap_.oom();
dvander@0
   138
    }
dvander@0
   139
    unsigned stackDepth() const {
dvander@58
   140
        return oopMap_.length();
dvander@0
   141
    }
dvander@0
   142
    unsigned maxStackDepth() const {
dvander@0
   143
        return maxStackDepth_;
dvander@0
   144
    }
dvander@33
   145
    const ObjectList *objects() const {
dvander@21
   146
        return &objects_;
dvander@12
   147
    }
dvander@58
   148
    PoolList<OopRecord *> *oopRecords() {
dvander@47
   149
        return &oopRecords_;
dvander@47
   150
    }
dvander@0
   151
dvander@46
   152
    void drop(unsigned amt) {
dvander@47
   153
        assert(amt <= stackDepth());
dvander@47
   154
        for (unsigned i = 0; i < amt; i++)
dvander@58
   155
            oopMap_.pop();
dvander@46
   156
    }
dvander@46
   157
dvander@70
   158
    void note_position(const SourcePosition &pos);
dvander@70
   159
    uint8 *sourcemap() const {
dvander@70
   160
        return sourcemap_.buffer();
dvander@70
   161
    }
dvander@70
   162
    size_t sourcemapLength() const {
dvander@70
   163
        return sourcemap_.length();
dvander@70
   164
    }
dvander@70
   165
    void setFirstLine(unsigned line) {
dvander@70
   166
        assert(!sourcemap_.length());
dvander@70
   167
        firstLine_ = line;
dvander@70
   168
    }
dvander@70
   169
dvander@0
   170
  public:
dvander@0
   171
    // A label represents a local control-flow target in the bytecode. A label
dvander@0
   172
    // may be in three states:
dvander@0
   173
    //
dvander@0
   174
    // (1) Empty - the label is not used yet.
dvander@0
   175
    // (2) Pending - the label has incoming jumps, but the actual location of
dvander@0
   176
    //               is not yet known. The list of jumps is threaded through
dvander@0
   177
    //               the four bytes reserved for each emitted jump target. In
dvander@0
   178
    //               this case, the offset field is the location of the most
dvander@0
   179
    //               recently emitted incoming jump.
dvander@0
   180
    // (3) Bound   - the label's position has been pinned.
dvander@0
   181
    //
dvander@0
   182
    // A jump can be emitted to a label in any state. Binding a label
dvander@0
   183
    // immediately backpatches all pending incoming jumps. A label must be
dvander@0
   184
    // bound if it is used.
dvander@0
   185
    class Label
dvander@0
   186
    {
dvander@0
   187
        int offset_ : 31;
dvander@0
   188
        bool bound_ : 1;
dvander@0
   189
dvander@0
   190
        void setOffset(int offset) {
dvander@0
   191
            offset_ = offset;
dvander@0
   192
            assert(offset_ == offset);
dvander@0
   193
        }
dvander@0
   194
dvander@0
   195
      public:
dvander@0
   196
        static const int INVALID_OFFSET = -1;
dvander@0
   197
dvander@0
   198
      public:
dvander@0
   199
        Label()
dvander@0
   200
          : offset_(INVALID_OFFSET),
dvander@0
   201
            bound_(false)
dvander@0
   202
        {
dvander@0
   203
        }
dvander@0
   204
        ~Label()
dvander@0
   205
        {
dvander@0
   206
            assert(bound_ || offset_ == INVALID_OFFSET);
dvander@0
   207
        }
dvander@0
   208
        
dvander@0
   209
        bool bound() const {
dvander@0
   210
            return bound_;
dvander@0
   211
        }
dvander@0
   212
        int offset() const {
dvander@0
   213
            return offset_;
dvander@0
   214
        }
dvander@0
   215
        void bind(int offset) {
dvander@0
   216
            assert(!bound_);
dvander@0
   217
            setOffset(offset);
dvander@0
   218
            bound_ = true;
dvander@0
   219
        }
dvander@0
   220
        int link(int offset) {
dvander@0
   221
            assert(!bound_);
dvander@0
   222
            int old = offset_;
dvander@0
   223
            setOffset(offset);
dvander@0
   224
            return old;
dvander@0
   225
        }
dvander@0
   226
    };
dvander@0
   227
dvander@0
   228
  private:
dvander@0
   229
    int patchJumpAt(int at, int to) {
dvander@0
   230
        assert(at >= 0 && at < position());
dvander@0
   231
        int old = *(int *)(buffer_ + at + 1);
dvander@0
   232
        *(int *)(buffer_ + at + 1) = (to - at);
dvander@0
   233
        return old;
dvander@0
   234
    }
dvander@0
   235
dvander@0
   236
    void singleByteOp(Opcode op) {
dvander@0
   237
        assert(OpcodeInfo[op].length == 1);
dvander@0
   238
        ensure(OpcodeInfo[op].length);
dvander@0
   239
        writeOp(op);
dvander@0
   240
    }
dvander@0
   241
dvander@47
   242
    // Mark a stack slot as having an object pointer.
dvander@47
   243
    void markOop(unsigned depth, bool oop = true) {
dvander@47
   244
        if (oom_)
dvander@47
   245
            return;
dvander@58
   246
        oopMap_[oopMap_.length() - depth] = oop;
dvander@47
   247
    }
dvander@47
   248
    bool getOop(unsigned depth) {
dvander@47
   249
        if (oom_)
dvander@47
   250
            return false;
dvander@58
   251
        return oopMap_[oopMap_.length() - depth];
dvander@47
   252
    }
dvander@47
   253
dvander@47
   254
    // Mark the current bytecode position as either re-entrant (meaning, it
dvander@47
   255
    // can leave the interpreter or call to another function), or causing GC.
dvander@47
   256
    // This will record which stack slots have objects and associate that
dvander@47
   257
    // information with the current pc.
dvander@47
   258
    void recordOops();
dvander@47
   259
dvander@0
   260
  public:
dvander@0
   261
    void int_(int value) {
dvander@0
   262
        ensure(OP_INT);
dvander@0
   263
        writeOp(OP_INT);
dvander@0
   264
        writeInt32(value);
dvander@0
   265
    }
dvander@0
   266
    void return_() {
dvander@0
   267
        ensure(OP_RETURN);
dvander@0
   268
        writeOp(OP_RETURN);
dvander@0
   269
    }
dvander@47
   270
    void getlocal(Variable *var) {
dvander@0
   271
        ensure(OP_GETLOCAL_LENGTH);
dvander@0
   272
        writeOp(OP_GETLOCAL);
dvander@47
   273
        writeUint32(var->slot());
dvander@47
   274
dvander@47
   275
        if (var->type()->isTraceable())
dvander@47
   276
            markOop(1);
dvander@0
   277
    }
dvander@47
   278
    void setlocal(Variable *var) {
dvander@0
   279
        ensure(OP_SETLOCAL_LENGTH);
dvander@0
   280
        writeOp(OP_SETLOCAL);
dvander@47
   281
        writeUint32(var->slot());
dvander@47
   282
dvander@47
   283
        if (var->type()->isTraceable())
dvander@47
   284
            markOop(1);
dvander@0
   285
    }
dvander@47
   286
    void getarg(Variable *var) {
dvander@0
   287
        ensure(OP_GETARG_LENGTH);
dvander@0
   288
        writeOp(OP_GETARG);
dvander@47
   289
        writeUint32(var->slot());
dvander@47
   290
dvander@47
   291
        if (var->type()->isTraceable())
dvander@47
   292
            markOop(1);
dvander@0
   293
    }
dvander@47
   294
    void setarg(Variable *var) {
dvander@0
   295
        ensure(OP_SETARG_LENGTH);
dvander@0
   296
        writeOp(OP_SETARG);
dvander@47
   297
        writeUint32(var->slot());
dvander@47
   298
dvander@47
   299
        if (var->type()->isTraceable())
dvander@47
   300
            markOop(1);
dvander@0
   301
    }
dvander@0
   302
dvander@0
   303
    void j(Opcode op, Label *label) {
dvander@0
   304
        // Since jumps can skip around the stream, do not try to do anything
dvander@0
   305
        // in a potentially truncated state.
dvander@0
   306
        if (oom())
dvander@0
   307
            return;
dvander@0
   308
dvander@0
   309
        assert(op >= OP_JL && op <= OP_JUMP);
dvander@0
   310
        ensure(OP_JUMP_LENGTH);
dvander@0
   311
dvander@0
   312
        if (label->bound()) {
dvander@0
   313
            // We can immediately emit this jump.
dvander@0
   314
            int distance = label->offset() - position();
dvander@0
   315
            writeOp(op);
dvander@0
   316
            writeInt32(distance);
dvander@0
   317
        } else {
dvander@0
   318
            // We can't emit this jump yet. Add a placeholder.
dvander@0
   319
            int old = label->link(position());
dvander@0
   320
            writeOp(op);
dvander@0
   321
            writeInt32(old);
dvander@0
   322
        }
dvander@0
   323
    }
dvander@0
   324
    void bind(Label *label) {
dvander@0
   325
        if (oom())
dvander@0
   326
            return;
dvander@0
   327
dvander@0
   328
        assert(!label->bound());
dvander@0
   329
dvander@0
   330
        int offset = label->offset();
dvander@0
   331
        while (offset != Label::INVALID_OFFSET)
dvander@0
   332
            offset = patchJumpAt(offset, position());
dvander@0
   333
dvander@0
   334
        label->bind(position());
dvander@0
   335
    }
dvander@0
   336
    void jump(Label *label) {
dvander@0
   337
        j(OP_JUMP, label);
dvander@0
   338
    }
dvander@0
   339
dvander@0
   340
    void binary(Opcode op) {
dvander@0
   341
        singleByteOp(op);
dvander@0
   342
    }
dvander@0
   343
dvander@0
   344
    void pop() {
dvander@0
   345
        singleByteOp(OP_POP);
dvander@0
   346
    }
dvander@0
   347
    void stop() {
dvander@0
   348
        singleByteOp(OP_STOP);
dvander@0
   349
    }
dvander@73
   350
    void call(Handle<Type> fun) {
dvander@47
   351
        recordOops();
dvander@73
   352
        ensure(OP_CALL_LENGTH);
dvander@73
   353
        writeOp(OP_CALL);
dvander@72
   354
dvander@72
   355
        if (fun->returnType()->isVoid())
dvander@72
   356
            drop(1);
dvander@72
   357
        else if (fun->returnType()->isTraceable())
dvander@72
   358
            markOop(1);
dvander@0
   359
    }
dvander@68
   360
    void callnative(unsigned index, unsigned argc) {
dvander@68
   361
        recordOops();
dvander@68
   362
        ensure(OP_CALLNATIVE_LENGTH);
dvander@68
   363
        writeOp(OP_CALLNATIVE);
dvander@68
   364
        writeUint32(index);
dvander@68
   365
        writeUint32(argc);
dvander@68
   366
    }
dvander@85
   367
dvander@157
   368
    void getelem(Type *type) {
dvander@157
   369
        singleByteOp(OP_GETELEM);
dvander@154
   370
dvander@157
   371
        if (type->isTraceable())
dvander@157
   372
            markOop(1);
dvander@0
   373
    }
dvander@157
   374
    void setelem(Type *type) {
dvander@157
   375
        singleByteOp(OP_SETELEM);
dvander@7
   376
    }
dvander@85
   377
dvander@147
   378
    void getfield(unsigned index, Type *type) {
dvander@147
   379
        ensure(OP_GETFIELD_LENGTH);
dvander@147
   380
        writeOp(OP_GETFIELD);
dvander@147
   381
        writeUint32(index);
dvander@147
   382
dvander@147
   383
        if (type->isTraceable())
dvander@147
   384
            markOop(1);
dvander@147
   385
    }
dvander@147
   386
    void setfield(unsigned index, Type *type) {
dvander@147
   387
        ensure(OP_SETFIELD_LENGTH);
dvander@147
   388
        writeOp(OP_SETFIELD);
dvander@147
   389
        writeUint32(index);
dvander@147
   390
dvander@147
   391
        if (type->isTraceable())
dvander@147
   392
            markOop(1);
dvander@147
   393
    }
dvander@147
   394
dvander@85
   395
    void getglobal(Variable *var) {
dvander@85
   396
        ensure(OP_GETGLOBAL_F_LENGTH);
dvander@85
   397
        if (var->type()->isPrimitive()) {
dvander@85
   398
            switch (var->type()->primitive()) {
dvander@85
   399
              case PrimitiveType_Float:
dvander@85
   400
                writeOp(OP_GETGLOBAL_F);
dvander@85
   401
                break;
dvander@85
   402
              default:
dvander@85
   403
                assert(var->type()->primitive() == PrimitiveType_Int32);
dvander@85
   404
                writeOp(OP_GETGLOBAL_I);
dvander@85
   405
                break;
dvander@85
   406
            }
dvander@85
   407
        } else {
dvander@85
   408
            writeOp(OP_GETGLOBAL_O);
dvander@85
   409
            markOop(1);
dvander@85
   410
        }
dvander@85
   411
        writeUint32(var->slot());
dvander@85
   412
    }
dvander@85
   413
    void setglobal(Variable *var) {
dvander@85
   414
        ensure(OP_SETGLOBAL_F_LENGTH);
dvander@85
   415
        if (var->type()->isPrimitive()) {
dvander@85
   416
            switch (var->type()->primitive()) {
dvander@85
   417
              case PrimitiveType_Float:
dvander@85
   418
                writeOp(OP_SETGLOBAL_F);
dvander@85
   419
                break;
dvander@85
   420
              default:
dvander@85
   421
                assert(var->type()->primitive() == PrimitiveType_Int32);
dvander@85
   422
                writeOp(OP_SETGLOBAL_I);
dvander@85
   423
                break;
dvander@85
   424
            }
dvander@85
   425
        } else {
dvander@85
   426
            writeOp(OP_SETGLOBAL_O);
dvander@85
   427
        }
dvander@85
   428
        writeUint32(var->slot());
dvander@85
   429
    }
dvander@85
   430
dvander@4
   431
    void float_(float value) {
dvander@4
   432
        ensure(OP_FLOAT_LENGTH);
dvander@4
   433
        writeOp(OP_FLOAT);
dvander@4
   434
        writeFloat(value);
dvander@4
   435
    }
dvander@4
   436
    void cvt_i2f() {
dvander@4
   437
        singleByteOp(OP_CVT_I2F);
dvander@4
   438
    }
dvander@185
   439
    void newarray(Opcode op, Handle<Map> map, Heap::Tenure tenure) {
dvander@185
   440
        assert(op == OP_NEWFIXED ||
dvander@185
   441
               op == OP_NEWEMPTY ||
dvander@185
   442
               op == OP_NEWSIZED);
dvander@185
   443
dvander@47
   444
        recordOops();
dvander@185
   445
        ensure(OpcodeInfo[op].length);
dvander@185
   446
        writeOp(op);
dvander@85
   447
        writeUint8(tenure);
dvander@21
   448
        writeObject(map);
dvander@47
   449
        markOop(1);
dvander@12
   450
    }
dvander@147
   451
    void newstruct(Handle<Map> map, Heap::Tenure tenure) {
dvander@147
   452
        recordOops();
dvander@147
   453
        ensure(OP_NEWSTRUCT_LENGTH);
dvander@147
   454
        writeOp(OP_NEWSTRUCT);
dvander@147
   455
        writeUint8(tenure);
dvander@147
   456
        writeObject(map);
dvander@147
   457
        markOop(1);
dvander@147
   458
    }
dvander@12
   459
    void savelifo(unsigned slot) {
dvander@12
   460
        ensure(OP_SAVELIFO_LENGTH);
dvander@12
   461
        writeOp(OP_SAVELIFO);
dvander@12
   462
        writeUint32(slot);
dvander@12
   463
    }
dvander@12
   464
    void unwindlifo(unsigned slot) {
dvander@12
   465
        ensure(OP_UNWINDLIFO_LENGTH);
dvander@12
   466
        writeOp(OP_UNWINDLIFO);
dvander@12
   467
        writeUint32(slot);
dvander@12
   468
    }
dvander@14
   469
    void newref(Variable *var) {
dvander@47
   470
        recordOops();
dvander@14
   471
        if (var->location() == Variable::STACK) {
dvander@14
   472
            ensure(OP_VARREF_LIFO_LENGTH);
dvander@14
   473
            writeOp(OP_VARREF_LIFO);
dvander@14
   474
        } else {
dvander@14
   475
            assert(var->location() == Variable::PARAMETER);
dvander@14
   476
            ensure(OP_ARGREF_LIFO_LENGTH);
dvander@14
   477
            writeOp(OP_ARGREF_LIFO);
dvander@14
   478
        }
dvander@14
   479
        writeUint32(var->slot());
dvander@47
   480
        markOop(1);
dvander@16
   481
    }
dvander@47
   482
dvander@14
   483
    void slotref_lifo() {
dvander@47
   484
        recordOops();
dvander@14
   485
        singleByteOp(OP_SLOTREF_LIFO);
dvander@47
   486
        markOop(1);
dvander@14
   487
    }
dvander@17
   488
    void arrayref_lifo() {
dvander@47
   489
        recordOops();
dvander@17
   490
        singleByteOp(OP_ARRAYREF_LIFO);
dvander@47
   491
        markOop(1);
dvander@17
   492
    }
dvander@164
   493
    void fieldref_lifo(unsigned index) {
dvander@164
   494
        recordOops();
dvander@164
   495
        ensure(OP_FIELDREF_LIFO_LENGTH);
dvander@164
   496
        writeOp(OP_FIELDREF_LIFO);
dvander@164
   497
        writeUint32(index);
dvander@164
   498
        markOop(1);
dvander@164
   499
    }
dvander@145
   500
    void getref(Type *type) {
dvander@145
   501
        if (type->pod() == PrimitiveType_Int32) {
dvander@22
   502
            singleByteOp(OP_GETREF_I);
dvander@22
   503
        } else {
dvander@145
   504
            assert(type->pod() == PrimitiveType_Float);
dvander@22
   505
            singleByteOp(OP_GETREF_F);
dvander@22
   506
        }
dvander@14
   507
    }
dvander@145
   508
    void setref(Type *type) {
dvander@145
   509
        if (type->pod() == PrimitiveType_Int32) {
dvander@22
   510
            singleByteOp(OP_SETREF_I);
dvander@22
   511
        } else {
dvander@145
   512
            assert(type->pod() == PrimitiveType_Float);
dvander@22
   513
            singleByteOp(OP_SETREF_F);
dvander@22
   514
        }
dvander@14
   515
    }
dvander@33
   516
    void object(Handle<Object> obj) {
dvander@21
   517
        ensure(OP_OBJECT_LENGTH);
dvander@21
   518
        writeOp(OP_OBJECT);
dvander@21
   519
        writeObject(obj);
dvander@47
   520
        markOop(1);
dvander@21
   521
    }
dvander@152
   522
    void copyarray() {
dvander@152
   523
        singleByteOp(OP_COPYARRAY);
dvander@152
   524
        markOop(1);
dvander@152
   525
    }
dvander@152
   526
    void copystruct() {
dvander@152
   527
        singleByteOp(OP_COPYSTRUCT);
dvander@47
   528
        markOop(1);
dvander@21
   529
    }
dvander@47
   530
dvander@22
   531
    void dup() {
dvander@47
   532
        bool oop = getOop(1);
dvander@22
   533
        singleByteOp(OP_DUP);
dvander@47
   534
        markOop(1, oop);
dvander@22
   535
    }
dvander@22
   536
    void dup2() {
dvander@47
   537
        bool oop2 = getOop(2);
dvander@47
   538
        bool oop1 = getOop(1);
dvander@47
   539
dvander@22
   540
        singleByteOp(OP_DUP2);
dvander@47
   541
dvander@47
   542
        markOop(2, oop2);
dvander@47
   543
        markOop(1, oop1);
dvander@22
   544
    }
dvander@23
   545
    void swap() {
dvander@47
   546
        bool oop2 = getOop(2);
dvander@47
   547
        bool oop1 = getOop(1);
dvander@47
   548
dvander@23
   549
        singleByteOp(OP_SWAP);
dvander@47
   550
dvander@47
   551
        markOop(2, oop1);
dvander@47
   552
        markOop(1, oop2);
dvander@23
   553
    }
dvander@23
   554
    void roll3() {
dvander@47
   555
        bool oop3 = getOop(3);
dvander@47
   556
        bool oop2 = getOop(2);
dvander@47
   557
        bool oop1 = getOop(1);
dvander@47
   558
dvander@23
   559
        singleByteOp(OP_ROLL3);
dvander@47
   560
dvander@47
   561
        markOop(3, oop2);
dvander@47
   562
        markOop(2, oop1);
dvander@47
   563
        markOop(1, oop3);
dvander@23
   564
    }
dvander@23
   565
    void pick2() {
dvander@47
   566
        bool oop2 = getOop(2);
dvander@47
   567
        bool oop1 = getOop(1);
dvander@47
   568
dvander@23
   569
        singleByteOp(OP_PICK2);
dvander@47
   570
dvander@47
   571
        markOop(3, oop2);
dvander@47
   572
        markOop(2, oop1);
dvander@47
   573
        markOop(1, oop2);
dvander@23
   574
    }
dvander@23
   575
    void pick3() {
dvander@47
   576
        bool oop3 = getOop(3);
dvander@47
   577
        bool oop2 = getOop(2);
dvander@47
   578
        bool oop1 = getOop(1);
dvander@47
   579
dvander@23
   580
        singleByteOp(OP_PICK3);
dvander@47
   581
dvander@47
   582
        markOop(4, oop3);
dvander@47
   583
        markOop(3, oop2);
dvander@47
   584
        markOop(2, oop1);
dvander@47
   585
        markOop(1, oop3);
dvander@47
   586
    }
dvander@47
   587
dvander@72
   588
    void returnvoid() {
dvander@72
   589
        singleByteOp(OP_RETURNVOID);
dvander@72
   590
    }
dvander@73
   591
    void module() {
dvander@73
   592
        singleByteOp(OP_MODULE);
dvander@73
   593
        markOop(1);
dvander@73
   594
    }
dvander@73
   595
    void getmodule_fn(unsigned index) {
dvander@73
   596
        ensure(OP_GETMODULE_FN_LENGTH);
dvander@73
   597
        writeOp(OP_GETMODULE_FN);
dvander@73
   598
        writeUint32(index);
dvander@73
   599
        markOop(1);
dvander@73
   600
    }
dvander@78
   601
    void bitnot() {
dvander@78
   602
        singleByteOp(OP_BITNOT);
dvander@78
   603
    }
dvander@79
   604
    void not_() {
dvander@79
   605
        singleByteOp(OP_NOT);
dvander@79
   606
    }
dvander@79
   607
    void not_f() {
dvander@79
   608
        singleByteOp(OP_NOT_F);
dvander@79
   609
    }
dvander@80
   610
    void neg() {
dvander@80
   611
        singleByteOp(OP_NEG);
dvander@80
   612
    }
dvander@80
   613
    void neg_f() {
dvander@80
   614
        singleByteOp(OP_NEG_F);
dvander@80
   615
    }
dvander@142
   616
    void bits_i2f() {
dvander@142
   617
        singleByteOp(OP_BITS_I2F);
dvander@142
   618
    }
dvander@142
   619
    void bits_f2i() {
dvander@142
   620
        singleByteOp(OP_BITS_F2I);
dvander@142
   621
    }
dvander@143
   622
    void true_() {
dvander@143
   623
        singleByteOp(OP_TRUE);
dvander@143
   624
    }
dvander@143
   625
    void false_() {
dvander@143
   626
        singleByteOp(OP_FALSE);
dvander@143
   627
    }
dvander@72
   628
dvander@172
   629
    void tableswitch(int low, int high, Label *def, Label **labels) {
dvander@172
   630
        unsigned tablesize = TableSwitchEntries(low, high);
dvander@172
   631
        assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
dvander@172
   632
dvander@172
   633
        ensure(OP_TABLESWITCH_LENGTH);
dvander@172
   634
        writeOp(OP_TABLESWITCH);
dvander@172
   635
        writeInt32(low);
dvander@172
   636
        writeInt32(high);
dvander@172
   637
        jump(def);
dvander@172
   638
dvander@172
   639
        // When labels are patched, we assume each position is a jump. Rather
dvander@172
   640
        // than hack position offsets to make labels work without actual
dvander@172
   641
        // incoming jumps, we emit a jump inline.
dvander@172
   642
        for (unsigned i = 0; i < tablesize; i++)
dvander@172
   643
            jump(labels[i]);
dvander@172
   644
    }
dvander@172
   645
dvander@47
   646
    // Helpers.
dvander@47
   647
    void get(Variable *var) {
dvander@47
   648
        if (var->location() == Variable::STACK) {
dvander@47
   649
            getlocal(var);
dvander@47
   650
        } else {
dvander@47
   651
            assert(var->location() == Variable::PARAMETER);
dvander@47
   652
            getarg(var);
dvander@47
   653
        }
dvander@47
   654
    }
dvander@47
   655
    void set(Variable *var) {
dvander@47
   656
        assert(!var->type()->isReference());
dvander@47
   657
        if (var->location() == Variable::STACK) {
dvander@47
   658
            setlocal(var);
dvander@47
   659
        } else {
dvander@47
   660
            assert(var->location() == Variable::PARAMETER);
dvander@47
   661
            setarg(var);
dvander@47
   662
        }
dvander@23
   663
    }
dvander@0
   664
};
dvander@0
   665
dvander@0
   666
}
dvander@0
   667
dvander@0
   668
#endif // _include_bytecode_emitter_h_