Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Unified Diff: src/virtual-frame-ia32.cc

Issue 19755: Experimental: allow the virtual frame to explicitly indicate sharing... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: '' Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/virtual-frame-ia32.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/virtual-frame-ia32.cc
===================================================================
--- src/virtual-frame-ia32.cc (revision 1239)
+++ src/virtual-frame-ia32.cc (working copy)
@@ -85,6 +85,46 @@
}
+FrameElement VirtualFrame::CopyElementAt(int index) {
+ ASSERT(index >= 0);
+ ASSERT(index < elements_.length());
+
+ FrameElement target = elements_[index];
+ FrameElement result;
+
+ switch (target.type()) {
+ case FrameElement::CONSTANT:
+ // We do not copy constants and instead return a fresh unsynced
+ // constant.
+ result = FrameElement::ConstantElement(target.handle(),
+ FrameElement::NOT_SYNCED);
+ break;
+
+ case FrameElement::COPY:
+ // We do not allow copies of copies, so we follow one link to
+ // the actual backing store of a copy before making a copy.
+ index = target.index();
+ ASSERT(elements_[index].is_memory() || elements_[index].is_register());
+ // Fall through.
+
+ case FrameElement::MEMORY: // Fall through.
+ case FrameElement::REGISTER:
+ // All copies are backed by memory or register locations.
+ result.type_ =
+ FrameElement::TypeField::encode(FrameElement::COPY) |
+ FrameElement::SyncField::encode(FrameElement::NOT_SYNCED);
+ result.data_.index_ = index;
+ break;
+
+ case FrameElement::INVALID:
+ // We should not try to copy invalid elements.
+ UNREACHABLE();
+ break;
+ }
+ return result;
+}
+
+
// Modify the state of the virtual frame to match the actual frame by adding
// extra in-memory elements to the top of the virtual frame. The extra
// elements will be externally materialized on the actual frame (eg, by
@@ -167,57 +207,100 @@
}
-// Spill an element, making its type be MEMORY.
-// Does not decrement usage counts, if element is a register.
-void VirtualFrame::RawSpillElementAt(int index) {
- if (elements_[index].is_valid()) {
- SyncElementAt(index);
- // The element is now in memory.
- elements_[index] = FrameElement::MemoryElement();
- }
-}
-
-
// Make the type of the element at a given index be MEMORY.
void VirtualFrame::SpillElementAt(int index) {
+ if (!elements_[index].is_valid()) return;
+
if (elements_[index].is_register()) {
Unuse(elements_[index].reg());
}
- RawSpillElementAt(index);
+ SyncElementAt(index);
+ // The element is now in memory.
+ elements_[index] = FrameElement::MemoryElement();
}
-// Clear the dirty bit for the element at a given index.
-// The element must be on the physical stack, or the first
-// element below the stack pointer (created by a single push).
+// Clear the dirty bit for the element at a given index if it is a
+// valid element. The stack address corresponding to the element must
+// be allocated on the physical stack, or the first element above the
+// stack pointer so it can be allocated by a single push instruction.
void VirtualFrame::RawSyncElementAt(int index) {
FrameElement element = elements_[index];
- if (element.is_valid() && !element.is_synced()) {
- if (index <= stack_pointer_) {
- // Write elements below the stack pointer to their (already allocated)
- // actual frame location.
- if (element.is_constant()) {
+
+ if (!element.is_valid() || element.is_synced()) return;
+
+ if (index <= stack_pointer_) {
+ // Emit code to write elements below the stack pointer to their
+ // (already allocated) stack address.
+ switch (element.type()) {
+ case FrameElement::INVALID: // Fall through.
+ case FrameElement::MEMORY:
+ // There was an early bailout for invalid and synced elements
+ // (memory elements are always synced).
+ UNREACHABLE();
+ break;
+
+ case FrameElement::REGISTER:
+ __ mov(Operand(ebp, fp_relative(index)), element.reg());
+ break;
+
+ case FrameElement::CONSTANT:
__ Set(Operand(ebp, fp_relative(index)), Immediate(element.handle()));
- } else {
- ASSERT(element.is_register());
- __ mov(Operand(ebp, fp_relative(index)), element.reg());
+ break;
+
+ case FrameElement::COPY: {
+ int backing_index = element.index();
+ FrameElement backing_element = elements_[backing_index];
+ if (backing_element.is_memory()) {
+ Result temp = cgen_->allocator()->Allocate();
+ ASSERT(temp.is_valid());
+ __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index)));
+ __ mov(Operand(ebp, fp_relative(index)), temp.reg());
+ } else {
+ ASSERT(backing_element.is_register());
+ __ mov(Operand(ebp, fp_relative(index)), backing_element.reg());
+ }
+ break;
}
- } else {
- // Push elements above the stack pointer to allocate space and sync
- // them. Space should have already been allocated in the actual frame
- // for all the elements below this one.
- ASSERT(index == stack_pointer_ + 1);
- stack_pointer_++;
- if (element.is_constant()) {
+ }
+
+ } else {
+ // Push elements above the stack pointer to allocate space and
+ // sync them. Space should have already been allocated in the
+ // actual frame for all the elements below this one.
+ ASSERT(index == stack_pointer_ + 1);
+ stack_pointer_++;
+ switch (element.type()) {
+ case FrameElement::INVALID: // Fall through.
+ case FrameElement::MEMORY:
+ // There was an early bailout for invalid and synced elements
+ // (memory elements are always synced).
+ UNREACHABLE();
+ break;
+
+ case FrameElement::REGISTER:
+ __ push(element.reg());
+ break;
+
+ case FrameElement::CONSTANT:
__ push(Immediate(element.handle()));
- } else {
- ASSERT(element.is_register());
- __ push(element.reg());
+ break;
+
+ case FrameElement::COPY: {
+ int backing_index = element.index();
+ FrameElement backing = elements_[backing_index];
+ ASSERT(backing.is_memory() || backing.is_register());
+ if (backing.is_memory()) {
+ __ push(Operand(ebp, fp_relative(backing_index)));
+ } else {
+ __ push(backing.reg());
+ }
+ break;
}
}
+ }
- elements_[index].set_sync();
- }
+ elements_[index].set_sync();
}
@@ -253,12 +336,19 @@
ASSERT(height() >= spilled_args);
ASSERT(dropped_args <= spilled_args);
- // Below the arguments to the function being called, spill all registers and
- // make sure that locals have the right values by synching them. The synching
- // is necessary to give the debugger a consistent view of the values of
- // locals in the frame. Spill the arguments to the function being called.
int arg_base_index = elements_.length() - spilled_args;
- for (int i = 0; i < arg_base_index; i++) {
+ // Spill the arguments. We spill from the top down so that the
+ // backing stores of register copies will be spilled only after all
+ // the copies are spilled---it is better to spill via a
+ // register-to-memory move than a memory-to-memory move.
+ for (int i = elements_.length() - 1; i >= arg_base_index; i--) {
+ SpillElementAt(i);
+ }
+
+ // Below the arguments, spill registers and sync everything else.
+ // Syncing is necessary for the locals and parameters to give the
+ // debugger a consistent view of the frame.
+ for (int i = arg_base_index - 1; i >= 0; i--) {
FrameElement element = elements_[i];
if (element.is_register()) {
SpillElementAt(i);
@@ -266,10 +356,6 @@
SyncElementAt(i);
}
}
- // The arguments are spilled.
- for (int i = arg_base_index; i < elements_.length(); i++) {
- SpillElementAt(i);
- }
// Forget the frame elements that will be popped by the call.
Forget(dropped_args);
@@ -283,53 +369,142 @@
ASSERT(cgen_->frame() == this);
ASSERT(cgen_->HasValidEntryRegisters());
- // Remove constants from the frame and ensure that no registers are
- // multiply referenced within the frame. Allocate elements to their new
- // locations from the top down so that the topmost elements have a chance
- // to be in registers, then fill them into memory from the bottom up.
- // (NB: Currently when spilling registers that are multiply referenced, it
- // is the lowermost occurrence that gets to stay in the register.)
-
- // The elements of new_elements are initially invalid.
+ // Remove constants from the frame and ensure that there are no
+ // copies. Allocate elements to their new locations from the top
+ // down so that the topmost elements have a chance to be in
+ // registers, then fill them into memory from the bottom up.
+ //
+ // Compute the new frame elements first. The elements of
+ // new_elements are initially invalid.
FrameElement* new_elements = new FrameElement[elements_.length()];
+ // Array of flags, true if we have found a the topmost copy of a
+ // register. Every element after the first is initialized to 0 (ie,
+ // false).
+ bool topmost_found[RegisterFile::kNumRegisters] = { false };
+ // "Singleton" memory element. They have no internal state.
FrameElement memory_element = FrameElement::MemoryElement();
+
for (int i = elements_.length() - 1; i >= 0; i--) {
FrameElement element = elements_[i];
- if (element.is_constant() ||
- (element.is_register() &&
- frame_registers_.count(element.reg()) > 1)) {
- // A simple strategy is to locate these elements in memory if they are
- // synced (avoiding a spill right now) and otherwise to prefer a
- // register for them.
- if (element.is_synced()) {
- new_elements[i] = memory_element;
- } else {
- Result fresh = cgen_->allocator()->AllocateWithoutSpilling();
- if (fresh.is_valid()) {
- // We immediately record the frame's use of the register so that
- // it will not be allocated again.
- Use(fresh.reg());
- new_elements[i] =
- FrameElement::RegisterElement(fresh.reg(),
- FrameElement::NOT_SYNCED);
+
+ switch (element.type()) {
+ case FrameElement::INVALID: // Fall through.
+ case FrameElement::MEMORY:
+ new_elements[i] = element;
+ break;
+
+ case FrameElement::REGISTER:
+ // If this is not the first (and only) register reference we
+ // try to find a good home for it, otherwise it can stay in
+ // the register.
+ if (topmost_found[element.reg().code()]) {
+ // A simple strategy is to spill to memory if it is already
+ // synced (avoiding a spill now), and otherwise to prefer a
+ // register if one is available.
+ if (element.is_synced()) {
+ // We do not unuse this register reference because we want
+ // the register allocator to count the other one (higher
+ // up in the new frame).
+ new_elements[i] = memory_element;
+ } else {
+ Result fresh = cgen_->allocator()->AllocateWithoutSpilling();
+ if (fresh.is_valid()) {
+ // We immediately record the frame's use of the register
+ // so that the register allocator will not try to use it
+ // again.
+ Use(fresh.reg());
+ new_elements[i] =
+ FrameElement::RegisterElement(fresh.reg(),
+ FrameElement::NOT_SYNCED);
+ } else {
+ new_elements[i] = memory_element;
+ }
+ }
} else {
+ // The only occurrence can stay in the register.
+ new_elements[i] = element;
+ }
+ break;
+
+ case FrameElement::CONSTANT:
+ // Prefer spilling synced constants and registers for the rest.
+ if (element.is_synced()) {
new_elements[i] = memory_element;
+ } else {
+ Result fresh = cgen_->allocator()->AllocateWithoutSpilling();
+ if (fresh.is_valid()) {
+ // We immediately record the frame's use of the register
+ // so that the register allocator will not try to use it
+ // again.
+ Use(fresh.reg());
+ new_elements[i] =
+ FrameElement::RegisterElement(fresh.reg(),
+ FrameElement::NOT_SYNCED);
+ } else {
+ new_elements[i] = memory_element;
+ }
}
- }
+ break;
- // We have not moved register references, but record that we will so
- // that we do not unnecessarily spill the last reference within the
- // frame.
- if (element.is_register()) {
- Unuse(element.reg());
+ case FrameElement::COPY: {
+ FrameElement backing = elements_[element.index()];
+ if (backing.is_memory()) {
+ new_elements[i] = memory_element;
+ } else {
+ ASSERT(backing.is_register());
+ if (topmost_found[backing.reg().code()]) {
+ if (element.is_synced()) {
+ new_elements[i] = memory_element;
+ } else {
+ Result fresh = cgen_->allocator()->AllocateWithoutSpilling();
+ if (fresh.is_valid()) {
+ // We immediately record the frame's use of the
+ // register so that the register allocator will not
+ // try to use it again.
+ Use(fresh.reg());
+ new_elements[i] =
+ FrameElement::RegisterElement(fresh.reg(),
+ FrameElement::NOT_SYNCED);
+ } else {
+ new_elements[i] = memory_element;
+ }
+ }
+ // When performing the moves (from bottom to top) later,
+ // we will need to know what register this one is a copy
+ // of and the original backing element will already be
+ // overwritten. We store that information in this
+ // elements frame slot so that it looks like this is a
+ // move from a register rather than a copy.
+ if (element.is_synced()) {
+ backing.set_sync();
+ } else {
+ backing.clear_sync();
+ }
+ Use(backing.reg());
+ elements_[i] = backing;
+
+ } else {
+ // This is the top occurrence of the register.
+ topmost_found[backing.reg().code()] = true;
+ if (element.is_synced()) {
+ backing.set_sync();
+ } else {
+ backing.clear_sync();
+ }
+ // Record the register reference immediately so that
+ // register allocator does not try to use this register as
+ // a temp register when performing the moves.
+ Use(backing.reg());
+ new_elements[i] = backing;
+ }
+ }
+ break;
}
- } else {
- // The element is in memory or a singly-frame-referenced register.
- new_elements[i] = element;
}
}
- // Perform the moves.
+ // Perform the moves. Reference counts for register targets have
+ // already been incremented.
for (int i = 0; i < elements_.length(); i++) {
FrameElement source = elements_[i];
FrameElement target = new_elements[i];
@@ -338,15 +513,18 @@
if (source.is_constant()) {
__ Set(target.reg(), Immediate(source.handle()));
} else if (source.is_register() && !source.reg().is(target.reg())) {
+ Unuse(source.reg());
__ mov(target.reg(), source.reg());
}
+ // Otherwise the source and target are the same register or the
+ // source is a copy. If the source is a copy that implies that
+ // it is the same register as the target (copies that are moved
+ // to other registers appear as register-to-register moves).
elements_[i] = target;
+ ASSERT(target.is_synced() == source.is_synced());
} else if (target.is_memory()) {
if (!source.is_memory()) {
- // Spilling a source register would decrement its reference count,
- // but we have already done that when computing new target elements,
- // so we use a raw spill.
- RawSpillElementAt(i);
+ SpillElementAt(i);
}
}
// Invalid elements do not need to be moved.
@@ -425,11 +603,14 @@
void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame *expected) {
+ // Move registers, constants, and copies to memory.
for (int i = 0; i < elements_.length(); i++) {
FrameElement source = elements_[i];
FrameElement target = expected->elements_[i];
if (target.is_memory() && !source.is_memory()) {
- ASSERT(source.is_register() || source.is_constant());
+ ASSERT(source.is_register() ||
+ source.is_constant() ||
+ source.is_copy());
SpillElementAt(i);
}
}
@@ -437,6 +618,7 @@
void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame *expected) {
+ // Perform register-to-register moves.
int start = 0;
int end = elements_.length() - 1;
bool any_moves_blocked; // Did we fail to make some moves this iteration?
@@ -498,46 +680,45 @@
void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame *expected) {
- // Finally, constant-to-register and memory-to-register. We do these from
- // the top down so we can use pop for memory-to-register moves above the
- // expected stack pointer.
- for (int i = elements_.length() - 1; i >= 0; i--) {
+ // Move memory, constants, and copies to registers. This is the
+ // final step and is done from the bottom up so that the backing
+ // elements of copies are in their correct locations when we
+ // encounter the copies.
+ for (int i = 0; i < elements_.length(); i++) {
FrameElement source = elements_[i];
FrameElement target = expected->elements_[i];
if (target.is_register() && !source.is_register()) {
- ASSERT(source.is_constant() || source.is_memory());
- if (source.is_memory()) {
- ASSERT(i <= stack_pointer_);
- if (i <= expected->stack_pointer_) {
- // Elements below both stack pointers can just be moved.
+ switch (source.type()) {
+ case FrameElement::INVALID: // Fall through.
+ case FrameElement::REGISTER:
+ UNREACHABLE();
+ break;
+
+ case FrameElement::MEMORY:
+ ASSERT(i <= stack_pointer_);
__ mov(target.reg(), Operand(ebp, fp_relative(i)));
- } else {
- // Elements below the current stack pointer but above the expected
- // one can be popped, but first we may have to adjust the stack
- // pointer downward.
- if (stack_pointer_ > i) {
- // Sync elements between i and stack pointer, and bring
- // stack pointer down to i.
-#ifdef DEBUG
- // In debug builds check to ensure this is safe.
- for (int j = stack_pointer_; j > i; j--) {
- ASSERT(!elements_[j].is_memory());
- }
-#endif
- int difference = stack_pointer_ - i;
- __ add(Operand(esp), Immediate(difference * kPointerSize));
- stack_pointer_ = i;
+ break;
+
+ case FrameElement::CONSTANT:
+ __ Set(target.reg(), Immediate(source.handle()));
+ break;
+
+ case FrameElement::COPY: {
+ FrameElement backing = elements_[source.index()];
+ ASSERT(backing.is_memory() || backing.is_register());
+ if (backing.is_memory()) {
+ ASSERT(source.index() <= stack_pointer_);
+ __ mov(target.reg(), Operand(ebp, fp_relative(source.index())));
+ } else {
+ __ mov(target.reg(), backing.reg());
}
- stack_pointer_--;
- __ pop(target.reg());
}
- } else {
- // Source is constant.
- __ Set(target.reg(), Immediate(source.handle()));
- if (target.is_synced()) {
- SyncElementAt(i);
- }
}
+ // Ensure the proper sync state. If the source was memory no
+ // code needs to be emitted.
+ if (target.is_synced() && !source.is_memory()) {
+ SyncElementAt(i);
+ }
Use(target.reg());
elements_[i] = target;
}
@@ -661,32 +842,66 @@
ASSERT(frame_index >= 0);
ASSERT(frame_index < elements_.length());
ASSERT(value->is_valid());
- FrameElement target = elements_[frame_index];
+ FrameElement original = elements_[frame_index];
- if (target.is_register()) {
- Unuse(target.reg());
+ // Early exit if the element is the same as the one being set.
+ bool same_register = original.is_register()
+ && value->is_register()
+ && original.reg().is(value->reg());
+ bool same_constant = original.is_constant()
+ && value->is_constant()
+ && original.handle().is_identical_to(value->handle());
+ if (same_register || same_constant) {
+ value->Unuse();
+ return;
}
+ // If the original may be a copy, adjust to preserve the copy-on-write
+ // semantics of copied elements.
+ if (original.is_register() || original.is_memory()) {
+ FrameElement ignored = AdjustCopies(frame_index);
+ }
+
+ // If the original is a register reference, deallocate it.
+ if (original.is_register()) {
+ Unuse(original.reg());
+ }
+
+ FrameElement new_element;
if (value->is_register()) {
- Use(value->reg());
- // Write the new value to the frame, if it is changed.
- // Otherwise, if target equals value, keep its current sync state.
- if (!target.is_register() ||
- !value->reg().is(target.reg())) {
+ // There are two cases depending no whether the register already
+ // occurs in the frame or not.
+ if (register_count(value->reg()) == 0) {
+ Use(value->reg());
elements_[frame_index] =
FrameElement::RegisterElement(value->reg(),
FrameElement::NOT_SYNCED);
+ } else {
+ for (int i = 0; i < elements_.length(); i++) {
+ FrameElement element = elements_[i];
+ if (element.is_register() && element.reg().is(value->reg())) {
+ // The register backing store is lower in the frame than its
+ // copy.
+ if (i < frame_index) {
+ elements_[frame_index] = CopyElementAt(i);
+ } else {
+ // There was an early bailout for the case of setting a
+ // register element to itself.
+ ASSERT(i != frame_index);
+ element.clear_sync();
+ elements_[frame_index] = element;
+ elements_[i] = CopyElementAt(frame_index);
+ }
+ // Exit the loop once the appropriate copy is inserted.
+ break;
+ }
+ }
}
} else {
ASSERT(value->is_constant());
- // Write the new value to the frame element, if it is a change.
- // Otherwise, do nothing, and keep the current sync state.
- if (!target.is_constant() ||
- !value->handle().is_identical_to(target.handle())) {
- elements_[frame_index] =
- FrameElement::ConstantElement(value->handle(),
- FrameElement::NOT_SYNCED);
- }
+ elements_[frame_index] =
+ FrameElement::ConstantElement(value->handle(),
+ FrameElement::NOT_SYNCED);
}
value->Unuse();
}
@@ -733,81 +948,258 @@
void VirtualFrame::LoadFrameSlotAt(int index) {
- ASSERT(index >= 0);
- ASSERT(index < elements_.length());
+ FrameElement new_element = CopyElementAt(index);
+ elements_.Add(new_element);
+}
- FrameElement element = elements_[index];
- if (element.is_memory()) {
- ASSERT(index <= stack_pointer_);
- // Eagerly load memory elements into a register. The element at
- // the index and the new top of the frame are backed by the same
- // register location.
- Result temp = cgen_->allocator()->Allocate();
- ASSERT(temp.is_valid());
- FrameElement new_element
- = FrameElement::RegisterElement(temp.reg(),
- FrameElement::SYNCED);
- Use(temp.reg());
- elements_[index] = new_element;
- __ mov(temp.reg(), Operand(ebp, fp_relative(index)));
+// Before changing an element which is copied, adjust so that the
+// first copy becomes the new backing store and all the other copies
+// are updated. If the original was in memory, the new backing store
+// is allocated to a register. Return a copy of the new backing store
+// or an invalid element if the original was not a copy.
+FrameElement VirtualFrame::AdjustCopies(int index) {
+ FrameElement original = elements_[index];
+ ASSERT(original.is_memory() || original.is_register());
- Use(temp.reg());
- new_element.clear_sync();
- elements_.Add(new_element);
- } else {
- // For constants and registers, add an (unsynced) copy of the element to
- // the top of the frame.
- ASSERT(element.is_register() || element.is_constant());
- if (element.is_register()) {
- Use(element.reg());
+ // Go looking for a first copy above index.
+ int i = index + 1;
+ while (i < elements_.length()) {
+ FrameElement elt = elements_[i];
+ if (elt.is_copy() && elt.index() == index) break;
+ i++;
+ }
+
+ if (i < elements_.length()) {
+ // There was a first copy. Make it the new backing element.
+ Register backing_reg;
+ if (original.is_memory()) {
+ Result fresh = cgen_->allocator()->Allocate();
+ ASSERT(fresh.is_valid());
+ backing_reg = fresh.reg();
+ __ mov(backing_reg, Operand(ebp, fp_relative(index)));
+ } else {
+ // The original was in a register.
+ backing_reg = original.reg();
}
- element.clear_sync();
- elements_.Add(element);
+ FrameElement new_backing_element =
+ FrameElement::RegisterElement(backing_reg, FrameElement::NOT_SYNCED);
+ if (elements_[i].is_synced()) {
+ new_backing_element.set_sync();
+ }
+ Use(backing_reg);
+ elements_[i] = new_backing_element;
+
+ // Update the other copies.
+ FrameElement copy = CopyElementAt(i);
+ for (int j = i; j < elements_.length(); j++) {
+ FrameElement elt = elements_[j];
+ if (elt.is_copy() && elt.index() == index) {
+ if (elt.is_synced()) {
+ copy.set_sync();
+ } else {
+ copy.clear_sync();
+ }
+ elements_[j] = copy;
+ }
+ }
+
+ copy.clear_sync();
+ return copy;
}
+
+ return FrameElement::InvalidElement();
}
void VirtualFrame::TakeFrameSlotAt(int index) {
- LoadFrameSlotAt(index);
+ ASSERT(index >= 0);
+ ASSERT(index <= elements_.length());
+ FrameElement original = elements_[index];
- if (elements_[index].is_register()) {
- Unuse(elements_[index].reg());
+ switch (original.type()) {
+ case FrameElement::INVALID:
+ UNREACHABLE();
+ break;
+
+ case FrameElement::MEMORY: {
+ // Allocate the element to a register. If it is not copied,
+ // push that register on top of the frame. If it is copied,
+ // make the first copy the backing store and push a fresh copy
+ // on top of the frame.
+ FrameElement copy = AdjustCopies(index);
+ if (copy.is_valid()) {
+ // The original element was a copy. Push the copy of the new
+ // backing store.
+ elements_.Add(copy);
+ } else {
+ // The element was not a copy. Move it to a register and push
+ // that.
+ Result fresh = cgen_->allocator()->Allocate();
+ ASSERT(fresh.is_valid());
+ FrameElement new_element =
+ FrameElement::RegisterElement(fresh.reg(),
+ FrameElement::NOT_SYNCED);
+ Use(fresh.reg());
+ elements_.Add(new_element);
+ __ mov(fresh.reg(), Operand(ebp, fp_relative(index)));
+ }
+ break;
+ }
+
+ case FrameElement::REGISTER: {
+ // If the element is not copied, push it on top of the frame.
+ // If it is copied, make the first copy be the new backing store
+ // and push a fresh copy on top of the frame.
+ FrameElement copy = AdjustCopies(index);
+ if (copy.is_valid()) {
+ // The original element was a copy. Push the copy of the new
+ // backing store.
+ elements_.Add(copy);
+ // This is the only case where we have to unuse the original
+ // register. The original is still counted and so is the new
+ // backing store of the copies.
+ Unuse(original.reg());
+ } else {
+ // The element was not a copy. Push it.
+ original.clear_sync();
+ elements_.Add(original);
+ }
+ break;
+ }
+
+ case FrameElement::CONSTANT:
+ elements_.Add(original);
+ break;
+
+ case FrameElement::COPY:
+ elements_.Add(original);
+ break;
}
elements_[index] = FrameElement::InvalidElement();
}
void VirtualFrame::StoreToFrameSlotAt(int index) {
- // Store the value on top of the frame to the virtual frame slot at a
- // given index. The value on top of the frame is left in place.
+ // Store the value on top of the frame to the virtual frame slot at
+ // a given index. The value on top of the frame is left in place.
+ // This is a duplicating operation, so it can create copies.
ASSERT(index >= 0);
ASSERT(index < elements_.length());
- FrameElement top = elements_[elements_.length() - 1];
- if (elements_[index].is_register()) {
- Unuse(elements_[index].reg());
+ FrameElement original = elements_[index];
+ // If the stored-to slot may be copied, adjust to preserve the
+ // copy-on-write semantics of copied elements.
+ if (original.is_register() || original.is_memory()) {
+ FrameElement ignored = AdjustCopies(index);
}
- // The virtual frame slot will be of the same type and have the same value
- // as the frame top.
+
+ // If the stored-to slot is a register reference, deallocate it.
+ if (original.is_register()) {
+ Unuse(original.reg());
+ }
+
+ int top_index = elements_.length() - 1;
+ FrameElement top = elements_[top_index];
+ ASSERT(top.is_valid());
+
+ if (top.is_copy()) {
+ // There are two cases based on the relative positions of the
+ // stored-to slot and the backing slot of the top element.
+ int backing_index = top.index();
+ ASSERT(backing_index != index);
+ if (backing_index < index) {
+ // 1. The top element is a copy of a slot below the stored-to
+ // slot. The stored-to slot becomes an unsynced copy of that
+ // same backing slot.
+ elements_[index] = CopyElementAt(backing_index);
+ } else {
+ // 2. The top element is a copy of a slot above the stored-to
+ // slot. The stored-to slot becomes the new (unsynced) backing
+ // slot and both the top element and the element at the former
+ // backing slot become copies of it. The sync state of the top
+ // and former backing elements is preserved.
+ FrameElement backing_element = elements_[backing_index];
+ ASSERT(backing_element.is_memory() || backing_element.is_register());
+ if (backing_element.is_memory()) {
+ // Because sets of copies are canonicalized to be backed by
+ // their lowest frame element, and because memory frame
+ // elements are backed by the corresponding stack address, we
+ // have to move the actual value down in the stack.
+ //
+ // TODO(209): considering allocating the stored-to slot to the
+ // temp register. Alternatively, allow copies to appear in
+ // any order in the frame and lazily move the value down to
+ // the slot.
+ Result temp = cgen_->allocator()->Allocate();
+ ASSERT(temp.is_valid());
+ __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index)));
+ __ mov(Operand (ebp, fp_relative(index)), temp.reg());
+ } else if (backing_element.is_synced()) {
+ // If the element is a register, we will not actually move
+ // anything on the stack but only update the virtual frame
+ // element.
+ backing_element.clear_sync();
+ }
+ elements_[index] = backing_element;
+
+ // The old backing element becomes a copy of the new backing
+ // element.
+ FrameElement new_element = CopyElementAt(index);
+ elements_[backing_index] = new_element;
+ if (backing_element.is_synced()) {
+ elements_[backing_index].set_sync();
+ }
+
+ // All the copies of the old backing element (including the top
+ // element) become copies of the new backing element.
+ for (int i = backing_index + 1; i < elements_.length(); i++) {
+ FrameElement current = elements_[i];
+ if (current.is_copy() && current.index() == backing_index) {
+ elements_[i] = new_element;
+ if (current.is_synced()) {
+ elements_[i].set_sync();
+ }
+ }
+ }
+
+ }
+
+ return;
+ }
+
+ // Move the top element to the stored-to slot and replace it (the
+ // top element) with a copy.
elements_[index] = top;
+ if (top.is_memory()) {
+ // TODO(209): consider allocating the stored-to slot to the temp
+ // register. Alternatively, allow copies to appear in any order
+ // in the frame and lazily move the value down to the slot.
+ FrameElement new_top = CopyElementAt(index);
+ new_top.set_sync();
+ elements_[top_index] = new_top;
- if (top.is_memory()) {
- // TODO(209): consider allocating the slot to a register.
- //
- // Emit code to store memory values into the required frame slot.
+ // The sync state of the former top element is correct (synced).
+ // Emit code to move the value down in the frame.
Result temp = cgen_->allocator()->Allocate();
ASSERT(temp.is_valid());
__ mov(temp.reg(), Top());
__ mov(Operand(ebp, fp_relative(index)), temp.reg());
+ } else if (top.is_register()) {
+ // The stored-to slot has the (unsynced) register reference and
+ // the top element becomes a copy. The sync state of the top is
+ // preserved.
+ FrameElement new_top = CopyElementAt(index);
+ if (top.is_synced()) {
+ new_top.set_sync();
+ elements_[index].clear_sync();
+ }
+ elements_[top_index] = new_top;
} else {
- // We have not actually written the value to memory.
+ // The stored-to slot holds the same value as the top but
+ // unsynced. (We do not have copies of constants yet.)
+ ASSERT(top.is_constant());
elements_[index].clear_sync();
-
- if (top.is_register()) {
- // Establish another frame-internal reference to the register.
- Use(top.reg());
- }
}
}
@@ -825,9 +1217,8 @@
}
-Result VirtualFrame::CallStub(CodeStub* stub, int frame_arg_count) {
+Result VirtualFrame::RawCallStub(CodeStub* stub, int frame_arg_count) {
ASSERT(cgen_->HasValidEntryRegisters());
- PrepareForCall(frame_arg_count, frame_arg_count);
__ CallStub(stub);
Result result = cgen_->allocator()->Allocate(eax);
ASSERT(result.is_valid());
@@ -835,11 +1226,18 @@
}
+Result VirtualFrame::CallStub(CodeStub* stub, int frame_arg_count) {
+ PrepareForCall(frame_arg_count, frame_arg_count);
+ return RawCallStub(stub, frame_arg_count);
+}
+
+
Result VirtualFrame::CallStub(CodeStub* stub,
Result* arg,
int frame_arg_count) {
+ PrepareForCall(frame_arg_count, frame_arg_count);
arg->Unuse();
- return CallStub(stub, frame_arg_count);
+ return RawCallStub(stub, frame_arg_count);
}
@@ -847,16 +1245,17 @@
Result* arg0,
Result* arg1,
int frame_arg_count) {
+ PrepareForCall(frame_arg_count, frame_arg_count);
arg0->Unuse();
arg1->Unuse();
- return CallStub(stub, frame_arg_count);
+ return RawCallStub(stub, frame_arg_count);
}
Result VirtualFrame::CallRuntime(Runtime::Function* f,
int frame_arg_count) {
+ PrepareForCall(frame_arg_count, frame_arg_count);
ASSERT(cgen_->HasValidEntryRegisters());
- PrepareForCall(frame_arg_count, frame_arg_count);
__ CallRuntime(f, frame_arg_count);
Result result = cgen_->allocator()->Allocate(eax);
ASSERT(result.is_valid());
@@ -866,8 +1265,8 @@
Result VirtualFrame::CallRuntime(Runtime::FunctionId id,
int frame_arg_count) {
+ PrepareForCall(frame_arg_count, frame_arg_count);
ASSERT(cgen_->HasValidEntryRegisters());
- PrepareForCall(frame_arg_count, frame_arg_count);
__ CallRuntime(id, frame_arg_count);
Result result = cgen_->allocator()->Allocate(eax);
ASSERT(result.is_valid());
@@ -878,8 +1277,8 @@
Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
int frame_arg_count) {
+ PrepareForCall(frame_arg_count, frame_arg_count);
ASSERT(cgen_->HasValidEntryRegisters());
- PrepareForCall(frame_arg_count, frame_arg_count);
__ InvokeBuiltin(id, flag);
Result result = cgen_->allocator()->Allocate(eax);
ASSERT(result.is_valid());
@@ -888,11 +1287,8 @@
Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
- RelocInfo::Mode rmode,
- int spilled_args,
- int dropped_args) {
+ RelocInfo::Mode rmode) {
ASSERT(cgen_->HasValidEntryRegisters());
- PrepareForCall(spilled_args, dropped_args);
__ call(code, rmode);
Result result = cgen_->allocator()->Allocate(eax);
ASSERT(result.is_valid());
@@ -922,7 +1318,8 @@
UNREACHABLE();
break;
}
- return RawCallCodeObject(code, rmode, spilled_args, dropped_args);
+ PrepareForCall(spilled_args, dropped_args);
+ return RawCallCodeObject(code, rmode);
}
@@ -952,8 +1349,9 @@
UNREACHABLE();
break;
}
+ PrepareForCall(spilled_args, dropped_args);
arg->Unuse();
- return RawCallCodeObject(code, rmode, spilled_args, dropped_args);
+ return RawCallCodeObject(code, rmode);
}
@@ -982,9 +1380,10 @@
UNREACHABLE();
break;
}
+ PrepareForCall(spilled_args, dropped_args);
arg0->Unuse();
arg1->Unuse();
- return RawCallCodeObject(code, rmode, spilled_args, dropped_args);
+ return RawCallCodeObject(code, rmode);
}
@@ -1010,30 +1409,53 @@
Result VirtualFrame::Pop() {
- FrameElement popped = elements_.RemoveLast();
- bool pop_needed = (stack_pointer_ == elements_.length());
+ FrameElement element = elements_.RemoveLast();
+ int index = elements_.length();
+ ASSERT(element.is_valid());
- if (popped.is_constant()) {
- if (pop_needed) {
- stack_pointer_--;
- __ add(Operand(esp), Immediate(kPointerSize));
+ bool pop_needed = (stack_pointer_ == index);
+ if (pop_needed) {
+ stack_pointer_--;
+ if (element.is_memory()) {
+ Result temp = cgen_->allocator()->Allocate();
+ ASSERT(temp.is_valid());
+ __ pop(temp.reg());
+ return temp;
}
- return Result(popped.handle(), cgen_);
- } else if (popped.is_register()) {
- Unuse(popped.reg());
- if (pop_needed) {
- stack_pointer_--;
- __ add(Operand(esp), Immediate(kPointerSize));
- }
- return Result(popped.reg(), cgen_);
- } else {
- ASSERT(popped.is_memory());
+
+ __ add(Operand(esp), Immediate(kPointerSize));
+ }
+ ASSERT(!element.is_memory());
+
+ // The top element is a register, constant, or a copy. Unuse
+ // registers and follow copies to their backing store.
+ if (element.is_register()) {
+ Unuse(element.reg());
+ } else if (element.is_copy()) {
+ ASSERT(element.index() < index);
+ index = element.index();
+ element = elements_[index];
+ }
+ ASSERT(!element.is_copy());
+
+ // The element is memory, a register, or a constant.
+ if (element.is_memory()) {
+ // Memory elements could only be the backing store of a copy.
+ // Allocate the original to a register.
+ ASSERT(index <= stack_pointer_);
Result temp = cgen_->allocator()->Allocate();
ASSERT(temp.is_valid());
- ASSERT(pop_needed);
- stack_pointer_--;
- __ pop(temp.reg());
- return temp;
+ Use(temp.reg());
+ FrameElement new_element =
+ FrameElement::RegisterElement(temp.reg(), FrameElement::SYNCED);
+ elements_[index] = new_element;
+ __ mov(temp.reg(), Operand(ebp, fp_relative(index)));
+ return Result(temp.reg(), cgen_);
+ } else if (element.is_register()) {
+ return Result(element.reg(), cgen_);
+ } else {
+ ASSERT(element.is_constant());
+ return Result(element.handle(), cgen_);
}
}
@@ -1079,9 +1501,21 @@
void VirtualFrame::Push(Register reg) {
- Use(reg);
- elements_.Add(FrameElement::RegisterElement(reg,
- FrameElement::NOT_SYNCED));
+ FrameElement new_element;
+ if (register_count(reg) == 0) {
+ Use(reg);
+ new_element =
+ FrameElement::RegisterElement(reg, FrameElement::NOT_SYNCED);
+ } else {
+ for (int i = 0; i < elements_.length(); i++) {
+ FrameElement element = elements_[i];
+ if (element.is_register() && element.reg().is(reg)) {
+ new_element = CopyElementAt(i);
+ break;
+ }
+ }
+ }
+ elements_.Add(new_element);
}
« no previous file with comments | « src/virtual-frame-ia32.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698