Chromium Code Reviews| Index: src/x64/codegen-x64.cc |
| =================================================================== |
| --- src/x64/codegen-x64.cc (revision 2277) |
| +++ src/x64/codegen-x64.cc (working copy) |
| @@ -263,8 +263,74 @@ |
| function_return_.set_direction(JumpTarget::BIDIRECTIONAL); |
| function_return_is_shadowed_ = false; |
| - // TODO(X64): Add code to handle arguments object and context object. |
| + // Allocate the local context if needed. |
| + if (scope_->num_heap_slots() > 0) { |
| + Comment cmnt(masm_, "[ allocate local context"); |
| + // Allocate local context. |
| + // Get outer context and create a new context based on it. |
| + frame_->PushFunction(); |
| + Result context = frame_->CallRuntime(Runtime::kNewContext, 1); |
| + // Update context local. |
| + frame_->SaveContextRegister(); |
| + |
| + // Verify that the runtime call result and esi agree. |
| + if (FLAG_debug_code) { |
| + __ cmpq(context.reg(), rsi); |
| + __ Assert(equal, "Runtime::NewContext should end up in esi"); |
|
Lasse Reichstein
2009/06/26 08:27:48
rsi
|
| + } |
| + } |
| + |
| + // TODO(1241774): Improve this code: |
| + // 1) only needed if we have a context |
| + // 2) no need to recompute context ptr every single time |
| + // 3) don't copy parameter operand code from SlotOperand! |
| + { |
| + Comment cmnt2(masm_, "[ copy context parameters into .context"); |
| + |
| + // Note that iteration order is relevant here! If we have the same |
| + // parameter twice (e.g., function (x, y, x)), and that parameter |
| + // needs to be copied into the context, it must be the last argument |
| + // passed to the parameter that needs to be copied. This is a rare |
| + // case so we don't check for it, instead we rely on the copying |
| + // order: such a parameter is copied repeatedly into the same |
| + // context location and thus the last value is what is seen inside |
| + // the function. |
| + for (int i = 0; i < scope_->num_parameters(); i++) { |
| + Variable* par = scope_->parameter(i); |
| + Slot* slot = par->slot(); |
| + if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| + // The use of SlotOperand below is safe in unspilled code |
| + // because the slot is guaranteed to be a context slot. |
| + // |
| + // There are no parameters in the global scope. |
| + ASSERT(!scope_->is_global_scope()); |
| + frame_->PushParameterAt(i); |
| + Result value = frame_->Pop(); |
| + value.ToRegister(); |
| + |
| + // SlotOperand loads context.reg() with the context object |
| + // stored to, used below in RecordWrite. |
| + Result context = allocator_->Allocate(); |
| + ASSERT(context.is_valid()); |
| + __ movq(SlotOperand(slot, context.reg()), value.reg()); |
| + int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| + Result scratch = allocator_->Allocate(); |
| + ASSERT(scratch.is_valid()); |
| + frame_->Spill(context.reg()); |
| + frame_->Spill(value.reg()); |
| + __ RecordWrite(context.reg(), offset, value.reg(), scratch.reg()); |
| + } |
| + } |
| + } |
| + |
| + // Store the arguments object. This must happen after context |
| + // initialization because the arguments object may be stored in |
| + // the context. |
| + if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) { |
| + StoreArgumentsObject(true); |
| + } |
| + |
| // Generate code to 'execute' declarations and initialize functions |
| // (source elements). In case of an illegal redeclaration we need to |
| // handle that instead of processing the declarations. |
| @@ -3336,6 +3402,71 @@ |
| } |
| +ArgumentsAllocationMode CodeGenerator::ArgumentsMode() const { |
| + if (scope_->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; |
| + ASSERT(scope_->arguments_shadow() != NULL); |
| + // We don't want to do lazy arguments allocation for functions that |
| + // have heap-allocated contexts, because it interfers with the |
| + // uninitialized const tracking in the context objects. |
| + return (scope_->num_heap_slots() > 0) |
| + ? EAGER_ARGUMENTS_ALLOCATION |
| + : LAZY_ARGUMENTS_ALLOCATION; |
| +} |
| + |
| + |
| +Result CodeGenerator::StoreArgumentsObject(bool initial) { |
| + ArgumentsAllocationMode mode = ArgumentsMode(); |
| + ASSERT(mode != NO_ARGUMENTS_ALLOCATION); |
| + |
| + Comment cmnt(masm_, "[ store arguments object"); |
| + if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { |
| + // When using lazy arguments allocation, we store the hole value |
| + // as a sentinel indicating that the arguments object hasn't been |
| + // allocated yet. |
| + frame_->Push(Factory::the_hole_value()); |
| + } else { |
| + ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| + frame_->PushFunction(); |
| + frame_->PushReceiverSlotAddress(); |
| + frame_->Push(Smi::FromInt(scope_->num_parameters())); |
| + Result result = frame_->CallStub(&stub, 3); |
| + frame_->Push(&result); |
| + } |
| + |
| + { Reference shadow_ref(this, scope_->arguments_shadow()); |
| + Reference arguments_ref(this, scope_->arguments()); |
| + ASSERT(shadow_ref.is_slot() && arguments_ref.is_slot()); |
| + // Here we rely on the convenient property that references to slot |
| + // take up zero space in the frame (ie, it doesn't matter that the |
| + // stored value is actually below the reference on the frame). |
| + JumpTarget done; |
| + bool skip_arguments = false; |
| + if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { |
| + // We have to skip storing into the arguments slot if it has |
| + // already been written to. This can happen if the a function |
| + // has a local variable named 'arguments'. |
| + LoadFromSlot(scope_->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); |
| + Result arguments = frame_->Pop(); |
| + if (arguments.is_constant()) { |
| + // We have to skip updating the arguments object if it has |
| + // been assigned a proper value. |
| + skip_arguments = !arguments.handle()->IsTheHole(); |
| + } else { |
| + __ Cmp(arguments.reg(), Factory::the_hole_value()); |
| + arguments.Unuse(); |
| + done.Branch(not_equal); |
| + } |
| + } |
| + if (!skip_arguments) { |
| + arguments_ref.SetValue(NOT_CONST_INIT); |
| + if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); |
| + } |
| + shadow_ref.SetValue(NOT_CONST_INIT); |
| + } |
| + return frame_->Pop(); |
| +} |
| + |
| + |
| // TODO(1241834): Get rid of this function in favor of just using Load, now |
| // that we have the INSIDE_TYPEOF typeof state. => Need to handle global |
| // variables w/o reference errors elsewhere. |