| 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);
|
|
|