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