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:
parent
8595cbb0d3
commit
9a7c403bbb
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user