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