src/compiler/BytecodeEmitter.h
author David Anderson <dvander@alliedmods.net>
Sat Dec 22 23:18:57 2012 -0800 (2012-12-22)
changeset 233 bbb498ccb4ac
parent 230 fb3cd08bc7fb
child 234 26e3035cdffc
permissions -rw-r--r--
Re-add enum support.
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@58
   191
        writeUint32(objects_.length());
dvander@64
   192
        ScopedRoot<Object> root(obj);
dvander@70
   193
        if (!objects_.append(root))
dvander@70
   194
            oom_ = true;
dvander@12
   195
    }
dvander@0
   196
dvander@0
   197
    int position() const {
dvander@0
   198
        assert(buffer_pos_ - buffer_ < INT_MAX / 2);
dvander@0
   199
        return int(buffer_pos_ - buffer_);
dvander@0
   200
    }
dvander@0
   201
dvander@0
   202
  public:
dvander@47
   203
    BytecodeEmitter(PoolAllocator &pool);
dvander@195
   204
    ~BytecodeEmitter();
dvander@195
   205
dvander@195
   206
    void accept(VirtualObjectVisitor *visitor);
dvander@0
   207
dvander@0
   208
    bytecode *buffer() const {
dvander@0
   209
        return buffer_;
dvander@0
   210
    }
dvander@0
   211
    unsigned length() const {
dvander@0
   212
        return unsigned(buffer_pos_ - buffer_);
dvander@0
   213
    }
dvander@0
   214
    bool oom() const {
dvander@70
   215
        return oom_ || sourcemap_.oom();
dvander@0
   216
    }
dvander@0
   217
    unsigned stackDepth() const {
dvander@58
   218
        return oopMap_.length();
dvander@0
   219
    }
dvander@0
   220
    unsigned maxStackDepth() const {
dvander@0
   221
        return maxStackDepth_;
dvander@0
   222
    }
dvander@0
   223
dvander@46
   224
    void drop(unsigned amt) {
dvander@47
   225
        assert(amt <= stackDepth());
dvander@47
   226
        for (unsigned i = 0; i < amt; i++)
dvander@58
   227
            oopMap_.pop();
dvander@46
   228
    }
dvander@46
   229
dvander@70
   230
    void note_position(const SourcePosition &pos);
dvander@70
   231
    void setFirstLine(unsigned line) {
dvander@70
   232
        assert(!sourcemap_.length());
dvander@70
   233
        firstLine_ = line;
dvander@70
   234
    }
dvander@70
   235
dvander@0
   236
  public:
dvander@0
   237
    // A label represents a local control-flow target in the bytecode. A label
dvander@0
   238
    // may be in three states:
dvander@0
   239
    //
dvander@0
   240
    // (1) Empty - the label is not used yet.
dvander@0
   241
    // (2) Pending - the label has incoming jumps, but the actual location of
dvander@0
   242
    //               is not yet known. The list of jumps is threaded through
dvander@0
   243
    //               the four bytes reserved for each emitted jump target. In
dvander@0
   244
    //               this case, the offset field is the location of the most
dvander@0
   245
    //               recently emitted incoming jump.
dvander@0
   246
    // (3) Bound   - the label's position has been pinned.
dvander@0
   247
    //
dvander@0
   248
    // A jump can be emitted to a label in any state. Binding a label
dvander@0
   249
    // immediately backpatches all pending incoming jumps. A label must be
dvander@0
   250
    // bound if it is used.
dvander@0
   251
    class Label
dvander@0
   252
    {
dvander@0
   253
        int offset_ : 31;
dvander@0
   254
        bool bound_ : 1;
dvander@0
   255
dvander@0
   256
        void setOffset(int offset) {
dvander@0
   257
            offset_ = offset;
dvander@0
   258
            assert(offset_ == offset);
dvander@0
   259
        }
dvander@0
   260
dvander@0
   261
      public:
dvander@0
   262
        static const int INVALID_OFFSET = -1;
dvander@0
   263
dvander@0
   264
      public:
dvander@0
   265
        Label()
dvander@0
   266
          : offset_(INVALID_OFFSET),
dvander@0
   267
            bound_(false)
dvander@0
   268
        {
dvander@0
   269
        }
dvander@0
   270
        ~Label()
dvander@0
   271
        {
dvander@0
   272
            assert(bound_ || offset_ == INVALID_OFFSET);
dvander@0
   273
        }
dvander@0
   274
        
dvander@0
   275
        bool bound() const {
dvander@0
   276
            return bound_;
dvander@0
   277
        }
dvander@0
   278
        int offset() const {
dvander@0
   279
            return offset_;
dvander@0
   280
        }
dvander@0
   281
        void bind(int offset) {
dvander@0
   282
            assert(!bound_);
dvander@0
   283
            setOffset(offset);
dvander@0
   284
            bound_ = true;
dvander@0
   285
        }
dvander@0
   286
        int link(int offset) {
dvander@0
   287
            assert(!bound_);
dvander@0
   288
            int old = offset_;
dvander@0
   289
            setOffset(offset);
dvander@0
   290
            return old;
dvander@0
   291
        }
dvander@0
   292
    };
dvander@0
   293
dvander@0
   294
  private:
dvander@0
   295
    int patchJumpAt(int at, int to) {
dvander@0
   296
        assert(at >= 0 && at < position());
dvander@0
   297
        int old = *(int *)(buffer_ + at + 1);
dvander@0
   298
        *(int *)(buffer_ + at + 1) = (to - at);
dvander@0
   299
        return old;
dvander@0
   300
    }
dvander@0
   301
dvander@0
   302
    void singleByteOp(Opcode op) {
dvander@0
   303
        assert(OpcodeInfo[op].length == 1);
dvander@0
   304
        ensure(OpcodeInfo[op].length);
dvander@0
   305
        writeOp(op);
dvander@0
   306
    }
dvander@0
   307
dvander@47
   308
    // Mark a stack slot as having an object pointer.
dvander@47
   309
    void markOop(unsigned depth, bool oop = true) {
dvander@47
   310
        if (oom_)
dvander@47
   311
            return;
dvander@58
   312
        oopMap_[oopMap_.length() - depth] = oop;
dvander@47
   313
    }
dvander@47
   314
    bool getOop(unsigned depth) {
dvander@47
   315
        if (oom_)
dvander@47
   316
            return false;
dvander@58
   317
        return oopMap_[oopMap_.length() - depth];
dvander@47
   318
    }
dvander@47
   319
dvander@47
   320
    // Mark the current bytecode position as either re-entrant (meaning, it
dvander@47
   321
    // can leave the interpreter or call to another function), or causing GC.
dvander@47
   322
    // This will record which stack slots have objects and associate that
dvander@47
   323
    // information with the current pc.
dvander@47
   324
    void recordOops();
dvander@47
   325
dvander@0
   326
  public:
dvander@0
   327
    void int_(int value) {
dvander@0
   328
        ensure(OP_INT);
dvander@0
   329
        writeOp(OP_INT);
dvander@0
   330
        writeInt32(value);
dvander@0
   331
    }
dvander@0
   332
    void return_() {
dvander@0
   333
        ensure(OP_RETURN);
dvander@0
   334
        writeOp(OP_RETURN);
dvander@0
   335
    }
dvander@195
   336
    void getlocal(VariableSymbol *var);
dvander@195
   337
    void setlocal(VariableSymbol *var);
dvander@220
   338
    void getarg(VariableSymbol *var);
dvander@220
   339
    void setarg(VariableSymbol *var);
dvander@0
   340
dvander@0
   341
    void j(Opcode op, Label *label) {
dvander@0
   342
        // Since jumps can skip around the stream, do not try to do anything
dvander@0
   343
        // in a potentially truncated state.
dvander@0
   344
        if (oom())
dvander@0
   345
            return;
dvander@0
   346
dvander@230
   347
        assert(op == OP_JT || op == OP_JF || op == OP_JUMP ||
dvander@230
   348
               op == OP_CONTINUE || op == OP_BREAK);
dvander@0
   349
        ensure(OP_JUMP_LENGTH);
dvander@0
   350
dvander@0
   351
        if (label->bound()) {
dvander@0
   352
            // We can immediately emit this jump.
dvander@0
   353
            int distance = label->offset() - position();
dvander@0
   354
            writeOp(op);
dvander@0
   355
            writeInt32(distance);
dvander@0
   356
        } else {
dvander@0
   357
            // We can't emit this jump yet. Add a placeholder.
dvander@0
   358
            int old = label->link(position());
dvander@0
   359
            writeOp(op);
dvander@0
   360
            writeInt32(old);
dvander@0
   361
        }
dvander@0
   362
    }
dvander@0
   363
    void bind(Label *label) {
dvander@0
   364
        if (oom())
dvander@0
   365
            return;
dvander@0
   366
dvander@0
   367
        assert(!label->bound());
dvander@0
   368
dvander@0
   369
        int offset = label->offset();
dvander@0
   370
        while (offset != Label::INVALID_OFFSET)
dvander@0
   371
            offset = patchJumpAt(offset, position());
dvander@0
   372
dvander@0
   373
        label->bind(position());
dvander@0
   374
    }
dvander@0
   375
    void jump(Label *label) {
dvander@0
   376
        j(OP_JUMP, label);
dvander@0
   377
    }
dvander@0
   378
dvander@0
   379
    void binary(Opcode op) {
dvander@0
   380
        singleByteOp(op);
dvander@0
   381
    }
dvander@195
   382
    void unary(Opcode op) {
dvander@195
   383
        singleByteOp(op);
dvander@195
   384
    }
dvander@0
   385
dvander@0
   386
    void pop() {
dvander@0
   387
        singleByteOp(OP_POP);
dvander@0
   388
    }
dvander@0
   389
    void stop() {
dvander@0
   390
        singleByteOp(OP_STOP);
dvander@0
   391
    }
dvander@195
   392
    void call(Handle<FunctionType> fun, unsigned argc) {
dvander@47
   393
        recordOops();
dvander@72
   394
dvander@195
   395
        if (fun->isNative()) {
dvander@195
   396
            ensure(OP_CALLNATIVE_LENGTH);
dvander@195
   397
            writeOp(OP_CALLNATIVE);
dvander@195
   398
            writeUint32(argc);
dvander@195
   399
            drop(argc + 1);
dvander@195
   400
        } else {
dvander@195
   401
            ensure(OP_CALL_LENGTH);
dvander@195
   402
            writeOp(OP_CALL);
dvander@195
   403
            drop(argc + 1);
dvander@195
   404
dvander@195
   405
            if (fun->returnType()->isVoid())
dvander@195
   406
                drop(1);
dvander@195
   407
            else if (fun->returnType()->isTraceable())
dvander@195
   408
                markOop(1);
dvander@195
   409
        }
dvander@68
   410
    }
dvander@85
   411
dvander@157
   412
    void getelem(Type *type) {
dvander@157
   413
        singleByteOp(OP_GETELEM);
dvander@154
   414
dvander@157
   415
        if (type->isTraceable())
dvander@157
   416
            markOop(1);
dvander@0
   417
    }
dvander@157
   418
    void setelem(Type *type) {
dvander@157
   419
        singleByteOp(OP_SETELEM);
dvander@7
   420
    }
dvander@85
   421
dvander@147
   422
    void getfield(unsigned index, Type *type) {
dvander@147
   423
        ensure(OP_GETFIELD_LENGTH);
dvander@147
   424
        writeOp(OP_GETFIELD);
dvander@147
   425
        writeUint32(index);
dvander@147
   426
dvander@147
   427
        if (type->isTraceable())
dvander@147
   428
            markOop(1);
dvander@147
   429
    }
dvander@147
   430
    void setfield(unsigned index, Type *type) {
dvander@147
   431
        ensure(OP_SETFIELD_LENGTH);
dvander@147
   432
        writeOp(OP_SETFIELD);
dvander@147
   433
        writeUint32(index);
dvander@147
   434
dvander@147
   435
        if (type->isTraceable())
dvander@147
   436
            markOop(1);
dvander@147
   437
    }
dvander@147
   438
dvander@230
   439
    int enterloop() {
dvander@230
   440
        int offset = position();
dvander@230
   441
dvander@230
   442
        ensure(OP_ENTERLOOP);
dvander@230
   443
        writeOp(OP_ENTERLOOP);
dvander@230
   444
        writeUint8(0);
dvander@230
   445
dvander@230
   446
        loopDepth_++;
dvander@230
   447
        if (loopDepth_ > maxLoopDepth_)
dvander@230
   448
            maxLoopDepth_ = loopDepth_;
dvander@230
   449
dvander@230
   450
        return offset;
dvander@85
   451
    }
dvander@230
   452
    void leaveloop() {
dvander@230
   453
        singleByteOp(OP_LEAVELOOP);
dvander@230
   454
dvander@230
   455
        assert(loopDepth_);
dvander@230
   456
        loopDepth_--;
dvander@85
   457
    }
dvander@230
   458
    void setLoopUsesLifoStack(int pos) {
dvander@230
   459
        assert(pos >= 0 && pos < position());
dvander@230
   460
        assert(*(buffer() + pos) == OP_ENTERLOOP);
dvander@230
   461
        *(buffer() + pos + 1) = 1;
dvander@230
   462
    }
dvander@85
   463
dvander@4
   464
    void float_(float value) {
dvander@4
   465
        ensure(OP_FLOAT_LENGTH);
dvander@4
   466
        writeOp(OP_FLOAT);
dvander@4
   467
        writeFloat(value);
dvander@4
   468
    }
dvander@4
   469
    void cvt_i2f() {
dvander@4
   470
        singleByteOp(OP_CVT_I2F);
dvander@4
   471
    }
dvander@187
   472
    void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
dvander@185
   473
        assert(op == OP_NEWFIXED ||
dvander@185
   474
               op == OP_NEWEMPTY ||
dvander@185
   475
               op == OP_NEWSIZED);
dvander@185
   476
dvander@47
   477
        recordOops();
dvander@185
   478
        ensure(OpcodeInfo[op].length);
dvander@185
   479
        writeOp(op);
dvander@85
   480
        writeUint8(tenure);
dvander@21
   481
        writeObject(map);
dvander@187
   482
dvander@187
   483
        if (op == OP_NEWSIZED)
dvander@187
   484
            drop(map->type()->levels());
dvander@187
   485
dvander@47
   486
        markOop(1);
dvander@12
   487
    }
dvander@147
   488
    void newstruct(Handle<Map> map, Heap::Tenure tenure) {
dvander@147
   489
        recordOops();
dvander@147
   490
        ensure(OP_NEWSTRUCT_LENGTH);
dvander@147
   491
        writeOp(OP_NEWSTRUCT);
dvander@147
   492
        writeUint8(tenure);
dvander@147
   493
        writeObject(map);
dvander@147
   494
        markOop(1);
dvander@147
   495
    }
dvander@12
   496
    void savelifo(unsigned slot) {
dvander@12
   497
        ensure(OP_SAVELIFO_LENGTH);
dvander@12
   498
        writeOp(OP_SAVELIFO);
dvander@12
   499
        writeUint32(slot);
dvander@12
   500
    }
dvander@12
   501
    void unwindlifo(unsigned slot) {
dvander@12
   502
        ensure(OP_UNWINDLIFO_LENGTH);
dvander@12
   503
        writeOp(OP_UNWINDLIFO);
dvander@12
   504
        writeUint32(slot);
dvander@12
   505
    }
dvander@222
   506
dvander@222
   507
    void newref(VariableSymbol *var);
dvander@47
   508
dvander@14
   509
    void slotref_lifo() {
dvander@47
   510
        recordOops();
dvander@14
   511
        singleByteOp(OP_SLOTREF_LIFO);
dvander@47
   512
        markOop(1);
dvander@14
   513
    }
dvander@145
   514
    void getref(Type *type) {
dvander@145
   515
        if (type->pod() == PrimitiveType_Int32) {
dvander@22
   516
            singleByteOp(OP_GETREF_I);
dvander@22
   517
        } else {
dvander@145
   518
            assert(type->pod() == PrimitiveType_Float);
dvander@22
   519
            singleByteOp(OP_GETREF_F);
dvander@22
   520
        }
dvander@14
   521
    }
dvander@145
   522
    void setref(Type *type) {
dvander@145
   523
        if (type->pod() == PrimitiveType_Int32) {
dvander@22
   524
            singleByteOp(OP_SETREF_I);
dvander@22
   525
        } else {
dvander@145
   526
            assert(type->pod() == PrimitiveType_Float);
dvander@22
   527
            singleByteOp(OP_SETREF_F);
dvander@22
   528
        }
dvander@14
   529
    }
dvander@33
   530
    void object(Handle<Object> obj) {
dvander@21
   531
        ensure(OP_OBJECT_LENGTH);
dvander@21
   532
        writeOp(OP_OBJECT);
dvander@21
   533
        writeObject(obj);
dvander@47
   534
        markOop(1);
dvander@21
   535
    }
dvander@152
   536
    void copyarray() {
dvander@152
   537
        singleByteOp(OP_COPYARRAY);
dvander@152
   538
        markOop(1);
dvander@152
   539
    }
dvander@152
   540
    void copystruct() {
dvander@152
   541
        singleByteOp(OP_COPYSTRUCT);
dvander@47
   542
        markOop(1);
dvander@21
   543
    }
dvander@194
   544
    void sizeof_() {
dvander@194
   545
        singleByteOp(OP_SIZEOF);
dvander@194
   546
    }
dvander@47
   547
dvander@22
   548
    void dup() {
dvander@47
   549
        bool oop = getOop(1);
dvander@22
   550
        singleByteOp(OP_DUP);
dvander@47
   551
        markOop(1, oop);
dvander@22
   552
    }
dvander@22
   553
    void dup2() {
dvander@47
   554
        bool oop2 = getOop(2);
dvander@47
   555
        bool oop1 = getOop(1);
dvander@47
   556
dvander@22
   557
        singleByteOp(OP_DUP2);
dvander@47
   558
dvander@47
   559
        markOop(2, oop2);
dvander@47
   560
        markOop(1, oop1);
dvander@22
   561
    }
dvander@23
   562
    void swap() {
dvander@47
   563
        bool oop2 = getOop(2);
dvander@47
   564
        bool oop1 = getOop(1);
dvander@47
   565
dvander@23
   566
        singleByteOp(OP_SWAP);
dvander@47
   567
dvander@47
   568
        markOop(2, oop1);
dvander@47
   569
        markOop(1, oop2);
dvander@23
   570
    }
dvander@23
   571
    void roll3() {
dvander@47
   572
        bool oop3 = getOop(3);
dvander@47
   573
        bool oop2 = getOop(2);
dvander@47
   574
        bool oop1 = getOop(1);
dvander@47
   575
dvander@23
   576
        singleByteOp(OP_ROLL3);
dvander@47
   577
dvander@47
   578
        markOop(3, oop2);
dvander@47
   579
        markOop(2, oop1);
dvander@47
   580
        markOop(1, oop3);
dvander@23
   581
    }
dvander@23
   582
    void pick2() {
dvander@47
   583
        bool oop2 = getOop(2);
dvander@47
   584
        bool oop1 = getOop(1);
dvander@47
   585
dvander@23
   586
        singleByteOp(OP_PICK2);
dvander@47
   587
dvander@47
   588
        markOop(3, oop2);
dvander@47
   589
        markOop(2, oop1);
dvander@47
   590
        markOop(1, oop2);
dvander@23
   591
    }
dvander@23
   592
    void pick3() {
dvander@47
   593
        bool oop3 = getOop(3);
dvander@47
   594
        bool oop2 = getOop(2);
dvander@47
   595
        bool oop1 = getOop(1);
dvander@47
   596
dvander@23
   597
        singleByteOp(OP_PICK3);
dvander@47
   598
dvander@47
   599
        markOop(4, oop3);
dvander@47
   600
        markOop(3, oop2);
dvander@47
   601
        markOop(2, oop1);
dvander@47
   602
        markOop(1, oop3);
dvander@47
   603
    }
dvander@47
   604
dvander@72
   605
    void returnvoid() {
dvander@72
   606
        singleByteOp(OP_RETURNVOID);
dvander@72
   607
    }
dvander@78
   608
    void bitnot() {
dvander@78
   609
        singleByteOp(OP_BITNOT);
dvander@78
   610
    }
dvander@79
   611
    void not_() {
dvander@79
   612
        singleByteOp(OP_NOT);
dvander@79
   613
    }
dvander@79
   614
    void not_f() {
dvander@79
   615
        singleByteOp(OP_NOT_F);
dvander@79
   616
    }
dvander@80
   617
    void neg() {
dvander@80
   618
        singleByteOp(OP_NEG);
dvander@80
   619
    }
dvander@80
   620
    void neg_f() {
dvander@80
   621
        singleByteOp(OP_NEG_F);
dvander@80
   622
    }
dvander@142
   623
    void bits_i2f() {
dvander@142
   624
        singleByteOp(OP_BITS_I2F);
dvander@142
   625
    }
dvander@142
   626
    void bits_f2i() {
dvander@142
   627
        singleByteOp(OP_BITS_F2I);
dvander@142
   628
    }
dvander@143
   629
    void true_() {
dvander@143
   630
        singleByteOp(OP_TRUE);
dvander@143
   631
    }
dvander@143
   632
    void false_() {
dvander@143
   633
        singleByteOp(OP_FALSE);
dvander@143
   634
    }
dvander@195
   635
    
dvander@195
   636
    unsigned addString(Handle<String> name) {
dvander@195
   637
        unsigned index;
dvander@195
   638
        if (!strings_.add(name, &index)) {
dvander@195
   639
            oom_ |= true;
dvander@195
   640
            return 0;
dvander@195
   641
        }
dvander@195
   642
        return index;
dvander@195
   643
    }
dvander@195
   644
dvander@195
   645
    void getglobal(Symbol *sym);
dvander@195
   646
    void setglobal(Symbol *sym);
dvander@195
   647
dvander@195
   648
    void public_() {
dvander@195
   649
        recordOops();
dvander@195
   650
        singleByteOp(OP_PUBLIC);
dvander@195
   651
    }
dvander@72
   652
dvander@172
   653
    void tableswitch(int low, int high, Label *def, Label **labels) {
dvander@172
   654
        unsigned tablesize = TableSwitchEntries(low, high);
dvander@172
   655
        assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
dvander@172
   656
dvander@172
   657
        ensure(OP_TABLESWITCH_LENGTH);
dvander@172
   658
        writeOp(OP_TABLESWITCH);
dvander@172
   659
        writeInt32(low);
dvander@172
   660
        writeInt32(high);
dvander@172
   661
        jump(def);
dvander@172
   662
dvander@172
   663
        // When labels are patched, we assume each position is a jump. Rather
dvander@172
   664
        // than hack position offsets to make labels work without actual
dvander@172
   665
        // incoming jumps, we emit a jump inline.
dvander@172
   666
        for (unsigned i = 0; i < tablesize; i++)
dvander@172
   667
            jump(labels[i]);
dvander@172
   668
    }
dvander@172
   669
dvander@195
   670
    bool allocate(VariableSymbol *sym);
dvander@195
   671
dvander@195
   672
    Code *finish();
dvander@195
   673
dvander@47
   674
    // Helpers.
dvander@195
   675
#if 0
dvander@47
   676
    void get(Variable *var) {
dvander@47
   677
        if (var->location() == Variable::STACK) {
dvander@47
   678
            getlocal(var);
dvander@47
   679
        } else {
dvander@47
   680
            assert(var->location() == Variable::PARAMETER);
dvander@47
   681
            getarg(var);
dvander@47
   682
        }
dvander@47
   683
    }
dvander@47
   684
    void set(Variable *var) {
dvander@47
   685
        assert(!var->type()->isReference());
dvander@47
   686
        if (var->location() == Variable::STACK) {
dvander@47
   687
            setlocal(var);
dvander@47
   688
        } else {
dvander@47
   689
            assert(var->location() == Variable::PARAMETER);
dvander@47
   690
            setarg(var);
dvander@47
   691
        }
dvander@23
   692
    }
dvander@195
   693
#endif
dvander@0
   694
};
dvander@0
   695
dvander@0
   696
}
dvander@0
   697
dvander@0
   698
#endif // _include_bytecode_emitter_h_