}
+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.
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);
}
}
// 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();
-
- 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++);
+ // 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++);
+ } 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);
}
}
-void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
- UNREACHABLE();
-}
-
-
void FastCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
SetStatementPosition(stmt);
}
+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.
}
+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.