Revert "AllocationSites for all literals"

This reverts commit r17219 due to WebKit failures.

R=mstarzinger@chromium.org
TBR=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/26539010

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17222 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mvstanton@chromium.org 2013-10-15 15:35:23 +00:00
parent ea4e0a3d28
commit f4edc076d8
10 changed files with 72 additions and 554 deletions

View File

@ -1,108 +0,0 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "allocation-site-scopes.h"
namespace v8 {
namespace internal {
Handle<AllocationSite> AllocationSiteCreationContext::EnterNewScope() {
Handle<AllocationSite> scope_site;
if (top().is_null()) {
// We are creating the top level AllocationSite as opposed to a nested
// AllocationSite.
InitializeTraversal(isolate()->factory()->NewAllocationSite());
scope_site = Handle<AllocationSite>(*top(), isolate());
if (FLAG_trace_creation_allocation_sites) {
PrintF("*** Creating top level AllocationSite %p\n",
static_cast<void*>(*scope_site));
}
} else {
ASSERT(!current().is_null());
scope_site = isolate()->factory()->NewAllocationSite();
if (FLAG_trace_creation_allocation_sites) {
PrintF("Creating nested site (top, current, new) (%p, %p, %p)\n",
static_cast<void*>(*top()),
static_cast<void*>(*current()),
static_cast<void*>(*scope_site));
}
current()->set_nested_site(*scope_site);
update_current_site(*scope_site);
}
ASSERT(!scope_site.is_null());
return scope_site;
}
void AllocationSiteCreationContext::ExitScope(
Handle<AllocationSite> scope_site,
Handle<JSObject> object) {
if (!object.is_null() && !object->IsFailure()) {
bool top_level = !scope_site.is_null() &&
top().is_identical_to(scope_site);
scope_site->set_transition_info(*object);
if (FLAG_trace_creation_allocation_sites) {
if (top_level) {
PrintF("*** Setting AllocationSite %p transition_info %p\n",
static_cast<void*>(*scope_site),
static_cast<void*>(*object));
} else {
PrintF("Setting AllocationSite (%p, %p) transition_info %p\n",
static_cast<void*>(*top()),
static_cast<void*>(*scope_site),
static_cast<void*>(*object));
}
}
}
}
Handle<AllocationSite> AllocationSiteUsageContext::EnterNewScope() {
if (top().is_null()) {
InitializeTraversal(top_site_);
} else {
// Advance current site
Object* nested_site = current()->nested_site();
// Something is wrong if we advance to the end of the list here.
ASSERT(nested_site->IsAllocationSite());
update_current_site(AllocationSite::cast(nested_site));
}
return Handle<AllocationSite>(*current(), isolate());
}
void AllocationSiteUsageContext::ExitScope(
Handle<AllocationSite> scope_site,
Handle<JSObject> object) {
// This assert ensures that we are pointing at the right sub-object in a
// recursive walk of a nested literal.
ASSERT(*object == scope_site->transition_info());
}
} } // namespace v8::internal

View File

@ -1,115 +0,0 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_ALLOCATION_SITE_SCOPES_H_
#define V8_ALLOCATION_SITE_SCOPES_H_
#include "ast.h"
#include "handles.h"
#include "objects.h"
#include "zone.h"
namespace v8 {
namespace internal {
// AllocationSiteContext is the base class for walking and copying a nested
// boilerplate with AllocationSite and AllocationMemento support.
class AllocationSiteContext {
public:
AllocationSiteContext(Isolate* isolate, bool activated) {
isolate_ = isolate;
activated_ = activated;
};
virtual ~AllocationSiteContext() {}
Handle<AllocationSite> top() { return top_; }
Handle<AllocationSite> current() { return current_; }
// If activated, then recursively create mementos
bool activated() const { return activated_; }
// Returns the AllocationSite that matches this scope.
virtual Handle<AllocationSite> EnterNewScope() = 0;
// scope_site should be the handle returned by the matching EnterNewScope()
virtual void ExitScope(Handle<AllocationSite> scope_site,
Handle<JSObject> object) = 0;
protected:
void update_current_site(AllocationSite* site) {
*(current_.location()) = site;
}
Isolate* isolate() { return isolate_; }
void InitializeTraversal(Handle<AllocationSite> site) {
top_ = site;
current_ = Handle<AllocationSite>(*top_, isolate());
}
private:
Isolate* isolate_;
Handle<AllocationSite> top_;
Handle<AllocationSite> current_;
bool activated_;
};
// AllocationSiteCreationContext aids in the creation of AllocationSites to
// accompany object literals.
class AllocationSiteCreationContext : public AllocationSiteContext {
public:
explicit AllocationSiteCreationContext(Isolate* isolate)
: AllocationSiteContext(isolate, true) { }
virtual Handle<AllocationSite> EnterNewScope() V8_OVERRIDE;
virtual void ExitScope(Handle<AllocationSite> site,
Handle<JSObject> object) V8_OVERRIDE;
};
// AllocationSiteUsageContext aids in the creation of AllocationMementos placed
// behind some/all components of a copied object literal.
class AllocationSiteUsageContext : public AllocationSiteContext {
public:
AllocationSiteUsageContext(Isolate* isolate, Handle<AllocationSite> site,
bool activated)
: AllocationSiteContext(isolate, activated),
top_site_(site) { }
virtual Handle<AllocationSite> EnterNewScope() V8_OVERRIDE;
virtual void ExitScope(Handle<AllocationSite> site,
Handle<JSObject> object) V8_OVERRIDE;
private:
Handle<AllocationSite> top_site_;
};
} } // namespace v8::internal
#endif // V8_ALLOCATION_SITE_SCOPES_H_

View File

@ -806,9 +806,6 @@ DEFINE_implication(log_internal_timer_events, prof)
// elements.cc
DEFINE_bool(trace_elements_transitions, false, "trace elements transitions")
DEFINE_bool(trace_creation_allocation_sites, false,
"trace the creation of allocation sites")
// code-stubs.cc
DEFINE_bool(print_code_stubs, false, "print code stubs")
DEFINE_bool(test_secondary_stub_cache,

View File

@ -30,7 +30,6 @@
#include <algorithm>
#include "v8.h"
#include "allocation-site-scopes.h"
#include "codegen.h"
#include "full-codegen.h"
#include "hashmap.h"
@ -4299,10 +4298,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
if (!boilerplate.is_null() &&
IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
AllocationSiteUsageContext usage_context(isolate(), site, false);
usage_context.EnterNewScope();
literal = BuildFastLiteral(boilerplate, &usage_context);
usage_context.ExitScope(site, boilerplate);
literal = BuildFastLiteral(boilerplate);
} else {
NoObservableSideEffectsScope no_effects(this);
Handle<FixedArray> closure_literals(closure->literals(), isolate());
@ -4318,9 +4314,6 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
Add<HPushArgument>(Add<HConstant>(constant_properties));
Add<HPushArgument>(Add<HConstant>(flags));
// TODO(mvstanton): Add a flag to turn off creation of any
// AllocationMementos for this call: we are in crankshaft and should have
// learned enough about transition behavior to stop emitting mementos.
Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral;
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
Runtime::FunctionForId(function_id),
@ -4411,48 +4404,45 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
bool uninitialized = false;
Handle<Object> literals_cell(literals->get(expr->literal_index()),
isolate());
Handle<JSObject> boilerplate_object;
Handle<Object> raw_boilerplate;
if (literals_cell->IsUndefined()) {
uninitialized = true;
Handle<Object> raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
isolate(), literals, expr->constant_elements());
if (raw_boilerplate.is_null()) {
return Bailout(kArrayBoilerplateCreationFailed);
}
boilerplate_object = Handle<JSObject>::cast(raw_boilerplate);
AllocationSiteCreationContext creation_context(isolate());
site = creation_context.EnterNewScope();
JSObject::DeepWalk(boilerplate_object, &creation_context);
creation_context.ExitScope(site, boilerplate_object);
site = isolate()->factory()->NewAllocationSite();
site->set_transition_info(*raw_boilerplate);
literals->set(expr->literal_index(), *site);
if (boilerplate_object->elements()->map() ==
if (JSObject::cast(*raw_boilerplate)->elements()->map() ==
isolate()->heap()->fixed_cow_array_map()) {
isolate()->counters()->cow_arrays_created_runtime()->Increment();
}
} else {
ASSERT(literals_cell->IsAllocationSite());
site = Handle<AllocationSite>::cast(literals_cell);
boilerplate_object = Handle<JSObject>(
JSObject::cast(site->transition_info()), isolate());
raw_boilerplate = Handle<Object>(site->transition_info(), isolate());
}
ASSERT(!boilerplate_object.is_null());
ASSERT(site->SitePointsToLiteral());
ASSERT(!raw_boilerplate.is_null());
ASSERT(site->IsLiteralSite());
Handle<JSObject> boilerplate_object =
Handle<JSObject>::cast(raw_boilerplate);
ElementsKind boilerplate_elements_kind =
boilerplate_object->GetElementsKind();
Handle<JSObject>::cast(boilerplate_object)->GetElementsKind();
ASSERT(AllocationSite::CanTrack(boilerplate_object->map()->instance_type()));
// Check whether to use fast or slow deep-copying for boilerplate.
int max_properties = kMaxFastLiteralProperties;
if (IsFastLiteral(boilerplate_object,
kMaxFastLiteralDepth,
&max_properties)) {
AllocationSiteUsageContext usage_context(isolate(), site, false);
usage_context.EnterNewScope();
literal = BuildFastLiteral(boilerplate_object, &usage_context);
usage_context.ExitScope(site, boilerplate_object);
literal = BuildFastLiteral(boilerplate_object);
} else {
NoObservableSideEffectsScope no_effects(this);
// Boilerplate already exists and constant elements are never accessed,
@ -4464,9 +4454,6 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
Add<HPushArgument>(Add<HConstant>(literal_index));
Add<HPushArgument>(Add<HConstant>(constants));
// TODO(mvstanton): Consider a flag to turn off creation of any
// AllocationMementos for this call: we are in crankshaft and should have
// learned enough about transition behavior to stop emitting mementos.
Runtime::FunctionId function_id = (expr->depth() > 1)
? Runtime::kCreateArrayLiteral : Runtime::kCreateArrayLiteralShallow;
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
@ -8355,8 +8342,7 @@ HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
Handle<JSObject> boilerplate_object,
AllocationSiteContext* site_context) {
Handle<JSObject> boilerplate_object) {
NoObservableSideEffectsScope no_effects(this);
InstanceType instance_type = boilerplate_object->map()->instance_type();
ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
@ -8388,15 +8374,15 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
}
BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements);
// Copy object elements if non-COW.
if (object_elements != NULL) {
BuildEmitElements(boilerplate_object, elements, object_elements,
site_context);
BuildEmitElements(boilerplate_object, elements, object_elements);
}
// Copy in-object properties.
if (boilerplate_object->map()->NumberOfFields() != 0) {
BuildEmitInObjectProperties(boilerplate_object, object, site_context);
BuildEmitInObjectProperties(boilerplate_object, object);
}
return object;
}
@ -8448,8 +8434,7 @@ void HOptimizedGraphBuilder::BuildInitElementsInObjectHeader(
void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
Handle<JSObject> boilerplate_object,
HInstruction* object,
AllocationSiteContext* site_context) {
HInstruction* object) {
Handle<DescriptorArray> descriptors(
boilerplate_object->map()->instance_descriptors());
int limit = boilerplate_object->map()->NumberOfOwnDescriptors();
@ -8473,10 +8458,7 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
Handle<AllocationSite> current_site = site_context->EnterNewScope();
HInstruction* result =
BuildFastLiteral(value_object, site_context);
site_context->ExitScope(current_site, value_object);
HInstruction* result = BuildFastLiteral(value_object);
Add<HStoreNamedField>(object, access, result);
} else {
Representation representation = details.representation();
@ -8485,12 +8467,6 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
if (representation.IsDouble()) {
// Allocate a HeapNumber box and store the value into it.
HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
// TODO(mvstanton): This heap number alloc does not have a corresponding
// AllocationSite. That is okay because
// 1) it's a child object of another object with a valid allocation site
// 2) we can just use the mode of the parent object for pretenuring
// The todo is replace GetPretenureMode() with
// site_context->top()->GetPretenureMode().
HInstruction* double_box =
Add<HAllocate>(heap_number_constant, HType::HeapNumber(),
isolate()->heap()->GetPretenureMode(), HEAP_NUMBER_TYPE);
@ -8520,8 +8496,7 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
void HOptimizedGraphBuilder::BuildEmitElements(
Handle<JSObject> boilerplate_object,
Handle<FixedArrayBase> elements,
HValue* object_elements,
AllocationSiteContext* site_context) {
HValue* object_elements) {
ElementsKind kind = boilerplate_object->map()->elements_kind();
int elements_length = elements->length();
HValue* object_elements_length = Add<HConstant>(elements_length);
@ -8531,8 +8506,7 @@ void HOptimizedGraphBuilder::BuildEmitElements(
if (elements->IsFixedDoubleArray()) {
BuildEmitFixedDoubleArray(elements, kind, object_elements);
} else if (elements->IsFixedArray()) {
BuildEmitFixedArray(elements, kind, object_elements,
site_context);
BuildEmitFixedArray(elements, kind, object_elements);
} else {
UNREACHABLE();
}
@ -8561,8 +8535,7 @@ void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
void HOptimizedGraphBuilder::BuildEmitFixedArray(
Handle<FixedArrayBase> elements,
ElementsKind kind,
HValue* object_elements,
AllocationSiteContext* site_context) {
HValue* object_elements) {
HInstruction* boilerplate_elements = Add<HConstant>(elements);
int elements_length = elements->length();
Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
@ -8571,10 +8544,7 @@ void HOptimizedGraphBuilder::BuildEmitFixedArray(
HValue* key_constant = Add<HConstant>(i);
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
Handle<AllocationSite> current_site = site_context->EnterNewScope();
HInstruction* result =
BuildFastLiteral(value_object, site_context);
site_context->ExitScope(current_site, value_object);
HInstruction* result = BuildFastLiteral(value_object);
Add<HStoreKeyed>(object_elements, key_constant, result, kind);
} else {
HInstruction* value_instruction =

View File

@ -2248,8 +2248,7 @@ class HOptimizedGraphBuilder V8_FINAL
HInstruction* BuildThisFunction();
HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object,
AllocationSiteContext* site_context);
HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object);
void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object,
HInstruction* object);
@ -2259,13 +2258,11 @@ class HOptimizedGraphBuilder V8_FINAL
HInstruction* object_elements);
void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object,
HInstruction* object,
AllocationSiteContext* site_context);
HInstruction* object);
void BuildEmitElements(Handle<JSObject> boilerplate_object,
Handle<FixedArrayBase> elements,
HValue* object_elements,
AllocationSiteContext* site_context);
HValue* object_elements);
void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements,
ElementsKind kind,
@ -2273,8 +2270,7 @@ class HOptimizedGraphBuilder V8_FINAL
void BuildEmitFixedArray(Handle<FixedArrayBase> elements,
ElementsKind kind,
HValue* object_elements,
AllocationSiteContext* site_context);
HValue* object_elements);
void AddCheckPrototypeMaps(Handle<JSObject> holder,
Handle<Map> receiver_map);

View File

@ -28,7 +28,6 @@
#include "v8.h"
#include "accessors.h"
#include "allocation-site-scopes.h"
#include "api.h"
#include "arguments.h"
#include "bootstrapper.h"
@ -5616,14 +5615,6 @@ 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,
@ -5633,93 +5624,45 @@ Handle<JSObject> JSObject::Copy(Handle<JSObject> object) {
class JSObjectWalkVisitor {
public:
explicit JSObjectWalkVisitor(AllocationSiteContext* site_context) :
site_context_(site_context) {}
explicit JSObjectWalkVisitor() {}
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 will be used for the object in all subsequent usages.
// This allows VisitObject to make a copy of the object if desired.
// 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.
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(AllocationSiteContext* site_context)
: JSObjectWalkVisitor(site_context) {}
explicit JSObjectCopyVisitor() {}
virtual bool is_copying() V8_OVERRIDE { return true; }
// 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.
protected:
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;
return JSObject::Copy(object);
}
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 object;
}
virtual Handle<JSObject> VisitElementOrProperty(
Handle<JSObject> object,
Handle<JSObject> value) V8_OVERRIDE {
Handle<AllocationSite> current_site = site_context()->EnterNewScope();
value = StructureWalk(value);
site_context()->ExitScope(current_site, value);
return value;
return StructureWalk(value);
}
};
@ -5866,18 +5809,8 @@ Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) {
}
Handle<JSObject> JSObject::DeepWalk(Handle<JSObject> object,
AllocationSiteContext* site_context) {
JSObjectCreateAllocationSitesVisitor v(site_context);
Handle<JSObject> copy = v.Visit(object);
ASSERT(!v.is_copying() && copy.is_identical_to(object));
return copy;
}
Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object,
AllocationSiteContext* site_context) {
JSObjectCopyVisitor v(site_context);
Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
JSObjectCopyVisitor v;
Handle<JSObject> copy = v.Visit(object);
ASSERT(v.is_copying() && !copy.is_identical_to(object));
return copy;
@ -12640,20 +12573,6 @@ 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;
@ -12666,8 +12585,7 @@ MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
// Walk through to the Allocation Site
AllocationSite* site = memento->GetAllocationSite();
if (site->SitePointsToLiteral() &&
site->transition_info()->IsJSArray()) {
if (site->IsLiteralSite()) {
JSArray* transition_info = JSArray::cast(site->transition_info());
ElementsKind kind = transition_info->GetElementsKind();
// if kind is holey ensure that to_kind is as well.
@ -12681,11 +12599,9 @@ 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 %s updated %s->%s\n",
"AllocationSite: JSArray %p boilerplate updated %s->%s\n",
reinterpret_cast<void*>(this),
is_nested ? "(nested)" : "",
ElementsKindToString(kind),
ElementsKindToString(to_kind));
}

View File

@ -865,9 +865,8 @@ enum CompareResult {
inline void set_##name(type* value, \
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
class AccessorPair;
class AllocationSite;
class AllocationSiteContext;
class DictionaryElementsAccessor;
class ElementsAccessor;
class Failure;
@ -2545,13 +2544,8 @@ class JSObject: public JSReceiver {
MUST_USE_RESULT MaybeObject* SetObserved(Isolate* isolate);
// Copy object.
static Handle<JSObject> Copy(Handle<JSObject> object,
Handle<AllocationSite> site);
static Handle<JSObject> Copy(Handle<JSObject> object);
static Handle<JSObject> DeepCopy(Handle<JSObject> object,
AllocationSiteContext* site_context);
static Handle<JSObject> DeepWalk(Handle<JSObject> object,
AllocationSiteContext* site_context);
static Handle<JSObject> DeepCopy(Handle<JSObject> object);
// Casting.
static inline JSObject* cast(Object* obj);
@ -8011,15 +8005,8 @@ class AllocationSite: public Struct {
inline void Initialize();
bool HasNestedSites() {
return nested_site()->IsAllocationSite();
}
// This method is expensive, it should only be called for reporting.
bool IsNestedSite();
ElementsKind GetElementsKind() {
ASSERT(!SitePointsToLiteral());
ASSERT(!IsLiteralSite());
return static_cast<ElementsKind>(Smi::cast(transition_info())->value());
}
@ -8027,11 +8014,11 @@ class AllocationSite: public Struct {
set_transition_info(Smi::FromInt(static_cast<int>(kind)));
}
bool SitePointsToLiteral() {
bool IsLiteralSite() {
// If transition_info is a smi, then it represents an ElementsKind
// for a constructed array. Otherwise, it must be a boilerplate
// for an object or array literal.
return transition_info()->IsJSArray() || transition_info()->IsJSObject();
// for an array literal
return transition_info()->IsJSArray();
}
DECLARE_PRINTER(AllocationSite)

View File

@ -31,7 +31,6 @@
#include "v8.h"
#include "accessors.h"
#include "allocation-site-scopes.h"
#include "api.h"
#include "arguments.h"
#include "bootstrapper.h"
@ -489,34 +488,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
// Check if boilerplate exists. If not, create it first.
Handle<Object> literal_site(literals->get(literals_index), isolate);
Handle<AllocationSite> site;
Handle<JSObject> boilerplate;
Handle<Object> boilerplate;
if (*literal_site == isolate->heap()->undefined_value()) {
Handle<Object> raw_boilerplate = CreateObjectLiteralBoilerplate(
isolate,
literals,
constant_properties,
should_have_fast_elements,
has_function_literal);
RETURN_IF_EMPTY_HANDLE(isolate, raw_boilerplate);
boilerplate = Handle<JSObject>::cast(raw_boilerplate);
AllocationSiteCreationContext creation_context(isolate);
site = creation_context.EnterNewScope();
JSObject::DeepWalk(boilerplate, &creation_context);
creation_context.ExitScope(site, boilerplate);
boilerplate = CreateObjectLiteralBoilerplate(isolate,
literals,
constant_properties,
should_have_fast_elements,
has_function_literal);
RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
site = isolate->factory()->NewAllocationSite();
site->set_transition_info(*boilerplate);
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *site);
} else {
site = Handle<AllocationSite>::cast(literal_site);
boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
isolate);
boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()));
}
AllocationSiteUsageContext usage_context(isolate, site, true);
usage_context.EnterNewScope();
Handle<Object> copy = JSObject::DeepCopy(boilerplate, &usage_context);
usage_context.ExitScope(site, boilerplate);
Handle<Object> copy = JSObject::DeepCopy(Handle<JSObject>::cast(boilerplate));
RETURN_IF_EMPTY_HANDLE(isolate, copy);
return *copy;
}
@ -534,13 +524,12 @@ static Handle<AllocationSite> GetLiteralAllocationSite(
ASSERT(*elements != isolate->heap()->empty_fixed_array());
Handle<Object> boilerplate =
Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
if (boilerplate.is_null()) return Handle<AllocationSite>::null();
AllocationSiteCreationContext creation_context(isolate);
site = creation_context.EnterNewScope();
JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate), &creation_context);
creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
if (boilerplate.is_null()) {
ASSERT(site.is_null());
return site;
}
site = isolate->factory()->NewAllocationSite();
site->set_transition_info(*boilerplate);
literals->set(literals_index, *site);
} else {
site = Handle<AllocationSite>::cast(literal_site);
@ -562,10 +551,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
RETURN_IF_EMPTY_HANDLE(isolate, site);
Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
AllocationSiteUsageContext usage_context(isolate, site, true);
usage_context.EnterNewScope();
Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context);
usage_context.ExitScope(site, boilerplate);
Handle<JSObject> copy = JSObject::DeepCopy(boilerplate);
RETURN_IF_EMPTY_HANDLE(isolate, copy);
return *copy;
}
@ -588,8 +574,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
isolate->counters()->cow_arrays_created_runtime()->Increment();
}
if (AllocationSite::GetMode(boilerplate->GetElementsKind()) ==
TRACK_ALLOCATION_SITE) {
AllocationSiteMode mode = AllocationSite::GetMode(
boilerplate->GetElementsKind());
if (mode == TRACK_ALLOCATION_SITE) {
return isolate->heap()->CopyJSObject(boilerplate, *site);
}
@ -14698,7 +14685,7 @@ static MaybeObject* ArrayConstructorCommon(Isolate* isolate,
Handle<Cell> cell = Handle<Cell>::cast(type_info);
Handle<AllocationSite> site = Handle<AllocationSite>(
AllocationSite::cast(cell->value()), isolate);
ASSERT(!site->SitePointsToLiteral());
ASSERT(!site->IsLiteralSite());
ElementsKind to_kind = site->GetElementsKind();
if (holey && !IsFastHoleyElementsKind(to_kind)) {
to_kind = GetHoleyElementsKind(to_kind);

View File

@ -383,114 +383,4 @@ if (support_smi_only_arrays) {
instanceof_check(realmBArray);
assertUnoptimized(instanceof_check);
// Case: make sure nested arrays benefit from allocation site feedback as
// well.
(function() {
// Make sure we handle nested arrays
function get_nested_literal() {
var literal = [[1,2,3,4], [2], [3]];
return literal;
}
obj = get_nested_literal();
assertKind(elements_kind.fast, obj);
obj[0][0] = 3.5;
obj[2][0] = "hello";
obj = get_nested_literal();
assertKind(elements_kind.fast_double, obj[0]);
assertKind(elements_kind.fast_smi_only, obj[1]);
assertKind(elements_kind.fast, obj[2]);
// A more complex nested literal case.
function get_deep_nested_literal() {
var literal = [[1], [[2], "hello"], 3, [4]];
return literal;
}
obj = get_deep_nested_literal();
assertKind(elements_kind.fast_smi_only, obj[1][0]);
obj[0][0] = 3.5;
obj[1][0][0] = "goodbye";
assertKind(elements_kind.fast_double, obj[0]);
assertKind(elements_kind.fast, obj[1][0]);
obj = get_deep_nested_literal();
assertKind(elements_kind.fast_double, obj[0]);
assertKind(elements_kind.fast, obj[1][0]);
})();
// Make sure object literals with array fields benefit from the type feedback
// that allocation mementos provide.
(function() {
// A literal in an object
function get_object_literal() {
var literal = {
array: [1,2,3],
data: 3.5
};
return literal;
}
obj = get_object_literal();
assertKind(elements_kind.fast_smi_only, obj.array);
obj.array[1] = 3.5;
assertKind(elements_kind.fast_double, obj.array);
obj = get_object_literal();
assertKind(elements_kind.fast_double, obj.array);
function get_nested_object_literal() {
var literal = {
array: [[1],[2],[3]],
data: 3.5
};
return literal;
}
obj = get_nested_object_literal();
assertKind(elements_kind.fast, obj.array);
assertKind(elements_kind.fast_smi_only, obj.array[1]);
obj.array[1][0] = 3.5;
assertKind(elements_kind.fast_double, obj.array[1]);
obj = get_nested_object_literal();
assertKind(elements_kind.fast_double, obj.array[1]);
%OptimizeFunctionOnNextCall(get_nested_object_literal);
get_nested_object_literal();
obj = get_nested_object_literal();
assertKind(elements_kind.fast_double, obj.array[1]);
// Make sure we handle nested arrays
function get_nested_literal() {
var literal = [[1,2,3,4], [2], [3]];
return literal;
}
obj = get_nested_literal();
assertKind(elements_kind.fast, obj);
obj[0][0] = 3.5;
obj[2][0] = "hello";
obj = get_nested_literal();
assertKind(elements_kind.fast_double, obj[0]);
assertKind(elements_kind.fast_smi_only, obj[1]);
assertKind(elements_kind.fast, obj[2]);
// A more complex nested literal case.
function get_deep_nested_literal() {
var literal = [[1], [[2], "hello"], 3, [4]];
return literal;
}
obj = get_deep_nested_literal();
assertKind(elements_kind.fast_smi_only, obj[1][0]);
obj[0][0] = 3.5;
obj[1][0][0] = "goodbye";
assertKind(elements_kind.fast_double, obj[0]);
assertKind(elements_kind.fast, obj[1][0]);
obj = get_deep_nested_literal();
assertKind(elements_kind.fast_double, obj[0]);
assertKind(elements_kind.fast, obj[1][0]);
})();
}

View File

@ -209,8 +209,6 @@
'../../src/accessors.h',
'../../src/allocation.cc',
'../../src/allocation.h',
'../../src/allocation-site-scopes.cc',
'../../src/allocation-site-scopes.h',
'../../src/api.cc',
'../../src/api.h',
'../../src/apiutils.h',