jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jul 12 00:38:00 2012 -0700 (2012-07-12)
changeset 70 1aec996cde2d
parent 69 dfce0539a77d
child 72 40746ab0a30b
permissions -rw-r--r--
Add support for line and file information in backtraces.
dvander@28
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@28
     2
 *
dvander@0
     3
 * Copyright (C) 2012 David Anderson
dvander@0
     4
 *
dvander@0
     5
 * This file is part of JITCraft.
dvander@0
     6
 *
dvander@0
     7
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@0
     8
 * the terms of the GNU General Public License as published by the Free
dvander@0
     9
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@0
    10
 * any later version.
dvander@0
    11
 * 
dvander@0
    12
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@0
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@0
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@0
    15
 *
dvander@0
    16
 * You should have received a copy of the GNU General Public License along with
dvander@0
    17
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@0
    18
 */
dvander@0
    19
#include "BytecodeCompiler.h"
dvander@0
    20
#include "Scopes.h"
dvander@0
    21
#include "Modules.h"
dvander@0
    22
#include "Types.h"
dvander@12
    23
#include "Array.h"
dvander@54
    24
#include "Strings.h"
dvander@12
    25
#include "Zone.h"
dvander@12
    26
#include "Heap-inl.h"
dvander@0
    27
dvander@59
    28
using namespace ke;
dvander@0
    29
dvander@0
    30
typedef BytecodeEmitter::Label Label;
dvander@0
    31
dvander@0
    32
#define __ emitter_.
dvander@0
    33
dvander@65
    34
BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
dvander@30
    35
  : zone_(zone),
dvander@30
    36
    tree_(tree),
dvander@47
    37
    emitter_(zone->pool()),
dvander@65
    38
    moduleData_(module),
dvander@28
    39
    locals_(NULL),
dvander@10
    40
    scope_(NULL),
dvander@28
    41
    loop_(NULL)
dvander@0
    42
{
dvander@0
    43
}
dvander@0
    44
dvander@0
    45
static inline TokenKind
dvander@0
    46
ToCompare(Expression *expr)
dvander@0
    47
{
dvander@0
    48
    if (expr->isBinaryExpression()) {
dvander@0
    49
        BinaryExpression *b = expr->toBinaryExpression();
dvander@0
    50
        if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
dvander@0
    51
            return b->token();
dvander@0
    52
    }
dvander@0
    53
    return TOK_EOF;
dvander@0
    54
}
dvander@0
    55
dvander@0
    56
static inline Opcode
dvander@0
    57
CompareTokenToJump(TokenKind kind)
dvander@0
    58
{
dvander@0
    59
    switch (kind) {
dvander@0
    60
      case TOK_EQUALS:
dvander@0
    61
        return OP_JEQ;
dvander@0
    62
      case TOK_NOTEQUALS:
dvander@0
    63
        return OP_JNE;
dvander@0
    64
      case TOK_GT:
dvander@0
    65
        return OP_JG;
dvander@0
    66
      case TOK_GE:
dvander@0
    67
        return OP_JGE;
dvander@0
    68
      case TOK_LT:
dvander@0
    69
        return OP_JL;
dvander@28
    70
      default:
dvander@28
    71
        assert(kind == TOK_LE);
dvander@0
    72
        return OP_JLE;
dvander@0
    73
    }
dvander@0
    74
}
dvander@0
    75
dvander@0
    76
static inline Opcode
dvander@0
    77
TokenToOpcode(TokenKind kind)
dvander@0
    78
{
dvander@0
    79
    switch (kind) {
dvander@0
    80
      case TOK_PLUS:
dvander@0
    81
        return OP_ADD;
dvander@0
    82
      case TOK_MINUS:
dvander@0
    83
        return OP_SUB;
dvander@0
    84
      case TOK_STAR:
dvander@0
    85
        return OP_MUL;
dvander@0
    86
      case TOK_SLASH:
dvander@0
    87
        return OP_DIV;
dvander@8
    88
      case TOK_SHR:
dvander@8
    89
        return OP_SHR;
dvander@8
    90
      case TOK_USHR:
dvander@8
    91
        return OP_USHR;
dvander@8
    92
      case TOK_SHL:
dvander@8
    93
        return OP_SHL;
dvander@8
    94
      case TOK_BITAND:
dvander@8
    95
        return OP_BITAND;
dvander@8
    96
      case TOK_BITOR:
dvander@8
    97
        return OP_BITOR;
dvander@28
    98
      default:
dvander@28
    99
        assert(kind == TOK_BITXOR);
dvander@8
   100
        return OP_BITXOR;
dvander@0
   101
    }
dvander@0
   102
}
dvander@0
   103
dvander@0
   104
void
dvander@12
   105
BytecodeCompiler::recordLifoSlot(Scope *scope)
dvander@1
   106
{
dvander@1
   107
    if (!scope)
dvander@1
   108
        return;
dvander@1
   109
dvander@12
   110
    if (Variable *var = scope->lifoSlot()) {
dvander@30
   111
        locals_->set(zone_, var->slot(), var->type());
dvander@12
   112
        __ savelifo(var->slot());
dvander@12
   113
    }
dvander@1
   114
}
dvander@1
   115
dvander@1
   116
void
dvander@10
   117
BytecodeCompiler::unwindTo(Scope *scope)
dvander@10
   118
{
dvander@12
   119
    // Note: we only need to unwind to the outermost scope's LIFO slot.
dvander@12
   120
    Variable *var = NULL;
dvander@10
   121
    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
dvander@12
   122
        if (Variable *slot = current->lifoSlot())
dvander@12
   123
            var = slot;
dvander@10
   124
    }
dvander@12
   125
dvander@12
   126
    if (var)
dvander@12
   127
        __ unwindlifo(var->slot());
dvander@10
   128
}
dvander@10
   129
dvander@10
   130
void
dvander@0
   131
BytecodeCompiler::visit(NameProxy *name)
dvander@0
   132
{
dvander@2
   133
    switch (name->binding()->kind()) {
dvander@2
   134
      case BoundName::VARIABLE:
dvander@2
   135
      {
dvander@2
   136
        Variable *var = name->binding()->toVariable();
dvander@0
   137
dvander@2
   138
        if (var->location() == Variable::STACK) {
dvander@47
   139
            __ getlocal(var);
dvander@14
   140
            assert(!name->type()->isReference());
dvander@2
   141
        } else {
dvander@2
   142
            assert(var->location() == Variable::PARAMETER);
dvander@47
   143
            __ getarg(var);
dvander@14
   144
dvander@14
   145
            // If this argument is actually a reference, dereference it now.
dvander@22
   146
            if (var->type()->isReference())
dvander@22
   147
                __ getref(var->type()->contained()->primitive());
dvander@2
   148
        }
dvander@2
   149
        break;
dvander@2
   150
      }
dvander@2
   151
dvander@2
   152
      default:
dvander@2
   153
      {
dvander@2
   154
        NamedConstant *constant = name->binding()->toNamedConstant();
dvander@2
   155
        __ int_(constant->value().toInt());
dvander@2
   156
        break;
dvander@2
   157
      }
dvander@0
   158
    }
dvander@0
   159
}
dvander@0
   160
dvander@0
   161
void
dvander@0
   162
BytecodeCompiler::visit(ExpressionStatement *node)
dvander@0
   163
{
dvander@0
   164
    // Expressions leave their value on the top of the stack, so we make sure
dvander@0
   165
    // to balance the stack if they're used as a statement.
dvander@0
   166
    node->expression()->accept(this);
dvander@0
   167
    __ pop();
dvander@0
   168
}
dvander@0
   169
dvander@0
   170
void
dvander@0
   171
BytecodeCompiler::visit(Assignment *node)
dvander@0
   172
{
dvander@22
   173
    // The first step is three sub-steps:
dvander@22
   174
    //
dvander@22
   175
    //   (1) Bind the left-hand side.
dvander@22
   176
    //   -- If a cumulative operation (+=, etc):
dvander@22
   177
    //   (2) Save a copy of the binding on the stack.
dvander@22
   178
    //   (3) Dereference the binding to get a value.
dvander@22
   179
    //
dvander@0
   180
    if (node->lvalue()->isNameProxy()) {
dvander@0
   181
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@0
   182
        Variable *var = proxy->binding()->toVariable();
dvander@0
   183
dvander@22
   184
        // Bind.
dvander@21
   185
        if (var->type()->isReference() || var->type()->isArray())
dvander@16
   186
            __ get(var);
dvander@14
   187
dvander@22
   188
        // Get the value if needed.
dvander@22
   189
        if (node->token() != TOK_ASSIGN) {
dvander@22
   190
            // += etc is not allowed on arrays.
dvander@22
   191
            assert(!var->type()->isArray());
dvander@22
   192
dvander@22
   193
            if (var->type()->isReference()) {
dvander@22
   194
                __ dup();
dvander@22
   195
                __ getref(var->type()->contained()->primitive());
dvander@22
   196
            } else {
dvander@22
   197
                __ get(var);
dvander@22
   198
            }
dvander@22
   199
        }
dvander@23
   200
    } else {
dvander@21
   201
        IndexExpression *index = node->lvalue()->toIndexExpression();
dvander@70
   202
        __ note_position(index->pos());
dvander@21
   203
dvander@21
   204
        // Note: Eventually, watch out for a whole here. An expression like:
dvander@21
   205
        //
dvander@21
   206
        //   (a[4] = (5, a = []))
dvander@21
   207
        //
dvander@21
   208
        // Could shrink array, so we need to either bind a[i] to a Reference,
dvander@21
   209
        // or keep the bounds check near the set. This is just a semantic
dvander@21
   210
        // decision.
dvander@21
   211
        index->left()->accept(this);
dvander@21
   212
        index->right()->accept(this);
dvander@22
   213
dvander@22
   214
        if (node->token() != TOK_ASSIGN) {
dvander@22
   215
            __ dup2();
dvander@22
   216
            __ bounds();
dvander@22
   217
            if (node->type()->isArray())
dvander@22
   218
                __ getarray_o();
dvander@22
   219
            else
dvander@22
   220
                __ getarray(node->type()->primitive());
dvander@22
   221
        }
dvander@22
   222
    }
dvander@22
   223
dvander@22
   224
    if (node->token() == TOK_ASSIGN) {
dvander@21
   225
        node->expression()->accept(this);
dvander@22
   226
    } else {
dvander@22
   227
        visitForALU(node->type(), node->expression());
dvander@22
   228
dvander@22
   229
        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
dvander@70
   230
        __ note_position(node->pos());
dvander@22
   231
        __ binary(TokenToOpcode(alu));
dvander@21
   232
    }
dvander@21
   233
dvander@21
   234
    // Emit the store.
dvander@21
   235
    if (node->expression()->type()->isArray()) {
dvander@21
   236
        // Unlike references, which can only be computed from a NamePRoxy,
dvander@21
   237
        // arrays can be computed from multiple lvalue types.
dvander@70
   238
        __ note_position(node->pos());
dvander@21
   239
        __ arraycopy();
dvander@21
   240
    } else if (node->lvalue()->isNameProxy()) {
dvander@21
   241
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@21
   242
        Variable *var = proxy->binding()->toVariable();
dvander@14
   243
dvander@22
   244
        if (var->type()->isReference())
dvander@22
   245
            __ setref(var->type()->contained()->primitive());
dvander@22
   246
        else
dvander@16
   247
            __ set(var);
dvander@21
   248
    } else {
dvander@0
   249
        IndexExpression *index = node->lvalue()->toIndexExpression();
dvander@23
   250
        // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
dvander@22
   251
        // We can't emit it here because the stack is slightly out of position.
dvander@22
   252
        // __ bounds();
dvander@21
   253
        __ setarray(index->left()->type()->contained()->primitive());
dvander@0
   254
    }
dvander@0
   255
}
dvander@0
   256
dvander@0
   257
void
dvander@23
   258
BytecodeCompiler::visit(IncDecExpression *node)
dvander@23
   259
{
dvander@23
   260
    // In the postfix case, the logic looks like:
dvander@23
   261
    //      (1) Bind       -> REF
dvander@23
   262
    //      (2) Dup        -> REF REF
dvander@23
   263
    //      (3) Fetch      -> REF VAL
dvander@23
   264
    //      (4) Swap       -> VAL REF
dvander@23
   265
    //      (5) Pick       -> VAL REF VAL
dvander@23
   266
    //      (6) Add        -> VAL REF VAL+1
dvander@23
   267
    //      (7) Store      -> VAL VAL+1
dvander@23
   268
    //      (8) Drop       -> VAL
dvander@23
   269
    //
dvander@23
   270
    // In the prefix case, the logic looks like:
dvander@23
   271
    //      (1) Bind       -> REF
dvander@23
   272
    //      (2) Dup        -> REF REF
dvander@23
   273
    //      (3) Fetch      -> REF VAL
dvander@23
   274
    //      --
dvander@23
   275
    //      --
dvander@23
   276
    //      (6) Add        -> REF VAL+1
dvander@23
   277
    //      (7) Store      -> VAL+1
dvander@23
   278
    //      --
dvander@23
   279
    //
dvander@23
   280
    // This is squirrely enough such that we don't bother sharing too much
dvander@23
   281
    // with the above.
dvander@23
   282
    // 
dvander@23
   283
    // Note: We simulate a "Pick" operation with a dup2+pop.
dvander@23
   284
dvander@23
   285
    // This is steps (1) to (5).
dvander@23
   286
    Expression *expr = node->expression();
dvander@23
   287
    if (expr->isNameProxy()) {
dvander@23
   288
        NameProxy *proxy = expr->toNameProxy();
dvander@23
   289
        Variable *var = proxy->binding()->toVariable();
dvander@23
   290
dvander@23
   291
        // Bind.
dvander@23
   292
        if (var->type()->isReference() || var->type()->isArray())
dvander@23
   293
            __ get(var);
dvander@23
   294
dvander@23
   295
        // Dup and fetch.
dvander@23
   296
        if (var->type()->isReference()) {
dvander@23
   297
            __ dup();
dvander@23
   298
            __ getref(node->type()->primitive());
dvander@23
   299
            if (node->postfix()) {
dvander@23
   300
                __ swap();
dvander@23
   301
                __ pick2();
dvander@23
   302
            }
dvander@23
   303
        } else {
dvander@23
   304
            assert(!var->type()->isArray());
dvander@23
   305
            __ get(var);
dvander@23
   306
            if (node->postfix())
dvander@23
   307
                __ dup();
dvander@23
   308
        }
dvander@23
   309
    } else {
dvander@23
   310
        IndexExpression *index = expr->toIndexExpression();
dvander@70
   311
        __ note_position(index->pos());
dvander@70
   312
dvander@23
   313
        index->left()->accept(this);
dvander@23
   314
        index->right()->accept(this);
dvander@23
   315
dvander@23
   316
        assert(!node->type()->isArray());
dvander@23
   317
        __ bounds();
dvander@23
   318
        __ dup2();
dvander@23
   319
        __ getarray(node->type()->primitive());
dvander@23
   320
dvander@23
   321
        if (node->postfix()) {
dvander@23
   322
            // The stack looks like this now:
dvander@23
   323
            // ARRAY INDEX VALUE
dvander@23
   324
            //
dvander@23
   325
            // So we must use a PICK operation to rotate the stack into position.
dvander@23
   326
            __ roll3();         // INDEX VALUE ARRAY
dvander@23
   327
            __ roll3();         // VALUE ARRAY INDEX
dvander@23
   328
            __ pick3();         // VALUE ARRAY INDEX VALUE
dvander@23
   329
        }
dvander@23
   330
    }
dvander@23
   331
dvander@23
   332
    // Perform step (6).
dvander@23
   333
    if (node->type()->isFloat()) {
dvander@23
   334
        __ float_(1.0);
dvander@23
   335
    } else {
dvander@23
   336
        assert(node->type()->isInt32());
dvander@23
   337
        __ int_(1);
dvander@23
   338
    }
dvander@23
   339
dvander@70
   340
    __ note_position(node->pos());
dvander@23
   341
    if (node->token() == TOK_INCREMENT)
dvander@23
   342
        __ binary(OP_ADD);
dvander@23
   343
    else
dvander@23
   344
        __ binary(OP_SUB);
dvander@23
   345
dvander@23
   346
    // Perform step (7).
dvander@23
   347
    if (expr->isNameProxy()) {
dvander@23
   348
        NameProxy *proxy = expr->toNameProxy();
dvander@23
   349
        Variable *var = proxy->binding()->toVariable();
dvander@23
   350
dvander@23
   351
        if (var->type()->isReference())
dvander@23
   352
            __ setref(node->type()->primitive());
dvander@23
   353
        else
dvander@23
   354
            __ set(var);
dvander@23
   355
    } else {
dvander@23
   356
        __ setarray(node->type()->primitive());
dvander@23
   357
    }
dvander@23
   358
dvander@23
   359
    // Perform step (8).
dvander@23
   360
    if (node->postfix())
dvander@23
   361
        __ pop();
dvander@23
   362
}
dvander@23
   363
dvander@23
   364
void
dvander@4
   365
BytecodeCompiler::visitForALU(Type *needed, Expression *node)
dvander@4
   366
{
dvander@4
   367
    node->accept(this);
dvander@4
   368
    if (needed->isFloat() && !node->type()->isFloat())
dvander@4
   369
        __ cvt_i2f();
dvander@22
   370
    else
dvander@22
   371
        assert(needed->primitive() == node->type()->primitive());
dvander@4
   372
}
dvander@4
   373
dvander@4
   374
void
dvander@0
   375
BytecodeCompiler::visit(BinaryExpression *node)
dvander@0
   376
{
dvander@4
   377
    visitForALU(node->type(), node->left());
dvander@4
   378
    visitForALU(node->type(), node->right());
dvander@0
   379
dvander@0
   380
    Opcode op = TokenToOpcode(node->token());
dvander@4
   381
    if (node->type()->isFloat())
dvander@4
   382
        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
dvander@70
   383
dvander@70
   384
    __ note_position(node->pos());
dvander@0
   385
    __ binary(op);
dvander@0
   386
}
dvander@0
   387
dvander@0
   388
void
dvander@0
   389
BytecodeCompiler::visit(IndexExpression *node)
dvander@0
   390
{
dvander@0
   391
    node->left()->accept(this);
dvander@0
   392
    node->right()->accept(this);
dvander@70
   393
    __ note_position(node->pos());
dvander@19
   394
    __ bounds();
dvander@0
   395
dvander@21
   396
    if (node->type()->isArray())
dvander@19
   397
        __ getarray_o();
dvander@21
   398
    else
dvander@21
   399
        __ getarray(node->type()->primitive());
dvander@0
   400
}
dvander@0
   401
dvander@0
   402
void
dvander@0
   403
BytecodeCompiler::visit(ReturnStatement *node)
dvander@0
   404
{
dvander@0
   405
    if (node->expression())
dvander@0
   406
        node->expression()->accept(this);
dvander@0
   407
    else
dvander@0
   408
        __ int_(0);
dvander@0
   409
dvander@0
   410
    __ return_();
dvander@0
   411
}
dvander@0
   412
dvander@0
   413
void
dvander@0
   414
BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
dvander@0
   415
{
dvander@0
   416
    TokenKind token = ToCompare(expression);
dvander@0
   417
    if (token == TOK_EOF) {
dvander@0
   418
        expression->accept(this);
dvander@0
   419
        if (onTrue)
dvander@0
   420
            __ j(OP_JT, label);
dvander@0
   421
        else
dvander@0
   422
            __ j(OP_JF, label);
dvander@0
   423
        return;
dvander@0
   424
    }
dvander@0
   425
dvander@0
   426
    Opcode op = CompareTokenToJump(token);
dvander@0
   427
    if (!onTrue)
dvander@0
   428
        op = Invert(op);
dvander@0
   429
dvander@0
   430
    assert(expression->isBinaryExpression());
dvander@0
   431
    BinaryExpression *binary = expression->toBinaryExpression();
dvander@0
   432
    binary->left()->accept(this);
dvander@0
   433
    binary->right()->accept(this);
dvander@0
   434
    __ j(op, label);
dvander@0
   435
}
dvander@0
   436
dvander@0
   437
void
dvander@0
   438
BytecodeCompiler::visit(ForStatement *node)
dvander@0
   439
{
dvander@1
   440
    AutoEnterScope forScope(this, node->scope());
dvander@1
   441
dvander@12
   442
    recordLifoSlot(node->scope());
dvander@12
   443
dvander@10
   444
    Label join, update;
dvander@10
   445
    LoopScope loop(scope_, &join, &update, &loop_);
dvander@10
   446
dvander@22
   447
    if (node->initialization())
dvander@22
   448
        node->initialization()->accept(this);
dvander@0
   449
dvander@0
   450
    Label header, test;
dvander@0
   451
    if (node->condition())
dvander@0
   452
        __ jump(&test);
dvander@0
   453
dvander@0
   454
    __ bind(&header);
dvander@0
   455
    node->body()->accept(this);
dvander@0
   456
dvander@10
   457
    __ bind(&update);
dvander@0
   458
    if (node->update())
dvander@0
   459
        node->update()->accept(this);
dvander@0
   460
dvander@0
   461
    if (node->condition()) {
dvander@0
   462
        __ bind(&test);
dvander@0
   463
        visitForTest(node->condition(), &header, true);
dvander@0
   464
    } else {
dvander@0
   465
        __ jump(&header);
dvander@0
   466
    }
dvander@0
   467
dvander@10
   468
    __ bind(&join);
dvander@10
   469
dvander@12
   470
    if (node->scope())
dvander@12
   471
        unwindTo(node->scope()->enclosing());
dvander@0
   472
    assert(__ stackDepth() == 0);
dvander@0
   473
}
dvander@0
   474
dvander@0
   475
void
dvander@9
   476
BytecodeCompiler::visit(WhileStatement *node)
dvander@9
   477
{
dvander@10
   478
    Label header, join;
dvander@9
   479
dvander@9
   480
    __ bind(&header);
dvander@9
   481
dvander@10
   482
    LoopScope loop(scope_, &join, &header, &loop_);
dvander@10
   483
dvander@9
   484
    if (node->token() == TOK_WHILE) {
dvander@9
   485
        visitForTest(node->condition(), &join, false);
dvander@9
   486
        node->body()->accept(this);
dvander@9
   487
        __ jump(&header);
dvander@9
   488
    } else {
dvander@9
   489
        node->body()->accept(this);
dvander@9
   490
        visitForTest(node->condition(), &header, true);
dvander@9
   491
    }
dvander@10
   492
dvander@10
   493
    __ bind(&join);
dvander@10
   494
}
dvander@10
   495
dvander@10
   496
void
dvander@10
   497
BytecodeCompiler::visit(BreakStatement *node)
dvander@10
   498
{
dvander@10
   499
    unwindTo(loop_->scope());
dvander@10
   500
    __ jump(loop_->break_());
dvander@10
   501
}
dvander@10
   502
dvander@10
   503
void
dvander@10
   504
BytecodeCompiler::visit(ContinueStatement *node)
dvander@10
   505
{
dvander@10
   506
    unwindTo(loop_->scope());
dvander@10
   507
    __ jump(loop_->continue_());
dvander@9
   508
}
dvander@9
   509
dvander@9
   510
void
dvander@0
   511
BytecodeCompiler::visit(BlockStatement *node)
dvander@0
   512
{
dvander@1
   513
    AutoEnterScope blockScope(this, node->scope());
dvander@1
   514
dvander@12
   515
    recordLifoSlot(node->scope());
dvander@12
   516
dvander@0
   517
    for (size_t i = 0; i < node->statements()->length(); i++) {
dvander@0
   518
        Statement *statement = node->statements()->at(i);
dvander@0
   519
        statement->accept(this);
dvander@0
   520
        assert(__ stackDepth() == 0);
dvander@0
   521
    }
dvander@1
   522
dvander@1
   523
    // We don't bother emitting an "unwind" instruction for function scopes,
dvander@1
   524
    // since this is taken care of by the calling convention.
dvander@1
   525
    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
dvander@12
   526
        unwindTo(node->scope()->enclosing());
dvander@0
   527
}
dvander@0
   528
dvander@0
   529
void
dvander@4
   530
BytecodeCompiler::visit(IntegerLiteral *node)
dvander@0
   531
{
dvander@0
   532
    __ int_(node->value());
dvander@0
   533
}
dvander@0
   534
dvander@0
   535
void
dvander@4
   536
BytecodeCompiler::visit(FloatLiteral *node)
dvander@4
   537
{
dvander@4
   538
    __ float_((float)node->value());
dvander@4
   539
}
dvander@4
   540
dvander@12
   541
static inline ArrayMap *
dvander@27
   542
BuildArrayMap(Zone *zone, Handle<Type> type)
dvander@12
   543
{
dvander@27
   544
    Local<ArrayMap> contained(zone);
dvander@12
   545
    if (type->levels() > 1) {
dvander@27
   546
        Local<Type> containedType(zone, type->contained());
dvander@27
   547
        contained = BuildArrayMap(zone, containedType);
dvander@12
   548
        if (!contained)
dvander@12
   549
            return NULL;
dvander@12
   550
    }
dvander@12
   551
dvander@12
   552
    return ArrayMap::New(zone, type, contained);
dvander@12
   553
}
dvander@12
   554
dvander@4
   555
void
dvander@21
   556
BytecodeCompiler::visit(StringLiteral *node)
dvander@21
   557
{
dvander@30
   558
    Local<Type> type(zone_, node->type());
dvander@30
   559
    Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
dvander@21
   560
    if (!map)
dvander@21
   561
        return;
dvander@21
   562
dvander@30
   563
    Local<Array> array(zone_, Array::New(zone_, map, node->string()->length(), Heap::Tenure_Old));
dvander@21
   564
    if (!array)
dvander@21
   565
        return;
dvander@21
   566
dvander@21
   567
    assert(array->nelements() >= node->string()->length());
dvander@21
   568
    memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
dvander@21
   569
dvander@70
   570
    __ note_position(node->pos());
dvander@21
   571
    __ object(array);
dvander@21
   572
}
dvander@21
   573
dvander@21
   574
void
dvander@0
   575
BytecodeCompiler::visit(VariableDeclaration *node)
dvander@0
   576
{
dvander@0
   577
    Variable *var = node->variable();
dvander@0
   578
    assert(var->location() == Variable::STACK);
dvander@0
   579
    
dvander@30
   580
    Local<Type> type(zone_, var->type());
dvander@0
   581
    if (type->isArray()) {
dvander@30
   582
        Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
dvander@70
   583
        __ note_position(node->pos());
dvander@19
   584
        __ newarray_lifo(map);
dvander@21
   585
dvander@21
   586
        if (node->initialization()) {
dvander@21
   587
            node->initialization()->accept(this);
dvander@70
   588
            __ note_position(node->pos());
dvander@21
   589
            __ arraycopy();
dvander@21
   590
        }
dvander@0
   591
    } else {
dvander@0
   592
        if (node->initialization()) {
dvander@0
   593
            node->initialization()->accept(this);
dvander@0
   594
        } else {
dvander@0
   595
            if (!node->postDimensions())
dvander@0
   596
                __ int_(0);
dvander@0
   597
        }
dvander@0
   598
    }
dvander@47
   599
    __ setlocal(var);
dvander@0
   600
    __ pop();
dvander@0
   601
dvander@30
   602
    locals_->set(zone_, var->slot(), var->type());
dvander@0
   603
}
dvander@0
   604
dvander@0
   605
void
dvander@0
   606
BytecodeCompiler::visit(CallExpression *node)
dvander@0
   607
{
dvander@32
   608
    Local<Type> funType(zone_, node->callee()->type());
dvander@14
   609
dvander@68
   610
    for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
dvander@0
   611
        Expression *arg = node->arguments()->at(i);
dvander@14
   612
dvander@68
   613
        // We need to compute a reference if the parameter was in the form:
dvander@68
   614
        //  f(&a)
dvander@68
   615
        // Note this form does not allow: f({})
dvander@68
   616
        // 
dvander@68
   617
        // We also need to compute references for all variadic native
dvander@68
   618
        // arguments, but arrays and references are already in the
dvander@68
   619
        // appropriate form.
dvander@32
   620
        Local<Type> given(zone_, arg->type());
dvander@69
   621
        bool mustPushReference = false;
dvander@69
   622
        if (i >= funType->parameters()->length()) {
dvander@68
   623
            assert(funType->isNative() && funType->isNativeVariadic());
dvander@69
   624
            mustPushReference = !given->isArray() && !given->isReference();
dvander@69
   625
        } else if (funType->parameterAt(i)->isReference()) {
dvander@69
   626
            mustPushReference = !given->isReference();
dvander@69
   627
        }
dvander@68
   628
dvander@68
   629
        // If a native is passed to a native, it must only be one level deep.
dvander@68
   630
        assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
dvander@68
   631
dvander@68
   632
        if (mustPushReference) {
dvander@68
   633
            if (arg->isNameProxy()) {
dvander@14
   634
                // :TODO: test with functions and globals
dvander@14
   635
                // Compute a reference to the name.
dvander@14
   636
                Variable *var = arg->toNameProxy()->binding()->toVariable();
dvander@70
   637
                __ note_position(node->pos());
dvander@14
   638
                __ newref(var);
dvander@17
   639
            } else if (arg->isIndexExpression()) {
dvander@17
   640
                IndexExpression *expr = arg->toIndexExpression();
dvander@17
   641
                expr->left()->accept(this);
dvander@17
   642
                expr->right()->accept(this);
dvander@70
   643
                __ note_position(expr->pos());
dvander@19
   644
                __ bounds();
dvander@17
   645
                __ arrayref_lifo();
dvander@14
   646
            } else {
dvander@14
   647
                // We don't know how to, or can't, build a direct reference to
dvander@14
   648
                // this type. Make an indirect one, by taking the top of the
dvander@14
   649
                // stack and boxing it up.
dvander@16
   650
                arg->accept(this);
dvander@70
   651
                __ note_position(node->pos());
dvander@14
   652
                __ slotref_lifo();
dvander@14
   653
            }
dvander@14
   654
        } else {
dvander@14
   655
            arg->accept(this);
dvander@14
   656
        }
dvander@0
   657
    }
dvander@0
   658
dvander@68
   659
    NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
dvander@68
   660
dvander@70
   661
    __ note_position(node->pos());
dvander@68
   662
    if (fun->isNative())
dvander@68
   663
        __ callnative(fun->slot(), node->arguments()->length());
dvander@68
   664
    else
dvander@68
   665
        __ callglobal(fun->slot());
dvander@55
   666
    __ drop(node->arguments()->length());
dvander@0
   667
}
dvander@0
   668
dvander@0
   669
void
dvander@0
   670
BytecodeCompiler::visit(IfStatement *node)
dvander@0
   671
{
dvander@0
   672
    if (!node->ifFalse()) {
dvander@0
   673
        Label fail;
dvander@0
   674
        visitForTest(node->condition(), &fail, false);
dvander@0
   675
        node->ifTrue()->accept(this);
dvander@0
   676
        __ bind(&fail);
dvander@0
   677
    } else {
dvander@0
   678
        Label fail, join;
dvander@0
   679
        visitForTest(node->condition(), &fail, false);
dvander@0
   680
        node->ifTrue()->accept(this);
dvander@0
   681
        __ jump(&join);
dvander@0
   682
        __ bind(&fail);
dvander@0
   683
        node->ifFalse()->accept(this);
dvander@0
   684
        __ bind(&join);
dvander@0
   685
    }
dvander@0
   686
}
dvander@0
   687
dvander@0
   688
void
dvander@0
   689
BytecodeCompiler::visit(FunctionStatement *node)
dvander@0
   690
{
dvander@68
   691
    if (node->fun()->isNative()) {
dvander@68
   692
        assert(!moduleData_->natives->at(node->fun()->slot()));
dvander@68
   693
dvander@68
   694
        Local<Type> type(zone_, node->fun()->type());
dvander@68
   695
        Local<String> name(zone_, node->fun()->name());
dvander@68
   696
        Local<Native> native(zone_, Native::New(zone_, type, name));
dvander@68
   697
        if (!native)
dvander@68
   698
            return;
dvander@68
   699
dvander@68
   700
        moduleData_->natives->set(zone_, node->fun()->slot(), native);
dvander@68
   701
        return;
dvander@68
   702
    }
dvander@68
   703
dvander@63
   704
    // If the function has no body, then it's just a declaration.
dvander@63
   705
    if (!node->body()) {
dvander@63
   706
        assert(node->fun()->isForward() || node->fun()->isPublic());
dvander@63
   707
        return;
dvander@63
   708
    }
dvander@63
   709
dvander@65
   710
    BytecodeCompiler child(zone_, tree_, moduleData_);
dvander@65
   711
    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
dvander@26
   712
    if (!fun)
dvander@26
   713
        return;
dvander@0
   714
    
dvander@65
   715
    assert(!moduleData_->module->getFunction(node->fun()->slot()));
dvander@65
   716
    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
dvander@0
   717
}
dvander@0
   718
dvander@2
   719
void
dvander@2
   720
BytecodeCompiler::visit(EnumStatement *node)
dvander@2
   721
{
dvander@2
   722
    // :TODO: eventually, we'll export these.
dvander@2
   723
}
dvander@2
   724
dvander@26
   725
Function *
dvander@65
   726
BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
dvander@0
   727
{
dvander@12
   728
    // Note: No need to record a life slot here, since it's part of the Frame.
dvander@1
   729
    AutoEnterScope functionScope(this, node->scope());
dvander@1
   730
dvander@70
   731
    // Set the initial line, because line mappings are deltas.
dvander@70
   732
    __ setFirstLine(node->pos().line);
dvander@30
   733
    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
dvander@0
   734
dvander@0
   735
    node->body()->accept(this);
dvander@0
   736
dvander@0
   737
    __ stop();
dvander@0
   738
dvander@69
   739
    if (__ oom() || zone_->hasPendingException())
dvander@12
   740
        return NULL;
dvander@0
   741
dvander@32
   742
    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
dvander@12
   743
    if (!bytes)
dvander@12
   744
        return NULL;
dvander@12
   745
    memcpy(bytes->raw(), __ buffer(), __ length());
dvander@0
   746
dvander@0
   747
    unsigned nargs = node->scope()->numArguments();
dvander@32
   748
    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
dvander@12
   749
    if (!args)
dvander@12
   750
        return NULL;
dvander@12
   751
dvander@0
   752
    for (size_t i = 0; i < node->scope()->numArguments(); i++)
dvander@30
   753
        args->set(zone_, i, node->scope()->getArgument(i)->type());
dvander@0
   754
dvander@0
   755
    for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
dvander@12
   756
        assert(locals_->at(i));
dvander@0
   757
dvander@58
   758
    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
dvander@21
   759
    if (!objects)
dvander@12
   760
        return NULL;
dvander@0
   761
dvander@58
   762
    for (size_t i = 0; i < __ objects()->length(); i++)
dvander@33
   763
        objects->set(zone_, i, *(__ objects()->at(i)));
dvander@12
   764
dvander@47
   765
    Local<ByteArray> safepoints(zone_);
dvander@47
   766
dvander@47
   767
    // If any stack slots hold gc pointers at potential failure points in the
dvander@47
   768
    // bytecode, record them now. We do this by building a list of tuples;
dvander@47
   769
    // each tuple contains the pc offset, and a bitset containing which stack
dvander@47
   770
    // slots must be scanned by the gc.
dvander@58
   771
    if (__ oopRecords()->length()) {
dvander@47
   772
        size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
dvander@58
   773
        size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
dvander@47
   774
        safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
dvander@47
   775
        if (!safepoints)
dvander@47
   776
            return NULL;
dvander@47
   777
dvander@47
   778
        Address cursor = safepoints->raw();
dvander@58
   779
        for (size_t i = 0; i < __ oopRecords()->length(); i++) {
dvander@47
   780
            OopRecord *record = __ oopRecords()->at(i);
dvander@47
   781
            assert(record->depth <= __ maxStackDepth());
dvander@47
   782
dvander@47
   783
            *reinterpret_cast<unsigned *>(cursor) = record->offset;
dvander@47
   784
dvander@47
   785
            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
dvander@47
   786
            for (unsigned i = 0; i < record->depth; i++)
dvander@47
   787
                bits[i / 8] |= (1 << (i % 8));
dvander@47
   788
dvander@47
   789
            cursor += bytesPerSafepoint;
dvander@47
   790
        }
dvander@47
   791
dvander@47
   792
        assert(cursor == safepoints->raw() + gcmapSize);
dvander@47
   793
    }
dvander@47
   794
dvander@70
   795
    Local<ByteArray> sourcemap(zone_);
dvander@70
   796
    if (__ sourcemapLength()) {
dvander@70
   797
        sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
dvander@70
   798
        if (!sourcemap)
dvander@70
   799
            return NULL;
dvander@70
   800
dvander@70
   801
        memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
dvander@70
   802
    }
dvander@70
   803
dvander@70
   804
    Local<Code> code(zone_);
dvander@70
   805
dvander@70
   806
    code = Code::New(zone_,
dvander@70
   807
                     bytes,
dvander@70
   808
                     locals_,
dvander@70
   809
                     objects,
dvander@70
   810
                     __ maxStackDepth(),
dvander@70
   811
                     moduleData_->module,
dvander@70
   812
                     safepoints,
dvander@70
   813
                     sourcemap,
dvander@70
   814
                     node->pos().line);
dvander@26
   815
    if (!code)
dvander@26
   816
        return NULL;
dvander@26
   817
dvander@64
   818
    Local<Type> type(zone_, node->fun()->type());
dvander@64
   819
    Local<String> name(zone_, node->fun()->name());
dvander@64
   820
    Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
dvander@26
   821
    if (!fun)
dvander@26
   822
        return NULL;
dvander@64
   823
dvander@64
   824
    // If this function had a forward, export it as a named public.
dvander@64
   825
    if (node->fun()->isPublic()) {
dvander@64
   826
        assert(node->fun()->isPublic());
dvander@64
   827
        ScopedRoot<Function> root(fun);
dvander@64
   828
        if (!root)
dvander@64
   829
            return NULL;
dvander@65
   830
        if (!moduleData_->publics.append(root))
dvander@64
   831
            return NULL;
dvander@64
   832
    }
dvander@66
   833
dvander@66
   834
    Disassemble(code, stdout);
dvander@26
   835
    
dvander@26
   836
    return fun;
dvander@0
   837
}
dvander@0
   838
dvander@0
   839
Module *
dvander@0
   840
BytecodeCompiler::compile()
dvander@0
   841
{
dvander@65
   842
    ModuleData moduleData;
dvander@65
   843
dvander@65
   844
    moduleData_ = &moduleData;
dvander@65
   845
    moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
dvander@65
   846
dvander@65
   847
    if (!moduleData_)
dvander@14
   848
        return NULL;
dvander@68
   849
    
dvander@68
   850
    moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
dvander@68
   851
    if (!moduleData_->natives)
dvander@68
   852
        return NULL;
dvander@0
   853
dvander@0
   854
    for (size_t i = 0; i < tree_->statements()->length(); i++) {
dvander@0
   855
        Statement *statement = tree_->statements()->at(i);
dvander@0
   856
        statement->accept(this);
dvander@0
   857
    }
dvander@0
   858
dvander@69
   859
    if (zone_->hasPendingException())
dvander@69
   860
        return NULL;
dvander@69
   861
dvander@0
   862
#ifndef NDEBUG
dvander@0
   863
    for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
dvander@65
   864
        assert(moduleData_->module->getFunction(i));
dvander@68
   865
    for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
dvander@68
   866
        assert(moduleData_->natives->at(i));
dvander@0
   867
#endif
dvander@0
   868
dvander@65
   869
    if (moduleData_->publics.length()) {
dvander@64
   870
        Local<Function> fun(zone_);
dvander@65
   871
        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
dvander@65
   872
                               Heap::Tenure_Old));
dvander@64
   873
        if (!list)
dvander@64
   874
            return NULL;
dvander@64
   875
dvander@65
   876
        for (size_t i = 0; i < moduleData_->publics.length(); i++)
dvander@65
   877
            list->set(zone_, i, moduleData_->publics[i]);
dvander@65
   878
dvander@65
   879
        moduleData_->module->setPublics(list);
dvander@64
   880
    }
dvander@64
   881
dvander@68
   882
    moduleData_->module->setNatives(moduleData_->natives);
dvander@68
   883
dvander@65
   884
    return moduleData_->module;
dvander@0
   885
}