| Index: src/arm/fast-codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/fast-codegen-arm.cc (revision 3241)
|
| +++ src/arm/fast-codegen-arm.cc (working copy)
|
| @@ -364,6 +364,7 @@
|
| __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
|
| int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
|
| __ mov(r2, Operand(offset));
|
| + // We know that we have written a function, which is not a smi.
|
| __ RecordWrite(cp, r2, r0);
|
| }
|
| break;
|
| @@ -421,6 +422,7 @@
|
| Comment cmnt(masm_, "[ VariableProxy");
|
| Expression* rewrite = expr->var()->rewrite();
|
| if (rewrite == NULL) {
|
| + ASSERT(expr->var()->is_global());
|
| Comment cmnt(masm_, "Global variable");
|
| // Use inline caching. Variable name is passed in r2 and the global
|
| // object on the stack.
|
| @@ -431,8 +433,47 @@
|
| __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
| DropAndMove(expr->context(), r0);
|
| } else {
|
| - Comment cmnt(masm_, "Stack slot");
|
| - Move(expr->context(), rewrite->AsSlot());
|
| + Slot* slot = rewrite->AsSlot();
|
| + ASSERT_NE(NULL, slot);
|
| + switch (slot->type()) {
|
| + case Slot::LOCAL:
|
| + case Slot::PARAMETER: {
|
| + Comment cmnt(masm_, "Stack slot");
|
| + Move(expr->context(), rewrite->AsSlot());
|
| + break;
|
| + }
|
| +
|
| + case Slot::CONTEXT: {
|
| + Comment cmnt(masm_, "Context slot");
|
| + int chain_length =
|
| + function_->scope()->ContextChainLength(slot->var()->scope());
|
| + if (chain_length > 0) {
|
| + // Move up the chain of contexts to the context containing the slot.
|
| + __ ldr(r0, CodeGenerator::ContextOperand(cp, Context::CLOSURE_INDEX));
|
| + // Load the function context (which is the incoming, outer context).
|
| + __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
|
| + for (int i = 1; i < chain_length; i++) {
|
| + __ ldr(r0,
|
| + CodeGenerator::ContextOperand(r0, Context::CLOSURE_INDEX));
|
| + // Load the function context (which is the incoming, outer context).
|
| + __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
|
| + }
|
| + // The context may be an intermediate context, not a function context.
|
| + __ ldr(r0,
|
| + CodeGenerator::ContextOperand(r0, Context::FCONTEXT_INDEX));
|
| + } else { // Slot is in the current context.
|
| + __ ldr(r0,
|
| + CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX));
|
| + }
|
| + __ ldr(r0, CodeGenerator::ContextOperand(r0, slot->index()));
|
| + Move(expr->context(), r0);
|
| + break;
|
| + }
|
| +
|
| + case Slot::LOOKUP:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| }
|
| }
|
|
|
| @@ -705,45 +746,103 @@
|
| DropAndMove(expr->context(), r0);
|
|
|
| } else {
|
| - switch (expr->context()) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| - case Expression::kEffect:
|
| - // Perform assignment and discard value.
|
| - __ pop(r0);
|
| - __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
| + Slot* slot = var->slot();
|
| + ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled.
|
| + switch (slot->type()) {
|
| + case Slot::LOCAL:
|
| + case Slot::PARAMETER: {
|
| + switch (expr->context()) {
|
| + case Expression::kUninitialized:
|
| + UNREACHABLE();
|
| + case Expression::kEffect:
|
| + // Perform assignment and discard value.
|
| + __ pop(r0);
|
| + __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
| + break;
|
| + case Expression::kValue:
|
| + // Perform assignment and preserve value.
|
| + __ ldr(r0, MemOperand(sp));
|
| + __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
| + break;
|
| + case Expression::kTest:
|
| + // Perform assignment and test (and discard) value.
|
| + __ pop(r0);
|
| + __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
| + TestAndBranch(r0, true_label_, false_label_);
|
| + break;
|
| + case Expression::kValueTest: {
|
| + Label discard;
|
| + __ ldr(r0, MemOperand(sp));
|
| + __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
| + TestAndBranch(r0, true_label_, &discard);
|
| + __ bind(&discard);
|
| + __ pop();
|
| + __ jmp(false_label_);
|
| + break;
|
| + }
|
| + case Expression::kTestValue: {
|
| + Label discard;
|
| + __ ldr(r0, MemOperand(sp));
|
| + __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
| + TestAndBranch(r0, &discard, false_label_);
|
| + __ bind(&discard);
|
| + __ pop();
|
| + __ jmp(true_label_);
|
| + break;
|
| + }
|
| + }
|
| break;
|
| - case Expression::kValue:
|
| - // Perform assignment and preserve value.
|
| - __ ldr(r0, MemOperand(sp));
|
| - __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
| + }
|
| +
|
| + case Slot::CONTEXT: {
|
| + int chain_length =
|
| + function_->scope()->ContextChainLength(slot->var()->scope());
|
| + if (chain_length > 0) {
|
| + // Move up the chain of contexts to the context containing the slot.
|
| + __ ldr(r0, CodeGenerator::ContextOperand(cp, Context::CLOSURE_INDEX));
|
| + // Load the function context (which is the incoming, outer context).
|
| + __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
|
| + for (int i = 1; i < chain_length; i++) {
|
| + __ ldr(r0,
|
| + CodeGenerator::ContextOperand(r0, Context::CLOSURE_INDEX));
|
| + __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
|
| + }
|
| + } else { // Slot is in the current context. Generate optimized code.
|
| + __ mov(r0, cp);
|
| + }
|
| + // The context may be an intermediate context, not a function context.
|
| + __ ldr(r0, CodeGenerator::ContextOperand(r0, Context::FCONTEXT_INDEX));
|
| + __ pop(r1);
|
| + __ str(r1, CodeGenerator::ContextOperand(r0, slot->index()));
|
| +
|
| + // RecordWrite may destroy all its register arguments.
|
| + if (expr->context() == Expression::kValue) {
|
| + __ push(r1);
|
| + } else if (expr->context() != Expression::kEffect) {
|
| + __ mov(r3, r1);
|
| + }
|
| + int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
|
| +
|
| + // Update the write barrier for the array store with r0 as the scratch
|
| + // register. Skip the write barrier if r0 is a smi.
|
| + // The smi test is part of RecordWrite on other platforms, not on arm.
|
| + Label exit;
|
| + __ tst(r0, Operand(kSmiTagMask));
|
| + __ b(eq, &exit);
|
| +
|
| + __ mov(r2, Operand(offset));
|
| + __ RecordWrite(r0, r2, r1);
|
| + __ bind(&exit);
|
| + if (expr->context() != Expression::kEffect &&
|
| + expr->context() != Expression::kValue) {
|
| + Move(expr->context(), r3);
|
| + }
|
| break;
|
| - case Expression::kTest:
|
| - // Perform assignment and test (and discard) value.
|
| - __ pop(r0);
|
| - __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
| - TestAndBranch(r0, true_label_, false_label_);
|
| - break;
|
| - case Expression::kValueTest: {
|
| - Label discard;
|
| - __ ldr(r0, MemOperand(sp));
|
| - __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
| - TestAndBranch(r0, true_label_, &discard);
|
| - __ bind(&discard);
|
| - __ pop();
|
| - __ jmp(false_label_);
|
| - break;
|
| }
|
| - case Expression::kTestValue: {
|
| - Label discard;
|
| - __ ldr(r0, MemOperand(sp));
|
| - __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
| - TestAndBranch(r0, &discard, false_label_);
|
| - __ bind(&discard);
|
| - __ pop();
|
| - __ jmp(true_label_);
|
| +
|
| + case Slot::LOOKUP:
|
| + UNREACHABLE();
|
| break;
|
| - }
|
| }
|
| }
|
| }
|
|
|