| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 0fac329a31e49b840e6f46aee16a1fe506f64480..3ea5b19c0743a3b700350233b7e4712b33ccd711 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -1999,6 +1999,155 @@ Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
|
| }
|
| }
|
|
|
| +namespace {
|
| +
|
| +MUST_USE_RESULT Maybe<bool> FastAssign(Handle<JSReceiver> target,
|
| + Handle<Object> source, bool use_set) {
|
| + // Non-empty strings are the only non-JSReceivers that need to be handled
|
| + // explicitly by Object.assign.
|
| + if (!source->IsJSReceiver()) {
|
| + return Just(!source->IsString() || String::cast(*source)->length() == 0);
|
| + }
|
| +
|
| + // If the target is deprecated, the object will be updated on first store. If
|
| + // the source for that store equals the target, this will invalidate the
|
| + // cached representation of the source. Preventively upgrade the target.
|
| + // Do this on each iteration since any property load could cause deprecation.
|
| + if (target->map()->is_deprecated()) {
|
| + JSObject::MigrateInstance(Handle<JSObject>::cast(target));
|
| + }
|
| +
|
| + Isolate* isolate = target->GetIsolate();
|
| + Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
|
| +
|
| + if (!map->IsJSObjectMap()) return Just(false);
|
| + if (!map->OnlyHasSimpleProperties()) return Just(false);
|
| +
|
| + Handle<JSObject> from = Handle<JSObject>::cast(source);
|
| + if (from->elements() != isolate->heap()->empty_fixed_array()) {
|
| + return Just(false);
|
| + }
|
| +
|
| + Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
|
| + int length = map->NumberOfOwnDescriptors();
|
| +
|
| + bool stable = true;
|
| +
|
| + 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 (stable) {
|
| + 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, JSReceiver::GetProperty(from, next_key),
|
| + Nothing<bool>());
|
| + stable = from->map() == *map;
|
| + }
|
| + } 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, from,
|
| + 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), Nothing<bool>());
|
| + }
|
| +
|
| + if (use_set) {
|
| + LookupIterator it(target, next_key, target);
|
| + bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA;
|
| + Maybe<bool> result = Object::SetProperty(
|
| + &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED);
|
| + if (result.IsNothing()) return result;
|
| + if (stable && call_to_js) stable = from->map() == *map;
|
| + } else {
|
| + // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
|
| + bool success;
|
| + LookupIterator it = LookupIterator::PropertyOrElement(
|
| + isolate, target, next_key, &success, LookupIterator::OWN);
|
| + CHECK(success);
|
| + CHECK(
|
| + JSObject::CreateDataProperty(&it, prop_value, Object::THROW_ON_ERROR)
|
| + .FromJust());
|
| + }
|
| + }
|
| +
|
| + return Just(true);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// static
|
| +Maybe<bool> JSReceiver::SetOrCopyDataProperties(Isolate* isolate,
|
| + Handle<JSReceiver> target,
|
| + Handle<Object> source,
|
| + bool use_set) {
|
| + Maybe<bool> fast_assign = FastAssign(target, source, use_set);
|
| + if (fast_assign.IsNothing()) return Nothing<bool>();
|
| + if (fast_assign.FromJust()) return Just(true);
|
| +
|
| + Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
|
| + // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
|
| + Handle<FixedArray> keys;
|
| + ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
| + isolate, keys,
|
| + KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
|
| + GetKeysConversion::kKeepNumbers),
|
| + Nothing<bool>());
|
| +
|
| + // 4. Repeat for each element nextKey of keys in List order,
|
| + for (int j = 0; j < keys->length(); ++j) {
|
| + Handle<Object> next_key(keys->get(j), isolate);
|
| + // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
|
| + PropertyDescriptor desc;
|
| + Maybe<bool> found =
|
| + JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
|
| + if (found.IsNothing()) return Nothing<bool>();
|
| + // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
|
| + if (found.FromJust() && desc.enumerable()) {
|
| + // 4a ii 1. Let propValue be ? Get(from, nextKey).
|
| + Handle<Object> prop_value;
|
| + ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
| + isolate, prop_value,
|
| + Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
|
| +
|
| + if (use_set) {
|
| + // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
|
| + Handle<Object> status;
|
| + ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
| + isolate, status, Runtime::SetObjectProperty(
|
| + isolate, target, next_key, prop_value, STRICT),
|
| + Nothing<bool>());
|
| + } else {
|
| + // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
|
| + bool success;
|
| + LookupIterator it = LookupIterator::PropertyOrElement(
|
| + isolate, target, next_key, &success, LookupIterator::OWN);
|
| + CHECK(success);
|
| + CHECK(JSObject::CreateDataProperty(&it, prop_value,
|
| + Object::THROW_ON_ERROR)
|
| + .FromJust());
|
| + }
|
| + }
|
| + }
|
| +
|
| + return Just(true);
|
| +}
|
| +
|
| Map* Object::GetPrototypeChainRootMap(Isolate* isolate) {
|
| DisallowHeapAllocation no_alloc;
|
| if (IsSmi()) {
|
|
|