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

Unified Diff: src/builtins.cc

Issue 1688953004: [builtins] Add an initial fast-path to Object.assign. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | src/lookup.h » ('j') | src/objects.cc » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/builtins.cc
diff --git a/src/builtins.cc b/src/builtins.cc
index 3aef9abb15ad267bee440a3e1705840d13a9fa5b..990f7d9eefea0c2367453ebd5b21f719cd68b683 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1562,6 +1562,75 @@ BUILTIN(ArrayIsArray) {
return *isolate->factory()->ToBoolean(result.FromJust());
}
+namespace {
+
+MUST_USE_RESULT Maybe<bool> FastAssign(Handle<JSReceiver> to,
+ Handle<Object> next_source) {
+ // Non-empty strings are the only non-JSReceivers that need to be handled
+ // explicitly by Object.assign.
+ if (!next_source->IsJSReceiver()) {
+ return Just(!next_source->IsString() ||
+ String::cast(*next_source)->length() == 0);
+ }
+
+ Isolate* isolate = to->GetIsolate();
+ Handle<Map> map(JSReceiver::cast(*next_source)->map(), isolate);
+
+ if (!map->IsJSObjectMap()) return Just(false);
+ if (!map->OnlyHasSimpleProperties()) return Just(false);
+
+ Handle<JSObject> from = Handle<JSObject>::cast(next_source);
+ if (from->elements() != isolate->heap()->empty_fixed_array()) {
+ return Just(false);
+ }
+
+ Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
+ int length = map->NumberOfOwnDescriptors();
+
+ for (int i = 0; i < length; i++) {
+ Handle<Name> next_key(descriptors->GetKey(i), isolate);
+ Handle<Object> prop_value;
+ // Directly decode from the descriptor array if |from| did not change shape.
+ if (from->map() == *map) {
+ PropertyDetails details = descriptors->GetDetails(i);
+ if (!details.IsEnumerable()) continue;
+ if (details.kind() == kData) {
+ if (details.location() == kDescriptor) {
+ prop_value = handle(descriptors->GetValue(i), isolate);
+ } else {
+ Representation representation = details.representation();
+ FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+ prop_value = JSObject::FastPropertyAt(from, representation, index);
+ }
+ } else {
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, prop_value, Object::GetProperty(from, next_key, STRICT),
+ Nothing<bool>());
+ }
+ } else {
+ // If the map did change, do a slower lookup. We are still guaranteed that
+ // the object has a simple shape, and that the key is a name.
+ LookupIterator it(from, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
+ if (!it.IsFound()) continue;
+ DCHECK(it.state() == LookupIterator::DATA ||
+ it.state() == LookupIterator::ACCESSOR);
+ if (!it.IsEnumerable()) continue;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, prop_value,
+ Object::GetProperty(&it, STRICT),
+ Nothing<bool>());
+ }
+ Handle<Object> status;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, status,
+ Object::SetProperty(to, next_key, prop_value, STRICT,
+ Object::CERTAINLY_NOT_STORE_FROM_KEYED),
+ Nothing<bool>());
+ }
+
+ return Just(true);
+}
+
+} // namespace
// ES6 19.1.2.1 Object.assign
BUILTIN(ObjectAssign) {
@@ -1579,10 +1648,13 @@ BUILTIN(ObjectAssign) {
// 4. For each element nextSource of sources, in ascending index order,
for (int i = 2; i < args.length(); ++i) {
Handle<Object> next_source = args.at<Object>(i);
+ Maybe<bool> fast_assign = FastAssign(to, next_source);
+ if (fast_assign.IsNothing()) return isolate->heap()->exception();
+ if (fast_assign.FromJust()) continue;
// 4a. If nextSource is undefined or null, let keys be an empty List.
- if (next_source->IsUndefined() || next_source->IsNull()) continue;
// 4b. Else,
// 4b i. Let from be ToObject(nextSource).
+ // Only non-empty strings and JSReceivers have enumerable properties.
Handle<JSReceiver> from =
Object::ToObject(isolate, next_source).ToHandleChecked();
// 4b ii. Let keys be ? from.[[OwnPropertyKeys]]().
« no previous file with comments | « no previous file | src/lookup.h » ('j') | src/objects.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698