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