jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 01 14:52:57 2012 -0700 (2012-07-01)
changeset 21 af5d8e985502
parent 20 e020a14e21be
child 22 765ab1b672a3
permissions -rw-r--r--
Added initial String: support.
dvander@0
     1
/*
dvander@0
     2
 * Copyright (C) 2012 David Anderson
dvander@0
     3
 *
dvander@0
     4
 * This file is part of JITCraft.
dvander@0
     5
 *
dvander@0
     6
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@0
     7
 * the terms of the GNU General Public License as published by the Free
dvander@0
     8
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@0
     9
 * any later version.
dvander@0
    10
 * 
dvander@0
    11
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@0
    12
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@0
    13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@0
    14
 *
dvander@0
    15
 * You should have received a copy of the GNU General Public License along with
dvander@0
    16
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@0
    17
 */
dvander@0
    18
#include "BytecodeCompiler.h"
dvander@0
    19
#include "Scopes.h"
dvander@0
    20
#include "Modules.h"
dvander@0
    21
#include "Types.h"
dvander@12
    22
#include "Array.h"
dvander@12
    23
#include "Zone.h"
dvander@12
    24
#include "Heap-inl.h"
dvander@0
    25
dvander@0
    26
using namespace jc;
dvander@0
    27
dvander@0
    28
typedef BytecodeEmitter::Label Label;
dvander@0
    29
dvander@0
    30
#define __ emitter_.
dvander@0
    31
dvander@14
    32
BytecodeCompiler::BytecodeCompiler(ParseTree *tree, Module *module)
dvander@1
    33
  : tree_(tree),
dvander@10
    34
    scope_(NULL),
dvander@14
    35
    loop_(NULL),
dvander@14
    36
    module_(module)
dvander@0
    37
{
dvander@0
    38
}
dvander@0
    39
dvander@0
    40
static inline TokenKind
dvander@0
    41
ToCompare(Expression *expr)
dvander@0
    42
{
dvander@0
    43
    if (expr->isBinaryExpression()) {
dvander@0
    44
        BinaryExpression *b = expr->toBinaryExpression();
dvander@0
    45
        if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
dvander@0
    46
            return b->token();
dvander@0
    47
    }
dvander@0
    48
    return TOK_EOF;
dvander@0
    49
}
dvander@0
    50
dvander@0
    51
static inline Opcode
dvander@0
    52
CompareTokenToJump(TokenKind kind)
dvander@0
    53
{
dvander@0
    54
    switch (kind) {
dvander@0
    55
      case TOK_EQUALS:
dvander@0
    56
        return OP_JEQ;
dvander@0
    57
      case TOK_NOTEQUALS:
dvander@0
    58
        return OP_JNE;
dvander@0
    59
      case TOK_GT:
dvander@0
    60
        return OP_JG;
dvander@0
    61
      case TOK_GE:
dvander@0
    62
        return OP_JGE;
dvander@0
    63
      case TOK_LT:
dvander@0
    64
        return OP_JL;
dvander@0
    65
      case TOK_LE:
dvander@0
    66
        return OP_JLE;
dvander@0
    67
    }
dvander@0
    68
    assert(false);
dvander@0
    69
    return OP_NOP;
dvander@0
    70
}
dvander@0
    71
dvander@0
    72
static inline Opcode
dvander@0
    73
TokenToOpcode(TokenKind kind)
dvander@0
    74
{
dvander@0
    75
    switch (kind) {
dvander@0
    76
      case TOK_PLUS:
dvander@0
    77
        return OP_ADD;
dvander@0
    78
      case TOK_MINUS:
dvander@0
    79
        return OP_SUB;
dvander@0
    80
      case TOK_STAR:
dvander@0
    81
        return OP_MUL;
dvander@0
    82
      case TOK_SLASH:
dvander@0
    83
        return OP_DIV;
dvander@8
    84
      case TOK_SHR:
dvander@8
    85
        return OP_SHR;
dvander@8
    86
      case TOK_USHR:
dvander@8
    87
        return OP_USHR;
dvander@8
    88
      case TOK_SHL:
dvander@8
    89
        return OP_SHL;
dvander@8
    90
      case TOK_BITAND:
dvander@8
    91
        return OP_BITAND;
dvander@8
    92
      case TOK_BITOR:
dvander@8
    93
        return OP_BITOR;
dvander@8
    94
      case TOK_BITXOR:
dvander@8
    95
        return OP_BITXOR;
dvander@0
    96
    }
dvander@0
    97
    assert(false);
dvander@0
    98
    return OP_NOP;
dvander@0
    99
}
dvander@0
   100
dvander@0
   101
void
dvander@12
   102
BytecodeCompiler::recordLifoSlot(Scope *scope)
dvander@1
   103
{
dvander@1
   104
    if (!scope)
dvander@1
   105
        return;
dvander@1
   106
dvander@12
   107
    if (Variable *var = scope->lifoSlot()) {
dvander@12
   108
        locals_->set(ZONE(), var->slot(), var->type());
dvander@12
   109
        __ savelifo(var->slot());
dvander@12
   110
    }
dvander@1
   111
}
dvander@1
   112
dvander@1
   113
void
dvander@10
   114
BytecodeCompiler::unwindTo(Scope *scope)
dvander@10
   115
{
dvander@12
   116
    // Note: we only need to unwind to the outermost scope's LIFO slot.
dvander@12
   117
    Variable *var = NULL;
dvander@10
   118
    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
dvander@12
   119
        if (Variable *slot = current->lifoSlot())
dvander@12
   120
            var = slot;
dvander@10
   121
    }
dvander@12
   122
dvander@12
   123
    if (var)
dvander@12
   124
        __ unwindlifo(var->slot());
dvander@10
   125
}
dvander@10
   126
dvander@10
   127
void
dvander@0
   128
BytecodeCompiler::visit(NameProxy *name)
dvander@0
   129
{
dvander@2
   130
    switch (name->binding()->kind()) {
dvander@2
   131
      case BoundName::VARIABLE:
dvander@2
   132
      {
dvander@2
   133
        Variable *var = name->binding()->toVariable();
dvander@0
   134
dvander@2
   135
        if (var->location() == Variable::STACK) {
dvander@2
   136
            __ getlocal(var->slot());
dvander@14
   137
            assert(!name->type()->isReference());
dvander@2
   138
        } else {
dvander@2
   139
            assert(var->location() == Variable::PARAMETER);
dvander@2
   140
            __ getarg(var->slot());
dvander@14
   141
dvander@14
   142
            // If this argument is actually a reference, dereference it now.
dvander@14
   143
            if (var->type()->isReference()) {
dvander@15
   144
                if (var->type()->contained()->isFloat()) {
dvander@14
   145
                    __ getref_f();
dvander@14
   146
                } else {
dvander@20
   147
                    assert(var->type()->contained()->isInt32());
dvander@14
   148
                    __ getref_i();
dvander@14
   149
                }
dvander@14
   150
            }
dvander@2
   151
        }
dvander@2
   152
        break;
dvander@2
   153
      }
dvander@2
   154
dvander@2
   155
      default:
dvander@2
   156
      {
dvander@2
   157
        NamedConstant *constant = name->binding()->toNamedConstant();
dvander@2
   158
        __ int_(constant->value().toInt());
dvander@2
   159
        break;
dvander@2
   160
      }
dvander@0
   161
    }
dvander@0
   162
}
dvander@0
   163
dvander@0
   164
void
dvander@0
   165
BytecodeCompiler::visit(ExpressionStatement *node)
dvander@0
   166
{
dvander@0
   167
    // Expressions leave their value on the top of the stack, so we make sure
dvander@0
   168
    // to balance the stack if they're used as a statement.
dvander@0
   169
    node->expression()->accept(this);
dvander@0
   170
    __ pop();
dvander@0
   171
}
dvander@0
   172
dvander@0
   173
void
dvander@0
   174
BytecodeCompiler::visit(Assignment *node)
dvander@0
   175
{
dvander@21
   176
    // First compute the left-hand side.
dvander@0
   177
    if (node->lvalue()->isNameProxy()) {
dvander@0
   178
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@0
   179
        Variable *var = proxy->binding()->toVariable();
dvander@0
   180
dvander@14
   181
        // Make sure to bind the left-hand side first.
dvander@21
   182
        if (var->type()->isReference() || var->type()->isArray())
dvander@16
   183
            __ get(var);
dvander@14
   184
dvander@0
   185
        node->expression()->accept(this);
dvander@21
   186
    } else if (node->lvalue()->isIndexExpression()) {
dvander@21
   187
        IndexExpression *index = node->lvalue()->toIndexExpression();
dvander@21
   188
dvander@21
   189
        // Note: Eventually, watch out for a whole here. An expression like:
dvander@21
   190
        //
dvander@21
   191
        //   (a[4] = (5, a = []))
dvander@21
   192
        //
dvander@21
   193
        // Could shrink array, so we need to either bind a[i] to a Reference,
dvander@21
   194
        // or keep the bounds check near the set. This is just a semantic
dvander@21
   195
        // decision.
dvander@21
   196
        index->left()->accept(this);
dvander@21
   197
        index->right()->accept(this);
dvander@21
   198
        node->expression()->accept(this);
dvander@21
   199
    }
dvander@21
   200
dvander@21
   201
    // Emit the store.
dvander@21
   202
    if (node->expression()->type()->isArray()) {
dvander@21
   203
        // Unlike references, which can only be computed from a NamePRoxy,
dvander@21
   204
        // arrays can be computed from multiple lvalue types.
dvander@21
   205
        __ arraycopy();
dvander@21
   206
    } else if (node->lvalue()->isNameProxy()) {
dvander@21
   207
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@21
   208
        Variable *var = proxy->binding()->toVariable();
dvander@14
   209
dvander@14
   210
        if (var->type()->isReference()) {
dvander@14
   211
            if (var->type()->contained()->isFloat()) {
dvander@14
   212
                __ setref_f();
dvander@14
   213
            } else {
dvander@20
   214
                assert(var->type()->contained()->isInt32());
dvander@14
   215
                __ setref_i();
dvander@14
   216
            }
dvander@0
   217
        } else {
dvander@16
   218
            __ set(var);
dvander@0
   219
        }
dvander@21
   220
    } else {
dvander@0
   221
        IndexExpression *index = node->lvalue()->toIndexExpression();
dvander@19
   222
        __ bounds();
dvander@21
   223
        __ setarray(index->left()->type()->contained()->primitive());
dvander@0
   224
    }
dvander@0
   225
}
dvander@0
   226
dvander@0
   227
void
dvander@4
   228
BytecodeCompiler::visitForALU(Type *needed, Expression *node)
dvander@4
   229
{
dvander@4
   230
    node->accept(this);
dvander@4
   231
    if (needed->isFloat() && !node->type()->isFloat())
dvander@4
   232
        __ cvt_i2f();
dvander@4
   233
}
dvander@4
   234
dvander@4
   235
void
dvander@0
   236
BytecodeCompiler::visit(BinaryExpression *node)
dvander@0
   237
{
dvander@4
   238
    visitForALU(node->type(), node->left());
dvander@4
   239
    visitForALU(node->type(), node->right());
dvander@0
   240
dvander@0
   241
    Opcode op = TokenToOpcode(node->token());
dvander@4
   242
    if (node->type()->isFloat())
dvander@4
   243
        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
dvander@0
   244
    __ binary(op);
dvander@0
   245
}
dvander@0
   246
dvander@0
   247
void
dvander@0
   248
BytecodeCompiler::visit(IndexExpression *node)
dvander@0
   249
{
dvander@0
   250
    node->left()->accept(this);
dvander@0
   251
    node->right()->accept(this);
dvander@19
   252
    __ bounds();
dvander@0
   253
dvander@21
   254
    if (node->type()->isArray())
dvander@19
   255
        __ getarray_o();
dvander@21
   256
    else
dvander@21
   257
        __ getarray(node->type()->primitive());
dvander@0
   258
}
dvander@0
   259
dvander@0
   260
void
dvander@0
   261
BytecodeCompiler::visit(ReturnStatement *node)
dvander@0
   262
{
dvander@0
   263
    if (node->expression())
dvander@0
   264
        node->expression()->accept(this);
dvander@0
   265
    else
dvander@0
   266
        __ int_(0);
dvander@0
   267
dvander@0
   268
    __ return_();
dvander@0
   269
}
dvander@0
   270
dvander@0
   271
void
dvander@0
   272
BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
dvander@0
   273
{
dvander@0
   274
    TokenKind token = ToCompare(expression);
dvander@0
   275
    if (token == TOK_EOF) {
dvander@0
   276
        expression->accept(this);
dvander@0
   277
        if (onTrue)
dvander@0
   278
            __ j(OP_JT, label);
dvander@0
   279
        else
dvander@0
   280
            __ j(OP_JF, label);
dvander@0
   281
        return;
dvander@0
   282
    }
dvander@0
   283
dvander@0
   284
    Opcode op = CompareTokenToJump(token);
dvander@0
   285
    if (!onTrue)
dvander@0
   286
        op = Invert(op);
dvander@0
   287
dvander@0
   288
    assert(expression->isBinaryExpression());
dvander@0
   289
    BinaryExpression *binary = expression->toBinaryExpression();
dvander@0
   290
    binary->left()->accept(this);
dvander@0
   291
    binary->right()->accept(this);
dvander@0
   292
    __ j(op, label);
dvander@0
   293
}
dvander@0
   294
dvander@0
   295
void
dvander@0
   296
BytecodeCompiler::visit(ForStatement *node)
dvander@0
   297
{
dvander@1
   298
    AutoEnterScope forScope(this, node->scope());
dvander@1
   299
dvander@12
   300
    recordLifoSlot(node->scope());
dvander@12
   301
dvander@10
   302
    Label join, update;
dvander@10
   303
    LoopScope loop(scope_, &join, &update, &loop_);
dvander@10
   304
dvander@0
   305
    if (node->declaration())
dvander@0
   306
        node->declaration()->accept(this);
dvander@0
   307
dvander@0
   308
    Label header, test;
dvander@0
   309
    if (node->condition())
dvander@0
   310
        __ jump(&test);
dvander@0
   311
dvander@0
   312
    __ bind(&header);
dvander@0
   313
    node->body()->accept(this);
dvander@0
   314
dvander@10
   315
    __ bind(&update);
dvander@0
   316
    if (node->update())
dvander@0
   317
        node->update()->accept(this);
dvander@0
   318
dvander@0
   319
    if (node->condition()) {
dvander@0
   320
        __ bind(&test);
dvander@0
   321
        visitForTest(node->condition(), &header, true);
dvander@0
   322
    } else {
dvander@0
   323
        __ jump(&header);
dvander@0
   324
    }
dvander@0
   325
dvander@10
   326
    __ bind(&join);
dvander@10
   327
dvander@12
   328
    if (node->scope())
dvander@12
   329
        unwindTo(node->scope()->enclosing());
dvander@0
   330
    assert(__ stackDepth() == 0);
dvander@0
   331
}
dvander@0
   332
dvander@0
   333
void
dvander@9
   334
BytecodeCompiler::visit(WhileStatement *node)
dvander@9
   335
{
dvander@10
   336
    Label header, join;
dvander@9
   337
dvander@9
   338
    __ bind(&header);
dvander@9
   339
dvander@10
   340
    LoopScope loop(scope_, &join, &header, &loop_);
dvander@10
   341
dvander@9
   342
    if (node->token() == TOK_WHILE) {
dvander@9
   343
        visitForTest(node->condition(), &join, false);
dvander@9
   344
        node->body()->accept(this);
dvander@9
   345
        __ jump(&header);
dvander@9
   346
    } else {
dvander@9
   347
        node->body()->accept(this);
dvander@9
   348
        visitForTest(node->condition(), &header, true);
dvander@9
   349
    }
dvander@10
   350
dvander@10
   351
    __ bind(&join);
dvander@10
   352
}
dvander@10
   353
dvander@10
   354
void
dvander@10
   355
BytecodeCompiler::visit(BreakStatement *node)
dvander@10
   356
{
dvander@10
   357
    unwindTo(loop_->scope());
dvander@10
   358
    __ jump(loop_->break_());
dvander@10
   359
}
dvander@10
   360
dvander@10
   361
void
dvander@10
   362
BytecodeCompiler::visit(ContinueStatement *node)
dvander@10
   363
{
dvander@10
   364
    unwindTo(loop_->scope());
dvander@10
   365
    __ jump(loop_->continue_());
dvander@9
   366
}
dvander@9
   367
dvander@9
   368
void
dvander@0
   369
BytecodeCompiler::visit(BlockStatement *node)
dvander@0
   370
{
dvander@1
   371
    AutoEnterScope blockScope(this, node->scope());
dvander@1
   372
dvander@12
   373
    recordLifoSlot(node->scope());
dvander@12
   374
dvander@0
   375
    for (size_t i = 0; i < node->statements()->length(); i++) {
dvander@0
   376
        Statement *statement = node->statements()->at(i);
dvander@0
   377
        statement->accept(this);
dvander@0
   378
        assert(__ stackDepth() == 0);
dvander@0
   379
    }
dvander@1
   380
dvander@1
   381
    // We don't bother emitting an "unwind" instruction for function scopes,
dvander@1
   382
    // since this is taken care of by the calling convention.
dvander@1
   383
    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
dvander@12
   384
        unwindTo(node->scope()->enclosing());
dvander@0
   385
}
dvander@0
   386
dvander@0
   387
void
dvander@4
   388
BytecodeCompiler::visit(IntegerLiteral *node)
dvander@0
   389
{
dvander@0
   390
    __ int_(node->value());
dvander@0
   391
}
dvander@0
   392
dvander@0
   393
void
dvander@4
   394
BytecodeCompiler::visit(FloatLiteral *node)
dvander@4
   395
{
dvander@4
   396
    __ float_((float)node->value());
dvander@4
   397
}
dvander@4
   398
dvander@12
   399
static inline ArrayMap *
dvander@12
   400
BuildArrayMap(Zone *zone, Type *type)
dvander@12
   401
{
dvander@12
   402
    // :TODO: use local
dvander@12
   403
    ArrayMap *contained = NULL;
dvander@12
   404
    if (type->levels() > 1) {
dvander@12
   405
        contained = BuildArrayMap(zone, type->contained());
dvander@12
   406
        if (!contained)
dvander@12
   407
            return NULL;
dvander@12
   408
    }
dvander@12
   409
dvander@12
   410
    return ArrayMap::New(zone, type, contained);
dvander@12
   411
}
dvander@12
   412
dvander@4
   413
void
dvander@21
   414
BytecodeCompiler::visit(StringLiteral *node)
dvander@21
   415
{
dvander@21
   416
    // :TODO: use Local
dvander@21
   417
    ArrayMap *map = BuildArrayMap(ZONE(), node->type());
dvander@21
   418
    if (!map)
dvander@21
   419
        return;
dvander@21
   420
dvander@21
   421
    Array *array = Array::New(ZONE(), map, node->string()->length(), Heap::Tenure_Old);
dvander@21
   422
    if (!array)
dvander@21
   423
        return;
dvander@21
   424
dvander@21
   425
    assert(array->nelements() >= node->string()->length());
dvander@21
   426
    memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
dvander@21
   427
dvander@21
   428
    __ object(array);
dvander@21
   429
}
dvander@21
   430
dvander@21
   431
void
dvander@0
   432
BytecodeCompiler::visit(VariableDeclaration *node)
dvander@0
   433
{
dvander@0
   434
    Variable *var = node->variable();
dvander@0
   435
    assert(var->location() == Variable::STACK);
dvander@0
   436
    
dvander@0
   437
    Type *type = var->type();
dvander@0
   438
    if (type->isArray()) {
dvander@12
   439
        // :TODO: use Local
dvander@12
   440
        ArrayMap *map = BuildArrayMap(ZONE(), type);
dvander@19
   441
        __ newarray_lifo(map);
dvander@21
   442
dvander@21
   443
        if (node->initialization()) {
dvander@21
   444
            node->initialization()->accept(this);
dvander@21
   445
            __ arraycopy();
dvander@21
   446
        }
dvander@0
   447
    } else {
dvander@0
   448
        if (node->initialization()) {
dvander@0
   449
            node->initialization()->accept(this);
dvander@0
   450
        } else {
dvander@0
   451
            if (!node->postDimensions())
dvander@0
   452
                __ int_(0);
dvander@0
   453
        }
dvander@0
   454
    }
dvander@0
   455
    __ setlocal(var->slot());
dvander@0
   456
    __ pop();
dvander@0
   457
dvander@12
   458
    locals_->set(ZONE(), var->slot(), var->type());
dvander@0
   459
}
dvander@0
   460
dvander@0
   461
void
dvander@0
   462
BytecodeCompiler::visit(CallExpression *node)
dvander@0
   463
{
dvander@0
   464
    NameProxy *fun = node->callee()->toNameProxy();
dvander@0
   465
dvander@14
   466
    // :TODO: use Local
dvander@14
   467
    Type *funType = node->callee()->type();
dvander@14
   468
dvander@0
   469
    for (size_t i = 0; i < node->arguments()->size(); i++) {
dvander@0
   470
        Expression *arg = node->arguments()->at(i);
dvander@14
   471
dvander@14
   472
        Type *given = arg->type();
dvander@14
   473
        Type *actual = Type::cast(funType->parameters()->at(i));
dvander@14
   474
        if (actual->isReference()) {
dvander@14
   475
            if (given->isReference()) {
dvander@14
   476
                // The input type is already a reference, so we're just passing
dvander@14
   477
                // it on to the callee.
dvander@14
   478
                arg->accept(this);
dvander@14
   479
            } else if (arg->isNameProxy()) {
dvander@14
   480
                // :TODO: test with functions and globals
dvander@14
   481
                // Compute a reference to the name.
dvander@14
   482
                Variable *var = arg->toNameProxy()->binding()->toVariable();
dvander@14
   483
                __ newref(var);
dvander@17
   484
            } else if (arg->isIndexExpression()) {
dvander@17
   485
                IndexExpression *expr = arg->toIndexExpression();
dvander@17
   486
                expr->left()->accept(this);
dvander@17
   487
                expr->right()->accept(this);
dvander@19
   488
                __ bounds();
dvander@17
   489
                __ arrayref_lifo();
dvander@14
   490
            } else {
dvander@14
   491
                // We don't know how to, or can't, build a direct reference to
dvander@14
   492
                // this type. Make an indirect one, by taking the top of the
dvander@14
   493
                // stack and boxing it up.
dvander@16
   494
                arg->accept(this);
dvander@14
   495
                __ slotref_lifo();
dvander@14
   496
            }
dvander@14
   497
        } else {
dvander@14
   498
            arg->accept(this);
dvander@14
   499
        }
dvander@0
   500
    }
dvander@0
   501
dvander@0
   502
    __ callglobal(node->arguments()->size(), 0);
dvander@0
   503
}
dvander@0
   504
dvander@0
   505
void
dvander@0
   506
BytecodeCompiler::visit(IfStatement *node)
dvander@0
   507
{
dvander@0
   508
    if (!node->ifFalse()) {
dvander@0
   509
        Label fail;
dvander@0
   510
        visitForTest(node->condition(), &fail, false);
dvander@0
   511
        node->ifTrue()->accept(this);
dvander@0
   512
        __ bind(&fail);
dvander@0
   513
    } else {
dvander@0
   514
        Label fail, join;
dvander@0
   515
        visitForTest(node->condition(), &fail, false);
dvander@0
   516
        node->ifTrue()->accept(this);
dvander@0
   517
        __ jump(&join);
dvander@0
   518
        __ bind(&fail);
dvander@0
   519
        node->ifFalse()->accept(this);
dvander@0
   520
        __ bind(&join);
dvander@0
   521
    }
dvander@0
   522
}
dvander@0
   523
dvander@0
   524
void
dvander@0
   525
BytecodeCompiler::visit(FunctionStatement *node)
dvander@0
   526
{
dvander@14
   527
    BytecodeCompiler child(tree_, module_);
dvander@0
   528
    Code *code = child.compileFunction(module_, node);
dvander@0
   529
    
dvander@0
   530
    assert(!module_->getFunction(node->fun()->slot()));
dvander@14
   531
    module_->setFunction(ZONE(), node->fun()->slot(), code);
dvander@0
   532
}
dvander@0
   533
dvander@2
   534
void
dvander@2
   535
BytecodeCompiler::visit(EnumStatement *node)
dvander@2
   536
{
dvander@2
   537
    // :TODO: eventually, we'll export these.
dvander@2
   538
}
dvander@2
   539
dvander@0
   540
Code *
dvander@0
   541
BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
dvander@0
   542
{
dvander@12
   543
    // Note: No need to record a life slot here, since it's part of the Frame.
dvander@1
   544
    AutoEnterScope functionScope(this, node->scope());
dvander@1
   545
dvander@12
   546
    // :TODO: use locals
dvander@12
   547
    locals_ = FixedArray::New(ZONE(), node->scope()->maxContainedLocals(), Heap::Tenure_Old);
dvander@0
   548
dvander@0
   549
    node->body()->accept(this);
dvander@0
   550
dvander@0
   551
    __ stop();
dvander@0
   552
dvander@0
   553
    if (__ oom())
dvander@12
   554
        return NULL;
dvander@0
   555
dvander@12
   556
    ByteArray *bytes = ByteArray::New(ZONE(), __ length() * sizeof(bytecode), Heap::Tenure_Old);
dvander@12
   557
    if (!bytes)
dvander@12
   558
        return NULL;
dvander@12
   559
    memcpy(bytes->raw(), __ buffer(), __ length());
dvander@0
   560
dvander@0
   561
    unsigned nargs = node->scope()->numArguments();
dvander@12
   562
    FixedArray *args = FixedArray::New(ZONE(), nargs, Heap::Tenure_Old);
dvander@12
   563
    if (!args)
dvander@12
   564
        return NULL;
dvander@12
   565
dvander@0
   566
    for (size_t i = 0; i < node->scope()->numArguments(); i++)
dvander@12
   567
        args->set(ZONE(), i, node->scope()->getArgument(i)->type());
dvander@0
   568
dvander@0
   569
    for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
dvander@12
   570
        assert(locals_->at(i));
dvander@0
   571
dvander@21
   572
    FixedArray *objects = FixedArray::New(ZONE(), __ objects()->size(), Heap::Tenure_Old);
dvander@21
   573
    if (!objects)
dvander@12
   574
        return NULL;
dvander@0
   575
dvander@21
   576
    for (size_t i = 0; i < __ objects()->size(); i++)
dvander@21
   577
        objects->set(ZONE(), i, __ objects()->at(i));
dvander@12
   578
dvander@21
   579
    Code *code = Code::New(ZONE(), bytes, locals_, args, objects, __ maxStackDepth(), module_);
dvander@0
   580
    return code;
dvander@0
   581
}
dvander@0
   582
dvander@0
   583
Module *
dvander@0
   584
BytecodeCompiler::compile()
dvander@0
   585
{
dvander@14
   586
    // :TODO: root
dvander@14
   587
    module_ = Module::New(ZONE(), tree_->scope()->numFunctions());
dvander@14
   588
    if (!module_)
dvander@14
   589
        return NULL;
dvander@0
   590
dvander@0
   591
    for (size_t i = 0; i < tree_->statements()->length(); i++) {
dvander@0
   592
        Statement *statement = tree_->statements()->at(i);
dvander@0
   593
        statement->accept(this);
dvander@0
   594
    }
dvander@0
   595
dvander@0
   596
#ifndef NDEBUG
dvander@0
   597
    for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
dvander@14
   598
        assert(module_->getFunction(i));
dvander@0
   599
#endif
dvander@0
   600
dvander@0
   601
    return module_;
dvander@0
   602
}