jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Mon Jun 25 02:57:28 2012 -0700 (2012-06-25)
changeset 0 c455ebb9a5dc
child 1 27f12e2fc369
permissions -rw-r--r--
Initial import of prototype.
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@0
    30
  : tree_(tree)
dvander@0
    31
{
dvander@0
    32
}
dvander@0
    33
dvander@0
    34
static inline TokenKind
dvander@0
    35
ToCompare(Expression *expr)
dvander@0
    36
{
dvander@0
    37
    if (expr->isBinaryExpression()) {
dvander@0
    38
        BinaryExpression *b = expr->toBinaryExpression();
dvander@0
    39
        if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
dvander@0
    40
            return b->token();
dvander@0
    41
    }
dvander@0
    42
    return TOK_EOF;
dvander@0
    43
}
dvander@0
    44
dvander@0
    45
static inline Opcode
dvander@0
    46
CompareTokenToJump(TokenKind kind)
dvander@0
    47
{
dvander@0
    48
    switch (kind) {
dvander@0
    49
      case TOK_EQUALS:
dvander@0
    50
        return OP_JEQ;
dvander@0
    51
      case TOK_NOTEQUALS:
dvander@0
    52
        return OP_JNE;
dvander@0
    53
      case TOK_GT:
dvander@0
    54
        return OP_JG;
dvander@0
    55
      case TOK_GE:
dvander@0
    56
        return OP_JGE;
dvander@0
    57
      case TOK_LT:
dvander@0
    58
        return OP_JL;
dvander@0
    59
      case TOK_LE:
dvander@0
    60
        return OP_JLE;
dvander@0
    61
    }
dvander@0
    62
    assert(false);
dvander@0
    63
    return OP_NOP;
dvander@0
    64
}
dvander@0
    65
dvander@0
    66
static inline Opcode
dvander@0
    67
TokenToOpcode(TokenKind kind)
dvander@0
    68
{
dvander@0
    69
    switch (kind) {
dvander@0
    70
      case TOK_PLUS:
dvander@0
    71
        return OP_ADD;
dvander@0
    72
      case TOK_MINUS:
dvander@0
    73
        return OP_SUB;
dvander@0
    74
      case TOK_STAR:
dvander@0
    75
        return OP_MUL;
dvander@0
    76
      case TOK_SLASH:
dvander@0
    77
        return OP_DIV;
dvander@0
    78
    }
dvander@0
    79
    assert(false);
dvander@0
    80
    return OP_NOP;
dvander@0
    81
}
dvander@0
    82
dvander@0
    83
void
dvander@0
    84
BytecodeCompiler::visit(NameProxy *name)
dvander@0
    85
{
dvander@0
    86
    Variable *var = name->binding()->toVariable();
dvander@0
    87
dvander@0
    88
    if (var->location() == Variable::STACK) {
dvander@0
    89
        __ getlocal(var->slot());
dvander@0
    90
    } else {
dvander@0
    91
        assert(var->location() == Variable::PARAMETER);
dvander@0
    92
        __ getarg(var->slot());
dvander@0
    93
    }
dvander@0
    94
}
dvander@0
    95
dvander@0
    96
void
dvander@0
    97
BytecodeCompiler::visit(ExpressionStatement *node)
dvander@0
    98
{
dvander@0
    99
    // Expressions leave their value on the top of the stack, so we make sure
dvander@0
   100
    // to balance the stack if they're used as a statement.
dvander@0
   101
    node->expression()->accept(this);
dvander@0
   102
    __ pop();
dvander@0
   103
}
dvander@0
   104
dvander@0
   105
void
dvander@0
   106
BytecodeCompiler::visit(Assignment *node)
dvander@0
   107
{
dvander@0
   108
    if (node->lvalue()->isNameProxy()) {
dvander@0
   109
        NameProxy *proxy = node->lvalue()->toNameProxy();
dvander@0
   110
        Variable *var = proxy->binding()->toVariable();
dvander@0
   111
dvander@0
   112
        node->expression()->accept(this);
dvander@0
   113
        if (var->location() == Variable::STACK) {
dvander@0
   114
            __ setlocal(var->slot());
dvander@0
   115
        } else {
dvander@0
   116
            assert(var->location() == Variable::PARAMETER);
dvander@0
   117
            __ setarg(var->slot());
dvander@0
   118
        }
dvander@0
   119
    } else if (node->lvalue()->isIndexExpression()) {
dvander@0
   120
        IndexExpression *index = node->lvalue()->toIndexExpression();
dvander@0
   121
dvander@0
   122
        index->left()->accept(this);
dvander@0
   123
        index->right()->accept(this);
dvander@0
   124
        __ bounds_sta();
dvander@0
   125
        node->expression()->accept(this);
dvander@0
   126
        __ st_sta_i();
dvander@0
   127
    }
dvander@0
   128
}
dvander@0
   129
dvander@0
   130
void
dvander@0
   131
BytecodeCompiler::visit(BinaryExpression *node)
dvander@0
   132
{
dvander@0
   133
    node->left()->accept(this);
dvander@0
   134
    node->right()->accept(this);
dvander@0
   135
dvander@0
   136
    Opcode op = TokenToOpcode(node->token());
dvander@0
   137
    __ binary(op);
dvander@0
   138
}
dvander@0
   139
dvander@0
   140
void
dvander@0
   141
BytecodeCompiler::visit(IndexExpression *node)
dvander@0
   142
{
dvander@0
   143
    node->left()->accept(this);
dvander@0
   144
    node->right()->accept(this);
dvander@0
   145
    __ bounds_sta();
dvander@0
   146
dvander@0
   147
    if (node->type()->isArray())
dvander@0
   148
        __ ld_sta_p();
dvander@0
   149
    else
dvander@0
   150
        __ ld_sta_i();
dvander@0
   151
}
dvander@0
   152
dvander@0
   153
void
dvander@0
   154
BytecodeCompiler::visit(ReturnStatement *node)
dvander@0
   155
{
dvander@0
   156
    if (node->expression())
dvander@0
   157
        node->expression()->accept(this);
dvander@0
   158
    else
dvander@0
   159
        __ int_(0);
dvander@0
   160
dvander@0
   161
    __ return_();
dvander@0
   162
}
dvander@0
   163
dvander@0
   164
void
dvander@0
   165
BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
dvander@0
   166
{
dvander@0
   167
    TokenKind token = ToCompare(expression);
dvander@0
   168
    if (token == TOK_EOF) {
dvander@0
   169
        expression->accept(this);
dvander@0
   170
        if (onTrue)
dvander@0
   171
            __ j(OP_JT, label);
dvander@0
   172
        else
dvander@0
   173
            __ j(OP_JF, label);
dvander@0
   174
        return;
dvander@0
   175
    }
dvander@0
   176
dvander@0
   177
    Opcode op = CompareTokenToJump(token);
dvander@0
   178
    if (!onTrue)
dvander@0
   179
        op = Invert(op);
dvander@0
   180
dvander@0
   181
    assert(expression->isBinaryExpression());
dvander@0
   182
    BinaryExpression *binary = expression->toBinaryExpression();
dvander@0
   183
    binary->left()->accept(this);
dvander@0
   184
    binary->right()->accept(this);
dvander@0
   185
    __ j(op, label);
dvander@0
   186
}
dvander@0
   187
dvander@0
   188
void
dvander@0
   189
BytecodeCompiler::visit(ForStatement *node)
dvander@0
   190
{
dvander@0
   191
    if (node->declaration())
dvander@0
   192
        node->declaration()->accept(this);
dvander@0
   193
dvander@0
   194
    Label header, test;
dvander@0
   195
    if (node->condition())
dvander@0
   196
        __ jump(&test);
dvander@0
   197
dvander@0
   198
    __ bind(&header);
dvander@0
   199
    node->body()->accept(this);
dvander@0
   200
dvander@0
   201
    if (node->update())
dvander@0
   202
        node->update()->accept(this);
dvander@0
   203
dvander@0
   204
    if (node->condition()) {
dvander@0
   205
        __ bind(&test);
dvander@0
   206
        visitForTest(node->condition(), &header, true);
dvander@0
   207
    } else {
dvander@0
   208
        __ jump(&header);
dvander@0
   209
    }
dvander@0
   210
dvander@0
   211
    assert(__ stackDepth() == 0);
dvander@0
   212
}
dvander@0
   213
dvander@0
   214
void
dvander@0
   215
BytecodeCompiler::visit(BlockStatement *node)
dvander@0
   216
{
dvander@0
   217
    for (size_t i = 0; i < node->statements()->length(); i++) {
dvander@0
   218
        Statement *statement = node->statements()->at(i);
dvander@0
   219
        statement->accept(this);
dvander@0
   220
        assert(__ stackDepth() == 0);
dvander@0
   221
    }
dvander@0
   222
}
dvander@0
   223
dvander@0
   224
void
dvander@0
   225
BytecodeCompiler::visit(IntegerLiteralExpression *node)
dvander@0
   226
{
dvander@0
   227
    __ int_(node->value());
dvander@0
   228
}
dvander@0
   229
dvander@0
   230
void
dvander@0
   231
BytecodeCompiler::visit(VariableDeclaration *node)
dvander@0
   232
{
dvander@0
   233
    Variable *var = node->variable();
dvander@0
   234
    assert(var->location() == Variable::STACK);
dvander@0
   235
    
dvander@0
   236
    Type *type = var->type();
dvander@0
   237
    if (type->isArray()) {
dvander@0
   238
        bool isConstant = true;
dvander@0
   239
        for (Type *child = type; child->isArray(); child = child->contained()) {
dvander@0
   240
            if (child->elements() == Type::UNKNOWN_SIZE) {
dvander@0
   241
                isConstant = false;
dvander@0
   242
                break;
dvander@0
   243
            }
dvander@0
   244
        }
dvander@0
   245
dvander@0
   246
        if (!isConstant) {
dvander@0
   247
            for (size_t i = 0; i < node->postDimensions()->size(); i++) {
dvander@0
   248
                Expression *expr = node->postDimensions()->at(i);
dvander@0
   249
                expr->accept(this);
dvander@0
   250
            }
dvander@0
   251
        }
dvander@0
   252
dvander@0
   253
        __ stackarray(type);
dvander@0
   254
    } else {
dvander@0
   255
        if (node->initialization()) {
dvander@0
   256
            node->initialization()->accept(this);
dvander@0
   257
        } else {
dvander@0
   258
            if (!node->postDimensions())
dvander@0
   259
                __ int_(0);
dvander@0
   260
        }
dvander@0
   261
    }
dvander@0
   262
    __ setlocal(var->slot());
dvander@0
   263
    __ pop();
dvander@0
   264
dvander@0
   265
    locals_[var->slot()] = var->type();
dvander@0
   266
}
dvander@0
   267
dvander@0
   268
void
dvander@0
   269
BytecodeCompiler::visit(CallExpression *node)
dvander@0
   270
{
dvander@0
   271
    NameProxy *fun = node->callee()->toNameProxy();
dvander@0
   272
dvander@0
   273
    for (size_t i = 0; i < node->arguments()->size(); i++) {
dvander@0
   274
        Expression *arg = node->arguments()->at(i);
dvander@0
   275
        arg->accept(this);
dvander@0
   276
    }
dvander@0
   277
dvander@0
   278
    __ callglobal(node->arguments()->size(), 0);
dvander@0
   279
}
dvander@0
   280
dvander@0
   281
void
dvander@0
   282
BytecodeCompiler::visit(IfStatement *node)
dvander@0
   283
{
dvander@0
   284
    if (!node->ifFalse()) {
dvander@0
   285
        Label fail;
dvander@0
   286
        visitForTest(node->condition(), &fail, false);
dvander@0
   287
        node->ifTrue()->accept(this);
dvander@0
   288
        __ bind(&fail);
dvander@0
   289
    } else {
dvander@0
   290
        Label fail, join;
dvander@0
   291
        visitForTest(node->condition(), &fail, false);
dvander@0
   292
        node->ifTrue()->accept(this);
dvander@0
   293
        __ jump(&join);
dvander@0
   294
        __ bind(&fail);
dvander@0
   295
        node->ifFalse()->accept(this);
dvander@0
   296
        __ bind(&join);
dvander@0
   297
    }
dvander@0
   298
}
dvander@0
   299
dvander@0
   300
void
dvander@0
   301
BytecodeCompiler::visit(FunctionStatement *node)
dvander@0
   302
{
dvander@0
   303
    BytecodeCompiler child(tree_);
dvander@0
   304
    Code *code = child.compileFunction(module_, node);
dvander@0
   305
    
dvander@0
   306
    assert(!module_->getFunction(node->fun()->slot()));
dvander@0
   307
    module_->setFunction(node->fun()->slot(), code);
dvander@0
   308
}
dvander@0
   309
dvander@0
   310
Code *
dvander@0
   311
BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
dvander@0
   312
{
dvander@0
   313
    locals_ = new Type *[node->scope()->maxContainedLocals()];
dvander@0
   314
    memset(locals_, 0, sizeof(Type *) * node->scope()->maxContainedLocals());
dvander@0
   315
dvander@0
   316
    node->body()->accept(this);
dvander@0
   317
dvander@0
   318
    __ stop();
dvander@0
   319
dvander@0
   320
    if (__ oom())
dvander@0
   321
        return false;
dvander@0
   322
dvander@0
   323
    bytecode *start = (bytecode *)malloc(__ length() * sizeof(bytecode));
dvander@0
   324
    memcpy(start, __ buffer(), __ length());
dvander@0
   325
dvander@0
   326
    unsigned nargs = node->scope()->numArguments();
dvander@0
   327
    Type **args = new Type *[nargs];
dvander@0
   328
    for (size_t i = 0; i < node->scope()->numArguments(); i++)
dvander@0
   329
        args[i] = node->scope()->getArgument(i)->type();
dvander@0
   330
dvander@0
   331
    for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
dvander@0
   332
        assert(locals_[i]);
dvander@0
   333
dvander@0
   334
    Code *code = new Code(module,
dvander@0
   335
                          start,
dvander@0
   336
                          __ length(),
dvander@0
   337
                          args,
dvander@0
   338
                          nargs,
dvander@0
   339
                          locals_,
dvander@0
   340
                          node->scope()->maxContainedLocals(),
dvander@0
   341
                          __ maxStackDepth());
dvander@0
   342
dvander@0
   343
    return code;
dvander@0
   344
}
dvander@0
   345
dvander@0
   346
Module *
dvander@0
   347
BytecodeCompiler::compile()
dvander@0
   348
{
dvander@0
   349
    Code **functions = new Code *[tree_->scope()->numFunctions()];
dvander@0
   350
    memset(functions, 0, sizeof(Code *) * tree_->scope()->numFunctions());
dvander@0
   351
dvander@0
   352
    module_ = new Module(functions, tree_->scope()->numFunctions());
dvander@0
   353
dvander@0
   354
    for (size_t i = 0; i < tree_->statements()->length(); i++) {
dvander@0
   355
        Statement *statement = tree_->statements()->at(i);
dvander@0
   356
        statement->accept(this);
dvander@0
   357
    }
dvander@0
   358
dvander@0
   359
#ifndef NDEBUG
dvander@0
   360
    for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
dvander@0
   361
        assert(functions[i]);
dvander@0
   362
#endif
dvander@0
   363
dvander@0
   364
    return module_;
dvander@0
   365
}