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