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