Support declarations of context allocated locals in Crankshaft.

The changes to scopes and parser introduce a VariableProxy
wrapping the function-name variable for function literals.
It seems the easiest way to get an AST id for the HSimulate
after context-slot stores in declarations.
Review URL: http://codereview.chromium.org/7826009

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9112 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
fschneider@chromium.org 2011-09-01 16:33:57 +00:00
parent 1be99a9627
commit 913f444cb7
9 changed files with 81 additions and 39 deletions

View File

@ -688,10 +688,11 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
} }
void FullCodeGenerator::EmitDeclaration(Variable* variable, void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode, Variable::Mode mode,
FunctionLiteral* function) { FunctionLiteral* function) {
Comment cmnt(masm_, "[ Declaration"); Comment cmnt(masm_, "[ Declaration");
Variable* variable = proxy->var();
ASSERT(variable != NULL); // Must have been resolved. ASSERT(variable != NULL); // Must have been resolved.
Slot* slot = variable->AsSlot(); Slot* slot = variable->AsSlot();
ASSERT(slot != NULL); ASSERT(slot != NULL);
@ -729,10 +730,12 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
// We know that we have written a function, which is not a smi. // We know that we have written a function, which is not a smi.
__ mov(r1, Operand(cp)); __ mov(r1, Operand(cp));
__ RecordWrite(r1, Operand(offset), r2, result_register()); __ RecordWrite(r1, Operand(offset), r2, result_register());
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) { } else if (mode == Variable::CONST || mode == Variable::LET) {
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ str(ip, ContextOperand(cp, slot->index())); __ str(ip, ContextOperand(cp, slot->index()));
// No write barrier since the_hole_value is in old space. // No write barrier since the_hole_value is in old space.
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} }
break; break;
@ -767,7 +770,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
void FullCodeGenerator::VisitDeclaration(Declaration* decl) { void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); EmitDeclaration(decl->proxy(), decl->mode(), decl->fun());
} }

View File

@ -403,7 +403,7 @@ class FullCodeGenerator: public AstVisitor {
// Platform-specific code for a variable, constant, or function // Platform-specific code for a variable, constant, or function
// declaration. Functions have an initial value. // declaration. Functions have an initial value.
void EmitDeclaration(Variable* variable, void EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode, Variable::Mode mode,
FunctionLiteral* function); FunctionLiteral* function);

View File

@ -2298,11 +2298,7 @@ HGraph* HGraphBuilder::CreateGraph() {
// Handle implicit declaration of the function name in named function // Handle implicit declaration of the function name in named function
// expressions before other declarations. // expressions before other declarations.
if (scope->is_function_scope() && scope->function() != NULL) { if (scope->is_function_scope() && scope->function() != NULL) {
if (!scope->function()->IsStackAllocated()) { HandleDeclaration(scope->function(), Variable::CONST, NULL);
Bailout("unsupported declaration");
return NULL;
}
environment()->Bind(scope->function(), graph()->GetConstantHole());
} }
VisitDeclarations(scope->declarations()); VisitDeclarations(scope->declarations());
AddSimulate(AstNode::kDeclarationsId); AddSimulate(AstNode::kDeclarationsId);
@ -5822,20 +5818,51 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
void HGraphBuilder::VisitDeclaration(Declaration* decl) { void HGraphBuilder::VisitDeclaration(Declaration* decl) {
// We support only declarations that do not require code generation. HandleDeclaration(decl->proxy(), decl->mode(), decl->fun());
Variable* var = decl->proxy()->var();
if (!var->IsStackAllocated() ||
decl->mode() == Variable::LET) {
return Bailout("unsupported declaration");
} }
if (decl->mode() == Variable::CONST) {
ASSERT(var->IsStackAllocated()); void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
Variable::Mode mode,
FunctionLiteral* function) {
if (mode == Variable::LET) return Bailout("unsupported let declaration");
Variable* var = proxy->var();
Slot* slot = var->AsSlot();
ASSERT(slot != NULL);
switch (slot->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
if (mode == Variable::CONST) {
environment()->Bind(var, graph()->GetConstantHole()); environment()->Bind(var, graph()->GetConstantHole());
} else if (decl->fun() != NULL) { } else if (function != NULL) {
VisitForValue(decl->fun()); VisitForValue(function);
HValue* function = Pop(); HValue* function_value = Pop();
environment()->Bind(var, function); environment()->Bind(var, function_value);
}
break;
case Slot::CONTEXT: {
HValue* context = environment()->LookupContext();
if (mode == Variable::CONST) {
HStoreContextSlot* store =
new HStoreContextSlot(context,
slot->index(),
graph()->GetConstantHole());
AddInstruction(store);
if (store->HasSideEffects()) AddSimulate(proxy->id());
} else if (function != NULL) {
VisitForValue(function);
HValue* function_value = Pop();
HStoreContextSlot* store =
new HStoreContextSlot(context,
slot->index(),
function_value);
AddInstruction(store);
if (store->HasSideEffects()) AddSimulate(proxy->id());
}
break;
}
case Slot::LOOKUP:
return Bailout("unsupported lookup slot in declaration");
} }
} }

View File

@ -779,6 +779,10 @@ class HGraphBuilder: public AstVisitor {
INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
#undef INLINE_FUNCTION_GENERATOR_DECLARATION #undef INLINE_FUNCTION_GENERATOR_DECLARATION
void HandleDeclaration(VariableProxy* proxy,
Variable::Mode mode,
FunctionLiteral* function);
void VisitDelete(UnaryOperation* expr); void VisitDelete(UnaryOperation* expr);
void VisitVoid(UnaryOperation* expr); void VisitVoid(UnaryOperation* expr);
void VisitTypeof(UnaryOperation* expr); void VisitTypeof(UnaryOperation* expr);

View File

@ -684,10 +684,11 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
} }
void FullCodeGenerator::EmitDeclaration(Variable* variable, void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode, Variable::Mode mode,
FunctionLiteral* function) { FunctionLiteral* function) {
Comment cmnt(masm_, "[ Declaration"); Comment cmnt(masm_, "[ Declaration");
Variable* variable = proxy->var();
ASSERT(variable != NULL); // Must have been resolved. ASSERT(variable != NULL); // Must have been resolved.
Slot* slot = variable->AsSlot(); Slot* slot = variable->AsSlot();
ASSERT(slot != NULL); ASSERT(slot != NULL);
@ -724,10 +725,12 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
int offset = Context::SlotOffset(slot->index()); int offset = Context::SlotOffset(slot->index());
__ mov(ebx, esi); __ mov(ebx, esi);
__ RecordWrite(ebx, offset, result_register(), ecx); __ RecordWrite(ebx, offset, result_register(), ecx);
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) { } else if (mode == Variable::CONST || mode == Variable::LET) {
__ mov(ContextOperand(esi, slot->index()), __ mov(ContextOperand(esi, slot->index()),
Immediate(isolate()->factory()->the_hole_value())); Immediate(isolate()->factory()->the_hole_value()));
// No write barrier since the hole value is in old space. // No write barrier since the hole value is in old space.
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} }
break; break;
@ -763,7 +766,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
void FullCodeGenerator::VisitDeclaration(Declaration* decl) { void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); EmitDeclaration(decl->proxy(), decl->mode(), decl->fun());
} }

View File

@ -131,18 +131,18 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
// For now, this must happen at the very end because of the // For now, this must happen at the very end because of the
// ordering of the scope info slots and the respective slot indices. // ordering of the scope info slots and the respective slot indices.
if (scope->is_function_scope()) { if (scope->is_function_scope()) {
Variable* var = scope->function(); VariableProxy* proxy = scope->function();
if (var != NULL && if (proxy != NULL &&
var->is_used() && proxy->var()->is_used() &&
var->AsSlot()->type() == Slot::CONTEXT) { proxy->var()->IsContextSlot()) {
function_name_ = var->name(); function_name_ = proxy->name();
// Note that we must not find the function name in the context slot // Note that we must not find the function name in the context slot
// list - instead it must be handled separately in the // list - instead it must be handled separately in the
// Contexts::Lookup() function. Thus record an empty symbol here so we // Contexts::Lookup() function. Thus record an empty symbol here so we
// get the correct number of context slots. // get the correct number of context slots.
ASSERT(var->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS == ASSERT(proxy->var()->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
context_slots_.length()); context_slots_.length());
ASSERT(var->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS == ASSERT(proxy->var()->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
context_modes_.length()); context_modes_.length());
context_slots_.Add(FACTORY->empty_symbol()); context_slots_.Add(FACTORY->empty_symbol());
context_modes_.Add(Variable::INTERNAL); context_modes_.Add(Variable::INTERNAL);

View File

@ -378,8 +378,10 @@ Variable* Scope::Lookup(Handle<String> name) {
Variable* Scope::DeclareFunctionVar(Handle<String> name) { Variable* Scope::DeclareFunctionVar(Handle<String> name) {
ASSERT(is_function_scope() && function_ == NULL); ASSERT(is_function_scope() && function_ == NULL);
function_ = new Variable(this, name, Variable::CONST, true, Variable::NORMAL); Variable* function_var =
return function_; new Variable(this, name, Variable::CONST, true, Variable::NORMAL);
function_ = new(isolate_->zone()) VariableProxy(isolate_, function_var);
return function_->var();
} }
@ -715,7 +717,7 @@ void Scope::Print(int n) {
PrettyPrinter printer; PrettyPrinter printer;
Indent(n1, "// function var\n"); Indent(n1, "// function var\n");
if (function_ != NULL) { if (function_ != NULL) {
PrintVar(&printer, n1, function_); PrintVar(&printer, n1, function_->var());
} }
Indent(n1, "// temporary vars\n"); Indent(n1, "// temporary vars\n");
@ -796,7 +798,7 @@ Variable* Scope::LookupRecursive(Handle<String> name,
// the name of named function literal is kept in an intermediate scope // the name of named function literal is kept in an intermediate scope
// in between this scope and the next outer scope.) // in between this scope and the next outer scope.)
if (function_ != NULL && function_->name().is_identical_to(name)) { if (function_ != NULL && function_->name().is_identical_to(name)) {
var = function_; var = function_->var();
} else if (outer_scope_ != NULL) { } else if (outer_scope_ != NULL) {
var = outer_scope_->LookupRecursive( var = outer_scope_->LookupRecursive(
@ -1114,7 +1116,7 @@ void Scope::AllocateNonParameterLocals() {
// because of the current ScopeInfo implementation (see // because of the current ScopeInfo implementation (see
// ScopeInfo::ScopeInfo(FunctionScope* scope) constructor). // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
if (function_ != NULL) { if (function_ != NULL) {
AllocateNonParameterLocal(function_); AllocateNonParameterLocal(function_->var());
} }
} }

View File

@ -239,7 +239,7 @@ class Scope: public ZoneObject {
// The variable holding the function literal for named function // The variable holding the function literal for named function
// literals, or NULL. // literals, or NULL.
// Only valid for function scopes. // Only valid for function scopes.
Variable* function() const { VariableProxy* function() const {
ASSERT(is_function_scope()); ASSERT(is_function_scope());
return function_; return function_;
} }
@ -358,7 +358,7 @@ class Scope: public ZoneObject {
// Convenience variable. // Convenience variable.
Variable* receiver_; Variable* receiver_;
// Function variable, if any; function scopes only. // Function variable, if any; function scopes only.
Variable* function_; VariableProxy* function_;
// Convenience variable; function scopes only. // Convenience variable; function scopes only.
Variable* arguments_; Variable* arguments_;

View File

@ -659,10 +659,11 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
} }
void FullCodeGenerator::EmitDeclaration(Variable* variable, void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode, Variable::Mode mode,
FunctionLiteral* function) { FunctionLiteral* function) {
Comment cmnt(masm_, "[ Declaration"); Comment cmnt(masm_, "[ Declaration");
Variable* variable = proxy->var();
ASSERT(variable != NULL); // Must have been resolved. ASSERT(variable != NULL); // Must have been resolved.
Slot* slot = variable->AsSlot(); Slot* slot = variable->AsSlot();
ASSERT(slot != NULL); ASSERT(slot != NULL);
@ -699,10 +700,12 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
int offset = Context::SlotOffset(slot->index()); int offset = Context::SlotOffset(slot->index());
__ movq(rbx, rsi); __ movq(rbx, rsi);
__ RecordWrite(rbx, offset, result_register(), rcx); __ RecordWrite(rbx, offset, result_register(), rcx);
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) { } else if (mode == Variable::CONST || mode == Variable::LET) {
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ movq(ContextOperand(rsi, slot->index()), kScratchRegister); __ movq(ContextOperand(rsi, slot->index()), kScratchRegister);
// No write barrier since the hole value is in old space. // No write barrier since the hole value is in old space.
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} }
break; break;
@ -734,7 +737,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
void FullCodeGenerator::VisitDeclaration(Declaration* decl) { void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); EmitDeclaration(decl->proxy(), decl->mode(), decl->fun());
} }