jitcraft/BytecodeCompiler.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jul 11 01:12:54 2012 -0700 (2012-07-11)
changeset 69 dfce0539a77d
parent 68 b40b0e18a918
child 70 1aec996cde2d
permissions -rw-r--r--
Added error reporting API and fixed all known error paths.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include "BytecodeCompiler.h"
    20 #include "Scopes.h"
    21 #include "Modules.h"
    22 #include "Types.h"
    23 #include "Array.h"
    24 #include "Strings.h"
    25 #include "Zone.h"
    26 #include "Heap-inl.h"
    27 
    28 using namespace ke;
    29 
    30 typedef BytecodeEmitter::Label Label;
    31 
    32 #define __ emitter_.
    33 
    34 BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
    35   : zone_(zone),
    36     tree_(tree),
    37     emitter_(zone->pool()),
    38     moduleData_(module),
    39     locals_(NULL),
    40     scope_(NULL),
    41     loop_(NULL)
    42 {
    43 }
    44 
    45 static inline TokenKind
    46 ToCompare(Expression *expr)
    47 {
    48     if (expr->isBinaryExpression()) {
    49         BinaryExpression *b = expr->toBinaryExpression();
    50         if (b->token() >= TOK_EQUALS && b->token() <= TOK_GE)
    51             return b->token();
    52     }
    53     return TOK_EOF;
    54 }
    55 
    56 static inline Opcode
    57 CompareTokenToJump(TokenKind kind)
    58 {
    59     switch (kind) {
    60       case TOK_EQUALS:
    61         return OP_JEQ;
    62       case TOK_NOTEQUALS:
    63         return OP_JNE;
    64       case TOK_GT:
    65         return OP_JG;
    66       case TOK_GE:
    67         return OP_JGE;
    68       case TOK_LT:
    69         return OP_JL;
    70       default:
    71         assert(kind == TOK_LE);
    72         return OP_JLE;
    73     }
    74 }
    75 
    76 static inline Opcode
    77 TokenToOpcode(TokenKind kind)
    78 {
    79     switch (kind) {
    80       case TOK_PLUS:
    81         return OP_ADD;
    82       case TOK_MINUS:
    83         return OP_SUB;
    84       case TOK_STAR:
    85         return OP_MUL;
    86       case TOK_SLASH:
    87         return OP_DIV;
    88       case TOK_SHR:
    89         return OP_SHR;
    90       case TOK_USHR:
    91         return OP_USHR;
    92       case TOK_SHL:
    93         return OP_SHL;
    94       case TOK_BITAND:
    95         return OP_BITAND;
    96       case TOK_BITOR:
    97         return OP_BITOR;
    98       default:
    99         assert(kind == TOK_BITXOR);
   100         return OP_BITXOR;
   101     }
   102 }
   103 
   104 void
   105 BytecodeCompiler::recordLifoSlot(Scope *scope)
   106 {
   107     if (!scope)
   108         return;
   109 
   110     if (Variable *var = scope->lifoSlot()) {
   111         locals_->set(zone_, var->slot(), var->type());
   112         __ savelifo(var->slot());
   113     }
   114 }
   115 
   116 void
   117 BytecodeCompiler::unwindTo(Scope *scope)
   118 {
   119     // Note: we only need to unwind to the outermost scope's LIFO slot.
   120     Variable *var = NULL;
   121     for (Scope *current = scope_; current != scope; current = current->enclosing()) {
   122         if (Variable *slot = current->lifoSlot())
   123             var = slot;
   124     }
   125 
   126     if (var)
   127         __ unwindlifo(var->slot());
   128 }
   129 
   130 void
   131 BytecodeCompiler::visit(NameProxy *name)
   132 {
   133     switch (name->binding()->kind()) {
   134       case BoundName::VARIABLE:
   135       {
   136         Variable *var = name->binding()->toVariable();
   137 
   138         if (var->location() == Variable::STACK) {
   139             __ getlocal(var);
   140             assert(!name->type()->isReference());
   141         } else {
   142             assert(var->location() == Variable::PARAMETER);
   143             __ getarg(var);
   144 
   145             // If this argument is actually a reference, dereference it now.
   146             if (var->type()->isReference())
   147                 __ getref(var->type()->contained()->primitive());
   148         }
   149         break;
   150       }
   151 
   152       default:
   153       {
   154         NamedConstant *constant = name->binding()->toNamedConstant();
   155         __ int_(constant->value().toInt());
   156         break;
   157       }
   158     }
   159 }
   160 
   161 void
   162 BytecodeCompiler::visit(ExpressionStatement *node)
   163 {
   164     // Expressions leave their value on the top of the stack, so we make sure
   165     // to balance the stack if they're used as a statement.
   166     node->expression()->accept(this);
   167     __ pop();
   168 }
   169 
   170 void
   171 BytecodeCompiler::visit(Assignment *node)
   172 {
   173     // The first step is three sub-steps:
   174     //
   175     //   (1) Bind the left-hand side.
   176     //   -- If a cumulative operation (+=, etc):
   177     //   (2) Save a copy of the binding on the stack.
   178     //   (3) Dereference the binding to get a value.
   179     //
   180     if (node->lvalue()->isNameProxy()) {
   181         NameProxy *proxy = node->lvalue()->toNameProxy();
   182         Variable *var = proxy->binding()->toVariable();
   183 
   184         // Bind.
   185         if (var->type()->isReference() || var->type()->isArray())
   186             __ get(var);
   187 
   188         // Get the value if needed.
   189         if (node->token() != TOK_ASSIGN) {
   190             // += etc is not allowed on arrays.
   191             assert(!var->type()->isArray());
   192 
   193             if (var->type()->isReference()) {
   194                 __ dup();
   195                 __ getref(var->type()->contained()->primitive());
   196             } else {
   197                 __ get(var);
   198             }
   199         }
   200     } else {
   201         IndexExpression *index = node->lvalue()->toIndexExpression();
   202 
   203         // Note: Eventually, watch out for a whole here. An expression like:
   204         //
   205         //   (a[4] = (5, a = []))
   206         //
   207         // Could shrink array, so we need to either bind a[i] to a Reference,
   208         // or keep the bounds check near the set. This is just a semantic
   209         // decision.
   210         index->left()->accept(this);
   211         index->right()->accept(this);
   212 
   213         if (node->token() != TOK_ASSIGN) {
   214             __ dup2();
   215             __ bounds();
   216             if (node->type()->isArray())
   217                 __ getarray_o();
   218             else
   219                 __ getarray(node->type()->primitive());
   220         }
   221     }
   222 
   223     if (node->token() == TOK_ASSIGN) {
   224         node->expression()->accept(this);
   225     } else {
   226         visitForALU(node->type(), node->expression());
   227 
   228         TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
   229         __ binary(TokenToOpcode(alu));
   230     }
   231 
   232     // Emit the store.
   233     if (node->expression()->type()->isArray()) {
   234         // Unlike references, which can only be computed from a NamePRoxy,
   235         // arrays can be computed from multiple lvalue types.
   236         __ arraycopy();
   237     } else if (node->lvalue()->isNameProxy()) {
   238         NameProxy *proxy = node->lvalue()->toNameProxy();
   239         Variable *var = proxy->binding()->toVariable();
   240 
   241         if (var->type()->isReference())
   242             __ setref(var->type()->contained()->primitive());
   243         else
   244             __ set(var);
   245     } else {
   246         IndexExpression *index = node->lvalue()->toIndexExpression();
   247         // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
   248         // We can't emit it here because the stack is slightly out of position.
   249         // __ bounds();
   250         __ setarray(index->left()->type()->contained()->primitive());
   251     }
   252 }
   253 
   254 void
   255 BytecodeCompiler::visit(IncDecExpression *node)
   256 {
   257     // In the postfix case, the logic looks like:
   258     //      (1) Bind       -> REF
   259     //      (2) Dup        -> REF REF
   260     //      (3) Fetch      -> REF VAL
   261     //      (4) Swap       -> VAL REF
   262     //      (5) Pick       -> VAL REF VAL
   263     //      (6) Add        -> VAL REF VAL+1
   264     //      (7) Store      -> VAL VAL+1
   265     //      (8) Drop       -> VAL
   266     //
   267     // In the prefix case, the logic looks like:
   268     //      (1) Bind       -> REF
   269     //      (2) Dup        -> REF REF
   270     //      (3) Fetch      -> REF VAL
   271     //      --
   272     //      --
   273     //      (6) Add        -> REF VAL+1
   274     //      (7) Store      -> VAL+1
   275     //      --
   276     //
   277     // This is squirrely enough such that we don't bother sharing too much
   278     // with the above.
   279     // 
   280     // Note: We simulate a "Pick" operation with a dup2+pop.
   281 
   282     // This is steps (1) to (5).
   283     Expression *expr = node->expression();
   284     if (expr->isNameProxy()) {
   285         NameProxy *proxy = expr->toNameProxy();
   286         Variable *var = proxy->binding()->toVariable();
   287 
   288         // Bind.
   289         if (var->type()->isReference() || var->type()->isArray())
   290             __ get(var);
   291 
   292         // Dup and fetch.
   293         if (var->type()->isReference()) {
   294             __ dup();
   295             __ getref(node->type()->primitive());
   296             if (node->postfix()) {
   297                 __ swap();
   298                 __ pick2();
   299             }
   300         } else {
   301             assert(!var->type()->isArray());
   302             __ get(var);
   303             if (node->postfix())
   304                 __ dup();
   305         }
   306     } else {
   307         IndexExpression *index = expr->toIndexExpression();
   308         index->left()->accept(this);
   309         index->right()->accept(this);
   310 
   311         assert(!node->type()->isArray());
   312         __ bounds();
   313         __ dup2();
   314         __ getarray(node->type()->primitive());
   315 
   316         if (node->postfix()) {
   317             // The stack looks like this now:
   318             // ARRAY INDEX VALUE
   319             //
   320             // So we must use a PICK operation to rotate the stack into position.
   321             __ roll3();         // INDEX VALUE ARRAY
   322             __ roll3();         // VALUE ARRAY INDEX
   323             __ pick3();         // VALUE ARRAY INDEX VALUE
   324         }
   325     }
   326 
   327     // Perform step (6).
   328     if (node->type()->isFloat()) {
   329         __ float_(1.0);
   330     } else {
   331         assert(node->type()->isInt32());
   332         __ int_(1);
   333     }
   334 
   335     if (node->token() == TOK_INCREMENT)
   336         __ binary(OP_ADD);
   337     else
   338         __ binary(OP_SUB);
   339 
   340     // Perform step (7).
   341     if (expr->isNameProxy()) {
   342         NameProxy *proxy = expr->toNameProxy();
   343         Variable *var = proxy->binding()->toVariable();
   344 
   345         if (var->type()->isReference())
   346             __ setref(node->type()->primitive());
   347         else
   348             __ set(var);
   349     } else {
   350         __ setarray(node->type()->primitive());
   351     }
   352 
   353     // Perform step (8).
   354     if (node->postfix())
   355         __ pop();
   356 }
   357 
   358 void
   359 BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   360 {
   361     node->accept(this);
   362     if (needed->isFloat() && !node->type()->isFloat())
   363         __ cvt_i2f();
   364     else
   365         assert(needed->primitive() == node->type()->primitive());
   366 }
   367 
   368 void
   369 BytecodeCompiler::visit(BinaryExpression *node)
   370 {
   371     visitForALU(node->type(), node->left());
   372     visitForALU(node->type(), node->right());
   373 
   374     Opcode op = TokenToOpcode(node->token());
   375     if (node->type()->isFloat())
   376         op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   377     __ binary(op);
   378 }
   379 
   380 void
   381 BytecodeCompiler::visit(IndexExpression *node)
   382 {
   383     node->left()->accept(this);
   384     node->right()->accept(this);
   385     __ bounds();
   386 
   387     if (node->type()->isArray())
   388         __ getarray_o();
   389     else
   390         __ getarray(node->type()->primitive());
   391 }
   392 
   393 void
   394 BytecodeCompiler::visit(ReturnStatement *node)
   395 {
   396     if (node->expression())
   397         node->expression()->accept(this);
   398     else
   399         __ int_(0);
   400 
   401     __ return_();
   402 }
   403 
   404 void
   405 BytecodeCompiler::visitForTest(Expression *expression, Label *label, bool onTrue)
   406 {
   407     TokenKind token = ToCompare(expression);
   408     if (token == TOK_EOF) {
   409         expression->accept(this);
   410         if (onTrue)
   411             __ j(OP_JT, label);
   412         else
   413             __ j(OP_JF, label);
   414         return;
   415     }
   416 
   417     Opcode op = CompareTokenToJump(token);
   418     if (!onTrue)
   419         op = Invert(op);
   420 
   421     assert(expression->isBinaryExpression());
   422     BinaryExpression *binary = expression->toBinaryExpression();
   423     binary->left()->accept(this);
   424     binary->right()->accept(this);
   425     __ j(op, label);
   426 }
   427 
   428 void
   429 BytecodeCompiler::visit(ForStatement *node)
   430 {
   431     AutoEnterScope forScope(this, node->scope());
   432 
   433     recordLifoSlot(node->scope());
   434 
   435     Label join, update;
   436     LoopScope loop(scope_, &join, &update, &loop_);
   437 
   438     if (node->initialization())
   439         node->initialization()->accept(this);
   440 
   441     Label header, test;
   442     if (node->condition())
   443         __ jump(&test);
   444 
   445     __ bind(&header);
   446     node->body()->accept(this);
   447 
   448     __ bind(&update);
   449     if (node->update())
   450         node->update()->accept(this);
   451 
   452     if (node->condition()) {
   453         __ bind(&test);
   454         visitForTest(node->condition(), &header, true);
   455     } else {
   456         __ jump(&header);
   457     }
   458 
   459     __ bind(&join);
   460 
   461     if (node->scope())
   462         unwindTo(node->scope()->enclosing());
   463     assert(__ stackDepth() == 0);
   464 }
   465 
   466 void
   467 BytecodeCompiler::visit(WhileStatement *node)
   468 {
   469     Label header, join;
   470 
   471     __ bind(&header);
   472 
   473     LoopScope loop(scope_, &join, &header, &loop_);
   474 
   475     if (node->token() == TOK_WHILE) {
   476         visitForTest(node->condition(), &join, false);
   477         node->body()->accept(this);
   478         __ jump(&header);
   479     } else {
   480         node->body()->accept(this);
   481         visitForTest(node->condition(), &header, true);
   482     }
   483 
   484     __ bind(&join);
   485 }
   486 
   487 void
   488 BytecodeCompiler::visit(BreakStatement *node)
   489 {
   490     unwindTo(loop_->scope());
   491     __ jump(loop_->break_());
   492 }
   493 
   494 void
   495 BytecodeCompiler::visit(ContinueStatement *node)
   496 {
   497     unwindTo(loop_->scope());
   498     __ jump(loop_->continue_());
   499 }
   500 
   501 void
   502 BytecodeCompiler::visit(BlockStatement *node)
   503 {
   504     AutoEnterScope blockScope(this, node->scope());
   505 
   506     recordLifoSlot(node->scope());
   507 
   508     for (size_t i = 0; i < node->statements()->length(); i++) {
   509         Statement *statement = node->statements()->at(i);
   510         statement->accept(this);
   511         assert(__ stackDepth() == 0);
   512     }
   513 
   514     // We don't bother emitting an "unwind" instruction for function scopes,
   515     // since this is taken care of by the calling convention.
   516     if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   517         unwindTo(node->scope()->enclosing());
   518 }
   519 
   520 void
   521 BytecodeCompiler::visit(IntegerLiteral *node)
   522 {
   523     __ int_(node->value());
   524 }
   525 
   526 void
   527 BytecodeCompiler::visit(FloatLiteral *node)
   528 {
   529     __ float_((float)node->value());
   530 }
   531 
   532 static inline ArrayMap *
   533 BuildArrayMap(Zone *zone, Handle<Type> type)
   534 {
   535     Local<ArrayMap> contained(zone);
   536     if (type->levels() > 1) {
   537         Local<Type> containedType(zone, type->contained());
   538         contained = BuildArrayMap(zone, containedType);
   539         if (!contained)
   540             return NULL;
   541     }
   542 
   543     return ArrayMap::New(zone, type, contained);
   544 }
   545 
   546 void
   547 BytecodeCompiler::visit(StringLiteral *node)
   548 {
   549     Local<Type> type(zone_, node->type());
   550     Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
   551     if (!map)
   552         return;
   553 
   554     Local<Array> array(zone_, Array::New(zone_, map, node->string()->length(), Heap::Tenure_Old));
   555     if (!array)
   556         return;
   557 
   558     assert(array->nelements() >= node->string()->length());
   559     memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
   560 
   561     __ object(array);
   562 }
   563 
   564 void
   565 BytecodeCompiler::visit(VariableDeclaration *node)
   566 {
   567     Variable *var = node->variable();
   568     assert(var->location() == Variable::STACK);
   569     
   570     Local<Type> type(zone_, var->type());
   571     if (type->isArray()) {
   572         Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
   573         __ newarray_lifo(map);
   574 
   575         if (node->initialization()) {
   576             node->initialization()->accept(this);
   577             __ arraycopy();
   578         }
   579     } else {
   580         if (node->initialization()) {
   581             node->initialization()->accept(this);
   582         } else {
   583             if (!node->postDimensions())
   584                 __ int_(0);
   585         }
   586     }
   587     __ setlocal(var);
   588     __ pop();
   589 
   590     locals_->set(zone_, var->slot(), var->type());
   591 }
   592 
   593 void
   594 BytecodeCompiler::visit(CallExpression *node)
   595 {
   596     Local<Type> funType(zone_, node->callee()->type());
   597 
   598     for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
   599         Expression *arg = node->arguments()->at(i);
   600 
   601         // We need to compute a reference if the parameter was in the form:
   602         //  f(&a)
   603         // Note this form does not allow: f({})
   604         // 
   605         // We also need to compute references for all variadic native
   606         // arguments, but arrays and references are already in the
   607         // appropriate form.
   608         Local<Type> given(zone_, arg->type());
   609         bool mustPushReference = false;
   610         if (i >= funType->parameters()->length()) {
   611             assert(funType->isNative() && funType->isNativeVariadic());
   612             mustPushReference = !given->isArray() && !given->isReference();
   613         } else if (funType->parameterAt(i)->isReference()) {
   614             mustPushReference = !given->isReference();
   615         }
   616 
   617         // If a native is passed to a native, it must only be one level deep.
   618         assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
   619 
   620         if (mustPushReference) {
   621             if (arg->isNameProxy()) {
   622                 // :TODO: test with functions and globals
   623                 // Compute a reference to the name.
   624                 Variable *var = arg->toNameProxy()->binding()->toVariable();
   625                 __ newref(var);
   626             } else if (arg->isIndexExpression()) {
   627                 IndexExpression *expr = arg->toIndexExpression();
   628                 expr->left()->accept(this);
   629                 expr->right()->accept(this);
   630                 __ bounds();
   631                 __ arrayref_lifo();
   632             } else {
   633                 // We don't know how to, or can't, build a direct reference to
   634                 // this type. Make an indirect one, by taking the top of the
   635                 // stack and boxing it up.
   636                 arg->accept(this);
   637                 __ slotref_lifo();
   638             }
   639         } else {
   640             arg->accept(this);
   641         }
   642     }
   643 
   644     NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
   645 
   646     if (fun->isNative())
   647         __ callnative(fun->slot(), node->arguments()->length());
   648     else
   649         __ callglobal(fun->slot());
   650     __ drop(node->arguments()->length());
   651 }
   652 
   653 void
   654 BytecodeCompiler::visit(IfStatement *node)
   655 {
   656     if (!node->ifFalse()) {
   657         Label fail;
   658         visitForTest(node->condition(), &fail, false);
   659         node->ifTrue()->accept(this);
   660         __ bind(&fail);
   661     } else {
   662         Label fail, join;
   663         visitForTest(node->condition(), &fail, false);
   664         node->ifTrue()->accept(this);
   665         __ jump(&join);
   666         __ bind(&fail);
   667         node->ifFalse()->accept(this);
   668         __ bind(&join);
   669     }
   670 }
   671 
   672 void
   673 BytecodeCompiler::visit(FunctionStatement *node)
   674 {
   675     if (node->fun()->isNative()) {
   676         assert(!moduleData_->natives->at(node->fun()->slot()));
   677 
   678         Local<Type> type(zone_, node->fun()->type());
   679         Local<String> name(zone_, node->fun()->name());
   680         Local<Native> native(zone_, Native::New(zone_, type, name));
   681         if (!native)
   682             return;
   683 
   684         moduleData_->natives->set(zone_, node->fun()->slot(), native);
   685         return;
   686     }
   687 
   688     // If the function has no body, then it's just a declaration.
   689     if (!node->body()) {
   690         assert(node->fun()->isForward() || node->fun()->isPublic());
   691         return;
   692     }
   693 
   694     BytecodeCompiler child(zone_, tree_, moduleData_);
   695     Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
   696     if (!fun)
   697         return;
   698     
   699     assert(!moduleData_->module->getFunction(node->fun()->slot()));
   700     moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
   701 }
   702 
   703 void
   704 BytecodeCompiler::visit(EnumStatement *node)
   705 {
   706     // :TODO: eventually, we'll export these.
   707 }
   708 
   709 Function *
   710 BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
   711 {
   712     // Note: No need to record a life slot here, since it's part of the Frame.
   713     AutoEnterScope functionScope(this, node->scope());
   714 
   715     locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
   716 
   717     node->body()->accept(this);
   718 
   719     __ stop();
   720 
   721     if (__ oom() || zone_->hasPendingException())
   722         return NULL;
   723 
   724     Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
   725     if (!bytes)
   726         return NULL;
   727     memcpy(bytes->raw(), __ buffer(), __ length());
   728 
   729     unsigned nargs = node->scope()->numArguments();
   730     Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
   731     if (!args)
   732         return NULL;
   733 
   734     for (size_t i = 0; i < node->scope()->numArguments(); i++)
   735         args->set(zone_, i, node->scope()->getArgument(i)->type());
   736 
   737     for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
   738         assert(locals_->at(i));
   739 
   740     Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
   741     if (!objects)
   742         return NULL;
   743 
   744     for (size_t i = 0; i < __ objects()->length(); i++)
   745         objects->set(zone_, i, *(__ objects()->at(i)));
   746 
   747     Local<ByteArray> safepoints(zone_);
   748 
   749     // If any stack slots hold gc pointers at potential failure points in the
   750     // bytecode, record them now. We do this by building a list of tuples;
   751     // each tuple contains the pc offset, and a bitset containing which stack
   752     // slots must be scanned by the gc.
   753     if (__ oopRecords()->length()) {
   754         size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
   755         size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
   756         safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
   757         if (!safepoints)
   758             return NULL;
   759 
   760         Address cursor = safepoints->raw();
   761         for (size_t i = 0; i < __ oopRecords()->length(); i++) {
   762             OopRecord *record = __ oopRecords()->at(i);
   763             assert(record->depth <= __ maxStackDepth());
   764 
   765             *reinterpret_cast<unsigned *>(cursor) = record->offset;
   766 
   767             unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
   768             for (unsigned i = 0; i < record->depth; i++)
   769                 bits[i / 8] |= (1 << (i % 8));
   770 
   771             cursor += bytesPerSafepoint;
   772         }
   773 
   774         assert(cursor == safepoints->raw() + gcmapSize);
   775     }
   776 
   777     Local<Code> code(zone_, Code::New(zone_, bytes, locals_, objects, __ maxStackDepth(),
   778                      moduleData_->module, safepoints));
   779     if (!code)
   780         return NULL;
   781 
   782     Local<Type> type(zone_, node->fun()->type());
   783     Local<String> name(zone_, node->fun()->name());
   784     Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
   785     if (!fun)
   786         return NULL;
   787 
   788     // If this function had a forward, export it as a named public.
   789     if (node->fun()->isPublic()) {
   790         assert(node->fun()->isPublic());
   791         ScopedRoot<Function> root(fun);
   792         if (!root)
   793             return NULL;
   794         if (!moduleData_->publics.append(root))
   795             return NULL;
   796     }
   797 
   798     Disassemble(code, stdout);
   799     
   800     return fun;
   801 }
   802 
   803 Module *
   804 BytecodeCompiler::compile()
   805 {
   806     ModuleData moduleData;
   807 
   808     moduleData_ = &moduleData;
   809     moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
   810 
   811     if (!moduleData_)
   812         return NULL;
   813     
   814     moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
   815     if (!moduleData_->natives)
   816         return NULL;
   817 
   818     for (size_t i = 0; i < tree_->statements()->length(); i++) {
   819         Statement *statement = tree_->statements()->at(i);
   820         statement->accept(this);
   821     }
   822 
   823     if (zone_->hasPendingException())
   824         return NULL;
   825 
   826 #ifndef NDEBUG
   827     for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
   828         assert(moduleData_->module->getFunction(i));
   829     for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
   830         assert(moduleData_->natives->at(i));
   831 #endif
   832 
   833     if (moduleData_->publics.length()) {
   834         Local<Function> fun(zone_);
   835         Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
   836                                Heap::Tenure_Old));
   837         if (!list)
   838             return NULL;
   839 
   840         for (size_t i = 0; i < moduleData_->publics.length(); i++)
   841             list->set(zone_, i, moduleData_->publics[i]);
   842 
   843         moduleData_->module->setPublics(list);
   844     }
   845 
   846     moduleData_->module->setNatives(moduleData_->natives);
   847 
   848     return moduleData_->module;
   849 }