jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Tue Jul 24 23:53:34 2012 -0700 (2012-07-24)
changeset 86 32ad0523b309
parent 85 06a0015b6a5c
permissions -rw-r--r--
Renamed jitcraft/ to src/, fixed some /Wp64 warnings.
     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 "Strings.h"
    25 #include "Zone.h"
    26 #include "Environments.h"
    27 #include "Heap-inl.h"
    28 
    29 using namespace ke;
    30 
    31 typedef BytecodeEmitter::Label Label;
    32 
    33 #define __ emitter_.
    34 
    35 BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
    36   : zone_(zone),
    37     tree_(tree),
    38     emitter_(zone->pool()),
    39     moduleData_(module),
    40     locals_(NULL),
    41     scope_(NULL),
    42     loop_(NULL)
    43 {
    44 }
    45 
    46 static inline TokenKind
    47 ToCompare(Expression *expr)
    48 {
    49     if (expr->isBinaryExpression()) {
    50         BinaryExpression *b = expr->toBinaryExpression();
    51         if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
    52             return b->token();
    53     } else if (expr->isUnaryExpression()) {
    54         UnaryExpression *u = expr->toUnaryExpression();
    55         if (u->token() == TOK_NOT)
    56             return TOK_NOT;
    57     }
    58     return TOK_EOF;
    59 }
    60 
    61 static inline Opcode
    62 CompareTokenToJump(TokenKind kind)
    63 {
    64     switch (kind) {
    65       case TOK_EQUALS:
    66         return OP_JEQ;
    67       case TOK_NOTEQUALS:
    68         return OP_JNE;
    69       case TOK_GT:
    70         return OP_JG;
    71       case TOK_GE:
    72         return OP_JGE;
    73       case TOK_LT:
    74         return OP_JL;
    75       default:
    76         assert(kind == TOK_LE);
    77         return OP_JLE;
    78     }
    79 }
    80 
    81 static inline Opcode
    82 TokenToOpcode(TokenKind kind)
    83 {
    84     switch (kind) {
    85       case TOK_PLUS:
    86         return OP_ADD;
    87       case TOK_MINUS:
    88         return OP_SUB;
    89       case TOK_STAR:
    90         return OP_MUL;
    91       case TOK_SLASH:
    92         return OP_DIV;
    93       case TOK_PERCENT:
    94         return OP_MOD;
    95       case TOK_SHR:
    96         return OP_SHR;
    97       case TOK_USHR:
    98         return OP_USHR;
    99       case TOK_SHL:
   100         return OP_SHL;
   101       case TOK_BITAND:
   102         return OP_BITAND;
   103       case TOK_BITOR:
   104         return OP_BITOR;
   105       case TOK_GT:
   106           return OP_GT;
   107       case TOK_GE:
   108           return OP_GE;
   109       case TOK_LT:
   110           return OP_LT;
   111       case TOK_LE:
   112           return OP_LE;
   113       case TOK_EQUALS:
   114           return OP_EQ;
   115       case TOK_NOTEQUALS:
   116           return OP_NE;
   117       default:
   118         assert(kind == TOK_BITXOR);
   119         return OP_BITXOR;
   120     }
   121 }
   122 
   123 void
   124 BytecodeCompiler::recordLifoSlot(Scope *scope)
   125 {
   126     if (!scope)
   127         return;
   128 
   129     if (Variable *var = scope->lifoSlot()) {
   130         locals_->set(zone_, var->slot(), var->type());
   131         __ savelifo(var->slot());
   132     }
   133 }
   134 
   135 void
   136 BytecodeCompiler::unwindTo(Scope *scope)
   137 {
   138     // Note: we only need to unwind to the outermost scope's LIFO slot.
   139     Variable *var = NULL;
   140     for (Scope *current = scope_; current != scope; current = current->enclosing()) {
   141         if (Variable *slot = current->lifoSlot())
   142             var = slot;
   143     }
   144 
   145     if (var)
   146         __ unwindlifo(var->slot());
   147 }
   148 
   149 void
   150 BytecodeCompiler::visit(NameProxy *name)
   151 {
   152     switch (name->binding()->kind()) {
   153       case BoundName::VARIABLE:
   154       {
   155         Variable *var = name->binding()->toVariable();
   156 
   157         if (var->location() == Variable::STACK) {
   158             __ getlocal(var);
   159             assert(!name->type()->isReference());
   160         } else if (var->location() == Variable::ENVIRONMENT) {
   161             getEnvSlot(var);
   162         } else {
   163             assert(var->location() == Variable::PARAMETER);
   164             __ getarg(var);
   165 
   166             // If this argument is actually a reference, dereference it now.
   167             if (var->type()->isReference())
   168                 __ getref(var->type()->contained()->primitive());
   169         }
   170         break;
   171       }
   172 
   173       case BoundName::FUNCTION:
   174       {
   175         NamedFunction *fun = name->binding()->toNamedFunction();
   176         __ module();
   177         __ getmodule_fn(fun->slot());
   178         break;
   179       }
   180 
   181       default:
   182       {
   183         NamedConstant *constant = name->binding()->toNamedConstant();
   184         __ int_(constant->value().toInt());
   185         break;
   186       }
   187     }
   188 }
   189 
   190 void
   191 BytecodeCompiler::visit(ExpressionStatement *node)
   192 {
   193     // Expressions leave their value on the top of the stack, so we make sure
   194     // to balance the stack if they're used as a statement.
   195     node->expression()->accept(this);
   196     if (!node->expression()->type()->isVoid())
   197         __ pop();
   198 }
   199 
   200 void
   201 BytecodeCompiler::visit(Assignment *node)
   202 {
   203     // The first step is three sub-steps:
   204     //
   205     //   (1) Bind the left-hand side.
   206     //   -- If a cumulative operation (+=, etc):
   207     //   (2) Save a copy of the binding on the stack.
   208     //   (3) Dereference the binding to get a value.
   209     //
   210     if (node->lvalue()->isNameProxy()) {
   211         NameProxy *proxy = node->lvalue()->toNameProxy();
   212         Variable *var = proxy->binding()->toVariable();
   213 
   214         // Bind.
   215         if (var->type()->isReference() || var->type()->isArray())
   216             __ get(var);
   217 
   218         // Get the value if needed.
   219         if (node->token() != TOK_ASSIGN) {
   220             // += etc is not allowed on arrays.
   221             assert(!var->type()->isArray());
   222 
   223             if (var->type()->isReference()) {
   224                 __ dup();
   225                 __ getref(var->type()->contained()->primitive());
   226             } else {
   227                 __ get(var);
   228             }
   229         }
   230     } else {
   231         IndexExpression *index = node->lvalue()->toIndexExpression();
   232         __ note_position(index->pos());
   233 
   234         // Note: Eventually, watch out for a whole here. An expression like:
   235         //
   236         //   (a[4] = (5, a = []))
   237         //
   238         // Could shrink array, so we need to either bind a[i] to a Reference,
   239         // or keep the bounds check near the set. This is just a semantic
   240         // decision.
   241         index->left()->accept(this);
   242         index->right()->accept(this);
   243 
   244         if (node->token() != TOK_ASSIGN) {
   245             __ dup2();
   246             __ bounds();
   247             if (node->type()->isArray())
   248                 __ getarray_o();
   249             else
   250                 __ getarray(node->type()->primitive());
   251         }
   252     }
   253 
   254     if (node->token() == TOK_ASSIGN) {
   255         node->expression()->accept(this);
   256     } else {
   257         visitForALU(node->type(), node->expression());
   258 
   259         TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
   260         __ note_position(node->pos());
   261         __ binary(TokenToOpcode(alu));
   262     }
   263 
   264     // Emit the store.
   265     if (node->expression()->type()->isArray()) {
   266         // Unlike references, which can only be computed from a NamePRoxy,
   267         // arrays can be computed from multiple lvalue types.
   268         __ note_position(node->pos());
   269         __ arraycopy();
   270     } else if (node->lvalue()->isNameProxy()) {
   271         NameProxy *proxy = node->lvalue()->toNameProxy();
   272         Variable *var = proxy->binding()->toVariable();
   273 
   274         if (var->type()->isReference())
   275             __ setref(var->type()->contained()->primitive());
   276         else
   277             __ set(var);
   278     } else {
   279         IndexExpression *index = node->lvalue()->toIndexExpression();
   280         // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
   281         // We can't emit it here because the stack is slightly out of position.
   282         // __ bounds();
   283         __ setarray(index->left()->type()->contained()->primitive());
   284     }
   285 }
   286 
   287 void
   288 BytecodeCompiler::visit(IncDecExpression *node)
   289 {
   290     // In the postfix case, the logic looks like:
   291     //      (1) Bind       -> REF
   292     //      (2) Dup        -> REF REF
   293     //      (3) Fetch      -> REF VAL
   294     //      (4) Swap       -> VAL REF
   295     //      (5) Pick       -> VAL REF VAL
   296     //      (6) Add        -> VAL REF VAL+1
   297     //      (7) Store      -> VAL VAL+1
   298     //      (8) Drop       -> VAL
   299     //
   300     // In the prefix case, the logic looks like:
   301     //      (1) Bind       -> REF
   302     //      (2) Dup        -> REF REF
   303     //      (3) Fetch      -> REF VAL
   304     //      --
   305     //      --
   306     //      (6) Add        -> REF VAL+1
   307     //      (7) Store      -> VAL+1
   308     //      --
   309     //
   310     // This is squirrely enough such that we don't bother sharing too much
   311     // with the above.
   312     // 
   313     // Note: We simulate a "Pick" operation with a dup2+pop.
   314 
   315     // This is steps (1) to (5).
   316     Expression *expr = node->expression();
   317     if (expr->isNameProxy()) {
   318         NameProxy *proxy = expr->toNameProxy();
   319         Variable *var = proxy->binding()->toVariable();
   320 
   321         // Bind.
   322         if (var->type()->isReference() || var->type()->isArray())
   323             __ get(var);
   324 
   325         // Dup and fetch.
   326         if (var->type()->isReference()) {
   327             __ dup();
   328             __ getref(node->type()->primitive());
   329             if (node->postfix()) {
   330                 __ swap();
   331                 __ pick2();
   332             }
   333         } else {
   334             assert(!var->type()->isArray());
   335             __ get(var);
   336             if (node->postfix())
   337                 __ dup();
   338         }
   339     } else {
   340         IndexExpression *index = expr->toIndexExpression();
   341         __ note_position(index->pos());
   342 
   343         index->left()->accept(this);
   344         index->right()->accept(this);
   345 
   346         assert(!node->type()->isArray());
   347         __ bounds();
   348         __ dup2();
   349         __ getarray(node->type()->primitive());
   350 
   351         if (node->postfix()) {
   352             // The stack looks like this now:
   353             // ARRAY INDEX VALUE
   354             //
   355             // So we must use a PICK operation to rotate the stack into position.
   356             __ roll3();         // INDEX VALUE ARRAY
   357             __ roll3();         // VALUE ARRAY INDEX
   358             __ pick3();         // VALUE ARRAY INDEX VALUE
   359         }
   360     }
   361 
   362     // Perform step (6).
   363     if (node->type()->isFloat()) {
   364         __ float_(1.0);
   365     } else {
   366         assert(node->type()->isInt32());
   367         __ int_(1);
   368     }
   369 
   370     __ note_position(node->pos());
   371     if (node->token() == TOK_INCREMENT)
   372         __ binary(OP_ADD);
   373     else
   374         __ binary(OP_SUB);
   375 
   376     // Perform step (7).
   377     if (expr->isNameProxy()) {
   378         NameProxy *proxy = expr->toNameProxy();
   379         Variable *var = proxy->binding()->toVariable();
   380 
   381         if (var->type()->isReference())
   382             __ setref(node->type()->primitive());
   383         else
   384             __ set(var);
   385     } else {
   386         __ setarray(node->type()->primitive());
   387     }
   388 
   389     // Perform step (8).
   390     if (node->postfix())
   391         __ pop();
   392 }
   393 
   394 void
   395 BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   396 {
   397     node->accept(this);
   398     if (needed->isFloat() && !node->type()->isFloat())
   399         __ cvt_i2f();
   400     else
   401         assert(needed->primitive() == node->type()->primitive());
   402 }
   403 
   404 static inline Type *
   405 GetCoercionType(TokenKind tok, Type *left, Type *right)
   406 {
   407     if (left->isFloat())
   408         return left;
   409     return right;
   410 }
   411 
   412 void
   413 BytecodeCompiler::visit(UnaryExpression *node)
   414 {
   415     switch (node->token()) {
   416       case TOK_MINUS:
   417       {
   418         Local<Type> type(zone_, node->expression()->type());
   419         node->expression()->accept(this);
   420         
   421         if (node->type()->isFloat())
   422             __ neg_f();
   423         else
   424             __ neg();
   425         break;
   426       }
   427 
   428       case TOK_NOT:
   429       {
   430         Local<Type> type(zone_, node->expression()->type());
   431         node->expression()->accept(this);
   432         
   433         if (node->type()->isFloat())
   434             __ not_f();
   435         else
   436             __ not_();
   437         break;
   438       }
   439 
   440       default:
   441         assert(node->token() == TOK_TILDE);
   442         node->expression()->accept(this);
   443         __ bitnot();
   444         break;
   445     }
   446 }
   447 
   448 void
   449 BytecodeCompiler::visit(BinaryExpression *node)
   450 {
   451     if (node->token() == TOK_AND || node->token() == TOK_OR) {
   452         Label success, failure, done;
   453         visitForTest(node, &success, &failure, &success);
   454         __ bind(&success);
   455         __ int_(1);
   456         __ drop(1);         // Otherwise, the stack depth will be +1 too much.
   457         __ jump(&done);
   458         __ bind(&failure);
   459         __ int_(0);
   460         __ bind(&done);
   461         return;
   462     }
   463 
   464     Local<Type> leftType(zone_, node->left()->type());
   465     Local<Type> rightType(zone_, node->right()->type());
   466     Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
   467 
   468     visitForALU(coerce, node->left());
   469     visitForALU(coerce, node->right());
   470 
   471     Opcode op = TokenToOpcode(node->token());
   472     if (node->type()->isFloat())
   473         op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   474 
   475     __ note_position(node->pos());
   476     __ binary(op);
   477 }
   478 
   479 void
   480 BytecodeCompiler::visit(IndexExpression *node)
   481 {
   482     node->left()->accept(this);
   483     node->right()->accept(this);
   484     __ note_position(node->pos());
   485     __ bounds();
   486 
   487     if (node->type()->isArray())
   488         __ getarray_o();
   489     else
   490         __ getarray(node->type()->primitive());
   491 }
   492 
   493 void
   494 BytecodeCompiler::visit(ReturnStatement *node)
   495 {
   496     if (node->expression()) {
   497         node->expression()->accept(this);
   498         __ return_();
   499     } else {
   500         __ returnvoid();
   501     }
   502 }
   503 
   504 void
   505 BytecodeCompiler::visitForTest(Expression *expression,
   506                                Label *trueBranch,
   507                                Label *falseBranch,
   508                                Label *fallthrough)
   509 {
   510     TokenKind token = ToCompare(expression);
   511     if (token == TOK_EOF || token == TOK_NOT) {
   512         if (token == TOK_EOF)
   513             expression->accept(this);
   514         else
   515             expression->toUnaryExpression()->expression()->accept(this);
   516         
   517         bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
   518 
   519         Opcode op = jumpOnTrue ? OP_JT : OP_JF;
   520         if (expression->type()->isFloat())
   521             op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
   522 
   523         if (fallthrough == falseBranch)
   524             __ j(op, trueBranch);
   525         else
   526             __ j(op, falseBranch); 
   527         return;
   528     }
   529 
   530     BinaryExpression *binary = expression->toBinaryExpression();
   531 
   532     if (token == TOK_AND || token == TOK_OR) {
   533         Label next;
   534         if (token == TOK_AND)
   535             visitForTest(binary->left(), &next, falseBranch, &next);
   536         else
   537             visitForTest(binary->left(), trueBranch, &next, &next);
   538         __ bind(&next);
   539         visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
   540         return;
   541     }
   542 
   543     Opcode op = CompareTokenToJump(token);
   544     if (fallthrough == trueBranch)
   545         op = Invert(op);
   546 
   547     Local<Type> leftType(zone_, binary->left()->type());
   548     Local<Type> rightType(zone_, binary->right()->type());
   549     Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
   550 
   551     visitForALU(coerce, binary->left());
   552     visitForALU(coerce, binary->right());
   553     if (coerce->isFloat())
   554         op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
   555 
   556     if (fallthrough == trueBranch)
   557         __ j(op, falseBranch);
   558     else
   559         __ j(op, trueBranch);
   560 }
   561 
   562 void
   563 BytecodeCompiler::visit(ForStatement *node)
   564 {
   565     AutoEnterScope forScope(this, node->scope());
   566 
   567     recordLifoSlot(node->scope());
   568 
   569     Label join, update;
   570     LoopScope loop(scope_, &join, &update, &loop_);
   571 
   572     if (node->initialization())
   573         node->initialization()->accept(this);
   574 
   575     Label header, test;
   576     if (node->condition())
   577         __ jump(&test);
   578 
   579     __ bind(&header);
   580     node->body()->accept(this);
   581 
   582     __ bind(&update);
   583     if (node->update())
   584         node->update()->accept(this);
   585 
   586     if (node->condition()) {
   587         __ bind(&test);
   588         visitForTest(node->condition(), &header, &join, &join);
   589     } else {
   590         __ jump(&header);
   591     }
   592 
   593     __ bind(&join);
   594 
   595     if (node->scope())
   596         unwindTo(node->scope()->enclosing());
   597     assert(__ stackDepth() == 0);
   598 }
   599 
   600 void
   601 BytecodeCompiler::visit(WhileStatement *node)
   602 {
   603     Label header, join;
   604 
   605     __ bind(&header);
   606 
   607     LoopScope loop(scope_, &join, &header, &loop_);
   608 
   609     if (node->token() == TOK_WHILE) {
   610         Label body;
   611 
   612         visitForTest(node->condition(), &body, &join, &body);
   613         __ bind(&body);
   614         node->body()->accept(this);
   615         __ jump(&header);
   616     } else {
   617         node->body()->accept(this);
   618         visitForTest(node->condition(), &header, &join, &join);
   619     }
   620 
   621     __ bind(&join);
   622 }
   623 
   624 void
   625 BytecodeCompiler::visit(BreakStatement *node)
   626 {
   627     unwindTo(loop_->scope());
   628     __ jump(loop_->break_());
   629 }
   630 
   631 void
   632 BytecodeCompiler::visit(ContinueStatement *node)
   633 {
   634     unwindTo(loop_->scope());
   635     __ jump(loop_->continue_());
   636 }
   637 
   638 void
   639 BytecodeCompiler::visit(BlockStatement *node)
   640 {
   641     AutoEnterScope blockScope(this, node->scope());
   642 
   643     recordLifoSlot(node->scope());
   644 
   645     for (size_t i = 0; i < node->statements()->length(); i++) {
   646         Statement *statement = node->statements()->at(i);
   647         statement->accept(this);
   648         assert(__ stackDepth() == 0);
   649     }
   650 
   651     // We don't bother emitting an "unwind" instruction for function scopes,
   652     // since this is taken care of by the calling convention.
   653     if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   654         unwindTo(node->scope()->enclosing());
   655 }
   656 
   657 void
   658 BytecodeCompiler::visit(IntegerLiteral *node)
   659 {
   660     __ int_(node->value());
   661 }
   662 
   663 void
   664 BytecodeCompiler::visit(FloatLiteral *node)
   665 {
   666     __ float_((float)node->value());
   667 }
   668 
   669 static inline ArrayMap *
   670 BuildArrayMap(Zone *zone, Handle<Type> type)
   671 {
   672     Local<ArrayMap> contained(zone);
   673     if (type->levels() > 1) {
   674         Local<Type> containedType(zone, type->contained());
   675         contained = BuildArrayMap(zone, containedType);
   676         if (!contained)
   677             return NULL;
   678     }
   679 
   680     return ArrayMap::New(zone, type, contained);
   681 }
   682 
   683 void
   684 BytecodeCompiler::visit(StringLiteral *node)
   685 {
   686     Local<Type> type(zone_, node->type());
   687     Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
   688     if (!map)
   689         return;
   690 
   691     Local<Array> array(zone_, Array::New(zone_, map, node->string()->length(), Heap::Tenure_Old));
   692     if (!array)
   693         return;
   694 
   695     assert(array->nelements() >= node->string()->length());
   696     memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
   697 
   698     __ note_position(node->pos());
   699     __ object(array);
   700 }
   701 
   702 void
   703 BytecodeCompiler::getEnvSlot(Variable *var)
   704 {
   705     assert(var->scope()->kind() == Scope::GLOBAL);
   706     __ getglobal(var);
   707 }
   708 
   709 void
   710 BytecodeCompiler::setEnvSlot(Variable *var)
   711 {
   712     assert(var->scope()->kind() == Scope::GLOBAL);
   713     __ setglobal(var);
   714 }
   715 
   716 void
   717 BytecodeCompiler::visit(VariableDeclaration *node)
   718 {
   719     Variable *var = node->variable();
   720     
   721     Local<Type> type(zone_, var->type());
   722     if (type->isArray()) {
   723         Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
   724         __ note_position(node->pos());
   725         if (var->scope()->kind() == Scope::GLOBAL)
   726             __ newarray(map, Heap::Tenure_Old);
   727         else if (var->needsHeapAllocation())
   728             __ newarray(map, Heap::Tenure_Default);
   729         else
   730             __ newarray(map, Heap::Tenure_Stack);
   731 
   732         if (node->initialization()) {
   733             node->initialization()->accept(this);
   734             __ note_position(node->pos());
   735             __ arraycopy();
   736         }
   737     } else {
   738         if (node->initialization()) {
   739             node->initialization()->accept(this);
   740         } else {
   741             if (!node->postDimensions())
   742                 __ int_(0);
   743         }
   744     }
   745 
   746     if (var->location() == Variable::STACK) {
   747         __ setlocal(var);
   748         locals_->set(zone_, var->slot(), var->type());
   749     } else {
   750         assert(var->location() == Variable::ENVIRONMENT);
   751         setEnvSlot(var);
   752     }
   753 
   754     __ pop();
   755 }
   756 
   757 void
   758 BytecodeCompiler::visit(CallExpression *node)
   759 {
   760     Local<Type> funType(zone_, node->callee()->type());
   761 
   762     // Sniff out natives, which have a specific opcode and are guaranteed to
   763     // be called via name proxy.
   764     NamedFunction *native = NULL;
   765     if (funType->isNative()) {
   766         native = node->callee()->toNameProxy()->binding()->toNamedFunction();
   767     }
   768 
   769     for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
   770         Expression *arg = node->arguments()->at(i);
   771 
   772         // We need to compute a reference if the parameter was in the form:
   773         //  f(&a)
   774         // Note this form does not allow: f({})
   775         // 
   776         // We also need to compute references for all variadic native
   777         // arguments, but arrays and references are already in the
   778         // appropriate form.
   779         Local<Type> given(zone_, arg->type());
   780         bool mustPushReference = false;
   781         if (i >= funType->parameters()->length()) {
   782             assert(funType->isNative() && funType->isNativeVariadic());
   783             mustPushReference = !given->isArray() && !given->isReference();
   784         } else if (funType->parameterAt(i)->isReference()) {
   785             mustPushReference = !given->isReference();
   786         }
   787 
   788         // If a native is passed to a native, it must only be one level deep.
   789         assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
   790 
   791         if (mustPushReference) {
   792             if (arg->isNameProxy()) {
   793                 // :TODO: test with functions and globals
   794                 // Compute a reference to the name.
   795                 Variable *var = arg->toNameProxy()->binding()->toVariable();
   796                 __ note_position(node->pos());
   797                 __ newref(var);
   798             } else if (arg->isIndexExpression()) {
   799                 IndexExpression *expr = arg->toIndexExpression();
   800                 expr->left()->accept(this);
   801                 expr->right()->accept(this);
   802                 __ note_position(expr->pos());
   803                 __ bounds();
   804                 __ arrayref_lifo();
   805             } else {
   806                 // We don't know how to, or can't, build a direct reference to
   807                 // this type. Make an indirect one, by taking the top of the
   808                 // stack and boxing it up.
   809                 arg->accept(this);
   810                 __ note_position(node->pos());
   811                 __ slotref_lifo();
   812             }
   813         } else {
   814             arg->accept(this);
   815         }
   816     }
   817 
   818     __ note_position(node->pos());
   819     if (native) {
   820         __ callnative(native->slot(), node->arguments()->length());
   821         __ drop(node->arguments()->length());
   822     } else {
   823         node->callee()->accept(this);
   824         __ call(funType);
   825         __ drop(node->arguments()->length() + 1);
   826     }
   827 }
   828 
   829 void
   830 BytecodeCompiler::visit(TernaryExpression *node)
   831 {
   832     Label success, failure, join;
   833 
   834     visitForTest(node->condition(), &success, &failure, &success);
   835     __ bind(&success);
   836     node->left()->accept(this);
   837     __ drop(1);
   838     __ jump(&join);
   839     __ bind(&failure);
   840     node->right()->accept(this);
   841     __ bind(&join);
   842 }
   843 
   844 void
   845 BytecodeCompiler::visit(IfStatement *node)
   846 {
   847     Label join;
   848     if (!node->ifFalse()) {
   849         Label success;
   850 
   851         visitForTest(node->condition(), &success, &join, &success);
   852         __ bind(&success);
   853         node->ifTrue()->accept(this);
   854     } else {
   855         Label success, next;
   856 
   857         visitForTest(node->condition(), &success, &next, &success);
   858         __ bind(&success);
   859         node->ifTrue()->accept(this);
   860         __ jump(&join);
   861         __ bind(&next);
   862         node->ifFalse()->accept(this);
   863     }
   864 
   865     __ bind(&join);
   866 }
   867 
   868 void
   869 BytecodeCompiler::visit(FunctionStatement *node)
   870 {
   871     if (node->fun()->isNative()) {
   872         assert(!moduleData_->natives->at(node->fun()->slot()));
   873 
   874         Local<Type> type(zone_, node->fun()->type());
   875         Local<String> name(zone_, node->fun()->name());
   876         Local<Native> native(zone_, Native::New(zone_, type, name));
   877         if (!native)
   878             return;
   879 
   880         moduleData_->natives->set(zone_, node->fun()->slot(), native);
   881         return;
   882     }
   883 
   884     // If the function has no body, then it's just a declaration.
   885     if (!node->body()) {
   886         assert(node->fun()->isForward() || node->fun()->isPublic());
   887         return;
   888     }
   889 
   890     BytecodeCompiler child(zone_, tree_, moduleData_);
   891     Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
   892     if (!fun)
   893         return;
   894     
   895     assert(!moduleData_->module->getFunction(node->fun()->slot()));
   896     moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
   897 }
   898 
   899 void
   900 BytecodeCompiler::visit(EnumStatement *node)
   901 {
   902     // :TODO: eventually, we'll export these.
   903 }
   904 
   905 Code *
   906 BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
   907 {
   908     // STOP doubles as RETURNVOID.
   909     __ stop();
   910 
   911     if (__ oom() || zone_->hasPendingException())
   912         return NULL;
   913 
   914     Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
   915     if (!bytes)
   916         return NULL;
   917     memcpy(bytes->raw(), __ buffer(), __ length());
   918 
   919     for (size_t i = 0; i < scope->maxContainedLocals(); i++)
   920         assert(locals_->at(i));
   921 
   922     Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
   923     if (!objects)
   924         return NULL;
   925 
   926     for (size_t i = 0; i < __ objects()->length(); i++)
   927         objects->set(zone_, i, *(__ objects()->at(i)));
   928 
   929     Local<ByteArray> safepoints(zone_);
   930 
   931     // If any stack slots hold gc pointers at potential failure points in the
   932     // bytecode, record them now. We do this by building a list of tuples;
   933     // each tuple contains the pc offset, and a bitset containing which stack
   934     // slots must be scanned by the gc.
   935     if (__ oopRecords()->length()) {
   936         size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
   937         size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
   938         safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
   939         if (!safepoints)
   940             return NULL;
   941 
   942         Address cursor = safepoints->raw();
   943         for (size_t i = 0; i < __ oopRecords()->length(); i++) {
   944             OopRecord *record = __ oopRecords()->at(i);
   945             assert(record->depth <= __ maxStackDepth());
   946 
   947             *reinterpret_cast<unsigned *>(cursor) = record->offset;
   948 
   949             unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
   950             for (unsigned i = 0; i < record->depth; i++)
   951                 bits[i / 8] |= (1 << (i % 8));
   952 
   953             cursor += bytesPerSafepoint;
   954         }
   955 
   956         assert(cursor == safepoints->raw() + gcmapSize);
   957     }
   958 
   959     Local<ByteArray> sourcemap(zone_);
   960     if (__ sourcemapLength()) {
   961         sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
   962         if (!sourcemap)
   963             return NULL;
   964 
   965         memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
   966     }
   967 
   968     Local<Code> code(zone_);
   969 
   970     code = Code::New(zone_,
   971                      bytes,
   972                      locals_,
   973                      objects,
   974                      __ maxStackDepth(),
   975                      moduleData_->module,
   976                      safepoints,
   977                      sourcemap,
   978                      lineno);
   979     return code;
   980 }
   981 
   982 Function *
   983 BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
   984 {
   985     // Note: No need to record a life slot here, since it's part of the Frame.
   986     AutoEnterScope functionScope(this, node->scope());
   987 
   988     // Set the initial line, because line mappings are deltas.
   989     __ setFirstLine(node->pos().line);
   990     locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
   991 
   992     node->body()->accept(this);
   993 
   994     unsigned nargs = node->scope()->numArguments();
   995     Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
   996     if (!args)
   997         return NULL;
   998 
   999     for (size_t i = 0; i < node->scope()->numArguments(); i++)
  1000         args->set(zone_, i, node->scope()->getArgument(i)->type());
  1001 
  1002 
  1003     Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
  1004     if (!code)
  1005         return NULL;
  1006 
  1007     Local<Type> type(zone_, node->fun()->type());
  1008     Local<String> name(zone_, node->fun()->name());
  1009     Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
  1010     if (!fun)
  1011         return NULL;
  1012 
  1013     // If this function had a forward, export it as a named public.
  1014     if (node->fun()->isPublic()) {
  1015         assert(node->fun()->isPublic());
  1016         ScopedRoot<Function> root(fun);
  1017         if (!root)
  1018             return NULL;
  1019         if (!moduleData_->publics.append(root))
  1020             return NULL;
  1021     }
  1022 
  1023     Disassemble(code, stdout);
  1024     
  1025     return fun;
  1026 }
  1027 
  1028 Module *
  1029 BytecodeCompiler::compile()
  1030 {
  1031     AutoEnterScope scope(this, tree_->scope());
  1032 
  1033     ModuleData moduleData;
  1034 
  1035     moduleData_ = &moduleData;
  1036     moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
  1037 
  1038     if (!moduleData_)
  1039         return NULL;
  1040     
  1041     moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
  1042     if (!moduleData_->natives)
  1043         return NULL;
  1044 
  1045     for (size_t i = 0; i < tree_->statements()->length(); i++) {
  1046         Statement *statement = tree_->statements()->at(i);
  1047         statement->accept(this);
  1048     }
  1049 
  1050     if (zone_->hasPendingException())
  1051         return NULL;
  1052 
  1053 #ifndef NDEBUG
  1054     for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
  1055         assert(moduleData_->module->getFunction(i));
  1056     for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
  1057         assert(moduleData_->natives->at(i));
  1058 #endif
  1059 
  1060     if (moduleData_->publics.length()) {
  1061         Local<Function> fun(zone_);
  1062         Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
  1063                                Heap::Tenure_Old));
  1064         if (!list)
  1065             return NULL;
  1066 
  1067         for (size_t i = 0; i < moduleData_->publics.length(); i++)
  1068             list->set(zone_, i, moduleData_->publics[i]);
  1069 
  1070         moduleData_->module->setPublics(list);
  1071     }
  1072 
  1073     moduleData_->module->setNatives(moduleData_->natives);
  1074 
  1075     if (scope_->numEnvironmentVars()) {
  1076         Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
  1077         if (!globalMap)
  1078             return NULL;
  1079 
  1080         Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
  1081         if (!environment)
  1082             return NULL;
  1083 
  1084         moduleData_->module->setEnvironment(environment);
  1085     }
  1086 
  1087     Local<Code> code(zone_, compileCode(tree_->scope(), 1));
  1088     if (!code)
  1089         return NULL;
  1090 
  1091     Disassemble(code, stdout);
  1092 
  1093     moduleData_->module->setCode(code);
  1094 
  1095     return moduleData_->module;
  1096 }