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