Index: src/arm/full-codegen-arm.cc |
=================================================================== |
--- src/arm/full-codegen-arm.cc (revision 11348) |
+++ src/arm/full-codegen-arm.cc (working copy) |
@@ -266,11 +266,11 @@ |
// For named function expressions, declare the function name as a |
// constant. |
if (scope()->is_function_scope() && scope()->function() != NULL) { |
- VariableProxy* proxy = scope()->function(); |
- ASSERT(proxy->var()->mode() == CONST || |
- proxy->var()->mode() == CONST_HARMONY); |
- ASSERT(proxy->var()->location() != Variable::UNALLOCATED); |
- EmitDeclaration(proxy, proxy->var()->mode(), NULL); |
+ VariableDeclaration* function = scope()->function(); |
+ ASSERT(function->proxy()->var()->mode() == CONST || |
+ function->proxy()->var()->mode() == CONST_HARMONY); |
+ ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); |
+ VisitVariableDeclaration(function); |
} |
VisitDeclarations(scope()->declarations()); |
} |
@@ -780,62 +780,51 @@ |
} |
-void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
- VariableMode mode, |
- FunctionLiteral* function) { |
+void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { |
+ // The variable in the declaration always resides in the current function |
+ // context. |
+ ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
+ if (FLAG_debug_code) { |
+ // Check that we're not inside a with or catch context. |
+ __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); |
+ __ CompareRoot(r1, Heap::kWithContextMapRootIndex); |
+ __ Check(ne, "Declaration in with context."); |
+ __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); |
+ __ Check(ne, "Declaration in catch context."); |
+ } |
+} |
+ |
+ |
+void FullCodeGenerator::VisitVariableDeclaration( |
+ VariableDeclaration* declaration) { |
// If it was not possible to allocate the variable at compile time, we |
// need to "declare" it at runtime to make sure it actually exists in the |
// local context. |
+ VariableProxy* proxy = declaration->proxy(); |
+ VariableMode mode = declaration->mode(); |
Variable* variable = proxy->var(); |
- bool binding_needs_init = (function == NULL) && |
- (mode == CONST || mode == CONST_HARMONY || mode == LET); |
+ bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; |
switch (variable->location()) { |
case Variable::UNALLOCATED: |
- ++global_count_; |
+ globals_->Add(variable->name()); |
+ globals_->Add(variable->binding_needs_init() |
+ ? isolate()->factory()->the_hole_value() |
+ : isolate()->factory()->undefined_value()); |
break; |
case Variable::PARAMETER: |
case Variable::LOCAL: |
- if (function != NULL) { |
- Comment cmnt(masm_, "[ Declaration"); |
- VisitForAccumulatorValue(function); |
- __ str(result_register(), StackOperand(variable)); |
- } else if (binding_needs_init) { |
- Comment cmnt(masm_, "[ Declaration"); |
+ if (hole_init) { |
+ Comment cmnt(masm_, "[ VariableDeclaration"); |
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
__ str(ip, StackOperand(variable)); |
} |
break; |
case Variable::CONTEXT: |
- // The variable in the decl always resides in the current function |
- // context. |
- ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
- if (FLAG_debug_code) { |
- // Check that we're not inside a with or catch context. |
- __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); |
- __ CompareRoot(r1, Heap::kWithContextMapRootIndex); |
- __ Check(ne, "Declaration in with context."); |
- __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); |
- __ Check(ne, "Declaration in catch context."); |
- } |
- if (function != NULL) { |
- Comment cmnt(masm_, "[ Declaration"); |
- VisitForAccumulatorValue(function); |
- __ str(result_register(), ContextOperand(cp, variable->index())); |
- int offset = Context::SlotOffset(variable->index()); |
- // We know that we have written a function, which is not a smi. |
- __ RecordWriteContextSlot(cp, |
- offset, |
- result_register(), |
- r2, |
- kLRHasBeenSaved, |
- kDontSaveFPRegs, |
- EMIT_REMEMBERED_SET, |
- OMIT_SMI_CHECK); |
- PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
- } else if (binding_needs_init) { |
- Comment cmnt(masm_, "[ Declaration"); |
+ if (hole_init) { |
+ Comment cmnt(masm_, "[ VariableDeclaration"); |
+ EmitDebugCheckDeclarationContext(variable); |
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
__ str(ip, ContextOperand(cp, variable->index())); |
// No write barrier since the_hole_value is in old space. |
@@ -844,13 +833,11 @@ |
break; |
case Variable::LOOKUP: { |
- Comment cmnt(masm_, "[ Declaration"); |
+ Comment cmnt(masm_, "[ VariableDeclaration"); |
__ mov(r2, Operand(variable->name())); |
// Declaration nodes are always introduced in one of four modes. |
- ASSERT(mode == VAR || |
- mode == CONST || |
- mode == CONST_HARMONY || |
- mode == LET); |
+ ASSERT(mode == VAR || mode == LET || |
+ mode == CONST || mode == CONST_HARMONY); |
PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) |
? READ_ONLY : NONE; |
__ mov(r1, Operand(Smi::FromInt(attr))); |
@@ -858,11 +845,7 @@ |
// Note: For variables we must not push an initial value (such as |
// 'undefined') because we may have a (legal) redeclaration and we |
// must not destroy the current value. |
- if (function != NULL) { |
- __ Push(cp, r2, r1); |
- // Push initial value for function declaration. |
- VisitForStackValue(function); |
- } else if (binding_needs_init) { |
+ if (hole_init) { |
__ LoadRoot(r0, Heap::kTheHoleValueRootIndex); |
__ Push(cp, r2, r1, r0); |
} else { |
@@ -876,6 +859,122 @@ |
} |
+void FullCodeGenerator::VisitFunctionDeclaration( |
+ FunctionDeclaration* declaration) { |
+ VariableProxy* proxy = declaration->proxy(); |
+ Variable* variable = proxy->var(); |
+ switch (variable->location()) { |
+ case Variable::UNALLOCATED: { |
+ globals_->Add(variable->name()); |
+ Handle<SharedFunctionInfo> function = |
+ Compiler::BuildFunctionInfo(declaration->fun(), script()); |
+ // Check for stack-overflow exception. |
+ if (function.is_null()) return SetStackOverflow(); |
+ globals_->Add(function); |
+ break; |
+ } |
+ |
+ case Variable::PARAMETER: |
+ case Variable::LOCAL: { |
+ Comment cmnt(masm_, "[ FunctionDeclaration"); |
+ VisitForAccumulatorValue(declaration->fun()); |
+ __ str(result_register(), StackOperand(variable)); |
+ break; |
+ } |
+ |
+ case Variable::CONTEXT: { |
+ Comment cmnt(masm_, "[ FunctionDeclaration"); |
+ EmitDebugCheckDeclarationContext(variable); |
+ VisitForAccumulatorValue(declaration->fun()); |
+ __ str(result_register(), ContextOperand(cp, variable->index())); |
+ int offset = Context::SlotOffset(variable->index()); |
+ // We know that we have written a function, which is not a smi. |
+ __ RecordWriteContextSlot(cp, |
+ offset, |
+ result_register(), |
+ r2, |
+ kLRHasBeenSaved, |
+ kDontSaveFPRegs, |
+ EMIT_REMEMBERED_SET, |
+ OMIT_SMI_CHECK); |
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
+ break; |
+ } |
+ |
+ case Variable::LOOKUP: { |
+ Comment cmnt(masm_, "[ FunctionDeclaration"); |
+ __ mov(r2, Operand(variable->name())); |
+ __ mov(r1, Operand(Smi::FromInt(NONE))); |
+ __ Push(cp, r2, r1); |
+ // Push initial value for function declaration. |
+ VisitForStackValue(declaration->fun()); |
+ __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
+ break; |
+ } |
+ } |
+} |
+ |
+ |
+void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { |
+ VariableProxy* proxy = declaration->proxy(); |
+ Variable* variable = proxy->var(); |
+ Handle<JSModule> instance = declaration->module()->interface()->Instance(); |
+ ASSERT(!instance.is_null()); |
+ |
+ switch (variable->location()) { |
+ case Variable::UNALLOCATED: { |
+ Comment cmnt(masm_, "[ ModuleDeclaration"); |
+ globals_->Add(variable->name()); |
+ globals_->Add(instance); |
+ Visit(declaration->module()); |
+ break; |
+ } |
+ |
+ case Variable::CONTEXT: { |
+ Comment cmnt(masm_, "[ ModuleDeclaration"); |
+ EmitDebugCheckDeclarationContext(variable); |
+ __ mov(r1, Operand(instance)); |
+ __ str(r1, ContextOperand(cp, variable->index())); |
+ Visit(declaration->module()); |
+ break; |
+ } |
+ |
+ case Variable::PARAMETER: |
+ case Variable::LOCAL: |
+ case Variable::LOOKUP: |
+ UNREACHABLE(); |
+ } |
+} |
+ |
+ |
+void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) { |
+ VariableProxy* proxy = declaration->proxy(); |
+ Variable* variable = proxy->var(); |
+ switch (variable->location()) { |
+ case Variable::UNALLOCATED: |
+ // TODO(rossberg) |
+ break; |
+ |
+ case Variable::CONTEXT: { |
+ Comment cmnt(masm_, "[ ImportDeclaration"); |
+ EmitDebugCheckDeclarationContext(variable); |
+ // TODO(rossberg) |
+ break; |
+ } |
+ |
+ case Variable::PARAMETER: |
+ case Variable::LOCAL: |
+ case Variable::LOOKUP: |
+ UNREACHABLE(); |
+ } |
+} |
+ |
+ |
+void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { |
+ // TODO(rossberg) |
+} |
+ |
+ |
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
// Call the runtime to declare the globals. |
// The context is the first argument. |
@@ -4446,7 +4545,8 @@ |
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { |
Scope* declaration_scope = scope()->DeclarationScope(); |
- if (declaration_scope->is_global_scope()) { |
+ if (declaration_scope->is_global_scope() || |
+ declaration_scope->is_module_scope()) { |
// Contexts nested in the global context have a canonical empty function |
// as their closure, not the anonymous closure containing the global |
// code. Pass a smi sentinel and let the runtime look up the empty |