jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Tue Jul 03 00:36:48 2012 -0700 (2012-07-03)
changeset 33 95baf120f7d4
parent 32 af1ed58252ac
child 46 735503e448a0
permissions -rw-r--r--
Handle-ize BytecodeEmitter.
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@12
    24
#include "Zone.h"
dvander@12
    25
#include "Heap-inl.h"
dvander@0
    26
dvander@0
    27
using namespace jc;
dvander@0
    28
dvander@0
    29
typedef BytecodeEmitter::Label Label;
dvander@0
    30
dvander@0
    31
#define __ emitter_.
dvander@0
    32
dvander@30
    33
BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, Module *module)
dvander@30
    34
  : zone_(zone),
dvander@30
    35
    tree_(tree),
dvander@28
    36
    module_(module),
dvander@28
    37
    locals_(NULL),
dvander@10
    38
    scope_(NULL),
dvander@28
    39
    loop_(NULL)
dvander@0
    40
{
dvander@0
    41
}
dvander@0
    42
dvander@0
    43
static inline TokenKind
dvander@0
    44
ToCompare(Expression *expr)
dvander@0
    45
{
dvander@0
    46
    if (expr->isBinaryExpression()) {
dvander@0
    47
        BinaryExpression *b = expr->toBinaryExpression();
dvander@0
    48
        if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
dvander@0
    49
            return b->token();
dvander@0
    50
    }
dvander@0
    51
    return TOK_EOF;
dvander@0
    52
}
dvander@0
    53
dvander@0
    54
static inline Opcode
dvander@0
    55
CompareTokenToJump(TokenKind kind)
dvander@0
    56
{
dvander@0
    57
    switch (kind) {
dvander@0
    58
      case TOK_EQUALS:
dvander@0
    59
        return OP_JEQ;
dvander@0
    60
      case TOK_NOTEQUALS:
dvander@0
    61
        return OP_JNE;
dvander@0
    62
      case TOK_GT:
dvander@0
    63
        return OP_JG;
dvander@0
    64
      case TOK_GE:
dvander@0
    65
        return OP_JGE;
dvander@0
    66
      case TOK_LT:
dvander@0
    67
        return OP_JL;
dvander@28
    68
      default:
dvander@28
    69
        assert(kind == TOK_LE);
dvander@0
    70
        return OP_JLE;
dvander@0
    71
    }
dvander@0
    72
}
dvander@0
    73
dvander@0
    74
static inline Opcode
dvander@0
    75
TokenToOpcode(TokenKind kind)
dvander@0
    76
{
dvander@0
    77
    switch (kind) {
dvander@0
    78
      case TOK_PLUS:
dvander@0
    79
        return OP_ADD;
dvander@0
    80
      case TOK_MINUS:
dvander@0
    81
        return OP_SUB;
dvander@0
    82
      case TOK_STAR:
dvander@0
    83
        return OP_MUL;
dvander@0
    84
      case TOK_SLASH:
dvander@0
    85
        return OP_DIV;
dvander@8
    86
      case TOK_SHR:
dvander@8
    87
        return OP_SHR;
dvander@8
    88
      case TOK_USHR:
dvander@8
    89
        return OP_USHR;
dvander@8
    90
      case TOK_SHL:
dvander@8
    91
        return OP_SHL;
dvander@8
    92
      case TOK_BITAND:
dvander@8
    93
        return OP_BITAND;
dvander@8
    94
      case TOK_BITOR:
dvander@8
    95
        return OP_BITOR;
dvander@28
    96
      default:
dvander@28
    97
        assert(kind == TOK_BITXOR);
dvander@8
    98
        return OP_BITXOR;
dvander@0
    99
    }
dvander@0
   100
}
dvander@0
   101
dvander@0
   102
void
dvander@12
   103
BytecodeCompiler::recordLifoSlot(Scope *scope)
dvander@1
   104
{
dvander@1
   105
    if (!scope)
dvander@1
   106
        return;
dvander@1
   107
dvander@12
   108
    if (Variable *var = scope->lifoSlot()) {
dvander@30
   109
        locals_->set(zone_, var->slot(), var->type());
dvander@12
   110
        __ savelifo(var->slot());
dvander@12
   111
    }
dvander@1
   112
}
dvander@1
   113
dvander@1
   114
void
dvander@10
   115
BytecodeCompiler::unwindTo(Scope *scope)
dvander@10
   116
{
dvander@12
   117
    // Note: we only need to unwind to the outermost scope's LIFO slot.
dvander@12
   118
    Variable *var = NULL;
dvander@10
   119
    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
dvander@12
   120
        if (Variable *slot = current->lifoSlot())
dvander@12
   121
            var = slot;
dvander@10
   122
    }
dvander@12
   123
dvander@12
   124
    if (var)
dvander@12
   125
        __ unwindlifo(var->slot());
dvander@10
   126
}
dvander@10
   127
dvander@10
   128
void
dvander@0
   129
BytecodeCompiler::visit(NameProxy *name)
dvander@0
   130
{
dvander@2
   131
    switch (name->binding()->kind()) {
dvander@2
   132
      case BoundName::VARIABLE:
dvander@2
   133
      {
dvander@2
   134
        Variable *var = name->binding()->toVariable();
dvander@0
   135
dvander@2
   136
        if (var->location() == Variable::STACK) {
dvander@2
   137
            __ getlocal(var->slot());
dvander@14
   138
            assert(!name->type()->isReference());
dvander@2
   139
        } else {
dvander@2
   140
            assert(var->location() == Variable::PARAMETER);
dvander@2
   141
            __ getarg(var->slot());
dvander@14
   142
dvander@14
   143
            // If this argument is actually a reference, dereference it now.
dvander@22
   144
            if (var->type()->isReference())
dvander@22
   145
                __ getref(var->type()->contained()->primitive());
dvander@2
   146
        }
dvander@2
   147
        break;
dvander@2
   148
      }
dvander@2
   149
dvander@2
   150
      default:
dvander@2
   151
      {
dvander@2
   152
        NamedConstant *constant = name->binding()->toNamedConstant();
dvander@2
   153
        __ int_(constant->value().toInt());
dvander@2
   154
        break;
dvander@2
   155
      }
dvander@0
   156
    }
dvander@0
   157
}
dvander@0
   158
dvander@0
   159
void
dvander@0
   160
BytecodeCompiler::visit(ExpressionStatement *node)
dvander@0
   161
{
dvander@0
   162
    // Expressions leave their value on the top of the stack, so we make sure
dvander@0
   163
    // to balance the stack if they're used as a statement.
dvander@0
   164
    node->expression()->accept(this);
dvander@0
   165
    __ pop();
dvander@0
   166
}
dvander@0
   167
dvander@0
   168
void
dvander@0
   169
BytecodeCompiler::visit(Assignment *node)
dvander@0
   170
{
dvander@22
   171
    // The first step is three sub-steps:
dvander@22
   172
    //
dvander@22
   173
    //   (1) Bind the left-hand side.
dvander@22
   174
    //   -- If a cumulative operation (+=, etc):
dvander@22
   175
    //   (2) Save a copy of the binding on the stack.
dvander@22
   176
    //   (3) Dereference the binding to get a value.
dvander@22
   177
    //
dvander@0
   178
    if (node->lvalue()->isNameProxy()) {
dvander@0
   179
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@0
   180
        Variable *var = proxy->binding()->toVariable();
dvander@0
   181
dvander@22
   182
        // Bind.
dvander@21
   183
        if (var->type()->isReference() || var->type()->isArray())
dvander@16
   184
            __ get(var);
dvander@14
   185
dvander@22
   186
        // Get the value if needed.
dvander@22
   187
        if (node->token() != TOK_ASSIGN) {
dvander@22
   188
            // += etc is not allowed on arrays.
dvander@22
   189
            assert(!var->type()->isArray());
dvander@22
   190
dvander@22
   191
            if (var->type()->isReference()) {
dvander@22
   192
                __ dup();
dvander@22
   193
                __ getref(var->type()->contained()->primitive());
dvander@22
   194
            } else {
dvander@22
   195
                __ get(var);
dvander@22
   196
            }
dvander@22
   197
        }
dvander@23
   198
    } else {
dvander@21
   199
        IndexExpression *index = node->lvalue()->toIndexExpression();
dvander@21
   200
dvander@21
   201
        // Note: Eventually, watch out for a whole here. An expression like:
dvander@21
   202
        //
dvander@21
   203
        //   (a[4] = (5, a = []))
dvander@21
   204
        //
dvander@21
   205
        // Could shrink array, so we need to either bind a[i] to a Reference,
dvander@21
   206
        // or keep the bounds check near the set. This is just a semantic
dvander@21
   207
        // decision.
dvander@21
   208
        index->left()->accept(this);
dvander@21
   209
        index->right()->accept(this);
dvander@22
   210
dvander@22
   211
        if (node->token() != TOK_ASSIGN) {
dvander@22
   212
            __ dup2();
dvander@22
   213
            __ bounds();
dvander@22
   214
            if (node->type()->isArray())
dvander@22
   215
                __ getarray_o();
dvander@22
   216
            else
dvander@22
   217
                __ getarray(node->type()->primitive());
dvander@22
   218
        }
dvander@22
   219
    }
dvander@22
   220
dvander@22
   221
    if (node->token() == TOK_ASSIGN) {
dvander@21
   222
        node->expression()->accept(this);
dvander@22
   223
    } else {
dvander@22
   224
        visitForALU(node->type(), node->expression());
dvander@22
   225
dvander@22
   226
        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
dvander@22
   227
        __ binary(TokenToOpcode(alu));
dvander@21
   228
    }
dvander@21
   229
dvander@21
   230
    // Emit the store.
dvander@21
   231
    if (node->expression()->type()->isArray()) {
dvander@21
   232
        // Unlike references, which can only be computed from a NamePRoxy,
dvander@21
   233
        // arrays can be computed from multiple lvalue types.
dvander@21
   234
        __ arraycopy();
dvander@21
   235
    } else if (node->lvalue()->isNameProxy()) {
dvander@21
   236
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@21
   237
        Variable *var = proxy->binding()->toVariable();
dvander@14
   238
dvander@22
   239
        if (var->type()->isReference())
dvander@22
   240
            __ setref(var->type()->contained()->primitive());
dvander@22
   241
        else
dvander@16
   242
            __ set(var);
dvander@21
   243
    } else {
dvander@0
   244
        IndexExpression *index = node->lvalue()->toIndexExpression();
dvander@23
   245
        // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
dvander@22
   246
        // We can't emit it here because the stack is slightly out of position.
dvander@22
   247
        // __ bounds();
dvander@21
   248
        __ setarray(index->left()->type()->contained()->primitive());
dvander@0
   249
    }
dvander@0
   250
}
dvander@0
   251
dvander@0
   252
void
dvander@23
   253
BytecodeCompiler::visit(IncDecExpression *node)
dvander@23
   254
{
dvander@23
   255
    // In the postfix case, the logic looks like:
dvander@23
   256
    //      (1) Bind       -> REF
dvander@23
   257
    //      (2) Dup        -> REF REF
dvander@23
   258
    //      (3) Fetch      -> REF VAL
dvander@23
   259
    //      (4) Swap       -> VAL REF
dvander@23
   260
    //      (5) Pick       -> VAL REF VAL
dvander@23
   261
    //      (6) Add        -> VAL REF VAL+1
dvander@23
   262
    //      (7) Store      -> VAL VAL+1
dvander@23
   263
    //      (8) Drop       -> VAL
dvander@23
   264
    //
dvander@23
   265
    // In the prefix case, the logic looks like:
dvander@23
   266
    //      (1) Bind       -> REF
dvander@23
   267
    //      (2) Dup        -> REF REF
dvander@23
   268
    //      (3) Fetch      -> REF VAL
dvander@23
   269
    //      --
dvander@23
   270
    //      --
dvander@23
   271
    //      (6) Add        -> REF VAL+1
dvander@23
   272
    //      (7) Store      -> VAL+1
dvander@23
   273
    //      --
dvander@23
   274
    //
dvander@23
   275
    // This is squirrely enough such that we don't bother sharing too much
dvander@23
   276
    // with the above.
dvander@23
   277
    // 
dvander@23
   278
    // Note: We simulate a "Pick" operation with a dup2+pop.
dvander@23
   279
dvander@23
   280
    // This is steps (1) to (5).
dvander@23
   281
    Expression *expr = node->expression();
dvander@23
   282
    if (expr->isNameProxy()) {
dvander@23
   283
        NameProxy *proxy = expr->toNameProxy();
dvander@23
   284
        Variable *var = proxy->binding()->toVariable();
dvander@23
   285
dvander@23
   286
        // Bind.
dvander@23
   287
        if (var->type()->isReference() || var->type()->isArray())
dvander@23
   288
            __ get(var);
dvander@23
   289
dvander@23
   290
        // Dup and fetch.
dvander@23
   291
        if (var->type()->isReference()) {
dvander@23
   292
            __ dup();
dvander@23
   293
            __ getref(node->type()->primitive());
dvander@23
   294
            if (node->postfix()) {
dvander@23
   295
                __ swap();
dvander@23
   296
                __ pick2();
dvander@23
   297
            }
dvander@23
   298
        } else {
dvander@23
   299
            assert(!var->type()->isArray());
dvander@23
   300
            __ get(var);
dvander@23
   301
            if (node->postfix())
dvander@23
   302
                __ dup();
dvander@23
   303
        }
dvander@23
   304
    } else {
dvander@23
   305
        IndexExpression *index = expr->toIndexExpression();
dvander@23
   306
        index->left()->accept(this);
dvander@23
   307
        index->right()->accept(this);
dvander@23
   308
dvander@23
   309
        assert(!node->type()->isArray());
dvander@23
   310
        __ bounds();
dvander@23
   311
        __ dup2();
dvander@23
   312
        __ getarray(node->type()->primitive());
dvander@23
   313
dvander@23
   314
        if (node->postfix()) {
dvander@23
   315
            // The stack looks like this now:
dvander@23
   316
            // ARRAY INDEX VALUE
dvander@23
   317
            //
dvander@23
   318
            // So we must use a PICK operation to rotate the stack into position.
dvander@23
   319
            __ roll3();         // INDEX VALUE ARRAY
dvander@23
   320
            __ roll3();         // VALUE ARRAY INDEX
dvander@23
   321
            __ pick3();         // VALUE ARRAY INDEX VALUE
dvander@23
   322
        }
dvander@23
   323
    }
dvander@23
   324
dvander@23
   325
    // Perform step (6).
dvander@23
   326
    if (node->type()->isFloat()) {
dvander@23
   327
        __ float_(1.0);
dvander@23
   328
    } else {
dvander@23
   329
        assert(node->type()->isInt32());
dvander@23
   330
        __ int_(1);
dvander@23
   331
    }
dvander@23
   332
dvander@23
   333
    if (node->token() == TOK_INCREMENT)
dvander@23
   334
        __ binary(OP_ADD);
dvander@23
   335
    else
dvander@23
   336
        __ binary(OP_SUB);
dvander@23
   337
dvander@23
   338
    // Perform step (7).
dvander@23
   339
    if (expr->isNameProxy()) {
dvander@23
   340
        NameProxy *proxy = expr->toNameProxy();
dvander@23
   341
        Variable *var = proxy->binding()->toVariable();
dvander@23
   342
dvander@23
   343
        if (var->type()->isReference())
dvander@23
   344
            __ setref(node->type()->primitive());
dvander@23
   345
        else
dvander@23
   346
            __ set(var);
dvander@23
   347
    } else {
dvander@23
   348
        __ setarray(node->type()->primitive());
dvander@23
   349
    }
dvander@23
   350
dvander@23
   351
    // Perform step (8).
dvander@23
   352
    if (node->postfix())
dvander@23
   353
        __ pop();
dvander@23
   354
}
dvander@23
   355
dvander@23
   356
void
dvander@4
   357
BytecodeCompiler::visitForALU(Type *needed, Expression *node)
dvander@4
   358
{
dvander@4
   359
    node->accept(this);
dvander@4
   360
    if (needed->isFloat() && !node->type()->isFloat())
dvander@4
   361
        __ cvt_i2f();
dvander@22
   362
    else
dvander@22
   363
        assert(needed->primitive() == node->type()->primitive());
dvander@4
   364
}
dvander@4
   365
dvander@4
   366
void
dvander@0
   367
BytecodeCompiler::visit(BinaryExpression *node)
dvander@0
   368
{
dvander@4
   369
    visitForALU(node->type(), node->left());
dvander@4
   370
    visitForALU(node->type(), node->right());
dvander@0
   371
dvander@0
   372
    Opcode op = TokenToOpcode(node->token());
dvander@4
   373
    if (node->type()->isFloat())
dvander@4
   374
        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
dvander@0
   375
    __ binary(op);
dvander@0
   376
}
dvander@0
   377
dvander@0
   378
void
dvander@0
   379
BytecodeCompiler::visit(IndexExpression *node)
dvander@0
   380
{
dvander@0
   381
    node->left()->accept(this);
dvander@0
   382
    node->right()->accept(this);
dvander@19
   383
    __ bounds();
dvander@0
   384
dvander@21
   385
    if (node->type()->isArray())
dvander@19
   386
        __ getarray_o();
dvander@21
   387
    else
dvander@21
   388
        __ getarray(node->type()->primitive());
dvander@0
   389
}
dvander@0
   390
dvander@0
   391
void
dvander@0
   392
BytecodeCompiler::visit(ReturnStatement *node)
dvander@0
   393
{
dvander@0
   394
    if (node->expression())
dvander@0
   395
        node->expression()->accept(this);
dvander@0
   396
    else
dvander@0
   397
        __ int_(0);
dvander@0
   398
dvander@0
   399
    __ return_();
dvander@0
   400
}
dvander@0
   401
dvander@0
   402
void
dvander@0
   403
BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
dvander@0
   404
{
dvander@0
   405
    TokenKind token = ToCompare(expression);
dvander@0
   406
    if (token == TOK_EOF) {
dvander@0
   407
        expression->accept(this);
dvander@0
   408
        if (onTrue)
dvander@0
   409
            __ j(OP_JT, label);
dvander@0
   410
        else
dvander@0
   411
            __ j(OP_JF, label);
dvander@0
   412
        return;
dvander@0
   413
    }
dvander@0
   414
dvander@0
   415
    Opcode op = CompareTokenToJump(token);
dvander@0
   416
    if (!onTrue)
dvander@0
   417
        op = Invert(op);
dvander@0
   418
dvander@0
   419
    assert(expression->isBinaryExpression());
dvander@0
   420
    BinaryExpression *binary = expression->toBinaryExpression();
dvander@0
   421
    binary->left()->accept(this);
dvander@0
   422
    binary->right()->accept(this);
dvander@0
   423
    __ j(op, label);
dvander@0
   424
}
dvander@0
   425
dvander@0
   426
void
dvander@0
   427
BytecodeCompiler::visit(ForStatement *node)
dvander@0
   428
{
dvander@1
   429
    AutoEnterScope forScope(this, node->scope());
dvander@1
   430
dvander@12
   431
    recordLifoSlot(node->scope());
dvander@12
   432
dvander@10
   433
    Label join, update;
dvander@10
   434
    LoopScope loop(scope_, &join, &update, &loop_);
dvander@10
   435
dvander@22
   436
    if (node->initialization())
dvander@22
   437
        node->initialization()->accept(this);
dvander@0
   438
dvander@0
   439
    Label header, test;
dvander@0
   440
    if (node->condition())
dvander@0
   441
        __ jump(&test);
dvander@0
   442
dvander@0
   443
    __ bind(&header);
dvander@0
   444
    node->body()->accept(this);
dvander@0
   445
dvander@10
   446
    __ bind(&update);
dvander@0
   447
    if (node->update())
dvander@0
   448
        node->update()->accept(this);
dvander@0
   449
dvander@0
   450
    if (node->condition()) {
dvander@0
   451
        __ bind(&test);
dvander@0
   452
        visitForTest(node->condition(), &header, true);
dvander@0
   453
    } else {
dvander@0
   454
        __ jump(&header);
dvander@0
   455
    }
dvander@0
   456
dvander@10
   457
    __ bind(&join);
dvander@10
   458
dvander@12
   459
    if (node->scope())
dvander@12
   460
        unwindTo(node->scope()->enclosing());
dvander@0
   461
    assert(__ stackDepth() == 0);
dvander@0
   462
}
dvander@0
   463
dvander@0
   464
void
dvander@9
   465
BytecodeCompiler::visit(WhileStatement *node)
dvander@9
   466
{
dvander@10
   467
    Label header, join;
dvander@9
   468
dvander@9
   469
    __ bind(&header);
dvander@9
   470
dvander@10
   471
    LoopScope loop(scope_, &join, &header, &loop_);
dvander@10
   472
dvander@9
   473
    if (node->token() == TOK_WHILE) {
dvander@9
   474
        visitForTest(node->condition(), &join, false);
dvander@9
   475
        node->body()->accept(this);
dvander@9
   476
        __ jump(&header);
dvander@9
   477
    } else {
dvander@9
   478
        node->body()->accept(this);
dvander@9
   479
        visitForTest(node->condition(), &header, true);
dvander@9
   480
    }
dvander@10
   481
dvander@10
   482
    __ bind(&join);
dvander@10
   483
}
dvander@10
   484
dvander@10
   485
void
dvander@10
   486
BytecodeCompiler::visit(BreakStatement *node)
dvander@10
   487
{
dvander@10
   488
    unwindTo(loop_->scope());
dvander@10
   489
    __ jump(loop_->break_());
dvander@10
   490
}
dvander@10
   491
dvander@10
   492
void
dvander@10
   493
BytecodeCompiler::visit(ContinueStatement *node)
dvander@10
   494
{
dvander@10
   495
    unwindTo(loop_->scope());
dvander@10
   496
    __ jump(loop_->continue_());
dvander@9
   497
}
dvander@9
   498
dvander@9
   499
void
dvander@0
   500
BytecodeCompiler::visit(BlockStatement *node)
dvander@0
   501
{
dvander@1
   502
    AutoEnterScope blockScope(this, node->scope());
dvander@1
   503
dvander@12
   504
    recordLifoSlot(node->scope());
dvander@12
   505
dvander@0
   506
    for (size_t i = 0; i < node->statements()->length(); i++) {
dvander@0
   507
        Statement *statement = node->statements()->at(i);
dvander@0
   508
        statement->accept(this);
dvander@0
   509
        assert(__ stackDepth() == 0);
dvander@0
   510
    }
dvander@1
   511
dvander@1
   512
    // We don't bother emitting an "unwind" instruction for function scopes,
dvander@1
   513
    // since this is taken care of by the calling convention.
dvander@1
   514
    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
dvander@12
   515
        unwindTo(node->scope()->enclosing());
dvander@0
   516
}
dvander@0
   517
dvander@0
   518
void
dvander@4
   519
BytecodeCompiler::visit(IntegerLiteral *node)
dvander@0
   520
{
dvander@0
   521
    __ int_(node->value());
dvander@0
   522
}
dvander@0
   523
dvander@0
   524
void
dvander@4
   525
BytecodeCompiler::visit(FloatLiteral *node)
dvander@4
   526
{
dvander@4
   527
    __ float_((float)node->value());
dvander@4
   528
}
dvander@4
   529
dvander@12
   530
static inline ArrayMap *
dvander@27
   531
BuildArrayMap(Zone *zone, Handle<Type> type)
dvander@12
   532
{
dvander@27
   533
    Local<ArrayMap> contained(zone);
dvander@12
   534
    if (type->levels() > 1) {
dvander@27
   535
        Local<Type> containedType(zone, type->contained());
dvander@27
   536
        contained = BuildArrayMap(zone, containedType);
dvander@12
   537
        if (!contained)
dvander@12
   538
            return NULL;
dvander@12
   539
    }
dvander@12
   540
dvander@12
   541
    return ArrayMap::New(zone, type, contained);
dvander@12
   542
}
dvander@12
   543
dvander@4
   544
void
dvander@21
   545
BytecodeCompiler::visit(StringLiteral *node)
dvander@21
   546
{
dvander@30
   547
    Local<Type> type(zone_, node->type());
dvander@30
   548
    Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
dvander@21
   549
    if (!map)
dvander@21
   550
        return;
dvander@21
   551
dvander@30
   552
    Local<Array> array(zone_, Array::New(zone_, map, node->string()->length(), Heap::Tenure_Old));
dvander@21
   553
    if (!array)
dvander@21
   554
        return;
dvander@21
   555
dvander@21
   556
    assert(array->nelements() >= node->string()->length());
dvander@21
   557
    memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
dvander@21
   558
dvander@21
   559
    __ object(array);
dvander@21
   560
}
dvander@21
   561
dvander@21
   562
void
dvander@0
   563
BytecodeCompiler::visit(VariableDeclaration *node)
dvander@0
   564
{
dvander@0
   565
    Variable *var = node->variable();
dvander@0
   566
    assert(var->location() == Variable::STACK);
dvander@0
   567
    
dvander@30
   568
    Local<Type> type(zone_, var->type());
dvander@0
   569
    if (type->isArray()) {
dvander@30
   570
        Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
dvander@19
   571
        __ newarray_lifo(map);
dvander@21
   572
dvander@21
   573
        if (node->initialization()) {
dvander@21
   574
            node->initialization()->accept(this);
dvander@21
   575
            __ arraycopy();
dvander@21
   576
        }
dvander@0
   577
    } else {
dvander@0
   578
        if (node->initialization()) {
dvander@0
   579
            node->initialization()->accept(this);
dvander@0
   580
        } else {
dvander@0
   581
            if (!node->postDimensions())
dvander@0
   582
                __ int_(0);
dvander@0
   583
        }
dvander@0
   584
    }
dvander@0
   585
    __ setlocal(var->slot());
dvander@0
   586
    __ pop();
dvander@0
   587
dvander@30
   588
    locals_->set(zone_, var->slot(), var->type());
dvander@0
   589
}
dvander@0
   590
dvander@0
   591
void
dvander@0
   592
BytecodeCompiler::visit(CallExpression *node)
dvander@0
   593
{
dvander@32
   594
    Local<Type> funType(zone_, node->callee()->type());
dvander@14
   595
dvander@0
   596
    for (size_t i = 0; i < node->arguments()->size(); i++) {
dvander@0
   597
        Expression *arg = node->arguments()->at(i);
dvander@14
   598
dvander@32
   599
        Local<Type> given(zone_, arg->type());
dvander@32
   600
        Local<Type> actual(zone_, Type::cast(funType->parameters()->at(i)));
dvander@14
   601
        if (actual->isReference()) {
dvander@14
   602
            if (given->isReference()) {
dvander@14
   603
                // The input type is already a reference, so we're just passing
dvander@14
   604
                // it on to the callee.
dvander@14
   605
                arg->accept(this);
dvander@14
   606
            } else if (arg->isNameProxy()) {
dvander@14
   607
                // :TODO: test with functions and globals
dvander@14
   608
                // Compute a reference to the name.
dvander@14
   609
                Variable *var = arg->toNameProxy()->binding()->toVariable();
dvander@14
   610
                __ newref(var);
dvander@17
   611
            } else if (arg->isIndexExpression()) {
dvander@17
   612
                IndexExpression *expr = arg->toIndexExpression();
dvander@17
   613
                expr->left()->accept(this);
dvander@17
   614
                expr->right()->accept(this);
dvander@19
   615
                __ bounds();
dvander@17
   616
                __ arrayref_lifo();
dvander@14
   617
            } else {
dvander@14
   618
                // We don't know how to, or can't, build a direct reference to
dvander@14
   619
                // this type. Make an indirect one, by taking the top of the
dvander@14
   620
                // stack and boxing it up.
dvander@16
   621
                arg->accept(this);
dvander@14
   622
                __ slotref_lifo();
dvander@14
   623
            }
dvander@14
   624
        } else {
dvander@14
   625
            arg->accept(this);
dvander@14
   626
        }
dvander@0
   627
    }
dvander@0
   628
dvander@0
   629
    __ callglobal(node->arguments()->size(), 0);
dvander@0
   630
}
dvander@0
   631
dvander@0
   632
void
dvander@0
   633
BytecodeCompiler::visit(IfStatement *node)
dvander@0
   634
{
dvander@0
   635
    if (!node->ifFalse()) {
dvander@0
   636
        Label fail;
dvander@0
   637
        visitForTest(node->condition(), &fail, false);
dvander@0
   638
        node->ifTrue()->accept(this);
dvander@0
   639
        __ bind(&fail);
dvander@0
   640
    } else {
dvander@0
   641
        Label fail, join;
dvander@0
   642
        visitForTest(node->condition(), &fail, false);
dvander@0
   643
        node->ifTrue()->accept(this);
dvander@0
   644
        __ jump(&join);
dvander@0
   645
        __ bind(&fail);
dvander@0
   646
        node->ifFalse()->accept(this);
dvander@0
   647
        __ bind(&join);
dvander@0
   648
    }
dvander@0
   649
}
dvander@0
   650
dvander@0
   651
void
dvander@0
   652
BytecodeCompiler::visit(FunctionStatement *node)
dvander@0
   653
{
dvander@30
   654
    BytecodeCompiler child(zone_, tree_, module_);
dvander@32
   655
    Local<Function> fun(zone_, child.compileFunction(module_, node));
dvander@26
   656
    if (!fun)
dvander@26
   657
        return;
dvander@0
   658
    
dvander@0
   659
    assert(!module_->getFunction(node->fun()->slot()));
dvander@30
   660
    module_->setFunction(zone_, node->fun()->slot(), fun);
dvander@0
   661
}
dvander@0
   662
dvander@2
   663
void
dvander@2
   664
BytecodeCompiler::visit(EnumStatement *node)
dvander@2
   665
{
dvander@2
   666
    // :TODO: eventually, we'll export these.
dvander@2
   667
}
dvander@2
   668
dvander@26
   669
Function *
dvander@0
   670
BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
dvander@0
   671
{
dvander@12
   672
    // Note: No need to record a life slot here, since it's part of the Frame.
dvander@1
   673
    AutoEnterScope functionScope(this, node->scope());
dvander@1
   674
dvander@30
   675
    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
dvander@0
   676
dvander@0
   677
    node->body()->accept(this);
dvander@0
   678
dvander@0
   679
    __ stop();
dvander@0
   680
dvander@0
   681
    if (__ oom())
dvander@12
   682
        return NULL;
dvander@0
   683
dvander@32
   684
    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
dvander@12
   685
    if (!bytes)
dvander@12
   686
        return NULL;
dvander@12
   687
    memcpy(bytes->raw(), __ buffer(), __ length());
dvander@0
   688
dvander@0
   689
    unsigned nargs = node->scope()->numArguments();
dvander@32
   690
    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
dvander@12
   691
    if (!args)
dvander@12
   692
        return NULL;
dvander@12
   693
dvander@0
   694
    for (size_t i = 0; i < node->scope()->numArguments(); i++)
dvander@30
   695
        args->set(zone_, i, node->scope()->getArgument(i)->type());
dvander@0
   696
dvander@0
   697
    for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
dvander@12
   698
        assert(locals_->at(i));
dvander@0
   699
dvander@32
   700
    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->size(), Heap::Tenure_Old));
dvander@21
   701
    if (!objects)
dvander@12
   702
        return NULL;
dvander@0
   703
dvander@21
   704
    for (size_t i = 0; i < __ objects()->size(); i++)
dvander@33
   705
        objects->set(zone_, i, *(__ objects()->at(i)));
dvander@12
   706
dvander@32
   707
    Local<Code> code(zone_, Code::New(zone_, bytes, locals_, objects, __ maxStackDepth(), module_));
dvander@26
   708
    if (!code)
dvander@26
   709
        return NULL;
dvander@26
   710
dvander@32
   711
    Local<Function> fun(zone_, Function::New(zone_, module_, code, node->fun()->type(), node->pos()));
dvander@26
   712
    if (!fun)
dvander@26
   713
        return NULL;
dvander@26
   714
    
dvander@26
   715
    return fun;
dvander@0
   716
}
dvander@0
   717
dvander@0
   718
Module *
dvander@0
   719
BytecodeCompiler::compile()
dvander@0
   720
{
dvander@30
   721
    module_ = Module::New(zone_, tree_->scope()->numFunctions());
dvander@14
   722
    if (!module_)
dvander@14
   723
        return NULL;
dvander@0
   724
dvander@0
   725
    for (size_t i = 0; i < tree_->statements()->length(); i++) {
dvander@0
   726
        Statement *statement = tree_->statements()->at(i);
dvander@0
   727
        statement->accept(this);
dvander@0
   728
    }
dvander@0
   729
dvander@0
   730
#ifndef NDEBUG
dvander@0
   731
    for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
dvander@14
   732
        assert(module_->getFunction(i));
dvander@0
   733
#endif
dvander@0
   734
dvander@0
   735
    return module_;
dvander@0
   736
}