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