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