Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 26cb3c53dc92a5008151669e849a998710f4e107..74e973cdc3594fda4ad71915e73a85c92ea9313d 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -28,6 +28,7 @@ |
#include "v8.h" |
#include "accessors.h" |
+#include "allocation-site-scopes.h" |
#include "api.h" |
#include "arguments.h" |
#include "bootstrapper.h" |
@@ -5615,6 +5616,14 @@ MUST_USE_RESULT MaybeObject* JSObject::SetObserved(Isolate* isolate) { |
} |
+Handle<JSObject> JSObject::Copy(Handle<JSObject> object, |
+ Handle<AllocationSite> site) { |
+ Isolate* isolate = object->GetIsolate(); |
+ CALL_HEAP_FUNCTION(isolate, |
+ isolate->heap()->CopyJSObject(*object, *site), JSObject); |
+} |
+ |
+ |
Handle<JSObject> JSObject::Copy(Handle<JSObject> object) { |
Isolate* isolate = object->GetIsolate(); |
CALL_HEAP_FUNCTION(isolate, |
@@ -5624,45 +5633,93 @@ Handle<JSObject> JSObject::Copy(Handle<JSObject> object) { |
class JSObjectWalkVisitor { |
public: |
- explicit JSObjectWalkVisitor() {} |
+ explicit JSObjectWalkVisitor(AllocationSiteContext* site_context) : |
+ site_context_(site_context) {} |
virtual ~JSObjectWalkVisitor() {} |
Handle<JSObject> Visit(Handle<JSObject> object) { |
return StructureWalk(object); |
} |
- // Returns true if the visitor is a copying visitor. |
virtual bool is_copying() = 0; |
protected: |
Handle<JSObject> StructureWalk(Handle<JSObject> object); |
- // The returned handle should point to a new object if the visitor is a |
- // copying visitor, otherwise it should be the same as the input object. |
+ // The returned handle will be used for the object in all subsequent usages. |
+ // This allows VisitObject to make a copy of the object if desired. |
virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0; |
- |
- // The returned handle should point to a new value if the visitor is a |
- // copying visitor, otherwise it should be the same as the input value. |
virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object, |
Handle<JSObject> value) = 0; |
+ |
+ AllocationSiteContext* site_context() { return site_context_; } |
+ |
+ private: |
+ AllocationSiteContext* site_context_; |
}; |
class JSObjectCopyVisitor: public JSObjectWalkVisitor { |
public: |
- explicit JSObjectCopyVisitor() {} |
+ explicit JSObjectCopyVisitor(AllocationSiteContext* site_context) |
+ : JSObjectWalkVisitor(site_context) {} |
virtual bool is_copying() V8_OVERRIDE { return true; } |
- protected: |
+ // The returned handle will be used for the object in all |
+ // subsequent usages. This allows VisitObject to make a copy |
+ // of the object if desired. |
+ virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE { |
+ // Only create a memento if |
+ // 1) we have a JSArray, and |
+ // 2) the elements kind is palatable |
+ // 3) allow_mementos is true |
+ Handle<JSObject> copy; |
+ if (site_context()->activated() && |
+ AllocationSite::CanTrack(object->map()->instance_type()) && |
+ AllocationSite::GetMode(object->GetElementsKind()) == |
+ TRACK_ALLOCATION_SITE) { |
+ copy = JSObject::Copy(object, site_context()->current()); |
+ } else { |
+ copy = JSObject::Copy(object); |
+ } |
+ |
+ return copy; |
+ } |
+ |
+ virtual Handle<JSObject> VisitElementOrProperty( |
+ Handle<JSObject> object, |
+ Handle<JSObject> value) V8_OVERRIDE { |
+ Handle<AllocationSite> current_site = site_context()->EnterNewScope(); |
+ Handle<JSObject> copy_of_value = StructureWalk(value); |
+ site_context()->ExitScope(current_site, value); |
+ return copy_of_value; |
+ } |
+}; |
+ |
+ |
+class JSObjectCreateAllocationSitesVisitor: public JSObjectWalkVisitor { |
+ public: |
+ explicit JSObjectCreateAllocationSitesVisitor( |
+ AllocationSiteContext* site_context) |
+ : JSObjectWalkVisitor(site_context) {} |
+ |
+ virtual bool is_copying() V8_OVERRIDE { return false; } |
+ |
+ // The returned handle will be used for the object in all |
+ // subsequent usages. This allows VisitObject to make a copy |
+ // of the object if desired. |
virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE { |
- return JSObject::Copy(object); |
+ return object; |
} |
virtual Handle<JSObject> VisitElementOrProperty( |
Handle<JSObject> object, |
Handle<JSObject> value) V8_OVERRIDE { |
- return StructureWalk(value); |
+ Handle<AllocationSite> current_site = site_context()->EnterNewScope(); |
+ value = StructureWalk(value); |
+ site_context()->ExitScope(current_site, value); |
+ return value; |
} |
}; |
@@ -5809,8 +5866,19 @@ Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) { |
} |
-Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) { |
- JSObjectCopyVisitor v; |
+Handle<JSObject> JSObject::DeepWalk(Handle<JSObject> object, |
+ AllocationSiteContext* site_context) { |
+ JSObjectCreateAllocationSitesVisitor v(site_context); |
+ Handle<JSObject> result = v.Visit(object); |
+ ASSERT(!v.is_copying() && |
+ (result.is_null() || result.is_identical_to(object))); |
+ return result; |
+} |
+ |
+ |
+Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object, |
+ AllocationSiteContext* site_context) { |
+ JSObjectCopyVisitor v(site_context); |
Handle<JSObject> copy = v.Visit(object); |
ASSERT(v.is_copying() && !copy.is_identical_to(object)); |
return copy; |
@@ -12573,6 +12641,20 @@ void JSObject::TransitionElementsKind(Handle<JSObject> object, |
} |
+bool AllocationSite::IsNestedSite() { |
+ ASSERT(FLAG_trace_track_allocation_sites); |
+ Object* current = GetHeap()->allocation_sites_list(); |
+ while (current != NULL && current->IsAllocationSite()) { |
+ AllocationSite* current_site = AllocationSite::cast(current); |
+ if (current_site->nested_site() == this) { |
+ return true; |
+ } |
+ current = current_site->weak_next(); |
+ } |
+ return false; |
+} |
+ |
+ |
MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) { |
if (!FLAG_track_allocation_sites || !IsJSArray()) { |
return this; |
@@ -12585,7 +12667,8 @@ MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) { |
// Walk through to the Allocation Site |
AllocationSite* site = memento->GetAllocationSite(); |
- if (site->IsLiteralSite()) { |
+ if (site->SitePointsToLiteral() && |
+ site->transition_info()->IsJSArray()) { |
JSArray* transition_info = JSArray::cast(site->transition_info()); |
ElementsKind kind = transition_info->GetElementsKind(); |
// if kind is holey ensure that to_kind is as well. |
@@ -12599,9 +12682,11 @@ MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) { |
CHECK(transition_info->length()->ToArrayIndex(&length)); |
if (length <= AllocationSite::kMaximumArrayBytesToPretransition) { |
if (FLAG_trace_track_allocation_sites) { |
+ bool is_nested = site->IsNestedSite(); |
PrintF( |
- "AllocationSite: JSArray %p boilerplate updated %s->%s\n", |
+ "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n", |
reinterpret_cast<void*>(this), |
+ is_nested ? "(nested)" : "", |
ElementsKindToString(kind), |
ElementsKindToString(to_kind)); |
} |