jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jun 30 19:38:53 2012 -0700 (2012-06-30)
changeset 12 75e385f68b7e
parent 10 0c3bcd50e361
child 14 0784ac5cc347
permissions -rw-r--r--
Refactored Array, Code to be Objects. Removed Object tagging.
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@0
    32
BytecodeCompiler::BytecodeCompiler(ParseTree *tree)
dvander@1
    33
  : tree_(tree),
dvander@10
    34
    scope_(NULL),
dvander@10
    35
    loop_(NULL)
dvander@0
    36
{
dvander@0
    37
}
dvander@0
    38
dvander@0
    39
static inline TokenKind
dvander@0
    40
ToCompare(Expression *expr)
dvander@0
    41
{
dvander@0
    42
    if (expr->isBinaryExpression()) {
dvander@0
    43
        BinaryExpression *b = expr->toBinaryExpression();
dvander@0
    44
        if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
dvander@0
    45
            return b->token();
dvander@0
    46
    }
dvander@0
    47
    return TOK_EOF;
dvander@0
    48
}
dvander@0
    49
dvander@0
    50
static inline Opcode
dvander@0
    51
CompareTokenToJump(TokenKind kind)
dvander@0
    52
{
dvander@0
    53
    switch (kind) {
dvander@0
    54
      case TOK_EQUALS:
dvander@0
    55
        return OP_JEQ;
dvander@0
    56
      case TOK_NOTEQUALS:
dvander@0
    57
        return OP_JNE;
dvander@0
    58
      case TOK_GT:
dvander@0
    59
        return OP_JG;
dvander@0
    60
      case TOK_GE:
dvander@0
    61
        return OP_JGE;
dvander@0
    62
      case TOK_LT:
dvander@0
    63
        return OP_JL;
dvander@0
    64
      case TOK_LE:
dvander@0
    65
        return OP_JLE;
dvander@0
    66
    }
dvander@0
    67
    assert(false);
dvander@0
    68
    return OP_NOP;
dvander@0
    69
}
dvander@0
    70
dvander@0
    71
static inline Opcode
dvander@0
    72
TokenToOpcode(TokenKind kind)
dvander@0
    73
{
dvander@0
    74
    switch (kind) {
dvander@0
    75
      case TOK_PLUS:
dvander@0
    76
        return OP_ADD;
dvander@0
    77
      case TOK_MINUS:
dvander@0
    78
        return OP_SUB;
dvander@0
    79
      case TOK_STAR:
dvander@0
    80
        return OP_MUL;
dvander@0
    81
      case TOK_SLASH:
dvander@0
    82
        return OP_DIV;
dvander@8
    83
      case TOK_SHR:
dvander@8
    84
        return OP_SHR;
dvander@8
    85
      case TOK_USHR:
dvander@8
    86
        return OP_USHR;
dvander@8
    87
      case TOK_SHL:
dvander@8
    88
        return OP_SHL;
dvander@8
    89
      case TOK_BITAND:
dvander@8
    90
        return OP_BITAND;
dvander@8
    91
      case TOK_BITOR:
dvander@8
    92
        return OP_BITOR;
dvander@8
    93
      case TOK_BITXOR:
dvander@8
    94
        return OP_BITXOR;
dvander@0
    95
    }
dvander@0
    96
    assert(false);
dvander@0
    97
    return OP_NOP;
dvander@0
    98
}
dvander@0
    99
dvander@0
   100
void
dvander@12
   101
BytecodeCompiler::recordLifoSlot(Scope *scope)
dvander@1
   102
{
dvander@1
   103
    if (!scope)
dvander@1
   104
        return;
dvander@1
   105
dvander@12
   106
    if (Variable *var = scope->lifoSlot()) {
dvander@12
   107
        locals_->set(ZONE(), var->slot(), var->type());
dvander@12
   108
        __ savelifo(var->slot());
dvander@12
   109
    }
dvander@1
   110
}
dvander@1
   111
dvander@1
   112
void
dvander@10
   113
BytecodeCompiler::unwindTo(Scope *scope)
dvander@10
   114
{
dvander@12
   115
    // Note: we only need to unwind to the outermost scope's LIFO slot.
dvander@12
   116
    Variable *var = NULL;
dvander@10
   117
    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
dvander@12
   118
        if (Variable *slot = current->lifoSlot())
dvander@12
   119
            var = slot;
dvander@10
   120
    }
dvander@12
   121
dvander@12
   122
    if (var)
dvander@12
   123
        __ unwindlifo(var->slot());
dvander@10
   124
}
dvander@10
   125
dvander@10
   126
void
dvander@0
   127
BytecodeCompiler::visit(NameProxy *name)
dvander@0
   128
{
dvander@2
   129
    switch (name->binding()->kind()) {
dvander@2
   130
      case BoundName::VARIABLE:
dvander@2
   131
      {
dvander@2
   132
        Variable *var = name->binding()->toVariable();
dvander@0
   133
dvander@2
   134
        if (var->location() == Variable::STACK) {
dvander@2
   135
            __ getlocal(var->slot());
dvander@2
   136
        } else {
dvander@2
   137
            assert(var->location() == Variable::PARAMETER);
dvander@2
   138
            __ getarg(var->slot());
dvander@2
   139
        }
dvander@2
   140
        break;
dvander@2
   141
      }
dvander@2
   142
dvander@2
   143
      default:
dvander@2
   144
      {
dvander@2
   145
        NamedConstant *constant = name->binding()->toNamedConstant();
dvander@2
   146
        __ int_(constant->value().toInt());
dvander@2
   147
        break;
dvander@2
   148
      }
dvander@0
   149
    }
dvander@0
   150
}
dvander@0
   151
dvander@0
   152
void
dvander@0
   153
BytecodeCompiler::visit(ExpressionStatement *node)
dvander@0
   154
{
dvander@0
   155
    // Expressions leave their value on the top of the stack, so we make sure
dvander@0
   156
    // to balance the stack if they're used as a statement.
dvander@0
   157
    node->expression()->accept(this);
dvander@0
   158
    __ pop();
dvander@0
   159
}
dvander@0
   160
dvander@0
   161
void
dvander@0
   162
BytecodeCompiler::visit(Assignment *node)
dvander@0
   163
{
dvander@0
   164
    if (node->lvalue()->isNameProxy()) {
dvander@0
   165
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@0
   166
        Variable *var = proxy->binding()->toVariable();
dvander@0
   167
dvander@0
   168
        node->expression()->accept(this);
dvander@0
   169
        if (var->location() == Variable::STACK) {
dvander@0
   170
            __ setlocal(var->slot());
dvander@0
   171
        } else {
dvander@0
   172
            assert(var->location() == Variable::PARAMETER);
dvander@0
   173
            __ setarg(var->slot());
dvander@0
   174
        }
dvander@0
   175
    } else if (node->lvalue()->isIndexExpression()) {
dvander@0
   176
        IndexExpression *index = node->lvalue()->toIndexExpression();
dvander@0
   177
dvander@0
   178
        index->left()->accept(this);
dvander@0
   179
        index->right()->accept(this);
dvander@0
   180
        __ bounds_sta();
dvander@0
   181
        node->expression()->accept(this);
dvander@7
   182
        if (index->left()->type()->contained()->isFloat()) {
dvander@7
   183
            __ setarray_f();
dvander@7
   184
        } else {
dvander@7
   185
            assert(index->left()->type()->contained()->isInt());
dvander@7
   186
            __ setarray_i();
dvander@7
   187
        }
dvander@0
   188
    }
dvander@0
   189
}
dvander@0
   190
dvander@0
   191
void
dvander@4
   192
BytecodeCompiler::visitForALU(Type *needed, Expression *node)
dvander@4
   193
{
dvander@4
   194
    node->accept(this);
dvander@4
   195
    if (needed->isFloat() && !node->type()->isFloat())
dvander@4
   196
        __ cvt_i2f();
dvander@4
   197
}
dvander@4
   198
dvander@4
   199
void
dvander@0
   200
BytecodeCompiler::visit(BinaryExpression *node)
dvander@0
   201
{
dvander@4
   202
    visitForALU(node->type(), node->left());
dvander@4
   203
    visitForALU(node->type(), node->right());
dvander@0
   204
dvander@0
   205
    Opcode op = TokenToOpcode(node->token());
dvander@4
   206
    if (node->type()->isFloat())
dvander@4
   207
        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
dvander@0
   208
    __ binary(op);
dvander@0
   209
}
dvander@0
   210
dvander@0
   211
void
dvander@0
   212
BytecodeCompiler::visit(IndexExpression *node)
dvander@0
   213
{
dvander@0
   214
    node->left()->accept(this);
dvander@0
   215
    node->right()->accept(this);
dvander@0
   216
    __ bounds_sta();
dvander@0
   217
dvander@7
   218
    if (node->type()->isArray()) {
dvander@6
   219
        __ getarray_p();
dvander@7
   220
    } else if (node->type()->isFloat()) {
dvander@7
   221
        __ getarray_f();
dvander@7
   222
    } else {
dvander@6
   223
        __ getarray_i();
dvander@7
   224
        assert(node->type()->isInt());
dvander@7
   225
    }
dvander@0
   226
}
dvander@0
   227
dvander@0
   228
void
dvander@0
   229
BytecodeCompiler::visit(ReturnStatement *node)
dvander@0
   230
{
dvander@0
   231
    if (node->expression())
dvander@0
   232
        node->expression()->accept(this);
dvander@0
   233
    else
dvander@0
   234
        __ int_(0);
dvander@0
   235
dvander@0
   236
    __ return_();
dvander@0
   237
}
dvander@0
   238
dvander@0
   239
void
dvander@0
   240
BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
dvander@0
   241
{
dvander@0
   242
    TokenKind token = ToCompare(expression);
dvander@0
   243
    if (token == TOK_EOF) {
dvander@0
   244
        expression->accept(this);
dvander@0
   245
        if (onTrue)
dvander@0
   246
            __ j(OP_JT, label);
dvander@0
   247
        else
dvander@0
   248
            __ j(OP_JF, label);
dvander@0
   249
        return;
dvander@0
   250
    }
dvander@0
   251
dvander@0
   252
    Opcode op = CompareTokenToJump(token);
dvander@0
   253
    if (!onTrue)
dvander@0
   254
        op = Invert(op);
dvander@0
   255
dvander@0
   256
    assert(expression->isBinaryExpression());
dvander@0
   257
    BinaryExpression *binary = expression->toBinaryExpression();
dvander@0
   258
    binary->left()->accept(this);
dvander@0
   259
    binary->right()->accept(this);
dvander@0
   260
    __ j(op, label);
dvander@0
   261
}
dvander@0
   262
dvander@0
   263
void
dvander@0
   264
BytecodeCompiler::visit(ForStatement *node)
dvander@0
   265
{
dvander@1
   266
    AutoEnterScope forScope(this, node->scope());
dvander@1
   267
dvander@12
   268
    recordLifoSlot(node->scope());
dvander@12
   269
dvander@10
   270
    Label join, update;
dvander@10
   271
    LoopScope loop(scope_, &join, &update, &loop_);
dvander@10
   272
dvander@0
   273
    if (node->declaration())
dvander@0
   274
        node->declaration()->accept(this);
dvander@0
   275
dvander@0
   276
    Label header, test;
dvander@0
   277
    if (node->condition())
dvander@0
   278
        __ jump(&test);
dvander@0
   279
dvander@0
   280
    __ bind(&header);
dvander@0
   281
    node->body()->accept(this);
dvander@0
   282
dvander@10
   283
    __ bind(&update);
dvander@0
   284
    if (node->update())
dvander@0
   285
        node->update()->accept(this);
dvander@0
   286
dvander@0
   287
    if (node->condition()) {
dvander@0
   288
        __ bind(&test);
dvander@0
   289
        visitForTest(node->condition(), &header, true);
dvander@0
   290
    } else {
dvander@0
   291
        __ jump(&header);
dvander@0
   292
    }
dvander@0
   293
dvander@10
   294
    __ bind(&join);
dvander@10
   295
dvander@12
   296
    if (node->scope())
dvander@12
   297
        unwindTo(node->scope()->enclosing());
dvander@0
   298
    assert(__ stackDepth() == 0);
dvander@0
   299
}
dvander@0
   300
dvander@0
   301
void
dvander@9
   302
BytecodeCompiler::visit(WhileStatement *node)
dvander@9
   303
{
dvander@10
   304
    Label header, join;
dvander@9
   305
dvander@9
   306
    __ bind(&header);
dvander@9
   307
dvander@10
   308
    LoopScope loop(scope_, &join, &header, &loop_);
dvander@10
   309
dvander@9
   310
    if (node->token() == TOK_WHILE) {
dvander@9
   311
        visitForTest(node->condition(), &join, false);
dvander@9
   312
        node->body()->accept(this);
dvander@9
   313
        __ jump(&header);
dvander@9
   314
    } else {
dvander@9
   315
        node->body()->accept(this);
dvander@9
   316
        visitForTest(node->condition(), &header, true);
dvander@9
   317
    }
dvander@10
   318
dvander@10
   319
    __ bind(&join);
dvander@10
   320
}
dvander@10
   321
dvander@10
   322
void
dvander@10
   323
BytecodeCompiler::visit(BreakStatement *node)
dvander@10
   324
{
dvander@10
   325
    unwindTo(loop_->scope());
dvander@10
   326
    __ jump(loop_->break_());
dvander@10
   327
}
dvander@10
   328
dvander@10
   329
void
dvander@10
   330
BytecodeCompiler::visit(ContinueStatement *node)
dvander@10
   331
{
dvander@10
   332
    unwindTo(loop_->scope());
dvander@10
   333
    __ jump(loop_->continue_());
dvander@9
   334
}
dvander@9
   335
dvander@9
   336
void
dvander@0
   337
BytecodeCompiler::visit(BlockStatement *node)
dvander@0
   338
{
dvander@1
   339
    AutoEnterScope blockScope(this, node->scope());
dvander@1
   340
dvander@12
   341
    recordLifoSlot(node->scope());
dvander@12
   342
dvander@0
   343
    for (size_t i = 0; i < node->statements()->length(); i++) {
dvander@0
   344
        Statement *statement = node->statements()->at(i);
dvander@0
   345
        statement->accept(this);
dvander@0
   346
        assert(__ stackDepth() == 0);
dvander@0
   347
    }
dvander@1
   348
dvander@1
   349
    // We don't bother emitting an "unwind" instruction for function scopes,
dvander@1
   350
    // since this is taken care of by the calling convention.
dvander@1
   351
    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
dvander@12
   352
        unwindTo(node->scope()->enclosing());
dvander@0
   353
}
dvander@0
   354
dvander@0
   355
void
dvander@4
   356
BytecodeCompiler::visit(IntegerLiteral *node)
dvander@0
   357
{
dvander@0
   358
    __ int_(node->value());
dvander@0
   359
}
dvander@0
   360
dvander@0
   361
void
dvander@4
   362
BytecodeCompiler::visit(FloatLiteral *node)
dvander@4
   363
{
dvander@4
   364
    __ float_((float)node->value());
dvander@4
   365
}
dvander@4
   366
dvander@12
   367
static inline ArrayMap *
dvander@12
   368
BuildArrayMap(Zone *zone, Type *type)
dvander@12
   369
{
dvander@12
   370
    // :TODO: use local
dvander@12
   371
    ArrayMap *contained = NULL;
dvander@12
   372
    if (type->levels() > 1) {
dvander@12
   373
        contained = BuildArrayMap(zone, type->contained());
dvander@12
   374
        if (!contained)
dvander@12
   375
            return NULL;
dvander@12
   376
    }
dvander@12
   377
dvander@12
   378
    return ArrayMap::New(zone, type, contained);
dvander@12
   379
}
dvander@12
   380
dvander@4
   381
void
dvander@0
   382
BytecodeCompiler::visit(VariableDeclaration *node)
dvander@0
   383
{
dvander@0
   384
    Variable *var = node->variable();
dvander@0
   385
    assert(var->location() == Variable::STACK);
dvander@0
   386
    
dvander@0
   387
    Type *type = var->type();
dvander@0
   388
    if (type->isArray()) {
dvander@12
   389
        // :TODO: use Local
dvander@12
   390
        ArrayMap *map = BuildArrayMap(ZONE(), type);
dvander@12
   391
        __ lifoarray(map);
dvander@0
   392
    } else {
dvander@0
   393
        if (node->initialization()) {
dvander@0
   394
            node->initialization()->accept(this);
dvander@0
   395
        } else {
dvander@0
   396
            if (!node->postDimensions())
dvander@0
   397
                __ int_(0);
dvander@0
   398
        }
dvander@0
   399
    }
dvander@0
   400
    __ setlocal(var->slot());
dvander@0
   401
    __ pop();
dvander@0
   402
dvander@12
   403
    locals_->set(ZONE(), var->slot(), var->type());
dvander@0
   404
}
dvander@0
   405
dvander@0
   406
void
dvander@0
   407
BytecodeCompiler::visit(CallExpression *node)
dvander@0
   408
{
dvander@0
   409
    NameProxy *fun = node->callee()->toNameProxy();
dvander@0
   410
dvander@0
   411
    for (size_t i = 0; i < node->arguments()->size(); i++) {
dvander@0
   412
        Expression *arg = node->arguments()->at(i);
dvander@0
   413
        arg->accept(this);
dvander@0
   414
    }
dvander@0
   415
dvander@0
   416
    __ callglobal(node->arguments()->size(), 0);
dvander@0
   417
}
dvander@0
   418
dvander@0
   419
void
dvander@0
   420
BytecodeCompiler::visit(IfStatement *node)
dvander@0
   421
{
dvander@0
   422
    if (!node->ifFalse()) {
dvander@0
   423
        Label fail;
dvander@0
   424
        visitForTest(node->condition(), &fail, false);
dvander@0
   425
        node->ifTrue()->accept(this);
dvander@0
   426
        __ bind(&fail);
dvander@0
   427
    } else {
dvander@0
   428
        Label fail, join;
dvander@0
   429
        visitForTest(node->condition(), &fail, false);
dvander@0
   430
        node->ifTrue()->accept(this);
dvander@0
   431
        __ jump(&join);
dvander@0
   432
        __ bind(&fail);
dvander@0
   433
        node->ifFalse()->accept(this);
dvander@0
   434
        __ bind(&join);
dvander@0
   435
    }
dvander@0
   436
}
dvander@0
   437
dvander@0
   438
void
dvander@0
   439
BytecodeCompiler::visit(FunctionStatement *node)
dvander@0
   440
{
dvander@0
   441
    BytecodeCompiler child(tree_);
dvander@0
   442
    Code *code = child.compileFunction(module_, node);
dvander@0
   443
    
dvander@0
   444
    assert(!module_->getFunction(node->fun()->slot()));
dvander@0
   445
    module_->setFunction(node->fun()->slot(), code);
dvander@0
   446
}
dvander@0
   447
dvander@2
   448
void
dvander@2
   449
BytecodeCompiler::visit(EnumStatement *node)
dvander@2
   450
{
dvander@2
   451
    // :TODO: eventually, we'll export these.
dvander@2
   452
}
dvander@2
   453
dvander@0
   454
Code *
dvander@0
   455
BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
dvander@0
   456
{
dvander@12
   457
    // Note: No need to record a life slot here, since it's part of the Frame.
dvander@1
   458
    AutoEnterScope functionScope(this, node->scope());
dvander@1
   459
dvander@12
   460
    // :TODO: use locals
dvander@12
   461
    locals_ = FixedArray::New(ZONE(), node->scope()->maxContainedLocals(), Heap::Tenure_Old);
dvander@0
   462
dvander@0
   463
    node->body()->accept(this);
dvander@0
   464
dvander@0
   465
    __ stop();
dvander@0
   466
dvander@0
   467
    if (__ oom())
dvander@12
   468
        return NULL;
dvander@0
   469
dvander@12
   470
    ByteArray *bytes = ByteArray::New(ZONE(), __ length() * sizeof(bytecode), Heap::Tenure_Old);
dvander@12
   471
    if (!bytes)
dvander@12
   472
        return NULL;
dvander@12
   473
    memcpy(bytes->raw(), __ buffer(), __ length());
dvander@0
   474
dvander@0
   475
    unsigned nargs = node->scope()->numArguments();
dvander@12
   476
    FixedArray *args = FixedArray::New(ZONE(), nargs, Heap::Tenure_Old);
dvander@12
   477
    if (!args)
dvander@12
   478
        return NULL;
dvander@12
   479
dvander@0
   480
    for (size_t i = 0; i < node->scope()->numArguments(); i++)
dvander@12
   481
        args->set(ZONE(), i, node->scope()->getArgument(i)->type());
dvander@0
   482
dvander@0
   483
    for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
dvander@12
   484
        assert(locals_->at(i));
dvander@0
   485
dvander@12
   486
    FixedArray *maps = FixedArray::New(ZONE(), __ maps()->size(), Heap::Tenure_Old);
dvander@12
   487
    if (!maps)
dvander@12
   488
        return NULL;
dvander@0
   489
dvander@12
   490
    for (size_t i = 0; i < __ maps()->size(); i++)
dvander@12
   491
        maps->set(ZONE(), i, __ maps()->at(i));
dvander@12
   492
dvander@12
   493
    Code *code = Code::New(ZONE(), bytes, locals_, args, maps, __ maxStackDepth(), module_);
dvander@0
   494
    return code;
dvander@0
   495
}
dvander@0
   496
dvander@0
   497
Module *
dvander@0
   498
BytecodeCompiler::compile()
dvander@0
   499
{
dvander@0
   500
    Code **functions = new Code *[tree_->scope()->numFunctions()];
dvander@0
   501
    memset(functions, 0, sizeof(Code *) * tree_->scope()->numFunctions());
dvander@0
   502
dvander@0
   503
    module_ = new Module(functions, tree_->scope()->numFunctions());
dvander@0
   504
dvander@0
   505
    for (size_t i = 0; i < tree_->statements()->length(); i++) {
dvander@0
   506
        Statement *statement = tree_->statements()->at(i);
dvander@0
   507
        statement->accept(this);
dvander@0
   508
    }
dvander@0
   509
dvander@0
   510
#ifndef NDEBUG
dvander@0
   511
    for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
dvander@0
   512
        assert(functions[i]);
dvander@0
   513
#endif
dvander@0
   514
dvander@0
   515
    return module_;
dvander@0
   516
}