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