| Index: src/arm/full-codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/full-codegen-arm.cc (revision 6881)
|
| +++ src/arm/full-codegen-arm.cc (working copy)
|
| @@ -219,46 +219,47 @@
|
| Move(dot_arguments_slot, r3, r1, r2);
|
| }
|
|
|
| - { Comment cmnt(masm_, "[ Declarations");
|
| - // For named function expressions, declare the function name as a
|
| - // constant.
|
| - if (scope()->is_function_scope() && scope()->function() != NULL) {
|
| - EmitDeclaration(scope()->function(), Variable::CONST, NULL);
|
| - }
|
| - // Visit all the explicit declarations unless there is an illegal
|
| - // redeclaration.
|
| - if (scope()->HasIllegalRedeclaration()) {
|
| - scope()->VisitIllegalRedeclaration(this);
|
| - } else {
|
| - VisitDeclarations(scope()->declarations());
|
| - }
|
| - }
|
| -
|
| if (FLAG_trace) {
|
| __ CallRuntime(Runtime::kTraceEnter, 0);
|
| }
|
|
|
| - // Check the stack for overflow or break request.
|
| - { Comment cmnt(masm_, "[ Stack check");
|
| - PrepareForBailout(info->function(), NO_REGISTERS);
|
| - Label ok;
|
| - __ LoadRoot(ip, Heap::kStackLimitRootIndex);
|
| - __ cmp(sp, Operand(ip));
|
| - __ b(hs, &ok);
|
| - StackCheckStub stub;
|
| - __ CallStub(&stub);
|
| - __ bind(&ok);
|
| - }
|
| + // Visit the declarations and body unless there is an illegal
|
| + // redeclaration.
|
| + if (scope()->HasIllegalRedeclaration()) {
|
| + Comment cmnt(masm_, "[ Declarations");
|
| + scope()->VisitIllegalRedeclaration(this);
|
|
|
| - { Comment cmnt(masm_, "[ Body");
|
| - ASSERT(loop_depth() == 0);
|
| - VisitStatements(function()->body());
|
| - ASSERT(loop_depth() == 0);
|
| + } else {
|
| + { Comment cmnt(masm_, "[ Declarations");
|
| + // For named function expressions, declare the function name as a
|
| + // constant.
|
| + if (scope()->is_function_scope() && scope()->function() != NULL) {
|
| + EmitDeclaration(scope()->function(), Variable::CONST, NULL);
|
| + }
|
| + VisitDeclarations(scope()->declarations());
|
| + }
|
| +
|
| + { Comment cmnt(masm_, "[ Stack check");
|
| + PrepareForBailout(info->function(), NO_REGISTERS);
|
| + Label ok;
|
| + __ LoadRoot(ip, Heap::kStackLimitRootIndex);
|
| + __ cmp(sp, Operand(ip));
|
| + __ b(hs, &ok);
|
| + StackCheckStub stub;
|
| + __ CallStub(&stub);
|
| + __ bind(&ok);
|
| + }
|
| +
|
| + { Comment cmnt(masm_, "[ Body");
|
| + ASSERT(loop_depth() == 0);
|
| + VisitStatements(function()->body());
|
| + ASSERT(loop_depth() == 0);
|
| + }
|
| }
|
|
|
| + // Always emit a 'return undefined' in case control fell off the end of
|
| + // the body.
|
| { Comment cmnt(masm_, "[ return <undefined>;");
|
| - // Emit a 'return undefined' in case control fell off the end of the
|
| - // body.
|
| __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
|
| }
|
| EmitReturnSequence();
|
| @@ -694,10 +695,11 @@
|
| // We bypass the general EmitSlotSearch because we know more about
|
| // this specific context.
|
|
|
| - // The variable in the decl always resides in the current 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 if we have the correct context pointer.
|
| + // Check that we're not inside a 'with'.
|
| __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
|
| __ cmp(r1, cp);
|
| __ Check(eq, "Unexpected declaration in current context.");
|
| @@ -1037,7 +1039,7 @@
|
| Slot* slot,
|
| Label* slow) {
|
| ASSERT(slot->type() == Slot::CONTEXT);
|
| - Register current = cp;
|
| + Register context = cp;
|
| Register next = r3;
|
| Register temp = r4;
|
|
|
| @@ -1045,22 +1047,25 @@
|
| if (s->num_heap_slots() > 0) {
|
| if (s->calls_eval()) {
|
| // Check that extension is NULL.
|
| - __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
|
| + __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
|
| __ tst(temp, temp);
|
| __ b(ne, slow);
|
| }
|
| - __ ldr(next, ContextOperand(current, Context::CLOSURE_INDEX));
|
| + __ ldr(next, ContextOperand(context, Context::CLOSURE_INDEX));
|
| __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
|
| // Walk the rest of the chain without clobbering cp.
|
| - current = next;
|
| + context = next;
|
| }
|
| }
|
| // Check that last extension is NULL.
|
| - __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
|
| + __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
|
| __ tst(temp, temp);
|
| __ b(ne, slow);
|
| - __ ldr(temp, ContextOperand(current, Context::FCONTEXT_INDEX));
|
| - return ContextOperand(temp, slot->index());
|
| +
|
| + // This function is used only for loads, not stores, so it's safe to
|
| + // return an cp-based operand (the write barrier cannot be allowed to
|
| + // destroy the cp register).
|
| + return ContextOperand(context, slot->index());
|
| }
|
|
|
|
|
| @@ -2004,34 +2009,60 @@
|
| : Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
|
|
| - } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
|
| - // Perform the assignment for non-const variables and for initialization
|
| - // of const variables. Const assignments are simply skipped.
|
| - Label done;
|
| + } else if (op == Token::INIT_CONST) {
|
| + // Like var declarations, const declarations are hoisted to function
|
| + // scope. However, unlike var initializers, const initializers are able
|
| + // to drill a hole to that function context, even from inside a 'with'
|
| + // context. We thus bypass the normal static scope lookup.
|
| Slot* slot = var->AsSlot();
|
| + Label skip;
|
| switch (slot->type()) {
|
| case Slot::PARAMETER:
|
| + // No const parameters.
|
| + UNREACHABLE();
|
| + break;
|
| case Slot::LOCAL:
|
| - if (op == Token::INIT_CONST) {
|
| - // Detect const reinitialization by checking for the hole value.
|
| - __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
|
| - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
| - __ cmp(r1, ip);
|
| - __ b(ne, &done);
|
| - }
|
| + // Detect const reinitialization by checking for the hole value.
|
| + __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
|
| + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
| + __ cmp(r1, ip);
|
| + __ b(ne, &skip);
|
| + __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
|
| + break;
|
| + case Slot::CONTEXT: {
|
| + __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
|
| + __ ldr(r2, ContextOperand(r1, slot->index()));
|
| + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
| + __ cmp(r2, ip);
|
| + __ b(ne, &skip);
|
| + __ str(r0, ContextOperand(r1, slot->index()));
|
| + int offset = Context::SlotOffset(slot->index());
|
| + __ mov(r3, r0); // Preserve the stored value in r0.
|
| + __ RecordWrite(r1, Operand(offset), r3, r2);
|
| + break;
|
| + }
|
| + case Slot::LOOKUP:
|
| + __ push(r0);
|
| + __ mov(r0, Operand(slot->var()->name()));
|
| + __ Push(cp, r0); // Context and name.
|
| + __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
|
| + break;
|
| + }
|
| + __ bind(&skip);
|
| +
|
| + } else if (var->mode() != Variable::CONST) {
|
| + // Perform the assignment for non-const variables. Const assignments
|
| + // are simply skipped.
|
| + Slot* slot = var->AsSlot();
|
| + switch (slot->type()) {
|
| + case Slot::PARAMETER:
|
| + case Slot::LOCAL:
|
| // Perform the assignment.
|
| __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
|
| break;
|
|
|
| case Slot::CONTEXT: {
|
| MemOperand target = EmitSlotSearch(slot, r1);
|
| - if (op == Token::INIT_CONST) {
|
| - // Detect const reinitialization by checking for the hole value.
|
| - __ ldr(r2, target);
|
| - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
| - __ cmp(r2, ip);
|
| - __ b(ne, &done);
|
| - }
|
| // Perform the assignment and issue the write barrier.
|
| __ str(result_register(), target);
|
| // RecordWrite may destroy all its register arguments.
|
| @@ -2042,20 +2073,13 @@
|
| }
|
|
|
| case Slot::LOOKUP:
|
| - // Call the runtime for the assignment. The runtime will ignore
|
| - // const reinitialization.
|
| + // Call the runtime for the assignment.
|
| __ push(r0); // Value.
|
| __ mov(r0, Operand(slot->var()->name()));
|
| __ Push(cp, r0); // Context and name.
|
| - if (op == Token::INIT_CONST) {
|
| - // The runtime will ignore const redeclaration.
|
| - __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
|
| - } else {
|
| - __ CallRuntime(Runtime::kStoreContextSlot, 3);
|
| - }
|
| + __ CallRuntime(Runtime::kStoreContextSlot, 3);
|
| break;
|
| }
|
| - __ bind(&done);
|
| }
|
| }
|
|
|
|
|