jitcraft/BytecodeEmitter.h
author David Anderson <dvander@alliedmods.net>
Tue Jul 10 02:11:13 2012 -0700 (2012-07-10)
changeset 68 b40b0e18a918
parent 64 11c81eb30246
child 69 dfce0539a77d
permissions -rw-r--r--
Added support for ISourcePawnEngine natives.
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@0
    27
dvander@59
    28
namespace ke {
dvander@0
    29
dvander@0
    30
class Type;
dvander@12
    31
class Map;
dvander@0
    32
dvander@64
    33
typedef PoolList<ScopedRoot<Object>> ObjectList;
dvander@33
    34
dvander@47
    35
struct OopRecord : public PoolObject
dvander@47
    36
{
dvander@47
    37
    unsigned depth;
dvander@47
    38
    unsigned offset;
dvander@47
    39
    bool *slots;
dvander@47
    40
dvander@47
    41
    OopRecord(unsigned length, unsigned offset)
dvander@47
    42
      : depth(length),
dvander@47
    43
        offset(offset),
dvander@47
    44
        slots(NULL)
dvander@47
    45
    {
dvander@47
    46
    }
dvander@47
    47
};
dvander@47
    48
dvander@0
    49
class BytecodeEmitter
dvander@0
    50
{
dvander@47
    51
  private:
dvander@47
    52
    PoolAllocator &pool_;
dvander@47
    53
dvander@0
    54
    bytecode *buffer_;
dvander@0
    55
    bytecode *buffer_pos_;
dvander@0
    56
    bytecode *buffer_end_;
dvander@0
    57
    bytecode inline_buffer_[512];
dvander@0
    58
    bool oom_;
dvander@0
    59
    unsigned maxStackDepth_;
dvander@33
    60
    ObjectList objects_;
dvander@58
    61
    PoolList<bool> oopMap_;
dvander@58
    62
    PoolList<OopRecord *> oopRecords_;
dvander@0
    63
dvander@0
    64
  private:
dvander@47
    65
    // The maximum size of a code object must be such that the distance between
dvander@47
    66
    // two instructions fits into a signed, 31-bit integer. This ensures that
dvander@47
    67
    // all code-bounded buffers (like the number of object literals or
dvander@47
    68
    // safepoints) does not need to be bounds checked. It also means we can add
dvander@47
    69
    // any two offsets and be guaranteed that they don't overflow.
dvander@0
    70
    static const size_t MAX_LENGTH = INT_MAX / 2;
dvander@0
    71
dvander@0
    72
  private:
dvander@0
    73
    bool growBuffer(size_t bytes);
dvander@0
    74
dvander@0
    75
    // Checking the return value is not necessary, since the inline buffer is
dvander@0
    76
    // used as a ballast.
dvander@0
    77
    bool ensure(size_t bytes) {
dvander@0
    78
        if (buffer_pos_ + bytes > buffer_end_)
dvander@0
    79
            return growBuffer(bytes);
dvander@0
    80
        return true;
dvander@0
    81
    }
dvander@0
    82
dvander@0
    83
    void writeUint8(unsigned value) {
dvander@47
    84
        assert(value <= UCHAR_MAX);
dvander@0
    85
        *buffer_pos_++ = value;
dvander@0
    86
    }
dvander@4
    87
    void writeFloat(float value) {
dvander@4
    88
        *(float *)buffer_pos_ = value;
dvander@4
    89
        buffer_pos_ += sizeof(float);
dvander@4
    90
    }
dvander@0
    91
    void writeInt32(int value) {
dvander@0
    92
        *(int *)buffer_pos_ = value;
dvander@0
    93
        buffer_pos_ += sizeof(int);
dvander@0
    94
    }
dvander@0
    95
    void writeUint32(unsigned value) {
dvander@0
    96
        *(unsigned *)buffer_pos_ = value;
dvander@0
    97
        buffer_pos_ += sizeof(unsigned);
dvander@0
    98
    }
dvander@0
    99
    void writeOp(Opcode op) {
dvander@47
   100
        if (oom_)
dvander@47
   101
            return;
dvander@47
   102
dvander@0
   103
        writeUint8(op);
dvander@47
   104
        for (int i = 0; i < OpcodeInfo[op].nuses; i++)
dvander@58
   105
            oopMap_.pop();
dvander@47
   106
        for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
dvander@58
   107
            oopMap_.append(false);
dvander@58
   108
        if (oopMap_.length() > maxStackDepth_)
dvander@58
   109
            maxStackDepth_ = oopMap_.length();
dvander@0
   110
    }
dvander@21
   111
    void writeObject(Object *obj) {
dvander@58
   112
        writeUint32(objects_.length());
dvander@64
   113
        ScopedRoot<Object> root(obj);
dvander@33
   114
        if (!root)
dvander@33
   115
            oom_ = true;
dvander@58
   116
        oom_ &= objects_.append(root);
dvander@12
   117
    }
dvander@0
   118
dvander@0
   119
    int position() const {
dvander@0
   120
        assert(buffer_pos_ - buffer_ < INT_MAX / 2);
dvander@0
   121
        return int(buffer_pos_ - buffer_);
dvander@0
   122
    }
dvander@0
   123
dvander@0
   124
  public:
dvander@47
   125
    BytecodeEmitter(PoolAllocator &pool);
dvander@0
   126
dvander@0
   127
    bytecode *buffer() const {
dvander@0
   128
        return buffer_;
dvander@0
   129
    }
dvander@0
   130
    unsigned length() const {
dvander@0
   131
        return unsigned(buffer_pos_ - buffer_);
dvander@0
   132
    }
dvander@0
   133
    bool oom() const {
dvander@0
   134
        return oom_;
dvander@0
   135
    }
dvander@0
   136
    unsigned stackDepth() const {
dvander@58
   137
        return oopMap_.length();
dvander@0
   138
    }
dvander@0
   139
    unsigned maxStackDepth() const {
dvander@0
   140
        return maxStackDepth_;
dvander@0
   141
    }
dvander@33
   142
    const ObjectList *objects() const {
dvander@21
   143
        return &objects_;
dvander@12
   144
    }
dvander@58
   145
    PoolList<OopRecord *> *oopRecords() {
dvander@47
   146
        return &oopRecords_;
dvander@47
   147
    }
dvander@0
   148
dvander@46
   149
    void drop(unsigned amt) {
dvander@47
   150
        assert(amt <= stackDepth());
dvander@47
   151
        for (unsigned i = 0; i < amt; i++)
dvander@58
   152
            oopMap_.pop();
dvander@46
   153
    }
dvander@46
   154
dvander@0
   155
  public:
dvander@0
   156
    // A label represents a local control-flow target in the bytecode. A label
dvander@0
   157
    // may be in three states:
dvander@0
   158
    //
dvander@0
   159
    // (1) Empty - the label is not used yet.
dvander@0
   160
    // (2) Pending - the label has incoming jumps, but the actual location of
dvander@0
   161
    //               is not yet known. The list of jumps is threaded through
dvander@0
   162
    //               the four bytes reserved for each emitted jump target. In
dvander@0
   163
    //               this case, the offset field is the location of the most
dvander@0
   164
    //               recently emitted incoming jump.
dvander@0
   165
    // (3) Bound   - the label's position has been pinned.
dvander@0
   166
    //
dvander@0
   167
    // A jump can be emitted to a label in any state. Binding a label
dvander@0
   168
    // immediately backpatches all pending incoming jumps. A label must be
dvander@0
   169
    // bound if it is used.
dvander@0
   170
    class Label
dvander@0
   171
    {
dvander@0
   172
        int offset_ : 31;
dvander@0
   173
        bool bound_ : 1;
dvander@0
   174
dvander@0
   175
        void setOffset(int offset) {
dvander@0
   176
            offset_ = offset;
dvander@0
   177
            assert(offset_ == offset);
dvander@0
   178
        }
dvander@0
   179
dvander@0
   180
      public:
dvander@0
   181
        static const int INVALID_OFFSET = -1;
dvander@0
   182
dvander@0
   183
      public:
dvander@0
   184
        Label()
dvander@0
   185
          : offset_(INVALID_OFFSET),
dvander@0
   186
            bound_(false)
dvander@0
   187
        {
dvander@0
   188
        }
dvander@0
   189
        ~Label()
dvander@0
   190
        {
dvander@0
   191
            assert(bound_ || offset_ == INVALID_OFFSET);
dvander@0
   192
        }
dvander@0
   193
        
dvander@0
   194
        bool bound() const {
dvander@0
   195
            return bound_;
dvander@0
   196
        }
dvander@0
   197
        int offset() const {
dvander@0
   198
            return offset_;
dvander@0
   199
        }
dvander@0
   200
        void bind(int offset) {
dvander@0
   201
            assert(!bound_);
dvander@0
   202
            setOffset(offset);
dvander@0
   203
            bound_ = true;
dvander@0
   204
        }
dvander@0
   205
        int link(int offset) {
dvander@0
   206
            assert(!bound_);
dvander@0
   207
            int old = offset_;
dvander@0
   208
            setOffset(offset);
dvander@0
   209
            return old;
dvander@0
   210
        }
dvander@0
   211
    };
dvander@0
   212
dvander@0
   213
  private:
dvander@0
   214
    int patchJumpAt(int at, int to) {
dvander@0
   215
        assert(at >= 0 && at < position());
dvander@0
   216
        int old = *(int *)(buffer_ + at + 1);
dvander@0
   217
        *(int *)(buffer_ + at + 1) = (to - at);
dvander@0
   218
        return old;
dvander@0
   219
    }
dvander@0
   220
dvander@0
   221
    void singleByteOp(Opcode op) {
dvander@0
   222
        assert(OpcodeInfo[op].length == 1);
dvander@0
   223
        ensure(OpcodeInfo[op].length);
dvander@0
   224
        writeOp(op);
dvander@0
   225
    }
dvander@0
   226
dvander@47
   227
    // Mark a stack slot as having an object pointer.
dvander@47
   228
    void markOop(unsigned depth, bool oop = true) {
dvander@47
   229
        if (oom_)
dvander@47
   230
            return;
dvander@58
   231
        oopMap_[oopMap_.length() - depth] = oop;
dvander@47
   232
    }
dvander@47
   233
    bool getOop(unsigned depth) {
dvander@47
   234
        if (oom_)
dvander@47
   235
            return false;
dvander@58
   236
        return oopMap_[oopMap_.length() - depth];
dvander@47
   237
    }
dvander@47
   238
dvander@47
   239
    // Mark the current bytecode position as either re-entrant (meaning, it
dvander@47
   240
    // can leave the interpreter or call to another function), or causing GC.
dvander@47
   241
    // This will record which stack slots have objects and associate that
dvander@47
   242
    // information with the current pc.
dvander@47
   243
    void recordOops();
dvander@47
   244
dvander@0
   245
  public:
dvander@0
   246
    void int_(int value) {
dvander@0
   247
        ensure(OP_INT);
dvander@0
   248
        writeOp(OP_INT);
dvander@0
   249
        writeInt32(value);
dvander@0
   250
    }
dvander@0
   251
    void return_() {
dvander@0
   252
        ensure(OP_RETURN);
dvander@0
   253
        writeOp(OP_RETURN);
dvander@0
   254
    }
dvander@47
   255
    void getlocal(Variable *var) {
dvander@0
   256
        ensure(OP_GETLOCAL_LENGTH);
dvander@0
   257
        writeOp(OP_GETLOCAL);
dvander@47
   258
        writeUint32(var->slot());
dvander@47
   259
dvander@47
   260
        if (var->type()->isTraceable())
dvander@47
   261
            markOop(1);
dvander@0
   262
    }
dvander@47
   263
    void setlocal(Variable *var) {
dvander@0
   264
        ensure(OP_SETLOCAL_LENGTH);
dvander@0
   265
        writeOp(OP_SETLOCAL);
dvander@47
   266
        writeUint32(var->slot());
dvander@47
   267
dvander@47
   268
        if (var->type()->isTraceable())
dvander@47
   269
            markOop(1);
dvander@0
   270
    }
dvander@47
   271
    void getarg(Variable *var) {
dvander@0
   272
        ensure(OP_GETARG_LENGTH);
dvander@0
   273
        writeOp(OP_GETARG);
dvander@47
   274
        writeUint32(var->slot());
dvander@47
   275
dvander@47
   276
        if (var->type()->isTraceable())
dvander@47
   277
            markOop(1);
dvander@0
   278
    }
dvander@47
   279
    void setarg(Variable *var) {
dvander@0
   280
        ensure(OP_SETARG_LENGTH);
dvander@0
   281
        writeOp(OP_SETARG);
dvander@47
   282
        writeUint32(var->slot());
dvander@47
   283
dvander@47
   284
        if (var->type()->isTraceable())
dvander@47
   285
            markOop(1);
dvander@0
   286
    }
dvander@0
   287
dvander@0
   288
    void j(Opcode op, Label *label) {
dvander@0
   289
        // Since jumps can skip around the stream, do not try to do anything
dvander@0
   290
        // in a potentially truncated state.
dvander@0
   291
        if (oom())
dvander@0
   292
            return;
dvander@0
   293
dvander@0
   294
        assert(op >= OP_JL && op <= OP_JUMP);
dvander@0
   295
        ensure(OP_JUMP_LENGTH);
dvander@0
   296
dvander@0
   297
        if (label->bound()) {
dvander@0
   298
            // We can immediately emit this jump.
dvander@0
   299
            int distance = label->offset() - position();
dvander@0
   300
            writeOp(op);
dvander@0
   301
            writeInt32(distance);
dvander@0
   302
        } else {
dvander@0
   303
            // We can't emit this jump yet. Add a placeholder.
dvander@0
   304
            int old = label->link(position());
dvander@0
   305
            writeOp(op);
dvander@0
   306
            writeInt32(old);
dvander@0
   307
        }
dvander@0
   308
    }
dvander@0
   309
    void bind(Label *label) {
dvander@0
   310
        if (oom())
dvander@0
   311
            return;
dvander@0
   312
dvander@0
   313
        assert(!label->bound());
dvander@0
   314
dvander@0
   315
        int offset = label->offset();
dvander@0
   316
        while (offset != Label::INVALID_OFFSET)
dvander@0
   317
            offset = patchJumpAt(offset, position());
dvander@0
   318
dvander@0
   319
        label->bind(position());
dvander@0
   320
    }
dvander@0
   321
    void jump(Label *label) {
dvander@0
   322
        j(OP_JUMP, label);
dvander@0
   323
    }
dvander@0
   324
dvander@0
   325
    void binary(Opcode op) {
dvander@0
   326
        singleByteOp(op);
dvander@0
   327
    }
dvander@0
   328
dvander@0
   329
    void pop() {
dvander@0
   330
        singleByteOp(OP_POP);
dvander@0
   331
    }
dvander@0
   332
    void stop() {
dvander@0
   333
        singleByteOp(OP_STOP);
dvander@0
   334
    }
dvander@46
   335
    void callglobal(unsigned index) {
dvander@47
   336
        recordOops();
dvander@0
   337
        ensure(OP_CALLGLOBAL_LENGTH);
dvander@0
   338
        writeOp(OP_CALLGLOBAL);
dvander@0
   339
        writeUint32(index);
dvander@0
   340
    }
dvander@68
   341
    void callnative(unsigned index, unsigned argc) {
dvander@68
   342
        recordOops();
dvander@68
   343
        ensure(OP_CALLNATIVE_LENGTH);
dvander@68
   344
        writeOp(OP_CALLNATIVE);
dvander@68
   345
        writeUint32(index);
dvander@68
   346
        writeUint32(argc);
dvander@68
   347
    }
dvander@21
   348
    void getarray(PrimitiveType type) {
dvander@21
   349
        switch (type) {
dvander@21
   350
          case PrimitiveType_Float:
dvander@21
   351
            singleByteOp(OP_GETARRAY_F);
dvander@21
   352
            break;
dvander@21
   353
          case PrimitiveType_Int32:
dvander@21
   354
            singleByteOp(OP_GETARRAY_I);
dvander@21
   355
            break;
dvander@21
   356
          default:
dvander@21
   357
            assert(type == PrimitiveType_Char);
dvander@21
   358
            singleByteOp(OP_GETARRAY_C);
dvander@21
   359
            break;
dvander@21
   360
        }
dvander@0
   361
    }
dvander@21
   362
    void setarray(PrimitiveType type) {
dvander@21
   363
        switch (type) {
dvander@21
   364
          case PrimitiveType_Float:
dvander@21
   365
            singleByteOp(OP_SETARRAY_F);
dvander@21
   366
            break;
dvander@21
   367
          case PrimitiveType_Int32:
dvander@21
   368
            singleByteOp(OP_SETARRAY_I);
dvander@21
   369
            break;
dvander@21
   370
          default:
dvander@21
   371
            assert(type == PrimitiveType_Char);
dvander@21
   372
            singleByteOp(OP_SETARRAY_C);
dvander@21
   373
            break;
dvander@21
   374
        }
dvander@7
   375
    }
dvander@19
   376
    void getarray_o() {
dvander@19
   377
        singleByteOp(OP_GETARRAY_O);
dvander@47
   378
        markOop(1);
dvander@0
   379
    }
dvander@19
   380
    void bounds() {
dvander@19
   381
        singleByteOp(OP_BOUNDS);
dvander@47
   382
        markOop(2);
dvander@0
   383
    }
dvander@4
   384
    void float_(float value) {
dvander@4
   385
        ensure(OP_FLOAT_LENGTH);
dvander@4
   386
        writeOp(OP_FLOAT);
dvander@4
   387
        writeFloat(value);
dvander@4
   388
    }
dvander@4
   389
    void cvt_i2f() {
dvander@4
   390
        singleByteOp(OP_CVT_I2F);
dvander@4
   391
    }
dvander@33
   392
    void newarray_lifo(Handle<Map> map) {
dvander@47
   393
        recordOops();
dvander@19
   394
        ensure(OP_NEWARRAY_LIFO_LENGTH);
dvander@19
   395
        writeOp(OP_NEWARRAY_LIFO);
dvander@21
   396
        writeObject(map);
dvander@47
   397
        markOop(1);
dvander@12
   398
    }
dvander@12
   399
    void savelifo(unsigned slot) {
dvander@12
   400
        ensure(OP_SAVELIFO_LENGTH);
dvander@12
   401
        writeOp(OP_SAVELIFO);
dvander@12
   402
        writeUint32(slot);
dvander@12
   403
    }
dvander@12
   404
    void unwindlifo(unsigned slot) {
dvander@12
   405
        ensure(OP_UNWINDLIFO_LENGTH);
dvander@12
   406
        writeOp(OP_UNWINDLIFO);
dvander@12
   407
        writeUint32(slot);
dvander@12
   408
    }
dvander@14
   409
    void newref(Variable *var) {
dvander@47
   410
        recordOops();
dvander@14
   411
        if (var->location() == Variable::STACK) {
dvander@14
   412
            ensure(OP_VARREF_LIFO_LENGTH);
dvander@14
   413
            writeOp(OP_VARREF_LIFO);
dvander@14
   414
        } else {
dvander@14
   415
            assert(var->location() == Variable::PARAMETER);
dvander@14
   416
            ensure(OP_ARGREF_LIFO_LENGTH);
dvander@14
   417
            writeOp(OP_ARGREF_LIFO);
dvander@14
   418
        }
dvander@14
   419
        writeUint32(var->slot());
dvander@47
   420
        markOop(1);
dvander@16
   421
    }
dvander@47
   422
dvander@14
   423
    void slotref_lifo() {
dvander@47
   424
        recordOops();
dvander@14
   425
        singleByteOp(OP_SLOTREF_LIFO);
dvander@47
   426
        markOop(1);
dvander@14
   427
    }
dvander@17
   428
    void arrayref_lifo() {
dvander@47
   429
        recordOops();
dvander@17
   430
        singleByteOp(OP_ARRAYREF_LIFO);
dvander@47
   431
        markOop(1);
dvander@17
   432
    }
dvander@22
   433
    void getref(PrimitiveType type) {
dvander@22
   434
        if (type == PrimitiveType_Int32) {
dvander@22
   435
            singleByteOp(OP_GETREF_I);
dvander@22
   436
        } else {
dvander@22
   437
            assert(type == PrimitiveType_Float);
dvander@22
   438
            singleByteOp(OP_GETREF_F);
dvander@22
   439
        }
dvander@14
   440
    }
dvander@22
   441
    void setref(PrimitiveType type) {
dvander@22
   442
        if (type == PrimitiveType_Int32) {
dvander@22
   443
            singleByteOp(OP_SETREF_I);
dvander@22
   444
        } else {
dvander@22
   445
            assert(type == PrimitiveType_Float);
dvander@22
   446
            singleByteOp(OP_SETREF_F);
dvander@22
   447
        }
dvander@14
   448
    }
dvander@33
   449
    void object(Handle<Object> obj) {
dvander@21
   450
        ensure(OP_OBJECT_LENGTH);
dvander@21
   451
        writeOp(OP_OBJECT);
dvander@21
   452
        writeObject(obj);
dvander@47
   453
        markOop(1);
dvander@21
   454
    }
dvander@21
   455
    void arraycopy() {
dvander@21
   456
        singleByteOp(OP_ARRAYCOPY);
dvander@47
   457
        markOop(1);
dvander@21
   458
    }
dvander@47
   459
dvander@22
   460
    void dup() {
dvander@47
   461
        bool oop = getOop(1);
dvander@22
   462
        singleByteOp(OP_DUP);
dvander@47
   463
        markOop(1, oop);
dvander@22
   464
    }
dvander@22
   465
    void dup2() {
dvander@47
   466
        bool oop2 = getOop(2);
dvander@47
   467
        bool oop1 = getOop(1);
dvander@47
   468
dvander@22
   469
        singleByteOp(OP_DUP2);
dvander@47
   470
dvander@47
   471
        markOop(2, oop2);
dvander@47
   472
        markOop(1, oop1);
dvander@22
   473
    }
dvander@23
   474
    void swap() {
dvander@47
   475
        bool oop2 = getOop(2);
dvander@47
   476
        bool oop1 = getOop(1);
dvander@47
   477
dvander@23
   478
        singleByteOp(OP_SWAP);
dvander@47
   479
dvander@47
   480
        markOop(2, oop1);
dvander@47
   481
        markOop(1, oop2);
dvander@23
   482
    }
dvander@23
   483
    void roll3() {
dvander@47
   484
        bool oop3 = getOop(3);
dvander@47
   485
        bool oop2 = getOop(2);
dvander@47
   486
        bool oop1 = getOop(1);
dvander@47
   487
dvander@23
   488
        singleByteOp(OP_ROLL3);
dvander@47
   489
dvander@47
   490
        markOop(3, oop2);
dvander@47
   491
        markOop(2, oop1);
dvander@47
   492
        markOop(1, oop3);
dvander@23
   493
    }
dvander@23
   494
    void pick2() {
dvander@47
   495
        bool oop2 = getOop(2);
dvander@47
   496
        bool oop1 = getOop(1);
dvander@47
   497
dvander@23
   498
        singleByteOp(OP_PICK2);
dvander@47
   499
dvander@47
   500
        markOop(3, oop2);
dvander@47
   501
        markOop(2, oop1);
dvander@47
   502
        markOop(1, oop2);
dvander@23
   503
    }
dvander@23
   504
    void pick3() {
dvander@47
   505
        bool oop3 = getOop(3);
dvander@47
   506
        bool oop2 = getOop(2);
dvander@47
   507
        bool oop1 = getOop(1);
dvander@47
   508
dvander@23
   509
        singleByteOp(OP_PICK3);
dvander@47
   510
dvander@47
   511
        markOop(4, oop3);
dvander@47
   512
        markOop(3, oop2);
dvander@47
   513
        markOop(2, oop1);
dvander@47
   514
        markOop(1, oop3);
dvander@47
   515
    }
dvander@47
   516
dvander@47
   517
    // Helpers.
dvander@47
   518
    void get(Variable *var) {
dvander@47
   519
        if (var->location() == Variable::STACK) {
dvander@47
   520
            getlocal(var);
dvander@47
   521
        } else {
dvander@47
   522
            assert(var->location() == Variable::PARAMETER);
dvander@47
   523
            getarg(var);
dvander@47
   524
        }
dvander@47
   525
    }
dvander@47
   526
    void set(Variable *var) {
dvander@47
   527
        assert(!var->type()->isReference());
dvander@47
   528
        if (var->location() == Variable::STACK) {
dvander@47
   529
            setlocal(var);
dvander@47
   530
        } else {
dvander@47
   531
            assert(var->location() == Variable::PARAMETER);
dvander@47
   532
            setarg(var);
dvander@47
   533
        }
dvander@23
   534
    }
dvander@0
   535
};
dvander@0
   536
dvander@0
   537
}
dvander@0
   538
dvander@0
   539
#endif // _include_bytecode_emitter_h_