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