jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jun 27 02:21:56 2012 -0700 (2012-06-27)
changeset 4 633176823669
parent 2 46fc53b8fd2f
child 6 172dd7799d0a
permissions -rw-r--r--
Add support for float variables and basic math.
     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         __ st_sta_i();
   151     }
   152 }
   153 
   154 void
   155 BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   156 {
   157     node->accept(this);
   158     if (needed->isFloat() && !node->type()->isFloat())
   159         __ cvt_i2f();
   160 }
   161 
   162 void
   163 BytecodeCompiler::visit(BinaryExpression *node)
   164 {
   165     visitForALU(node->type(), node->left());
   166     visitForALU(node->type(), node->right());
   167 
   168     Opcode op = TokenToOpcode(node->token());
   169     if (node->type()->isFloat())
   170         op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   171     __ binary(op);
   172 }
   173 
   174 void
   175 BytecodeCompiler::visit(IndexExpression *node)
   176 {
   177     node->left()->accept(this);
   178     node->right()->accept(this);
   179     __ bounds_sta();
   180 
   181     if (node->type()->isArray())
   182         __ ld_sta_p();
   183     else
   184         __ ld_sta_i();
   185 }
   186 
   187 void
   188 BytecodeCompiler::visit(ReturnStatement *node)
   189 {
   190     if (node->expression())
   191         node->expression()->accept(this);
   192     else
   193         __ int_(0);
   194 
   195     __ return_();
   196 }
   197 
   198 void
   199 BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
   200 {
   201     TokenKind token = ToCompare(expression);
   202     if (token == TOK_EOF) {
   203         expression->accept(this);
   204         if (onTrue)
   205             __ j(OP_JT, label);
   206         else
   207             __ j(OP_JF, label);
   208         return;
   209     }
   210 
   211     Opcode op = CompareTokenToJump(token);
   212     if (!onTrue)
   213         op = Invert(op);
   214 
   215     assert(expression->isBinaryExpression());
   216     BinaryExpression *binary = expression->toBinaryExpression();
   217     binary->left()->accept(this);
   218     binary->right()->accept(this);
   219     __ j(op, label);
   220 }
   221 
   222 void
   223 BytecodeCompiler::visit(ForStatement *node)
   224 {
   225     AutoEnterScope forScope(this, node->scope());
   226 
   227     if (node->declaration())
   228         node->declaration()->accept(this);
   229 
   230     Label header, test;
   231     if (node->condition())
   232         __ jump(&test);
   233 
   234     __ bind(&header);
   235     node->body()->accept(this);
   236 
   237     if (node->update())
   238         node->update()->accept(this);
   239 
   240     if (node->condition()) {
   241         __ bind(&test);
   242         visitForTest(node->condition(), &header, true);
   243     } else {
   244         __ jump(&header);
   245     }
   246 
   247     leaveScope(node->scope());
   248     assert(__ stackDepth() == 0);
   249 }
   250 
   251 void
   252 BytecodeCompiler::visit(BlockStatement *node)
   253 {
   254     AutoEnterScope blockScope(this, node->scope());
   255 
   256     for (size_t i = 0; i < node->statements()->length(); i++) {
   257         Statement *statement = node->statements()->at(i);
   258         statement->accept(this);
   259         assert(__ stackDepth() == 0);
   260     }
   261 
   262     // We don't bother emitting an "unwind" instruction for function scopes,
   263     // since this is taken care of by the calling convention.
   264     if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   265         leaveScope(node->scope());
   266 }
   267 
   268 void
   269 BytecodeCompiler::visit(IntegerLiteral *node)
   270 {
   271     __ int_(node->value());
   272 }
   273 
   274 void
   275 BytecodeCompiler::visit(FloatLiteral *node)
   276 {
   277     __ float_((float)node->value());
   278 }
   279 
   280 void
   281 BytecodeCompiler::visit(VariableDeclaration *node)
   282 {
   283     Variable *var = node->variable();
   284     assert(var->location() == Variable::STACK);
   285     
   286     Type *type = var->type();
   287     if (type->isArray()) {
   288         bool isConstant = true;
   289         for (Type *child = type; child->isArray(); child = child->contained()) {
   290             if (child->elements() == Type::UNKNOWN_SIZE) {
   291                 isConstant = false;
   292                 break;
   293             }
   294         }
   295 
   296         if (!isConstant) {
   297             for (size_t i = 0; i < node->postDimensions()->size(); i++) {
   298                 Expression *expr = node->postDimensions()->at(i);
   299                 expr->accept(this);
   300             }
   301         }
   302 
   303         __ stackarray(type);
   304     } else {
   305         if (node->initialization()) {
   306             node->initialization()->accept(this);
   307         } else {
   308             if (!node->postDimensions())
   309                 __ int_(0);
   310         }
   311     }
   312     __ setlocal(var->slot());
   313     __ pop();
   314 
   315     locals_[var->slot()] = var->type();
   316 }
   317 
   318 void
   319 BytecodeCompiler::visit(CallExpression *node)
   320 {
   321     NameProxy *fun = node->callee()->toNameProxy();
   322 
   323     for (size_t i = 0; i < node->arguments()->size(); i++) {
   324         Expression *arg = node->arguments()->at(i);
   325         arg->accept(this);
   326     }
   327 
   328     __ callglobal(node->arguments()->size(), 0);
   329 }
   330 
   331 void
   332 BytecodeCompiler::visit(IfStatement *node)
   333 {
   334     if (!node->ifFalse()) {
   335         Label fail;
   336         visitForTest(node->condition(), &fail, false);
   337         node->ifTrue()->accept(this);
   338         __ bind(&fail);
   339     } else {
   340         Label fail, join;
   341         visitForTest(node->condition(), &fail, false);
   342         node->ifTrue()->accept(this);
   343         __ jump(&join);
   344         __ bind(&fail);
   345         node->ifFalse()->accept(this);
   346         __ bind(&join);
   347     }
   348 }
   349 
   350 void
   351 BytecodeCompiler::visit(FunctionStatement *node)
   352 {
   353     BytecodeCompiler child(tree_);
   354     Code *code = child.compileFunction(module_, node);
   355     
   356     assert(!module_->getFunction(node->fun()->slot()));
   357     module_->setFunction(node->fun()->slot(), code);
   358 }
   359 
   360 void
   361 BytecodeCompiler::visit(EnumStatement *node)
   362 {
   363     // :TODO: eventually, we'll export these.
   364 }
   365 
   366 Code *
   367 BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
   368 {
   369     AutoEnterScope functionScope(this, node->scope());
   370 
   371     locals_ = new Type *[node->scope()->maxContainedLocals()];
   372     memset(locals_, 0, sizeof(Type *) * node->scope()->maxContainedLocals());
   373 
   374     node->body()->accept(this);
   375 
   376     __ stop();
   377 
   378     if (__ oom())
   379         return false;
   380 
   381     bytecode *start = (bytecode *)malloc(__ length() * sizeof(bytecode));
   382     memcpy(start, __ buffer(), __ length());
   383 
   384     unsigned nargs = node->scope()->numArguments();
   385     Type **args = new Type *[nargs];
   386     for (size_t i = 0; i < node->scope()->numArguments(); i++)
   387         args[i] = node->scope()->getArgument(i)->type();
   388 
   389     for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
   390         assert(locals_[i]);
   391 
   392     Code *code = new Code(module,
   393                           start,
   394                           __ length(),
   395                           args,
   396                           nargs,
   397                           locals_,
   398                           node->scope()->maxContainedLocals(),
   399                           __ maxStackDepth());
   400 
   401     return code;
   402 }
   403 
   404 Module *
   405 BytecodeCompiler::compile()
   406 {
   407     Code **functions = new Code *[tree_->scope()->numFunctions()];
   408     memset(functions, 0, sizeof(Code *) * tree_->scope()->numFunctions());
   409 
   410     module_ = new Module(functions, tree_->scope()->numFunctions());
   411 
   412     for (size_t i = 0; i < tree_->statements()->length(); i++) {
   413         Statement *statement = tree_->statements()->at(i);
   414         statement->accept(this);
   415     }
   416 
   417 #ifndef NDEBUG
   418     for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
   419         assert(functions[i]);
   420 #endif
   421 
   422     return module_;
   423 }