Revision: 11331
Author: [email protected]
Date: Mon Apr 16 04:48:20 2012
Log: Refactoring of code generation for declarations, in preparation
for modules.
Do proper dispatch on declaration type instead of mingling together
different code generation paths. Once we add more declaration forms,
this is more scalable.
In separate steps, I'd like to (1) clean up the logic for DeclareGlobal,
and (2) try to reduce the special handling of the name function var if
possible.
[email protected]
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com/9704054
http://code.google.com/p/v8/source/detail?r=11331
Modified:
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/full-codegen.cc
/branches/bleeding_edge/src/full-codegen.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/parser.cc
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/scopeinfo.cc
/branches/bleeding_edge/src/scopes.cc
/branches/bleeding_edge/src/scopes.h
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Mon Apr 2 08:53:38
2012
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Mon Apr 16 04:48:20
2012
@@ -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,15 +780,30 @@
}
-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_;
@@ -796,46 +811,17 @@
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 +830,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 +842,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 {
@@ -874,6 +854,107 @@
}
}
}
+
+
+void FullCodeGenerator::VisitFunctionDeclaration(
+ FunctionDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++global_count_;
+ 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();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++global_count_;
+ break;
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ // TODO(rossberg): initialize module instance object
+ 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:
+ ++global_count_;
+ 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) {
=======================================
--- /branches/bleeding_edge/src/full-codegen.cc Tue Mar 27 05:26:58 2012
+++ /branches/bleeding_edge/src/full-codegen.cc Mon Apr 16 04:48:20 2012
@@ -611,31 +611,6 @@
global_count_ = save_global_count;
}
-
-
-void FullCodeGenerator::VisitVariableDeclaration(VariableDeclaration*
decl) {
- EmitDeclaration(decl->proxy(), decl->mode(), NULL);
-}
-
-
-void FullCodeGenerator::VisitFunctionDeclaration(FunctionDeclaration*
decl) {
- EmitDeclaration(decl->proxy(), decl->mode(), decl->fun());
-}
-
-
-void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* decl) {
- EmitDeclaration(decl->proxy(), decl->mode(), NULL);
-}
-
-
-void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) {
- EmitDeclaration(decl->proxy(), decl->mode(), NULL);
-}
-
-
-void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
- // TODO(rossberg)
-}
void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) {
=======================================
--- /branches/bleeding_edge/src/full-codegen.h Tue Mar 27 04:21:27 2012
+++ /branches/bleeding_edge/src/full-codegen.h Mon Apr 16 04:48:20 2012
@@ -413,12 +413,9 @@
Label* if_true,
Label* if_false);
- // Platform-specific code for a variable, constant, or function
- // declaration. Functions have an initial value.
- // Increments global_count_ for unallocated variables.
- void EmitDeclaration(VariableProxy* proxy,
- VariableMode mode,
- FunctionLiteral* function);
+ // If enabled, emit debug code for checking that the current context is
+ // neither a with nor a catch context.
+ void EmitDebugCheckDeclarationContext(Variable* variable);
// Platform-specific code for checking the stack limit at the back edge
of
// a loop.
@@ -548,12 +545,8 @@
Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); }
bool is_native() { return info_->is_native(); }
- bool is_classic_mode() {
- return language_mode() == CLASSIC_MODE;
- }
- LanguageMode language_mode() {
- return function()->language_mode();
- }
+ bool is_classic_mode() { return language_mode() == CLASSIC_MODE; }
+ LanguageMode language_mode() { return function()->language_mode(); }
FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return scope_; }
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Wed Apr 11 06:40:55 2012
+++ /branches/bleeding_edge/src/hydrogen.cc Mon Apr 16 04:48:20 2012
@@ -2550,7 +2550,7 @@
// Handle implicit declaration of the function name in named function
// expressions before other declarations.
if (scope->is_function_scope() && scope->function() != NULL) {
- HandleDeclaration(scope->function(), CONST, NULL, NULL);
+ VisitVariableDeclaration(scope->function());
}
VisitDeclarations(scope->declarations());
AddSimulate(AstNode::kDeclarationsId);
@@ -7161,20 +7161,15 @@
void HGraphBuilder::VisitDeclarations(ZoneList<Declaration*>*
declarations) {
int length = declarations->length();
- int global_count = 0;
- for (int i = 0; i < declarations->length(); i++) {
- Declaration* decl = declarations->at(i);
- FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration();
- HandleDeclaration(decl->proxy(),
- decl->mode(),
- fun_decl != NULL ? fun_decl->fun() : NULL,
- &global_count);
- }
+ int save_global_count = global_count_;
+ global_count_ = 0;
+
+ AstVisitor::VisitDeclarations(declarations);
// Batch declare global functions and variables.
- if (global_count > 0) {
+ if (global_count_ > 0) {
Handle<FixedArray> array =
- isolate()->factory()->NewFixedArray(2 * global_count, TENURED);
+ isolate()->factory()->NewFixedArray(2 * global_count_, TENURED);
for (int j = 0, i = 0; i < length; i++) {
Declaration* decl = declarations->at(i);
Variable* var = decl->proxy()->var();
@@ -7210,40 +7205,35 @@
flags);
AddInstruction(result);
}
+
+ global_count_ = save_global_count;
}
-void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
- VariableMode mode,
- FunctionLiteral* function,
- int* global_count) {
+void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration*
declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ VariableMode mode = declaration->mode();
Variable* var = proxy->var();
- bool binding_needs_init =
- (mode == CONST || mode == CONST_HARMONY || mode == LET);
+ bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
switch (var->location()) {
case Variable::UNALLOCATED:
- ++(*global_count);
+ ++global_count_;
return;
case Variable::PARAMETER:
case Variable::LOCAL:
+ if (hole_init) {
+ HValue* value = graph()->GetConstantHole();
+ environment()->Bind(var, value);
+ }
+ break;
case Variable::CONTEXT:
- if (binding_needs_init || function != NULL) {
- HValue* value = NULL;
- if (function != NULL) {
- CHECK_ALIVE(VisitForValue(function));
- value = Pop();
- } else {
- value = graph()->GetConstantHole();
- }
- if (var->IsContextSlot()) {
- HValue* context = environment()->LookupContext();
- HStoreContextSlot* store = new HStoreContextSlot(
- context, var->index(), HStoreContextSlot::kNoCheck, value);
- AddInstruction(store);
- if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
- } else {
- environment()->Bind(var, value);
- }
+ if (hole_init) {
+ HValue* value = graph()->GetConstantHole();
+ HValue* context = environment()->LookupContext();
+ HStoreContextSlot* store = new HStoreContextSlot(
+ context, var->index(), HStoreContextSlot::kNoCheck, value);
+ AddInstruction(store);
+ if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
}
break;
case Variable::LOOKUP:
@@ -7252,28 +7242,76 @@
}
-void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
- UNREACHABLE();
+void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration*
declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* var = proxy->var();
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ ++global_count_;
+ return;
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ CHECK_ALIVE(VisitForValue(declaration->fun()));
+ HValue* value = Pop();
+ environment()->Bind(var, value);
+ break;
+ }
+ case Variable::CONTEXT: {
+ CHECK_ALIVE(VisitForValue(declaration->fun()));
+ HValue* value = Pop();
+ HValue* context = environment()->LookupContext();
+ HStoreContextSlot* store = new HStoreContextSlot(
+ context, var->index(), HStoreContextSlot::kNoCheck, value);
+ AddInstruction(store);
+ if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
+ break;
+ }
+ case Variable::LOOKUP:
+ return Bailout("unsupported lookup slot in declaration");
+ }
}
-void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
- UNREACHABLE();
+void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* declaration)
{
+ VariableProxy* proxy = declaration->proxy();
+ Variable* var = proxy->var();
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ ++global_count_;
+ return;
+ case Variable::CONTEXT: {
+ // TODO(rossberg)
+ break;
+ }
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::LOOKUP:
+ UNREACHABLE();
+ }
}
-void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) {
- UNREACHABLE();
+void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* declaration)
{
+ VariableProxy* proxy = declaration->proxy();
+ Variable* var = proxy->var();
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ ++global_count_;
+ return;
+ case Variable::CONTEXT: {
+ // TODO(rossberg)
+ break;
+ }
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::LOOKUP:
+ UNREACHABLE();
+ }
}
-void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) {
- UNREACHABLE();
-}
-
-
-void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) {
- UNREACHABLE();
+void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* declaration)
{
+ // TODO(rossberg)
}
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Wed Apr 11 06:40:55 2012
+++ /branches/bleeding_edge/src/hydrogen.h Mon Apr 16 04:48:20 2012
@@ -913,11 +913,6 @@
INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
#undef INLINE_FUNCTION_GENERATOR_DECLARATION
- void HandleDeclaration(VariableProxy* proxy,
- VariableMode mode,
- FunctionLiteral* function,
- int* global_count);
-
void VisitDelete(UnaryOperation* expr);
void VisitVoid(UnaryOperation* expr);
void VisitTypeof(UnaryOperation* expr);
@@ -1167,6 +1162,7 @@
HBasicBlock* current_block_;
int inlined_count_;
+ int global_count_;
Zone* zone_;
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue Mar 27
04:21:27 2012
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Mon Apr 16
04:48:20 2012
@@ -262,11 +262,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());
}
@@ -756,15 +756,30 @@
}
-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.
+ __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
+ __ cmp(ebx, isolate()->factory()->with_context_map());
+ __ Check(not_equal, "Declaration in with context.");
+ __ cmp(ebx, isolate()->factory()->catch_context_map());
+ __ Check(not_equal, "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_;
@@ -772,44 +787,17 @@
case Variable::PARAMETER:
case Variable::LOCAL:
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ mov(StackOperand(variable), result_register());
- } else if (binding_needs_init) {
- Comment cmnt(masm_, "[ Declaration");
+ if (hole_init) {
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ mov(StackOperand(variable),
Immediate(isolate()->factory()->the_hole_value()));
}
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.
- __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
- __ cmp(ebx, isolate()->factory()->with_context_map());
- __ Check(not_equal, "Declaration in with context.");
- __ cmp(ebx, isolate()->factory()->catch_context_map());
- __ Check(not_equal, "Declaration in catch context.");
- }
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ mov(ContextOperand(esi, variable->index()), result_register());
- // We know that we have written a function, which is not a smi.
- __ RecordWriteContextSlot(esi,
- Context::SlotOffset(variable->index()),
- result_register(),
- ecx,
- 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);
__ mov(ContextOperand(esi, variable->index()),
Immediate(isolate()->factory()->the_hole_value()));
// No write barrier since the hole value is in old space.
@@ -818,14 +806,12 @@
break;
case Variable::LOOKUP: {
- Comment cmnt(masm_, "[ Declaration");
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ push(esi);
__ push(Immediate(variable->name()));
- // Declaration nodes are always introduced in one of four modes.
- ASSERT(mode == VAR ||
- mode == CONST ||
- mode == CONST_HARMONY ||
- mode == LET);
+ // VariableDeclaration nodes are always introduced in one of four
modes.
+ ASSERT(mode == VAR || mode == LET ||
+ mode == CONST || mode == CONST_HARMONY);
PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY)
? READ_ONLY : NONE;
__ push(Immediate(Smi::FromInt(attr)));
@@ -833,9 +819,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) {
- VisitForStackValue(function);
- } else if (binding_needs_init) {
+ if (hole_init) {
__ push(Immediate(isolate()->factory()->the_hole_value()));
} else {
__ push(Immediate(Smi::FromInt(0))); // Indicates no initial
value.
@@ -845,6 +829,104 @@
}
}
}
+
+
+void FullCodeGenerator::VisitFunctionDeclaration(
+ FunctionDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++global_count_;
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ VisitForAccumulatorValue(declaration->fun());
+ __ mov(StackOperand(variable), result_register());
+ break;
+ }
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ VisitForAccumulatorValue(declaration->fun());
+ __ mov(ContextOperand(esi, variable->index()), result_register());
+ // We know that we have written a function, which is not a smi.
+ __ RecordWriteContextSlot(esi,
+ Context::SlotOffset(variable->index()),
+ result_register(),
+ ecx,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+ break;
+ }
+
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ __ push(esi);
+ __ push(Immediate(variable->name()));
+ __ push(Immediate(Smi::FromInt(NONE)));
+ VisitForStackValue(declaration->fun());
+ __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ break;
+ }
+ }
+}
+
+
+void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration*
declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++global_count_;
+ break;
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ // TODO(rossberg): initialize module instance object
+ 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:
+ ++global_count_;
+ 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) {
=======================================
--- /branches/bleeding_edge/src/parser.cc Thu Mar 15 06:02:21 2012
+++ /branches/bleeding_edge/src/parser.cc Mon Apr 16 04:48:20 2012
@@ -4460,15 +4460,15 @@
Variable* fvar = NULL;
Token::Value fvar_init_op = Token::INIT_CONST;
if (type == FunctionLiteral::NAMED_EXPRESSION) {
- VariableMode fvar_mode;
- if (is_extended_mode()) {
- fvar_mode = CONST_HARMONY;
- fvar_init_op = Token::INIT_CONST_HARMONY;
- } else {
- fvar_mode = CONST;
- }
- fvar =
- top_scope_->DeclareFunctionVar(function_name, fvar_mode,
factory());
+ if (is_extended_mode()) fvar_init_op = Token::INIT_CONST_HARMONY;
+ VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST;
+ fvar = new(zone()) Variable(top_scope_,
+ function_name, fvar_mode, true /* is valid LHS */,
+ Variable::NORMAL, kCreatedInitialized);
+ VariableProxy* proxy = factory()->NewVariableProxy(fvar);
+ VariableDeclaration* fvar_declaration =
+ factory()->NewVariableDeclaration(proxy, fvar_mode, top_scope_);
+ top_scope_->DeclareFunctionVar(fvar_declaration);
}
// Determine whether the function will be lazily compiled.
=======================================
--- /branches/bleeding_edge/src/runtime.cc Wed Apr 11 06:40:55 2012
+++ /branches/bleeding_edge/src/runtime.cc Mon Apr 16 04:48:20 2012
@@ -1289,9 +1289,13 @@
// We have to declare a global const property. To capture we only
// assign to it when evaluating the assignment for "const x =
// <expr>" the initial value is the hole.
- bool is_const_property = value->IsTheHole();
- bool is_function_declaration = false;
- if (value->IsUndefined() || is_const_property) {
+ bool is_var = value->IsUndefined();
+ bool is_const = value->IsTheHole();
+ bool is_function = value->IsSharedFunctionInfo();
+ bool is_module = value->IsJSObject();
+ ASSERT(is_var + is_const + is_function + is_module == 1);
+
+ if (is_var || is_const) {
// Lookup the property in the global object, and don't set the
// value of the variable if the property is already there.
LookupResult lookup(isolate);
@@ -1299,41 +1303,34 @@
if (lookup.IsProperty()) {
// We found an existing property. Unless it was an interceptor
// that claims the property is absent, skip this declaration.
- if (lookup.type() != INTERCEPTOR) {
- continue;
- }
+ if (lookup.type() != INTERCEPTOR) continue;
PropertyAttributes attributes =
global->GetPropertyAttribute(*name);
- if (attributes != ABSENT) {
- continue;
- }
+ if (attributes != ABSENT) continue;
// Fall-through and introduce the absent property by using
// SetProperty.
}
- } else {
- is_function_declaration = true;
+ } else if (is_function) {
// Copy the function and update its context. Use it as value.
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>::cast(value);
Handle<JSFunction> function =
- isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
- context,
- TENURED);
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ shared, context, TENURED);
value = function;
}
LookupResult lookup(isolate);
global->LocalLookup(*name, &lookup);
- // Compute the property attributes. According to ECMA-262, section
- // 13, page 71, the property must be read-only and
- // non-deletable. However, neither SpiderMonkey nor KJS creates the
- // property as read-only, so we don't either.
+ // Compute the property attributes. According to ECMA-262,
+ // the property must be non-configurable except in eval.
int attr = NONE;
- if (!DeclareGlobalsEvalFlag::decode(flags)) {
+ bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
+ if (!is_eval || is_module) {
attr |= DONT_DELETE;
}
bool is_native = DeclareGlobalsNativeFlag::decode(flags);
- if (is_const_property || (is_native && is_function_declaration)) {
+ if (is_const || is_module || (is_native && is_function)) {
attr |= READ_ONLY;
}
@@ -1346,7 +1343,7 @@
// handlers such as "function onload() {}". Firefox does call the
// onload setter in those case and Safari does not. We follow
// Safari for compatibility.
- if (is_function_declaration) {
+ if (is_function || is_module) {
if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
// Do not overwrite READ_ONLY properties.
if (lookup.GetAttributes() & READ_ONLY) {
=======================================
--- /branches/bleeding_edge/src/scopeinfo.cc Thu Nov 24 07:17:04 2011
+++ /branches/bleeding_edge/src/scopeinfo.cc Mon Apr 16 04:48:20 2012
@@ -53,7 +53,7 @@
FunctionVariableInfo function_name_info;
VariableMode function_variable_mode;
if (scope->is_function_scope() && scope->function() != NULL) {
- Variable* var = scope->function()->var();
+ Variable* var = scope->function()->proxy()->var();
if (!var->is_used()) {
function_name_info = UNUSED;
} else if (var->IsContextSlot()) {
@@ -129,8 +129,8 @@
// If present, add the function variable name and its index.
ASSERT(index == scope_info->FunctionNameEntryIndex());
if (has_function_name) {
- int var_index = scope->function()->var()->index();
- scope_info->set(index++, *scope->function()->name());
+ int var_index = scope->function()->proxy()->var()->index();
+ scope_info->set(index++, *scope->function()->proxy()->name());
scope_info->set(index++, Smi::FromInt(var_index));
ASSERT(function_name_info != STACK ||
(var_index == scope_info->StackLocalCount() &&
=======================================
--- /branches/bleeding_edge/src/scopes.cc Thu Apr 12 12:32:29 2012
+++ /branches/bleeding_edge/src/scopes.cc Mon Apr 16 04:48:20 2012
@@ -415,14 +415,20 @@
Variable* Scope::LookupFunctionVar(Handle<String> name,
AstNodeFactory<AstNullVisitor>*
factory) {
- if (function_ != NULL && function_->name().is_identical_to(name)) {
- return function_->var();
+ if (function_ != NULL &&
function_->proxy()->name().is_identical_to(name)) {
+ return function_->proxy()->var();
} else if (!scope_info_.is_null()) {
// If we are backed by a scope info, try to lookup the variable there.
VariableMode mode;
int index = scope_info_->FunctionContextSlotIndex(*name, &mode);
if (index < 0) return NULL;
- Variable* var = DeclareFunctionVar(name, mode, factory);
+ Variable* var = new Variable(
+ this, name, mode, true /* is valid LHS */,
+ Variable::NORMAL, kCreatedInitialized);
+ VariableProxy* proxy = factory->NewVariableProxy(var);
+ VariableDeclaration* declaration =
+ factory->NewVariableDeclaration(proxy, mode, this);
+ DeclareFunctionVar(declaration);
var->AllocateTo(Variable::CONTEXT, index);
return var;
} else {
@@ -794,7 +800,7 @@
// Function name, if any (named function literals, only).
if (function_ != NULL) {
Indent(n1, "// (local) function name: ");
- PrintName(function_->name());
+ PrintName(function_->proxy()->name());
PrintF("\n");
}
@@ -827,7 +833,7 @@
// Print locals.
Indent(n1, "// function var\n");
if (function_ != NULL) {
- PrintVar(n1, function_->var());
+ PrintVar(n1, function_->proxy()->var());
}
Indent(n1, "// temporary vars\n");
@@ -1211,7 +1217,7 @@
// because of the current ScopeInfo implementation (see
// ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
if (function_ != NULL) {
- AllocateNonParameterLocal(function_->var());
+ AllocateNonParameterLocal(function_->proxy()->var());
}
}
@@ -1253,14 +1259,14 @@
int Scope::StackLocalCount() const {
return num_stack_slots() -
- (function_ != NULL && function_->var()->IsStackLocal() ? 1 : 0);
+ (function_ != NULL && function_->proxy()->var()->IsStackLocal() ?
1 : 0);
}
int Scope::ContextLocalCount() const {
if (num_heap_slots() == 0) return 0;
return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
- (function_ != NULL && function_->var()->IsContextSlot() ? 1 : 0);
+ (function_ != NULL && function_->proxy()->var()->IsContextSlot() ?
1 : 0);
}
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/scopes.h Thu Mar 8 05:03:07 2012
+++ /branches/bleeding_edge/src/scopes.h Mon Apr 16 04:48:20 2012
@@ -126,15 +126,9 @@
// Declare the function variable for a function literal. This variable
// is in an intermediate scope between this function scope and the the
// outer scope. Only possible for function scopes; at most one variable.
- template<class Visitor>
- Variable* DeclareFunctionVar(Handle<String> name,
- VariableMode mode,
- AstNodeFactory<Visitor>* factory) {
- ASSERT(is_function_scope() && function_ == NULL);
- Variable* function_var = new Variable(
- this, name, mode, true, Variable::NORMAL, kCreatedInitialized);
- function_ = factory->NewVariableProxy(function_var);
- return function_var;
+ void DeclareFunctionVar(VariableDeclaration* declaration) {
+ ASSERT(is_function_scope());
+ function_ = declaration;
}
// Declare a parameter in this scope. When there are duplicated
@@ -312,9 +306,8 @@
Variable* receiver() { return receiver_; }
// The variable holding the function literal for named function
- // literals, or NULL.
- // Only valid for function scopes.
- VariableProxy* function() const {
+ // literals, or NULL. Only valid for function scopes.
+ VariableDeclaration* function() const {
ASSERT(is_function_scope());
return function_;
}
@@ -446,7 +439,7 @@
// Convenience variable.
Variable* receiver_;
// Function variable, if any; function scopes only.
- VariableProxy* function_;
+ VariableDeclaration* function_;
// Convenience variable; function scopes only.
Variable* arguments_;
// Interface; module scopes only.
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Thu Mar 29 07:04:41
2012
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Mon Apr 16 04:48:20
2012
@@ -257,11 +257,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());
}
@@ -753,15 +753,30 @@
}
-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.
+ __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
+ __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
+ __ Check(not_equal, "Declaration in with context.");
+ __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
+ __ Check(not_equal, "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_;
@@ -769,45 +784,17 @@
case Variable::PARAMETER:
case Variable::LOCAL:
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ movq(StackOperand(variable), result_register());
- } else if (binding_needs_init) {
- Comment cmnt(masm_, "[ Declaration");
+ if (hole_init) {
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ movq(StackOperand(variable), kScratchRegister);
}
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.
- __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
- __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
- __ Check(not_equal, "Declaration in with context.");
- __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
- __ Check(not_equal, "Declaration in catch context.");
- }
- if (function != NULL) {
- Comment cmnt(masm_, "[ Declaration");
- VisitForAccumulatorValue(function);
- __ movq(ContextOperand(rsi, variable->index()), result_register());
- int offset = Context::SlotOffset(variable->index());
- // We know that we have written a function, which is not a smi.
- __ RecordWriteContextSlot(rsi,
- offset,
- result_register(),
- rcx,
- 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(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ movq(ContextOperand(rsi, variable->index()), kScratchRegister);
// No write barrier since the hole value is in old space.
@@ -816,14 +803,12 @@
break;
case Variable::LOOKUP: {
- Comment cmnt(masm_, "[ Declaration");
+ Comment cmnt(masm_, "[ VariableDeclaration");
__ push(rsi);
__ Push(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;
__ Push(Smi::FromInt(attr));
@@ -831,9 +816,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) {
- VisitForStackValue(function);
- } else if (binding_needs_init) {
+ if (hole_init) {
__ PushRoot(Heap::kTheHoleValueRootIndex);
} else {
__ Push(Smi::FromInt(0)); // Indicates no initial value.
@@ -843,6 +826,105 @@
}
}
}
+
+
+void FullCodeGenerator::VisitFunctionDeclaration(
+ FunctionDeclaration* declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++global_count_;
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ VisitForAccumulatorValue(declaration->fun());
+ __ movq(StackOperand(variable), result_register());
+ break;
+ }
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ VisitForAccumulatorValue(declaration->fun());
+ __ movq(ContextOperand(rsi, variable->index()), result_register());
+ int offset = Context::SlotOffset(variable->index());
+ // We know that we have written a function, which is not a smi.
+ __ RecordWriteContextSlot(rsi,
+ offset,
+ result_register(),
+ rcx,
+ kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+ break;
+ }
+
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ FunctionDeclaration");
+ __ push(rsi);
+ __ Push(variable->name());
+ __ Push(Smi::FromInt(NONE));
+ VisitForStackValue(declaration->fun());
+ __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ break;
+ }
+ }
+}
+
+
+void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration*
declaration) {
+ VariableProxy* proxy = declaration->proxy();
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++global_count_;
+ break;
+
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, "[ ModuleDeclaration");
+ EmitDebugCheckDeclarationContext(variable);
+ // TODO(rossberg): initialize module instance object
+ 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:
+ ++global_count_;
+ 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) {
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev