Revision: 18046
Author: [email protected]
Date: Mon Nov 25 12:41:27 2013 UTC
Log: A performance regression in array literal creation was caused by
refactoring that eliminated a special fast case for shallow arrays. At the
same time the general case got a bit slower. This CL restores most of the
performance without coding the special fast case. The virtual dispatching
is unnecessary because we know what we want to do at compile time. A flag
was added to Runtime::CreateArrayLiteral. The flags delivers information
about shallowness but also whether or not allocation mementos should be
created. This is useful for crankshafted code.
BUG=v8:3008
LOG=Y
[email protected]
Review URL: https://codereview.chromium.org/77293003
http://code.google.com/p/v8/source/detail?r=18046
Modified:
/branches/bleeding_edge/src/allocation-site-scopes.cc
/branches/bleeding_edge/src/allocation-site-scopes.h
/branches/bleeding_edge/src/arm/code-stubs-arm.cc
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/ast.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/runtime.h
/branches/bleeding_edge/src/x64/code-stubs-x64.cc
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
/branches/bleeding_edge/test/mjsunit/array-literal-feedback.js
=======================================
--- /branches/bleeding_edge/src/allocation-site-scopes.cc Wed Oct 16
08:10:36 2013 UTC
+++ /branches/bleeding_edge/src/allocation-site-scopes.cc Mon Nov 25
12:41:27 2013 UTC
@@ -81,28 +81,5 @@
}
}
}
-
-
-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.is_null() || *object == scope_site->transition_info());
-}
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/allocation-site-scopes.h Wed Oct 16
08:10:36 2013 UTC
+++ /branches/bleeding_edge/src/allocation-site-scopes.h Mon Nov 25
12:41:27 2013 UTC
@@ -45,7 +45,6 @@
isolate_ = isolate;
activated_ = activated;
};
- virtual ~AllocationSiteContext() {}
Handle<AllocationSite> top() { return top_; }
Handle<AllocationSite> current() { return current_; }
@@ -53,19 +52,13 @@
// 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;
+ Isolate* isolate() { return isolate_; }
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());
@@ -86,9 +79,8 @@
explicit AllocationSiteCreationContext(Isolate* isolate)
: AllocationSiteContext(isolate, true) { }
- virtual Handle<AllocationSite> EnterNewScope() V8_OVERRIDE;
- virtual void ExitScope(Handle<AllocationSite> site,
- Handle<JSObject> object) V8_OVERRIDE;
+ Handle<AllocationSite> EnterNewScope();
+ void ExitScope(Handle<AllocationSite> site, Handle<JSObject> object);
};
@@ -101,9 +93,25 @@
: AllocationSiteContext(isolate, activated),
top_site_(site) { }
- virtual Handle<AllocationSite> EnterNewScope() V8_OVERRIDE;
- virtual void ExitScope(Handle<AllocationSite> site,
- Handle<JSObject> object) V8_OVERRIDE;
+ inline Handle<AllocationSite> 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());
+ }
+
+ inline void 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.is_null() || *object == scope_site->transition_info());
+ }
private:
Handle<AllocationSite> top_site_;
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Fri Nov 15 17:53:35
2013 UTC
+++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Nov 25 12:41:27
2013 UTC
@@ -77,7 +77,7 @@
descriptor->register_param_count_ = 3;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ =
- Runtime::FunctionForId(Runtime::kCreateArrayLiteral)->entry;
+
Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry;
}
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Nov 22 11:35:39
2013 UTC
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Mon Nov 25 12:41:27
2013 UTC
@@ -1770,6 +1770,10 @@
Comment cmnt(masm_, "[ ArrayLiteral");
expr->BuildConstantElements(isolate());
+ int flags = expr->depth() == 1
+ ? ArrayLiteral::kShallowElements
+ : ArrayLiteral::kNoFlags;
+
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements();
@@ -1795,8 +1799,9 @@
isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2);
} else if (expr->depth() > 1 || Serializer::enabled() ||
length > FastCloneShallowArrayStub::kMaximumClonedLength) {
- __ Push(r3, r2, r1);
- __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
+ __ mov(r0, Operand(Smi::FromInt(flags)));
+ __ Push(r3, r2, r1, r0);
+ __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
} else {
ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
FLAG_smi_only_arrays);
=======================================
--- /branches/bleeding_edge/src/ast.h Wed Nov 20 14:17:47 2013 UTC
+++ /branches/bleeding_edge/src/ast.h Mon Nov 25 12:41:27 2013 UTC
@@ -1604,6 +1604,12 @@
// Populate the constant elements fixed array.
void BuildConstantElements(Isolate* isolate);
+ enum Flags {
+ kNoFlags = 0,
+ kShallowElements = 1,
+ kDisableMementos = 1 << 1
+ };
+
protected:
ArrayLiteral(Isolate* isolate,
ZoneList<Expression*>* values,
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Fri Nov 22 19:05:21 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc Mon Nov 25 12:41:27 2013 UTC
@@ -5107,10 +5107,15 @@
// pass an empty fixed array to the runtime function instead.
Handle<FixedArray> constants =
isolate()->factory()->empty_fixed_array();
int literal_index = expr->literal_index();
+ int flags = expr->depth() == 1
+ ? ArrayLiteral::kShallowElements
+ : ArrayLiteral::kNoFlags;
+ flags |= ArrayLiteral::kDisableMementos;
Add<HPushArgument>(Add<HConstant>(literals));
Add<HPushArgument>(Add<HConstant>(literal_index));
Add<HPushArgument>(Add<HConstant>(constants));
+ Add<HPushArgument>(Add<HConstant>(flags));
// TODO(mvstanton): Consider a flag to turn off creation of any
// AllocationMementos for this call: we are in crankshaft and should
have
@@ -5118,7 +5123,7 @@
Runtime::FunctionId function_id = Runtime::kCreateArrayLiteral;
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
Runtime::FunctionForId(function_id),
- 3);
+ 4);
// De-opt if elements kind changed from boilerplate_elements_kind.
Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate());
@@ -9175,7 +9180,7 @@
HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
Handle<JSObject> boilerplate_object,
- AllocationSiteContext* site_context) {
+ AllocationSiteUsageContext* site_context) {
NoObservableSideEffectsScope no_effects(this);
InstanceType instance_type = boilerplate_object->map()->instance_type();
ASSERT(instance_type == JS_ARRAY_TYPE || instance_type ==
JS_OBJECT_TYPE);
@@ -9268,7 +9273,7 @@
void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
Handle<JSObject> boilerplate_object,
HInstruction* object,
- AllocationSiteContext* site_context) {
+ AllocationSiteUsageContext* site_context) {
Handle<DescriptorArray> descriptors(
boilerplate_object->map()->instance_descriptors());
int limit = boilerplate_object->map()->NumberOfOwnDescriptors();
@@ -9340,7 +9345,7 @@
Handle<JSObject> boilerplate_object,
Handle<FixedArrayBase> elements,
HValue* object_elements,
- AllocationSiteContext* site_context) {
+ AllocationSiteUsageContext* site_context) {
ElementsKind kind = boilerplate_object->map()->elements_kind();
int elements_length = elements->length();
HValue* object_elements_length = Add<HConstant>(elements_length);
@@ -9381,7 +9386,7 @@
Handle<FixedArrayBase> elements,
ElementsKind kind,
HValue* object_elements,
- AllocationSiteContext* site_context) {
+ AllocationSiteUsageContext* site_context) {
HInstruction* boilerplate_elements = Add<HConstant>(elements);
int elements_length = elements->length();
Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Fri Nov 22 19:05:21 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.h Mon Nov 25 12:41:27 2013 UTC
@@ -2403,7 +2403,7 @@
HInstruction* BuildThisFunction();
HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object,
- AllocationSiteContext* site_context);
+ AllocationSiteUsageContext* site_context);
void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object,
HInstruction* object);
@@ -2414,12 +2414,12 @@
void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object,
HInstruction* object,
- AllocationSiteContext* site_context);
+ AllocationSiteUsageContext*
site_context);
void BuildEmitElements(Handle<JSObject> boilerplate_object,
Handle<FixedArrayBase> elements,
HValue* object_elements,
- AllocationSiteContext* site_context);
+ AllocationSiteUsageContext* site_context);
void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements,
ElementsKind kind,
@@ -2428,7 +2428,7 @@
void BuildEmitFixedArray(Handle<FixedArrayBase> elements,
ElementsKind kind,
HValue* object_elements,
- AllocationSiteContext* site_context);
+ AllocationSiteUsageContext* site_context);
void AddCheckPrototypeMaps(Handle<JSObject> holder,
Handle<Map> receiver_map);
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Fri Nov 15 17:53:35
2013 UTC
+++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Mon Nov 25 12:41:27
2013 UTC
@@ -82,7 +82,7 @@
descriptor->register_param_count_ = 3;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ =
- Runtime::FunctionForId(Runtime::kCreateArrayLiteral)->entry;
+
Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry;
}
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Nov 22
11:35:39 2013 UTC
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Mon Nov 25
12:41:27 2013 UTC
@@ -1705,6 +1705,10 @@
Comment cmnt(masm_, "[ ArrayLiteral");
expr->BuildConstantElements(isolate());
+ int flags = expr->depth() == 1
+ ? ArrayLiteral::kShallowElements
+ : ArrayLiteral::kNoFlags;
+
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements();
@@ -1737,7 +1741,8 @@
__ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(expr->literal_index())));
__ push(Immediate(constant_elements));
- __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
+ __ push(Immediate(Smi::FromInt(flags)));
+ __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
} else {
ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
FLAG_smi_only_arrays);
=======================================
--- /branches/bleeding_edge/src/objects.cc Fri Nov 22 13:10:31 2013 UTC
+++ /branches/bleeding_edge/src/objects.cc Mon Nov 25 12:41:27 2013 UTC
@@ -5654,14 +5654,6 @@
}
object->set_map(*new_map);
}
-
-
-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) {
@@ -5671,258 +5663,229 @@
}
+template<class ContextObject>
class JSObjectWalkVisitor {
public:
- explicit JSObjectWalkVisitor(AllocationSiteContext* site_context) :
- site_context_(site_context) {}
- virtual ~JSObjectWalkVisitor() {}
+ JSObjectWalkVisitor(ContextObject* site_context, bool copying,
+ JSObject::DeepCopyHints hints)
+ : site_context_(site_context),
+ copying_(copying),
+ hints_(hints) {}
- Handle<JSObject> Visit(Handle<JSObject> object) {
- return StructureWalk(object);
- }
-
- 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.
- virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0;
- 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) {}
-
- 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.
- 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 {
+ protected:
+ inline Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object,
+ Handle<JSObject> value) {
Handle<AllocationSite> current_site = site_context()->EnterNewScope();
Handle<JSObject> copy_of_value = StructureWalk(value);
site_context()->ExitScope(current_site, value);
return copy_of_value;
}
-};
+ inline ContextObject* site_context() { return site_context_; }
+ inline Isolate* isolate() { return site_context()->isolate(); }
-class JSObjectCreateAllocationSitesVisitor: public JSObjectWalkVisitor {
- public:
- explicit JSObjectCreateAllocationSitesVisitor(
- AllocationSiteContext* site_context)
- : JSObjectWalkVisitor(site_context) {}
+ inline bool copying() const { return copying_; }
- virtual bool is_copying() V8_OVERRIDE { return false; }
+ private:
+ ContextObject* site_context_;
+ const bool copying_;
+ const JSObject::DeepCopyHints hints_;
+};
- // 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;
- }
-};
+template <class ContextObject>
+Handle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
+ Handle<JSObject> object) {
+ Isolate* isolate = this->isolate();
+ bool copying = this->copying();
+ bool shallow = hints_ == JSObject::kObjectIsShallowArray;
+ if (!shallow) {
+ StackLimitCheck check(isolate);
-Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject>
object) {
- bool copying = is_copying();
- Isolate* isolate = object->GetIsolate();
- StackLimitCheck check(isolate);
- if (check.HasOverflowed()) {
- isolate->StackOverflow();
- return Handle<JSObject>::null();
+ if (check.HasOverflowed()) {
+ isolate->StackOverflow();
+ return Handle<JSObject>::null();
+ }
}
if (object->map()->is_deprecated()) {
JSObject::MigrateInstance(object);
}
- Handle<JSObject> copy = VisitObject(object);
+ Handle<JSObject> copy;
+ if (copying) {
+ Handle<AllocationSite> site_to_pass;
+ if (site_context()->activated() &&
+ AllocationSite::CanTrack(object->map()->instance_type()) &&
+ AllocationSite::GetMode(object->GetElementsKind()) ==
+ TRACK_ALLOCATION_SITE) {
+ site_to_pass = site_context()->current();
+ }
+ CALL_AND_RETRY_OR_DIE(isolate,
+ isolate->heap()->CopyJSObject(*object,
+ site_to_pass.is_null() ? NULL :
*site_to_pass),
+ { copy =
Handle<JSObject>(JSObject::cast(__object__),
+ isolate);
+ break;
+ },
+ return Handle<JSObject>());
+ } else {
+ copy = object;
+ }
+
ASSERT(copying || copy.is_identical_to(object));
- HandleScope scope(isolate);
+ if (!shallow) {
+ HandleScope scope(isolate);
- // Deep copy local properties.
- if (copy->HasFastProperties()) {
- Handle<DescriptorArray>
descriptors(copy->map()->instance_descriptors());
- int limit = copy->map()->NumberOfOwnDescriptors();
- for (int i = 0; i < limit; i++) {
- PropertyDetails details = descriptors->GetDetails(i);
- if (details.type() != FIELD) continue;
- int index = descriptors->GetFieldIndex(i);
- Handle<Object> value(object->RawFastPropertyAt(index), isolate);
- if (value->IsJSObject()) {
- value = VisitElementOrProperty(copy,
Handle<JSObject>::cast(value));
- RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<JSObject>());
- } else {
- Representation representation = details.representation();
- value = NewStorageFor(isolate, value, representation);
- }
- if (copying) {
- copy->FastPropertyAtPut(index, *value);
- }
- }
- } else {
- Handle<FixedArray> names =
- isolate->factory()->NewFixedArray(copy->NumberOfLocalProperties());
- copy->GetLocalPropertyNames(*names, 0);
- for (int i = 0; i < names->length(); i++) {
- ASSERT(names->get(i)->IsString());
- Handle<String> key_string(String::cast(names->get(i)));
- PropertyAttributes attributes =
- copy->GetLocalPropertyAttribute(*key_string);
- // Only deep copy fields from the object literal expression.
- // In particular, don't try to copy the length attribute of
- // an array.
- if (attributes != NONE) continue;
- Handle<Object> value(
- copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(),
- isolate);
- if (value->IsJSObject()) {
- Handle<JSObject> result = VisitElementOrProperty(
- copy, Handle<JSObject>::cast(value));
- RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
+ // Deep copy local properties.
+ if (copy->HasFastProperties()) {
+ Handle<DescriptorArray>
descriptors(copy->map()->instance_descriptors());
+ int limit = copy->map()->NumberOfOwnDescriptors();
+ for (int i = 0; i < limit; i++) {
+ PropertyDetails details = descriptors->GetDetails(i);
+ if (details.type() != FIELD) continue;
+ int index = descriptors->GetFieldIndex(i);
+ Handle<Object> value(object->RawFastPropertyAt(index), isolate);
+ if (value->IsJSObject()) {
+ value = VisitElementOrProperty(copy,
Handle<JSObject>::cast(value));
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<JSObject>());
+ } else {
+ Representation representation = details.representation();
+ value = NewStorageFor(isolate, value, representation);
+ }
if (copying) {
- // Creating object copy for literals. No strict mode needed.
- CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty(
- copy, key_string, result, NONE, kNonStrictMode));
+ copy->FastPropertyAtPut(index, *value);
+ }
+ }
+ } else {
+ Handle<FixedArray> names =
+
isolate->factory()->NewFixedArray(copy->NumberOfLocalProperties());
+ copy->GetLocalPropertyNames(*names, 0);
+ for (int i = 0; i < names->length(); i++) {
+ ASSERT(names->get(i)->IsString());
+ Handle<String> key_string(String::cast(names->get(i)));
+ PropertyAttributes attributes =
+ copy->GetLocalPropertyAttribute(*key_string);
+ // Only deep copy fields from the object literal expression.
+ // In particular, don't try to copy the length attribute of
+ // an array.
+ if (attributes != NONE) continue;
+ Handle<Object> value(
+ copy->GetProperty(*key_string,
&attributes)->ToObjectUnchecked(),
+ isolate);
+ if (value->IsJSObject()) {
+ Handle<JSObject> result = VisitElementOrProperty(
+ copy, Handle<JSObject>::cast(value));
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result,
Handle<JSObject>());
+ if (copying) {
+ // Creating object copy for literals. No strict mode needed.
+ CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty(
+ copy, key_string, result, NONE, kNonStrictMode));
+ }
}
}
}
- }
- // Deep copy local elements.
- // Pixel elements cannot be created using an object literal.
- ASSERT(!copy->HasExternalArrayElements());
- switch (copy->GetElementsKind()) {
- case FAST_SMI_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_ELEMENTS: {
- Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
- if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
- if (copying) {
- isolate->counters()->cow_arrays_created_runtime()->Increment();
- }
+ // Deep copy local elements.
+ // Pixel elements cannot be created using an object literal.
+ ASSERT(!copy->HasExternalArrayElements());
+ switch (copy->GetElementsKind()) {
+ case FAST_SMI_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS: {
+ Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
+ if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
+ if (copying) {
+ isolate->counters()->cow_arrays_created_runtime()->Increment();
+ }
#ifdef DEBUG
- for (int i = 0; i < elements->length(); i++) {
- ASSERT(!elements->get(i)->IsJSObject());
- }
+ for (int i = 0; i < elements->length(); i++) {
+ ASSERT(!elements->get(i)->IsJSObject());
+ }
#endif
- } else {
- for (int i = 0; i < elements->length(); i++) {
- Handle<Object> value(elements->get(i), isolate);
- ASSERT(value->IsSmi() ||
- value->IsTheHole() ||
- (IsFastObjectElementsKind(copy->GetElementsKind())));
- if (value->IsJSObject()) {
- Handle<JSObject> result = VisitElementOrProperty(
- copy, Handle<JSObject>::cast(value));
- RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result,
Handle<JSObject>());
- if (copying) {
- elements->set(i, *result);
+ } else {
+ for (int i = 0; i < elements->length(); i++) {
+ Handle<Object> value(elements->get(i), isolate);
+ ASSERT(value->IsSmi() ||
+ value->IsTheHole() ||
+ (IsFastObjectElementsKind(copy->GetElementsKind())));
+ if (value->IsJSObject()) {
+ Handle<JSObject> result = VisitElementOrProperty(
+ copy, Handle<JSObject>::cast(value));
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result,
Handle<JSObject>());
+ if (copying) {
+ elements->set(i, *result);
+ }
}
}
}
+ break;
}
- break;
- }
- case DICTIONARY_ELEMENTS: {
- Handle<SeededNumberDictionary> element_dictionary(
- copy->element_dictionary());
- int capacity = element_dictionary->Capacity();
- for (int i = 0; i < capacity; i++) {
- Object* k = element_dictionary->KeyAt(i);
- if (element_dictionary->IsKey(k)) {
- Handle<Object> value(element_dictionary->ValueAt(i), isolate);
- if (value->IsJSObject()) {
- Handle<JSObject> result = VisitElementOrProperty(
- copy, Handle<JSObject>::cast(value));
- RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result,
Handle<JSObject>());
- if (copying) {
- element_dictionary->ValueAtPut(i, *result);
+ case DICTIONARY_ELEMENTS: {
+ Handle<SeededNumberDictionary> element_dictionary(
+ copy->element_dictionary());
+ int capacity = element_dictionary->Capacity();
+ for (int i = 0; i < capacity; i++) {
+ Object* k = element_dictionary->KeyAt(i);
+ if (element_dictionary->IsKey(k)) {
+ Handle<Object> value(element_dictionary->ValueAt(i), isolate);
+ if (value->IsJSObject()) {
+ Handle<JSObject> result = VisitElementOrProperty(
+ copy, Handle<JSObject>::cast(value));
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result,
Handle<JSObject>());
+ if (copying) {
+ element_dictionary->ValueAtPut(i, *result);
+ }
}
}
}
+ break;
}
- break;
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
+ UNIMPLEMENTED();
+ break;
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ // No contained objects, nothing to do.
+ break;
}
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNIMPLEMENTED();
- break;
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- // No contained objects, nothing to do.
- break;
}
+
return copy;
}
-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)));
+Handle<JSObject> JSObject::DeepWalk(
+ Handle<JSObject> object,
+ AllocationSiteCreationContext* site_context) {
+ JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
+ kNoHints);
+ Handle<JSObject> result = v.StructureWalk(object);
+ ASSERT(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));
+ AllocationSiteUsageContext*
site_context,
+ DeepCopyHints hints) {
+ JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true,
hints);
+ Handle<JSObject> copy = v.StructureWalk(object);
+ ASSERT(!copy.is_identical_to(object));
return copy;
}
=======================================
--- /branches/bleeding_edge/src/objects.h Fri Nov 22 15:06:20 2013 UTC
+++ /branches/bleeding_edge/src/objects.h Mon Nov 25 12:41:27 2013 UTC
@@ -861,7 +861,8 @@
class AccessorPair;
class AllocationSite;
-class AllocationSiteContext;
+class AllocationSiteCreationContext;
+class AllocationSiteUsageContext;
class DictionaryElementsAccessor;
class ElementsAccessor;
class Failure;
@@ -2521,13 +2522,17 @@
static void SetObserved(Handle<JSObject> object);
// Copy object.
- static Handle<JSObject> Copy(Handle<JSObject> object,
- Handle<AllocationSite> site);
+ enum DeepCopyHints {
+ kNoHints = 0,
+ kObjectIsShallowArray = 1
+ };
+
static Handle<JSObject> Copy(Handle<JSObject> object);
static Handle<JSObject> DeepCopy(Handle<JSObject> object,
- AllocationSiteContext* site_context);
+ AllocationSiteUsageContext*
site_context,
+ DeepCopyHints hints = kNoHints);
static Handle<JSObject> DeepWalk(Handle<JSObject> object,
- AllocationSiteContext* site_context);
+ AllocationSiteCreationContext*
site_context);
// Casting.
static inline JSObject* cast(Object* obj);
=======================================
--- /branches/bleeding_edge/src/runtime.cc Fri Nov 22 11:35:39 2013 UTC
+++ /branches/bleeding_edge/src/runtime.cc Mon Nov 25 12:41:27 2013 UTC
@@ -554,25 +554,53 @@
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 3);
- CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
- CONVERT_SMI_ARG_CHECKED(literals_index, 1);
- CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
-
+static MaybeObject* CreateArrayLiteralImpl(Isolate* isolate,
+ Handle<FixedArray> literals,
+ int literals_index,
+ Handle<FixedArray> elements,
+ int flags) {
Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals,
literals_index, elements);
RETURN_IF_EMPTY_HANDLE(isolate, site);
+ bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0;
Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
- AllocationSiteUsageContext usage_context(isolate, site, true);
+ AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
usage_context.EnterNewScope();
- Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context);
+ JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements)
== 0
+ ? JSObject::kNoHints
+ : JSObject::kObjectIsShallowArray;
+ Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context,
+ hints);
usage_context.ExitScope(site, boilerplate);
RETURN_IF_EMPTY_HANDLE(isolate, copy);
return *copy;
}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 4);
+ CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
+ CONVERT_SMI_ARG_CHECKED(literals_index, 1);
+ CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
+ CONVERT_SMI_ARG_CHECKED(flags, 3);
+
+ return CreateArrayLiteralImpl(isolate, literals, literals_index,
elements,
+ flags);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralStubBailout) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
+ CONVERT_SMI_ARG_CHECKED(literals_index, 1);
+ CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
+
+ return CreateArrayLiteralImpl(isolate, literals, literals_index,
elements,
+ ArrayLiteral::kShallowElements);
+}
RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) {
=======================================
--- /branches/bleeding_edge/src/runtime.h Fri Nov 22 11:35:39 2013 UTC
+++ /branches/bleeding_edge/src/runtime.h Mon Nov 25 12:41:27 2013 UTC
@@ -300,7 +300,8 @@
/* Literals */ \
F(MaterializeRegExpLiteral, 4, 1)\
F(CreateObjectLiteral, 4, 1) \
- F(CreateArrayLiteral, 3, 1) \
+ F(CreateArrayLiteral, 4, 1) \
+ F(CreateArrayLiteralStubBailout, 3, 1) \
\
/* Harmony generators */ \
F(CreateJSGeneratorObject, 0, 1) \
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Sat Nov 16 15:22:09
2013 UTC
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Nov 25 12:41:27
2013 UTC
@@ -78,7 +78,7 @@
descriptor->register_param_count_ = 3;
descriptor->register_params_ = registers;
descriptor->deoptimization_handler_ =
- Runtime::FunctionForId(Runtime::kCreateArrayLiteral)->entry;
+
Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry;
}
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Nov 22 11:35:39
2013 UTC
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Mon Nov 25 12:41:27
2013 UTC
@@ -1726,6 +1726,10 @@
Comment cmnt(masm_, "[ ArrayLiteral");
expr->BuildConstantElements(isolate());
+ int flags = expr->depth() == 1
+ ? ArrayLiteral::kShallowElements
+ : ArrayLiteral::kNoFlags;
+
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements();
@@ -1758,7 +1762,8 @@
__ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
__ Push(Smi::FromInt(expr->literal_index()));
__ Push(constant_elements);
- __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
+ __ Push(Smi::FromInt(flags));
+ __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
} else {
ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
FLAG_smi_only_arrays);
=======================================
--- /branches/bleeding_edge/test/mjsunit/array-literal-feedback.js Thu Nov
7 12:20:45 2013 UTC
+++ /branches/bleeding_edge/test/mjsunit/array-literal-feedback.js Mon Nov
25 12:41:27 2013 UTC
@@ -93,11 +93,15 @@
}
get_literal(3);
- get_literal(3);
- %OptimizeFunctionOnNextCall(get_literal);
+ // It's important to store a from before we crankshaft get_literal,
because
+ // mementos won't be created from crankshafted code at all.
a = get_literal(3);
+ %OptimizeFunctionOnNextCall(get_literal);
+ get_literal(3);
assertOptimized(get_literal);
assertTrue(%HasFastSmiElements(a));
+ // a has a memento so the transition caused by the store will affect the
+ // boilerplate.
a[0] = 3.5;
// We should have transitioned the boilerplate array to double, and
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.