jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jun 27 22:02:40 2012 -0700 (2012-06-27)
changeset 7 0478c27ba82c
parent 6 172dd7799d0a
child 8 069d207a8f2a
permissions -rw-r--r--
Added support for arrays of Floats.
     1 /*
     2  * Copyright (C) 2012 David Anderson
     3  *
     4  * This file is part of JITCraft.
     5  *
     6  * JITCraft is free software: you can redistribute it and/or modify it under
     7  * the terms of the GNU General Public License as published by the Free
     8  * Software Foundation, either version 3 of the License, or (at your option)
     9  * any later version.
    10  * 
    11  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    13  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along with
    16  * JITCraft. If not, see http://www.gnu.org/licenses/.
    17  */
    18 #include "BytecodeCompiler.h"
    19 #include "Scopes.h"
    20 #include "Modules.h"
    21 #include "Types.h"
    22 
    23 using namespace jc;
    24 
    25 typedef BytecodeEmitter::Label Label;
    26 
    27 #define __ emitter_.
    28 
    29 BytecodeCompiler::BytecodeCompiler(ParseTree *tree)
    30   : tree_(tree),
    31     scope_(NULL)
    32 {
    33 }
    34 
    35 static inline TokenKind
    36 ToCompare(Expression *expr)
    37 {
    38     if (expr->isBinaryExpression()) {
    39         BinaryExpression *b = expr->toBinaryExpression();
    40         if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
    41             return b->token();
    42     }
    43     return TOK_EOF;
    44 }
    45 
    46 static inline Opcode
    47 CompareTokenToJump(TokenKind kind)
    48 {
    49     switch (kind) {
    50       case TOK_EQUALS:
    51         return OP_JEQ;
    52       case TOK_NOTEQUALS:
    53         return OP_JNE;
    54       case TOK_GT:
    55         return OP_JG;
    56       case TOK_GE:
    57         return OP_JGE;
    58       case TOK_LT:
    59         return OP_JL;
    60       case TOK_LE:
    61         return OP_JLE;
    62     }
    63     assert(false);
    64     return OP_NOP;
    65 }
    66 
    67 static inline Opcode
    68 TokenToOpcode(TokenKind kind)
    69 {
    70     switch (kind) {
    71       case TOK_PLUS:
    72         return OP_ADD;
    73       case TOK_MINUS:
    74         return OP_SUB;
    75       case TOK_STAR:
    76         return OP_MUL;
    77       case TOK_SLASH:
    78         return OP_DIV;
    79     }
    80     assert(false);
    81     return OP_NOP;
    82 }
    83 
    84 void
    85 BytecodeCompiler::leaveScope(Scope *scope)
    86 {
    87     if (!scope)
    88         return;
    89 
    90     if (Variable *var = scope->firstUnsafeArray())
    91         __ unwind(var->slot());
    92 }
    93 
    94 void
    95 BytecodeCompiler::visit(NameProxy *name)
    96 {
    97     switch (name->binding()->kind()) {
    98       case BoundName::VARIABLE:
    99       {
   100         Variable *var = name->binding()->toVariable();
   101 
   102         if (var->location() == Variable::STACK) {
   103             __ getlocal(var->slot());
   104         } else {
   105             assert(var->location() == Variable::PARAMETER);
   106             __ getarg(var->slot());
   107         }
   108         break;
   109       }
   110 
   111       default:
   112       {
   113         NamedConstant *constant = name->binding()->toNamedConstant();
   114         __ int_(constant->value().toInt());
   115         break;
   116       }
   117     }
   118 }
   119 
   120 void
   121 BytecodeCompiler::visit(ExpressionStatement *node)
   122 {
   123     // Expressions leave their value on the top of the stack, so we make sure
   124     // to balance the stack if they're used as a statement.
   125     node->expression()->accept(this);
   126     __ pop();
   127 }
   128 
   129 void
   130 BytecodeCompiler::visit(Assignment *node)
   131 {
   132     if (node->lvalue()->isNameProxy()) {
   133         NameProxy *proxy = node->lvalue()->toNameProxy();
   134         Variable *var = proxy->binding()->toVariable();
   135 
   136         node->expression()->accept(this);
   137         if (var->location() == Variable::STACK) {
   138             __ setlocal(var->slot());
   139         } else {
   140             assert(var->location() == Variable::PARAMETER);
   141             __ setarg(var->slot());
   142         }
   143     } else if (node->lvalue()->isIndexExpression()) {
   144         IndexExpression *index = node->lvalue()->toIndexExpression();
   145 
   146         index->left()->accept(this);
   147         index->right()->accept(this);
   148         __ bounds_sta();
   149         node->expression()->accept(this);
   150         if (index->left()->type()->contained()->isFloat()) {
   151             __ setarray_f();
   152         } else {
   153             assert(index->left()->type()->contained()->isInt());
   154             __ setarray_i();
   155         }
   156     }
   157 }
   158 
   159 void
   160 BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   161 {
   162     node->accept(this);
   163     if (needed->isFloat() && !node->type()->isFloat())
   164         __ cvt_i2f();
   165 }
   166 
   167 void
   168 BytecodeCompiler::visit(BinaryExpression *node)
   169 {
   170     visitForALU(node->type(), node->left());
   171     visitForALU(node->type(), node->right());
   172 
   173     Opcode op = TokenToOpcode(node->token());
   174     if (node->type()->isFloat())
   175         op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   176     __ binary(op);
   177 }
   178 
   179 void
   180 BytecodeCompiler::visit(IndexExpression *node)
   181 {
   182     node->left()->accept(this);
   183     node->right()->accept(this);
   184     __ bounds_sta();
   185 
   186     if (node->type()->isArray()) {
   187         __ getarray_p();
   188     } else if (node->type()->isFloat()) {
   189         __ getarray_f();
   190     } else {
   191         __ getarray_i();
   192         assert(node->type()->isInt());
   193     }
   194 }
   195 
   196 void
   197 BytecodeCompiler::visit(ReturnStatement *node)
   198 {
   199     if (node->expression())
   200         node->expression()->accept(this);
   201     else
   202         __ int_(0);
   203 
   204     __ return_();
   205 }
   206 
   207 void
   208 BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
   209 {
   210     TokenKind token = ToCompare(expression);
   211     if (token == TOK_EOF) {
   212         expression->accept(this);
   213         if (onTrue)
   214             __ j(OP_JT, label);
   215         else
   216             __ j(OP_JF, label);
   217         return;
   218     }
   219 
   220     Opcode op = CompareTokenToJump(token);
   221     if (!onTrue)
   222         op = Invert(op);
   223 
   224     assert(expression->isBinaryExpression());
   225     BinaryExpression *binary = expression->toBinaryExpression();
   226     binary->left()->accept(this);
   227     binary->right()->accept(this);
   228     __ j(op, label);
   229 }
   230 
   231 void
   232 BytecodeCompiler::visit(ForStatement *node)
   233 {
   234     AutoEnterScope forScope(this, node->scope());
   235 
   236     if (node->declaration())
   237         node->declaration()->accept(this);
   238 
   239     Label header, test;
   240     if (node->condition())
   241         __ jump(&test);
   242 
   243     __ bind(&header);
   244     node->body()->accept(this);
   245 
   246     if (node->update())
   247         node->update()->accept(this);
   248 
   249     if (node->condition()) {
   250         __ bind(&test);
   251         visitForTest(node->condition(), &header, true);
   252     } else {
   253         __ jump(&header);
   254     }
   255 
   256     leaveScope(node->scope());
   257     assert(__ stackDepth() == 0);
   258 }
   259 
   260 void
   261 BytecodeCompiler::visit(BlockStatement *node)
   262 {
   263     AutoEnterScope blockScope(this, node->scope());
   264 
   265     for (size_t i = 0; i < node->statements()->length(); i++) {
   266         Statement *statement = node->statements()->at(i);
   267         statement->accept(this);
   268         assert(__ stackDepth() == 0);
   269     }
   270 
   271     // We don't bother emitting an "unwind" instruction for function scopes,
   272     // since this is taken care of by the calling convention.
   273     if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   274         leaveScope(node->scope());
   275 }
   276 
   277 void
   278 BytecodeCompiler::visit(IntegerLiteral *node)
   279 {
   280     __ int_(node->value());
   281 }
   282 
   283 void
   284 BytecodeCompiler::visit(FloatLiteral *node)
   285 {
   286     __ float_((float)node->value());
   287 }
   288 
   289 void
   290 BytecodeCompiler::visit(VariableDeclaration *node)
   291 {
   292     Variable *var = node->variable();
   293     assert(var->location() == Variable::STACK);
   294     
   295     Type *type = var->type();
   296     if (type->isArray()) {
   297         bool isConstant = true;
   298         for (Type *child = type; child->isArray(); child = child->contained()) {
   299             if (child->elements() == Type::UNKNOWN_SIZE) {
   300                 isConstant = false;
   301                 break;
   302             }
   303         }
   304 
   305         if (!isConstant) {
   306             for (size_t i = 0; i < node->postDimensions()->size(); i++) {
   307                 Expression *expr = node->postDimensions()->at(i);
   308                 expr->accept(this);
   309             }
   310         }
   311 
   312         __ stackarray(type);
   313     } else {
   314         if (node->initialization()) {
   315             node->initialization()->accept(this);
   316         } else {
   317             if (!node->postDimensions())
   318                 __ int_(0);
   319         }
   320     }
   321     __ setlocal(var->slot());
   322     __ pop();
   323 
   324     locals_[var->slot()] = var->type();
   325 }
   326 
   327 void
   328 BytecodeCompiler::visit(CallExpression *node)
   329 {
   330     NameProxy *fun = node->callee()->toNameProxy();
   331 
   332     for (size_t i = 0; i < node->arguments()->size(); i++) {
   333         Expression *arg = node->arguments()->at(i);
   334         arg->accept(this);
   335     }
   336 
   337     __ callglobal(node->arguments()->size(), 0);
   338 }
   339 
   340 void
   341 BytecodeCompiler::visit(IfStatement *node)
   342 {
   343     if (!node->ifFalse()) {
   344         Label fail;
   345         visitForTest(node->condition(), &fail, false);
   346         node->ifTrue()->accept(this);
   347         __ bind(&fail);
   348     } else {
   349         Label fail, join;
   350         visitForTest(node->condition(), &fail, false);
   351         node->ifTrue()->accept(this);
   352         __ jump(&join);
   353         __ bind(&fail);
   354         node->ifFalse()->accept(this);
   355         __ bind(&join);
   356     }
   357 }
   358 
   359 void
   360 BytecodeCompiler::visit(FunctionStatement *node)
   361 {
   362     BytecodeCompiler child(tree_);
   363     Code *code = child.compileFunction(module_, node);
   364     
   365     assert(!module_->getFunction(node->fun()->slot()));
   366     module_->setFunction(node->fun()->slot(), code);
   367 }
   368 
   369 void
   370 BytecodeCompiler::visit(EnumStatement *node)
   371 {
   372     // :TODO: eventually, we'll export these.
   373 }
   374 
   375 Code *
   376 BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
   377 {
   378     AutoEnterScope functionScope(this, node->scope());
   379 
   380     locals_ = new Type *[node->scope()->maxContainedLocals()];
   381     memset(locals_, 0, sizeof(Type *) * node->scope()->maxContainedLocals());
   382 
   383     node->body()->accept(this);
   384 
   385     __ stop();
   386 
   387     if (__ oom())
   388         return false;
   389 
   390     bytecode *start = (bytecode *)malloc(__ length() * sizeof(bytecode));
   391     memcpy(start, __ buffer(), __ length());
   392 
   393     unsigned nargs = node->scope()->numArguments();
   394     Type **args = new Type *[nargs];
   395     for (size_t i = 0; i < node->scope()->numArguments(); i++)
   396         args[i] = node->scope()->getArgument(i)->type();
   397 
   398     for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
   399         assert(locals_[i]);
   400 
   401     Code *code = new Code(module,
   402                           start,
   403                           __ length(),
   404                           args,
   405                           nargs,
   406                           locals_,
   407                           node->scope()->maxContainedLocals(),
   408                           __ maxStackDepth());
   409 
   410     return code;
   411 }
   412 
   413 Module *
   414 BytecodeCompiler::compile()
   415 {
   416     Code **functions = new Code *[tree_->scope()->numFunctions()];
   417     memset(functions, 0, sizeof(Code *) * tree_->scope()->numFunctions());
   418 
   419     module_ = new Module(functions, tree_->scope()->numFunctions());
   420 
   421     for (size_t i = 0; i < tree_->statements()->length(); i++) {
   422         Statement *statement = tree_->statements()->at(i);
   423         statement->accept(this);
   424     }
   425 
   426 #ifndef NDEBUG
   427     for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
   428         assert(functions[i]);
   429 #endif
   430 
   431     return module_;
   432 }