jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 01 14:52:57 2012 -0700 (2012-07-01)
changeset 21 af5d8e985502
parent 20 e020a14e21be
child 22 765ab1b672a3
permissions -rw-r--r--
Added initial String: support.
     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 #include "Array.h"
    23 #include "Zone.h"
    24 #include "Heap-inl.h"
    25 
    26 using namespace jc;
    27 
    28 typedef BytecodeEmitter::Label Label;
    29 
    30 #define __ emitter_.
    31 
    32 BytecodeCompiler::BytecodeCompiler(ParseTree *tree, Module *module)
    33   : tree_(tree),
    34     scope_(NULL),
    35     loop_(NULL),
    36     module_(module)
    37 {
    38 }
    39 
    40 static inline TokenKind
    41 ToCompare(Expression *expr)
    42 {
    43     if (expr->isBinaryExpression()) {
    44         BinaryExpression *b = expr->toBinaryExpression();
    45         if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
    46             return b->token();
    47     }
    48     return TOK_EOF;
    49 }
    50 
    51 static inline Opcode
    52 CompareTokenToJump(TokenKind kind)
    53 {
    54     switch (kind) {
    55       case TOK_EQUALS:
    56         return OP_JEQ;
    57       case TOK_NOTEQUALS:
    58         return OP_JNE;
    59       case TOK_GT:
    60         return OP_JG;
    61       case TOK_GE:
    62         return OP_JGE;
    63       case TOK_LT:
    64         return OP_JL;
    65       case TOK_LE:
    66         return OP_JLE;
    67     }
    68     assert(false);
    69     return OP_NOP;
    70 }
    71 
    72 static inline Opcode
    73 TokenToOpcode(TokenKind kind)
    74 {
    75     switch (kind) {
    76       case TOK_PLUS:
    77         return OP_ADD;
    78       case TOK_MINUS:
    79         return OP_SUB;
    80       case TOK_STAR:
    81         return OP_MUL;
    82       case TOK_SLASH:
    83         return OP_DIV;
    84       case TOK_SHR:
    85         return OP_SHR;
    86       case TOK_USHR:
    87         return OP_USHR;
    88       case TOK_SHL:
    89         return OP_SHL;
    90       case TOK_BITAND:
    91         return OP_BITAND;
    92       case TOK_BITOR:
    93         return OP_BITOR;
    94       case TOK_BITXOR:
    95         return OP_BITXOR;
    96     }
    97     assert(false);
    98     return OP_NOP;
    99 }
   100 
   101 void
   102 BytecodeCompiler::recordLifoSlot(Scope *scope)
   103 {
   104     if (!scope)
   105         return;
   106 
   107     if (Variable *var = scope->lifoSlot()) {
   108         locals_->set(ZONE(), var->slot(), var->type());
   109         __ savelifo(var->slot());
   110     }
   111 }
   112 
   113 void
   114 BytecodeCompiler::unwindTo(Scope *scope)
   115 {
   116     // Note: we only need to unwind to the outermost scope's LIFO slot.
   117     Variable *var = NULL;
   118     for (Scope *current = scope_; current != scope; current = current->enclosing()) {
   119         if (Variable *slot = current->lifoSlot())
   120             var = slot;
   121     }
   122 
   123     if (var)
   124         __ unwindlifo(var->slot());
   125 }
   126 
   127 void
   128 BytecodeCompiler::visit(NameProxy *name)
   129 {
   130     switch (name->binding()->kind()) {
   131       case BoundName::VARIABLE:
   132       {
   133         Variable *var = name->binding()->toVariable();
   134 
   135         if (var->location() == Variable::STACK) {
   136             __ getlocal(var->slot());
   137             assert(!name->type()->isReference());
   138         } else {
   139             assert(var->location() == Variable::PARAMETER);
   140             __ getarg(var->slot());
   141 
   142             // If this argument is actually a reference, dereference it now.
   143             if (var->type()->isReference()) {
   144                 if (var->type()->contained()->isFloat()) {
   145                     __ getref_f();
   146                 } else {
   147                     assert(var->type()->contained()->isInt32());
   148                     __ getref_i();
   149                 }
   150             }
   151         }
   152         break;
   153       }
   154 
   155       default:
   156       {
   157         NamedConstant *constant = name->binding()->toNamedConstant();
   158         __ int_(constant->value().toInt());
   159         break;
   160       }
   161     }
   162 }
   163 
   164 void
   165 BytecodeCompiler::visit(ExpressionStatement *node)
   166 {
   167     // Expressions leave their value on the top of the stack, so we make sure
   168     // to balance the stack if they're used as a statement.
   169     node->expression()->accept(this);
   170     __ pop();
   171 }
   172 
   173 void
   174 BytecodeCompiler::visit(Assignment *node)
   175 {
   176     // First compute the left-hand side.
   177     if (node->lvalue()->isNameProxy()) {
   178         NameProxy *proxy = node->lvalue()->toNameProxy();
   179         Variable *var = proxy->binding()->toVariable();
   180 
   181         // Make sure to bind the left-hand side first.
   182         if (var->type()->isReference() || var->type()->isArray())
   183             __ get(var);
   184 
   185         node->expression()->accept(this);
   186     } else if (node->lvalue()->isIndexExpression()) {
   187         IndexExpression *index = node->lvalue()->toIndexExpression();
   188 
   189         // Note: Eventually, watch out for a whole here. An expression like:
   190         //
   191         //   (a[4] = (5, a = []))
   192         //
   193         // Could shrink array, so we need to either bind a[i] to a Reference,
   194         // or keep the bounds check near the set. This is just a semantic
   195         // decision.
   196         index->left()->accept(this);
   197         index->right()->accept(this);
   198         node->expression()->accept(this);
   199     }
   200 
   201     // Emit the store.
   202     if (node->expression()->type()->isArray()) {
   203         // Unlike references, which can only be computed from a NamePRoxy,
   204         // arrays can be computed from multiple lvalue types.
   205         __ arraycopy();
   206     } else if (node->lvalue()->isNameProxy()) {
   207         NameProxy *proxy = node->lvalue()->toNameProxy();
   208         Variable *var = proxy->binding()->toVariable();
   209 
   210         if (var->type()->isReference()) {
   211             if (var->type()->contained()->isFloat()) {
   212                 __ setref_f();
   213             } else {
   214                 assert(var->type()->contained()->isInt32());
   215                 __ setref_i();
   216             }
   217         } else {
   218             __ set(var);
   219         }
   220     } else {
   221         IndexExpression *index = node->lvalue()->toIndexExpression();
   222         __ bounds();
   223         __ setarray(index->left()->type()->contained()->primitive());
   224     }
   225 }
   226 
   227 void
   228 BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   229 {
   230     node->accept(this);
   231     if (needed->isFloat() && !node->type()->isFloat())
   232         __ cvt_i2f();
   233 }
   234 
   235 void
   236 BytecodeCompiler::visit(BinaryExpression *node)
   237 {
   238     visitForALU(node->type(), node->left());
   239     visitForALU(node->type(), node->right());
   240 
   241     Opcode op = TokenToOpcode(node->token());
   242     if (node->type()->isFloat())
   243         op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   244     __ binary(op);
   245 }
   246 
   247 void
   248 BytecodeCompiler::visit(IndexExpression *node)
   249 {
   250     node->left()->accept(this);
   251     node->right()->accept(this);
   252     __ bounds();
   253 
   254     if (node->type()->isArray())
   255         __ getarray_o();
   256     else
   257         __ getarray(node->type()->primitive());
   258 }
   259 
   260 void
   261 BytecodeCompiler::visit(ReturnStatement *node)
   262 {
   263     if (node->expression())
   264         node->expression()->accept(this);
   265     else
   266         __ int_(0);
   267 
   268     __ return_();
   269 }
   270 
   271 void
   272 BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
   273 {
   274     TokenKind token = ToCompare(expression);
   275     if (token == TOK_EOF) {
   276         expression->accept(this);
   277         if (onTrue)
   278             __ j(OP_JT, label);
   279         else
   280             __ j(OP_JF, label);
   281         return;
   282     }
   283 
   284     Opcode op = CompareTokenToJump(token);
   285     if (!onTrue)
   286         op = Invert(op);
   287 
   288     assert(expression->isBinaryExpression());
   289     BinaryExpression *binary = expression->toBinaryExpression();
   290     binary->left()->accept(this);
   291     binary->right()->accept(this);
   292     __ j(op, label);
   293 }
   294 
   295 void
   296 BytecodeCompiler::visit(ForStatement *node)
   297 {
   298     AutoEnterScope forScope(this, node->scope());
   299 
   300     recordLifoSlot(node->scope());
   301 
   302     Label join, update;
   303     LoopScope loop(scope_, &join, &update, &loop_);
   304 
   305     if (node->declaration())
   306         node->declaration()->accept(this);
   307 
   308     Label header, test;
   309     if (node->condition())
   310         __ jump(&test);
   311 
   312     __ bind(&header);
   313     node->body()->accept(this);
   314 
   315     __ bind(&update);
   316     if (node->update())
   317         node->update()->accept(this);
   318 
   319     if (node->condition()) {
   320         __ bind(&test);
   321         visitForTest(node->condition(), &header, true);
   322     } else {
   323         __ jump(&header);
   324     }
   325 
   326     __ bind(&join);
   327 
   328     if (node->scope())
   329         unwindTo(node->scope()->enclosing());
   330     assert(__ stackDepth() == 0);
   331 }
   332 
   333 void
   334 BytecodeCompiler::visit(WhileStatement *node)
   335 {
   336     Label header, join;
   337 
   338     __ bind(&header);
   339 
   340     LoopScope loop(scope_, &join, &header, &loop_);
   341 
   342     if (node->token() == TOK_WHILE) {
   343         visitForTest(node->condition(), &join, false);
   344         node->body()->accept(this);
   345         __ jump(&header);
   346     } else {
   347         node->body()->accept(this);
   348         visitForTest(node->condition(), &header, true);
   349     }
   350 
   351     __ bind(&join);
   352 }
   353 
   354 void
   355 BytecodeCompiler::visit(BreakStatement *node)
   356 {
   357     unwindTo(loop_->scope());
   358     __ jump(loop_->break_());
   359 }
   360 
   361 void
   362 BytecodeCompiler::visit(ContinueStatement *node)
   363 {
   364     unwindTo(loop_->scope());
   365     __ jump(loop_->continue_());
   366 }
   367 
   368 void
   369 BytecodeCompiler::visit(BlockStatement *node)
   370 {
   371     AutoEnterScope blockScope(this, node->scope());
   372 
   373     recordLifoSlot(node->scope());
   374 
   375     for (size_t i = 0; i < node->statements()->length(); i++) {
   376         Statement *statement = node->statements()->at(i);
   377         statement->accept(this);
   378         assert(__ stackDepth() == 0);
   379     }
   380 
   381     // We don't bother emitting an "unwind" instruction for function scopes,
   382     // since this is taken care of by the calling convention.
   383     if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   384         unwindTo(node->scope()->enclosing());
   385 }
   386 
   387 void
   388 BytecodeCompiler::visit(IntegerLiteral *node)
   389 {
   390     __ int_(node->value());
   391 }
   392 
   393 void
   394 BytecodeCompiler::visit(FloatLiteral *node)
   395 {
   396     __ float_((float)node->value());
   397 }
   398 
   399 static inline ArrayMap *
   400 BuildArrayMap(Zone *zone, Type *type)
   401 {
   402     // :TODO: use local
   403     ArrayMap *contained = NULL;
   404     if (type->levels() > 1) {
   405         contained = BuildArrayMap(zone, type->contained());
   406         if (!contained)
   407             return NULL;
   408     }
   409 
   410     return ArrayMap::New(zone, type, contained);
   411 }
   412 
   413 void
   414 BytecodeCompiler::visit(StringLiteral *node)
   415 {
   416     // :TODO: use Local
   417     ArrayMap *map = BuildArrayMap(ZONE(), node->type());
   418     if (!map)
   419         return;
   420 
   421     Array *array = Array::New(ZONE(), map, node->string()->length(), Heap::Tenure_Old);
   422     if (!array)
   423         return;
   424 
   425     assert(array->nelements() >= node->string()->length());
   426     memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
   427 
   428     __ object(array);
   429 }
   430 
   431 void
   432 BytecodeCompiler::visit(VariableDeclaration *node)
   433 {
   434     Variable *var = node->variable();
   435     assert(var->location() == Variable::STACK);
   436     
   437     Type *type = var->type();
   438     if (type->isArray()) {
   439         // :TODO: use Local
   440         ArrayMap *map = BuildArrayMap(ZONE(), type);
   441         __ newarray_lifo(map);
   442 
   443         if (node->initialization()) {
   444             node->initialization()->accept(this);
   445             __ arraycopy();
   446         }
   447     } else {
   448         if (node->initialization()) {
   449             node->initialization()->accept(this);
   450         } else {
   451             if (!node->postDimensions())
   452                 __ int_(0);
   453         }
   454     }
   455     __ setlocal(var->slot());
   456     __ pop();
   457 
   458     locals_->set(ZONE(), var->slot(), var->type());
   459 }
   460 
   461 void
   462 BytecodeCompiler::visit(CallExpression *node)
   463 {
   464     NameProxy *fun = node->callee()->toNameProxy();
   465 
   466     // :TODO: use Local
   467     Type *funType = node->callee()->type();
   468 
   469     for (size_t i = 0; i < node->arguments()->size(); i++) {
   470         Expression *arg = node->arguments()->at(i);
   471 
   472         Type *given = arg->type();
   473         Type *actual = Type::cast(funType->parameters()->at(i));
   474         if (actual->isReference()) {
   475             if (given->isReference()) {
   476                 // The input type is already a reference, so we're just passing
   477                 // it on to the callee.
   478                 arg->accept(this);
   479             } else if (arg->isNameProxy()) {
   480                 // :TODO: test with functions and globals
   481                 // Compute a reference to the name.
   482                 Variable *var = arg->toNameProxy()->binding()->toVariable();
   483                 __ newref(var);
   484             } else if (arg->isIndexExpression()) {
   485                 IndexExpression *expr = arg->toIndexExpression();
   486                 expr->left()->accept(this);
   487                 expr->right()->accept(this);
   488                 __ bounds();
   489                 __ arrayref_lifo();
   490             } else {
   491                 // We don't know how to, or can't, build a direct reference to
   492                 // this type. Make an indirect one, by taking the top of the
   493                 // stack and boxing it up.
   494                 arg->accept(this);
   495                 __ slotref_lifo();
   496             }
   497         } else {
   498             arg->accept(this);
   499         }
   500     }
   501 
   502     __ callglobal(node->arguments()->size(), 0);
   503 }
   504 
   505 void
   506 BytecodeCompiler::visit(IfStatement *node)
   507 {
   508     if (!node->ifFalse()) {
   509         Label fail;
   510         visitForTest(node->condition(), &fail, false);
   511         node->ifTrue()->accept(this);
   512         __ bind(&fail);
   513     } else {
   514         Label fail, join;
   515         visitForTest(node->condition(), &fail, false);
   516         node->ifTrue()->accept(this);
   517         __ jump(&join);
   518         __ bind(&fail);
   519         node->ifFalse()->accept(this);
   520         __ bind(&join);
   521     }
   522 }
   523 
   524 void
   525 BytecodeCompiler::visit(FunctionStatement *node)
   526 {
   527     BytecodeCompiler child(tree_, module_);
   528     Code *code = child.compileFunction(module_, node);
   529     
   530     assert(!module_->getFunction(node->fun()->slot()));
   531     module_->setFunction(ZONE(), node->fun()->slot(), code);
   532 }
   533 
   534 void
   535 BytecodeCompiler::visit(EnumStatement *node)
   536 {
   537     // :TODO: eventually, we'll export these.
   538 }
   539 
   540 Code *
   541 BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
   542 {
   543     // Note: No need to record a life slot here, since it's part of the Frame.
   544     AutoEnterScope functionScope(this, node->scope());
   545 
   546     // :TODO: use locals
   547     locals_ = FixedArray::New(ZONE(), node->scope()->maxContainedLocals(), Heap::Tenure_Old);
   548 
   549     node->body()->accept(this);
   550 
   551     __ stop();
   552 
   553     if (__ oom())
   554         return NULL;
   555 
   556     ByteArray *bytes = ByteArray::New(ZONE(), __ length() * sizeof(bytecode), Heap::Tenure_Old);
   557     if (!bytes)
   558         return NULL;
   559     memcpy(bytes->raw(), __ buffer(), __ length());
   560 
   561     unsigned nargs = node->scope()->numArguments();
   562     FixedArray *args = FixedArray::New(ZONE(), nargs, Heap::Tenure_Old);
   563     if (!args)
   564         return NULL;
   565 
   566     for (size_t i = 0; i < node->scope()->numArguments(); i++)
   567         args->set(ZONE(), i, node->scope()->getArgument(i)->type());
   568 
   569     for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
   570         assert(locals_->at(i));
   571 
   572     FixedArray *objects = FixedArray::New(ZONE(), __ objects()->size(), Heap::Tenure_Old);
   573     if (!objects)
   574         return NULL;
   575 
   576     for (size_t i = 0; i < __ objects()->size(); i++)
   577         objects->set(ZONE(), i, __ objects()->at(i));
   578 
   579     Code *code = Code::New(ZONE(), bytes, locals_, args, objects, __ maxStackDepth(), module_);
   580     return code;
   581 }
   582 
   583 Module *
   584 BytecodeCompiler::compile()
   585 {
   586     // :TODO: root
   587     module_ = Module::New(ZONE(), tree_->scope()->numFunctions());
   588     if (!module_)
   589         return NULL;
   590 
   591     for (size_t i = 0; i < tree_->statements()->length(); i++) {
   592         Statement *statement = tree_->statements()->at(i);
   593         statement->accept(this);
   594     }
   595 
   596 #ifndef NDEBUG
   597     for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
   598         assert(module_->getFunction(i));
   599 #endif
   600 
   601     return module_;
   602 }