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:
parent
ea4e0a3d28
commit
f4edc076d8
@ -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
|
|
@ -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_
|
|
@ -806,9 +806,6 @@ DEFINE_implication(log_internal_timer_events, prof)
|
|||||||
// elements.cc
|
// elements.cc
|
||||||
DEFINE_bool(trace_elements_transitions, false, "trace elements transitions")
|
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
|
// code-stubs.cc
|
||||||
DEFINE_bool(print_code_stubs, false, "print code stubs")
|
DEFINE_bool(print_code_stubs, false, "print code stubs")
|
||||||
DEFINE_bool(test_secondary_stub_cache,
|
DEFINE_bool(test_secondary_stub_cache,
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
#include "allocation-site-scopes.h"
|
|
||||||
#include "codegen.h"
|
#include "codegen.h"
|
||||||
#include "full-codegen.h"
|
#include "full-codegen.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
@ -4299,10 +4298,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
|
|
||||||
if (!boilerplate.is_null() &&
|
if (!boilerplate.is_null() &&
|
||||||
IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
|
IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
|
||||||
AllocationSiteUsageContext usage_context(isolate(), site, false);
|
literal = BuildFastLiteral(boilerplate);
|
||||||
usage_context.EnterNewScope();
|
|
||||||
literal = BuildFastLiteral(boilerplate, &usage_context);
|
|
||||||
usage_context.ExitScope(site, boilerplate);
|
|
||||||
} else {
|
} else {
|
||||||
NoObservableSideEffectsScope no_effects(this);
|
NoObservableSideEffectsScope no_effects(this);
|
||||||
Handle<FixedArray> closure_literals(closure->literals(), isolate());
|
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>(constant_properties));
|
||||||
Add<HPushArgument>(Add<HConstant>(flags));
|
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;
|
Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral;
|
||||||
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
|
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
|
||||||
Runtime::FunctionForId(function_id),
|
Runtime::FunctionForId(function_id),
|
||||||
@ -4411,48 +4404,45 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
|||||||
bool uninitialized = false;
|
bool uninitialized = false;
|
||||||
Handle<Object> literals_cell(literals->get(expr->literal_index()),
|
Handle<Object> literals_cell(literals->get(expr->literal_index()),
|
||||||
isolate());
|
isolate());
|
||||||
Handle<JSObject> boilerplate_object;
|
Handle<Object> raw_boilerplate;
|
||||||
if (literals_cell->IsUndefined()) {
|
if (literals_cell->IsUndefined()) {
|
||||||
uninitialized = true;
|
uninitialized = true;
|
||||||
Handle<Object> raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
|
raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
|
||||||
isolate(), literals, expr->constant_elements());
|
isolate(), literals, expr->constant_elements());
|
||||||
if (raw_boilerplate.is_null()) {
|
if (raw_boilerplate.is_null()) {
|
||||||
return Bailout(kArrayBoilerplateCreationFailed);
|
return Bailout(kArrayBoilerplateCreationFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
boilerplate_object = Handle<JSObject>::cast(raw_boilerplate);
|
site = isolate()->factory()->NewAllocationSite();
|
||||||
AllocationSiteCreationContext creation_context(isolate());
|
site->set_transition_info(*raw_boilerplate);
|
||||||
site = creation_context.EnterNewScope();
|
|
||||||
JSObject::DeepWalk(boilerplate_object, &creation_context);
|
|
||||||
creation_context.ExitScope(site, boilerplate_object);
|
|
||||||
literals->set(expr->literal_index(), *site);
|
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()->heap()->fixed_cow_array_map()) {
|
||||||
isolate()->counters()->cow_arrays_created_runtime()->Increment();
|
isolate()->counters()->cow_arrays_created_runtime()->Increment();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ASSERT(literals_cell->IsAllocationSite());
|
ASSERT(literals_cell->IsAllocationSite());
|
||||||
site = Handle<AllocationSite>::cast(literals_cell);
|
site = Handle<AllocationSite>::cast(literals_cell);
|
||||||
boilerplate_object = Handle<JSObject>(
|
raw_boilerplate = Handle<Object>(site->transition_info(), isolate());
|
||||||
JSObject::cast(site->transition_info()), isolate());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(!boilerplate_object.is_null());
|
ASSERT(!raw_boilerplate.is_null());
|
||||||
ASSERT(site->SitePointsToLiteral());
|
ASSERT(site->IsLiteralSite());
|
||||||
|
|
||||||
|
Handle<JSObject> boilerplate_object =
|
||||||
|
Handle<JSObject>::cast(raw_boilerplate);
|
||||||
ElementsKind boilerplate_elements_kind =
|
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.
|
// Check whether to use fast or slow deep-copying for boilerplate.
|
||||||
int max_properties = kMaxFastLiteralProperties;
|
int max_properties = kMaxFastLiteralProperties;
|
||||||
if (IsFastLiteral(boilerplate_object,
|
if (IsFastLiteral(boilerplate_object,
|
||||||
kMaxFastLiteralDepth,
|
kMaxFastLiteralDepth,
|
||||||
&max_properties)) {
|
&max_properties)) {
|
||||||
AllocationSiteUsageContext usage_context(isolate(), site, false);
|
literal = BuildFastLiteral(boilerplate_object);
|
||||||
usage_context.EnterNewScope();
|
|
||||||
literal = BuildFastLiteral(boilerplate_object, &usage_context);
|
|
||||||
usage_context.ExitScope(site, boilerplate_object);
|
|
||||||
} else {
|
} else {
|
||||||
NoObservableSideEffectsScope no_effects(this);
|
NoObservableSideEffectsScope no_effects(this);
|
||||||
// Boilerplate already exists and constant elements are never accessed,
|
// 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>(literal_index));
|
||||||
Add<HPushArgument>(Add<HConstant>(constants));
|
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::FunctionId function_id = (expr->depth() > 1)
|
||||||
? Runtime::kCreateArrayLiteral : Runtime::kCreateArrayLiteralShallow;
|
? Runtime::kCreateArrayLiteral : Runtime::kCreateArrayLiteralShallow;
|
||||||
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
|
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
|
||||||
@ -8355,8 +8342,7 @@ HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
|
|||||||
|
|
||||||
|
|
||||||
HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
|
HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
|
||||||
Handle<JSObject> boilerplate_object,
|
Handle<JSObject> boilerplate_object) {
|
||||||
AllocationSiteContext* site_context) {
|
|
||||||
NoObservableSideEffectsScope no_effects(this);
|
NoObservableSideEffectsScope no_effects(this);
|
||||||
InstanceType instance_type = boilerplate_object->map()->instance_type();
|
InstanceType instance_type = boilerplate_object->map()->instance_type();
|
||||||
ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_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);
|
BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements);
|
||||||
|
|
||||||
|
|
||||||
// Copy object elements if non-COW.
|
// Copy object elements if non-COW.
|
||||||
if (object_elements != NULL) {
|
if (object_elements != NULL) {
|
||||||
BuildEmitElements(boilerplate_object, elements, object_elements,
|
BuildEmitElements(boilerplate_object, elements, object_elements);
|
||||||
site_context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy in-object properties.
|
// Copy in-object properties.
|
||||||
if (boilerplate_object->map()->NumberOfFields() != 0) {
|
if (boilerplate_object->map()->NumberOfFields() != 0) {
|
||||||
BuildEmitInObjectProperties(boilerplate_object, object, site_context);
|
BuildEmitInObjectProperties(boilerplate_object, object);
|
||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
@ -8448,8 +8434,7 @@ void HOptimizedGraphBuilder::BuildInitElementsInObjectHeader(
|
|||||||
|
|
||||||
void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
||||||
Handle<JSObject> boilerplate_object,
|
Handle<JSObject> boilerplate_object,
|
||||||
HInstruction* object,
|
HInstruction* object) {
|
||||||
AllocationSiteContext* site_context) {
|
|
||||||
Handle<DescriptorArray> descriptors(
|
Handle<DescriptorArray> descriptors(
|
||||||
boilerplate_object->map()->instance_descriptors());
|
boilerplate_object->map()->instance_descriptors());
|
||||||
int limit = boilerplate_object->map()->NumberOfOwnDescriptors();
|
int limit = boilerplate_object->map()->NumberOfOwnDescriptors();
|
||||||
@ -8473,10 +8458,7 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
|||||||
|
|
||||||
if (value->IsJSObject()) {
|
if (value->IsJSObject()) {
|
||||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||||
Handle<AllocationSite> current_site = site_context->EnterNewScope();
|
HInstruction* result = BuildFastLiteral(value_object);
|
||||||
HInstruction* result =
|
|
||||||
BuildFastLiteral(value_object, site_context);
|
|
||||||
site_context->ExitScope(current_site, value_object);
|
|
||||||
Add<HStoreNamedField>(object, access, result);
|
Add<HStoreNamedField>(object, access, result);
|
||||||
} else {
|
} else {
|
||||||
Representation representation = details.representation();
|
Representation representation = details.representation();
|
||||||
@ -8485,12 +8467,6 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
|||||||
if (representation.IsDouble()) {
|
if (representation.IsDouble()) {
|
||||||
// Allocate a HeapNumber box and store the value into it.
|
// Allocate a HeapNumber box and store the value into it.
|
||||||
HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
|
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 =
|
HInstruction* double_box =
|
||||||
Add<HAllocate>(heap_number_constant, HType::HeapNumber(),
|
Add<HAllocate>(heap_number_constant, HType::HeapNumber(),
|
||||||
isolate()->heap()->GetPretenureMode(), HEAP_NUMBER_TYPE);
|
isolate()->heap()->GetPretenureMode(), HEAP_NUMBER_TYPE);
|
||||||
@ -8520,8 +8496,7 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
|||||||
void HOptimizedGraphBuilder::BuildEmitElements(
|
void HOptimizedGraphBuilder::BuildEmitElements(
|
||||||
Handle<JSObject> boilerplate_object,
|
Handle<JSObject> boilerplate_object,
|
||||||
Handle<FixedArrayBase> elements,
|
Handle<FixedArrayBase> elements,
|
||||||
HValue* object_elements,
|
HValue* object_elements) {
|
||||||
AllocationSiteContext* site_context) {
|
|
||||||
ElementsKind kind = boilerplate_object->map()->elements_kind();
|
ElementsKind kind = boilerplate_object->map()->elements_kind();
|
||||||
int elements_length = elements->length();
|
int elements_length = elements->length();
|
||||||
HValue* object_elements_length = Add<HConstant>(elements_length);
|
HValue* object_elements_length = Add<HConstant>(elements_length);
|
||||||
@ -8531,8 +8506,7 @@ void HOptimizedGraphBuilder::BuildEmitElements(
|
|||||||
if (elements->IsFixedDoubleArray()) {
|
if (elements->IsFixedDoubleArray()) {
|
||||||
BuildEmitFixedDoubleArray(elements, kind, object_elements);
|
BuildEmitFixedDoubleArray(elements, kind, object_elements);
|
||||||
} else if (elements->IsFixedArray()) {
|
} else if (elements->IsFixedArray()) {
|
||||||
BuildEmitFixedArray(elements, kind, object_elements,
|
BuildEmitFixedArray(elements, kind, object_elements);
|
||||||
site_context);
|
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
@ -8561,8 +8535,7 @@ void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
|
|||||||
void HOptimizedGraphBuilder::BuildEmitFixedArray(
|
void HOptimizedGraphBuilder::BuildEmitFixedArray(
|
||||||
Handle<FixedArrayBase> elements,
|
Handle<FixedArrayBase> elements,
|
||||||
ElementsKind kind,
|
ElementsKind kind,
|
||||||
HValue* object_elements,
|
HValue* object_elements) {
|
||||||
AllocationSiteContext* site_context) {
|
|
||||||
HInstruction* boilerplate_elements = Add<HConstant>(elements);
|
HInstruction* boilerplate_elements = Add<HConstant>(elements);
|
||||||
int elements_length = elements->length();
|
int elements_length = elements->length();
|
||||||
Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
|
Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
|
||||||
@ -8571,10 +8544,7 @@ void HOptimizedGraphBuilder::BuildEmitFixedArray(
|
|||||||
HValue* key_constant = Add<HConstant>(i);
|
HValue* key_constant = Add<HConstant>(i);
|
||||||
if (value->IsJSObject()) {
|
if (value->IsJSObject()) {
|
||||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||||
Handle<AllocationSite> current_site = site_context->EnterNewScope();
|
HInstruction* result = BuildFastLiteral(value_object);
|
||||||
HInstruction* result =
|
|
||||||
BuildFastLiteral(value_object, site_context);
|
|
||||||
site_context->ExitScope(current_site, value_object);
|
|
||||||
Add<HStoreKeyed>(object_elements, key_constant, result, kind);
|
Add<HStoreKeyed>(object_elements, key_constant, result, kind);
|
||||||
} else {
|
} else {
|
||||||
HInstruction* value_instruction =
|
HInstruction* value_instruction =
|
||||||
|
@ -2248,8 +2248,7 @@ class HOptimizedGraphBuilder V8_FINAL
|
|||||||
|
|
||||||
HInstruction* BuildThisFunction();
|
HInstruction* BuildThisFunction();
|
||||||
|
|
||||||
HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object,
|
HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object);
|
||||||
AllocationSiteContext* site_context);
|
|
||||||
|
|
||||||
void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object,
|
void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object,
|
||||||
HInstruction* object);
|
HInstruction* object);
|
||||||
@ -2259,13 +2258,11 @@ class HOptimizedGraphBuilder V8_FINAL
|
|||||||
HInstruction* object_elements);
|
HInstruction* object_elements);
|
||||||
|
|
||||||
void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object,
|
void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object,
|
||||||
HInstruction* object,
|
HInstruction* object);
|
||||||
AllocationSiteContext* site_context);
|
|
||||||
|
|
||||||
void BuildEmitElements(Handle<JSObject> boilerplate_object,
|
void BuildEmitElements(Handle<JSObject> boilerplate_object,
|
||||||
Handle<FixedArrayBase> elements,
|
Handle<FixedArrayBase> elements,
|
||||||
HValue* object_elements,
|
HValue* object_elements);
|
||||||
AllocationSiteContext* site_context);
|
|
||||||
|
|
||||||
void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements,
|
void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements,
|
||||||
ElementsKind kind,
|
ElementsKind kind,
|
||||||
@ -2273,8 +2270,7 @@ class HOptimizedGraphBuilder V8_FINAL
|
|||||||
|
|
||||||
void BuildEmitFixedArray(Handle<FixedArrayBase> elements,
|
void BuildEmitFixedArray(Handle<FixedArrayBase> elements,
|
||||||
ElementsKind kind,
|
ElementsKind kind,
|
||||||
HValue* object_elements,
|
HValue* object_elements);
|
||||||
AllocationSiteContext* site_context);
|
|
||||||
|
|
||||||
void AddCheckPrototypeMaps(Handle<JSObject> holder,
|
void AddCheckPrototypeMaps(Handle<JSObject> holder,
|
||||||
Handle<Map> receiver_map);
|
Handle<Map> receiver_map);
|
||||||
|
114
src/objects.cc
114
src/objects.cc
@ -28,7 +28,6 @@
|
|||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
|
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
#include "allocation-site-scopes.h"
|
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
#include "arguments.h"
|
#include "arguments.h"
|
||||||
#include "bootstrapper.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) {
|
Handle<JSObject> JSObject::Copy(Handle<JSObject> object) {
|
||||||
Isolate* isolate = object->GetIsolate();
|
Isolate* isolate = object->GetIsolate();
|
||||||
CALL_HEAP_FUNCTION(isolate,
|
CALL_HEAP_FUNCTION(isolate,
|
||||||
@ -5633,93 +5624,45 @@ Handle<JSObject> JSObject::Copy(Handle<JSObject> object) {
|
|||||||
|
|
||||||
class JSObjectWalkVisitor {
|
class JSObjectWalkVisitor {
|
||||||
public:
|
public:
|
||||||
explicit JSObjectWalkVisitor(AllocationSiteContext* site_context) :
|
explicit JSObjectWalkVisitor() {}
|
||||||
site_context_(site_context) {}
|
|
||||||
virtual ~JSObjectWalkVisitor() {}
|
virtual ~JSObjectWalkVisitor() {}
|
||||||
|
|
||||||
Handle<JSObject> Visit(Handle<JSObject> object) {
|
Handle<JSObject> Visit(Handle<JSObject> object) {
|
||||||
return StructureWalk(object);
|
return StructureWalk(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if the visitor is a copying visitor.
|
||||||
virtual bool is_copying() = 0;
|
virtual bool is_copying() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Handle<JSObject> StructureWalk(Handle<JSObject> object);
|
Handle<JSObject> StructureWalk(Handle<JSObject> object);
|
||||||
|
|
||||||
// The returned handle will be used for the object in all subsequent usages.
|
// The returned handle should point to a new object if the visitor is a
|
||||||
// This allows VisitObject to make a copy of the object if desired.
|
// copying visitor, otherwise it should be the same as the input object.
|
||||||
virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0;
|
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,
|
virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object,
|
||||||
Handle<JSObject> value) = 0;
|
Handle<JSObject> value) = 0;
|
||||||
|
|
||||||
AllocationSiteContext* site_context() { return site_context_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
AllocationSiteContext* site_context_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class JSObjectCopyVisitor: public JSObjectWalkVisitor {
|
class JSObjectCopyVisitor: public JSObjectWalkVisitor {
|
||||||
public:
|
public:
|
||||||
explicit JSObjectCopyVisitor(AllocationSiteContext* site_context)
|
explicit JSObjectCopyVisitor() {}
|
||||||
: JSObjectWalkVisitor(site_context) {}
|
|
||||||
|
|
||||||
virtual bool is_copying() V8_OVERRIDE { return true; }
|
virtual bool is_copying() V8_OVERRIDE { return true; }
|
||||||
|
|
||||||
// The returned handle will be used for the object in all
|
protected:
|
||||||
// subsequent usages. This allows VisitObject to make a copy
|
|
||||||
// of the object if desired.
|
|
||||||
virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
|
virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
|
||||||
// Only create a memento if
|
return JSObject::Copy(object);
|
||||||
// 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(
|
virtual Handle<JSObject> VisitElementOrProperty(
|
||||||
Handle<JSObject> object,
|
Handle<JSObject> object,
|
||||||
Handle<JSObject> value) V8_OVERRIDE {
|
Handle<JSObject> value) V8_OVERRIDE {
|
||||||
Handle<AllocationSite> current_site = site_context()->EnterNewScope();
|
return StructureWalk(value);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5866,18 +5809,8 @@ Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Handle<JSObject> JSObject::DeepWalk(Handle<JSObject> object,
|
Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
|
||||||
AllocationSiteContext* site_context) {
|
JSObjectCopyVisitor v;
|
||||||
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> copy = v.Visit(object);
|
Handle<JSObject> copy = v.Visit(object);
|
||||||
ASSERT(v.is_copying() && !copy.is_identical_to(object));
|
ASSERT(v.is_copying() && !copy.is_identical_to(object));
|
||||||
return copy;
|
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) {
|
MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
|
||||||
if (!FLAG_track_allocation_sites || !IsJSArray()) {
|
if (!FLAG_track_allocation_sites || !IsJSArray()) {
|
||||||
return this;
|
return this;
|
||||||
@ -12666,8 +12585,7 @@ MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
|
|||||||
|
|
||||||
// Walk through to the Allocation Site
|
// Walk through to the Allocation Site
|
||||||
AllocationSite* site = memento->GetAllocationSite();
|
AllocationSite* site = memento->GetAllocationSite();
|
||||||
if (site->SitePointsToLiteral() &&
|
if (site->IsLiteralSite()) {
|
||||||
site->transition_info()->IsJSArray()) {
|
|
||||||
JSArray* transition_info = JSArray::cast(site->transition_info());
|
JSArray* transition_info = JSArray::cast(site->transition_info());
|
||||||
ElementsKind kind = transition_info->GetElementsKind();
|
ElementsKind kind = transition_info->GetElementsKind();
|
||||||
// if kind is holey ensure that to_kind is as well.
|
// 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));
|
CHECK(transition_info->length()->ToArrayIndex(&length));
|
||||||
if (length <= AllocationSite::kMaximumArrayBytesToPretransition) {
|
if (length <= AllocationSite::kMaximumArrayBytesToPretransition) {
|
||||||
if (FLAG_trace_track_allocation_sites) {
|
if (FLAG_trace_track_allocation_sites) {
|
||||||
bool is_nested = site->IsNestedSite();
|
|
||||||
PrintF(
|
PrintF(
|
||||||
"AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
|
"AllocationSite: JSArray %p boilerplate updated %s->%s\n",
|
||||||
reinterpret_cast<void*>(this),
|
reinterpret_cast<void*>(this),
|
||||||
is_nested ? "(nested)" : "",
|
|
||||||
ElementsKindToString(kind),
|
ElementsKindToString(kind),
|
||||||
ElementsKindToString(to_kind));
|
ElementsKindToString(to_kind));
|
||||||
}
|
}
|
||||||
|
@ -865,9 +865,8 @@ enum CompareResult {
|
|||||||
inline void set_##name(type* value, \
|
inline void set_##name(type* value, \
|
||||||
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
|
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
|
||||||
|
|
||||||
|
|
||||||
class AccessorPair;
|
class AccessorPair;
|
||||||
class AllocationSite;
|
|
||||||
class AllocationSiteContext;
|
|
||||||
class DictionaryElementsAccessor;
|
class DictionaryElementsAccessor;
|
||||||
class ElementsAccessor;
|
class ElementsAccessor;
|
||||||
class Failure;
|
class Failure;
|
||||||
@ -2545,13 +2544,8 @@ class JSObject: public JSReceiver {
|
|||||||
MUST_USE_RESULT MaybeObject* SetObserved(Isolate* isolate);
|
MUST_USE_RESULT MaybeObject* SetObserved(Isolate* isolate);
|
||||||
|
|
||||||
// Copy object.
|
// Copy object.
|
||||||
static Handle<JSObject> Copy(Handle<JSObject> object,
|
|
||||||
Handle<AllocationSite> site);
|
|
||||||
static Handle<JSObject> Copy(Handle<JSObject> object);
|
static Handle<JSObject> Copy(Handle<JSObject> object);
|
||||||
static Handle<JSObject> DeepCopy(Handle<JSObject> object,
|
static Handle<JSObject> DeepCopy(Handle<JSObject> object);
|
||||||
AllocationSiteContext* site_context);
|
|
||||||
static Handle<JSObject> DeepWalk(Handle<JSObject> object,
|
|
||||||
AllocationSiteContext* site_context);
|
|
||||||
|
|
||||||
// Casting.
|
// Casting.
|
||||||
static inline JSObject* cast(Object* obj);
|
static inline JSObject* cast(Object* obj);
|
||||||
@ -8011,15 +8005,8 @@ class AllocationSite: public Struct {
|
|||||||
|
|
||||||
inline void Initialize();
|
inline void Initialize();
|
||||||
|
|
||||||
bool HasNestedSites() {
|
|
||||||
return nested_site()->IsAllocationSite();
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method is expensive, it should only be called for reporting.
|
|
||||||
bool IsNestedSite();
|
|
||||||
|
|
||||||
ElementsKind GetElementsKind() {
|
ElementsKind GetElementsKind() {
|
||||||
ASSERT(!SitePointsToLiteral());
|
ASSERT(!IsLiteralSite());
|
||||||
return static_cast<ElementsKind>(Smi::cast(transition_info())->value());
|
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)));
|
set_transition_info(Smi::FromInt(static_cast<int>(kind)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SitePointsToLiteral() {
|
bool IsLiteralSite() {
|
||||||
// If transition_info is a smi, then it represents an ElementsKind
|
// If transition_info is a smi, then it represents an ElementsKind
|
||||||
// for a constructed array. Otherwise, it must be a boilerplate
|
// for a constructed array. Otherwise, it must be a boilerplate
|
||||||
// for an object or array literal.
|
// for an array literal
|
||||||
return transition_info()->IsJSArray() || transition_info()->IsJSObject();
|
return transition_info()->IsJSArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_PRINTER(AllocationSite)
|
DECLARE_PRINTER(AllocationSite)
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
|
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
#include "allocation-site-scopes.h"
|
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
#include "arguments.h"
|
#include "arguments.h"
|
||||||
#include "bootstrapper.h"
|
#include "bootstrapper.h"
|
||||||
@ -489,34 +488,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
|
|||||||
// Check if boilerplate exists. If not, create it first.
|
// Check if boilerplate exists. If not, create it first.
|
||||||
Handle<Object> literal_site(literals->get(literals_index), isolate);
|
Handle<Object> literal_site(literals->get(literals_index), isolate);
|
||||||
Handle<AllocationSite> site;
|
Handle<AllocationSite> site;
|
||||||
Handle<JSObject> boilerplate;
|
Handle<Object> boilerplate;
|
||||||
if (*literal_site == isolate->heap()->undefined_value()) {
|
if (*literal_site == isolate->heap()->undefined_value()) {
|
||||||
Handle<Object> raw_boilerplate = CreateObjectLiteralBoilerplate(
|
boilerplate = CreateObjectLiteralBoilerplate(isolate,
|
||||||
isolate,
|
literals,
|
||||||
literals,
|
constant_properties,
|
||||||
constant_properties,
|
should_have_fast_elements,
|
||||||
should_have_fast_elements,
|
has_function_literal);
|
||||||
has_function_literal);
|
RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
|
||||||
RETURN_IF_EMPTY_HANDLE(isolate, raw_boilerplate);
|
site = isolate->factory()->NewAllocationSite();
|
||||||
boilerplate = Handle<JSObject>::cast(raw_boilerplate);
|
site->set_transition_info(*boilerplate);
|
||||||
|
|
||||||
AllocationSiteCreationContext creation_context(isolate);
|
|
||||||
site = creation_context.EnterNewScope();
|
|
||||||
JSObject::DeepWalk(boilerplate, &creation_context);
|
|
||||||
creation_context.ExitScope(site, boilerplate);
|
|
||||||
|
|
||||||
// Update the functions literal and return the boilerplate.
|
// Update the functions literal and return the boilerplate.
|
||||||
literals->set(literals_index, *site);
|
literals->set(literals_index, *site);
|
||||||
} else {
|
} else {
|
||||||
site = Handle<AllocationSite>::cast(literal_site);
|
site = Handle<AllocationSite>::cast(literal_site);
|
||||||
boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
|
boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()));
|
||||||
isolate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocationSiteUsageContext usage_context(isolate, site, true);
|
Handle<Object> copy = JSObject::DeepCopy(Handle<JSObject>::cast(boilerplate));
|
||||||
usage_context.EnterNewScope();
|
|
||||||
Handle<Object> copy = JSObject::DeepCopy(boilerplate, &usage_context);
|
|
||||||
usage_context.ExitScope(site, boilerplate);
|
|
||||||
RETURN_IF_EMPTY_HANDLE(isolate, copy);
|
RETURN_IF_EMPTY_HANDLE(isolate, copy);
|
||||||
return *copy;
|
return *copy;
|
||||||
}
|
}
|
||||||
@ -534,13 +524,12 @@ static Handle<AllocationSite> GetLiteralAllocationSite(
|
|||||||
ASSERT(*elements != isolate->heap()->empty_fixed_array());
|
ASSERT(*elements != isolate->heap()->empty_fixed_array());
|
||||||
Handle<Object> boilerplate =
|
Handle<Object> boilerplate =
|
||||||
Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
|
Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
|
||||||
if (boilerplate.is_null()) return Handle<AllocationSite>::null();
|
if (boilerplate.is_null()) {
|
||||||
|
ASSERT(site.is_null());
|
||||||
AllocationSiteCreationContext creation_context(isolate);
|
return site;
|
||||||
site = creation_context.EnterNewScope();
|
}
|
||||||
JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate), &creation_context);
|
site = isolate->factory()->NewAllocationSite();
|
||||||
creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
|
site->set_transition_info(*boilerplate);
|
||||||
|
|
||||||
literals->set(literals_index, *site);
|
literals->set(literals_index, *site);
|
||||||
} else {
|
} else {
|
||||||
site = Handle<AllocationSite>::cast(literal_site);
|
site = Handle<AllocationSite>::cast(literal_site);
|
||||||
@ -562,10 +551,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
|
|||||||
RETURN_IF_EMPTY_HANDLE(isolate, site);
|
RETURN_IF_EMPTY_HANDLE(isolate, site);
|
||||||
|
|
||||||
Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
|
Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
|
||||||
AllocationSiteUsageContext usage_context(isolate, site, true);
|
Handle<JSObject> copy = JSObject::DeepCopy(boilerplate);
|
||||||
usage_context.EnterNewScope();
|
|
||||||
Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context);
|
|
||||||
usage_context.ExitScope(site, boilerplate);
|
|
||||||
RETURN_IF_EMPTY_HANDLE(isolate, copy);
|
RETURN_IF_EMPTY_HANDLE(isolate, copy);
|
||||||
return *copy;
|
return *copy;
|
||||||
}
|
}
|
||||||
@ -588,8 +574,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
|
|||||||
isolate->counters()->cow_arrays_created_runtime()->Increment();
|
isolate->counters()->cow_arrays_created_runtime()->Increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AllocationSite::GetMode(boilerplate->GetElementsKind()) ==
|
AllocationSiteMode mode = AllocationSite::GetMode(
|
||||||
TRACK_ALLOCATION_SITE) {
|
boilerplate->GetElementsKind());
|
||||||
|
if (mode == TRACK_ALLOCATION_SITE) {
|
||||||
return isolate->heap()->CopyJSObject(boilerplate, *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<Cell> cell = Handle<Cell>::cast(type_info);
|
||||||
Handle<AllocationSite> site = Handle<AllocationSite>(
|
Handle<AllocationSite> site = Handle<AllocationSite>(
|
||||||
AllocationSite::cast(cell->value()), isolate);
|
AllocationSite::cast(cell->value()), isolate);
|
||||||
ASSERT(!site->SitePointsToLiteral());
|
ASSERT(!site->IsLiteralSite());
|
||||||
ElementsKind to_kind = site->GetElementsKind();
|
ElementsKind to_kind = site->GetElementsKind();
|
||||||
if (holey && !IsFastHoleyElementsKind(to_kind)) {
|
if (holey && !IsFastHoleyElementsKind(to_kind)) {
|
||||||
to_kind = GetHoleyElementsKind(to_kind);
|
to_kind = GetHoleyElementsKind(to_kind);
|
||||||
|
@ -383,114 +383,4 @@ if (support_smi_only_arrays) {
|
|||||||
|
|
||||||
instanceof_check(realmBArray);
|
instanceof_check(realmBArray);
|
||||||
assertUnoptimized(instanceof_check);
|
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]);
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
|
@ -209,8 +209,6 @@
|
|||||||
'../../src/accessors.h',
|
'../../src/accessors.h',
|
||||||
'../../src/allocation.cc',
|
'../../src/allocation.cc',
|
||||||
'../../src/allocation.h',
|
'../../src/allocation.h',
|
||||||
'../../src/allocation-site-scopes.cc',
|
|
||||||
'../../src/allocation-site-scopes.h',
|
|
||||||
'../../src/api.cc',
|
'../../src/api.cc',
|
||||||
'../../src/api.h',
|
'../../src/api.h',
|
||||||
'../../src/apiutils.h',
|
'../../src/apiutils.h',
|
||||||
|
Loading…
Reference in New Issue
Block a user