src/Interpreter.cpp
author David Anderson <dvander@alliedmods.net>
Sun Aug 05 00:31:20 2012 -0700 (2012-08-05)
changeset 154 a85a0303bcb8
parent 152 153d0cafc1fd
child 155 7926a7921fa3
permissions -rw-r--r--
Refactory array maps to allow arrays of structs.
dvander@39
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@39
     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
 */
danderson@91
    19
#include <string.h>
dvander@0
    20
#include "Interpreter.h"
dvander@0
    21
#include "Modules.h"
dvander@0
    22
#include "Zone.h"
dvander@0
    23
#include "Types.h"
dvander@12
    24
#include "Array.h"
dvander@14
    25
#include "Reference.h"
dvander@69
    26
#include "Strings.h"
dvander@85
    27
#include "Environments.h"
dvander@147
    28
#include "Structures.h"
dvander@28
    29
#include "Heap-inl.h"
dvander@0
    30
dvander@59
    31
using namespace ke;
dvander@0
    32
dvander@0
    33
#define PUSH_I32(top, value)    \
dvander@0
    34
    do {                        \
dvander@0
    35
        top.sp->i32 = value;    \
dvander@0
    36
        top.sp++;               \
dvander@0
    37
   } while (0)
dvander@0
    38
dvander@4
    39
#define PUSH_F(top, value)      \
dvander@4
    40
    do {                        \
dvander@4
    41
        top.sp->f = value;      \
dvander@4
    42
        top.sp++;               \
dvander@4
    43
   } while (0)
dvander@4
    44
dvander@0
    45
static inline int
dvander@0
    46
POP_I32(Top &top)
dvander@0
    47
{
dvander@0
    48
    int value = top.sp[-1].i32;
dvander@0
    49
    top.sp--;
dvander@0
    50
    return value;
dvander@0
    51
}
dvander@0
    52
dvander@4
    53
static inline float
dvander@4
    54
POP_F(Top &top)
dvander@4
    55
{
dvander@4
    56
    float value = top.sp[-1].f;
dvander@4
    57
    top.sp--;
dvander@4
    58
    return value;
dvander@4
    59
}
dvander@4
    60
dvander@77
    61
// Pawn's original semantics specify some kind of floor operation, so
dvander@77
    62
// (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
dvander@77
    63
// the upstream algorithm when constant folding. However the SourcePawn 1 JIT
dvander@77
    64
// does not. My guess is that Borja freaked out seeing the 13-instruction x86
dvander@77
    65
// sequence necessary to get this functionality (I vaguely recall a thread
dvander@77
    66
// where we discussed this with Mark Peter? But the ITB forums are gone...),
dvander@77
    67
// and we just decided to break the damn thing. So SP1 was inconsistent, but
dvander@77
    68
// we are not. And for completeness, we assert that the C compiler does the
dvander@77
    69
// right thing, since C89 leaves it unspecified.
dvander@77
    70
STATIC_ASSERT(8 / -3 == -2);
dvander@77
    71
STATIC_ASSERT(-8 / 3 == -2);
dvander@77
    72
dvander@0
    73
static inline bool
dvander@14
    74
PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
dvander@14
    75
{
dvander@14
    76
    Reference *ref = Reference::NewStack(zone, location, tenure);
dvander@14
    77
    if (!ref)
dvander@14
    78
        return false;
dvander@14
    79
    top.sp->ref = ref;
dvander@14
    80
    top.sp++;
dvander@14
    81
    return true;
dvander@14
    82
}
dvander@14
    83
dvander@152
    84
// Even though this function can fail, we immediately bail out, so it doesn't
dvander@152
    85
// matter if we've leaving things unrooted.
dvander@21
    86
static bool
dvander@21
    87
CopyArray(Zone *zone, Array *source, Array *dest)
dvander@21
    88
{
dvander@21
    89
    assert(source->type()->levels() == 1);
dvander@21
    90
    assert(dest->type()->levels() == 1);
dvander@21
    91
    assert(source->type()->contained()->primitive() ==
dvander@21
    92
           dest->type()->contained()->primitive());
dvander@21
    93
    assert(source->nelements() >= dest->nelements());
dvander@21
    94
    assert(dest->elementSize() == source->elementSize());
dvander@21
    95
dvander@21
    96
    memcpy(source->vec(), dest->vec(), dest->nelements() * dest->elementSize());
dvander@21
    97
    return true;
dvander@21
    98
}
dvander@21
    99
dvander@152
   100
static void
dvander@152
   101
GetField(Struct *obj, Descriptor *desc, LocalSlot *vp)
dvander@152
   102
{
dvander@152
   103
    // :TODO: assert no GC.
dvander@152
   104
    if (desc->type()->isTraceable()) {
dvander@152
   105
        vp->obj = obj->get<Object *>(desc);
dvander@152
   106
    } else {
dvander@152
   107
        switch (desc->type()->pod()) {
dvander@152
   108
          case PrimitiveType_Float:
dvander@152
   109
            vp->f = obj->get<float>(desc);
dvander@152
   110
            break;
dvander@152
   111
dvander@152
   112
          default:
dvander@152
   113
            assert(desc->type()->pod() == PrimitiveType_Int32);
dvander@152
   114
            vp->i32 = obj->get<int>(desc);
dvander@152
   115
            break;
dvander@152
   116
        }
dvander@152
   117
    }
dvander@152
   118
}
dvander@152
   119
dvander@152
   120
static void
dvander@152
   121
GetField(Struct *obj, unsigned index, LocalSlot *vp)
dvander@152
   122
{
dvander@152
   123
    Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
dvander@152
   124
    GetField(obj, desc, vp);
dvander@152
   125
}
dvander@152
   126
dvander@152
   127
static void
dvander@152
   128
SetField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
dvander@152
   129
{
dvander@152
   130
    // :TODO: assert no GC.
dvander@152
   131
    if (desc->type()->isTraceable()) {
dvander@152
   132
        obj->set(zone, desc, v.obj);
dvander@152
   133
    } else {
dvander@152
   134
        switch (desc->type()->pod()) {
dvander@152
   135
          case PrimitiveType_Float:
dvander@152
   136
            obj->set<float>(desc, v.f);
dvander@152
   137
            break;
dvander@152
   138
dvander@152
   139
          default:
dvander@152
   140
            assert(desc->type()->pod() == PrimitiveType_Int32);
dvander@152
   141
            obj->set<int>(desc, v.i32);
dvander@152
   142
            break;
dvander@152
   143
        }
dvander@152
   144
    }
dvander@152
   145
}
dvander@152
   146
dvander@152
   147
static void
dvander@152
   148
SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
dvander@152
   149
{
dvander@152
   150
    Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
dvander@152
   151
    SetField(zone, obj, desc, v);
dvander@152
   152
}
dvander@152
   153
dvander@152
   154
// Even though this function can fail, we immediately bail out, so it doesn't
dvander@152
   155
// matter if we've leaving things unrooted.
dvander@152
   156
static bool
dvander@152
   157
CopyStruct(Zone *zone, Struct *left, Struct *right)
dvander@152
   158
{
dvander@152
   159
    assert(left->map()->type() == right->map()->type());
dvander@152
   160
dvander@152
   161
    Type *type = left->map()->type();
dvander@152
   162
    for (unsigned i = 0; i < type->fields()->length(); i++) {
dvander@152
   163
        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
dvander@152
   164
dvander@152
   165
        LocalSlot rval;
dvander@152
   166
        GetField(right, desc, &rval);
dvander@152
   167
dvander@152
   168
        // If the field is a struct, we need to deep-copy.
dvander@152
   169
        if (desc->type()->isStruct()) {
dvander@152
   170
            LocalSlot lval;
dvander@152
   171
dvander@152
   172
            GetField(left, desc, &lval);
dvander@152
   173
            if (!CopyStruct(zone, Struct::cast(lval.obj), Struct::cast(rval.obj)))
dvander@152
   174
                return false;
dvander@152
   175
        } else if (desc->type()->isArray()) {
dvander@152
   176
            LocalSlot lval;
dvander@152
   177
dvander@152
   178
            GetField(left, desc, &lval);
dvander@152
   179
            if (!CopyArray(zone, Array::cast(lval.obj), Array::cast(rval.obj)))
dvander@152
   180
                return false;
dvander@152
   181
        } else {
dvander@152
   182
            SetField(zone, left, desc, rval);
dvander@152
   183
        }
dvander@152
   184
    }
dvander@152
   185
dvander@152
   186
    return true;
dvander@152
   187
}
dvander@152
   188
dvander@68
   189
static bool
dvander@68
   190
InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
dvander@68
   191
             int *result)
dvander@68
   192
{
dvander@68
   193
    NativeArgs guard;
dvander@68
   194
dvander@68
   195
    if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
dvander@68
   196
        return false;
dvander@68
   197
dvander@68
   198
    intptr_t *cells = guard.args();
dvander@68
   199
dvander@68
   200
    // params[0] == argc, in ISPE
dvander@68
   201
    cells[0] = argc;
dvander@68
   202
dvander@68
   203
    // Pass the formal arguments.
dvander@68
   204
    Local<Type> type(zone, native->type());
dvander@68
   205
    Local<Type> param(zone);
dvander@68
   206
    for (unsigned i = 0; i < type->parameters()->length(); i++) {
dvander@68
   207
        param = type->parameterAt(i);
dvander@68
   208
        
dvander@68
   209
        // For floats, we rely on the aliasing of |i32| and |f|.
dvander@68
   210
        LocalSlot &arg = args[-int(i) - 1];
dvander@68
   211
        if (param->isInt32() || param->isFloat()) {
dvander@68
   212
            cells[i + 1] = arg.i32;
dvander@68
   213
        } else if (param->isReference()) {
dvander@68
   214
            cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
dvander@68
   215
        } else {
dvander@68
   216
            assert(param->isArray());
dvander@68
   217
            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
dvander@68
   218
        }
dvander@68
   219
    }
dvander@68
   220
dvander@68
   221
    // For variadic arguments, the compiler left either arrays or references.
dvander@68
   222
    for (unsigned i = type->parameters()->length(); i < argc; i++) {
dvander@68
   223
        LocalSlot &arg = args[-int(i) - 1];
dvander@68
   224
dvander@68
   225
        if (arg.obj->is(MapKind_Reference)) {
dvander@68
   226
            cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
dvander@68
   227
        } else {
dvander@68
   228
            assert(arg.obj->is(MapKind_Array));
dvander@68
   229
            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
dvander@68
   230
        }
dvander@68
   231
    }
dvander@68
   232
dvander@68
   233
    typedef intptr_t (*INVOKE)(void *, intptr_t *);
dvander@68
   234
    INVOKE invoke = (INVOKE)native->function();
dvander@68
   235
    *result = invoke(identity, cells);
dvander@68
   236
dvander@69
   237
    return !zone->hasPendingException();
dvander@68
   238
}
dvander@68
   239
dvander@0
   240
bool
dvander@59
   241
ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
dvander@0
   242
{
dvander@42
   243
    Top &top = *zone->stack().top();
dvander@69
   244
    if (!entryFrame)
dvander@69
   245
        entryFrame = top.fp;
dvander@69
   246
dvander@47
   247
    LocalSlot *locals = entryFrame->locals();
dvander@0
   248
dvander@0
   249
    for (;;) {
dvander@0
   250
        Opcode op = Opcode(*top.pc);
dvander@0
   251
        switch (op) {
dvander@0
   252
dvander@0
   253
case OP_NOP:
dvander@0
   254
    break;
dvander@0
   255
dvander@0
   256
case OP_INT:
dvander@0
   257
    PUSH_I32(top, READ_INT32(top.pc));
dvander@0
   258
    break;
dvander@0
   259
dvander@4
   260
case OP_FLOAT:
dvander@4
   261
    PUSH_F(top, READ_FLOAT(top.pc));
dvander@4
   262
    break;
dvander@4
   263
dvander@0
   264
case OP_RETURN:
dvander@72
   265
case OP_RETURNVOID:
dvander@72
   266
case OP_STOP:
dvander@0
   267
{
dvander@72
   268
    if (op == OP_RETURN)
dvander@72
   269
        *result = *--top.sp;
dvander@72
   270
dvander@69
   271
    if (top.fp == entryFrame)
dvander@69
   272
        goto done;
dvander@0
   273
dvander@72
   274
    // This must not GC.
dvander@65
   275
    zone->stack().popInlineFrame();
dvander@47
   276
    locals = top.fp->locals();
dvander@72
   277
dvander@72
   278
    if (op == OP_RETURN)
dvander@72
   279
        *top.sp++ = *result;
dvander@72
   280
dvander@0
   281
    top.pc += OpcodeInfo[*top.pc].length;
dvander@0
   282
    continue;
dvander@0
   283
}
dvander@0
   284
dvander@80
   285
case OP_POP:
dvander@80
   286
{
dvander@80
   287
    top.sp--;
dvander@80
   288
    break;
dvander@80
   289
}
dvander@80
   290
dvander@0
   291
#define RELATIONAL_JUMP(op)                 \
dvander@0
   292
    {                                       \
dvander@0
   293
        int right = POP_I32(top);           \
dvander@0
   294
        int left = POP_I32(top);            \
dvander@0
   295
        if (left op right) {                \
dvander@0
   296
            top.pc += READ_INT32(top.pc);   \
dvander@0
   297
            continue;                       \
dvander@0
   298
        }                                   \
dvander@0
   299
    }
dvander@0
   300
dvander@0
   301
case OP_JL:
dvander@0
   302
    RELATIONAL_JUMP(<);
dvander@0
   303
    break;
dvander@0
   304
dvander@0
   305
case OP_JLE:
dvander@0
   306
    RELATIONAL_JUMP(<=);
dvander@0
   307
    break;
dvander@0
   308
dvander@0
   309
case OP_JG:
dvander@0
   310
    RELATIONAL_JUMP(>);
dvander@0
   311
    break;
dvander@0
   312
dvander@0
   313
case OP_JGE:
dvander@0
   314
    RELATIONAL_JUMP(>=);
dvander@0
   315
    break;
dvander@0
   316
dvander@0
   317
case OP_JEQ:
dvander@0
   318
    RELATIONAL_JUMP(==);
dvander@0
   319
    break;
dvander@0
   320
dvander@0
   321
case OP_JNE:
dvander@0
   322
    RELATIONAL_JUMP(!=);
dvander@0
   323
    break;
dvander@0
   324
dvander@74
   325
#undef RELATIONAL_JUMP
dvander@74
   326
dvander@0
   327
case OP_JT:
dvander@0
   328
{
dvander@0
   329
    int value = POP_I32(top);
dvander@0
   330
    if (value) {
dvander@0
   331
        top.pc += READ_INT32(top.pc);
dvander@0
   332
        continue;
dvander@0
   333
    }
dvander@0
   334
    break;
dvander@0
   335
}
dvander@0
   336
dvander@0
   337
case OP_JF:
dvander@0
   338
{
dvander@0
   339
    int value = POP_I32(top);
dvander@0
   340
    if (!value) {
dvander@0
   341
        top.pc += READ_INT32(top.pc);
dvander@0
   342
        continue;
dvander@0
   343
    }
dvander@0
   344
    break;
dvander@0
   345
}
dvander@0
   346
dvander@74
   347
#define RELATIONAL_JUMP_F(op)               \
dvander@74
   348
    {                                       \
dvander@74
   349
        float right = POP_F(top);           \
dvander@74
   350
        float left = POP_F(top);            \
dvander@74
   351
        if (left op right) {                \
dvander@74
   352
            top.pc += READ_INT32(top.pc);   \
dvander@74
   353
            continue;                       \
dvander@74
   354
        }                                   \
dvander@74
   355
    }
dvander@74
   356
dvander@74
   357
case OP_JL_F:
dvander@74
   358
    RELATIONAL_JUMP_F(<);
dvander@74
   359
    break;
dvander@74
   360
dvander@74
   361
case OP_JLE_F:
dvander@74
   362
    RELATIONAL_JUMP_F(<=);
dvander@74
   363
    break;
dvander@74
   364
dvander@74
   365
case OP_JG_F:
dvander@74
   366
    RELATIONAL_JUMP_F(>);
dvander@74
   367
    break;
dvander@74
   368
dvander@74
   369
case OP_JGE_F:
dvander@74
   370
    RELATIONAL_JUMP_F(>=);
dvander@74
   371
    break;
dvander@74
   372
dvander@74
   373
case OP_JEQ_F:
dvander@74
   374
    RELATIONAL_JUMP_F(==);
dvander@74
   375
    break;
dvander@74
   376
dvander@74
   377
case OP_JNE_F:
dvander@74
   378
    RELATIONAL_JUMP_F(!=);
dvander@74
   379
    break;
dvander@74
   380
dvander@74
   381
case OP_JT_F:
dvander@74
   382
{
dvander@74
   383
    float value = POP_F(top);
dvander@74
   384
    if (value) {
dvander@74
   385
        top.pc += READ_INT32(top.pc);
dvander@74
   386
        continue;
dvander@74
   387
    }
dvander@74
   388
    break;
dvander@74
   389
}
dvander@74
   390
dvander@74
   391
case OP_JF_F:
dvander@74
   392
{
dvander@74
   393
    float value = POP_F(top);
dvander@74
   394
    if (!value) {
dvander@74
   395
        top.pc += READ_INT32(top.pc);
dvander@74
   396
        continue;
dvander@74
   397
    }
dvander@74
   398
    break;
dvander@74
   399
}
dvander@74
   400
dvander@0
   401
case OP_JUMP:
dvander@0
   402
    top.pc += READ_INT32(top.pc);
dvander@0
   403
    continue;
dvander@0
   404
dvander@0
   405
case OP_GETLOCAL:
dvander@0
   406
{
dvander@0
   407
    int slot = READ_INT32(top.pc);
dvander@0
   408
    *top.sp++ = locals[slot];
dvander@0
   409
    break;
dvander@0
   410
}
dvander@0
   411
dvander@0
   412
case OP_SETLOCAL:
dvander@0
   413
{
dvander@0
   414
    int slot = READ_INT32(top.pc);
dvander@0
   415
    locals[slot] = top.sp[-1];
dvander@0
   416
    break;
dvander@0
   417
}
dvander@0
   418
dvander@0
   419
case OP_ADD:
dvander@0
   420
{
dvander@77
   421
    top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
dvander@77
   422
    top.sp--;
dvander@0
   423
    break;
dvander@0
   424
}
dvander@0
   425
dvander@0
   426
case OP_SUB:
dvander@0
   427
{
dvander@77
   428
    top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
dvander@77
   429
    top.sp--;
dvander@0
   430
    break;
dvander@0
   431
}
dvander@0
   432
dvander@0
   433
case OP_MUL:
dvander@0
   434
{
dvander@77
   435
    top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
dvander@77
   436
    top.sp--;
dvander@0
   437
    break;
dvander@0
   438
}
dvander@0
   439
dvander@0
   440
case OP_DIV:
dvander@0
   441
{
dvander@77
   442
    if (top.sp[-1].i32 == 0) {
dvander@69
   443
        zone->reportError(Message_IntegerDivideByZero);
dvander@69
   444
        goto error;
dvander@69
   445
    }
dvander@77
   446
    top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
dvander@77
   447
    top.sp--;
dvander@0
   448
    break;
dvander@0
   449
}
dvander@0
   450
dvander@82
   451
case OP_MOD:
dvander@82
   452
{
dvander@82
   453
    if (top.sp[-1].i32 == 0) {
dvander@82
   454
        zone->reportError(Message_IntegerDivideByZero);
dvander@82
   455
        goto error;
dvander@82
   456
    }
dvander@82
   457
    top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
dvander@82
   458
    top.sp--;
dvander@82
   459
    break;
dvander@82
   460
}
dvander@82
   461
dvander@74
   462
case OP_LT:
dvander@74
   463
{
dvander@74
   464
    top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
dvander@74
   465
    top.sp--;
dvander@74
   466
    break;
dvander@74
   467
}
dvander@74
   468
dvander@74
   469
case OP_LE:
dvander@74
   470
{
dvander@74
   471
    top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
dvander@74
   472
    top.sp--;
dvander@74
   473
    break;
dvander@74
   474
}
dvander@74
   475
dvander@74
   476
case OP_GT:
dvander@74
   477
{
dvander@74
   478
    top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
dvander@74
   479
    top.sp--;
dvander@74
   480
    break;
dvander@74
   481
}
dvander@74
   482
dvander@74
   483
case OP_GE:
dvander@74
   484
{
dvander@74
   485
    top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
dvander@74
   486
    top.sp--;
dvander@74
   487
    break;
dvander@74
   488
}
dvander@74
   489
dvander@74
   490
case OP_EQ:
dvander@74
   491
{
dvander@74
   492
    top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
dvander@74
   493
    top.sp--;
dvander@74
   494
    break;
dvander@74
   495
}
dvander@74
   496
dvander@74
   497
case OP_NE:
dvander@74
   498
{
dvander@74
   499
    top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
dvander@74
   500
    top.sp--;
dvander@74
   501
    break;
dvander@74
   502
}
dvander@74
   503
dvander@4
   504
case OP_ADD_F:
dvander@4
   505
{
dvander@77
   506
    top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
dvander@77
   507
    top.sp--;
dvander@4
   508
    break;
dvander@4
   509
}
dvander@4
   510
dvander@4
   511
case OP_SUB_F:
dvander@4
   512
{
dvander@77
   513
    top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
dvander@77
   514
    top.sp--;
dvander@4
   515
    break;
dvander@4
   516
}
dvander@4
   517
dvander@4
   518
case OP_MUL_F:
dvander@4
   519
{
dvander@77
   520
    top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
dvander@77
   521
    top.sp--;
dvander@4
   522
    break;
dvander@4
   523
}
dvander@4
   524
dvander@4
   525
case OP_DIV_F:
dvander@4
   526
{
dvander@77
   527
    top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
dvander@77
   528
    top.sp--;
dvander@4
   529
    break;
dvander@4
   530
}
dvander@4
   531
dvander@74
   532
case OP_LT_F:
dvander@74
   533
{
dvander@74
   534
    top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
dvander@74
   535
    top.sp--;
dvander@74
   536
    break;
dvander@74
   537
}
dvander@74
   538
dvander@74
   539
case OP_LE_F:
dvander@74
   540
{
dvander@74
   541
    top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
dvander@74
   542
    top.sp--;
dvander@74
   543
    break;
dvander@74
   544
}
dvander@74
   545
dvander@74
   546
case OP_GT_F:
dvander@74
   547
{
dvander@74
   548
    top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
dvander@74
   549
    top.sp--;
dvander@74
   550
    break;
dvander@74
   551
}
dvander@74
   552
dvander@74
   553
case OP_GE_F:
dvander@74
   554
{
dvander@74
   555
    top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
dvander@74
   556
    top.sp--;
dvander@74
   557
    break;
dvander@74
   558
}
dvander@74
   559
dvander@74
   560
case OP_EQ_F:
dvander@74
   561
{
dvander@74
   562
    top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
dvander@74
   563
    top.sp--;
dvander@74
   564
    break;
dvander@74
   565
}
dvander@74
   566
dvander@74
   567
case OP_NE_F:
dvander@74
   568
{
dvander@74
   569
    top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
dvander@74
   570
    top.sp--;
dvander@74
   571
    break;
dvander@74
   572
}
dvander@74
   573
dvander@8
   574
case OP_SHL:
dvander@8
   575
{
dvander@77
   576
    top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
dvander@77
   577
    top.sp--;
dvander@8
   578
    break;
dvander@8
   579
}
dvander@8
   580
dvander@8
   581
case OP_SHR:
dvander@8
   582
{
dvander@77
   583
    top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
dvander@77
   584
    top.sp--;
dvander@8
   585
    break;
dvander@8
   586
}
dvander@8
   587
dvander@8
   588
case OP_USHR:
dvander@8
   589
{
dvander@77
   590
    top.sp[-2].i32 = unsigned(top.sp[-2].i32) << unsigned(top.sp[-1].i32);
dvander@77
   591
    top.sp--;
dvander@8
   592
    break;
dvander@8
   593
}
dvander@8
   594
dvander@8
   595
case OP_BITAND:
dvander@8
   596
{
dvander@77
   597
    top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
dvander@77
   598
    top.sp--;
dvander@8
   599
    break;
dvander@8
   600
}
dvander@8
   601
dvander@8
   602
case OP_BITOR:
dvander@8
   603
{
dvander@77
   604
    top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
dvander@77
   605
    top.sp--;
dvander@8
   606
    break;
dvander@8
   607
}
dvander@8
   608
dvander@8
   609
case OP_BITXOR:
dvander@8
   610
{
dvander@77
   611
    top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
dvander@77
   612
    top.sp--;
dvander@8
   613
    break;
dvander@8
   614
}
dvander@8
   615
dvander@78
   616
case OP_BITNOT:
dvander@78
   617
{
dvander@78
   618
    top.sp[-1].i32 = ~top.sp[-1].i32;
dvander@78
   619
    break;
dvander@78
   620
}
dvander@78
   621
dvander@79
   622
case OP_NOT:
dvander@79
   623
{
dvander@79
   624
    top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
dvander@79
   625
    break;
dvander@79
   626
}
dvander@79
   627
dvander@79
   628
case OP_NOT_F:
dvander@79
   629
{
dvander@79
   630
    top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
dvander@79
   631
    break;
dvander@79
   632
}
dvander@79
   633
dvander@80
   634
case OP_NEG:
dvander@79
   635
{
dvander@80
   636
    top.sp[-1].i32 = -top.sp[-1].i32;
dvander@80
   637
    break;
dvander@80
   638
}
dvander@80
   639
dvander@80
   640
case OP_NEG_F:
dvander@80
   641
{
dvander@80
   642
    top.sp[-1].f = -top.sp[-1].f;
dvander@0
   643
    break;
dvander@79
   644
}
dvander@0
   645
dvander@73
   646
case OP_CALL:
dvander@0
   647
{
dvander@73
   648
    Local<Function> newFun(zone, top.sp[-1].fun);
dvander@73
   649
    top.sp--;
dvander@73
   650
dvander@69
   651
    if (!zone->stack().pushInlineFrame(newFun))
dvander@69
   652
        goto error;
dvander@0
   653
dvander@47
   654
    locals = top.fp->locals();
dvander@0
   655
    continue;
dvander@0
   656
}
dvander@0
   657
dvander@0
   658
case OP_GETARG:
dvander@0
   659
{
dvander@0
   660
    unsigned slot = READ_UINT32(top.pc);
dvander@47
   661
    *top.sp++ = top.fp->arg(slot);
dvander@0
   662
    break;
dvander@0
   663
}
dvander@0
   664
dvander@0
   665
case OP_SETARG:
dvander@0
   666
{
dvander@0
   667
    unsigned slot = READ_UINT32(top.pc);
dvander@47
   668
    top.fp->arg(slot) = *--top.sp;
dvander@0
   669
    break;
dvander@0
   670
}
dvander@0
   671
dvander@19
   672
case OP_BOUNDS:
dvander@0
   673
{
dvander@12
   674
    Array *array = top.sp[-2].array;
dvander@0
   675
    int index = top.sp[-1].i32;
dvander@69
   676
    if (index < 0 || unsigned(index) >= array->nelements()) {
dvander@69
   677
        zone->reportError(Message_ArrayIndexOutOfBounds, index, array->nelements());
dvander@69
   678
        goto error;
dvander@69
   679
    }
dvander@0
   680
    break;
dvander@0
   681
}
dvander@0
   682
dvander@6
   683
case OP_GETARRAY_I:
dvander@0
   684
{
dvander@12
   685
    Array *array = top.sp[-2].array;
dvander@0
   686
    int index = top.sp[-1].i32;
dvander@0
   687
    top.sp[-2].i32 = array->readInt32(index);
dvander@0
   688
    top.sp--;
dvander@0
   689
    break;
dvander@0
   690
}
dvander@0
   691
dvander@7
   692
case OP_GETARRAY_F:
dvander@7
   693
{
dvander@12
   694
    Array *array = top.sp[-2].array;
dvander@7
   695
    int index = top.sp[-1].i32;
dvander@7
   696
    top.sp[-2].f = array->readFloat(index);
dvander@7
   697
    top.sp--;
dvander@7
   698
    break;
dvander@7
   699
}
dvander@7
   700
dvander@21
   701
case OP_GETARRAY_C:
dvander@21
   702
{
dvander@21
   703
    Array *array = top.sp[-2].array;
dvander@21
   704
    int index = top.sp[-1].i32;
dvander@21
   705
    top.sp[-2].i32 = array->readChar(index);
dvander@21
   706
    top.sp--;
dvander@21
   707
    break;
dvander@21
   708
}
dvander@21
   709
dvander@6
   710
case OP_SETARRAY_I:
dvander@0
   711
{
dvander@12
   712
    Array *array = top.sp[-3].array;
dvander@0
   713
    int index = top.sp[-2].i32;
dvander@0
   714
    array->writeInt32(index, top.sp[-1].i32);
dvander@0
   715
    top.sp[-3] = top.sp[-1];
dvander@0
   716
    top.sp -= 2;
dvander@0
   717
    break;
dvander@0
   718
}
dvander@0
   719
dvander@7
   720
case OP_SETARRAY_F:
dvander@7
   721
{
dvander@12
   722
    Array *array = top.sp[-3].array;
dvander@7
   723
    int index = top.sp[-2].i32;
dvander@7
   724
    array->writeFloat(index, top.sp[-1].f);
dvander@7
   725
    top.sp[-3] = top.sp[-1];
dvander@7
   726
    top.sp -= 2;
dvander@7
   727
    break;
dvander@7
   728
}
dvander@7
   729
dvander@21
   730
case OP_SETARRAY_C:
dvander@21
   731
{
dvander@21
   732
    Array *array = top.sp[-3].array;
dvander@21
   733
    int index = top.sp[-2].i32;
dvander@21
   734
    array->writeChar(index, top.sp[-1].i32);
dvander@21
   735
    top.sp[-3] = top.sp[-1];
dvander@21
   736
    top.sp -= 2;
dvander@21
   737
    break;
dvander@21
   738
}
dvander@21
   739
dvander@19
   740
case OP_GETARRAY_O:
dvander@0
   741
{
dvander@12
   742
    Array *array = top.sp[-2].array;
dvander@0
   743
    int index = top.sp[-1].i32;
dvander@154
   744
    top.sp[-2].obj = array->readObject(index);
dvander@0
   745
    top.sp--;
dvander@0
   746
    break;
dvander@0
   747
}
dvander@0
   748
dvander@4
   749
case OP_CVT_I2F:
dvander@4
   750
{
dvander@4
   751
    int ival = POP_I32(top);
dvander@4
   752
    float fval = (float)ival;
dvander@4
   753
    PUSH_F(top, fval);
dvander@4
   754
    break;
dvander@4
   755
}
dvander@4
   756
dvander@85
   757
case OP_NEWARRAY:
dvander@12
   758
{
dvander@85
   759
    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
dvander@85
   760
    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
dvander@154
   761
    Array *array = Array::New(zone, map, map->type()->elements(), tenure);
dvander@69
   762
    if (!array)
dvander@69
   763
        goto error;
dvander@12
   764
    top.sp->obj = array;
dvander@12
   765
    top.sp++;
dvander@12
   766
    break;
dvander@12
   767
}
dvander@12
   768
dvander@147
   769
case OP_NEWSTRUCT:
dvander@147
   770
{
dvander@147
   771
    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
dvander@147
   772
    Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
dvander@147
   773
    top.sp->obj = Struct::New(zone, map, tenure);
dvander@147
   774
    if (!top.sp->obj)
dvander@147
   775
        goto error;
dvander@147
   776
    top.sp++;
dvander@147
   777
    break;
dvander@147
   778
}
dvander@147
   779
dvander@12
   780
case OP_SAVELIFO:
dvander@10
   781
{
dvander@10
   782
    unsigned slot = READ_UINT32(top.pc);
dvander@42
   783
    locals[slot].address = zone->heap().lifoPosition();
dvander@12
   784
    break;
dvander@12
   785
}
dvander@12
   786
dvander@12
   787
case OP_UNWINDLIFO:
dvander@12
   788
{
dvander@12
   789
    unsigned slot = READ_UINT32(top.pc);
dvander@42
   790
    zone->heap().unwindLifo(locals[slot].address);
dvander@10
   791
    break;
dvander@10
   792
}
dvander@10
   793
dvander@14
   794
case OP_VARREF_LIFO:
dvander@14
   795
{
dvander@14
   796
    unsigned slot = READ_UINT32(top.pc);
dvander@69
   797
    if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
dvander@69
   798
        goto error;
dvander@14
   799
    break;
dvander@14
   800
}
dvander@14
   801
dvander@14
   802
case OP_ARGREF_LIFO:
dvander@14
   803
{
dvander@14
   804
    unsigned slot = READ_UINT32(top.pc);
dvander@69
   805
    if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
dvander@69
   806
        goto error;
dvander@14
   807
    break;
dvander@14
   808
}
dvander@14
   809
dvander@17
   810
case OP_ARRAYREF_LIFO:
dvander@17
   811
{
dvander@42
   812
    Local<Array> array(zone, top.sp[-2].array);
dvander@42
   813
    Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
dvander@69
   814
    if (!ref)
dvander@69
   815
        goto error;
dvander@17
   816
    top.sp[-2].ref = ref;
dvander@17
   817
    top.sp--;
dvander@17
   818
    break;
dvander@17
   819
}
dvander@17
   820
dvander@16
   821
case OP_SLOTREF_LIFO:
dvander@16
   822
{
dvander@42
   823
    Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
dvander@69
   824
    if (!ref)
dvander@69
   825
        goto error;
dvander@16
   826
    top.sp[-1].ref = ref;
dvander@16
   827
    break;
dvander@16
   828
}
dvander@16
   829
dvander@14
   830
case OP_GETREF_I:
dvander@14
   831
{
dvander@14
   832
    top.sp[-1].i32 = top.sp[-1].ref->getInt();
dvander@14
   833
    break;
dvander@14
   834
}
dvander@14
   835
dvander@14
   836
case OP_SETREF_I:
dvander@14
   837
{
dvander@14
   838
    top.sp[-2].ref->setInt(top.sp[-1].i32);
dvander@14
   839
    top.sp[-2].i32 = top.sp[-1].i32;
dvander@23
   840
    top.sp--;
dvander@14
   841
    break;
dvander@14
   842
}
dvander@14
   843
dvander@14
   844
case OP_GETREF_F:
dvander@14
   845
{
dvander@14
   846
    top.sp[-1].f = top.sp[-1].ref->getFloat();
dvander@14
   847
    break;
dvander@14
   848
}
dvander@14
   849
dvander@14
   850
case OP_SETREF_F:
dvander@14
   851
{
dvander@14
   852
    top.sp[-2].ref->setFloat(top.sp[-1].f);
dvander@14
   853
    top.sp[-2].f = top.sp[-1].f;
dvander@14
   854
    break;
dvander@14
   855
}
dvander@14
   856
dvander@21
   857
case OP_OBJECT:
dvander@21
   858
{
dvander@47
   859
    top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
dvander@21
   860
    top.sp++;
dvander@21
   861
    break;
dvander@21
   862
}
dvander@21
   863
dvander@152
   864
case OP_COPYARRAY:
dvander@21
   865
{
dvander@21
   866
    // Note for this assignment opcode, we return the left-hand side, not the
dvander@21
   867
    // right, since in this case the result of the expression could be different.
dvander@69
   868
    if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
dvander@69
   869
        goto error;
dvander@21
   870
    top.sp--;
dvander@21
   871
    break;
dvander@21
   872
}
dvander@21
   873
dvander@22
   874
case OP_DUP:
dvander@22
   875
{
dvander@23
   876
    top.sp++;
dvander@23
   877
    top.sp[-1] = top.sp[-2];
dvander@22
   878
    break;
dvander@22
   879
}
dvander@22
   880
dvander@22
   881
case OP_DUP2:
dvander@22
   882
{
dvander@23
   883
    top.sp += 2;
dvander@23
   884
    top.sp[-2] = top.sp[-4];
dvander@23
   885
    top.sp[-1] = top.sp[-3];
dvander@23
   886
    break;
dvander@23
   887
}
dvander@23
   888
dvander@23
   889
case OP_SWAP:
dvander@23
   890
{
dvander@23
   891
    LocalSlot slot = top.sp[-2];
dvander@23
   892
    top.sp[-2] = top.sp[-1];
dvander@23
   893
    top.sp[-1] = slot;
dvander@23
   894
    break;
dvander@23
   895
}
dvander@23
   896
dvander@23
   897
case OP_ROLL3:
dvander@23
   898
{
dvander@23
   899
    LocalSlot slot = top.sp[-3];
dvander@23
   900
    top.sp[-3] = top.sp[-2];
dvander@23
   901
    top.sp[-2] = top.sp[-1];
dvander@23
   902
    top.sp[-1] = slot;
dvander@23
   903
    break;
dvander@23
   904
}
dvander@23
   905
dvander@23
   906
case OP_PICK2:
dvander@23
   907
{
dvander@23
   908
    top.sp++;
dvander@23
   909
    top.sp[-1] = top.sp[-3];
dvander@23
   910
    break;
dvander@23
   911
}
dvander@23
   912
dvander@23
   913
case OP_PICK3:
dvander@23
   914
{
dvander@23
   915
    top.sp++;
dvander@23
   916
    top.sp[-1] = top.sp[-4];
dvander@22
   917
    break;
dvander@22
   918
}
dvander@22
   919
dvander@68
   920
case OP_CALLNATIVE:
dvander@68
   921
{
dvander@68
   922
    unsigned index = READ_UINT32(top.pc);
dvander@68
   923
    unsigned argc = READ_UINT32(top.pc + 4);
dvander@68
   924
dvander@68
   925
    Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
dvander@68
   926
    if (!native->function()) {
dvander@69
   927
        zone->reportError(Message_NativeNotBound, native->name()->chars());
dvander@69
   928
        goto error;
dvander@68
   929
    }
dvander@68
   930
dvander@68
   931
    int result;
dvander@68
   932
    void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
dvander@69
   933
    if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
dvander@69
   934
        goto error;
dvander@68
   935
dvander@68
   936
    top.sp -= argc;
dvander@68
   937
    PUSH_I32(top, result);
dvander@68
   938
    break;
dvander@68
   939
}
dvander@68
   940
dvander@73
   941
case OP_MODULE:
dvander@73
   942
{
dvander@73
   943
    top.sp++;
dvander@73
   944
    top.sp[-1].module = top.fp->code()->module();
dvander@73
   945
    break;
dvander@73
   946
}
dvander@73
   947
dvander@73
   948
case OP_GETMODULE_FN:
dvander@73
   949
{
dvander@73
   950
    top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
dvander@73
   951
    break;
dvander@73
   952
}
dvander@73
   953
dvander@85
   954
case OP_GETGLOBAL_I:
dvander@85
   955
{
dvander@85
   956
    unsigned slot = READ_UINT32(top.pc);
dvander@85
   957
    top.sp++;
dvander@85
   958
    top.sp[-1].i32 = top.fp->code()->module()->environment()->getInt32(slot);
dvander@85
   959
    break;
dvander@85
   960
}
dvander@85
   961
dvander@85
   962
case OP_GETGLOBAL_F:
dvander@85
   963
{
dvander@85
   964
    unsigned slot = READ_UINT32(top.pc);
dvander@85
   965
    top.sp++;
dvander@85
   966
    top.sp[-1].f = top.fp->code()->module()->environment()->getFloat(slot);
dvander@85
   967
    break;
dvander@85
   968
}
dvander@85
   969
dvander@85
   970
case OP_GETGLOBAL_O:
dvander@85
   971
{
dvander@85
   972
    unsigned slot = READ_UINT32(top.pc);
dvander@85
   973
    top.sp++;
dvander@85
   974
    top.sp[-1].obj = top.fp->code()->module()->environment()->getObject(slot);
dvander@85
   975
    break;
dvander@85
   976
}
dvander@85
   977
dvander@85
   978
case OP_SETGLOBAL_I:
dvander@85
   979
{
dvander@85
   980
    unsigned slot = READ_UINT32(top.pc);
dvander@85
   981
    top.fp->code()->module()->environment()->setInt32(slot, top.sp[-1].i32);
dvander@85
   982
    break;
dvander@85
   983
}
dvander@85
   984
dvander@85
   985
case OP_SETGLOBAL_F:
dvander@85
   986
{
dvander@85
   987
    unsigned slot = READ_UINT32(top.pc);
dvander@85
   988
    top.fp->code()->module()->environment()->setFloat(slot, top.sp[-1].f);
dvander@85
   989
    break;
dvander@85
   990
}
dvander@85
   991
dvander@85
   992
case OP_SETGLOBAL_O:
dvander@85
   993
{
dvander@85
   994
    unsigned slot = READ_UINT32(top.pc);
dvander@85
   995
    top.fp->code()->module()->environment()->setObject(slot, top.sp[-1].obj);
dvander@85
   996
    break;
dvander@85
   997
}
dvander@85
   998
dvander@142
   999
case OP_BITS_I2F:
dvander@142
  1000
case OP_BITS_F2I:
dvander@142
  1001
{
dvander@142
  1002
    // Because the stack is a union, these are actually no-ops in the
dvander@142
  1003
    // interpreter.
dvander@142
  1004
    break;
dvander@142
  1005
}
dvander@142
  1006
dvander@143
  1007
case OP_TRUE:
dvander@143
  1008
{
dvander@143
  1009
    top.sp++;
dvander@143
  1010
    top.sp[-1].i32 = 1;
dvander@143
  1011
    break;
dvander@143
  1012
}
dvander@143
  1013
dvander@143
  1014
case OP_FALSE:
dvander@143
  1015
{
dvander@143
  1016
    top.sp++;
dvander@143
  1017
    top.sp[-1].i32 = 0;
dvander@143
  1018
    break;
dvander@143
  1019
}
dvander@143
  1020
dvander@152
  1021
case OP_GETFIELD:
dvander@152
  1022
{
dvander@152
  1023
    Struct *obj = Struct::cast(top.sp[-1].obj);
dvander@152
  1024
    GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
dvander@152
  1025
    break;
dvander@152
  1026
}
dvander@152
  1027
dvander@152
  1028
case OP_SETFIELD:
dvander@152
  1029
{
dvander@152
  1030
    Struct *obj = Struct::cast(top.sp[-2].obj);
dvander@152
  1031
    SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
dvander@152
  1032
    top.sp[-2] = top.sp[-1];
dvander@152
  1033
    top.sp--;
dvander@152
  1034
    break;
dvander@152
  1035
}
dvander@152
  1036
dvander@152
  1037
case OP_COPYSTRUCT:
dvander@152
  1038
{
dvander@152
  1039
    if (!CopyStruct(zone, Struct::cast(top.sp[-2].obj), Struct::cast(top.sp[-1].obj)))
dvander@152
  1040
        goto error;
dvander@152
  1041
    top.sp[-2].obj = top.sp[-1].obj;
dvander@152
  1042
    top.sp--;
dvander@152
  1043
    break;
dvander@152
  1044
}
dvander@152
  1045
dvander@0
  1046
default:
dvander@0
  1047
    assert(false);
dvander@0
  1048
    return false;
dvander@0
  1049
dvander@0
  1050
        }
dvander@0
  1051
dvander@0
  1052
        top.pc += OpcodeInfo[op].length;
dvander@0
  1053
    }
dvander@0
  1054
dvander@69
  1055
done:
dvander@0
  1056
    return true;
dvander@69
  1057
dvander@69
  1058
error:
dvander@69
  1059
    // Unwind frames until we can continue.
dvander@69
  1060
    while (top.fp != entryFrame)
dvander@69
  1061
        zone->stack().popInlineFrame();
dvander@69
  1062
    return false;
dvander@0
  1063
}