Add support for all declarations in the top-level compiler:

Until now we only handled global declarations. This change
adds declarations of local variables, consts and functions.

Review URL: http://codereview.chromium.org/368005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3234 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
fschneider@chromium.org 2009-11-05 17:33:50 +00:00
parent 8595cbb0d3
commit 9a7c403bbb
5 changed files with 255 additions and 34 deletions

View File

@ -294,6 +294,85 @@ void FastCodeGenerator::TestAndBranch(Register source,
}
void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
Variable* var = decl->proxy()->var();
ASSERT(var != NULL); // Must have been resolved.
Slot* slot = var->slot();
ASSERT(slot != NULL); // No global declarations here.
// We have 3 cases for slots: LOOKUP, LOCAL, CONTEXT.
switch (slot->type()) {
case Slot::LOOKUP: {
__ mov(r2, Operand(var->name()));
// Declaration nodes are always introduced in one of two modes.
ASSERT(decl->mode() == Variable::VAR || decl->mode() == Variable::CONST);
PropertyAttributes attr = decl->mode() == Variable::VAR ?
NONE : READ_ONLY;
__ mov(r1, Operand(Smi::FromInt(attr)));
// Push initial value, if any.
// 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 (decl->mode() == Variable::CONST) {
__ mov(r0, Operand(Factory::the_hole_value()));
__ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
} else if (decl->fun() != NULL) {
__ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit());
Visit(decl->fun()); // Initial value for function decl.
} else {
__ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
__ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
break;
}
case Slot::LOCAL:
if (decl->mode() == Variable::CONST) {
__ mov(r0, Operand(Factory::the_hole_value()));
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
} else if (decl->fun() != NULL) {
Visit(decl->fun());
__ pop(r0);
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
}
break;
case Slot::CONTEXT:
// The variable in the decl always resides in the current context.
ASSERT(function_->scope()->ContextChainLength(slot->var()->scope()) == 0);
if (decl->mode() == Variable::CONST) {
__ mov(r0, Operand(Factory::the_hole_value()));
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
__ ldr(r1, CodeGenerator::ContextOperand(
cp, Context::FCONTEXT_INDEX));
__ cmp(r1, cp);
__ Check(eq, "Unexpected declaration in current context.");
}
__ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
// No write barrier since the_hole_value is in old space.
ASSERT(Heap::InNewSpace(*Factory::the_hole_value()));
} else if (decl->fun() != NULL) {
Visit(decl->fun());
__ pop(r0);
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
__ ldr(r1, CodeGenerator::ContextOperand(
cp, Context::FCONTEXT_INDEX));
__ cmp(r1, cp);
__ Check(eq, "Unexpected declaration in current context.");
}
__ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
__ mov(r2, Operand(offset));
__ RecordWrite(cp, r2, r0);
}
break;
default:
UNREACHABLE();
}
}
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
// The context is the first argument.

View File

@ -647,9 +647,8 @@ void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
void CodeGenSelector::VisitDeclaration(Declaration* decl) {
Variable* var = decl->proxy()->var();
if (!var->is_global() || var->mode() == Variable::CONST) {
BAILOUT("Non-global declaration");
if (decl->fun() != NULL) {
ProcessExpression(decl->fun(), Expression::kValue);
}
}

View File

@ -88,45 +88,44 @@ void FastCodeGenerator::VisitDeclarations(
// time, we need to "declare" it at runtime to make sure it
// actually exists in the local context.
if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
UNREACHABLE();
VisitDeclaration(decl);
} else {
// Count global variables and functions for later processing
globals++;
}
}
// Return in case of no declared global functions or variables.
if (globals == 0) return;
// Compute array of global variable and function declarations.
Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
for (int j = 0, i = 0; i < length; i++) {
Declaration* decl = declarations->at(i);
Variable* var = decl->proxy()->var();
Slot* slot = var->slot();
// Do nothing in case of no declared global functions or variables.
if (globals > 0) {
Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
for (int j = 0, i = 0; i < length; i++) {
Declaration* decl = declarations->at(i);
Variable* var = decl->proxy()->var();
Slot* slot = var->slot();
if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
array->set(j++, *(var->name()));
if (decl->fun() == NULL) {
if (var->mode() == Variable::CONST) {
// In case this is const property use the hole.
array->set_the_hole(j++);
if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
array->set(j++, *(var->name()));
if (decl->fun() == NULL) {
if (var->mode() == Variable::CONST) {
// In case this is const property use the hole.
array->set_the_hole(j++);
} else {
array->set_undefined(j++);
}
} else {
array->set_undefined(j++);
Handle<JSFunction> function =
Compiler::BuildBoilerplate(decl->fun(), script_, this);
// Check for stack-overflow exception.
if (HasStackOverflow()) return;
array->set(j++, *function);
}
} else {
Handle<JSFunction> function =
Compiler::BuildBoilerplate(decl->fun(), script_, this);
// Check for stack-overflow exception.
if (HasStackOverflow()) return;
array->set(j++, *function);
}
}
// Invoke the platform-dependent code generator to do the actual
// declaration the global variables and functions.
DeclareGlobals(array);
}
// Invoke the platform-dependent code generator to do the actual
// declaration the global variables and functions.
DeclareGlobals(array);
}
@ -232,11 +231,6 @@ void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
}
void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
UNREACHABLE();
}
void FastCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
SetStatementPosition(stmt);

View File

@ -290,6 +290,80 @@ void FastCodeGenerator::TestAndBranch(Register source,
}
void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
Variable* var = decl->proxy()->var();
ASSERT(var != NULL); // Must have been resolved.
Slot* slot = var->slot();
ASSERT(slot != NULL); // No global declarations here.
// We have 3 cases for slots: LOOKUP, LOCAL, CONTEXT.
switch (slot->type()) {
case Slot::LOOKUP: {
__ push(esi);
__ push(Immediate(var->name()));
// Declaration nodes are always introduced in one of two modes.
ASSERT(decl->mode() == Variable::VAR || decl->mode() == Variable::CONST);
PropertyAttributes attr =
(decl->mode() == Variable::VAR) ? NONE : READ_ONLY;
__ push(Immediate(Smi::FromInt(attr)));
// Push initial value, if any.
// 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 (decl->mode() == Variable::CONST) {
__ push(Immediate(Factory::the_hole_value()));
} else if (decl->fun() != NULL) {
Visit(decl->fun());
} else {
__ push(Immediate(Smi::FromInt(0))); // No initial value!
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
break;
}
case Slot::LOCAL:
if (decl->mode() == Variable::CONST) {
__ mov(Operand(ebp, SlotOffset(var->slot())),
Immediate(Factory::the_hole_value()));
} else if (decl->fun() != NULL) {
Visit(decl->fun());
__ pop(Operand(ebp, SlotOffset(var->slot())));
}
break;
case Slot::CONTEXT:
// The variable in the decl always resides in the current context.
ASSERT(function_->scope()->ContextChainLength(slot->var()->scope()) == 0);
if (decl->mode() == Variable::CONST) {
__ mov(eax, Immediate(Factory::the_hole_value()));
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
__ mov(ebx,
CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX));
__ cmp(ebx, Operand(esi));
__ Check(equal, "Unexpected declaration in current context.");
}
__ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
// No write barrier since the_hole_value is in old space.
} else if (decl->fun() != NULL) {
Visit(decl->fun());
__ pop(eax);
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
__ mov(ebx,
CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX));
__ cmp(ebx, Operand(esi));
__ Check(equal, "Unexpected declaration in current context.");
}
__ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
__ RecordWrite(esi, offset, eax, ecx);
}
break;
default:
UNREACHABLE();
}
}
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ push(esi); // The context is the first argument.

View File

@ -297,6 +297,81 @@ void FastCodeGenerator::TestAndBranch(Register source,
}
void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
Variable* var = decl->proxy()->var();
ASSERT(var != NULL); // Must have been resolved.
Slot* slot = var->slot();
ASSERT(slot != NULL); // No global declarations here.
// We have 3 cases for slots: LOOKUP, LOCAL, CONTEXT.
switch (slot->type()) {
case Slot::LOOKUP: {
__ push(rsi);
__ Push(var->name());
// Declaration nodes are always introduced in one of two modes.
ASSERT(decl->mode() == Variable::VAR || decl->mode() == Variable::CONST);
PropertyAttributes attr = decl->mode() == Variable::VAR ?
NONE : READ_ONLY;
__ Push(Smi::FromInt(attr));
// Push initial value, if any.
// 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 (decl->mode() == Variable::CONST) {
__ Push(Factory::the_hole_value());
} else if (decl->fun() != NULL) {
Visit(decl->fun());
} else {
__ Push(Smi::FromInt(0)); // no initial value!
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
break;
}
case Slot::LOCAL:
if (decl->mode() == Variable::CONST) {
__ Move(Operand(rbp, SlotOffset(var->slot())),
Factory::the_hole_value());
} else if (decl->fun() != NULL) {
Visit(decl->fun());
__ pop(Operand(rbp, SlotOffset(var->slot())));
}
break;
case Slot::CONTEXT:
// The variable in the decl always resides in the current context.
ASSERT(function_->scope()->ContextChainLength(slot->var()->scope()) == 0);
if (decl->mode() == Variable::CONST) {
__ Move(rax, Factory::the_hole_value());
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
__ movq(rbx, CodeGenerator::ContextOperand(
rsi, Context::FCONTEXT_INDEX));
__ cmpq(rbx, rsi);
__ Check(equal, "Unexpected declaration in current context.");
}
__ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
// No write barrier since the_hole_value is in old space.
ASSERT(Heap::InNewSpace(*Factory::the_hole_value()));
} else if (decl->fun() != NULL) {
Visit(decl->fun());
__ pop(rax);
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
__ movq(rbx, CodeGenerator::ContextOperand(
rsi, Context::FCONTEXT_INDEX));
__ cmpq(rbx, rsi);
__ Check(equal, "Unexpected declaration in current context.");
}
__ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
__ RecordWrite(rsi, offset, rax, rcx);
}
break;
default:
UNREACHABLE();
}
}
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ push(rsi); // The context is the first argument.