jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Tue Jul 03 00:25:29 2012 -0700 (2012-07-03)
changeset 30 8c8bf75114f7
parent 28 a9665857cfd5
child 32 af1ed58252ac
permissions -rw-r--r--
Remove calls to ZONE().
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include "BytecodeCompiler.h"
    20 #include "Scopes.h"
    21 #include "Modules.h"
    22 #include "Types.h"
    23 #include "Array.h"
    24 #include "Zone.h"
    25 #include "Heap-inl.h"
    26 
    27 using namespace jc;
    28 
    29 typedef BytecodeEmitter::Label Label;
    30 
    31 #define __ emitter_.
    32 
    33 BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, Module *module)
    34   : zone_(zone),
    35     tree_(tree),
    36     module_(module),
    37     locals_(NULL),
    38     scope_(NULL),
    39     loop_(NULL)
    40 {
    41 }
    42 
    43 static inline TokenKind
    44 ToCompare(Expression *expr)
    45 {
    46     if (expr->isBinaryExpression()) {
    47         BinaryExpression *b = expr->toBinaryExpression();
    48         if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
    49             return b->token();
    50     }
    51     return TOK_EOF;
    52 }
    53 
    54 static inline Opcode
    55 CompareTokenToJump(TokenKind kind)
    56 {
    57     switch (kind) {
    58       case TOK_EQUALS:
    59         return OP_JEQ;
    60       case TOK_NOTEQUALS:
    61         return OP_JNE;
    62       case TOK_GT:
    63         return OP_JG;
    64       case TOK_GE:
    65         return OP_JGE;
    66       case TOK_LT:
    67         return OP_JL;
    68       default:
    69         assert(kind == TOK_LE);
    70         return OP_JLE;
    71     }
    72 }
    73 
    74 static inline Opcode
    75 TokenToOpcode(TokenKind kind)
    76 {
    77     switch (kind) {
    78       case TOK_PLUS:
    79         return OP_ADD;
    80       case TOK_MINUS:
    81         return OP_SUB;
    82       case TOK_STAR:
    83         return OP_MUL;
    84       case TOK_SLASH:
    85         return OP_DIV;
    86       case TOK_SHR:
    87         return OP_SHR;
    88       case TOK_USHR:
    89         return OP_USHR;
    90       case TOK_SHL:
    91         return OP_SHL;
    92       case TOK_BITAND:
    93         return OP_BITAND;
    94       case TOK_BITOR:
    95         return OP_BITOR;
    96       default:
    97         assert(kind == TOK_BITXOR);
    98         return OP_BITXOR;
    99     }
   100 }
   101 
   102 void
   103 BytecodeCompiler::recordLifoSlot(Scope *scope)
   104 {
   105     if (!scope)
   106         return;
   107 
   108     if (Variable *var = scope->lifoSlot()) {
   109         locals_->set(zone_, var->slot(), var->type());
   110         __ savelifo(var->slot());
   111     }
   112 }
   113 
   114 void
   115 BytecodeCompiler::unwindTo(Scope *scope)
   116 {
   117     // Note: we only need to unwind to the outermost scope's LIFO slot.
   118     Variable *var = NULL;
   119     for (Scope *current = scope_; current != scope; current = current->enclosing()) {
   120         if (Variable *slot = current->lifoSlot())
   121             var = slot;
   122     }
   123 
   124     if (var)
   125         __ unwindlifo(var->slot());
   126 }
   127 
   128 void
   129 BytecodeCompiler::visit(NameProxy *name)
   130 {
   131     switch (name->binding()->kind()) {
   132       case BoundName::VARIABLE:
   133       {
   134         Variable *var = name->binding()->toVariable();
   135 
   136         if (var->location() == Variable::STACK) {
   137             __ getlocal(var->slot());
   138             assert(!name->type()->isReference());
   139         } else {
   140             assert(var->location() == Variable::PARAMETER);
   141             __ getarg(var->slot());
   142 
   143             // If this argument is actually a reference, dereference it now.
   144             if (var->type()->isReference())
   145                 __ getref(var->type()->contained()->primitive());
   146         }
   147         break;
   148       }
   149 
   150       default:
   151       {
   152         NamedConstant *constant = name->binding()->toNamedConstant();
   153         __ int_(constant->value().toInt());
   154         break;
   155       }
   156     }
   157 }
   158 
   159 void
   160 BytecodeCompiler::visit(ExpressionStatement *node)
   161 {
   162     // Expressions leave their value on the top of the stack, so we make sure
   163     // to balance the stack if they're used as a statement.
   164     node->expression()->accept(this);
   165     __ pop();
   166 }
   167 
   168 void
   169 BytecodeCompiler::visit(Assignment *node)
   170 {
   171     // The first step is three sub-steps:
   172     //
   173     //   (1) Bind the left-hand side.
   174     //   -- If a cumulative operation (+=, etc):
   175     //   (2) Save a copy of the binding on the stack.
   176     //   (3) Dereference the binding to get a value.
   177     //
   178     if (node->lvalue()->isNameProxy()) {
   179         NameProxy *proxy = node->lvalue()->toNameProxy();
   180         Variable *var = proxy->binding()->toVariable();
   181 
   182         // Bind.
   183         if (var->type()->isReference() || var->type()->isArray())
   184             __ get(var);
   185 
   186         // Get the value if needed.
   187         if (node->token() != TOK_ASSIGN) {
   188             // += etc is not allowed on arrays.
   189             assert(!var->type()->isArray());
   190 
   191             if (var->type()->isReference()) {
   192                 __ dup();
   193                 __ getref(var->type()->contained()->primitive());
   194             } else {
   195                 __ get(var);
   196             }
   197         }
   198     } else {
   199         IndexExpression *index = node->lvalue()->toIndexExpression();
   200 
   201         // Note: Eventually, watch out for a whole here. An expression like:
   202         //
   203         //   (a[4] = (5, a = []))
   204         //
   205         // Could shrink array, so we need to either bind a[i] to a Reference,
   206         // or keep the bounds check near the set. This is just a semantic
   207         // decision.
   208         index->left()->accept(this);
   209         index->right()->accept(this);
   210 
   211         if (node->token() != TOK_ASSIGN) {
   212             __ dup2();
   213             __ bounds();
   214             if (node->type()->isArray())
   215                 __ getarray_o();
   216             else
   217                 __ getarray(node->type()->primitive());
   218         }
   219     }
   220 
   221     if (node->token() == TOK_ASSIGN) {
   222         node->expression()->accept(this);
   223     } else {
   224         visitForALU(node->type(), node->expression());
   225 
   226         TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
   227         __ binary(TokenToOpcode(alu));
   228     }
   229 
   230     // Emit the store.
   231     if (node->expression()->type()->isArray()) {
   232         // Unlike references, which can only be computed from a NamePRoxy,
   233         // arrays can be computed from multiple lvalue types.
   234         __ arraycopy();
   235     } else if (node->lvalue()->isNameProxy()) {
   236         NameProxy *proxy = node->lvalue()->toNameProxy();
   237         Variable *var = proxy->binding()->toVariable();
   238 
   239         if (var->type()->isReference())
   240             __ setref(var->type()->contained()->primitive());
   241         else
   242             __ set(var);
   243     } else {
   244         IndexExpression *index = node->lvalue()->toIndexExpression();
   245         // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
   246         // We can't emit it here because the stack is slightly out of position.
   247         // __ bounds();
   248         __ setarray(index->left()->type()->contained()->primitive());
   249     }
   250 }
   251 
   252 void
   253 BytecodeCompiler::visit(IncDecExpression *node)
   254 {
   255     // In the postfix case, the logic looks like:
   256     //      (1) Bind       -> REF
   257     //      (2) Dup        -> REF REF
   258     //      (3) Fetch      -> REF VAL
   259     //      (4) Swap       -> VAL REF
   260     //      (5) Pick       -> VAL REF VAL
   261     //      (6) Add        -> VAL REF VAL+1
   262     //      (7) Store      -> VAL VAL+1
   263     //      (8) Drop       -> VAL
   264     //
   265     // In the prefix case, the logic looks like:
   266     //      (1) Bind       -> REF
   267     //      (2) Dup        -> REF REF
   268     //      (3) Fetch      -> REF VAL
   269     //      --
   270     //      --
   271     //      (6) Add        -> REF VAL+1
   272     //      (7) Store      -> VAL+1
   273     //      --
   274     //
   275     // This is squirrely enough such that we don't bother sharing too much
   276     // with the above.
   277     // 
   278     // Note: We simulate a "Pick" operation with a dup2+pop.
   279 
   280     // This is steps (1) to (5).
   281     Expression *expr = node->expression();
   282     if (expr->isNameProxy()) {
   283         NameProxy *proxy = expr->toNameProxy();
   284         Variable *var = proxy->binding()->toVariable();
   285 
   286         // Bind.
   287         if (var->type()->isReference() || var->type()->isArray())
   288             __ get(var);
   289 
   290         // Dup and fetch.
   291         if (var->type()->isReference()) {
   292             __ dup();
   293             __ getref(node->type()->primitive());
   294             if (node->postfix()) {
   295                 __ swap();
   296                 __ pick2();
   297             }
   298         } else {
   299             assert(!var->type()->isArray());
   300             __ get(var);
   301             if (node->postfix())
   302                 __ dup();
   303         }
   304     } else {
   305         IndexExpression *index = expr->toIndexExpression();
   306         index->left()->accept(this);
   307         index->right()->accept(this);
   308 
   309         assert(!node->type()->isArray());
   310         __ bounds();
   311         __ dup2();
   312         __ getarray(node->type()->primitive());
   313 
   314         if (node->postfix()) {
   315             // The stack looks like this now:
   316             // ARRAY INDEX VALUE
   317             //
   318             // So we must use a PICK operation to rotate the stack into position.
   319             __ roll3();         // INDEX VALUE ARRAY
   320             __ roll3();         // VALUE ARRAY INDEX
   321             __ pick3();         // VALUE ARRAY INDEX VALUE
   322         }
   323     }
   324 
   325     // Perform step (6).
   326     if (node->type()->isFloat()) {
   327         __ float_(1.0);
   328     } else {
   329         assert(node->type()->isInt32());
   330         __ int_(1);
   331     }
   332 
   333     if (node->token() == TOK_INCREMENT)
   334         __ binary(OP_ADD);
   335     else
   336         __ binary(OP_SUB);
   337 
   338     // Perform step (7).
   339     if (expr->isNameProxy()) {
   340         NameProxy *proxy = expr->toNameProxy();
   341         Variable *var = proxy->binding()->toVariable();
   342 
   343         if (var->type()->isReference())
   344             __ setref(node->type()->primitive());
   345         else
   346             __ set(var);
   347     } else {
   348         __ setarray(node->type()->primitive());
   349     }
   350 
   351     // Perform step (8).
   352     if (node->postfix())
   353         __ pop();
   354 }
   355 
   356 void
   357 BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   358 {
   359     node->accept(this);
   360     if (needed->isFloat() && !node->type()->isFloat())
   361         __ cvt_i2f();
   362     else
   363         assert(needed->primitive() == node->type()->primitive());
   364 }
   365 
   366 void
   367 BytecodeCompiler::visit(BinaryExpression *node)
   368 {
   369     visitForALU(node->type(), node->left());
   370     visitForALU(node->type(), node->right());
   371 
   372     Opcode op = TokenToOpcode(node->token());
   373     if (node->type()->isFloat())
   374         op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   375     __ binary(op);
   376 }
   377 
   378 void
   379 BytecodeCompiler::visit(IndexExpression *node)
   380 {
   381     node->left()->accept(this);
   382     node->right()->accept(this);
   383     __ bounds();
   384 
   385     if (node->type()->isArray())
   386         __ getarray_o();
   387     else
   388         __ getarray(node->type()->primitive());
   389 }
   390 
   391 void
   392 BytecodeCompiler::visit(ReturnStatement *node)
   393 {
   394     if (node->expression())
   395         node->expression()->accept(this);
   396     else
   397         __ int_(0);
   398 
   399     __ return_();
   400 }
   401 
   402 void
   403 BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
   404 {
   405     TokenKind token = ToCompare(expression);
   406     if (token == TOK_EOF) {
   407         expression->accept(this);
   408         if (onTrue)
   409             __ j(OP_JT, label);
   410         else
   411             __ j(OP_JF, label);
   412         return;
   413     }
   414 
   415     Opcode op = CompareTokenToJump(token);
   416     if (!onTrue)
   417         op = Invert(op);
   418 
   419     assert(expression->isBinaryExpression());
   420     BinaryExpression *binary = expression->toBinaryExpression();
   421     binary->left()->accept(this);
   422     binary->right()->accept(this);
   423     __ j(op, label);
   424 }
   425 
   426 void
   427 BytecodeCompiler::visit(ForStatement *node)
   428 {
   429     AutoEnterScope forScope(this, node->scope());
   430 
   431     recordLifoSlot(node->scope());
   432 
   433     Label join, update;
   434     LoopScope loop(scope_, &join, &update, &loop_);
   435 
   436     if (node->initialization())
   437         node->initialization()->accept(this);
   438 
   439     Label header, test;
   440     if (node->condition())
   441         __ jump(&test);
   442 
   443     __ bind(&header);
   444     node->body()->accept(this);
   445 
   446     __ bind(&update);
   447     if (node->update())
   448         node->update()->accept(this);
   449 
   450     if (node->condition()) {
   451         __ bind(&test);
   452         visitForTest(node->condition(), &header, true);
   453     } else {
   454         __ jump(&header);
   455     }
   456 
   457     __ bind(&join);
   458 
   459     if (node->scope())
   460         unwindTo(node->scope()->enclosing());
   461     assert(__ stackDepth() == 0);
   462 }
   463 
   464 void
   465 BytecodeCompiler::visit(WhileStatement *node)
   466 {
   467     Label header, join;
   468 
   469     __ bind(&header);
   470 
   471     LoopScope loop(scope_, &join, &header, &loop_);
   472 
   473     if (node->token() == TOK_WHILE) {
   474         visitForTest(node->condition(), &join, false);
   475         node->body()->accept(this);
   476         __ jump(&header);
   477     } else {
   478         node->body()->accept(this);
   479         visitForTest(node->condition(), &header, true);
   480     }
   481 
   482     __ bind(&join);
   483 }
   484 
   485 void
   486 BytecodeCompiler::visit(BreakStatement *node)
   487 {
   488     unwindTo(loop_->scope());
   489     __ jump(loop_->break_());
   490 }
   491 
   492 void
   493 BytecodeCompiler::visit(ContinueStatement *node)
   494 {
   495     unwindTo(loop_->scope());
   496     __ jump(loop_->continue_());
   497 }
   498 
   499 void
   500 BytecodeCompiler::visit(BlockStatement *node)
   501 {
   502     AutoEnterScope blockScope(this, node->scope());
   503 
   504     recordLifoSlot(node->scope());
   505 
   506     for (size_t i = 0; i < node->statements()->length(); i++) {
   507         Statement *statement = node->statements()->at(i);
   508         statement->accept(this);
   509         assert(__ stackDepth() == 0);
   510     }
   511 
   512     // We don't bother emitting an "unwind" instruction for function scopes,
   513     // since this is taken care of by the calling convention.
   514     if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   515         unwindTo(node->scope()->enclosing());
   516 }
   517 
   518 void
   519 BytecodeCompiler::visit(IntegerLiteral *node)
   520 {
   521     __ int_(node->value());
   522 }
   523 
   524 void
   525 BytecodeCompiler::visit(FloatLiteral *node)
   526 {
   527     __ float_((float)node->value());
   528 }
   529 
   530 static inline ArrayMap *
   531 BuildArrayMap(Zone *zone, Handle<Type> type)
   532 {
   533     // :TODO: use local
   534     Local<ArrayMap> contained(zone);
   535     if (type->levels() > 1) {
   536         Local<Type> containedType(zone, type->contained());
   537         contained = BuildArrayMap(zone, containedType);
   538         if (!contained)
   539             return NULL;
   540     }
   541 
   542     return ArrayMap::New(zone, type, contained);
   543 }
   544 
   545 void
   546 BytecodeCompiler::visit(StringLiteral *node)
   547 {
   548     // :TODO: remove this Local
   549     Local<Type> type(zone_, node->type());
   550     Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
   551     if (!map)
   552         return;
   553 
   554     Local<Array> array(zone_, Array::New(zone_, map, node->string()->length(), Heap::Tenure_Old));
   555     if (!array)
   556         return;
   557 
   558     assert(array->nelements() >= node->string()->length());
   559     memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
   560 
   561     __ object(array);
   562 }
   563 
   564 void
   565 BytecodeCompiler::visit(VariableDeclaration *node)
   566 {
   567     Variable *var = node->variable();
   568     assert(var->location() == Variable::STACK);
   569     
   570     Local<Type> type(zone_, var->type());
   571     if (type->isArray()) {
   572         // :TODO: use Local
   573         Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
   574         __ newarray_lifo(map);
   575 
   576         if (node->initialization()) {
   577             node->initialization()->accept(this);
   578             __ arraycopy();
   579         }
   580     } else {
   581         if (node->initialization()) {
   582             node->initialization()->accept(this);
   583         } else {
   584             if (!node->postDimensions())
   585                 __ int_(0);
   586         }
   587     }
   588     __ setlocal(var->slot());
   589     __ pop();
   590 
   591     locals_->set(zone_, var->slot(), var->type());
   592 }
   593 
   594 void
   595 BytecodeCompiler::visit(CallExpression *node)
   596 {
   597     // :TODO: use Local
   598     Type *funType = node->callee()->type();
   599 
   600     for (size_t i = 0; i < node->arguments()->size(); i++) {
   601         Expression *arg = node->arguments()->at(i);
   602 
   603         Type *given = arg->type();
   604         Type *actual = Type::cast(funType->parameters()->at(i));
   605         if (actual->isReference()) {
   606             if (given->isReference()) {
   607                 // The input type is already a reference, so we're just passing
   608                 // it on to the callee.
   609                 arg->accept(this);
   610             } else if (arg->isNameProxy()) {
   611                 // :TODO: test with functions and globals
   612                 // Compute a reference to the name.
   613                 Variable *var = arg->toNameProxy()->binding()->toVariable();
   614                 __ newref(var);
   615             } else if (arg->isIndexExpression()) {
   616                 IndexExpression *expr = arg->toIndexExpression();
   617                 expr->left()->accept(this);
   618                 expr->right()->accept(this);
   619                 __ bounds();
   620                 __ arrayref_lifo();
   621             } else {
   622                 // We don't know how to, or can't, build a direct reference to
   623                 // this type. Make an indirect one, by taking the top of the
   624                 // stack and boxing it up.
   625                 arg->accept(this);
   626                 __ slotref_lifo();
   627             }
   628         } else {
   629             arg->accept(this);
   630         }
   631     }
   632 
   633     __ callglobal(node->arguments()->size(), 0);
   634 }
   635 
   636 void
   637 BytecodeCompiler::visit(IfStatement *node)
   638 {
   639     if (!node->ifFalse()) {
   640         Label fail;
   641         visitForTest(node->condition(), &fail, false);
   642         node->ifTrue()->accept(this);
   643         __ bind(&fail);
   644     } else {
   645         Label fail, join;
   646         visitForTest(node->condition(), &fail, false);
   647         node->ifTrue()->accept(this);
   648         __ jump(&join);
   649         __ bind(&fail);
   650         node->ifFalse()->accept(this);
   651         __ bind(&join);
   652     }
   653 }
   654 
   655 void
   656 BytecodeCompiler::visit(FunctionStatement *node)
   657 {
   658     BytecodeCompiler child(zone_, tree_, module_);
   659     Function *fun = child.compileFunction(module_, node);
   660     if (!fun)
   661         return;
   662     
   663     assert(!module_->getFunction(node->fun()->slot()));
   664     module_->setFunction(zone_, node->fun()->slot(), fun);
   665 }
   666 
   667 void
   668 BytecodeCompiler::visit(EnumStatement *node)
   669 {
   670     // :TODO: eventually, we'll export these.
   671 }
   672 
   673 Function *
   674 BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
   675 {
   676     // Note: No need to record a life slot here, since it's part of the Frame.
   677     AutoEnterScope functionScope(this, node->scope());
   678 
   679     // :TODO: use locals
   680     locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
   681 
   682     node->body()->accept(this);
   683 
   684     __ stop();
   685 
   686     if (__ oom())
   687         return NULL;
   688 
   689     ByteArray *bytes = ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old);
   690     if (!bytes)
   691         return NULL;
   692     memcpy(bytes->raw(), __ buffer(), __ length());
   693 
   694     unsigned nargs = node->scope()->numArguments();
   695     FixedArray *args = FixedArray::New(zone_, nargs, Heap::Tenure_Old);
   696     if (!args)
   697         return NULL;
   698 
   699     for (size_t i = 0; i < node->scope()->numArguments(); i++)
   700         args->set(zone_, i, node->scope()->getArgument(i)->type());
   701 
   702     for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
   703         assert(locals_->at(i));
   704 
   705     FixedArray *objects = FixedArray::New(zone_, __ objects()->size(), Heap::Tenure_Old);
   706     if (!objects)
   707         return NULL;
   708 
   709     for (size_t i = 0; i < __ objects()->size(); i++)
   710         objects->set(zone_, i, __ objects()->at(i));
   711 
   712     Code *code = Code::New(zone_, bytes, locals_, objects, __ maxStackDepth(), module_);
   713     if (!code)
   714         return NULL;
   715 
   716     Function *fun = Function::New(zone_, module_, code, node->fun()->type(), node->pos());
   717     if (!fun)
   718         return NULL;
   719     
   720     return fun;
   721 }
   722 
   723 Module *
   724 BytecodeCompiler::compile()
   725 {
   726     // :TODO: root
   727     module_ = Module::New(zone_, tree_->scope()->numFunctions());
   728     if (!module_)
   729         return NULL;
   730 
   731     for (size_t i = 0; i < tree_->statements()->length(); i++) {
   732         Statement *statement = tree_->statements()->at(i);
   733         statement->accept(this);
   734     }
   735 
   736 #ifndef NDEBUG
   737     for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
   738         assert(module_->getFunction(i));
   739 #endif
   740 
   741     return module_;
   742 }