jitcraft/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jun 30 22:45:25 2012 -0700 (2012-06-30)
changeset 16 23627f8bc421
parent 14 0784ac5cc347
child 17 8aa89dd41e25
permissions -rw-r--r--
Added support for arbitrary expression references.
dvander@0
     1
/*
dvander@0
     2
 * Copyright (C) 2012 David Anderson
dvander@0
     3
 *
dvander@0
     4
 * This file is part of JITCraft.
dvander@0
     5
 *
dvander@0
     6
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@0
     7
 * the terms of the GNU General Public License as published by the Free
dvander@0
     8
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@0
     9
 * any later version.
dvander@0
    10
 * 
dvander@0
    11
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@0
    12
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@0
    13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@0
    14
 *
dvander@0
    15
 * You should have received a copy of the GNU General Public License along with
dvander@0
    16
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@0
    17
 */
dvander@0
    18
#include "Interpreter.h"
dvander@0
    19
#include "Modules.h"
dvander@0
    20
#include "Zone.h"
dvander@0
    21
#include "Types.h"
dvander@12
    22
#include "Array.h"
dvander@14
    23
#include "Reference.h"
dvander@0
    24
dvander@0
    25
using namespace jc;
dvander@0
    26
dvander@0
    27
#define PUSH_I32(top, value)    \
dvander@0
    28
    do {                        \
dvander@0
    29
        top.sp->i32 = value;    \
dvander@0
    30
        top.sp++;               \
dvander@0
    31
   } while (0)
dvander@0
    32
dvander@4
    33
#define PUSH_F(top, value)      \
dvander@4
    34
    do {                        \
dvander@4
    35
        top.sp->f = value;      \
dvander@4
    36
        top.sp++;               \
dvander@4
    37
   } while (0)
dvander@4
    38
dvander@0
    39
static inline int
dvander@0
    40
POP_I32(Top &top)
dvander@0
    41
{
dvander@0
    42
    int value = top.sp[-1].i32;
dvander@0
    43
    top.sp--;
dvander@0
    44
    return value;
dvander@0
    45
}
dvander@0
    46
dvander@4
    47
static inline float
dvander@4
    48
POP_F(Top &top)
dvander@4
    49
{
dvander@4
    50
    float value = top.sp[-1].f;
dvander@4
    51
    top.sp--;
dvander@4
    52
    return value;
dvander@4
    53
}
dvander@4
    54
dvander@0
    55
static inline bool
dvander@14
    56
PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
dvander@14
    57
{
dvander@14
    58
    Reference *ref = Reference::NewStack(zone, location, tenure);
dvander@14
    59
    if (!ref)
dvander@14
    60
        return false;
dvander@14
    61
    top.sp->ref = ref;
dvander@14
    62
    top.sp++;
dvander@14
    63
    return true;
dvander@14
    64
}
dvander@14
    65
dvander@14
    66
static inline bool
dvander@0
    67
CheckDimensionSize(int size, unsigned width)
dvander@0
    68
{
dvander@0
    69
    if (size <= 0) {
dvander@0
    70
        assert(false);
dvander@0
    71
        return false;
dvander@0
    72
    }
dvander@0
    73
    // One  word, because we hide stuff below and need to add that in.
dvander@0
    74
    if (unsigned(size) >= (INT_MAX / width) - sizeof(unsigned)) {
dvander@0
    75
        assert(false);
dvander@0
    76
        return false;
dvander@0
    77
    }
dvander@0
    78
    return true;
dvander@0
    79
}
dvander@0
    80
dvander@12
    81
// Generate an array with completely static sizes.
dvander@12
    82
static Array *
dvander@12
    83
GenerateArray(Zone *zone, ArrayMap *map)
dvander@0
    84
{
dvander@12
    85
    assert(map->type()->elements() != -1);
dvander@0
    86
dvander@12
    87
    // :TODO: use Local
dvander@12
    88
    Array *array = Array::New(zone, map, map->type()->elements(), Heap::Tenure_Stack);
dvander@12
    89
    if (!array)
dvander@0
    90
        return NULL;
dvander@0
    91
dvander@12
    92
    if (map->type()->levels() == 1)
dvander@12
    93
        return array;
dvander@0
    94
dvander@12
    95
    for (unsigned i = 0; i < unsigned(map->type()->elements()); i++) {
dvander@12
    96
        Array *sub = GenerateArray(zone, map->contained());
dvander@12
    97
        if (!sub)
dvander@0
    98
            return NULL;
dvander@12
    99
        array->writeObject(zone, i, sub);
dvander@0
   100
    }
dvander@0
   101
dvander@12
   102
    return array;
dvander@0
   103
}
dvander@0
   104
dvander@0
   105
bool
dvander@4
   106
jc::Interpret(Frame *frame, LocalSlot *result)
dvander@0
   107
{
dvander@0
   108
    Top &top = *ZONE()->stack().top();
dvander@0
   109
    LocalSlot *locals = frame->locals();
dvander@0
   110
dvander@0
   111
    for (;;) {
dvander@0
   112
        Opcode op = Opcode(*top.pc);
dvander@0
   113
        switch (op) {
dvander@0
   114
dvander@0
   115
case OP_NOP:
dvander@0
   116
    break;
dvander@0
   117
dvander@0
   118
case OP_INT:
dvander@0
   119
    PUSH_I32(top, READ_INT32(top.pc));
dvander@0
   120
    break;
dvander@0
   121
dvander@4
   122
case OP_FLOAT:
dvander@4
   123
    PUSH_F(top, READ_FLOAT(top.pc));
dvander@4
   124
    break;
dvander@4
   125
dvander@0
   126
case OP_RETURN:
dvander@0
   127
{
dvander@4
   128
    *result = *--top.sp;
dvander@4
   129
    if (!frame->prev())
dvander@0
   130
        return true;
dvander@0
   131
dvander@0
   132
    frame = ZONE()->stack().popFrame(frame);
dvander@0
   133
    locals = frame->locals();
dvander@4
   134
    *top.sp++ = *result;
dvander@0
   135
    top.pc += OpcodeInfo[*top.pc].length;
dvander@0
   136
    continue;
dvander@0
   137
}
dvander@0
   138
dvander@0
   139
#define RELATIONAL_JUMP(op)                 \
dvander@0
   140
    {                                       \
dvander@0
   141
        int right = POP_I32(top);           \
dvander@0
   142
        int left = POP_I32(top);            \
dvander@0
   143
        if (left op right) {                \
dvander@0
   144
            top.pc += READ_INT32(top.pc);   \
dvander@0
   145
            continue;                       \
dvander@0
   146
        }                                   \
dvander@0
   147
    }
dvander@0
   148
dvander@0
   149
case OP_JL:
dvander@0
   150
    RELATIONAL_JUMP(<);
dvander@0
   151
    break;
dvander@0
   152
dvander@0
   153
case OP_JLE:
dvander@0
   154
    RELATIONAL_JUMP(<=);
dvander@0
   155
    break;
dvander@0
   156
dvander@0
   157
case OP_JG:
dvander@0
   158
    RELATIONAL_JUMP(>);
dvander@0
   159
    break;
dvander@0
   160
dvander@0
   161
case OP_JGE:
dvander@0
   162
    RELATIONAL_JUMP(>=);
dvander@0
   163
    break;
dvander@0
   164
dvander@0
   165
case OP_JEQ:
dvander@0
   166
    RELATIONAL_JUMP(==);
dvander@0
   167
    break;
dvander@0
   168
dvander@0
   169
case OP_JNE:
dvander@0
   170
    RELATIONAL_JUMP(!=);
dvander@0
   171
    break;
dvander@0
   172
dvander@0
   173
case OP_JT:
dvander@0
   174
{
dvander@0
   175
    int value = POP_I32(top);
dvander@0
   176
    if (value) {
dvander@0
   177
        top.pc += READ_INT32(top.pc);
dvander@0
   178
        continue;
dvander@0
   179
    }
dvander@0
   180
    break;
dvander@0
   181
}
dvander@0
   182
dvander@0
   183
case OP_JF:
dvander@0
   184
{
dvander@0
   185
    int value = POP_I32(top);
dvander@0
   186
    if (!value) {
dvander@0
   187
        top.pc += READ_INT32(top.pc);
dvander@0
   188
        continue;
dvander@0
   189
    }
dvander@0
   190
    break;
dvander@0
   191
}
dvander@0
   192
dvander@0
   193
case OP_JUMP:
dvander@0
   194
    top.pc += READ_INT32(top.pc);
dvander@0
   195
    continue;
dvander@0
   196
dvander@0
   197
case OP_GETLOCAL:
dvander@0
   198
{
dvander@0
   199
    int slot = READ_INT32(top.pc);
dvander@0
   200
    *top.sp++ = locals[slot];
dvander@0
   201
    break;
dvander@0
   202
}
dvander@0
   203
dvander@0
   204
case OP_SETLOCAL:
dvander@0
   205
{
dvander@0
   206
    int slot = READ_INT32(top.pc);
dvander@0
   207
    locals[slot] = top.sp[-1];
dvander@0
   208
    break;
dvander@0
   209
}
dvander@0
   210
dvander@0
   211
case OP_ADD:
dvander@0
   212
{
dvander@0
   213
    int right = POP_I32(top);
dvander@0
   214
    int left = POP_I32(top);
dvander@0
   215
    int result = left + right;
dvander@0
   216
    PUSH_I32(top, result);
dvander@0
   217
    break;
dvander@0
   218
}
dvander@0
   219
dvander@0
   220
case OP_SUB:
dvander@0
   221
{
dvander@0
   222
    int right = POP_I32(top);
dvander@0
   223
    int left = POP_I32(top);
dvander@0
   224
    int result = left - right;
dvander@0
   225
    PUSH_I32(top, result);
dvander@0
   226
    break;
dvander@0
   227
}
dvander@0
   228
dvander@0
   229
case OP_MUL:
dvander@0
   230
{
dvander@0
   231
    int right = POP_I32(top);
dvander@0
   232
    int left = POP_I32(top);
dvander@0
   233
    int result = left * right;
dvander@0
   234
   PUSH_I32(top, result);
dvander@0
   235
    break;
dvander@0
   236
}
dvander@0
   237
dvander@0
   238
case OP_DIV:
dvander@0
   239
{
dvander@0
   240
    int right = POP_I32(top);
dvander@0
   241
    int left = POP_I32(top);
dvander@0
   242
    if (!right)
dvander@0
   243
        return false;
dvander@0
   244
    int result = left / right;
dvander@0
   245
    PUSH_I32(top, result);
dvander@0
   246
    break;
dvander@0
   247
}
dvander@0
   248
dvander@4
   249
case OP_ADD_F:
dvander@4
   250
{
dvander@4
   251
    float right = POP_F(top);
dvander@4
   252
    float left = POP_F(top);
dvander@4
   253
    float result = left + right;
dvander@4
   254
    PUSH_F(top, result);
dvander@4
   255
    break;
dvander@4
   256
}
dvander@4
   257
dvander@4
   258
case OP_SUB_F:
dvander@4
   259
{
dvander@4
   260
    float right = POP_F(top);
dvander@4
   261
    float left = POP_F(top);
dvander@4
   262
    float result = left - right;
dvander@4
   263
    PUSH_F(top, result);
dvander@4
   264
    break;
dvander@4
   265
}
dvander@4
   266
dvander@4
   267
case OP_MUL_F:
dvander@4
   268
{
dvander@4
   269
    float right = POP_F(top);
dvander@4
   270
    float left = POP_F(top);
dvander@4
   271
    float result = left * right;
dvander@4
   272
    PUSH_F(top, result);
dvander@4
   273
    break;
dvander@4
   274
}
dvander@4
   275
dvander@4
   276
case OP_DIV_F:
dvander@4
   277
{
dvander@4
   278
    float right = POP_F(top);
dvander@4
   279
    float left = POP_F(top);
dvander@4
   280
    if (!right)
dvander@4
   281
        return false;
dvander@4
   282
    float result = left / right;
dvander@4
   283
    PUSH_F(top, result);
dvander@4
   284
    break;
dvander@4
   285
}
dvander@4
   286
dvander@8
   287
case OP_SHL:
dvander@8
   288
{
dvander@8
   289
    int right = POP_I32(top);
dvander@8
   290
    int left = POP_I32(top);
dvander@8
   291
    int result = left << right;
dvander@8
   292
    PUSH_I32(top, result);
dvander@8
   293
    break;
dvander@8
   294
}
dvander@8
   295
dvander@8
   296
case OP_SHR:
dvander@8
   297
{
dvander@8
   298
    int right = POP_I32(top);
dvander@8
   299
    int left = POP_I32(top);
dvander@8
   300
    int result = left >> right;
dvander@8
   301
    PUSH_I32(top, result);
dvander@8
   302
    break;
dvander@8
   303
}
dvander@8
   304
dvander@8
   305
case OP_USHR:
dvander@8
   306
{
dvander@8
   307
    int right = POP_I32(top);
dvander@8
   308
    int left = POP_I32(top);
dvander@8
   309
    int result = unsigned(left) >> unsigned(right);
dvander@8
   310
    PUSH_I32(top, result);
dvander@8
   311
    break;
dvander@8
   312
}
dvander@8
   313
dvander@8
   314
case OP_BITAND:
dvander@8
   315
{
dvander@8
   316
    int right = POP_I32(top);
dvander@8
   317
    int left = POP_I32(top);
dvander@8
   318
    int result = left & right;
dvander@8
   319
    PUSH_I32(top, result);
dvander@8
   320
    break;
dvander@8
   321
}
dvander@8
   322
dvander@8
   323
case OP_BITOR:
dvander@8
   324
{
dvander@8
   325
    int right = POP_I32(top);
dvander@8
   326
    int left = POP_I32(top);
dvander@8
   327
    int result = left | right;
dvander@8
   328
    PUSH_I32(top, result);
dvander@8
   329
    break;
dvander@8
   330
}
dvander@8
   331
dvander@8
   332
case OP_BITXOR:
dvander@8
   333
{
dvander@8
   334
    int right = POP_I32(top);
dvander@8
   335
    int left = POP_I32(top);
dvander@8
   336
    int result = left ^ right;
dvander@8
   337
    PUSH_I32(top, result);
dvander@8
   338
    break;
dvander@8
   339
}
dvander@8
   340
dvander@0
   341
case OP_POP:
dvander@0
   342
    top.sp--;
dvander@0
   343
    break;
dvander@0
   344
dvander@0
   345
case OP_STOP:
dvander@0
   346
    assert(false);
dvander@0
   347
    break;
dvander@0
   348
dvander@0
   349
case OP_CALLGLOBAL:
dvander@0
   350
{
dvander@0
   351
    unsigned argc = READ_UINT32(top.pc);
dvander@0
   352
    unsigned index = READ_UINT32(top.pc + 4);
dvander@0
   353
    Code *newCode = frame->code()->module()->getFunction(index);
dvander@0
   354
    frame = ZONE()->stack().pushFrame(frame, newCode);
dvander@0
   355
    assert(frame);
dvander@0
   356
    assert(newCode->nargs() == argc);
dvander@0
   357
dvander@0
   358
    locals = frame->locals();
dvander@0
   359
    continue;
dvander@0
   360
}
dvander@0
   361
dvander@0
   362
case OP_GETARG:
dvander@0
   363
{
dvander@0
   364
    unsigned slot = READ_UINT32(top.pc);
dvander@0
   365
    *top.sp++ = frame->arg(slot);
dvander@0
   366
    break;
dvander@0
   367
}
dvander@0
   368
dvander@0
   369
case OP_SETARG:
dvander@0
   370
{
dvander@0
   371
    unsigned slot = READ_UINT32(top.pc);
dvander@0
   372
    frame->arg(slot) = *--top.sp;
dvander@0
   373
    break;
dvander@0
   374
}
dvander@0
   375
dvander@0
   376
case OP_BOUNDS_STA:
dvander@0
   377
{
dvander@12
   378
    Array *array = top.sp[-2].array;
dvander@0
   379
    int index = top.sp[-1].i32;
dvander@12
   380
    if (index < 0 || unsigned(index) >= array->nelements())
dvander@0
   381
        return false;
dvander@0
   382
    break;
dvander@0
   383
}
dvander@0
   384
dvander@6
   385
case OP_GETARRAY_I:
dvander@0
   386
{
dvander@12
   387
    Array *array = top.sp[-2].array;
dvander@0
   388
    int index = top.sp[-1].i32;
dvander@0
   389
    top.sp[-2].i32 = array->readInt32(index);
dvander@0
   390
    top.sp--;
dvander@0
   391
    break;
dvander@0
   392
}
dvander@0
   393
dvander@7
   394
case OP_GETARRAY_F:
dvander@7
   395
{
dvander@12
   396
    Array *array = top.sp[-2].array;
dvander@7
   397
    int index = top.sp[-1].i32;
dvander@7
   398
    top.sp[-2].f = array->readFloat(index);
dvander@7
   399
    top.sp--;
dvander@7
   400
    break;
dvander@7
   401
}
dvander@7
   402
dvander@6
   403
case OP_SETARRAY_I:
dvander@0
   404
{
dvander@12
   405
    Array *array = top.sp[-3].array;
dvander@0
   406
    int index = top.sp[-2].i32;
dvander@0
   407
    array->writeInt32(index, top.sp[-1].i32);
dvander@0
   408
    top.sp[-3] = top.sp[-1];
dvander@0
   409
    top.sp -= 2;
dvander@0
   410
    break;
dvander@0
   411
}
dvander@0
   412
dvander@7
   413
case OP_SETARRAY_F:
dvander@7
   414
{
dvander@12
   415
    Array *array = top.sp[-3].array;
dvander@7
   416
    int index = top.sp[-2].i32;
dvander@7
   417
    array->writeFloat(index, top.sp[-1].f);
dvander@7
   418
    top.sp[-3] = top.sp[-1];
dvander@7
   419
    top.sp -= 2;
dvander@7
   420
    break;
dvander@7
   421
}
dvander@7
   422
dvander@6
   423
case OP_GETARRAY_P:
dvander@0
   424
{
dvander@12
   425
    Array *array = top.sp[-2].array;
dvander@0
   426
    int index = top.sp[-1].i32;
dvander@12
   427
    top.sp[-2].array = Array::cast(array->readObject(index));
dvander@0
   428
    top.sp--;
dvander@0
   429
    break;
dvander@0
   430
}
dvander@0
   431
dvander@4
   432
case OP_CVT_I2F:
dvander@4
   433
{
dvander@4
   434
    int ival = POP_I32(top);
dvander@4
   435
    float fval = (float)ival;
dvander@4
   436
    PUSH_F(top, fval);
dvander@4
   437
    break;
dvander@4
   438
}
dvander@4
   439
dvander@12
   440
case OP_LIFOARRAY:
dvander@12
   441
{
dvander@12
   442
    // :TODO: use Local
dvander@12
   443
    ArrayMap *map = ArrayMap::cast(frame->code()->map(READ_UINT32(top.pc)));
dvander@12
   444
    Array *array = GenerateArray(ZONE(), map);
dvander@12
   445
    if (!array) {
dvander@12
   446
        assert(false);
dvander@12
   447
        return false;
dvander@12
   448
    }
dvander@12
   449
    top.sp->obj = array;
dvander@12
   450
    top.sp++;
dvander@12
   451
    break;
dvander@12
   452
}
dvander@12
   453
dvander@12
   454
case OP_SAVELIFO:
dvander@10
   455
{
dvander@10
   456
    unsigned slot = READ_UINT32(top.pc);
dvander@12
   457
    locals[slot].address = ZONE()->heap().lifoPosition();
dvander@12
   458
    break;
dvander@12
   459
}
dvander@12
   460
dvander@12
   461
case OP_UNWINDLIFO:
dvander@12
   462
{
dvander@12
   463
    unsigned slot = READ_UINT32(top.pc);
dvander@12
   464
    ZONE()->heap().unwindLifo(locals[slot].address);
dvander@10
   465
    break;
dvander@10
   466
}
dvander@10
   467
dvander@14
   468
case OP_VARREF_LIFO:
dvander@14
   469
{
dvander@14
   470
    unsigned slot = READ_UINT32(top.pc);
dvander@14
   471
    if (!PushNewRef(ZONE(), top, &locals[slot], Heap::Tenure_Stack)) {
dvander@14
   472
        assert(false);
dvander@14
   473
        return false;
dvander@14
   474
    }
dvander@14
   475
    break;
dvander@14
   476
}
dvander@14
   477
dvander@14
   478
case OP_ARGREF_LIFO:
dvander@14
   479
{
dvander@14
   480
    unsigned slot = READ_UINT32(top.pc);
dvander@14
   481
    if (!PushNewRef(ZONE(), top, &frame->arg(slot), Heap::Tenure_Stack)) {
dvander@14
   482
        assert(false);
dvander@14
   483
        return false;
dvander@14
   484
    }
dvander@14
   485
    break;
dvander@14
   486
}
dvander@14
   487
dvander@16
   488
case OP_SLOTREF_LIFO:
dvander@16
   489
{
dvander@16
   490
    Reference *ref = Reference::NewStack(ZONE(),  top.sp[-1], Heap::Tenure_Stack);
dvander@16
   491
    if (!ref) {
dvander@16
   492
        assert(false);
dvander@16
   493
        return false;
dvander@16
   494
    }
dvander@16
   495
    top.sp[-1].ref = ref;
dvander@16
   496
    break;
dvander@16
   497
}
dvander@16
   498
dvander@14
   499
case OP_GETREF_I:
dvander@14
   500
{
dvander@14
   501
    top.sp[-1].i32 = top.sp[-1].ref->getInt();
dvander@14
   502
    break;
dvander@14
   503
}
dvander@14
   504
dvander@14
   505
case OP_SETREF_I:
dvander@14
   506
{
dvander@14
   507
    top.sp[-2].ref->setInt(top.sp[-1].i32);
dvander@14
   508
    top.sp[-2].i32 = top.sp[-1].i32;
dvander@14
   509
    break;
dvander@14
   510
}
dvander@14
   511
dvander@14
   512
case OP_GETREF_F:
dvander@14
   513
{
dvander@14
   514
    top.sp[-1].f = top.sp[-1].ref->getFloat();
dvander@14
   515
    break;
dvander@14
   516
}
dvander@14
   517
dvander@14
   518
case OP_SETREF_F:
dvander@14
   519
{
dvander@14
   520
    top.sp[-2].ref->setFloat(top.sp[-1].f);
dvander@14
   521
    top.sp[-2].f = top.sp[-1].f;
dvander@14
   522
    break;
dvander@14
   523
}
dvander@14
   524
dvander@0
   525
default:
dvander@0
   526
    assert(false);
dvander@0
   527
    return false;
dvander@0
   528
dvander@0
   529
        }
dvander@0
   530
dvander@0
   531
        top.pc += OpcodeInfo[op].length;
dvander@0
   532
    }
dvander@0
   533
dvander@0
   534
    return true;
dvander@0
   535
}