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