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