jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 01 18:21:15 2012 -0700 (2012-07-01)
changeset 23 8a31742781c1
parent 22 765ab1b672a3
child 26 a48382113da6
permissions -rw-r--r--
Implement ++ and -- operators.
     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                 __ getref(var->type()->contained()->primitive());
   145         }
   146         break;
   147       }
   148 
   149       default:
   150       {
   151         NamedConstant *constant = name->binding()->toNamedConstant();
   152         __ int_(constant->value().toInt());
   153         break;
   154       }
   155     }
   156 }
   157 
   158 void
   159 BytecodeCompiler::visit(ExpressionStatement *node)
   160 {
   161     // Expressions leave their value on the top of the stack, so we make sure
   162     // to balance the stack if they're used as a statement.
   163     node->expression()->accept(this);
   164     __ pop();
   165 }
   166 
   167 void
   168 BytecodeCompiler::visit(Assignment *node)
   169 {
   170     // The first step is three sub-steps:
   171     //
   172     //   (1) Bind the left-hand side.
   173     //   -- If a cumulative operation (+=, etc):
   174     //   (2) Save a copy of the binding on the stack.
   175     //   (3) Dereference the binding to get a value.
   176     //
   177     if (node->lvalue()->isNameProxy()) {
   178         NameProxy *proxy = node->lvalue()->toNameProxy();
   179         Variable *var = proxy->binding()->toVariable();
   180 
   181         // Bind.
   182         if (var->type()->isReference() || var->type()->isArray())
   183             __ get(var);
   184 
   185         // Get the value if needed.
   186         if (node->token() != TOK_ASSIGN) {
   187             // += etc is not allowed on arrays.
   188             assert(!var->type()->isArray());
   189 
   190             if (var->type()->isReference()) {
   191                 __ dup();
   192                 __ getref(var->type()->contained()->primitive());
   193             } else {
   194                 __ get(var);
   195             }
   196         }
   197     } else {
   198         IndexExpression *index = node->lvalue()->toIndexExpression();
   199 
   200         // Note: Eventually, watch out for a whole here. An expression like:
   201         //
   202         //   (a[4] = (5, a = []))
   203         //
   204         // Could shrink array, so we need to either bind a[i] to a Reference,
   205         // or keep the bounds check near the set. This is just a semantic
   206         // decision.
   207         index->left()->accept(this);
   208         index->right()->accept(this);
   209 
   210         if (node->token() != TOK_ASSIGN) {
   211             __ dup2();
   212             __ bounds();
   213             if (node->type()->isArray())
   214                 __ getarray_o();
   215             else
   216                 __ getarray(node->type()->primitive());
   217         }
   218     }
   219 
   220     if (node->token() == TOK_ASSIGN) {
   221         node->expression()->accept(this);
   222     } else {
   223         visitForALU(node->type(), node->expression());
   224 
   225         TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
   226         __ binary(TokenToOpcode(alu));
   227     }
   228 
   229     // Emit the store.
   230     if (node->expression()->type()->isArray()) {
   231         // Unlike references, which can only be computed from a NamePRoxy,
   232         // arrays can be computed from multiple lvalue types.
   233         __ arraycopy();
   234     } else if (node->lvalue()->isNameProxy()) {
   235         NameProxy *proxy = node->lvalue()->toNameProxy();
   236         Variable *var = proxy->binding()->toVariable();
   237 
   238         if (var->type()->isReference())
   239             __ setref(var->type()->contained()->primitive());
   240         else
   241             __ set(var);
   242     } else {
   243         IndexExpression *index = node->lvalue()->toIndexExpression();
   244         // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
   245         // We can't emit it here because the stack is slightly out of position.
   246         // __ bounds();
   247         __ setarray(index->left()->type()->contained()->primitive());
   248     }
   249 }
   250 
   251 void
   252 BytecodeCompiler::visit(IncDecExpression *node)
   253 {
   254     // In the postfix case, the logic looks like:
   255     //      (1) Bind       -> REF
   256     //      (2) Dup        -> REF REF
   257     //      (3) Fetch      -> REF VAL
   258     //      (4) Swap       -> VAL REF
   259     //      (5) Pick       -> VAL REF VAL
   260     //      (6) Add        -> VAL REF VAL+1
   261     //      (7) Store      -> VAL VAL+1
   262     //      (8) Drop       -> VAL
   263     //
   264     // In the prefix case, the logic looks like:
   265     //      (1) Bind       -> REF
   266     //      (2) Dup        -> REF REF
   267     //      (3) Fetch      -> REF VAL
   268     //      --
   269     //      --
   270     //      (6) Add        -> REF VAL+1
   271     //      (7) Store      -> VAL+1
   272     //      --
   273     //
   274     // This is squirrely enough such that we don't bother sharing too much
   275     // with the above.
   276     // 
   277     // Note: We simulate a "Pick" operation with a dup2+pop.
   278 
   279     // This is steps (1) to (5).
   280     Expression *expr = node->expression();
   281     if (expr->isNameProxy()) {
   282         NameProxy *proxy = expr->toNameProxy();
   283         Variable *var = proxy->binding()->toVariable();
   284 
   285         // Bind.
   286         if (var->type()->isReference() || var->type()->isArray())
   287             __ get(var);
   288 
   289         // Dup and fetch.
   290         if (var->type()->isReference()) {
   291             __ dup();
   292             __ getref(node->type()->primitive());
   293             if (node->postfix()) {
   294                 __ swap();
   295                 __ pick2();
   296             }
   297         } else {
   298             assert(!var->type()->isArray());
   299             __ get(var);
   300             if (node->postfix())
   301                 __ dup();
   302         }
   303     } else {
   304         IndexExpression *index = expr->toIndexExpression();
   305         index->left()->accept(this);
   306         index->right()->accept(this);
   307 
   308         assert(!node->type()->isArray());
   309         __ bounds();
   310         __ dup2();
   311         __ getarray(node->type()->primitive());
   312 
   313         if (node->postfix()) {
   314             // The stack looks like this now:
   315             // ARRAY INDEX VALUE
   316             //
   317             // So we must use a PICK operation to rotate the stack into position.
   318             __ roll3();         // INDEX VALUE ARRAY
   319             __ roll3();         // VALUE ARRAY INDEX
   320             __ pick3();         // VALUE ARRAY INDEX VALUE
   321         }
   322     }
   323 
   324     // Perform step (6).
   325     if (node->type()->isFloat()) {
   326         __ float_(1.0);
   327     } else {
   328         assert(node->type()->isInt32());
   329         __ int_(1);
   330     }
   331 
   332     if (node->token() == TOK_INCREMENT)
   333         __ binary(OP_ADD);
   334     else
   335         __ binary(OP_SUB);
   336 
   337     // Perform step (7).
   338     if (expr->isNameProxy()) {
   339         NameProxy *proxy = expr->toNameProxy();
   340         Variable *var = proxy->binding()->toVariable();
   341 
   342         if (var->type()->isReference())
   343             __ setref(node->type()->primitive());
   344         else
   345             __ set(var);
   346     } else {
   347         __ setarray(node->type()->primitive());
   348     }
   349 
   350     // Perform step (8).
   351     if (node->postfix())
   352         __ pop();
   353 }
   354 
   355 void
   356 BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   357 {
   358     node->accept(this);
   359     if (needed->isFloat() && !node->type()->isFloat())
   360         __ cvt_i2f();
   361     else
   362         assert(needed->primitive() == node->type()->primitive());
   363 }
   364 
   365 void
   366 BytecodeCompiler::visit(BinaryExpression *node)
   367 {
   368     visitForALU(node->type(), node->left());
   369     visitForALU(node->type(), node->right());
   370 
   371     Opcode op = TokenToOpcode(node->token());
   372     if (node->type()->isFloat())
   373         op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   374     __ binary(op);
   375 }
   376 
   377 void
   378 BytecodeCompiler::visit(IndexExpression *node)
   379 {
   380     node->left()->accept(this);
   381     node->right()->accept(this);
   382     __ bounds();
   383 
   384     if (node->type()->isArray())
   385         __ getarray_o();
   386     else
   387         __ getarray(node->type()->primitive());
   388 }
   389 
   390 void
   391 BytecodeCompiler::visit(ReturnStatement *node)
   392 {
   393     if (node->expression())
   394         node->expression()->accept(this);
   395     else
   396         __ int_(0);
   397 
   398     __ return_();
   399 }
   400 
   401 void
   402 BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
   403 {
   404     TokenKind token = ToCompare(expression);
   405     if (token == TOK_EOF) {
   406         expression->accept(this);
   407         if (onTrue)
   408             __ j(OP_JT, label);
   409         else
   410             __ j(OP_JF, label);
   411         return;
   412     }
   413 
   414     Opcode op = CompareTokenToJump(token);
   415     if (!onTrue)
   416         op = Invert(op);
   417 
   418     assert(expression->isBinaryExpression());
   419     BinaryExpression *binary = expression->toBinaryExpression();
   420     binary->left()->accept(this);
   421     binary->right()->accept(this);
   422     __ j(op, label);
   423 }
   424 
   425 void
   426 BytecodeCompiler::visit(ForStatement *node)
   427 {
   428     AutoEnterScope forScope(this, node->scope());
   429 
   430     recordLifoSlot(node->scope());
   431 
   432     Label join, update;
   433     LoopScope loop(scope_, &join, &update, &loop_);
   434 
   435     if (node->initialization())
   436         node->initialization()->accept(this);
   437 
   438     Label header, test;
   439     if (node->condition())
   440         __ jump(&test);
   441 
   442     __ bind(&header);
   443     node->body()->accept(this);
   444 
   445     __ bind(&update);
   446     if (node->update())
   447         node->update()->accept(this);
   448 
   449     if (node->condition()) {
   450         __ bind(&test);
   451         visitForTest(node->condition(), &header, true);
   452     } else {
   453         __ jump(&header);
   454     }
   455 
   456     __ bind(&join);
   457 
   458     if (node->scope())
   459         unwindTo(node->scope()->enclosing());
   460     assert(__ stackDepth() == 0);
   461 }
   462 
   463 void
   464 BytecodeCompiler::visit(WhileStatement *node)
   465 {
   466     Label header, join;
   467 
   468     __ bind(&header);
   469 
   470     LoopScope loop(scope_, &join, &header, &loop_);
   471 
   472     if (node->token() == TOK_WHILE) {
   473         visitForTest(node->condition(), &join, false);
   474         node->body()->accept(this);
   475         __ jump(&header);
   476     } else {
   477         node->body()->accept(this);
   478         visitForTest(node->condition(), &header, true);
   479     }
   480 
   481     __ bind(&join);
   482 }
   483 
   484 void
   485 BytecodeCompiler::visit(BreakStatement *node)
   486 {
   487     unwindTo(loop_->scope());
   488     __ jump(loop_->break_());
   489 }
   490 
   491 void
   492 BytecodeCompiler::visit(ContinueStatement *node)
   493 {
   494     unwindTo(loop_->scope());
   495     __ jump(loop_->continue_());
   496 }
   497 
   498 void
   499 BytecodeCompiler::visit(BlockStatement *node)
   500 {
   501     AutoEnterScope blockScope(this, node->scope());
   502 
   503     recordLifoSlot(node->scope());
   504 
   505     for (size_t i = 0; i < node->statements()->length(); i++) {
   506         Statement *statement = node->statements()->at(i);
   507         statement->accept(this);
   508         assert(__ stackDepth() == 0);
   509     }
   510 
   511     // We don't bother emitting an "unwind" instruction for function scopes,
   512     // since this is taken care of by the calling convention.
   513     if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   514         unwindTo(node->scope()->enclosing());
   515 }
   516 
   517 void
   518 BytecodeCompiler::visit(IntegerLiteral *node)
   519 {
   520     __ int_(node->value());
   521 }
   522 
   523 void
   524 BytecodeCompiler::visit(FloatLiteral *node)
   525 {
   526     __ float_((float)node->value());
   527 }
   528 
   529 static inline ArrayMap *
   530 BuildArrayMap(Zone *zone, Type *type)
   531 {
   532     // :TODO: use local
   533     ArrayMap *contained = NULL;
   534     if (type->levels() > 1) {
   535         contained = BuildArrayMap(zone, type->contained());
   536         if (!contained)
   537             return NULL;
   538     }
   539 
   540     return ArrayMap::New(zone, type, contained);
   541 }
   542 
   543 void
   544 BytecodeCompiler::visit(StringLiteral *node)
   545 {
   546     // :TODO: use Local
   547     ArrayMap *map = BuildArrayMap(ZONE(), node->type());
   548     if (!map)
   549         return;
   550 
   551     Array *array = Array::New(ZONE(), map, node->string()->length(), Heap::Tenure_Old);
   552     if (!array)
   553         return;
   554 
   555     assert(array->nelements() >= node->string()->length());
   556     memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
   557 
   558     __ object(array);
   559 }
   560 
   561 void
   562 BytecodeCompiler::visit(VariableDeclaration *node)
   563 {
   564     Variable *var = node->variable();
   565     assert(var->location() == Variable::STACK);
   566     
   567     Type *type = var->type();
   568     if (type->isArray()) {
   569         // :TODO: use Local
   570         ArrayMap *map = BuildArrayMap(ZONE(), type);
   571         __ newarray_lifo(map);
   572 
   573         if (node->initialization()) {
   574             node->initialization()->accept(this);
   575             __ arraycopy();
   576         }
   577     } else {
   578         if (node->initialization()) {
   579             node->initialization()->accept(this);
   580         } else {
   581             if (!node->postDimensions())
   582                 __ int_(0);
   583         }
   584     }
   585     __ setlocal(var->slot());
   586     __ pop();
   587 
   588     locals_->set(ZONE(), var->slot(), var->type());
   589 }
   590 
   591 void
   592 BytecodeCompiler::visit(CallExpression *node)
   593 {
   594     NameProxy *fun = node->callee()->toNameProxy();
   595 
   596     // :TODO: use Local
   597     Type *funType = node->callee()->type();
   598 
   599     for (size_t i = 0; i < node->arguments()->size(); i++) {
   600         Expression *arg = node->arguments()->at(i);
   601 
   602         Type *given = arg->type();
   603         Type *actual = Type::cast(funType->parameters()->at(i));
   604         if (actual->isReference()) {
   605             if (given->isReference()) {
   606                 // The input type is already a reference, so we're just passing
   607                 // it on to the callee.
   608                 arg->accept(this);
   609             } else if (arg->isNameProxy()) {
   610                 // :TODO: test with functions and globals
   611                 // Compute a reference to the name.
   612                 Variable *var = arg->toNameProxy()->binding()->toVariable();
   613                 __ newref(var);
   614             } else if (arg->isIndexExpression()) {
   615                 IndexExpression *expr = arg->toIndexExpression();
   616                 expr->left()->accept(this);
   617                 expr->right()->accept(this);
   618                 __ bounds();
   619                 __ arrayref_lifo();
   620             } else {
   621                 // We don't know how to, or can't, build a direct reference to
   622                 // this type. Make an indirect one, by taking the top of the
   623                 // stack and boxing it up.
   624                 arg->accept(this);
   625                 __ slotref_lifo();
   626             }
   627         } else {
   628             arg->accept(this);
   629         }
   630     }
   631 
   632     __ callglobal(node->arguments()->size(), 0);
   633 }
   634 
   635 void
   636 BytecodeCompiler::visit(IfStatement *node)
   637 {
   638     if (!node->ifFalse()) {
   639         Label fail;
   640         visitForTest(node->condition(), &fail, false);
   641         node->ifTrue()->accept(this);
   642         __ bind(&fail);
   643     } else {
   644         Label fail, join;
   645         visitForTest(node->condition(), &fail, false);
   646         node->ifTrue()->accept(this);
   647         __ jump(&join);
   648         __ bind(&fail);
   649         node->ifFalse()->accept(this);
   650         __ bind(&join);
   651     }
   652 }
   653 
   654 void
   655 BytecodeCompiler::visit(FunctionStatement *node)
   656 {
   657     BytecodeCompiler child(tree_, module_);
   658     Code *code = child.compileFunction(module_, node);
   659     
   660     assert(!module_->getFunction(node->fun()->slot()));
   661     module_->setFunction(ZONE(), node->fun()->slot(), code);
   662 }
   663 
   664 void
   665 BytecodeCompiler::visit(EnumStatement *node)
   666 {
   667     // :TODO: eventually, we'll export these.
   668 }
   669 
   670 Code *
   671 BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
   672 {
   673     // Note: No need to record a life slot here, since it's part of the Frame.
   674     AutoEnterScope functionScope(this, node->scope());
   675 
   676     // :TODO: use locals
   677     locals_ = FixedArray::New(ZONE(), node->scope()->maxContainedLocals(), Heap::Tenure_Old);
   678 
   679     node->body()->accept(this);
   680 
   681     __ stop();
   682 
   683     if (__ oom())
   684         return NULL;
   685 
   686     ByteArray *bytes = ByteArray::New(ZONE(), __ length() * sizeof(bytecode), Heap::Tenure_Old);
   687     if (!bytes)
   688         return NULL;
   689     memcpy(bytes->raw(), __ buffer(), __ length());
   690 
   691     unsigned nargs = node->scope()->numArguments();
   692     FixedArray *args = FixedArray::New(ZONE(), nargs, Heap::Tenure_Old);
   693     if (!args)
   694         return NULL;
   695 
   696     for (size_t i = 0; i < node->scope()->numArguments(); i++)
   697         args->set(ZONE(), i, node->scope()->getArgument(i)->type());
   698 
   699     for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
   700         assert(locals_->at(i));
   701 
   702     FixedArray *objects = FixedArray::New(ZONE(), __ objects()->size(), Heap::Tenure_Old);
   703     if (!objects)
   704         return NULL;
   705 
   706     for (size_t i = 0; i < __ objects()->size(); i++)
   707         objects->set(ZONE(), i, __ objects()->at(i));
   708 
   709     Code *code = Code::New(ZONE(), bytes, locals_, args, objects, __ maxStackDepth(), module_);
   710     return code;
   711 }
   712 
   713 Module *
   714 BytecodeCompiler::compile()
   715 {
   716     // :TODO: root
   717     module_ = Module::New(ZONE(), tree_->scope()->numFunctions());
   718     if (!module_)
   719         return NULL;
   720 
   721     for (size_t i = 0; i < tree_->statements()->length(); i++) {
   722         Statement *statement = tree_->statements()->at(i);
   723         statement->accept(this);
   724     }
   725 
   726 #ifndef NDEBUG
   727     for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
   728         assert(module_->getFunction(i));
   729 #endif
   730 
   731     return module_;
   732 }