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