Clean up array ops to match the new GET/SETFIELD style.
1 /* vim: set ts=4 sw=4 tw=99 et:
3 * Copyright (C) 2012 David Anderson
5 * This file is part of JITCraft.
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)
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.
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/.
20 #include "BytecodeCompiler.h"
27 #include "Environments.h"
32 typedef BytecodeEmitter::Label Label;
36 BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
39 emitter_(zone->pool()),
47 static inline TokenKind
48 ToCompare(Expression *expr)
50 if (expr->isBinaryExpression()) {
51 BinaryExpression *b = expr->toBinaryExpression();
52 if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
54 } else if (expr->isUnaryExpression()) {
55 UnaryExpression *u = expr->toUnaryExpression();
56 if (u->token() == TOK_NOT)
63 CompareTokenToJump(TokenKind kind)
77 assert(kind == TOK_LE);
83 TokenToOpcode(TokenKind kind)
119 assert(kind == TOK_BITXOR);
125 BytecodeCompiler::recordLifoSlot(Scope *scope)
130 if (Variable *var = scope->lifoSlot()) {
131 locals_->set(zone_, var->slot(), var->type());
132 __ savelifo(var->slot());
137 BytecodeCompiler::unwindTo(Scope *scope)
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())
147 __ unwindlifo(var->slot());
151 BytecodeCompiler::visit(NameProxy *name)
153 switch (name->binding()->kind()) {
154 case BoundName::VARIABLE:
156 Variable *var = name->binding()->toVariable();
158 if (var->location() == Variable::STACK) {
160 assert(!name->type()->isReference());
161 } else if (var->location() == Variable::ENVIRONMENT) {
164 assert(var->location() == Variable::PARAMETER);
167 // If this argument is actually a reference, dereference it now.
168 if (var->type()->isReference())
169 __ getref(var->type()->contained());
174 case BoundName::FUNCTION:
176 NamedFunction *fun = name->binding()->toNamedFunction();
178 __ getmodule_fn(fun->slot());
184 NamedConstant *constant = name->binding()->toNamedConstant();
185 __ int_(constant->value().toInt());
192 BytecodeCompiler::visit(ExpressionStatement *node)
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())
202 BytecodeCompiler::visit(Assignment *node)
204 Local<Type> type(zone_, node->expression()->type());
206 // The first step is three sub-steps:
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.
213 if (node->lvalue()->isNameProxy()) {
214 NameProxy *proxy = node->lvalue()->toNameProxy();
215 Variable *var = proxy->binding()->toVariable();
218 if (var->type()->isReference() ||
219 var->type()->isArray() ||
220 var->type()->isStruct())
225 // Get the value if needed.
226 if (node->token() != TOK_ASSIGN) {
227 // += etc is not allowed on arrays.
228 assert(!var->type()->isArray());
230 if (var->type()->isReference()) {
232 __ getref(var->type()->contained());
237 } else if (node->lvalue()->isFieldExpression()) {
238 FieldExpression *expr = node->lvalue()->toFieldExpression();
239 __ note_position(expr->pos());
241 expr->left()->accept(this);
243 if (node->token() != TOK_ASSIGN)
246 if (node->token() != TOK_ASSIGN || (type->isStruct() || type->isArray()))
247 __ getfield(expr->fieldIndex(), expr->type());
249 IndexExpression *index = node->lvalue()->toIndexExpression();
250 __ note_position(index->pos());
252 // Note: Eventually, watch out for a hole here. An expression like:
254 // (a[4] = (5, a = []))
256 // Could shrink array, so we need to either bind a[i] to a Reference,
257 // or keep the bounds check near the set. This is just a semantic
259 index->left()->accept(this);
260 index->right()->accept(this);
262 if (node->token() != TOK_ASSIGN)
265 if (node->token() != TOK_ASSIGN || (type->isStruct() || type->isArray())) {
267 __ getelem(index->type());
271 if (node->token() == TOK_ASSIGN) {
272 node->expression()->accept(this);
274 visitForALU(node->type(), node->expression());
276 TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
277 __ note_position(node->pos());
278 __ binary(TokenToOpcode(alu));
282 if (type->isArray()) {
283 // Unlike references, which can only be computed from a NamePRoxy,
284 // arrays can be computed from multiple lvalue types.
285 __ note_position(node->pos());
287 } else if (type->isStruct()) {
288 // Structs have value semantics, so emit a full copy. We don't break
289 // this down into u-ops, to avoid unnecessary bytecode explosion.
290 __ note_position(node->pos());
292 } else if (node->lvalue()->isNameProxy()) {
293 NameProxy *proxy = node->lvalue()->toNameProxy();
294 Variable *var = proxy->binding()->toVariable();
296 if (var->type()->isReference())
297 __ setref(var->type()->contained());
300 } else if (node->lvalue()->isFieldExpression()) {
301 FieldExpression *expr = node->lvalue()->toFieldExpression();
302 __ setfield(expr->fieldIndex(), expr->type());
304 IndexExpression *index = node->lvalue()->toIndexExpression();
305 // :TODO: get rid of the BOUNDS instruction, embed it in g/setelem*?
306 // We can't emit it here because the stack is slightly out of position.
308 __ setelem(index->type());
313 BytecodeCompiler::visit(IncDecExpression *node)
315 // In the postfix case, the logic looks like:
317 // (2) Dup -> REF REF
318 // (3) Fetch -> REF VAL
319 // (4) Swap -> VAL REF
320 // (5) Pick -> VAL REF VAL
321 // (6) Add -> VAL REF VAL+1
322 // (7) Store -> VAL VAL+1
325 // In the prefix case, the logic looks like:
327 // (2) Dup -> REF REF
328 // (3) Fetch -> REF VAL
331 // (6) Add -> REF VAL+1
332 // (7) Store -> VAL+1
335 // This is squirrely enough such that we don't bother sharing too much
338 // Note: We simulate a "Pick" operation with a dup2+pop.
340 // This is steps (1) to (5).
341 Expression *expr = node->expression();
342 if (expr->isNameProxy()) {
343 NameProxy *proxy = expr->toNameProxy();
344 Variable *var = proxy->binding()->toVariable();
347 if (var->type()->isReference() || var->type()->isArray())
351 if (var->type()->isReference()) {
353 __ getref(node->type());
354 if (node->postfix()) {
359 assert(!var->type()->isArray());
364 } else if (expr->isFieldExpression()) {
365 FieldExpression *field = expr->toFieldExpression();
367 field->left()->accept(this);
369 __ getfield(field->fieldIndex(), field->type());
371 if (node->postfix()) {
372 // The stack looks like this now:
374 __ swap(); // VALUE OBJECT
375 __ pick2(); // VALUE OBJECT VALUE
378 IndexExpression *index = expr->toIndexExpression();
379 __ note_position(index->pos());
381 index->left()->accept(this);
382 index->right()->accept(this);
384 assert(!node->type()->isArray());
387 __ getelem(node->type());
389 if (node->postfix()) {
390 // The stack looks like this now:
393 // So we must use a PICK operation to rotate the stack into position.
394 __ roll3(); // INDEX VALUE ARRAY
395 __ roll3(); // VALUE ARRAY INDEX
396 __ pick3(); // VALUE ARRAY INDEX VALUE
401 if (node->type()->isFloat()) {
404 assert(node->type()->isInt32());
408 __ note_position(node->pos());
409 if (node->token() == TOK_INCREMENT)
415 if (expr->isNameProxy()) {
416 NameProxy *proxy = expr->toNameProxy();
417 Variable *var = proxy->binding()->toVariable();
419 if (var->type()->isReference())
420 __ setref(node->type());
423 } else if (expr->isFieldExpression()) {
424 FieldExpression *field = expr->toFieldExpression();
425 __ setfield(field->fieldIndex(), field->type());
427 assert(expr->isIndexExpression());
428 __ setelem(node->type());
437 BytecodeCompiler::visitForALU(Type *needed, Expression *node)
440 if (needed->isFloat() && !node->type()->isFloat())
443 assert(needed->primitive() == node->type()->primitive());
447 GetCoercionType(TokenKind tok, Type *left, Type *right)
455 BytecodeCompiler::visit(UnaryExpression *node)
457 Local<Type> out(zone_, ((Expression *)node)->type());
459 switch (node->token()) {
462 Local<Type> type(zone_, node->expression()->type());
463 node->expression()->accept(this);
474 Local<Type> type(zone_, node->expression()->type());
475 node->expression()->accept(this);
486 Local<Type> from(zone_, node->expression()->type());
488 node->expression()->accept(this);
489 if (!from->isFloat() && out->isFloat())
491 else if (from->isFloat() && !out->isFloat())
497 assert(node->token() == TOK_TILDE);
498 node->expression()->accept(this);
505 BytecodeCompiler::visit(BinaryExpression *node)
507 if (node->token() == TOK_AND || node->token() == TOK_OR) {
508 Label success, failure, done;
509 visitForTest(node, &success, &failure, &success);
512 __ drop(1); // Otherwise, the stack depth will be +1 too much.
520 Local<Type> leftType(zone_, node->left()->type());
521 Local<Type> rightType(zone_, node->right()->type());
522 Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
524 visitForALU(coerce, node->left());
525 visitForALU(coerce, node->right());
527 Opcode op = TokenToOpcode(node->token());
528 if (node->type()->isFloat())
529 op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
531 __ note_position(node->pos());
536 BytecodeCompiler::visit(IndexExpression *node)
538 node->left()->accept(this);
539 node->right()->accept(this);
540 __ note_position(node->pos());
542 __ getelem(node->type());
546 BytecodeCompiler::visit(FieldExpression *node)
548 node->left()->accept(this);
549 __ getfield(node->fieldIndex(), node->type());
553 BytecodeCompiler::visit(ReturnStatement *node)
555 if (node->expression()) {
556 node->expression()->accept(this);
564 BytecodeCompiler::visitForTest(Expression *expression,
569 TokenKind token = ToCompare(expression);
570 if (token == TOK_EOF || token == TOK_NOT) {
571 if (token == TOK_EOF)
572 expression->accept(this);
574 expression->toUnaryExpression()->expression()->accept(this);
576 bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
578 Opcode op = jumpOnTrue ? OP_JT : OP_JF;
579 if (expression->type()->isFloat())
580 op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
582 if (fallthrough == falseBranch)
583 __ j(op, trueBranch);
585 __ j(op, falseBranch);
589 BinaryExpression *binary = expression->toBinaryExpression();
591 if (token == TOK_AND || token == TOK_OR) {
593 if (token == TOK_AND)
594 visitForTest(binary->left(), &next, falseBranch, &next);
596 visitForTest(binary->left(), trueBranch, &next, &next);
598 visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
602 Opcode op = CompareTokenToJump(token);
603 if (fallthrough == trueBranch)
606 Local<Type> leftType(zone_, binary->left()->type());
607 Local<Type> rightType(zone_, binary->right()->type());
608 Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
610 visitForALU(coerce, binary->left());
611 visitForALU(coerce, binary->right());
612 if (coerce->isFloat())
613 op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
615 if (fallthrough == trueBranch)
616 __ j(op, falseBranch);
618 __ j(op, trueBranch);
622 BytecodeCompiler::visit(ForStatement *node)
624 AutoEnterScope forScope(this, node->scope());
626 recordLifoSlot(node->scope());
629 LoopScope loop(scope_, &join, &update, &loop_);
631 if (node->initialization())
632 node->initialization()->accept(this);
635 if (node->condition())
639 node->body()->accept(this);
643 node->update()->accept(this);
645 if (node->condition()) {
647 visitForTest(node->condition(), &header, &join, &join);
655 unwindTo(node->scope()->enclosing());
656 assert(__ stackDepth() == 0);
660 BytecodeCompiler::visit(WhileStatement *node)
666 LoopScope loop(scope_, &join, &header, &loop_);
668 if (node->token() == TOK_WHILE) {
671 visitForTest(node->condition(), &body, &join, &body);
673 node->body()->accept(this);
676 node->body()->accept(this);
677 visitForTest(node->condition(), &header, &join, &join);
684 BytecodeCompiler::visit(BreakStatement *node)
686 unwindTo(loop_->scope());
687 __ jump(loop_->break_());
691 BytecodeCompiler::visit(ContinueStatement *node)
693 unwindTo(loop_->scope());
694 __ jump(loop_->continue_());
698 BytecodeCompiler::visit(BlockStatement *node)
700 AutoEnterScope blockScope(this, node->scope());
702 recordLifoSlot(node->scope());
704 for (size_t i = 0; i < node->statements()->length(); i++) {
705 Statement *statement = node->statements()->at(i);
706 statement->accept(this);
707 assert(__ stackDepth() == 0);
710 // We don't bother emitting an "unwind" instruction for function scopes,
711 // since this is taken care of by the calling convention.
712 if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
713 unwindTo(node->scope()->enclosing());
717 BytecodeCompiler::visit(IntegerLiteral *node)
719 __ int_(node->value());
723 BytecodeCompiler::visit(BooleanLiteral *node)
725 if (node->token() == TOK_TRUE)
732 BytecodeCompiler::visit(FloatLiteral *node)
734 __ float_((float)node->value());
737 static inline ArrayMap *
738 BuildArrayMap(Zone *zone, Handle<Type> type)
741 return ArrayMap::cast(type->newMap());
743 Local<ArrayMap> map(zone, ArrayMap::New(zone, type));
747 // Ensure the inner type has an array map if needed.
748 if (type->contained()->isArray()) {
749 Local<Type> contained(zone, type->contained());
750 if (!BuildArrayMap(zone, contained))
754 type->setNewMap(map);
759 BytecodeCompiler::visit(StringLiteral *node)
761 Local<Type> type(zone_, node->type());
762 Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
766 Local<Array> array(zone_, Array::New(zone_, map, node->string()->length(), Heap::Tenure_Old));
770 assert(array->length() >= node->string()->length());
771 memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
773 __ note_position(node->pos());
778 BytecodeCompiler::getEnvSlot(Variable *var)
780 assert(var->scope()->kind() == Scope::GLOBAL);
785 BytecodeCompiler::setEnvSlot(Variable *var)
787 assert(var->scope()->kind() == Scope::GLOBAL);
792 BytecodeCompiler::visit(VariableDeclaration *node)
794 Variable *var = node->variable();
796 Local<Type> type(zone_, var->type());
797 if (type->isArray()) {
798 Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
799 __ note_position(node->pos());
800 if (var->scope()->kind() == Scope::GLOBAL)
801 __ newarray(map, Heap::Tenure_Old);
802 else if (var->needsHeapAllocation())
803 __ newarray(map, Heap::Tenure_Default);
805 __ newarray(map, Heap::Tenure_Stack);
807 if (node->initialization()) {
808 node->initialization()->accept(this);
809 __ note_position(node->pos());
812 } else if (type->isStruct()) {
813 Local<Map> map(zone_, type->newMap());
814 if (var->scope()->kind() == Scope::GLOBAL)
815 __ newstruct(map, Heap::Tenure_Old);
816 else if (var->needsHeapAllocation())
817 __ newstruct(map, Heap::Tenure_Default);
819 __ newstruct(map, Heap::Tenure_Stack);
821 if (node->initialization()) {
822 node->initialization()->accept(this);
824 if (type->isInt32OrEnum() || type->isBool()) {
827 assert(type->isFloat());
833 if (var->location() == Variable::STACK) {
835 locals_->set(zone_, var->slot(), var->type());
837 assert(var->location() == Variable::ENVIRONMENT);
845 BytecodeCompiler::visit(CallExpression *node)
847 Local<Type> funType(zone_, node->callee()->type());
849 // Sniff out natives, which have a specific opcode and are guaranteed to
850 // be called via name proxy.
851 NamedFunction *native = NULL;
852 if (funType->isNative()) {
853 native = node->callee()->toNameProxy()->binding()->toNamedFunction();
856 for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
857 Expression *arg = node->arguments()->at(i);
859 // We need to compute a reference if the parameter was in the form:
861 // Note this form does not allow: f({})
863 // We also need to compute references for all variadic native
864 // arguments, but arrays and references are already in the
866 Local<Type> given(zone_, arg->type());
867 bool mustPushReference = false;
868 if (i >= funType->parameters()->length()) {
869 assert(funType->isNative() && funType->isNativeVariadic());
870 mustPushReference = !given->isArray() && !given->isReference();
871 } else if (funType->parameterAt(i)->isReference()) {
872 mustPushReference = !given->isReference();
875 // If a native is passed to a native, it must only be one level deep.
876 assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
878 if (mustPushReference) {
879 if (arg->isNameProxy()) {
880 // :TODO: test with functions and globals
881 // Compute a reference to the name.
882 Variable *var = arg->toNameProxy()->binding()->toVariable();
883 __ note_position(node->pos());
885 } else if (arg->isIndexExpression()) {
886 IndexExpression *expr = arg->toIndexExpression();
887 expr->left()->accept(this);
888 expr->right()->accept(this);
889 __ note_position(expr->pos());
893 // We don't know how to, or can't, build a direct reference to
894 // this type. Make an indirect one, by taking the top of the
895 // stack and boxing it up.
897 __ note_position(node->pos());
905 __ note_position(node->pos());
907 __ callnative(native->slot(), node->arguments()->length());
908 __ drop(node->arguments()->length());
910 node->callee()->accept(this);
912 __ drop(node->arguments()->length() + 1);
917 BytecodeCompiler::visit(TernaryExpression *node)
919 Label success, failure, join;
921 visitForTest(node->condition(), &success, &failure, &success);
923 node->left()->accept(this);
927 node->right()->accept(this);
932 BytecodeCompiler::visit(IfStatement *node)
935 if (!node->ifFalse()) {
938 visitForTest(node->condition(), &success, &join, &success);
940 node->ifTrue()->accept(this);
944 visitForTest(node->condition(), &success, &next, &success);
946 node->ifTrue()->accept(this);
949 node->ifFalse()->accept(this);
956 BytecodeCompiler::visit(FunctionStatement *node)
958 if (!node->fun()->used())
961 if (node->fun()->isNative()) {
962 assert(!moduleData_->natives->at(node->fun()->slot()));
964 Local<Type> type(zone_, node->fun()->type());
965 Local<String> name(zone_, node->fun()->name());
966 Local<Native> native(zone_, Native::New(zone_, type, name));
970 moduleData_->natives->set(zone_, node->fun()->slot(), native);
974 // If the function has no body, then it's just a declaration.
976 assert(node->fun()->isForward() || node->fun()->isPublic());
980 BytecodeCompiler child(zone_, tree_, moduleData_);
981 Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
985 assert(!moduleData_->module->getFunction(node->fun()->slot()));
986 moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
990 BytecodeCompiler::visit(EnumStatement *node)
992 // :TODO: eventually, we'll export these.
996 BytecodeCompiler::visit(StructureStatement *node)
1001 BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
1003 // STOP doubles as RETURNVOID.
1006 if (__ oom() || zone_->hasPendingException())
1009 Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
1012 memcpy(bytes->raw(), __ buffer(), __ length());
1014 for (size_t i = 0; i < scope->maxContainedLocals(); i++)
1015 assert(locals_->at(i));
1017 Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
1021 for (size_t i = 0; i < __ objects()->length(); i++)
1022 objects->set(zone_, i, *(__ objects()->at(i)));
1024 Local<ByteArray> safepoints(zone_);
1026 // If any stack slots hold gc pointers at potential failure points in the
1027 // bytecode, record them now. We do this by building a list of tuples;
1028 // each tuple contains the pc offset, and a bitset containing which stack
1029 // slots must be scanned by the gc.
1030 if (__ oopRecords()->length()) {
1031 size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
1032 size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
1033 safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
1037 Address cursor = safepoints->raw();
1038 for (size_t i = 0; i < __ oopRecords()->length(); i++) {
1039 OopRecord *record = __ oopRecords()->at(i);
1040 assert(record->depth <= __ maxStackDepth());
1042 *reinterpret_cast<unsigned *>(cursor) = record->offset;
1044 unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
1045 for (unsigned i = 0; i < record->depth; i++)
1046 bits[i / 8] |= (1 << (i % 8));
1048 cursor += bytesPerSafepoint;
1051 assert(cursor == safepoints->raw() + gcmapSize);
1054 Local<ByteArray> sourcemap(zone_);
1055 if (__ sourcemapLength()) {
1056 sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
1060 memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
1063 Local<Code> code(zone_);
1065 code = Code::New(zone_,
1070 moduleData_->module,
1078 BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
1080 // Note: No need to record a life slot here, since it's part of the Frame.
1081 AutoEnterScope functionScope(this, node->scope());
1083 // Set the initial line, because line mappings are deltas.
1084 __ setFirstLine(node->pos().line);
1085 locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
1087 node->body()->accept(this);
1089 unsigned nargs = node->scope()->numArguments();
1090 Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
1094 for (size_t i = 0; i < node->scope()->numArguments(); i++)
1095 args->set(zone_, i, node->scope()->getArgument(i)->type());
1098 Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
1102 Local<Type> type(zone_, node->fun()->type());
1103 Local<String> name(zone_, node->fun()->name());
1104 Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
1108 // If this function had a forward, export it as a named public.
1109 if (node->fun()->isPublic()) {
1110 assert(node->fun()->isPublic());
1111 ScopedRoot<Function> root(fun);
1114 if (!moduleData_->publics.append(root))
1119 Disassemble(code, stdout);
1126 BytecodeCompiler::compile()
1128 AutoEnterScope scope(this, tree_->scope());
1130 ModuleData moduleData;
1132 moduleData_ = &moduleData;
1133 moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
1138 moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
1139 if (!moduleData_->natives)
1142 for (size_t i = 0; i < tree_->statements()->length(); i++) {
1143 Statement *statement = tree_->statements()->at(i);
1144 statement->accept(this);
1147 if (zone_->hasPendingException())
1151 for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
1152 assert(moduleData_->module->getFunction(i));
1153 for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
1154 assert(moduleData_->natives->at(i));
1157 if (moduleData_->publics.length()) {
1158 Local<Function> fun(zone_);
1159 Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
1164 for (size_t i = 0; i < moduleData_->publics.length(); i++)
1165 list->set(zone_, i, moduleData_->publics[i]);
1167 moduleData_->module->setPublics(list);
1170 moduleData_->module->setNatives(moduleData_->natives);
1172 if (scope_->numEnvironmentVars()) {
1173 Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
1177 Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
1181 moduleData_->module->setEnvironment(environment);
1184 Local<Code> code(zone_, compileCode(tree_->scope(), 1));
1188 Disassemble(code, stdout);
1190 moduleData_->module->setCode(code);
1192 return moduleData_->module;