Index: src/full-codegen.cc |
diff --git a/src/full-codegen.cc b/src/full-codegen.cc |
index 9592e0afa21c45aec364adb1e1557fae8f4d0551..01d9bd0714be04b4ff4de2f7a66e98da32c67349 100644 |
--- a/src/full-codegen.cc |
+++ b/src/full-codegen.cc |
@@ -86,6 +86,10 @@ void BreakableStatementChecker::VisitModuleUrl(ModuleUrl* module) { |
} |
+void BreakableStatementChecker::VisitModuleStatement(ModuleStatement* stmt) { |
+} |
+ |
+ |
void BreakableStatementChecker::VisitBlock(Block* stmt) { |
} |
@@ -582,16 +586,137 @@ void FullCodeGenerator::DoTest(const TestContext* context) { |
} |
+void FullCodeGenerator::AllocateModules(ZoneList<Declaration*>* declarations) { |
+ ASSERT(scope_->is_global_scope()); |
+ |
+ for (int i = 0; i < declarations->length(); i++) { |
+ ModuleDeclaration* declaration = declarations->at(i)->AsModuleDeclaration(); |
+ if (declaration != NULL) { |
+ ModuleLiteral* module = declaration->module()->AsModuleLiteral(); |
+ if (module != NULL) { |
+ Comment cmnt(masm_, "[ Link nested modules"); |
+ Scope* scope = module->body()->scope(); |
+ Interface* interface = scope->interface(); |
+ ASSERT(interface->IsModule() && interface->IsFrozen()); |
+ |
+ interface->Allocate(scope->module_var()->index()); |
+ |
+ // Set up module context. |
+ ASSERT(scope->interface()->Index() >= 0); |
+ __ Push(Smi::FromInt(scope->interface()->Index())); |
+ __ Push(scope->GetScopeInfo()); |
+ __ CallRuntime(Runtime::kPushModuleContext, 2); |
+ StoreToFrameField(StandardFrameConstants::kContextOffset, |
+ context_register()); |
+ |
+ AllocateModules(scope->declarations()); |
+ |
+ // Pop module context. |
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
+ // Update local stack frame context field. |
+ StoreToFrameField(StandardFrameConstants::kContextOffset, |
+ context_register()); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+// Modules have their own local scope, represented by their own context. |
+// Module instance objects have an accessor for every export that forwards |
+// access to the respective slot from the module's context. (Exports that are |
+// modules themselves, however, are simple data properties.) |
+// |
+// All modules have a _hosting_ scope/context, which (currently) is the |
+// (innermost) enclosing global scope. To deal with recursion, nested modules |
+// are hosted by the same scope as global ones. |
+// |
+// For every (global or nested) module literal, the hosting context has an |
+// internal slot that points directly to the respective module context. This |
+// enables quick access to (statically resolved) module members by 2-dimensional |
+// access through the hosting context. For example, |
+// |
+// module A { |
+// let x; |
+// module B { let y; } |
+// } |
+// module C { let z; } |
+// |
+// allocates contexts as follows: |
+// |
+// [header| .A | .B | .C | A | C ] (global) |
+// | | | |
+// | | +-- [header| z ] (module) |
+// | | |
+// | +------- [header| y ] (module) |
+// | |
+// +------------ [header| x | B ] (module) |
+// |
+// Here, .A, .B, .C are the internal slots pointing to the hosted module |
+// contexts, whereas A, B, C hold the actual instance objects (note that every |
+// module context also points to the respective instance object through its |
+// extension slot in the header). |
+// |
+// To deal with arbitrary recursion and aliases between modules, |
+// they are created and initialized in several stages. Each stage applies to |
+// all modules in the hosting global scope, including nested ones. |
+// |
+// 1. Allocate: for each module _literal_, allocate the module contexts and |
+// respective instance object and wire them up. This happens in the |
+// PushModuleContext runtime function, as generated by AllocateModules |
+// (invoked by VisitDeclarations in the hosting scope). |
+// |
+// 2. Bind: for each module _declaration_ (i.e. literals as well as aliases), |
+// assign the respective instance object to respective local variables. This |
+// happens in VisitModuleDeclaration, and uses the instance objects created |
+// in the previous stage. |
+// For each module _literal_, this phase also constructs a module descriptor |
+// for the next stage. This happens in VisitModuleLiteral. |
+// |
+// 3. Populate: invoke the DeclareModules runtime function to populate each |
+// _instance_ object with accessors for it exports. This is generated by |
+// DeclareModules (invoked by VisitDeclarations in the hosting scope again), |
+// and uses the descriptors generated in the previous stage. |
+// |
+// 4. Initialize: execute the module bodies (and other code) in sequence. This |
+// happens by the separate statements generated for module bodies. To reenter |
+// the module scopes properly, the parser inserted ModuleStatements. |
+ |
void FullCodeGenerator::VisitDeclarations( |
ZoneList<Declaration*>* declarations) { |
+ Handle<FixedArray> saved_modules = modules_; |
+ int saved_module_index = module_index_; |
ZoneList<Handle<Object> >* saved_globals = globals_; |
ZoneList<Handle<Object> > inner_globals(10, zone()); |
globals_ = &inner_globals; |
+ if (scope_->num_modules() != 0) { |
+ // This is a scope hosting modules. Allocate a descriptor array to pass |
+ // to the runtime for initialization. |
+ Comment cmnt(masm_, "[ Allocate modules"); |
+ ASSERT(scope_->is_global_scope()); |
+ modules_ = |
+ isolate()->factory()->NewFixedArray(scope_->num_modules(), TENURED); |
+ module_index_ = 0; |
+ |
+ // Generate code for allocating all modules, including nested ones. |
+ // The allocated contexts are stored in internal variables in this scope. |
+ AllocateModules(declarations); |
+ } |
+ |
AstVisitor::VisitDeclarations(declarations); |
+ |
+ if (scope_->num_modules() != 0) { |
+ // Initialize modules from descriptor array. |
+ ASSERT(module_index_ == modules_->length()); |
+ DeclareModules(modules_); |
+ modules_ = saved_modules; |
+ module_index_ = saved_module_index; |
+ } |
+ |
if (!globals_->is_empty()) { |
// Invoke the platform-dependent code generator to do the actual |
- // declaration the global functions and variables. |
+ // declaration of the global functions and variables. |
Handle<FixedArray> array = |
isolate()->factory()->NewFixedArray(globals_->length(), TENURED); |
for (int i = 0; i < globals_->length(); ++i) |
@@ -604,19 +729,23 @@ void FullCodeGenerator::VisitDeclarations( |
void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) { |
- // Allocate a module context statically. |
Block* block = module->body(); |
Scope* saved_scope = scope(); |
scope_ = block->scope(); |
- Interface* interface = module->interface(); |
- Handle<JSModule> instance = interface->Instance(); |
+ Interface* interface = scope_->interface(); |
Comment cmnt(masm_, "[ ModuleLiteral"); |
SetStatementPosition(block); |
+ ASSERT(!modules_.is_null()); |
+ ASSERT(module_index_ < modules_->length()); |
+ int index = module_index_++; |
+ |
// Set up module context. |
- __ Push(instance); |
- __ CallRuntime(Runtime::kPushModuleContext, 1); |
+ ASSERT(interface->Index() >= 0); |
+ __ Push(Smi::FromInt(interface->Index())); |
+ __ Push(Smi::FromInt(0)); |
+ __ CallRuntime(Runtime::kPushModuleContext, 2); |
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); |
{ |
@@ -624,6 +753,11 @@ void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) { |
VisitDeclarations(scope_->declarations()); |
} |
+ // Populate the module description. |
+ Handle<ModuleInfo> description = |
+ ModuleInfo::Create(isolate(), interface, scope_); |
+ modules_->set(index, *description); |
+ |
scope_ = saved_scope; |
// Pop module context. |
LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
@@ -644,8 +778,20 @@ void FullCodeGenerator::VisitModulePath(ModulePath* module) { |
} |
-void FullCodeGenerator::VisitModuleUrl(ModuleUrl* decl) { |
- // TODO(rossberg) |
+void FullCodeGenerator::VisitModuleUrl(ModuleUrl* module) { |
+ // TODO(rossberg): dummy allocation for now. |
+ Scope* scope = module->body()->scope(); |
+ Interface* interface = scope_->interface(); |
+ |
+ ASSERT(interface->IsModule() && interface->IsFrozen()); |
+ ASSERT(!modules_.is_null()); |
+ ASSERT(module_index_ < modules_->length()); |
+ interface->Allocate(scope->module_var()->index()); |
+ int index = module_index_++; |
+ |
+ Handle<ModuleInfo> description = |
+ ModuleInfo::Create(isolate(), interface, scope_); |
+ modules_->set(index, *description); |
} |
@@ -904,37 +1050,28 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { |
// Push a block context when entering a block with block scoped variables. |
if (stmt->scope() != NULL) { |
scope_ = stmt->scope(); |
- if (scope_->is_module_scope()) { |
- // If this block is a module body, then we have already allocated and |
- // initialized the declarations earlier. Just push the context. |
- ASSERT(!scope_->interface()->Instance().is_null()); |
- __ Push(scope_->interface()->Instance()); |
- __ CallRuntime(Runtime::kPushModuleContext, 1); |
- StoreToFrameField( |
- StandardFrameConstants::kContextOffset, context_register()); |
- } else { |
- { Comment cmnt(masm_, "[ Extend block context"); |
- Handle<ScopeInfo> scope_info = scope_->GetScopeInfo(); |
- int heap_slots = |
- scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS; |
- __ Push(scope_info); |
- PushFunctionArgumentForContextAllocation(); |
- if (heap_slots <= FastNewBlockContextStub::kMaximumSlots) { |
- FastNewBlockContextStub stub(heap_slots); |
- __ CallStub(&stub); |
- } else { |
- __ CallRuntime(Runtime::kPushBlockContext, 2); |
- } |
- |
- // Replace the context stored in the frame. |
- StoreToFrameField(StandardFrameConstants::kContextOffset, |
- context_register()); |
- } |
- { Comment cmnt(masm_, "[ Declarations"); |
- VisitDeclarations(scope_->declarations()); |
+ ASSERT(!scope_->is_module_scope()); |
+ { Comment cmnt(masm_, "[ Extend block context"); |
+ Handle<ScopeInfo> scope_info = scope_->GetScopeInfo(); |
+ int heap_slots = scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS; |
+ __ Push(scope_info); |
+ PushFunctionArgumentForContextAllocation(); |
+ if (heap_slots <= FastNewBlockContextStub::kMaximumSlots) { |
+ FastNewBlockContextStub stub(heap_slots); |
+ __ CallStub(&stub); |
+ } else { |
+ __ CallRuntime(Runtime::kPushBlockContext, 2); |
} |
+ |
+ // Replace the context stored in the frame. |
+ StoreToFrameField(StandardFrameConstants::kContextOffset, |
+ context_register()); |
+ } |
+ { Comment cmnt(masm_, "[ Declarations"); |
+ VisitDeclarations(scope_->declarations()); |
} |
} |
+ |
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
VisitStatements(stmt->statements()); |
scope_ = saved_scope; |
@@ -951,6 +1088,26 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { |
} |
+void FullCodeGenerator::VisitModuleStatement(ModuleStatement* stmt) { |
+ Comment cmnt(masm_, "[ Module context"); |
+ |
+ __ Push(Smi::FromInt(stmt->proxy()->interface()->Index())); |
+ __ Push(Smi::FromInt(0)); |
+ __ CallRuntime(Runtime::kPushModuleContext, 2); |
+ StoreToFrameField( |
+ StandardFrameConstants::kContextOffset, context_register()); |
+ |
+ Scope* saved_scope = scope_; |
+ scope_ = stmt->body()->scope(); |
+ VisitStatements(stmt->body()->statements()); |
+ scope_ = saved_scope; |
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX); |
+ // Update local stack frame context field. |
+ StoreToFrameField(StandardFrameConstants::kContextOffset, |
+ context_register()); |
+} |
+ |
+ |
void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { |
Comment cmnt(masm_, "[ ExpressionStatement"); |
SetStatementPosition(stmt); |