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