jitcraft/Opcodes.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 15 19:48:15 2012 -0700 (2012-07-15)
changeset 74 80e29e23eb4e
parent 73 ef5492aa8d8b
child 78 93e0a19c805a
permissions -rw-r--r--
Added full comparator support.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include <stdlib.h>
    20 #include "Opcodes.h"
    21 #include "Utility.h"
    22 #include "Code.h"
    23 #include "Zone.h"
    24 #include "Array.h"
    25 #include "Strings.h"
    26 #include "CompactBuffer.h"
    27 #include "Heap-inl.h"
    28 
    29 using namespace ke;
    30 
    31 OpInfo ke::OpcodeInfo[] =
    32 {
    33 #define OPDEF(name, number, text, length, uses, defs) \
    34     {text, length, uses, defs},
    35 #include "Opcodes.tbl"
    36 #undef OPDEF
    37 };
    38 
    39 Code *
    40 Code::New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
    41           Handle<FixedArray> objects, unsigned maxStackDepth, Handle<Module> module,
    42 	      Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap,
    43           unsigned lineNumber)
    44 {
    45     Local<Code> code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old)));
    46     if (!code)
    47         return NULL;
    48 
    49     code->bytecode_ = bytecode;
    50     code->locals_ = locals;
    51     code->objects_ = objects;
    52     code->maxStackDepth_ = maxStackDepth;
    53     code->module_ = module;
    54     code->safepoints_ = safepoints;
    55     code->sourcemap_ = sourcemap;
    56     code->lineNumber_ = lineNumber;
    57     return code;
    58 }
    59 
    60 static int
    61 CompareSafepoints(const void *a, const void *b)
    62 {
    63     const unsigned *sa = reinterpret_cast<const unsigned *>(a);
    64     const unsigned *sb = reinterpret_cast<const unsigned *>(b);
    65     if (*sa > *sb)
    66         return 1;
    67     if (*sa == *sb)
    68         return 0;
    69     return -1;
    70 }
    71 
    72 uint8 *
    73 Code::safepointAt(unsigned pcOffset)
    74 {
    75     // Only specific opcodes may have safepoints. Asking for a safepoint at
    76     // any other position indicates a failure to mark that position as a
    77     // safepoint, which is a bug.
    78     Opcode op = Opcode(*(start() + pcOffset));
    79     assert(op == OP_CALL || op == OP_NEWARRAY_LIFO || op == OP_VARREF_LIFO ||
    80            op == OP_ARGREF_LIFO || op == OP_SLOTREF_LIFO || op == OP_ARRAYREF_LIFO ||
    81            op == OP_ARRAYCOPY);
    82 
    83     if (!safepoints_)
    84         return NULL;
    85 
    86     size_t bytesPerSafepoint = BytesPerSafepoint(maxStackDepth());
    87     assert(!(safepoints_->length() % bytesPerSafepoint));
    88 
    89     size_t count = safepoints_->length() / bytesPerSafepoint;
    90 
    91     void *result = bsearch(&pcOffset,
    92                            safepoints_->raw(),
    93                            count,
    94                            bytesPerSafepoint,
    95                            CompareSafepoints);
    96 
    97     if (!result)
    98         return NULL;
    99 
   100     assert(*reinterpret_cast<unsigned *>(result) == pcOffset);
   101 
   102     return Address(result) + sizeof(unsigned);
   103 }
   104 
   105 SourcePosition
   106 Code::pcToSource(unsigned pc)
   107 {
   108     assert(pc < bytecode_->length());
   109 
   110     CompactBufferReader reader(sourcemap_->raw(), sourcemap_->raw() + sourcemap_->length());
   111 
   112     unsigned line = 1;
   113     unsigned col = 0;
   114     unsigned curPc = 0;
   115     while (!reader.done()) {
   116         curPc += reader.readUint32();
   117         if (curPc > pc)
   118             break;
   119 
   120         line = reader.readUint32();
   121         col = reader.readUint32();
   122     }
   123 
   124     return SourcePosition(lineNumber_ + line, col);
   125 }
   126 
   127 // All jumps must be the same length.
   128 STATIC_ASSERT(OP_JL_LENGTH == OP_JUMP_LENGTH);
   129 STATIC_ASSERT(OP_JLE_LENGTH == OP_JUMP_LENGTH);
   130 STATIC_ASSERT(OP_JG_LENGTH == OP_JUMP_LENGTH);
   131 STATIC_ASSERT(OP_JGE_LENGTH == OP_JUMP_LENGTH);
   132 STATIC_ASSERT(OP_JEQ_LENGTH == OP_JUMP_LENGTH);
   133 STATIC_ASSERT(OP_JNE_LENGTH == OP_JUMP_LENGTH);
   134 STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH);
   135 STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH);
   136 
   137 void
   138 ke::Disassemble(Code *code, FILE *fp)
   139 {
   140     bytecode *pc = code->start();
   141     for (;;) {
   142         Opcode op = Opcode(*pc);
   143 
   144         fprintf(fp, "%-4d %s ", int(pc - code->start()), OpcodeInfo[op].name);
   145 
   146         switch (op) {
   147           case OP_NOP:
   148           case OP_RETURN:
   149           case OP_RETURNVOID:
   150           case OP_ADD:
   151           case OP_SUB:
   152           case OP_MUL:
   153           case OP_DIV:
   154           case OP_ADD_F:
   155           case OP_SUB_F:
   156           case OP_MUL_F:
   157           case OP_DIV_F:
   158           case OP_CVT_I2F:
   159           case OP_POP:
   160           case OP_GETARRAY_I:
   161           case OP_SETARRAY_I:
   162           case OP_GETARRAY_F:
   163           case OP_SETARRAY_F:
   164           case OP_GETARRAY_C:
   165           case OP_SETARRAY_C:
   166           case OP_GETARRAY_O:
   167           case OP_BOUNDS:
   168           case OP_SHL:
   169           case OP_SHR:
   170           case OP_USHR:
   171           case OP_BITAND:
   172           case OP_BITOR:
   173           case OP_BITXOR:
   174           case OP_GETREF_I:
   175           case OP_SETREF_I:
   176           case OP_GETREF_F:
   177           case OP_SETREF_F:
   178           case OP_SLOTREF_LIFO:
   179           case OP_ARRAYREF_LIFO:
   180           case OP_ARRAYCOPY:
   181           case OP_DUP:
   182           case OP_DUP2:
   183           case OP_SWAP:
   184           case OP_ROLL3:
   185           case OP_PICK2:
   186           case OP_PICK3:
   187           case OP_CALL:
   188           case OP_MODULE:
   189           case OP_LT:
   190           case OP_LE:
   191           case OP_GE:
   192           case OP_GT:
   193           case OP_EQ:
   194           case OP_NE:
   195           case OP_LT_F:
   196           case OP_LE_F:
   197           case OP_GE_F:
   198           case OP_GT_F:
   199           case OP_EQ_F:
   200           case OP_NE_F:
   201             break;
   202 
   203           case OP_STOP:
   204             fprintf(fp, "\n");
   205             break;
   206 
   207           case OP_INT:
   208             fprintf(fp, "%d", READ_INT32(pc));
   209             break;
   210 
   211           case OP_FLOAT:
   212             fprintf(fp, "%f", READ_FLOAT(pc));
   213             break;
   214 
   215           case OP_JL:
   216           case OP_JLE:
   217           case OP_JG:
   218           case OP_JGE:
   219           case OP_JEQ:
   220           case OP_JNE:
   221           case OP_JT:
   222           case OP_JF:
   223           case OP_JL_F:
   224           case OP_JLE_F:
   225           case OP_JG_F:
   226           case OP_JGE_F:
   227           case OP_JEQ_F:
   228           case OP_JNE_F:
   229           case OP_JT_F:
   230           case OP_JF_F:
   231           case OP_JUMP:
   232             fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc));
   233             break;
   234 
   235           case OP_NEWARRAY_LIFO:
   236           {
   237             ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc)));
   238             fprintf(fp, "%s:", map->type()->innermost()->tag()
   239                                ? map->type()->innermost()->tag()->chars()
   240                                : "_");
   241             for (; map; map = map->contained()) {
   242                 Type *type = map->type();
   243                 fprintf(fp, "[%d]", type->elements());
   244             }
   245             break;
   246           }
   247 
   248           case OP_GETLOCAL:
   249           case OP_SETLOCAL:
   250           case OP_GETARG:
   251           case OP_SETARG:
   252           case OP_SAVELIFO:
   253           case OP_UNWINDLIFO:
   254           case OP_VARREF_LIFO:
   255           case OP_ARGREF_LIFO:
   256           case OP_OBJECT:
   257           case OP_GETMODULE_FN:
   258             fprintf(fp, "%u", READ_UINT32(pc));
   259             break;
   260 
   261           case OP_CALLNATIVE:
   262             fprintf(fp, "%u %u", READ_UINT32(pc), READ_UINT32(pc + 4));
   263             break;
   264 
   265           default:
   266             // Unknown opcode!
   267             assert(false);
   268             return;
   269         }
   270 
   271         if (op == OP_STOP)
   272             break;
   273 
   274         fprintf(fp, "\n");
   275         pc += OpcodeInfo[op].length;
   276         assert(pc < code->start() + code->length());
   277     }
   278 
   279     fprintf(fp, "\nSafepoints:\n");
   280     ByteArray *safepoints = code->safepoints();
   281     if (safepoints) {
   282         size_t nsafepoints = safepoints->length() / Code::BytesPerSafepoint(code->maxStackDepth());
   283         for (size_t i = 0; i < nsafepoints; i++) {
   284             Address address = safepoints->raw() + Code::BytesPerSafepoint(code->maxStackDepth()) * i;
   285             fprintf(fp, "%4d: ", *reinterpret_cast<unsigned *>(address));
   286             unsigned char *bits = (unsigned char *)(address + sizeof(unsigned));
   287             for (unsigned j = 0; j < code->maxStackDepth(); j++) {
   288                 if (bits[j / 8] & (1 << (j % 8)))
   289                     fprintf(fp, "%d ", j);
   290             }
   291             fprintf(fp, "\n");
   292         }
   293     }
   294 }