src/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Sun Sep 02 13:06:09 2012 -0700 (2012-09-02)
changeset 177 56f7e5b0243c
parent 175 f875ce723f2c
child 182 c52ca323063f
permissions -rw-r--r--
Fix bug in bytecode resizing.
dvander@28
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@28
     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@92
    19
#include <string.h>
dvander@0
    20
#include "BytecodeCompiler.h"
dvander@0
    21
#include "Scopes.h"
dvander@0
    22
#include "Modules.h"
dvander@0
    23
#include "Types.h"
dvander@12
    24
#include "Array.h"
dvander@54
    25
#include "Strings.h"
dvander@12
    26
#include "Zone.h"
dvander@85
    27
#include "Environments.h"
dvander@168
    28
#include "Box.h"
dvander@12
    29
#include "Heap-inl.h"
dvander@0
    30
dvander@59
    31
using namespace ke;
dvander@0
    32
dvander@0
    33
typedef BytecodeEmitter::Label Label;
dvander@0
    34
dvander@0
    35
#define __ emitter_.
dvander@0
    36
dvander@65
    37
BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
dvander@30
    38
  : zone_(zone),
dvander@30
    39
    tree_(tree),
dvander@47
    40
    emitter_(zone->pool()),
dvander@28
    41
    locals_(NULL),
dvander@10
    42
    scope_(NULL),
danderson@91
    43
    moduleData_(module),
dvander@28
    44
    loop_(NULL)
dvander@0
    45
{
dvander@0
    46
}
dvander@0
    47
dvander@0
    48
static inline TokenKind
dvander@0
    49
ToCompare(Expression *expr)
dvander@0
    50
{
dvander@0
    51
    if (expr->isBinaryExpression()) {
dvander@0
    52
        BinaryExpression *b = expr->toBinaryExpression();
dvander@75
    53
        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
dvander@0
    54
            return b->token();
dvander@79
    55
    } else if (expr->isUnaryExpression()) {
dvander@79
    56
        UnaryExpression *u = expr->toUnaryExpression();
dvander@79
    57
        if (u->token() == TOK_NOT)
dvander@79
    58
            return TOK_NOT;
dvander@0
    59
    }
dvander@0
    60
    return TOK_EOF;
dvander@0
    61
}
dvander@0
    62
dvander@0
    63
static inline Opcode
dvander@0
    64
CompareTokenToJump(TokenKind kind)
dvander@0
    65
{
dvander@0
    66
    switch (kind) {
dvander@0
    67
      case TOK_EQUALS:
dvander@0
    68
        return OP_JEQ;
dvander@0
    69
      case TOK_NOTEQUALS:
dvander@0
    70
        return OP_JNE;
dvander@0
    71
      case TOK_GT:
dvander@0
    72
        return OP_JG;
dvander@0
    73
      case TOK_GE:
dvander@0
    74
        return OP_JGE;
dvander@0
    75
      case TOK_LT:
dvander@0
    76
        return OP_JL;
dvander@28
    77
      default:
dvander@28
    78
        assert(kind == TOK_LE);
dvander@0
    79
        return OP_JLE;
dvander@0
    80
    }
dvander@0
    81
}
dvander@0
    82
dvander@0
    83
static inline Opcode
dvander@0
    84
TokenToOpcode(TokenKind kind)
dvander@0
    85
{
dvander@0
    86
    switch (kind) {
dvander@0
    87
      case TOK_PLUS:
dvander@0
    88
        return OP_ADD;
dvander@0
    89
      case TOK_MINUS:
dvander@0
    90
        return OP_SUB;
dvander@0
    91
      case TOK_STAR:
dvander@0
    92
        return OP_MUL;
dvander@0
    93
      case TOK_SLASH:
dvander@0
    94
        return OP_DIV;
dvander@82
    95
      case TOK_PERCENT:
dvander@82
    96
        return OP_MOD;
dvander@8
    97
      case TOK_SHR:
dvander@8
    98
        return OP_SHR;
dvander@8
    99
      case TOK_USHR:
dvander@8
   100
        return OP_USHR;
dvander@8
   101
      case TOK_SHL:
dvander@8
   102
        return OP_SHL;
dvander@8
   103
      case TOK_BITAND:
dvander@8
   104
        return OP_BITAND;
dvander@8
   105
      case TOK_BITOR:
dvander@8
   106
        return OP_BITOR;
dvander@74
   107
      case TOK_GT:
dvander@74
   108
          return OP_GT;
dvander@74
   109
      case TOK_GE:
dvander@74
   110
          return OP_GE;
dvander@74
   111
      case TOK_LT:
dvander@74
   112
          return OP_LT;
dvander@74
   113
      case TOK_LE:
dvander@74
   114
          return OP_LE;
dvander@74
   115
      case TOK_EQUALS:
dvander@74
   116
          return OP_EQ;
dvander@74
   117
      case TOK_NOTEQUALS:
dvander@74
   118
          return OP_NE;
dvander@28
   119
      default:
dvander@28
   120
        assert(kind == TOK_BITXOR);
dvander@8
   121
        return OP_BITXOR;
dvander@0
   122
    }
dvander@0
   123
}
dvander@0
   124
dvander@0
   125
void
dvander@12
   126
BytecodeCompiler::recordLifoSlot(Scope *scope)
dvander@1
   127
{
dvander@1
   128
    if (!scope)
dvander@1
   129
        return;
dvander@1
   130
dvander@12
   131
    if (Variable *var = scope->lifoSlot()) {
dvander@30
   132
        locals_->set(zone_, var->slot(), var->type());
dvander@12
   133
        __ savelifo(var->slot());
dvander@12
   134
    }
dvander@1
   135
}
dvander@1
   136
dvander@1
   137
void
dvander@10
   138
BytecodeCompiler::unwindTo(Scope *scope)
dvander@10
   139
{
dvander@12
   140
    // Note: we only need to unwind to the outermost scope's LIFO slot.
dvander@12
   141
    Variable *var = NULL;
dvander@10
   142
    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
dvander@12
   143
        if (Variable *slot = current->lifoSlot())
dvander@12
   144
            var = slot;
dvander@10
   145
    }
dvander@12
   146
dvander@12
   147
    if (var)
dvander@12
   148
        __ unwindlifo(var->slot());
dvander@10
   149
}
dvander@10
   150
dvander@10
   151
void
dvander@0
   152
BytecodeCompiler::visit(NameProxy *name)
dvander@0
   153
{
dvander@2
   154
    switch (name->binding()->kind()) {
dvander@2
   155
      case BoundName::VARIABLE:
dvander@2
   156
      {
dvander@2
   157
        Variable *var = name->binding()->toVariable();
dvander@0
   158
dvander@2
   159
        if (var->location() == Variable::STACK) {
dvander@47
   160
            __ getlocal(var);
dvander@14
   161
            assert(!name->type()->isReference());
dvander@85
   162
        } else if (var->location() == Variable::ENVIRONMENT) {
dvander@85
   163
            getEnvSlot(var);
dvander@2
   164
        } else {
dvander@2
   165
            assert(var->location() == Variable::PARAMETER);
dvander@47
   166
            __ getarg(var);
dvander@14
   167
dvander@14
   168
            // If this argument is actually a reference, dereference it now.
dvander@22
   169
            if (var->type()->isReference())
dvander@145
   170
                __ getref(var->type()->contained());
dvander@2
   171
        }
dvander@2
   172
        break;
dvander@2
   173
      }
dvander@2
   174
dvander@73
   175
      case BoundName::FUNCTION:
dvander@73
   176
      {
dvander@73
   177
        NamedFunction *fun = name->binding()->toNamedFunction();
dvander@73
   178
        __ module();
dvander@73
   179
        __ getmodule_fn(fun->slot());
dvander@73
   180
        break;
dvander@73
   181
      }
dvander@73
   182
dvander@2
   183
      default:
dvander@2
   184
      {
dvander@2
   185
        NamedConstant *constant = name->binding()->toNamedConstant();
dvander@2
   186
        __ int_(constant->value().toInt());
dvander@2
   187
        break;
dvander@2
   188
      }
dvander@0
   189
    }
dvander@0
   190
}
dvander@0
   191
dvander@0
   192
void
dvander@0
   193
BytecodeCompiler::visit(ExpressionStatement *node)
dvander@0
   194
{
dvander@0
   195
    // Expressions leave their value on the top of the stack, so we make sure
dvander@0
   196
    // to balance the stack if they're used as a statement.
dvander@0
   197
    node->expression()->accept(this);
dvander@72
   198
    if (!node->expression()->type()->isVoid())
dvander@72
   199
        __ pop();
dvander@0
   200
}
dvander@0
   201
dvander@0
   202
void
dvander@0
   203
BytecodeCompiler::visit(Assignment *node)
dvander@0
   204
{
dvander@152
   205
    Local<Type> type(zone_, node->expression()->type());
dvander@152
   206
dvander@22
   207
    // The first step is three sub-steps:
dvander@22
   208
    //
dvander@22
   209
    //   (1) Bind the left-hand side.
dvander@22
   210
    //   -- If a cumulative operation (+=, etc):
dvander@22
   211
    //   (2) Save a copy of the binding on the stack.
dvander@22
   212
    //   (3) Dereference the binding to get a value.
dvander@22
   213
    //
dvander@0
   214
    if (node->lvalue()->isNameProxy()) {
dvander@0
   215
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@0
   216
        Variable *var = proxy->binding()->toVariable();
dvander@0
   217
dvander@22
   218
        // Bind.
dvander@152
   219
        if (var->type()->isReference() ||
dvander@152
   220
            var->type()->isArray() ||
dvander@152
   221
            var->type()->isStruct())
dvander@152
   222
        {
dvander@16
   223
            __ get(var);
dvander@152
   224
        }
dvander@14
   225
dvander@22
   226
        // Get the value if needed.
dvander@22
   227
        if (node->token() != TOK_ASSIGN) {
dvander@22
   228
            // += etc is not allowed on arrays.
dvander@22
   229
            assert(!var->type()->isArray());
dvander@22
   230
dvander@175
   231
            if (var->location() == Variable::ENVIRONMENT)
dvander@175
   232
                getEnvSlot(var);
dvander@175
   233
dvander@22
   234
            if (var->type()->isReference()) {
dvander@22
   235
                __ dup();
dvander@145
   236
                __ getref(var->type()->contained());
dvander@175
   237
            } else if (var->location() != Variable::ENVIRONMENT) {
dvander@22
   238
                __ get(var);
dvander@22
   239
            }
dvander@22
   240
        }
dvander@148
   241
    } else if (node->lvalue()->isFieldExpression()) {
dvander@148
   242
        FieldExpression *expr = node->lvalue()->toFieldExpression();
dvander@148
   243
        __ note_position(expr->pos());
dvander@148
   244
dvander@148
   245
        expr->left()->accept(this);
dvander@148
   246
dvander@152
   247
        if (node->token() != TOK_ASSIGN)
dvander@148
   248
            __ dup();
dvander@152
   249
dvander@152
   250
        if (node->token() != TOK_ASSIGN || (type->isStruct() || type->isArray()))
dvander@148
   251
            __ getfield(expr->fieldIndex(), expr->type());
dvander@23
   252
    } else {
dvander@21
   253
        IndexExpression *index = node->lvalue()->toIndexExpression();
dvander@70
   254
        __ note_position(index->pos());
dvander@21
   255
dvander@21
   256
        index->left()->accept(this);
dvander@21
   257
        index->right()->accept(this);
dvander@22
   258
dvander@152
   259
        if (node->token() != TOK_ASSIGN)
dvander@22
   260
            __ dup2();
dvander@152
   261
dvander@158
   262
        if (node->token() != TOK_ASSIGN || (type->isStruct() || type->isArray()))
dvander@157
   263
            __ getelem(index->type());
dvander@22
   264
    }
dvander@22
   265
dvander@22
   266
    if (node->token() == TOK_ASSIGN) {
dvander@21
   267
        node->expression()->accept(this);
dvander@22
   268
    } else {
dvander@22
   269
        visitForALU(node->type(), node->expression());
dvander@22
   270
dvander@22
   271
        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
dvander@70
   272
        __ note_position(node->pos());
dvander@22
   273
        __ binary(TokenToOpcode(alu));
dvander@21
   274
    }
dvander@21
   275
dvander@21
   276
    // Emit the store.
dvander@152
   277
    if (type->isArray()) {
dvander@21
   278
        // Unlike references, which can only be computed from a NamePRoxy,
dvander@21
   279
        // arrays can be computed from multiple lvalue types.
dvander@70
   280
        __ note_position(node->pos());
dvander@152
   281
        __ copyarray();
dvander@152
   282
    } else if (type->isStruct()) {
dvander@152
   283
        // Structs have value semantics, so emit a full copy. We don't break
dvander@152
   284
        // this down into u-ops, to avoid unnecessary bytecode explosion.
dvander@152
   285
        __ note_position(node->pos());
dvander@152
   286
        __ copystruct();
dvander@21
   287
    } else if (node->lvalue()->isNameProxy()) {
dvander@21
   288
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@21
   289
        Variable *var = proxy->binding()->toVariable();
dvander@14
   290
dvander@22
   291
        if (var->type()->isReference())
dvander@145
   292
            __ setref(var->type()->contained());
dvander@175
   293
        else if (var->location() == Variable::ENVIRONMENT)
dvander@175
   294
            setEnvSlot(var);
dvander@22
   295
        else
dvander@16
   296
            __ set(var);
dvander@148
   297
    } else if (node->lvalue()->isFieldExpression()) {
dvander@148
   298
        FieldExpression *expr = node->lvalue()->toFieldExpression();
dvander@148
   299
        __ setfield(expr->fieldIndex(), expr->type());
dvander@21
   300
    } else {
dvander@0
   301
        IndexExpression *index = node->lvalue()->toIndexExpression();
dvander@157
   302
        __ setelem(index->type());
dvander@0
   303
    }
dvander@0
   304
}
dvander@0
   305
dvander@0
   306
void
dvander@23
   307
BytecodeCompiler::visit(IncDecExpression *node)
dvander@23
   308
{
dvander@23
   309
    // In the postfix case, the logic looks like:
dvander@23
   310
    //      (1) Bind       -> REF
dvander@23
   311
    //      (2) Dup        -> REF REF
dvander@23
   312
    //      (3) Fetch      -> REF VAL
dvander@23
   313
    //      (4) Swap       -> VAL REF
dvander@23
   314
    //      (5) Pick       -> VAL REF VAL
dvander@23
   315
    //      (6) Add        -> VAL REF VAL+1
dvander@23
   316
    //      (7) Store      -> VAL VAL+1
dvander@23
   317
    //      (8) Drop       -> VAL
dvander@23
   318
    //
dvander@23
   319
    // In the prefix case, the logic looks like:
dvander@23
   320
    //      (1) Bind       -> REF
dvander@23
   321
    //      (2) Dup        -> REF REF
dvander@23
   322
    //      (3) Fetch      -> REF VAL
dvander@23
   323
    //      --
dvander@23
   324
    //      --
dvander@23
   325
    //      (6) Add        -> REF VAL+1
dvander@23
   326
    //      (7) Store      -> VAL+1
dvander@23
   327
    //      --
dvander@23
   328
    //
dvander@23
   329
    // This is squirrely enough such that we don't bother sharing too much
dvander@23
   330
    // with the above.
dvander@23
   331
    // 
dvander@23
   332
    // Note: We simulate a "Pick" operation with a dup2+pop.
dvander@23
   333
dvander@23
   334
    // This is steps (1) to (5).
dvander@23
   335
    Expression *expr = node->expression();
dvander@23
   336
    if (expr->isNameProxy()) {
dvander@23
   337
        NameProxy *proxy = expr->toNameProxy();
dvander@23
   338
        Variable *var = proxy->binding()->toVariable();
dvander@23
   339
dvander@23
   340
        // Bind.
dvander@174
   341
        if (var->location() == Variable::ENVIRONMENT)
dvander@174
   342
            getEnvSlot(var);
dvander@174
   343
        else if (var->type()->isReference() || var->type()->isArray())
dvander@23
   344
            __ get(var);
dvander@23
   345
dvander@23
   346
        // Dup and fetch.
dvander@23
   347
        if (var->type()->isReference()) {
dvander@23
   348
            __ dup();
dvander@145
   349
            __ getref(node->type());
dvander@23
   350
            if (node->postfix()) {
dvander@23
   351
                __ swap();
dvander@23
   352
                __ pick2();
dvander@23
   353
            }
dvander@23
   354
        } else {
dvander@23
   355
            assert(!var->type()->isArray());
dvander@174
   356
            if (var->location() != Variable::ENVIRONMENT)
dvander@174
   357
                __ get(var);
dvander@23
   358
            if (node->postfix())
dvander@23
   359
                __ dup();
dvander@23
   360
        }
dvander@149
   361
    } else if (expr->isFieldExpression()) {
dvander@149
   362
        FieldExpression *field = expr->toFieldExpression();
dvander@149
   363
dvander@149
   364
        field->left()->accept(this);
dvander@149
   365
        __ dup();
dvander@149
   366
        __ getfield(field->fieldIndex(), field->type());
dvander@149
   367
dvander@149
   368
        if (node->postfix()) {
dvander@149
   369
            // The stack looks like this now:
dvander@149
   370
            // OBJECT VALUE
dvander@149
   371
            __ swap();          // VALUE OBJECT
dvander@149
   372
            __ pick2();         // VALUE OBJECT VALUE
dvander@149
   373
        }
dvander@23
   374
    } else {
dvander@23
   375
        IndexExpression *index = expr->toIndexExpression();
dvander@70
   376
        __ note_position(index->pos());
dvander@70
   377
dvander@23
   378
        index->left()->accept(this);
dvander@23
   379
        index->right()->accept(this);
dvander@23
   380
dvander@23
   381
        assert(!node->type()->isArray());
dvander@23
   382
        __ dup2();
dvander@157
   383
        __ getelem(node->type());
dvander@23
   384
dvander@23
   385
        if (node->postfix()) {
dvander@23
   386
            // The stack looks like this now:
dvander@23
   387
            // ARRAY INDEX VALUE
dvander@23
   388
            //
dvander@23
   389
            // So we must use a PICK operation to rotate the stack into position.
dvander@23
   390
            __ roll3();         // INDEX VALUE ARRAY
dvander@23
   391
            __ roll3();         // VALUE ARRAY INDEX
dvander@23
   392
            __ pick3();         // VALUE ARRAY INDEX VALUE
dvander@23
   393
        }
dvander@23
   394
    }
dvander@23
   395
dvander@23
   396
    // Perform step (6).
dvander@23
   397
    if (node->type()->isFloat()) {
dvander@23
   398
        __ float_(1.0);
dvander@23
   399
    } else {
dvander@23
   400
        assert(node->type()->isInt32());
dvander@23
   401
        __ int_(1);
dvander@23
   402
    }
dvander@23
   403
dvander@70
   404
    __ note_position(node->pos());
dvander@23
   405
    if (node->token() == TOK_INCREMENT)
dvander@23
   406
        __ binary(OP_ADD);
dvander@23
   407
    else
dvander@23
   408
        __ binary(OP_SUB);
dvander@23
   409
dvander@23
   410
    // Perform step (7).
dvander@23
   411
    if (expr->isNameProxy()) {
dvander@23
   412
        NameProxy *proxy = expr->toNameProxy();
dvander@23
   413
        Variable *var = proxy->binding()->toVariable();
dvander@23
   414
dvander@23
   415
        if (var->type()->isReference())
dvander@145
   416
            __ setref(node->type());
dvander@174
   417
        else if (var->location() == Variable::ENVIRONMENT)
dvander@174
   418
            setEnvSlot(var);
dvander@23
   419
        else
dvander@23
   420
            __ set(var);
dvander@149
   421
    } else if (expr->isFieldExpression()) {
dvander@149
   422
        FieldExpression *field = expr->toFieldExpression();
dvander@149
   423
        __ setfield(field->fieldIndex(), field->type());
dvander@23
   424
    } else {
dvander@149
   425
        assert(expr->isIndexExpression());
dvander@157
   426
        __ setelem(node->type());
dvander@23
   427
    }
dvander@23
   428
dvander@23
   429
    // Perform step (8).
dvander@23
   430
    if (node->postfix())
dvander@23
   431
        __ pop();
dvander@23
   432
}
dvander@23
   433
dvander@23
   434
void
dvander@4
   435
BytecodeCompiler::visitForALU(Type *needed, Expression *node)
dvander@4
   436
{
dvander@4
   437
    node->accept(this);
dvander@4
   438
    if (needed->isFloat() && !node->type()->isFloat())
dvander@4
   439
        __ cvt_i2f();
dvander@22
   440
    else
dvander@22
   441
        assert(needed->primitive() == node->type()->primitive());
dvander@4
   442
}
dvander@4
   443
dvander@74
   444
static inline Type *
dvander@74
   445
GetCoercionType(TokenKind tok, Type *left, Type *right)
dvander@74
   446
{
dvander@74
   447
    if (left->isFloat())
dvander@74
   448
        return left;
dvander@74
   449
    return right;
dvander@74
   450
}
dvander@74
   451
dvander@4
   452
void
dvander@78
   453
BytecodeCompiler::visit(UnaryExpression *node)
dvander@78
   454
{
dvander@145
   455
    Local<Type> out(zone_, ((Expression *)node)->type());
dvander@145
   456
dvander@78
   457
    switch (node->token()) {
dvander@80
   458
      case TOK_MINUS:
dvander@80
   459
      {
dvander@80
   460
        Local<Type> type(zone_, node->expression()->type());
dvander@80
   461
        node->expression()->accept(this);
dvander@80
   462
        
dvander@145
   463
        if (out->isFloat())
dvander@80
   464
            __ neg_f();
dvander@80
   465
        else
dvander@80
   466
            __ neg();
dvander@80
   467
        break;
dvander@80
   468
      }
dvander@80
   469
dvander@79
   470
      case TOK_NOT:
dvander@79
   471
      {
dvander@79
   472
        Local<Type> type(zone_, node->expression()->type());
dvander@79
   473
        node->expression()->accept(this);
dvander@79
   474
        
dvander@145
   475
        if (out->isFloat())
dvander@79
   476
            __ not_f();
dvander@79
   477
        else
dvander@79
   478
            __ not_();
dvander@79
   479
        break;
dvander@79
   480
      }
dvander@79
   481
dvander@142
   482
      case TOK_LABEL:
dvander@142
   483
      {
dvander@142
   484
        Local<Type> from(zone_, node->expression()->type());
dvander@142
   485
dvander@142
   486
        node->expression()->accept(this);
dvander@145
   487
        if (!from->isFloat() && out->isFloat())
dvander@142
   488
            __ bits_f2i();
dvander@145
   489
        else if (from->isFloat() && !out->isFloat())
dvander@142
   490
            __ bits_i2f();
dvander@142
   491
        break;
dvander@142
   492
      }
dvander@142
   493
dvander@78
   494
      default:
dvander@78
   495
        assert(node->token() == TOK_TILDE);
dvander@78
   496
        node->expression()->accept(this);
dvander@78
   497
        __ bitnot();
dvander@78
   498
        break;
dvander@78
   499
    }
dvander@78
   500
}
dvander@78
   501
dvander@78
   502
void
dvander@0
   503
BytecodeCompiler::visit(BinaryExpression *node)
dvander@0
   504
{
dvander@75
   505
    if (node->token() == TOK_AND || node->token() == TOK_OR) {
dvander@75
   506
        Label success, failure, done;
dvander@75
   507
        visitForTest(node, &success, &failure, &success);
dvander@75
   508
        __ bind(&success);
dvander@75
   509
        __ int_(1);
dvander@75
   510
        __ drop(1);         // Otherwise, the stack depth will be +1 too much.
dvander@75
   511
        __ jump(&done);
dvander@75
   512
        __ bind(&failure);
dvander@75
   513
        __ int_(0);
dvander@75
   514
        __ bind(&done);
dvander@75
   515
        return;
dvander@75
   516
    }
dvander@75
   517
dvander@74
   518
    Local<Type> leftType(zone_, node->left()->type());
dvander@74
   519
    Local<Type> rightType(zone_, node->right()->type());
dvander@74
   520
    Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
dvander@74
   521
dvander@74
   522
    visitForALU(coerce, node->left());
dvander@74
   523
    visitForALU(coerce, node->right());
dvander@0
   524
dvander@0
   525
    Opcode op = TokenToOpcode(node->token());
dvander@4
   526
    if (node->type()->isFloat())
dvander@4
   527
        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
dvander@70
   528
dvander@70
   529
    __ note_position(node->pos());
dvander@0
   530
    __ binary(op);
dvander@0
   531
}
dvander@0
   532
dvander@0
   533
void
dvander@0
   534
BytecodeCompiler::visit(IndexExpression *node)
dvander@0
   535
{
dvander@0
   536
    node->left()->accept(this);
dvander@0
   537
    node->right()->accept(this);
dvander@70
   538
    __ note_position(node->pos());
dvander@157
   539
    __ getelem(node->type());
dvander@0
   540
}
dvander@0
   541
dvander@0
   542
void
dvander@148
   543
BytecodeCompiler::visit(FieldExpression *node)
dvander@148
   544
{
dvander@148
   545
    node->left()->accept(this);
dvander@148
   546
    __ getfield(node->fieldIndex(), node->type());
dvander@148
   547
}
dvander@148
   548
dvander@148
   549
void
dvander@0
   550
BytecodeCompiler::visit(ReturnStatement *node)
dvander@0
   551
{
dvander@72
   552
    if (node->expression()) {
dvander@0
   553
        node->expression()->accept(this);
dvander@72
   554
        __ return_();
dvander@72
   555
    } else {
dvander@72
   556
        __ returnvoid();
dvander@72
   557
    }
dvander@0
   558
}
dvander@0
   559
dvander@0
   560
void
dvander@75
   561
BytecodeCompiler::visitForTest(Expression *expression,
dvander@75
   562
                               Label *trueBranch,
dvander@75
   563
                               Label *falseBranch,
dvander@75
   564
                               Label *fallthrough)
dvander@0
   565
{
dvander@0
   566
    TokenKind token = ToCompare(expression);
dvander@79
   567
    if (token == TOK_EOF || token == TOK_NOT) {
dvander@79
   568
        if (token == TOK_EOF)
dvander@79
   569
            expression->accept(this);
dvander@79
   570
        else
dvander@79
   571
            expression->toUnaryExpression()->expression()->accept(this);
dvander@79
   572
        
dvander@79
   573
        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
dvander@74
   574
dvander@79
   575
        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
dvander@74
   576
        if (expression->type()->isFloat())
dvander@74
   577
            op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
dvander@74
   578
dvander@79
   579
        if (fallthrough == falseBranch)
dvander@79
   580
            __ j(op, trueBranch);
dvander@75
   581
        else
dvander@79
   582
            __ j(op, falseBranch); 
dvander@75
   583
        return;
dvander@75
   584
    }
dvander@75
   585
dvander@75
   586
    BinaryExpression *binary = expression->toBinaryExpression();
dvander@75
   587
dvander@75
   588
    if (token == TOK_AND || token == TOK_OR) {
dvander@75
   589
        Label next;
dvander@75
   590
        if (token == TOK_AND)
dvander@75
   591
            visitForTest(binary->left(), &next, falseBranch, &next);
dvander@75
   592
        else
dvander@75
   593
            visitForTest(binary->left(), trueBranch, &next, &next);
dvander@75
   594
        __ bind(&next);
dvander@75
   595
        visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
dvander@0
   596
        return;
dvander@0
   597
    }
dvander@0
   598
dvander@0
   599
    Opcode op = CompareTokenToJump(token);
dvander@75
   600
    if (fallthrough == trueBranch)
dvander@0
   601
        op = Invert(op);
dvander@0
   602
dvander@74
   603
    Local<Type> leftType(zone_, binary->left()->type());
dvander@74
   604
    Local<Type> rightType(zone_, binary->right()->type());
dvander@74
   605
    Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
dvander@74
   606
dvander@74
   607
    visitForALU(coerce, binary->left());
dvander@74
   608
    visitForALU(coerce, binary->right());
dvander@74
   609
    if (coerce->isFloat())
dvander@74
   610
        op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
dvander@74
   611
dvander@75
   612
    if (fallthrough == trueBranch)
dvander@75
   613
        __ j(op, falseBranch);
dvander@75
   614
    else
dvander@75
   615
        __ j(op, trueBranch);
dvander@0
   616
}
dvander@0
   617
dvander@0
   618
void
dvander@0
   619
BytecodeCompiler::visit(ForStatement *node)
dvander@0
   620
{
dvander@1
   621
    AutoEnterScope forScope(this, node->scope());
dvander@1
   622
dvander@12
   623
    recordLifoSlot(node->scope());
dvander@12
   624
dvander@10
   625
    Label join, update;
dvander@10
   626
    LoopScope loop(scope_, &join, &update, &loop_);
dvander@10
   627
dvander@22
   628
    if (node->initialization())
dvander@22
   629
        node->initialization()->accept(this);
dvander@0
   630
dvander@0
   631
    Label header, test;
dvander@0
   632
    if (node->condition())
dvander@0
   633
        __ jump(&test);
dvander@0
   634
dvander@0
   635
    __ bind(&header);
dvander@0
   636
    node->body()->accept(this);
dvander@0
   637
dvander@10
   638
    __ bind(&update);
dvander@0
   639
    if (node->update())
dvander@0
   640
        node->update()->accept(this);
dvander@0
   641
dvander@0
   642
    if (node->condition()) {
dvander@0
   643
        __ bind(&test);
dvander@75
   644
        visitForTest(node->condition(), &header, &join, &join);
dvander@0
   645
    } else {
dvander@0
   646
        __ jump(&header);
dvander@0
   647
    }
dvander@0
   648
dvander@10
   649
    __ bind(&join);
dvander@10
   650
dvander@12
   651
    if (node->scope())
dvander@12
   652
        unwindTo(node->scope()->enclosing());
dvander@0
   653
    assert(__ stackDepth() == 0);
dvander@0
   654
}
dvander@0
   655
dvander@0
   656
void
dvander@9
   657
BytecodeCompiler::visit(WhileStatement *node)
dvander@9
   658
{
dvander@10
   659
    Label header, join;
dvander@9
   660
dvander@9
   661
    __ bind(&header);
dvander@9
   662
dvander@10
   663
    LoopScope loop(scope_, &join, &header, &loop_);
dvander@10
   664
dvander@9
   665
    if (node->token() == TOK_WHILE) {
dvander@75
   666
        Label body;
dvander@75
   667
dvander@75
   668
        visitForTest(node->condition(), &body, &join, &body);
dvander@75
   669
        __ bind(&body);
dvander@9
   670
        node->body()->accept(this);
dvander@9
   671
        __ jump(&header);
dvander@9
   672
    } else {
dvander@9
   673
        node->body()->accept(this);
dvander@75
   674
        visitForTest(node->condition(), &header, &join, &join);
dvander@9
   675
    }
dvander@10
   676
dvander@10
   677
    __ bind(&join);
dvander@10
   678
}
dvander@10
   679
dvander@10
   680
void
dvander@10
   681
BytecodeCompiler::visit(BreakStatement *node)
dvander@10
   682
{
dvander@10
   683
    unwindTo(loop_->scope());
dvander@10
   684
    __ jump(loop_->break_());
dvander@10
   685
}
dvander@10
   686
dvander@10
   687
void
dvander@10
   688
BytecodeCompiler::visit(ContinueStatement *node)
dvander@10
   689
{
dvander@10
   690
    unwindTo(loop_->scope());
dvander@10
   691
    __ jump(loop_->continue_());
dvander@9
   692
}
dvander@9
   693
dvander@9
   694
void
dvander@0
   695
BytecodeCompiler::visit(BlockStatement *node)
dvander@0
   696
{
dvander@1
   697
    AutoEnterScope blockScope(this, node->scope());
dvander@1
   698
dvander@12
   699
    recordLifoSlot(node->scope());
dvander@12
   700
dvander@0
   701
    for (size_t i = 0; i < node->statements()->length(); i++) {
dvander@0
   702
        Statement *statement = node->statements()->at(i);
dvander@0
   703
        statement->accept(this);
dvander@0
   704
        assert(__ stackDepth() == 0);
dvander@0
   705
    }
dvander@1
   706
dvander@1
   707
    // We don't bother emitting an "unwind" instruction for function scopes,
dvander@1
   708
    // since this is taken care of by the calling convention.
dvander@1
   709
    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
dvander@12
   710
        unwindTo(node->scope()->enclosing());
dvander@0
   711
}
dvander@0
   712
dvander@0
   713
void
dvander@4
   714
BytecodeCompiler::visit(IntegerLiteral *node)
dvander@0
   715
{
dvander@0
   716
    __ int_(node->value());
dvander@0
   717
}
dvander@0
   718
dvander@0
   719
void
dvander@143
   720
BytecodeCompiler::visit(BooleanLiteral *node)
dvander@143
   721
{
dvander@143
   722
    if (node->token() == TOK_TRUE)
dvander@143
   723
        __ true_();
dvander@143
   724
    else
dvander@143
   725
        __ false_();
dvander@143
   726
}
dvander@143
   727
dvander@143
   728
void
dvander@4
   729
BytecodeCompiler::visit(FloatLiteral *node)
dvander@4
   730
{
dvander@4
   731
    __ float_((float)node->value());
dvander@4
   732
}
dvander@4
   733
dvander@4
   734
void
dvander@21
   735
BytecodeCompiler::visit(StringLiteral *node)
dvander@21
   736
{
dvander@30
   737
    Local<Type> type(zone_, node->type());
dvander@169
   738
    Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
dvander@21
   739
    if (!map)
dvander@21
   740
        return;
dvander@21
   741
dvander@169
   742
    Local<Array> array(zone_,
dvander@169
   743
        Array::NewString(zone_,
dvander@169
   744
                         map,
dvander@169
   745
                         node->string()->raw(),
dvander@169
   746
                         node->string()->length(),
dvander@169
   747
                         Heap::Tenure_Old));
dvander@21
   748
    if (!array)
dvander@21
   749
        return;
dvander@21
   750
dvander@70
   751
    __ note_position(node->pos());
dvander@21
   752
    __ object(array);
dvander@21
   753
}
dvander@21
   754
dvander@21
   755
void
dvander@85
   756
BytecodeCompiler::getEnvSlot(Variable *var)
dvander@85
   757
{
dvander@85
   758
    assert(var->scope()->kind() == Scope::GLOBAL);
dvander@85
   759
    __ getglobal(var);
dvander@85
   760
}
dvander@85
   761
dvander@85
   762
void
dvander@85
   763
BytecodeCompiler::setEnvSlot(Variable *var)
dvander@85
   764
{
dvander@85
   765
    assert(var->scope()->kind() == Scope::GLOBAL);
dvander@85
   766
    __ setglobal(var);
dvander@85
   767
}
dvander@85
   768
dvander@85
   769
void
dvander@0
   770
BytecodeCompiler::visit(VariableDeclaration *node)
dvander@0
   771
{
dvander@0
   772
    Variable *var = node->variable();
dvander@0
   773
    
dvander@30
   774
    Local<Type> type(zone_, var->type());
dvander@0
   775
    if (type->isArray()) {
dvander@169
   776
        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
dvander@70
   777
        __ note_position(node->pos());
dvander@85
   778
        if (var->scope()->kind() == Scope::GLOBAL)
dvander@85
   779
            __ newarray(map, Heap::Tenure_Old);
dvander@85
   780
        else if (var->needsHeapAllocation())
dvander@85
   781
            __ newarray(map, Heap::Tenure_Default);
dvander@85
   782
        else
dvander@85
   783
            __ newarray(map, Heap::Tenure_Stack);
dvander@21
   784
dvander@21
   785
        if (node->initialization()) {
dvander@21
   786
            node->initialization()->accept(this);
dvander@70
   787
            __ note_position(node->pos());
dvander@152
   788
            __ copyarray();
dvander@21
   789
        }
dvander@147
   790
    } else if (type->isStruct()) {
dvander@147
   791
        Local<Map> map(zone_, type->newMap());
dvander@147
   792
        if (var->scope()->kind() == Scope::GLOBAL)
dvander@147
   793
            __ newstruct(map, Heap::Tenure_Old);
dvander@147
   794
        else if (var->needsHeapAllocation())
dvander@147
   795
            __ newstruct(map, Heap::Tenure_Default);
dvander@147
   796
        else
dvander@147
   797
            __ newstruct(map, Heap::Tenure_Stack);
dvander@0
   798
    } else {
dvander@0
   799
        if (node->initialization()) {
dvander@0
   800
            node->initialization()->accept(this);
dvander@0
   801
        } else {
dvander@147
   802
            if (type->isInt32OrEnum() || type->isBool()) {
dvander@0
   803
                __ int_(0);
dvander@147
   804
            } else {
dvander@147
   805
                assert(type->isFloat());
dvander@147
   806
                __ float_(0);
dvander@147
   807
            }
dvander@0
   808
        }
dvander@0
   809
    }
dvander@85
   810
dvander@85
   811
    if (var->location() == Variable::STACK) {
dvander@85
   812
        __ setlocal(var);
dvander@85
   813
        locals_->set(zone_, var->slot(), var->type());
dvander@85
   814
    } else {
dvander@85
   815
        assert(var->location() == Variable::ENVIRONMENT);
dvander@85
   816
        setEnvSlot(var);
dvander@85
   817
    }
dvander@85
   818
dvander@0
   819
    __ pop();
dvander@0
   820
}
dvander@0
   821
dvander@0
   822
void
dvander@0
   823
BytecodeCompiler::visit(CallExpression *node)
dvander@0
   824
{
dvander@32
   825
    Local<Type> funType(zone_, node->callee()->type());
dvander@14
   826
dvander@73
   827
    // Sniff out natives, which have a specific opcode and are guaranteed to
dvander@73
   828
    // be called via name proxy.
dvander@73
   829
    NamedFunction *native = NULL;
dvander@73
   830
    if (funType->isNative()) {
dvander@73
   831
        native = node->callee()->toNameProxy()->binding()->toNamedFunction();
dvander@73
   832
    }
dvander@73
   833
dvander@168
   834
    Local<Type> given(zone_);
dvander@68
   835
    for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
dvander@0
   836
        Expression *arg = node->arguments()->at(i);
dvander@14
   837
dvander@168
   838
        given = arg->type();
dvander@168
   839
dvander@68
   840
        // We need to compute a reference if the parameter was in the form:
dvander@68
   841
        //  f(&a)
dvander@68
   842
        // Note this form does not allow: f({})
dvander@68
   843
        // 
dvander@68
   844
        // We also need to compute references for all variadic native
dvander@68
   845
        // arguments, but arrays and references are already in the
dvander@68
   846
        // appropriate form.
dvander@69
   847
        bool mustPushReference = false;
dvander@69
   848
        if (i >= funType->parameters()->length()) {
dvander@68
   849
            assert(funType->isNative() && funType->isNativeVariadic());
dvander@69
   850
            mustPushReference = !given->isArray() && !given->isReference();
dvander@69
   851
        } else if (funType->parameterAt(i)->isReference()) {
dvander@69
   852
            mustPushReference = !given->isReference();
dvander@69
   853
        }
dvander@68
   854
dvander@68
   855
        // If a native is passed to a native, it must only be one level deep.
dvander@68
   856
        assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
dvander@68
   857
dvander@68
   858
        if (mustPushReference) {
dvander@68
   859
            if (arg->isNameProxy()) {
dvander@14
   860
                // :TODO: test with functions and globals
dvander@14
   861
                // Compute a reference to the name.
dvander@14
   862
                Variable *var = arg->toNameProxy()->binding()->toVariable();
dvander@70
   863
                __ note_position(node->pos());
dvander@14
   864
                __ newref(var);
dvander@17
   865
            } else if (arg->isIndexExpression()) {
dvander@17
   866
                IndexExpression *expr = arg->toIndexExpression();
dvander@17
   867
                expr->left()->accept(this);
dvander@17
   868
                expr->right()->accept(this);
dvander@70
   869
                __ note_position(expr->pos());
dvander@17
   870
                __ arrayref_lifo();
dvander@164
   871
            } else if (arg->isFieldExpression()) {
dvander@164
   872
                FieldExpression *expr = arg->toFieldExpression();
dvander@164
   873
                expr->left()->accept(this);
dvander@164
   874
                __ note_position(expr->pos());
dvander@164
   875
                __ fieldref_lifo(expr->fieldIndex());
dvander@14
   876
            } else {
dvander@14
   877
                // We don't know how to, or can't, build a direct reference to
dvander@14
   878
                // this type. Make an indirect one, by taking the top of the
dvander@14
   879
                // stack and boxing it up.
dvander@16
   880
                arg->accept(this);
dvander@70
   881
                __ note_position(node->pos());
dvander@14
   882
                __ slotref_lifo();
dvander@14
   883
            }
dvander@14
   884
        } else {
dvander@14
   885
            arg->accept(this);
dvander@14
   886
        }
dvander@0
   887
    }
dvander@0
   888
dvander@168
   889
    unsigned argc = node->arguments()->length();
dvander@168
   890
dvander@168
   891
    // If there are missing arguments, then we're not done and have to push
dvander@168
   892
    // default parameters.
dvander@168
   893
    Local<Box> box(zone_);
dvander@169
   894
    Local<Array> array(zone_);
dvander@169
   895
    Local<ArrayMap> map(zone_);
dvander@168
   896
    for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
dvander@168
   897
        box = Box::cast(funType->defaults()->at(i));
dvander@168
   898
dvander@168
   899
        if (box->type()->isPod()) {
dvander@168
   900
            if (box->type()->pod() == PrimitiveType_Int32)
dvander@168
   901
                __ int_(box->toInt32());
dvander@168
   902
            else if (box->type()->pod() == PrimitiveType_Float)
dvander@168
   903
                __ float_(box->toFloat());
dvander@168
   904
            else
dvander@168
   905
                assert(false);
dvander@169
   906
dvander@169
   907
            if (funType->parameterAt(i)->isReference()) {
dvander@169
   908
                __ note_position(node->pos());
dvander@169
   909
                __ slotref_lifo();
dvander@169
   910
            }
dvander@168
   911
        } else {
dvander@169
   912
            assert(box->type()->isArray());
dvander@168
   913
dvander@169
   914
            array = Array::cast(box->toObject());
dvander@169
   915
            if (funType->parameterAt(i)->isConst()) {
dvander@169
   916
                __ object(array);
dvander@169
   917
            } else {
dvander@169
   918
                // We need to copy the array since it's mutable. Note that
dvander@169
   919
                // although COPYARRAY returns its left-hand side, this may
dvander@169
   920
                // change in the future, we do the same thing and dupe the
dvander@169
   921
                // newly allocated array.
dvander@169
   922
                map = ArrayMap::cast(array->map());
dvander@169
   923
                __ newarray(map, Heap::Tenure_Stack);
dvander@169
   924
                __ dup();
dvander@169
   925
                __ object(array);
dvander@169
   926
                __ copyarray();
dvander@169
   927
                __ pop();
dvander@169
   928
            }
dvander@168
   929
        }
dvander@168
   930
dvander@168
   931
        argc++;
dvander@168
   932
    }
dvander@168
   933
dvander@70
   934
    __ note_position(node->pos());
dvander@73
   935
    if (native) {
dvander@168
   936
        __ callnative(native->slot(), argc);
dvander@168
   937
        __ drop(argc);
dvander@73
   938
    } else {
dvander@73
   939
        node->callee()->accept(this);
dvander@73
   940
        __ call(funType);
dvander@168
   941
        __ drop(argc + 1);
dvander@73
   942
    }
dvander@0
   943
}
dvander@0
   944
dvander@0
   945
void
dvander@83
   946
BytecodeCompiler::visit(TernaryExpression *node)
dvander@83
   947
{
dvander@83
   948
    Label success, failure, join;
dvander@83
   949
dvander@83
   950
    visitForTest(node->condition(), &success, &failure, &success);
dvander@83
   951
    __ bind(&success);
dvander@83
   952
    node->left()->accept(this);
dvander@83
   953
    __ drop(1);
dvander@83
   954
    __ jump(&join);
dvander@83
   955
    __ bind(&failure);
dvander@83
   956
    node->right()->accept(this);
dvander@83
   957
    __ bind(&join);
dvander@83
   958
}
dvander@83
   959
dvander@83
   960
void
dvander@0
   961
BytecodeCompiler::visit(IfStatement *node)
dvander@0
   962
{
dvander@75
   963
    Label join;
dvander@0
   964
    if (!node->ifFalse()) {
dvander@75
   965
        Label success;
dvander@75
   966
dvander@75
   967
        visitForTest(node->condition(), &success, &join, &success);
dvander@75
   968
        __ bind(&success);
dvander@0
   969
        node->ifTrue()->accept(this);
dvander@0
   970
    } else {
dvander@75
   971
        Label success, next;
dvander@75
   972
dvander@75
   973
        visitForTest(node->condition(), &success, &next, &success);
dvander@75
   974
        __ bind(&success);
dvander@0
   975
        node->ifTrue()->accept(this);
dvander@0
   976
        __ jump(&join);
dvander@75
   977
        __ bind(&next);
dvander@0
   978
        node->ifFalse()->accept(this);
dvander@0
   979
    }
dvander@75
   980
dvander@75
   981
    __ bind(&join);
dvander@0
   982
}
dvander@0
   983
dvander@172
   984
bool
dvander@172
   985
BytecodeCompiler::tableswitch(SwitchStatement *node)
dvander@172
   986
{
dvander@172
   987
    CaseValueList *values = node->caseValueList();
dvander@172
   988
dvander@172
   989
    if (values->length() < 3)
dvander@172
   990
        return false;
dvander@172
   991
dvander@172
   992
    // Find the delta between the largest and smallest value.
dvander@172
   993
    int hi = values->at(values->length() - 1).box.toInt();
dvander@172
   994
    int lo = values->at(0).box.toInt();
dvander@172
   995
    assert(hi > lo);
dvander@172
   996
dvander@172
   997
    unsigned tablesize = TableSwitchEntries(lo, hi);
dvander@172
   998
    if (tablesize > MAX_TABLESWITCH_ENTRIES)
dvander@172
   999
        return false;
dvander@172
  1000
dvander@172
  1001
    Label def, join;
dvander@172
  1002
dvander@172
  1003
    // Create the list of labels that each statement will bind to.
dvander@172
  1004
    Label *labels = new Label[node->cases()->length()];
dvander@172
  1005
dvander@172
  1006
    // Create the table of labels we'll use for each case.
dvander@172
  1007
    Label **table = new Label *[tablesize];
dvander@172
  1008
dvander@172
  1009
    // Link all cases, by default, to the default label.
dvander@172
  1010
    for (size_t i = 0; i < tablesize; i++)
dvander@172
  1011
        table[i] = &def;
dvander@172
  1012
dvander@172
  1013
    // Now patch actual cases to their correct labels.
dvander@172
  1014
    for (size_t i = 0; i < values->length(); i++) {
dvander@172
  1015
        CaseValue &v = values->at(i);
dvander@172
  1016
        assert(v.statement < node->cases()->length());
dvander@172
  1017
dvander@172
  1018
        unsigned index = unsigned(v.box.toInt() - lo);
dvander@172
  1019
        assert(index < tablesize);
dvander@172
  1020
dvander@172
  1021
        table[index] = &labels[v.statement];
dvander@172
  1022
    }
dvander@172
  1023
dvander@172
  1024
    // Emit the tableswitch opcode and the jump table.
dvander@172
  1025
    __ tableswitch(lo, hi, &def, table);
dvander@172
  1026
dvander@172
  1027
    // We're done with the jump table now.
dvander@172
  1028
    delete [] table;
dvander@172
  1029
dvander@172
  1030
    // Emit each statement.
dvander@172
  1031
    for (size_t i = 0; i < node->cases()->length(); i++) {
dvander@172
  1032
        Statement *stmt = node->cases()->at(i)->statement();
dvander@172
  1033
dvander@172
  1034
        __ bind(&labels[i]);
dvander@172
  1035
        stmt->accept(this);
dvander@172
  1036
        __ jump(&join);
dvander@172
  1037
    }
dvander@172
  1038
dvander@172
  1039
    // We're done with the statement labels.
dvander@172
  1040
    delete [] labels;
dvander@172
  1041
dvander@172
  1042
    // Emit the default case.
dvander@172
  1043
    __ bind(&def);
dvander@172
  1044
    if (node->defaultCase())
dvander@172
  1045
        node->defaultCase()->accept(this);
dvander@172
  1046
dvander@172
  1047
    __ bind(&join);
dvander@172
  1048
dvander@172
  1049
    return true;
dvander@172
  1050
}
dvander@172
  1051
dvander@172
  1052
void
dvander@172
  1053
BytecodeCompiler::visit(SwitchStatement *node)
dvander@172
  1054
{
dvander@172
  1055
    node->expression()->accept(this);
dvander@172
  1056
dvander@172
  1057
    if (tableswitch(node))
dvander@172
  1058
        return;
dvander@172
  1059
dvander@172
  1060
    Label join;
dvander@172
  1061
dvander@172
  1062
    for (size_t i = 0; i < node->cases()->length(); i++) {
dvander@172
  1063
        Case *c = node->cases()->at(i);
dvander@172
  1064
dvander@172
  1065
        Label success, fail;
dvander@172
  1066
        if (c->others()) {
dvander@172
  1067
            for (size_t j = 0; j < c->others()->length(); j++) {
dvander@172
  1068
                Expression *expr = c->others()->at(j);
dvander@172
  1069
dvander@172
  1070
                __ dup();
dvander@172
  1071
                expr->accept(this);
dvander@172
  1072
                __ j(OP_JEQ, &success);
dvander@172
  1073
            }
dvander@172
  1074
        }
dvander@172
  1075
dvander@172
  1076
        // The final test.
dvander@172
  1077
        __ dup();
dvander@172
  1078
        c->expression()->accept(this);
dvander@172
  1079
        __ j(OP_JNE, &fail);
dvander@172
  1080
        __ bind(&success);
dvander@172
  1081
        c->statement()->accept(this);
dvander@172
  1082
        __ jump(&join);
dvander@172
  1083
        __ bind(&fail);
dvander@172
  1084
    }
dvander@172
  1085
dvander@172
  1086
    if (node->defaultCase())
dvander@172
  1087
        node->defaultCase()->accept(this);
dvander@172
  1088
dvander@173
  1089
    __ pop();
dvander@172
  1090
    __ bind(&join);
dvander@172
  1091
}
dvander@172
  1092
dvander@0
  1093
void
dvander@0
  1094
BytecodeCompiler::visit(FunctionStatement *node)
dvander@0
  1095
{
dvander@137
  1096
    if (!node->fun()->used())
dvander@137
  1097
        return;
dvander@137
  1098
dvander@68
  1099
    if (node->fun()->isNative()) {
dvander@68
  1100
        assert(!moduleData_->natives->at(node->fun()->slot()));
dvander@68
  1101
dvander@68
  1102
        Local<Type> type(zone_, node->fun()->type());
dvander@68
  1103
        Local<String> name(zone_, node->fun()->name());
dvander@68
  1104
        Local<Native> native(zone_, Native::New(zone_, type, name));
dvander@68
  1105
        if (!native)
dvander@68
  1106
            return;
dvander@68
  1107
dvander@68
  1108
        moduleData_->natives->set(zone_, node->fun()->slot(), native);
dvander@68
  1109
        return;
dvander@68
  1110
    }
dvander@68
  1111
dvander@63
  1112
    // If the function has no body, then it's just a declaration.
dvander@63
  1113
    if (!node->body()) {
dvander@63
  1114
        assert(node->fun()->isForward() || node->fun()->isPublic());
dvander@63
  1115
        return;
dvander@63
  1116
    }
dvander@63
  1117
dvander@65
  1118
    BytecodeCompiler child(zone_, tree_, moduleData_);
dvander@65
  1119
    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
dvander@26
  1120
    if (!fun)
dvander@26
  1121
        return;
dvander@0
  1122
    
dvander@65
  1123
    assert(!moduleData_->module->getFunction(node->fun()->slot()));
dvander@65
  1124
    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
dvander@0
  1125
}
dvander@0
  1126
dvander@2
  1127
void
dvander@174
  1128
BytecodeCompiler::visit(FunctionTypeStatement *node)
dvander@174
  1129
{
dvander@174
  1130
}
dvander@174
  1131
dvander@174
  1132
void
dvander@2
  1133
BytecodeCompiler::visit(EnumStatement *node)
dvander@2
  1134
{
dvander@2
  1135
}
dvander@2
  1136
dvander@146
  1137
void
dvander@146
  1138
BytecodeCompiler::visit(StructureStatement *node)
dvander@146
  1139
{
dvander@146
  1140
}
dvander@146
  1141
dvander@85
  1142
Code *
dvander@85
  1143
BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
dvander@0
  1144
{
dvander@72
  1145
    // STOP doubles as RETURNVOID.
dvander@0
  1146
    __ stop();
dvander@0
  1147
dvander@69
  1148
    if (__ oom() || zone_->hasPendingException())
dvander@12
  1149
        return NULL;
dvander@0
  1150
dvander@32
  1151
    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
dvander@12
  1152
    if (!bytes)
dvander@12
  1153
        return NULL;
dvander@12
  1154
    memcpy(bytes->raw(), __ buffer(), __ length());
dvander@0
  1155
dvander@85
  1156
    for (size_t i = 0; i < scope->maxContainedLocals(); i++)
dvander@12
  1157
        assert(locals_->at(i));
dvander@0
  1158
dvander@58
  1159
    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
dvander@21
  1160
    if (!objects)
dvander@12
  1161
        return NULL;
dvander@0
  1162
dvander@58
  1163
    for (size_t i = 0; i < __ objects()->length(); i++)
dvander@33
  1164
        objects->set(zone_, i, *(__ objects()->at(i)));
dvander@12
  1165
dvander@47
  1166
    Local<ByteArray> safepoints(zone_);
dvander@47
  1167
dvander@47
  1168
    // If any stack slots hold gc pointers at potential failure points in the
dvander@47
  1169
    // bytecode, record them now. We do this by building a list of tuples;
dvander@47
  1170
    // each tuple contains the pc offset, and a bitset containing which stack
dvander@47
  1171
    // slots must be scanned by the gc.
dvander@58
  1172
    if (__ oopRecords()->length()) {
dvander@47
  1173
        size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
dvander@58
  1174
        size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
dvander@47
  1175
        safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
dvander@47
  1176
        if (!safepoints)
dvander@47
  1177
            return NULL;
dvander@47
  1178
dvander@47
  1179
        Address cursor = safepoints->raw();
dvander@58
  1180
        for (size_t i = 0; i < __ oopRecords()->length(); i++) {
dvander@47
  1181
            OopRecord *record = __ oopRecords()->at(i);
dvander@47
  1182
            assert(record->depth <= __ maxStackDepth());
dvander@47
  1183
dvander@47
  1184
            *reinterpret_cast<unsigned *>(cursor) = record->offset;
dvander@47
  1185
dvander@47
  1186
            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
dvander@47
  1187
            for (unsigned i = 0; i < record->depth; i++)
dvander@47
  1188
                bits[i / 8] |= (1 << (i % 8));
dvander@47
  1189
dvander@47
  1190
            cursor += bytesPerSafepoint;
dvander@47
  1191
        }
dvander@47
  1192
dvander@47
  1193
        assert(cursor == safepoints->raw() + gcmapSize);
dvander@47
  1194
    }
dvander@47
  1195
dvander@70
  1196
    Local<ByteArray> sourcemap(zone_);
dvander@70
  1197
    if (__ sourcemapLength()) {
dvander@70
  1198
        sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
dvander@70
  1199
        if (!sourcemap)
dvander@70
  1200
            return NULL;
dvander@70
  1201
dvander@70
  1202
        memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
dvander@70
  1203
    }
dvander@70
  1204
dvander@70
  1205
    Local<Code> code(zone_);
dvander@70
  1206
dvander@70
  1207
    code = Code::New(zone_,
dvander@70
  1208
                     bytes,
dvander@70
  1209
                     locals_,
dvander@70
  1210
                     objects,
dvander@70
  1211
                     __ maxStackDepth(),
dvander@70
  1212
                     moduleData_->module,
dvander@70
  1213
                     safepoints,
dvander@70
  1214
                     sourcemap,
dvander@85
  1215
                     lineno);
dvander@85
  1216
    return code;
dvander@85
  1217
}
dvander@85
  1218
dvander@85
  1219
Function *
dvander@85
  1220
BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
dvander@85
  1221
{
dvander@85
  1222
    // Note: No need to record a life slot here, since it's part of the Frame.
dvander@85
  1223
    AutoEnterScope functionScope(this, node->scope());
dvander@85
  1224
dvander@85
  1225
    // Set the initial line, because line mappings are deltas.
dvander@85
  1226
    __ setFirstLine(node->pos().line);
dvander@85
  1227
    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
dvander@85
  1228
dvander@85
  1229
    node->body()->accept(this);
dvander@85
  1230
dvander@85
  1231
    unsigned nargs = node->scope()->numArguments();
dvander@85
  1232
    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
dvander@85
  1233
    if (!args)
dvander@85
  1234
        return NULL;
dvander@85
  1235
dvander@85
  1236
    for (size_t i = 0; i < node->scope()->numArguments(); i++)
dvander@85
  1237
        args->set(zone_, i, node->scope()->getArgument(i)->type());
dvander@85
  1238
dvander@85
  1239
dvander@85
  1240
    Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
dvander@26
  1241
    if (!code)
dvander@26
  1242
        return NULL;
dvander@26
  1243
dvander@64
  1244
    Local<Type> type(zone_, node->fun()->type());
dvander@64
  1245
    Local<String> name(zone_, node->fun()->name());
dvander@64
  1246
    Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
dvander@26
  1247
    if (!fun)
dvander@26
  1248
        return NULL;
dvander@64
  1249
dvander@64
  1250
    // If this function had a forward, export it as a named public.
dvander@64
  1251
    if (node->fun()->isPublic()) {
dvander@64
  1252
        assert(node->fun()->isPublic());
dvander@64
  1253
        ScopedRoot<Function> root(fun);
dvander@64
  1254
        if (!root)
dvander@64
  1255
            return NULL;
dvander@65
  1256
        if (!moduleData_->publics.append(root))
dvander@64
  1257
            return NULL;
dvander@64
  1258
    }
dvander@66
  1259
dvander@153
  1260
#ifndef NDEBUG
dvander@66
  1261
    Disassemble(code, stdout);
dvander@153
  1262
#endif
dvander@26
  1263
    
dvander@26
  1264
    return fun;
dvander@0
  1265
}
dvander@0
  1266
dvander@0
  1267
Module *
dvander@0
  1268
BytecodeCompiler::compile()
dvander@0
  1269
{
dvander@85
  1270
    AutoEnterScope scope(this, tree_->scope());
dvander@85
  1271
dvander@65
  1272
    ModuleData moduleData;
dvander@65
  1273
dvander@65
  1274
    moduleData_ = &moduleData;
dvander@65
  1275
    moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
dvander@65
  1276
dvander@65
  1277
    if (!moduleData_)
dvander@14
  1278
        return NULL;
dvander@68
  1279
    
dvander@68
  1280
    moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
dvander@68
  1281
    if (!moduleData_->natives)
dvander@68
  1282
        return NULL;
dvander@0
  1283
dvander@0
  1284
    for (size_t i = 0; i < tree_->statements()->length(); i++) {
dvander@0
  1285
        Statement *statement = tree_->statements()->at(i);
dvander@0
  1286
        statement->accept(this);
dvander@0
  1287
    }
dvander@0
  1288
dvander@69
  1289
    if (zone_->hasPendingException())
dvander@69
  1290
        return NULL;
dvander@69
  1291
dvander@0
  1292
#ifndef NDEBUG
dvander@0
  1293
    for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
dvander@65
  1294
        assert(moduleData_->module->getFunction(i));
dvander@68
  1295
    for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
dvander@68
  1296
        assert(moduleData_->natives->at(i));
dvander@0
  1297
#endif
dvander@0
  1298
dvander@65
  1299
    if (moduleData_->publics.length()) {
dvander@64
  1300
        Local<Function> fun(zone_);
dvander@65
  1301
        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
dvander@65
  1302
                               Heap::Tenure_Old));
dvander@64
  1303
        if (!list)
dvander@64
  1304
            return NULL;
dvander@64
  1305
dvander@65
  1306
        for (size_t i = 0; i < moduleData_->publics.length(); i++)
dvander@65
  1307
            list->set(zone_, i, moduleData_->publics[i]);
dvander@65
  1308
dvander@65
  1309
        moduleData_->module->setPublics(list);
dvander@64
  1310
    }
dvander@64
  1311
dvander@68
  1312
    moduleData_->module->setNatives(moduleData_->natives);
dvander@68
  1313
dvander@85
  1314
    if (scope_->numEnvironmentVars()) {
dvander@85
  1315
        Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
dvander@85
  1316
        if (!globalMap)
dvander@85
  1317
            return NULL;
dvander@85
  1318
dvander@85
  1319
        Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
dvander@85
  1320
        if (!environment)
dvander@85
  1321
            return NULL;
dvander@85
  1322
dvander@85
  1323
        moduleData_->module->setEnvironment(environment);
dvander@85
  1324
    }
dvander@85
  1325
dvander@85
  1326
    Local<Code> code(zone_, compileCode(tree_->scope(), 1));
dvander@85
  1327
    if (!code)
dvander@85
  1328
        return NULL;
dvander@85
  1329
dvander@85
  1330
    Disassemble(code, stdout);
dvander@85
  1331
dvander@85
  1332
    moduleData_->module->setCode(code);
dvander@85
  1333
dvander@65
  1334
    return moduleData_->module;
dvander@0
  1335
}