src/Opcodes.cpp
author Asher Baker <asherkin@gmail.com>
Mon Jun 10 15:52:44 2013 +0100 (2013-06-10)
changeset 265 3a903b89a514
parent 263 ba85a47ee414
permissions -rw-r--r--
Fixed type checking for multidimensional arrays.
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
#include <stdlib.h>
asherkin@263
    20
#include "Opcodes.h"
asherkin@263
    21
#include "Utility.h"
asherkin@263
    22
#include "Code.h"
asherkin@263
    23
#include "Zone.h"
asherkin@263
    24
#include "Array.h"
asherkin@263
    25
#include "Strings.h"
asherkin@263
    26
#include "CompactBuffer.h"
asherkin@263
    27
#include "Structures.h"
asherkin@263
    28
#include "Modules.h"
asherkin@263
    29
#include "Heap-inl.h"
asherkin@263
    30
asherkin@263
    31
using namespace ke;
asherkin@263
    32
asherkin@263
    33
OpInfo ke::OpcodeInfo[] =
asherkin@263
    34
{
asherkin@263
    35
#define OPDEF(name, text, length, uses, defs) \
asherkin@263
    36
    {text, length, uses, defs},
asherkin@263
    37
#include "Opcodes.tbl"
asherkin@263
    38
#undef OPDEF
asherkin@263
    39
};
asherkin@263
    40
asherkin@263
    41
Code *
asherkin@263
    42
Code::New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
asherkin@263
    43
          Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
asherkin@263
    44
          unsigned maxLoopDepth, Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap)
asherkin@263
    45
{
asherkin@263
    46
    Local<Code> code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old)));
asherkin@263
    47
    if (!code)
asherkin@263
    48
        return NULL;
asherkin@263
    49
asherkin@263
    50
    code->bytecode_ = bytecode;
asherkin@263
    51
    code->locals_ = locals;
asherkin@263
    52
    code->objects_ = objects;
asherkin@263
    53
    code->maxStackDepth_ = maxStackDepth;
asherkin@263
    54
    code->module_ = NULL;
asherkin@263
    55
    code->safepoints_ = safepoints;
asherkin@263
    56
    code->sourcemap_ = sourcemap;
asherkin@263
    57
    code->lineNumber_ = 0;
asherkin@263
    58
    code->strings_ = strings;
asherkin@263
    59
    code->maxLoopDepth_ = maxLoopDepth;
asherkin@263
    60
    return code;
asherkin@263
    61
}
asherkin@263
    62
asherkin@263
    63
static int
asherkin@263
    64
CompareSafepoints(const void *a, const void *b)
asherkin@263
    65
{
asherkin@263
    66
    const unsigned *sa = reinterpret_cast<const unsigned *>(a);
asherkin@263
    67
    const unsigned *sb = reinterpret_cast<const unsigned *>(b);
asherkin@263
    68
    if (*sa > *sb)
asherkin@263
    69
        return 1;
asherkin@263
    70
    if (*sa == *sb)
asherkin@263
    71
        return 0;
asherkin@263
    72
    return -1;
asherkin@263
    73
}
asherkin@263
    74
asherkin@263
    75
uint8 *
asherkin@263
    76
Code::safepointAt(unsigned pcOffset)
asherkin@263
    77
{
asherkin@263
    78
    // Only specific opcodes may have safepoints. Asking for a safepoint at
asherkin@263
    79
    // any other position indicates a failure to mark that position as a
asherkin@263
    80
    // safepoint, which is a bug.
asherkin@263
    81
#ifndef NDEBUG
asherkin@263
    82
    Opcode op = Opcode(*(start() + pcOffset));
asherkin@263
    83
    assert(op == OP_CALL ||
asherkin@263
    84
           op == OP_NEWFIXED ||
asherkin@263
    85
           op == OP_NEWEMPTY ||
asherkin@263
    86
           op == OP_NEWSIZED ||
asherkin@263
    87
           op == OP_VARREF_LIFO ||
asherkin@263
    88
           op == OP_ARGREF_LIFO ||
asherkin@263
    89
           op == OP_SLOTREF_LIFO ||
asherkin@263
    90
           op == OP_COPYARRAY ||
asherkin@263
    91
           op == OP_CALLNATIVE ||
asherkin@263
    92
           op == OP_PUBLIC);
asherkin@263
    93
#endif
asherkin@263
    94
asherkin@263
    95
    if (!safepoints_)
asherkin@263
    96
        return NULL;
asherkin@263
    97
asherkin@263
    98
    size_t bytesPerSafepoint = BytesPerSafepoint(maxStackDepth());
asherkin@263
    99
    assert(!(safepoints_->length() % bytesPerSafepoint));
asherkin@263
   100
asherkin@263
   101
    size_t count = safepoints_->length() / bytesPerSafepoint;
asherkin@263
   102
asherkin@263
   103
    void *result = bsearch(&pcOffset,
asherkin@263
   104
                           safepoints_->raw(),
asherkin@263
   105
                           count,
asherkin@263
   106
                           bytesPerSafepoint,
asherkin@263
   107
                           CompareSafepoints);
asherkin@263
   108
asherkin@263
   109
    if (!result)
asherkin@263
   110
        return NULL;
asherkin@263
   111
asherkin@263
   112
    assert(*reinterpret_cast<unsigned *>(result) == pcOffset);
asherkin@263
   113
asherkin@263
   114
    return Address(result) + sizeof(unsigned);
asherkin@263
   115
}
asherkin@263
   116
asherkin@263
   117
SourcePosition
asherkin@263
   118
Code::pcToSource(unsigned pc)
asherkin@263
   119
{
asherkin@263
   120
    assert(pc < bytecode_->length());
asherkin@263
   121
asherkin@263
   122
    CompactBufferReader reader(sourcemap_->raw(), sourcemap_->raw() + sourcemap_->length());
asherkin@263
   123
asherkin@263
   124
    unsigned line = 1;
asherkin@263
   125
    unsigned col = 0;
asherkin@263
   126
    unsigned curPc = 0;
asherkin@263
   127
    while (!reader.done()) {
asherkin@263
   128
        curPc += reader.readUint32();
asherkin@263
   129
        if (curPc > pc)
asherkin@263
   130
            break;
asherkin@263
   131
asherkin@263
   132
        line = reader.readUint32();
asherkin@263
   133
        col = reader.readUint32();
asherkin@263
   134
    }
asherkin@263
   135
asherkin@263
   136
    return SourcePosition(lineNumber_ + line, col);
asherkin@263
   137
}
asherkin@263
   138
asherkin@263
   139
// All jumps must be the same length.
asherkin@263
   140
STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH);
asherkin@263
   141
STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH);
asherkin@263
   142
asherkin@263
   143
void
asherkin@263
   144
ke::Disassemble(Code *code, FILE *fp)
asherkin@263
   145
{
asherkin@263
   146
    bytecode *pc = code->start();
asherkin@263
   147
    for (;;) {
asherkin@263
   148
        Opcode op = Opcode(*pc);
asherkin@263
   149
asherkin@263
   150
        fprintf(fp, "%-4d %s ", int(pc - code->start()), OpcodeInfo[op].name);
asherkin@263
   151
asherkin@263
   152
        switch (op) {
asherkin@263
   153
          case OP_NOP:
asherkin@263
   154
          case OP_RETURN:
asherkin@263
   155
          case OP_RETURNVOID:
asherkin@263
   156
          case OP_ADD:
asherkin@263
   157
          case OP_SUB:
asherkin@263
   158
          case OP_MUL:
asherkin@263
   159
          case OP_DIV:
asherkin@263
   160
          case OP_ADD_F:
asherkin@263
   161
          case OP_SUB_F:
asherkin@263
   162
          case OP_MUL_F:
asherkin@263
   163
          case OP_DIV_F:
asherkin@263
   164
          case OP_CVT_I2F:
asherkin@263
   165
          case OP_CVT_I2B:
asherkin@263
   166
          case OP_POP:
asherkin@263
   167
          case OP_GETELEM:
asherkin@263
   168
          case OP_SETELEM:
asherkin@263
   169
          case OP_SHL:
asherkin@263
   170
          case OP_SHR:
asherkin@263
   171
          case OP_USHR:
asherkin@263
   172
          case OP_BITAND:
asherkin@263
   173
          case OP_BITOR:
asherkin@263
   174
          case OP_BITXOR:
asherkin@263
   175
          case OP_GETREF_I:
asherkin@263
   176
          case OP_SETREF_I:
asherkin@263
   177
          case OP_GETREF_F:
asherkin@263
   178
          case OP_SETREF_F:
asherkin@263
   179
          case OP_SLOTREF_LIFO:
asherkin@263
   180
          case OP_COPYARRAY:
asherkin@263
   181
          case OP_COPYSTRUCT:
asherkin@263
   182
          case OP_DUP:
asherkin@263
   183
          case OP_DUP2:
asherkin@263
   184
          case OP_SWAP:
asherkin@263
   185
          case OP_ROLL3:
asherkin@263
   186
          case OP_PICK2:
asherkin@263
   187
          case OP_PICK3:
asherkin@263
   188
          case OP_CALL:
asherkin@263
   189
          case OP_LT:
asherkin@263
   190
          case OP_LE:
asherkin@263
   191
          case OP_GE:
asherkin@263
   192
          case OP_GT:
asherkin@263
   193
          case OP_EQ:
asherkin@263
   194
          case OP_NE:
asherkin@263
   195
          case OP_LT_F:
asherkin@263
   196
          case OP_LE_F:
asherkin@263
   197
          case OP_GE_F:
asherkin@263
   198
          case OP_GT_F:
asherkin@263
   199
          case OP_EQ_F:
asherkin@263
   200
          case OP_NE_F:
asherkin@263
   201
          case OP_BITNOT:
asherkin@263
   202
          case OP_NOT:
asherkin@263
   203
          case OP_NOT_F:
asherkin@263
   204
          case OP_NEG:
asherkin@263
   205
          case OP_NEG_F:
asherkin@263
   206
          case OP_MOD:
asherkin@263
   207
          case OP_BITCAST:
asherkin@263
   208
          case OP_TRUE:
asherkin@263
   209
          case OP_FALSE:
asherkin@263
   210
          case OP_SIZEOF:
asherkin@263
   211
          case OP_PUBLIC:
asherkin@263
   212
          case OP_LEAVELOOP:
asherkin@263
   213
          case OP_DUPARRAY:
asherkin@263
   214
          case OP_DEPARRAY:
asherkin@263
   215
            break;
asherkin@263
   216
asherkin@263
   217
          case OP_ENTERLOOP:
asherkin@263
   218
            if (pc[1])
asherkin@263
   219
              fprintf(fp, "; lifo region");
asherkin@263
   220
            break;
asherkin@263
   221
asherkin@263
   222
          case OP_STOP:
asherkin@263
   223
            fprintf(fp, "\n");
asherkin@263
   224
            break;
asherkin@263
   225
asherkin@263
   226
          case OP_INT:
asherkin@263
   227
            fprintf(fp, "%d", READ_INT32(pc));
asherkin@263
   228
            break;
asherkin@263
   229
asherkin@263
   230
          case OP_FLOAT:
asherkin@263
   231
            fprintf(fp, "%f", READ_FLOAT(pc));
asherkin@263
   232
            break;
asherkin@263
   233
asherkin@263
   234
          case OP_JT:
asherkin@263
   235
          case OP_JF:
asherkin@263
   236
          case OP_JUMP:
asherkin@263
   237
          case OP_CONTINUE:
asherkin@263
   238
          case OP_BREAK:
asherkin@263
   239
            fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc));
asherkin@263
   240
            break;
asherkin@263
   241
asherkin@263
   242
          case OP_NEWFIXED:
asherkin@263
   243
          case OP_NEWEMPTY:
asherkin@263
   244
          case OP_NEWSIZED:
asherkin@263
   245
          {
asherkin@263
   246
            Heap::Tenure tenure = (Heap::Tenure)pc[1];
asherkin@263
   247
            //ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1)));
asherkin@263
   248
            if (tenure == Heap::Tenure_Stack)
asherkin@263
   249
                fprintf(fp, " ; lifo");
asherkin@263
   250
            else if (tenure == Heap::Tenure_Old)
asherkin@263
   251
                fprintf(fp, " ; pretenured");
asherkin@263
   252
            else if (tenure == Heap::Tenure_Default)
asherkin@263
   253
                fprintf(fp, " ; newborn");
asherkin@263
   254
            break;
asherkin@263
   255
          }
asherkin@263
   256
asherkin@263
   257
          case OP_NEWSTRUCT:
asherkin@263
   258
          {
asherkin@263
   259
            Heap::Tenure tenure = (Heap::Tenure)pc[1];
asherkin@263
   260
            StructMap *map = StructMap::cast(code->map(READ_UINT32(pc + 1)));
asherkin@263
   261
            fprintf(fp, "%s", StructType::cast(map->type())->name()->chars());
asherkin@263
   262
            if (tenure == Heap::Tenure_Stack)
asherkin@263
   263
                fprintf(fp, " ; lifo");
asherkin@263
   264
            else if (tenure == Heap::Tenure_Old)
asherkin@263
   265
                fprintf(fp, " ; pretenured");
asherkin@263
   266
            else if (tenure == Heap::Tenure_Default)
asherkin@263
   267
                fprintf(fp, " ; newborn");
asherkin@263
   268
            break;
asherkin@263
   269
          }
asherkin@263
   270
asherkin@263
   271
          case OP_GETLOCAL:
asherkin@263
   272
          case OP_SETLOCAL:
asherkin@263
   273
          case OP_GETARG:
asherkin@263
   274
          case OP_SETARG:
asherkin@263
   275
          case OP_SAVELIFO:
asherkin@263
   276
          case OP_UNWINDLIFO:
asherkin@263
   277
          case OP_VARREF_LIFO:
asherkin@263
   278
          case OP_ARGREF_LIFO:
asherkin@263
   279
          case OP_OBJECT:
asherkin@263
   280
          case OP_GETFIELD:
asherkin@263
   281
          case OP_SETFIELD:
asherkin@263
   282
            fprintf(fp, "%u", READ_UINT32(pc));
asherkin@263
   283
            break;
asherkin@263
   284
asherkin@263
   285
          case OP_CALLNATIVE:
asherkin@263
   286
          {
asherkin@263
   287
            unsigned argc = READ_UINT32(pc);
asherkin@263
   288
            fprintf(fp, " ; %u args", argc);
asherkin@263
   289
            break;
asherkin@263
   290
          }
asherkin@263
   291
asherkin@263
   292
          case OP_TABLESWITCH:
asherkin@263
   293
          {
asherkin@263
   294
            int low = READ_TABLESWITCH_LOW(pc);
asherkin@263
   295
            int high = READ_TABLESWITCH_HIGH(pc);
asherkin@263
   296
            fprintf(fp, "%d, %d\n", low, high);
asherkin@263
   297
            break;
asherkin@263
   298
          }
asherkin@263
   299
asherkin@263
   300
          case OP_GETGLOBAL:
asherkin@263
   301
          case OP_SETGLOBAL:
asherkin@263
   302
          {
asherkin@263
   303
            unsigned index = READ_UINT32(pc);
asherkin@263
   304
            fprintf(fp, "%s", String::cast(code->strings()->at(index))->chars());
asherkin@263
   305
            break;
asherkin@263
   306
          }
asherkin@263
   307
asherkin@263
   308
          case OP_IMPORT:
asherkin@263
   309
          {
asherkin@263
   310
            unsigned index = READ_UINT32(pc);
asherkin@263
   311
            FixedArray *path = code->module()->importPathAt(index);
asherkin@263
   312
            fprintf(fp, " ; ");
asherkin@263
   313
            for (unsigned i = 0; i < path->length(); i++) {
asherkin@263
   314
                fprintf(fp, "%s", String::cast(path->at(i))->chars());
asherkin@263
   315
                if (i != path->length() - 1)
asherkin@263
   316
                    fprintf(fp, ".");
asherkin@263
   317
            }
asherkin@263
   318
            break;
asherkin@263
   319
          }
asherkin@263
   320
asherkin@263
   321
          default:
asherkin@263
   322
            // Unknown opcode!
asherkin@263
   323
            assert(false);
asherkin@263
   324
            return;
asherkin@263
   325
        }
asherkin@263
   326
asherkin@263
   327
        if (op == OP_STOP)
asherkin@263
   328
            break;
asherkin@263
   329
asherkin@263
   330
        fprintf(fp, "\n");
asherkin@263
   331
        pc += OpcodeInfo[op].length;
asherkin@263
   332
        assert(pc < code->start() + code->length());
asherkin@263
   333
    }
asherkin@263
   334
asherkin@263
   335
    fprintf(fp, "\nSafepoints:\n");
asherkin@263
   336
    ByteArray *safepoints = code->safepoints();
asherkin@263
   337
    if (safepoints) {
asherkin@263
   338
        size_t nsafepoints = safepoints->length() / Code::BytesPerSafepoint(code->maxStackDepth());
asherkin@263
   339
        for (size_t i = 0; i < nsafepoints; i++) {
asherkin@263
   340
            Address address = safepoints->raw() + Code::BytesPerSafepoint(code->maxStackDepth()) * i;
asherkin@263
   341
            fprintf(fp, "%4d: ", *reinterpret_cast<unsigned *>(address));
asherkin@263
   342
            unsigned char *bits = (unsigned char *)(address + sizeof(unsigned));
asherkin@263
   343
            for (unsigned j = 0; j < code->maxStackDepth(); j++) {
asherkin@263
   344
                if (bits[j / 8] & (1 << (j % 8)))
asherkin@263
   345
                    fprintf(fp, "%d ", j);
asherkin@263
   346
            }
asherkin@263
   347
            fprintf(fp, "\n");
asherkin@263
   348
        }
asherkin@263
   349
    }
asherkin@263
   350
}