Chromium Code Reviews| Index: src/interpreter/bytecode-generator.cc |
| diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
| index d5fa0d0bc0fabf1bd920e75f93acfaeaff290dc7..56d0292109523d4dc75bab0bdc535e5df11addb2 100644 |
| --- a/src/interpreter/bytecode-generator.cc |
| +++ b/src/interpreter/bytecode-generator.cc |
| @@ -743,7 +743,6 @@ void BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) { |
| VisitGeneratorPrologue(); |
| } |
| - // Build function context only if there are context allocated variables. |
|
neis
2016/09/02 12:06:07
This comment was not quite right: a scope may not
|
| if (scope()->NeedsContext()) { |
| // Push a new inner context scope for the function. |
| VisitNewLocalFunctionContext(); |
|
neis
2016/09/02 12:06:07
I'm not happy with this name, as it can also creat
adamk
2016/09/02 17:51:51
BuildNewContext?
rmcilroy
2016/09/05 11:36:07
Could we do a rename pass on all the context creat
|
| @@ -940,7 +939,8 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { |
| break; |
| } |
| case VariableLocation::MODULE: |
| - UNREACHABLE(); |
| + // Nothing to do here. |
| + break; |
| } |
| } |
| @@ -980,7 +980,11 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { |
| break; |
| } |
| case VariableLocation::MODULE: |
| - UNREACHABLE(); |
| + DCHECK(variable->mode() == LET); |
| + VisitForAccumulatorValue(decl->fun()); |
| + VisitVariableAssignment(variable, Token::INIT, |
| + FeedbackVectorSlot::Invalid()); |
| + break; |
| } |
| } |
| @@ -1986,8 +1990,21 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
| builder()->LoadLookupSlot(variable->name(), typeof_mode); |
| break; |
| } |
| - case VariableLocation::MODULE: |
| - UNREACHABLE(); |
| + case VariableLocation::MODULE: { |
| + ModuleDescriptor* descriptor = scope()->GetModuleScope()->module(); |
| + if (variable->IsExport()) { |
| + auto it = descriptor->regular_exports().find(variable->raw_name()); |
| + DCHECK(it != descriptor->regular_exports().end()); |
| + Register export_name = register_allocator()->NewRegister(); |
| + builder() |
| + ->LoadLiteral(it->second->export_name->string()) |
| + .StoreAccumulatorInRegister(export_name) |
| + .CallRuntime(Runtime::kLoadModuleExport, export_name, 1); |
| + } else { |
| + UNIMPLEMENTED(); |
| + } |
| + break; |
| + } |
| } |
| execution_result()->SetResultInAccumulator(); |
| } |
| @@ -2185,8 +2202,33 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
| builder()->StoreLookupSlot(variable->name(), language_mode()); |
| break; |
| } |
| - case VariableLocation::MODULE: |
| - UNREACHABLE(); |
| + case VariableLocation::MODULE: { |
| + DCHECK(IsDeclaredVariableMode(mode)); |
| + |
| + if (mode == CONST && op != Token::INIT) { |
| + builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0); |
| + break; |
| + } |
| + |
| + // If we don't throw above, we know that we're dealing with an |
| + // export because imports are const and we do not generate initializing |
| + // assignments for them. |
| + DCHECK(variable->IsExport()); |
| + |
| + ModuleDescriptor* mod = scope()->GetModuleScope()->module(); |
| + auto it = mod->regular_exports().find(variable->raw_name()); |
| + DCHECK(it != mod->regular_exports().end()); |
| + |
| + register_allocator()->PrepareForConsecutiveAllocations(2); |
| + Register export_name = register_allocator()->NextConsecutiveRegister(); |
| + Register value = register_allocator()->NextConsecutiveRegister(); |
| + builder() |
| + ->StoreAccumulatorInRegister(value) |
| + .LoadLiteral(it->second->export_name->string()) |
| + .StoreAccumulatorInRegister(export_name) |
| + .CallRuntime(Runtime::kStoreModuleExport, export_name, 2); |
| + break; |
| + } |
| } |
| } |
| @@ -3143,8 +3185,26 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() { |
| AccumulatorResultScope accumulator_execution_result(this); |
| Scope* scope = this->scope(); |
| - // Allocate a new local context. |
| - if (scope->is_script_scope()) { |
| + // Create the appropriate context. |
| + if (scope->is_module_scope()) { |
| + // We don't need to do anything for the outer script scope. |
| + DCHECK(scope->outer_scope()->is_script_scope()); |
| + |
| + RegisterAllocationScope register_scope(this); |
| + Register module = register_allocator()->NewRegister(); |
| + Register closure = register_allocator()->NewRegister(); |
| + Register scope_info = register_allocator()->NewRegister(); |
| + DCHECK(Register::AreContiguous(module, closure, scope_info)); |
|
rmcilroy
2016/09/05 11:36:07
Please use PrepareForConsecutiveAllocations / Next
|
| + // A JSFunction representing a module is called with the module object as |
| + // its sole argument, which we pass on to PushModuleContext. |
| + builder() |
| + ->MoveRegister(builder()->Parameter(1), module) |
| + .LoadAccumulatorWithRegister(Register::function_closure()) |
| + .StoreAccumulatorInRegister(closure) |
|
rmcilroy
2016/09/05 11:36:07
.MoveRegister(Register::function_closure(), closur
|
| + .LoadLiteral(scope->scope_info()) |
| + .StoreAccumulatorInRegister(scope_info) |
| + .CallRuntime(Runtime::kPushModuleContext, module, 3); |
| + } else if (scope->is_script_scope()) { |
|
rmcilroy
2016/09/05 11:36:07
nit - could we do script scope first.
|
| RegisterAllocationScope register_scope(this); |
| Register closure = register_allocator()->NewRegister(); |
| Register scope_info = register_allocator()->NewRegister(); |
| @@ -3292,8 +3352,7 @@ void BytecodeGenerator::VisitFunctionClosureForContext() { |
| AccumulatorResultScope accumulator_execution_result(this); |
| DeclarationScope* closure_scope = |
| execution_context()->scope()->GetClosureScope(); |
| - if (closure_scope->is_script_scope() || |
| - closure_scope->is_module_scope()) { |
| + if (closure_scope->is_script_scope()) { |
| // Contexts nested in the native context have a canonical empty function as |
| // their closure, not the anonymous closure containing the global code. |
| Register native_context = register_allocator()->NewRegister(); |
| @@ -3309,7 +3368,8 @@ void BytecodeGenerator::VisitFunctionClosureForContext() { |
| builder()->LoadContextSlot(execution_context()->reg(), |
| Context::CLOSURE_INDEX); |
| } else { |
| - DCHECK(closure_scope->is_function_scope()); |
| + DCHECK(closure_scope->is_function_scope() || |
| + closure_scope->is_module_scope()); |
| builder()->LoadAccumulatorWithRegister(Register::function_closure()); |
| } |
| execution_result()->SetResultInAccumulator(); |