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