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