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