1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/objects/js-objects.h"
6
7#include "src/api/api-arguments-inl.h"
8#include "src/base/optional.h"
9#include "src/common/globals.h"
10#include "src/date/date.h"
11#include "src/execution/arguments.h"
12#include "src/execution/frames.h"
13#include "src/execution/isolate.h"
14#include "src/handles/handles-inl.h"
15#include "src/handles/maybe-handles.h"
16#include "src/heap/factory-inl.h"
17#include "src/heap/heap-inl.h"
18#include "src/heap/memory-chunk.h"
19#include "src/init/bootstrapper.h"
20#include "src/logging/counters.h"
21#include "src/logging/log.h"
22#include "src/objects/allocation-site-inl.h"
23#include "src/objects/api-callbacks.h"
24#include "src/objects/arguments-inl.h"
25#include "src/objects/dictionary.h"
26#include "src/objects/elements.h"
27#include "src/objects/field-type.h"
28#include "src/objects/fixed-array.h"
29#include "src/objects/heap-number.h"
30#include "src/objects/heap-object.h"
31#include "src/objects/js-array-buffer-inl.h"
32#include "src/objects/js-array-inl.h"
33#include "src/objects/lookup.h"
34#include "src/objects/map-updater.h"
35#include "src/objects/objects-inl.h"
36#ifdef V8_INTL_SUPPORT
37#include "src/objects/js-break-iterator.h"
38#include "src/objects/js-collator.h"
39#endif  // V8_INTL_SUPPORT
40#include "src/objects/js-collection.h"
41#ifdef V8_INTL_SUPPORT
42#include "src/objects/js-date-time-format.h"
43#include "src/objects/js-display-names.h"
44#endif  // V8_INTL_SUPPORT
45#include "src/objects/js-generator-inl.h"
46#ifdef V8_INTL_SUPPORT
47#include "src/objects/js-list-format.h"
48#include "src/objects/js-locale.h"
49#include "src/objects/js-number-format.h"
50#include "src/objects/js-plural-rules.h"
51#endif  // V8_INTL_SUPPORT
52#include "src/objects/js-promise.h"
53#include "src/objects/js-regexp-inl.h"
54#include "src/objects/js-regexp-string-iterator.h"
55#include "src/objects/js-shadow-realms.h"
56#ifdef V8_INTL_SUPPORT
57#include "src/objects/js-relative-time-format.h"
58#include "src/objects/js-segment-iterator.h"
59#include "src/objects/js-segmenter.h"
60#include "src/objects/js-segments.h"
61#endif  // V8_INTL_SUPPORT
62#include "src/objects/js-struct-inl.h"
63#include "src/objects/js-temporal-objects-inl.h"
64#include "src/objects/js-weak-refs.h"
65#include "src/objects/map-inl.h"
66#include "src/objects/module.h"
67#include "src/objects/oddball.h"
68#include "src/objects/property-cell.h"
69#include "src/objects/property-descriptor.h"
70#include "src/objects/property.h"
71#include "src/objects/prototype-info.h"
72#include "src/objects/prototype.h"
73#include "src/objects/shared-function-info.h"
74#include "src/objects/swiss-name-dictionary-inl.h"
75#include "src/objects/transitions.h"
76#include "src/strings/string-builder-inl.h"
77#include "src/strings/string-stream.h"
78#include "src/utils/ostreams.h"
79
80#if V8_ENABLE_WEBASSEMBLY
81#include "src/wasm/wasm-objects.h"
82#include "src/debug/debug-wasm-objects.h"
83#endif  // V8_ENABLE_WEBASSEMBLY
84
85namespace v8 {
86namespace internal {
87
88// static
89Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
90  for (; it->IsFound(); it->Next()) {
91    switch (it->state()) {
92      case LookupIterator::NOT_FOUND:
93      case LookupIterator::TRANSITION:
94        UNREACHABLE();
95      case LookupIterator::JSPROXY:
96        return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
97                                    it->GetName());
98      case LookupIterator::INTERCEPTOR: {
99        Maybe<PropertyAttributes> result =
100            JSObject::GetPropertyAttributesWithInterceptor(it);
101        if (result.IsNothing()) return Nothing<bool>();
102        if (result.FromJust() != ABSENT) return Just(true);
103        break;
104      }
105      case LookupIterator::ACCESS_CHECK: {
106        if (it->HasAccess()) break;
107        Maybe<PropertyAttributes> result =
108            JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
109        if (result.IsNothing()) return Nothing<bool>();
110        return Just(result.FromJust() != ABSENT);
111      }
112      case LookupIterator::INTEGER_INDEXED_EXOTIC:
113        // TypedArray out-of-bounds access.
114        return Just(false);
115      case LookupIterator::ACCESSOR:
116      case LookupIterator::DATA:
117        return Just(true);
118    }
119  }
120  return Just(false);
121}
122
123// static
124Maybe<bool> JSReceiver::HasOwnProperty(Isolate* isolate,
125                                       Handle<JSReceiver> object,
126                                       Handle<Name> name) {
127  if (object->IsJSModuleNamespace()) {
128    PropertyDescriptor desc;
129    return JSReceiver::GetOwnPropertyDescriptor(isolate, object, name, &desc);
130  }
131
132  if (object->IsJSObject()) {  // Shortcut.
133    PropertyKey key(isolate, name);
134    LookupIterator it(isolate, object, key, LookupIterator::OWN);
135    return HasProperty(&it);
136  }
137
138  Maybe<PropertyAttributes> attributes =
139      JSReceiver::GetOwnPropertyAttributes(object, name);
140  MAYBE_RETURN(attributes, Nothing<bool>());
141  return Just(attributes.FromJust() != ABSENT);
142}
143
144Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it,
145                                           AllocationPolicy allocation_policy) {
146  for (; it->IsFound(); it->Next()) {
147    switch (it->state()) {
148      case LookupIterator::INTERCEPTOR:
149      case LookupIterator::NOT_FOUND:
150      case LookupIterator::TRANSITION:
151        UNREACHABLE();
152      case LookupIterator::ACCESS_CHECK:
153        // Support calling this method without an active context, but refuse
154        // access to access-checked objects in that case.
155        if (!it->isolate()->context().is_null() && it->HasAccess()) continue;
156        V8_FALLTHROUGH;
157      case LookupIterator::JSPROXY:
158        it->NotFound();
159        return it->isolate()->factory()->undefined_value();
160      case LookupIterator::ACCESSOR:
161        // TODO(verwaest): For now this doesn't call into AccessorInfo, since
162        // clients don't need it. Update once relevant.
163        it->NotFound();
164        return it->isolate()->factory()->undefined_value();
165      case LookupIterator::INTEGER_INDEXED_EXOTIC:
166        return it->isolate()->factory()->undefined_value();
167      case LookupIterator::DATA:
168        return it->GetDataValue(allocation_policy);
169    }
170  }
171  return it->isolate()->factory()->undefined_value();
172}
173
174// static
175Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
176                                            Handle<JSReceiver> object,
177                                            Handle<Object> proto) {
178  PrototypeIterator iter(isolate, object, kStartAtReceiver);
179  while (true) {
180    if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
181    if (iter.IsAtEnd()) return Just(false);
182    if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
183      return Just(true);
184    }
185  }
186}
187
188// static
189bool JSReceiver::CheckPrivateNameStore(LookupIterator* it, bool is_define) {
190  DCHECK(it->GetName()->IsPrivateName());
191  Isolate* isolate = it->isolate();
192  Handle<String> name_string(
193      String::cast(Handle<Symbol>::cast(it->GetName())->description()),
194      isolate);
195  bool should_throw = GetShouldThrow(isolate, Nothing<ShouldThrow>()) ==
196                      ShouldThrow::kThrowOnError;
197  for (; it->IsFound(); it->Next()) {
198    switch (it->state()) {
199      case LookupIterator::TRANSITION:
200      case LookupIterator::INTERCEPTOR:
201      case LookupIterator::JSPROXY:
202      case LookupIterator::NOT_FOUND:
203      case LookupIterator::INTEGER_INDEXED_EXOTIC:
204      case LookupIterator::ACCESSOR:
205        UNREACHABLE();
206      case LookupIterator::ACCESS_CHECK:
207        if (!it->HasAccess()) {
208          isolate->ReportFailedAccessCheck(
209              Handle<JSObject>::cast(it->GetReceiver()));
210          RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, false);
211          return false;
212        }
213        break;
214      case LookupIterator::DATA:
215        if (is_define && should_throw) {
216          MessageTemplate message =
217              it->GetName()->IsPrivateBrand()
218                  ? MessageTemplate::kInvalidPrivateBrandReinitialization
219                  : MessageTemplate::kInvalidPrivateFieldReinitialization;
220          isolate->Throw(*(isolate->factory()->NewTypeError(
221              message, name_string, it->GetReceiver())));
222          return false;
223        }
224        return true;
225    }
226  }
227  DCHECK(!it->IsFound());
228  if (!is_define && should_throw) {
229    isolate->Throw(*(isolate->factory()->NewTypeError(
230        MessageTemplate::kInvalidPrivateMemberWrite, name_string,
231        it->GetReceiver())));
232    return false;
233  }
234  return true;
235}
236
237// static
238Maybe<bool> JSReceiver::CheckIfCanDefine(Isolate* isolate, LookupIterator* it,
239                                         Handle<Object> value,
240                                         Maybe<ShouldThrow> should_throw) {
241  if (it->IsFound()) {
242    Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
243    MAYBE_RETURN(attributes, Nothing<bool>());
244    if ((attributes.FromJust() & DONT_DELETE) != 0) {
245      RETURN_FAILURE(
246          isolate, GetShouldThrow(isolate, should_throw),
247          NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
248    }
249  } else if (!JSObject::IsExtensible(
250                 Handle<JSObject>::cast(it->GetReceiver()))) {
251    RETURN_FAILURE(
252        isolate, GetShouldThrow(isolate, should_throw),
253        NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
254  }
255  return Just(true);
256}
257
258namespace {
259
260bool HasExcludedProperty(
261    const base::ScopedVector<Handle<Object>>* excluded_properties,
262    Handle<Object> search_element) {
263  // TODO(gsathya): Change this to be a hashtable.
264  for (int i = 0; i < excluded_properties->length(); i++) {
265    if (search_element->SameValue(*excluded_properties->at(i))) {
266      return true;
267    }
268  }
269
270  return false;
271}
272
273V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign(
274    Handle<JSReceiver> target, Handle<Object> source,
275    PropertiesEnumerationMode mode,
276    const base::ScopedVector<Handle<Object>>* excluded_properties,
277    bool use_set) {
278  // Non-empty strings are the only non-JSReceivers that need to be handled
279  // explicitly by Object.assign.
280  if (!source->IsJSReceiver()) {
281    return Just(!source->IsString() || String::cast(*source).length() == 0);
282  }
283
284  Isolate* isolate = target->GetIsolate();
285
286  // If the target is deprecated, the object will be updated on first store. If
287  // the source for that store equals the target, this will invalidate the
288  // cached representation of the source. Preventively upgrade the target.
289  // Do this on each iteration since any property load could cause deprecation.
290  if (target->map().is_deprecated()) {
291    JSObject::MigrateInstance(isolate, Handle<JSObject>::cast(target));
292  }
293
294  Handle<Map> map(JSReceiver::cast(*source).map(), isolate);
295
296  if (!map->IsJSObjectMap()) return Just(false);
297  if (!map->OnlyHasSimpleProperties()) return Just(false);
298
299  Handle<JSObject> from = Handle<JSObject>::cast(source);
300  if (from->elements() != ReadOnlyRoots(isolate).empty_fixed_array()) {
301    return Just(false);
302  }
303
304  // We should never try to copy properties from an object itself.
305  CHECK_IMPLIES(!use_set, !target.is_identical_to(from));
306
307  Handle<DescriptorArray> descriptors(map->instance_descriptors(isolate),
308                                      isolate);
309
310  bool stable = true;
311
312  // Process symbols last and only do that if we found symbols.
313  bool has_symbol = false;
314  bool process_symbol_only = false;
315  while (true) {
316    for (InternalIndex i : map->IterateOwnDescriptors()) {
317      HandleScope inner_scope(isolate);
318
319      Handle<Name> next_key(descriptors->GetKey(i), isolate);
320      if (mode == PropertiesEnumerationMode::kEnumerationOrder) {
321        if (next_key->IsSymbol()) {
322          has_symbol = true;
323          if (!process_symbol_only) continue;
324        } else {
325          if (process_symbol_only) continue;
326        }
327      }
328      Handle<Object> prop_value;
329      // Directly decode from the descriptor array if |from| did not change
330      // shape.
331      if (stable) {
332        DCHECK_EQ(from->map(), *map);
333        DCHECK_EQ(*descriptors, map->instance_descriptors(isolate));
334
335        PropertyDetails details = descriptors->GetDetails(i);
336        if (!details.IsEnumerable()) continue;
337        if (details.kind() == PropertyKind::kData) {
338          if (details.location() == PropertyLocation::kDescriptor) {
339            prop_value = handle(descriptors->GetStrongValue(i), isolate);
340          } else {
341            Representation representation = details.representation();
342            FieldIndex index = FieldIndex::ForPropertyIndex(
343                *map, details.field_index(), representation);
344            prop_value =
345                JSObject::FastPropertyAt(isolate, from, representation, index);
346          }
347        } else {
348          LookupIterator it(isolate, from, next_key,
349                            LookupIterator::OWN_SKIP_INTERCEPTOR);
350          ASSIGN_RETURN_ON_EXCEPTION_VALUE(
351              isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
352          stable = from->map() == *map;
353          descriptors.PatchValue(map->instance_descriptors(isolate));
354        }
355      } else {
356        // If the map did change, do a slower lookup. We are still guaranteed
357        // that the object has a simple shape, and that the key is a name.
358        LookupIterator it(isolate, from, next_key, from,
359                          LookupIterator::OWN_SKIP_INTERCEPTOR);
360        if (!it.IsFound()) continue;
361        DCHECK(it.state() == LookupIterator::DATA ||
362               it.state() == LookupIterator::ACCESSOR);
363        if (!it.IsEnumerable()) continue;
364        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
365            isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
366      }
367
368      if (use_set) {
369        // The lookup will walk the prototype chain, so we have to be careful
370        // to treat any key correctly for any receiver/holder.
371        PropertyKey key(isolate, next_key);
372        LookupIterator it(isolate, target, key);
373        Maybe<bool> result =
374            Object::SetProperty(&it, prop_value, StoreOrigin::kNamed,
375                                Just(ShouldThrow::kThrowOnError));
376        if (result.IsNothing()) return result;
377        if (stable) {
378          stable = from->map() == *map;
379          descriptors.PatchValue(map->instance_descriptors(isolate));
380        }
381      } else {
382        // No element indexes should get here or the exclusion check may
383        // yield false negatives for type mismatch.
384        if (excluded_properties != nullptr &&
385            HasExcludedProperty(excluded_properties, next_key)) {
386          continue;
387        }
388
389        // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
390        // This is an OWN lookup, so constructing a named-mode LookupIterator
391        // from {next_key} is safe.
392        LookupIterator it(isolate, target, next_key, LookupIterator::OWN);
393        CHECK(JSObject::CreateDataProperty(&it, prop_value, Just(kThrowOnError))
394                  .FromJust());
395      }
396    }
397    if (mode == PropertiesEnumerationMode::kEnumerationOrder) {
398      if (process_symbol_only || !has_symbol) {
399        return Just(true);
400      }
401      if (has_symbol) {
402        process_symbol_only = true;
403      }
404    } else {
405      DCHECK_EQ(mode, PropertiesEnumerationMode::kPropertyAdditionOrder);
406      return Just(true);
407    }
408  }
409  UNREACHABLE();
410}
411}  // namespace
412
413// static
414Maybe<bool> JSReceiver::SetOrCopyDataProperties(
415    Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
416    PropertiesEnumerationMode mode,
417    const base::ScopedVector<Handle<Object>>* excluded_properties,
418    bool use_set) {
419  Maybe<bool> fast_assign =
420      FastAssign(target, source, mode, excluded_properties, use_set);
421  if (fast_assign.IsNothing()) return Nothing<bool>();
422  if (fast_assign.FromJust()) return Just(true);
423
424  Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
425
426  // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
427  Handle<FixedArray> keys;
428  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
429      isolate, keys,
430      KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
431                              GetKeysConversion::kKeepNumbers),
432      Nothing<bool>());
433
434  if (!from->HasFastProperties() && target->HasFastProperties() &&
435      !target->IsJSGlobalProxy()) {
436    // JSProxy is always in slow-mode.
437    DCHECK(!target->IsJSProxy());
438    // Convert to slow properties if we're guaranteed to overflow the number of
439    // descriptors.
440    int source_length;
441    if (from->IsJSGlobalObject()) {
442      source_length = JSGlobalObject::cast(*from)
443                          .global_dictionary(kAcquireLoad)
444                          .NumberOfEnumerableProperties();
445    } else if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
446      source_length =
447          from->property_dictionary_swiss().NumberOfEnumerableProperties();
448    } else {
449      source_length =
450          from->property_dictionary().NumberOfEnumerableProperties();
451    }
452    if (source_length > kMaxNumberOfDescriptors) {
453      JSObject::NormalizeProperties(isolate, Handle<JSObject>::cast(target),
454                                    CLEAR_INOBJECT_PROPERTIES, source_length,
455                                    "Copying data properties");
456    }
457  }
458
459  // 4. Repeat for each element nextKey of keys in List order,
460  for (int i = 0; i < keys->length(); ++i) {
461    Handle<Object> next_key(keys->get(i), isolate);
462    if (excluded_properties != nullptr &&
463        HasExcludedProperty(excluded_properties, next_key)) {
464      continue;
465    }
466
467    // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
468    PropertyDescriptor desc;
469    Maybe<bool> found =
470        JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
471    if (found.IsNothing()) return Nothing<bool>();
472    // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
473    if (found.FromJust() && desc.enumerable()) {
474      // 4a ii 1. Let propValue be ? Get(from, nextKey).
475      Handle<Object> prop_value;
476      ASSIGN_RETURN_ON_EXCEPTION_VALUE(
477          isolate, prop_value,
478          Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
479
480      if (use_set) {
481        // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
482        Handle<Object> status;
483        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
484            isolate, status,
485            Runtime::SetObjectProperty(isolate, target, next_key, prop_value,
486                                       StoreOrigin::kMaybeKeyed,
487                                       Just(ShouldThrow::kThrowOnError)),
488            Nothing<bool>());
489      } else {
490        // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
491        PropertyKey key(isolate, next_key);
492        LookupIterator it(isolate, target, key, LookupIterator::OWN);
493        CHECK(JSObject::CreateDataProperty(&it, prop_value, Just(kThrowOnError))
494                  .FromJust());
495      }
496    }
497  }
498
499  return Just(true);
500}
501
502String JSReceiver::class_name() {
503  ReadOnlyRoots roots = GetReadOnlyRoots();
504  if (IsFunction()) return roots.Function_string();
505  if (IsJSArgumentsObject()) return roots.Arguments_string();
506  if (IsJSArray()) return roots.Array_string();
507  if (IsJSArrayBuffer()) {
508    if (JSArrayBuffer::cast(*this).is_shared()) {
509      return roots.SharedArrayBuffer_string();
510    }
511    return roots.ArrayBuffer_string();
512  }
513  if (IsJSArrayIterator()) return roots.ArrayIterator_string();
514  if (IsJSDate()) return roots.Date_string();
515  if (IsJSError()) return roots.Error_string();
516  if (IsJSGeneratorObject()) return roots.Generator_string();
517  if (IsJSMap()) return roots.Map_string();
518  if (IsJSMapIterator()) return roots.MapIterator_string();
519  if (IsJSProxy()) {
520    return map().is_callable() ? roots.Function_string()
521                               : roots.Object_string();
522  }
523  if (IsJSRegExp()) return roots.RegExp_string();
524  if (IsJSSet()) return roots.Set_string();
525  if (IsJSSetIterator()) return roots.SetIterator_string();
526  if (IsJSTypedArray()) {
527#define SWITCH_KIND(Type, type, TYPE, ctype)      \
528  if (map().elements_kind() == TYPE##_ELEMENTS) { \
529    return roots.Type##Array_string();            \
530  }
531    TYPED_ARRAYS(SWITCH_KIND)
532#undef SWITCH_KIND
533  }
534  if (IsJSPrimitiveWrapper()) {
535    Object value = JSPrimitiveWrapper::cast(*this).value();
536    if (value.IsBoolean()) return roots.Boolean_string();
537    if (value.IsString()) return roots.String_string();
538    if (value.IsNumber()) return roots.Number_string();
539    if (value.IsBigInt()) return roots.BigInt_string();
540    if (value.IsSymbol()) return roots.Symbol_string();
541    if (value.IsScript()) return roots.Script_string();
542    UNREACHABLE();
543  }
544  if (IsJSWeakMap()) return roots.WeakMap_string();
545  if (IsJSWeakSet()) return roots.WeakSet_string();
546  if (IsJSGlobalProxy()) return roots.global_string();
547
548  return roots.Object_string();
549}
550
551namespace {
552std::pair<MaybeHandle<JSFunction>, Handle<String>> GetConstructorHelper(
553    Isolate* isolate, Handle<JSReceiver> receiver) {
554  // If the object was instantiated simply with base == new.target, the
555  // constructor on the map provides the most accurate name.
556  // Don't provide the info for prototypes, since their constructors are
557  // reclaimed and replaced by Object in OptimizeAsPrototype.
558  if (!receiver->IsJSProxy() && receiver->map().new_target_is_base() &&
559      !receiver->map().is_prototype_map()) {
560    Handle<Object> maybe_constructor(receiver->map().GetConstructor(), isolate);
561    if (maybe_constructor->IsJSFunction()) {
562      Handle<JSFunction> constructor =
563          Handle<JSFunction>::cast(maybe_constructor);
564      Handle<String> name =
565          SharedFunctionInfo::DebugName(handle(constructor->shared(), isolate));
566      if (name->length() != 0 &&
567          !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
568        return std::make_pair(constructor, name);
569      }
570    }
571  }
572
573  for (PrototypeIterator it(isolate, receiver, kStartAtReceiver); !it.IsAtEnd();
574       it.AdvanceIgnoringProxies()) {
575    auto current = PrototypeIterator::GetCurrent<JSReceiver>(it);
576
577    LookupIterator it_to_string_tag(
578        isolate, receiver, isolate->factory()->to_string_tag_symbol(), current,
579        LookupIterator::OWN_SKIP_INTERCEPTOR);
580    auto maybe_to_string_tag = JSReceiver::GetDataProperty(
581        &it_to_string_tag, AllocationPolicy::kAllocationDisallowed);
582    if (maybe_to_string_tag->IsString()) {
583      return std::make_pair(MaybeHandle<JSFunction>(),
584                            Handle<String>::cast(maybe_to_string_tag));
585    }
586
587    // Consider the following example:
588    //
589    //   function A() {}
590    //   function B() {}
591    //   B.prototype = new A();
592    //   B.prototype.constructor = B;
593    //
594    // The constructor name for `B.prototype` must yield "A", so we don't take
595    // "constructor" into account for the receiver itself, but only starting
596    // on the prototype chain.
597    if (!receiver.is_identical_to(current)) {
598      LookupIterator it_constructor(
599          isolate, receiver, isolate->factory()->constructor_string(), current,
600          LookupIterator::OWN_SKIP_INTERCEPTOR);
601      auto maybe_constructor = JSReceiver::GetDataProperty(
602          &it_constructor, AllocationPolicy::kAllocationDisallowed);
603      if (maybe_constructor->IsJSFunction()) {
604        auto constructor = Handle<JSFunction>::cast(maybe_constructor);
605        auto name = SharedFunctionInfo::DebugName(
606            handle(constructor->shared(), isolate));
607
608        if (name->length() != 0 &&
609            !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
610          return std::make_pair(constructor, name);
611        }
612      }
613    }
614  }
615
616  return std::make_pair(MaybeHandle<JSFunction>(),
617                        handle(receiver->class_name(), isolate));
618}
619}  // anonymous namespace
620
621// static
622MaybeHandle<JSFunction> JSReceiver::GetConstructor(
623    Isolate* isolate, Handle<JSReceiver> receiver) {
624  return GetConstructorHelper(isolate, receiver).first;
625}
626
627// static
628Handle<String> JSReceiver::GetConstructorName(Isolate* isolate,
629                                              Handle<JSReceiver> receiver) {
630  return GetConstructorHelper(isolate, receiver).second;
631}
632
633MaybeHandle<NativeContext> JSReceiver::GetCreationContext() {
634  JSReceiver receiver = *this;
635  // Externals are JSObjects with null as a constructor.
636  DCHECK(!receiver.IsJSExternalObject());
637  Object constructor = receiver.map().GetConstructor();
638  JSFunction function;
639  if (constructor.IsJSFunction()) {
640    function = JSFunction::cast(constructor);
641  } else if (constructor.IsFunctionTemplateInfo()) {
642    // Remote objects don't have a creation context.
643    return MaybeHandle<NativeContext>();
644  } else if (receiver.IsJSGeneratorObject()) {
645    function = JSGeneratorObject::cast(receiver).function();
646  } else if (receiver.IsJSFunction()) {
647    function = JSFunction::cast(receiver);
648  } else {
649    return MaybeHandle<NativeContext>();
650  }
651
652  return function.has_context()
653             ? Handle<NativeContext>(function.native_context(),
654                                     receiver.GetIsolate())
655             : MaybeHandle<NativeContext>();
656}
657
658// static
659MaybeHandle<NativeContext> JSReceiver::GetFunctionRealm(
660    Handle<JSReceiver> receiver) {
661  Isolate* isolate = receiver->GetIsolate();
662  // This is implemented as a loop because it's possible to construct very
663  // long chains of bound functions or proxies where a recursive implementation
664  // would run out of stack space.
665  DisallowGarbageCollection no_gc;
666  JSReceiver current = *receiver;
667  do {
668    DCHECK(current.map().is_constructor());
669    if (current.IsJSProxy()) {
670      JSProxy proxy = JSProxy::cast(current);
671      if (proxy.IsRevoked()) {
672        AllowGarbageCollection allow_allocating_errors;
673        THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyRevoked),
674                        NativeContext);
675      }
676      current = JSReceiver::cast(proxy.target());
677      continue;
678    }
679    if (current.IsJSFunction()) {
680      JSFunction function = JSFunction::cast(current);
681      return handle(function.native_context(), isolate);
682    }
683    if (current.IsJSBoundFunction()) {
684      JSBoundFunction function = JSBoundFunction::cast(current);
685      current = function.bound_target_function();
686      continue;
687    }
688    if (current.IsJSWrappedFunction()) {
689      JSWrappedFunction function = JSWrappedFunction::cast(current);
690      current = function.wrapped_target_function();
691      continue;
692    }
693    JSObject object = JSObject::cast(current);
694    DCHECK(!object.IsJSFunction());
695    return object.GetCreationContext();
696  } while (true);
697}
698
699// static
700MaybeHandle<NativeContext> JSReceiver::GetContextForMicrotask(
701    Handle<JSReceiver> receiver) {
702  Isolate* isolate = receiver->GetIsolate();
703  while (receiver->IsJSBoundFunction() || receiver->IsJSProxy()) {
704    if (receiver->IsJSBoundFunction()) {
705      receiver = handle(
706          Handle<JSBoundFunction>::cast(receiver)->bound_target_function(),
707          isolate);
708    } else {
709      DCHECK(receiver->IsJSProxy());
710      Handle<Object> target(Handle<JSProxy>::cast(receiver)->target(), isolate);
711      if (!target->IsJSReceiver()) return MaybeHandle<NativeContext>();
712      receiver = Handle<JSReceiver>::cast(target);
713    }
714  }
715
716  if (!receiver->IsJSFunction()) return MaybeHandle<NativeContext>();
717  return handle(Handle<JSFunction>::cast(receiver)->native_context(), isolate);
718}
719
720Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
721    LookupIterator* it) {
722  for (; it->IsFound(); it->Next()) {
723    switch (it->state()) {
724      case LookupIterator::NOT_FOUND:
725      case LookupIterator::TRANSITION:
726        UNREACHABLE();
727      case LookupIterator::JSPROXY:
728        return JSProxy::GetPropertyAttributes(it);
729      case LookupIterator::INTERCEPTOR: {
730        Maybe<PropertyAttributes> result =
731            JSObject::GetPropertyAttributesWithInterceptor(it);
732        if (result.IsNothing()) return result;
733        if (result.FromJust() != ABSENT) return result;
734        break;
735      }
736      case LookupIterator::ACCESS_CHECK:
737        if (it->HasAccess()) break;
738        return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
739      case LookupIterator::INTEGER_INDEXED_EXOTIC:
740        return Just(ABSENT);
741      case LookupIterator::ACCESSOR:
742        if (it->GetHolder<Object>()->IsJSModuleNamespace()) {
743          return JSModuleNamespace::GetPropertyAttributes(it);
744        } else {
745          return Just(it->property_attributes());
746        }
747      case LookupIterator::DATA:
748        return Just(it->property_attributes());
749    }
750  }
751  return Just(ABSENT);
752}
753
754namespace {
755
756Object SetHashAndUpdateProperties(HeapObject properties, int hash) {
757  DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
758  DCHECK(PropertyArray::HashField::is_valid(hash));
759
760  ReadOnlyRoots roots = properties.GetReadOnlyRoots();
761  if (properties == roots.empty_fixed_array() ||
762      properties == roots.empty_property_array() ||
763      properties == roots.empty_property_dictionary() ||
764      properties == roots.empty_swiss_property_dictionary()) {
765    return Smi::FromInt(hash);
766  }
767
768  if (properties.IsPropertyArray()) {
769    PropertyArray::cast(properties).SetHash(hash);
770    DCHECK_LT(0, PropertyArray::cast(properties).length());
771    return properties;
772  }
773
774  if (properties.IsGlobalDictionary()) {
775    GlobalDictionary::cast(properties).SetHash(hash);
776    return properties;
777  }
778
779  if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
780    DCHECK(properties.IsSwissNameDictionary());
781    SwissNameDictionary::cast(properties).SetHash(hash);
782  } else {
783    DCHECK(properties.IsNameDictionary());
784    NameDictionary::cast(properties).SetHash(hash);
785  }
786  return properties;
787}
788
789int GetIdentityHashHelper(JSReceiver object) {
790  DisallowGarbageCollection no_gc;
791  Object properties = object.raw_properties_or_hash();
792  if (properties.IsSmi()) {
793    return Smi::ToInt(properties);
794  }
795
796  if (properties.IsPropertyArray()) {
797    return PropertyArray::cast(properties).Hash();
798  }
799  if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL &&
800      properties.IsSwissNameDictionary()) {
801    return SwissNameDictionary::cast(properties).Hash();
802  }
803
804  if (properties.IsNameDictionary()) {
805    DCHECK(!V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL);
806    return NameDictionary::cast(properties).Hash();
807  }
808
809  if (properties.IsGlobalDictionary()) {
810    return GlobalDictionary::cast(properties).Hash();
811  }
812
813#ifdef DEBUG
814  ReadOnlyRoots roots = object.GetReadOnlyRoots();
815  DCHECK(properties == roots.empty_fixed_array() ||
816         properties == roots.empty_property_dictionary() ||
817         properties == roots.empty_swiss_property_dictionary());
818#endif
819
820  return PropertyArray::kNoHashSentinel;
821}
822}  // namespace
823
824void JSReceiver::SetIdentityHash(int hash) {
825  DisallowGarbageCollection no_gc;
826  DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
827  DCHECK(PropertyArray::HashField::is_valid(hash));
828
829  HeapObject existing_properties = HeapObject::cast(raw_properties_or_hash());
830  Object new_properties = SetHashAndUpdateProperties(existing_properties, hash);
831  set_raw_properties_or_hash(new_properties, kRelaxedStore);
832}
833
834void JSReceiver::SetProperties(HeapObject properties) {
835  DCHECK_IMPLIES(properties.IsPropertyArray() &&
836                     PropertyArray::cast(properties).length() == 0,
837                 properties == GetReadOnlyRoots().empty_property_array());
838  DisallowGarbageCollection no_gc;
839  int hash = GetIdentityHashHelper(*this);
840  Object new_properties = properties;
841
842  // TODO(cbruni): Make GetIdentityHashHelper return a bool so that we
843  // don't have to manually compare against kNoHashSentinel.
844  if (hash != PropertyArray::kNoHashSentinel) {
845    new_properties = SetHashAndUpdateProperties(properties, hash);
846  }
847
848  set_raw_properties_or_hash(new_properties, kRelaxedStore);
849}
850
851Object JSReceiver::GetIdentityHash() {
852  DisallowGarbageCollection no_gc;
853
854  int hash = GetIdentityHashHelper(*this);
855  if (hash == PropertyArray::kNoHashSentinel) {
856    return GetReadOnlyRoots().undefined_value();
857  }
858
859  return Smi::FromInt(hash);
860}
861
862// static
863Smi JSReceiver::CreateIdentityHash(Isolate* isolate, JSReceiver key) {
864  DisallowGarbageCollection no_gc;
865  int hash = isolate->GenerateIdentityHash(PropertyArray::HashField::kMax);
866  DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
867
868  key.SetIdentityHash(hash);
869  return Smi::FromInt(hash);
870}
871
872Smi JSReceiver::GetOrCreateIdentityHash(Isolate* isolate) {
873  DisallowGarbageCollection no_gc;
874
875  int hash = GetIdentityHashHelper(*this);
876  if (hash != PropertyArray::kNoHashSentinel) {
877    return Smi::FromInt(hash);
878  }
879
880  return JSReceiver::CreateIdentityHash(isolate, *this);
881}
882
883void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
884                                          InternalIndex entry) {
885  DCHECK(!object->HasFastProperties());
886  Isolate* isolate = object->GetIsolate();
887  DCHECK(entry.is_found());
888
889  if (object->IsJSGlobalObject()) {
890    // If we have a global object, invalidate the cell and remove it from the
891    // global object's dictionary.
892    Handle<GlobalDictionary> dictionary(
893        JSGlobalObject::cast(*object).global_dictionary(kAcquireLoad), isolate);
894
895    Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
896
897    Handle<GlobalDictionary> new_dictionary =
898        GlobalDictionary::DeleteEntry(isolate, dictionary, entry);
899    JSGlobalObject::cast(*object).set_global_dictionary(*new_dictionary,
900                                                        kReleaseStore);
901
902    cell->ClearAndInvalidate(ReadOnlyRoots(isolate));
903  } else {
904    if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
905      Handle<SwissNameDictionary> dictionary(
906          object->property_dictionary_swiss(), isolate);
907
908      dictionary = SwissNameDictionary::DeleteEntry(isolate, dictionary, entry);
909      object->SetProperties(*dictionary);
910    } else {
911      Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
912
913      dictionary = NameDictionary::DeleteEntry(isolate, dictionary, entry);
914      object->SetProperties(*dictionary);
915    }
916  }
917  if (object->map().is_prototype_map()) {
918    // Invalidate prototype validity cell as this may invalidate transitioning
919    // store IC handlers.
920    JSObject::InvalidatePrototypeChains(object->map());
921  }
922}
923
924Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
925                                       LanguageMode language_mode) {
926  it->UpdateProtector();
927
928  Isolate* isolate = it->isolate();
929
930  if (it->state() == LookupIterator::JSPROXY) {
931    return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
932                                            it->GetName(), language_mode);
933  }
934
935  if (it->GetReceiver()->IsJSProxy()) {
936    if (it->state() != LookupIterator::NOT_FOUND) {
937      DCHECK_EQ(LookupIterator::DATA, it->state());
938      DCHECK(it->name()->IsPrivate());
939      it->Delete();
940    }
941    return Just(true);
942  }
943  Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
944
945  for (; it->IsFound(); it->Next()) {
946    switch (it->state()) {
947      case LookupIterator::JSPROXY:
948      case LookupIterator::NOT_FOUND:
949      case LookupIterator::TRANSITION:
950        UNREACHABLE();
951      case LookupIterator::ACCESS_CHECK:
952        if (it->HasAccess()) break;
953        isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
954        RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
955        return Just(false);
956      case LookupIterator::INTERCEPTOR: {
957        ShouldThrow should_throw =
958            is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
959        Maybe<bool> result =
960            JSObject::DeletePropertyWithInterceptor(it, should_throw);
961        // An exception was thrown in the interceptor. Propagate.
962        if (isolate->has_pending_exception()) return Nothing<bool>();
963        // Delete with interceptor succeeded. Return result.
964        // TODO(neis): In strict mode, we should probably throw if the
965        // interceptor returns false.
966        if (result.IsJust()) return result;
967        break;
968      }
969      case LookupIterator::INTEGER_INDEXED_EXOTIC:
970        return Just(true);
971      case LookupIterator::DATA:
972      case LookupIterator::ACCESSOR: {
973        Handle<JSObject> holder = it->GetHolder<JSObject>();
974        if (!it->IsConfigurable() ||
975            (holder->IsJSTypedArray() && it->IsElement(*holder))) {
976          // Fail if the property is not configurable if the property is a
977          // TypedArray element.
978          if (is_strict(language_mode)) {
979            isolate->Throw(*isolate->factory()->NewTypeError(
980                MessageTemplate::kStrictDeleteProperty, it->GetName(),
981                receiver));
982            return Nothing<bool>();
983          }
984          return Just(false);
985        }
986
987        it->Delete();
988
989        return Just(true);
990      }
991    }
992  }
993
994  return Just(true);
995}
996
997Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
998                                      LanguageMode language_mode) {
999  LookupIterator it(object->GetIsolate(), object, index, object,
1000                    LookupIterator::OWN);
1001  return DeleteProperty(&it, language_mode);
1002}
1003
1004Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
1005                                       Handle<Name> name,
1006                                       LanguageMode language_mode) {
1007  LookupIterator it(object->GetIsolate(), object, name, object,
1008                    LookupIterator::OWN);
1009  return DeleteProperty(&it, language_mode);
1010}
1011
1012Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
1013                                                Handle<Name> name,
1014                                                LanguageMode language_mode) {
1015  Isolate* isolate = object->GetIsolate();
1016  PropertyKey key(isolate, name);
1017  LookupIterator it(isolate, object, key, object, LookupIterator::OWN);
1018  return DeleteProperty(&it, language_mode);
1019}
1020
1021// ES6 19.1.2.4
1022// static
1023Object JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
1024                                  Handle<Object> key,
1025                                  Handle<Object> attributes) {
1026  // 1. If Type(O) is not Object, throw a TypeError exception.
1027  if (!object->IsJSReceiver()) {
1028    Handle<String> fun_name =
1029        isolate->factory()->InternalizeUtf8String("Object.defineProperty");
1030    THROW_NEW_ERROR_RETURN_FAILURE(
1031        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
1032  }
1033  // 2. Let key be ToPropertyKey(P).
1034  // 3. ReturnIfAbrupt(key).
1035  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key,
1036                                     Object::ToPropertyKey(isolate, key));
1037  // 4. Let desc be ToPropertyDescriptor(Attributes).
1038  // 5. ReturnIfAbrupt(desc).
1039  PropertyDescriptor desc;
1040  if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
1041    return ReadOnlyRoots(isolate).exception();
1042  }
1043  // 6. Let success be DefinePropertyOrThrow(O,key, desc).
1044  Maybe<bool> success =
1045      DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object), key, &desc,
1046                        Just(kThrowOnError));
1047  // 7. ReturnIfAbrupt(success).
1048  MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
1049  CHECK(success.FromJust());
1050  // 8. Return O.
1051  return *object;
1052}
1053
1054// ES6 19.1.2.3.1
1055// static
1056MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
1057                                                 Handle<Object> object,
1058                                                 Handle<Object> properties) {
1059  // 1. If Type(O) is not Object, throw a TypeError exception.
1060  if (!object->IsJSReceiver()) {
1061    Handle<String> fun_name =
1062        isolate->factory()->InternalizeUtf8String("Object.defineProperties");
1063    THROW_NEW_ERROR(isolate,
1064                    NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
1065                    Object);
1066  }
1067  // 2. Let props be ToObject(Properties).
1068  // 3. ReturnIfAbrupt(props).
1069  Handle<JSReceiver> props;
1070  ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
1071                             Object::ToObject(isolate, properties), Object);
1072
1073  // 4. Let keys be props.[[OwnPropertyKeys]]().
1074  // 5. ReturnIfAbrupt(keys).
1075  Handle<FixedArray> keys;
1076  ASSIGN_RETURN_ON_EXCEPTION(
1077      isolate, keys,
1078      KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
1079                              ALL_PROPERTIES),
1080      Object);
1081  // 6. Let descriptors be an empty List.
1082  int capacity = keys->length();
1083  std::vector<PropertyDescriptor> descriptors(capacity);
1084  size_t descriptors_index = 0;
1085  // 7. Repeat for each element nextKey of keys in List order,
1086  for (int i = 0; i < keys->length(); ++i) {
1087    Handle<Object> next_key(keys->get(i), isolate);
1088    // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
1089    // 7b. ReturnIfAbrupt(propDesc).
1090    PropertyKey key(isolate, next_key);
1091    LookupIterator it(isolate, props, key, LookupIterator::OWN);
1092    Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
1093    if (maybe.IsNothing()) return MaybeHandle<Object>();
1094    PropertyAttributes attrs = maybe.FromJust();
1095    // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
1096    if (attrs == ABSENT) continue;
1097    if (attrs & DONT_ENUM) continue;
1098    // 7c i. Let descObj be Get(props, nextKey).
1099    // 7c ii. ReturnIfAbrupt(descObj).
1100    Handle<Object> desc_obj;
1101    ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
1102                               Object);
1103    // 7c iii. Let desc be ToPropertyDescriptor(descObj).
1104    bool success = PropertyDescriptor::ToPropertyDescriptor(
1105        isolate, desc_obj, &descriptors[descriptors_index]);
1106    // 7c iv. ReturnIfAbrupt(desc).
1107    if (!success) return MaybeHandle<Object>();
1108    // 7c v. Append the pair (a two element List) consisting of nextKey and
1109    //       desc to the end of descriptors.
1110    descriptors[descriptors_index].set_name(next_key);
1111    descriptors_index++;
1112  }
1113  // 8. For each pair from descriptors in list order,
1114  for (size_t i = 0; i < descriptors_index; ++i) {
1115    PropertyDescriptor* desc = &descriptors[i];
1116    // 8a. Let P be the first element of pair.
1117    // 8b. Let desc be the second element of pair.
1118    // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
1119    Maybe<bool> status =
1120        DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
1121                          desc->name(), desc, Just(kThrowOnError));
1122    // 8d. ReturnIfAbrupt(status).
1123    if (status.IsNothing()) return MaybeHandle<Object>();
1124    CHECK(status.FromJust());
1125  }
1126  // 9. Return o.
1127  return object;
1128}
1129
1130// static
1131Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
1132                                          Handle<JSReceiver> object,
1133                                          Handle<Object> key,
1134                                          PropertyDescriptor* desc,
1135                                          Maybe<ShouldThrow> should_throw) {
1136  if (object->IsJSArray()) {
1137    return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
1138                                      key, desc, should_throw);
1139  }
1140  if (object->IsJSProxy()) {
1141    return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
1142                                      key, desc, should_throw);
1143  }
1144  if (object->IsJSTypedArray()) {
1145    return JSTypedArray::DefineOwnProperty(
1146        isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
1147  }
1148  if (object->IsJSModuleNamespace()) {
1149    return JSModuleNamespace::DefineOwnProperty(
1150        isolate, Handle<JSModuleNamespace>::cast(object), key, desc,
1151        should_throw);
1152  }
1153
1154  // OrdinaryDefineOwnProperty, by virtue of calling
1155  // DefineOwnPropertyIgnoreAttributes, can handle arguments
1156  // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
1157  return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
1158                                   desc, should_throw);
1159}
1160
1161// static
1162Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(
1163    Isolate* isolate, Handle<JSObject> object, Handle<Object> key,
1164    PropertyDescriptor* desc, Maybe<ShouldThrow> should_throw) {
1165  DCHECK(key->IsName() || key->IsNumber());  // |key| is a PropertyKey.
1166  PropertyKey lookup_key(isolate, key);
1167  return OrdinaryDefineOwnProperty(isolate, object, lookup_key, desc,
1168                                   should_throw);
1169}
1170
1171Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(
1172    Isolate* isolate, Handle<JSObject> object, const PropertyKey& key,
1173    PropertyDescriptor* desc, Maybe<ShouldThrow> should_throw) {
1174  LookupIterator it(isolate, object, key, LookupIterator::OWN);
1175
1176  // Deal with access checks first.
1177  if (it.state() == LookupIterator::ACCESS_CHECK) {
1178    if (!it.HasAccess()) {
1179      isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
1180      RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1181      return Just(true);
1182    }
1183    it.Next();
1184  }
1185
1186  return OrdinaryDefineOwnProperty(&it, desc, should_throw);
1187}
1188
1189namespace {
1190
1191MaybeHandle<Object> GetPropertyWithInterceptorInternal(
1192    LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
1193  *done = false;
1194  Isolate* isolate = it->isolate();
1195  // Make sure that the top context does not change when doing callbacks or
1196  // interceptor calls.
1197  AssertNoContextChange ncc(isolate);
1198
1199  if (interceptor->getter().IsUndefined(isolate)) {
1200    return isolate->factory()->undefined_value();
1201  }
1202
1203  Handle<JSObject> holder = it->GetHolder<JSObject>();
1204  Handle<Object> result;
1205  Handle<Object> receiver = it->GetReceiver();
1206  if (!receiver->IsJSReceiver()) {
1207    ASSIGN_RETURN_ON_EXCEPTION(
1208        isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
1209  }
1210  PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1211                                 *holder, Just(kDontThrow));
1212
1213  if (it->IsElement(*holder)) {
1214    result = args.CallIndexedGetter(interceptor, it->array_index());
1215  } else {
1216    result = args.CallNamedGetter(interceptor, it->name());
1217  }
1218
1219  RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1220  if (result.is_null()) return isolate->factory()->undefined_value();
1221  *done = true;
1222  // Rebox handle before return
1223  return handle(*result, isolate);
1224}
1225
1226Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
1227    LookupIterator* it, Handle<InterceptorInfo> interceptor) {
1228  Isolate* isolate = it->isolate();
1229  // Make sure that the top context does not change when doing
1230  // callbacks or interceptor calls.
1231  AssertNoContextChange ncc(isolate);
1232  HandleScope scope(isolate);
1233
1234  Handle<JSObject> holder = it->GetHolder<JSObject>();
1235  DCHECK_IMPLIES(!it->IsElement(*holder) && it->name()->IsSymbol(),
1236                 interceptor->can_intercept_symbols());
1237  Handle<Object> receiver = it->GetReceiver();
1238  if (!receiver->IsJSReceiver()) {
1239    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1240                                     Object::ConvertReceiver(isolate, receiver),
1241                                     Nothing<PropertyAttributes>());
1242  }
1243  PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1244                                 *holder, Just(kDontThrow));
1245  if (!interceptor->query().IsUndefined(isolate)) {
1246    Handle<Object> result;
1247    if (it->IsElement(*holder)) {
1248      result = args.CallIndexedQuery(interceptor, it->array_index());
1249    } else {
1250      result = args.CallNamedQuery(interceptor, it->name());
1251    }
1252    if (!result.is_null()) {
1253      int32_t value;
1254      CHECK(result->ToInt32(&value));
1255      DCHECK_IMPLIES((value & ~PropertyAttributes::ALL_ATTRIBUTES_MASK) != 0,
1256                     value == PropertyAttributes::ABSENT);
1257      return Just(static_cast<PropertyAttributes>(value));
1258    }
1259  } else if (!interceptor->getter().IsUndefined(isolate)) {
1260    // TODO(verwaest): Use GetPropertyWithInterceptor?
1261    Handle<Object> result;
1262    if (it->IsElement(*holder)) {
1263      result = args.CallIndexedGetter(interceptor, it->array_index());
1264    } else {
1265      result = args.CallNamedGetter(interceptor, it->name());
1266    }
1267    if (!result.is_null()) return Just(DONT_ENUM);
1268  }
1269
1270  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
1271  return Just(ABSENT);
1272}
1273
1274Maybe<bool> SetPropertyWithInterceptorInternal(
1275    LookupIterator* it, Handle<InterceptorInfo> interceptor,
1276    Maybe<ShouldThrow> should_throw, Handle<Object> value) {
1277  Isolate* isolate = it->isolate();
1278  // Make sure that the top context does not change when doing callbacks or
1279  // interceptor calls.
1280  AssertNoContextChange ncc(isolate);
1281
1282  if (interceptor->setter().IsUndefined(isolate)) return Just(false);
1283
1284  Handle<JSObject> holder = it->GetHolder<JSObject>();
1285  bool result;
1286  Handle<Object> receiver = it->GetReceiver();
1287  if (!receiver->IsJSReceiver()) {
1288    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1289                                     Object::ConvertReceiver(isolate, receiver),
1290                                     Nothing<bool>());
1291  }
1292  PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1293                                 *holder, should_throw);
1294
1295  if (it->IsElement(*holder)) {
1296    // TODO(neis): In the future, we may want to actually return the
1297    // interceptor's result, which then should be a boolean.
1298    result = !args.CallIndexedSetter(interceptor, it->array_index(), value)
1299                  .is_null();
1300  } else {
1301    result = !args.CallNamedSetter(interceptor, it->name(), value).is_null();
1302  }
1303
1304  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1305  return Just(result);
1306}
1307
1308Maybe<bool> DefinePropertyWithInterceptorInternal(
1309    LookupIterator* it, Handle<InterceptorInfo> interceptor,
1310    Maybe<ShouldThrow> should_throw, PropertyDescriptor* desc) {
1311  Isolate* isolate = it->isolate();
1312  // Make sure that the top context does not change when doing callbacks or
1313  // interceptor calls.
1314  AssertNoContextChange ncc(isolate);
1315
1316  if (interceptor->definer().IsUndefined(isolate)) return Just(false);
1317
1318  Handle<JSObject> holder = it->GetHolder<JSObject>();
1319  bool result;
1320  Handle<Object> receiver = it->GetReceiver();
1321  if (!receiver->IsJSReceiver()) {
1322    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1323                                     Object::ConvertReceiver(isolate, receiver),
1324                                     Nothing<bool>());
1325  }
1326  PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1327                                 *holder, should_throw);
1328
1329  std::unique_ptr<v8::PropertyDescriptor> descriptor(
1330      new v8::PropertyDescriptor());
1331  if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
1332    descriptor.reset(new v8::PropertyDescriptor(
1333        v8::Utils::ToLocal(desc->get()), v8::Utils::ToLocal(desc->set())));
1334  } else if (PropertyDescriptor::IsDataDescriptor(desc)) {
1335    if (desc->has_writable()) {
1336      descriptor.reset(new v8::PropertyDescriptor(
1337          v8::Utils::ToLocal(desc->value()), desc->writable()));
1338    } else {
1339      descriptor.reset(
1340          new v8::PropertyDescriptor(v8::Utils::ToLocal(desc->value())));
1341    }
1342  }
1343  if (desc->has_enumerable()) {
1344    descriptor->set_enumerable(desc->enumerable());
1345  }
1346  if (desc->has_configurable()) {
1347    descriptor->set_configurable(desc->configurable());
1348  }
1349
1350  if (it->IsElement(*holder)) {
1351    result =
1352        !args.CallIndexedDefiner(interceptor, it->array_index(), *descriptor)
1353             .is_null();
1354  } else {
1355    result =
1356        !args.CallNamedDefiner(interceptor, it->name(), *descriptor).is_null();
1357  }
1358
1359  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1360  return Just(result);
1361}
1362
1363}  // namespace
1364
1365// ES6 9.1.6.1
1366// static
1367Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(
1368    LookupIterator* it, PropertyDescriptor* desc,
1369    Maybe<ShouldThrow> should_throw) {
1370  Isolate* isolate = it->isolate();
1371  // 1. Let current be O.[[GetOwnProperty]](P).
1372  // 2. ReturnIfAbrupt(current).
1373  PropertyDescriptor current;
1374  MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>());
1375
1376  it->Restart();
1377  // Handle interceptor
1378  for (; it->IsFound(); it->Next()) {
1379    if (it->state() == LookupIterator::INTERCEPTOR) {
1380      if (it->HolderIsReceiverOrHiddenPrototype()) {
1381        Maybe<bool> result = DefinePropertyWithInterceptorInternal(
1382            it, it->GetInterceptor(), should_throw, desc);
1383        if (result.IsNothing() || result.FromJust()) {
1384          return result;
1385        }
1386      }
1387    }
1388  }
1389
1390  // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
1391  // the iterator every time. Currently, the reasons why we need it are:
1392  // - handle interceptors correctly
1393  // - handle accessors correctly (which might change the holder's map)
1394  it->Restart();
1395  // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
1396  Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
1397  bool extensible = JSObject::IsExtensible(object);
1398
1399  return ValidateAndApplyPropertyDescriptor(
1400      isolate, it, extensible, desc, &current, should_throw, Handle<Name>());
1401}
1402
1403// ES6 9.1.6.2
1404// static
1405Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
1406    Isolate* isolate, bool extensible, PropertyDescriptor* desc,
1407    PropertyDescriptor* current, Handle<Name> property_name,
1408    Maybe<ShouldThrow> should_throw) {
1409  // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
1410  //    Extensible, Desc, Current).
1411  return ValidateAndApplyPropertyDescriptor(
1412      isolate, nullptr, extensible, desc, current, should_throw, property_name);
1413}
1414
1415// https://tc39.es/ecma262/#sec-validateandapplypropertydescriptor
1416// static
1417Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
1418    Isolate* isolate, LookupIterator* it, bool extensible,
1419    PropertyDescriptor* desc, PropertyDescriptor* current,
1420    Maybe<ShouldThrow> should_throw, Handle<Name> property_name) {
1421  // We either need a LookupIterator, or a property name.
1422  DCHECK((it == nullptr) != property_name.is_null());
1423  Handle<JSObject> object;
1424  if (it != nullptr) object = Handle<JSObject>::cast(it->GetReceiver());
1425  bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
1426  bool desc_is_accessor_descriptor =
1427      PropertyDescriptor::IsAccessorDescriptor(desc);
1428  bool desc_is_generic_descriptor =
1429      PropertyDescriptor::IsGenericDescriptor(desc);
1430  // 1. (Assert)
1431  // 2. If current is undefined, then
1432  if (current->is_empty()) {
1433    // 2a. If extensible is false, return false.
1434    if (!extensible) {
1435      RETURN_FAILURE(
1436          isolate, GetShouldThrow(isolate, should_throw),
1437          NewTypeError(MessageTemplate::kDefineDisallowed,
1438                       it != nullptr ? it->GetName() : property_name));
1439    }
1440    // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
1441    // (This is equivalent to !IsAccessorDescriptor(desc).)
1442    DCHECK_EQ(desc_is_generic_descriptor || desc_is_data_descriptor,
1443              !desc_is_accessor_descriptor);
1444    if (!desc_is_accessor_descriptor) {
1445      // 2c i. If O is not undefined, create an own data property named P of
1446      // object O whose [[Value]], [[Writable]], [[Enumerable]] and
1447      // [[Configurable]] attribute values are described by Desc. If the value
1448      // of an attribute field of Desc is absent, the attribute of the newly
1449      // created property is set to its default value.
1450      if (it != nullptr) {
1451        if (!desc->has_writable()) desc->set_writable(false);
1452        if (!desc->has_enumerable()) desc->set_enumerable(false);
1453        if (!desc->has_configurable()) desc->set_configurable(false);
1454        Handle<Object> value(
1455            desc->has_value()
1456                ? desc->value()
1457                : Handle<Object>::cast(isolate->factory()->undefined_value()));
1458        MaybeHandle<Object> result =
1459            JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
1460                                                        desc->ToAttributes());
1461        if (result.is_null()) return Nothing<bool>();
1462      }
1463    } else {
1464      // 2d. Else Desc must be an accessor Property Descriptor,
1465      DCHECK(desc_is_accessor_descriptor);
1466      // 2d i. If O is not undefined, create an own accessor property named P
1467      // of object O whose [[Get]], [[Set]], [[Enumerable]] and
1468      // [[Configurable]] attribute values are described by Desc. If the value
1469      // of an attribute field of Desc is absent, the attribute of the newly
1470      // created property is set to its default value.
1471      if (it != nullptr) {
1472        if (!desc->has_enumerable()) desc->set_enumerable(false);
1473        if (!desc->has_configurable()) desc->set_configurable(false);
1474        Handle<Object> getter(
1475            desc->has_get()
1476                ? desc->get()
1477                : Handle<Object>::cast(isolate->factory()->null_value()));
1478        Handle<Object> setter(
1479            desc->has_set()
1480                ? desc->set()
1481                : Handle<Object>::cast(isolate->factory()->null_value()));
1482        MaybeHandle<Object> result =
1483            JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
1484        if (result.is_null()) return Nothing<bool>();
1485      }
1486    }
1487    // 2e. Return true.
1488    return Just(true);
1489  }
1490  // 3. If every field in Desc is absent, return true. (This also has a shortcut
1491  // not in the spec: if every field value matches the current value, return.)
1492  if ((!desc->has_enumerable() ||
1493       desc->enumerable() == current->enumerable()) &&
1494      (!desc->has_configurable() ||
1495       desc->configurable() == current->configurable()) &&
1496      (!desc->has_value() ||
1497       (current->has_value() && current->value()->SameValue(*desc->value()))) &&
1498      (!desc->has_writable() ||
1499       (current->has_writable() && current->writable() == desc->writable())) &&
1500      (!desc->has_get() ||
1501       (current->has_get() && current->get()->SameValue(*desc->get()))) &&
1502      (!desc->has_set() ||
1503       (current->has_set() && current->set()->SameValue(*desc->set())))) {
1504    return Just(true);
1505  }
1506  // 4. If current.[[Configurable]] is false, then
1507  if (!current->configurable()) {
1508    // 4a. If Desc.[[Configurable]] is present and its value is true, return
1509    // false.
1510    if (desc->has_configurable() && desc->configurable()) {
1511      RETURN_FAILURE(
1512          isolate, GetShouldThrow(isolate, should_throw),
1513          NewTypeError(MessageTemplate::kRedefineDisallowed,
1514                       it != nullptr ? it->GetName() : property_name));
1515    }
1516    // 4b. If Desc.[[Enumerable]] is present and
1517    // ! SameValue(Desc.[[Enumerable]], current.[[Enumerable]]) is false, return
1518    // false.
1519    if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
1520      RETURN_FAILURE(
1521          isolate, GetShouldThrow(isolate, should_throw),
1522          NewTypeError(MessageTemplate::kRedefineDisallowed,
1523                       it != nullptr ? it->GetName() : property_name));
1524    }
1525  }
1526
1527  bool current_is_data_descriptor =
1528      PropertyDescriptor::IsDataDescriptor(current);
1529  // 5. If ! IsGenericDescriptor(Desc) is true, no further validation is
1530  // required.
1531  if (desc_is_generic_descriptor) {
1532    // Nothing to see here.
1533
1534    // 6. Else if ! SameValue(!IsDataDescriptor(current),
1535    // !IsDataDescriptor(Desc)) is false, the
1536  } else if (current_is_data_descriptor != desc_is_data_descriptor) {
1537    // 6a. If current.[[Configurable]] is false, return false.
1538    if (!current->configurable()) {
1539      RETURN_FAILURE(
1540          isolate, GetShouldThrow(isolate, should_throw),
1541          NewTypeError(MessageTemplate::kRedefineDisallowed,
1542                       it != nullptr ? it->GetName() : property_name));
1543    }
1544    // 6b. If IsDataDescriptor(current) is true, then:
1545    if (current_is_data_descriptor) {
1546      // 6b i. If O is not undefined, convert the property named P of object O
1547      // from a data property to an accessor property. Preserve the existing
1548      // values of the converted property's [[Configurable]] and [[Enumerable]]
1549      // attributes and set the rest of the property's attributes to their
1550      // default values.
1551      // --> Folded into step 9
1552    } else {
1553      // 6c i. If O is not undefined, convert the property named P of object O
1554      // from an accessor property to a data property. Preserve the existing
1555      // values of the converted property’s [[Configurable]] and [[Enumerable]]
1556      // attributes and set the rest of the property’s attributes to their
1557      // default values.
1558      // --> Folded into step 9
1559    }
1560
1561    // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
1562    // true, then:
1563  } else if (current_is_data_descriptor && desc_is_data_descriptor) {
1564    // 7a. If current.[[Configurable]] is false and current.[[Writable]] is
1565    // false, then
1566    if (!current->configurable() && !current->writable()) {
1567      // 7a i. If Desc.[[Writable]] is present and Desc.[[Writable]] is true,
1568      // return false.
1569      if (desc->has_writable() && desc->writable()) {
1570        RETURN_FAILURE(
1571            isolate, GetShouldThrow(isolate, should_throw),
1572            NewTypeError(MessageTemplate::kRedefineDisallowed,
1573                         it != nullptr ? it->GetName() : property_name));
1574      }
1575      // 7a ii. If Desc.[[Value]] is present and SameValue(Desc.[[Value]],
1576      // current.[[Value]]) is false, return false.
1577      if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
1578        RETURN_FAILURE(
1579            isolate, GetShouldThrow(isolate, should_throw),
1580            NewTypeError(MessageTemplate::kRedefineDisallowed,
1581                         it != nullptr ? it->GetName() : property_name));
1582      }
1583    }
1584  } else {
1585    // 8. Else,
1586    // 8a. Assert: ! IsAccessorDescriptor(current) and
1587    // ! IsAccessorDescriptor(Desc) are both true.
1588    DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
1589           desc_is_accessor_descriptor);
1590    // 8b. If current.[[Configurable]] is false, then:
1591    if (!current->configurable()) {
1592      // 8a i. If Desc.[[Set]] is present and SameValue(Desc.[[Set]],
1593      // current.[[Set]]) is false, return false.
1594      if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
1595        RETURN_FAILURE(
1596            isolate, GetShouldThrow(isolate, should_throw),
1597            NewTypeError(MessageTemplate::kRedefineDisallowed,
1598                         it != nullptr ? it->GetName() : property_name));
1599      }
1600      // 8a ii. If Desc.[[Get]] is present and SameValue(Desc.[[Get]],
1601      // current.[[Get]]) is false, return false.
1602      if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
1603        RETURN_FAILURE(
1604            isolate, GetShouldThrow(isolate, should_throw),
1605            NewTypeError(MessageTemplate::kRedefineDisallowed,
1606                         it != nullptr ? it->GetName() : property_name));
1607      }
1608    }
1609  }
1610
1611  // 9. If O is not undefined, then:
1612  if (it != nullptr) {
1613    // 9a. For each field of Desc that is present, set the corresponding
1614    // attribute of the property named P of object O to the value of the field.
1615    PropertyAttributes attrs = NONE;
1616
1617    if (desc->has_enumerable()) {
1618      attrs = static_cast<PropertyAttributes>(
1619          attrs | (desc->enumerable() ? NONE : DONT_ENUM));
1620    } else {
1621      attrs = static_cast<PropertyAttributes>(
1622          attrs | (current->enumerable() ? NONE : DONT_ENUM));
1623    }
1624    if (desc->has_configurable()) {
1625      attrs = static_cast<PropertyAttributes>(
1626          attrs | (desc->configurable() ? NONE : DONT_DELETE));
1627    } else {
1628      attrs = static_cast<PropertyAttributes>(
1629          attrs | (current->configurable() ? NONE : DONT_DELETE));
1630    }
1631    if (desc_is_data_descriptor ||
1632        (desc_is_generic_descriptor && current_is_data_descriptor)) {
1633      if (desc->has_writable()) {
1634        attrs = static_cast<PropertyAttributes>(
1635            attrs | (desc->writable() ? NONE : READ_ONLY));
1636      } else {
1637        attrs = static_cast<PropertyAttributes>(
1638            attrs | (current->writable() ? NONE : READ_ONLY));
1639      }
1640      Handle<Object> value(
1641          desc->has_value() ? desc->value()
1642                            : current->has_value()
1643                                  ? current->value()
1644                                  : Handle<Object>::cast(
1645                                        isolate->factory()->undefined_value()));
1646      return JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs,
1647                                                         should_throw);
1648    } else {
1649      DCHECK(desc_is_accessor_descriptor ||
1650             (desc_is_generic_descriptor &&
1651              PropertyDescriptor::IsAccessorDescriptor(current)));
1652      Handle<Object> getter(
1653          desc->has_get()
1654              ? desc->get()
1655              : current->has_get()
1656                    ? current->get()
1657                    : Handle<Object>::cast(isolate->factory()->null_value()));
1658      Handle<Object> setter(
1659          desc->has_set()
1660              ? desc->set()
1661              : current->has_set()
1662                    ? current->set()
1663                    : Handle<Object>::cast(isolate->factory()->null_value()));
1664      MaybeHandle<Object> result =
1665          JSObject::DefineAccessor(it, getter, setter, attrs);
1666      if (result.is_null()) return Nothing<bool>();
1667    }
1668  }
1669
1670  // 10. Return true.
1671  return Just(true);
1672}
1673
1674// static
1675Maybe<bool> JSReceiver::CreateDataProperty(Isolate* isolate,
1676                                           Handle<JSReceiver> object,
1677                                           Handle<Name> key,
1678                                           Handle<Object> value,
1679                                           Maybe<ShouldThrow> should_throw) {
1680  PropertyKey lookup_key(isolate, key);
1681  LookupIterator it(isolate, object, lookup_key, LookupIterator::OWN);
1682  return CreateDataProperty(&it, value, should_throw);
1683}
1684
1685// static
1686Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
1687                                           Handle<Object> value,
1688                                           Maybe<ShouldThrow> should_throw) {
1689  DCHECK(!it->check_prototype_chain());
1690  Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
1691  Isolate* isolate = receiver->GetIsolate();
1692
1693  if (receiver->IsJSObject()) {
1694    return JSObject::CreateDataProperty(it, value, should_throw);  // Shortcut.
1695  }
1696
1697  PropertyDescriptor new_desc;
1698  new_desc.set_value(value);
1699  new_desc.set_writable(true);
1700  new_desc.set_enumerable(true);
1701  new_desc.set_configurable(true);
1702
1703  return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
1704                                       &new_desc, should_throw);
1705}
1706
1707// static
1708Maybe<bool> JSReceiver::AddPrivateField(LookupIterator* it,
1709                                        Handle<Object> value,
1710                                        Maybe<ShouldThrow> should_throw) {
1711  Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
1712  Isolate* isolate = receiver->GetIsolate();
1713  DCHECK(it->GetName()->IsPrivateName());
1714  Handle<Symbol> symbol = Handle<Symbol>::cast(it->GetName());
1715
1716  switch (it->state()) {
1717    case LookupIterator::JSPROXY: {
1718      PropertyDescriptor new_desc;
1719      new_desc.set_value(value);
1720      new_desc.set_writable(true);
1721      new_desc.set_enumerable(true);
1722      new_desc.set_configurable(true);
1723      return JSProxy::SetPrivateSymbol(isolate, Handle<JSProxy>::cast(receiver),
1724                                       symbol, &new_desc, should_throw);
1725    }
1726    case LookupIterator::DATA:
1727    case LookupIterator::INTERCEPTOR:
1728    case LookupIterator::ACCESSOR:
1729    case LookupIterator::INTEGER_INDEXED_EXOTIC:
1730      UNREACHABLE();
1731
1732    case LookupIterator::ACCESS_CHECK: {
1733      if (!it->HasAccess()) {
1734        it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
1735        RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
1736        return Just(true);
1737      }
1738      break;
1739    }
1740
1741    case LookupIterator::TRANSITION:
1742    case LookupIterator::NOT_FOUND:
1743      break;
1744  }
1745
1746  return Object::TransitionAndWriteDataProperty(it, value, NONE, should_throw,
1747                                                StoreOrigin::kMaybeKeyed);
1748}
1749
1750// static
1751Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
1752                                                 Handle<JSReceiver> object,
1753                                                 Handle<Object> key,
1754                                                 PropertyDescriptor* desc) {
1755  DCHECK(key->IsName() || key->IsNumber());  // |key| is a PropertyKey.
1756  PropertyKey lookup_key(isolate, key);
1757  LookupIterator it(isolate, object, lookup_key, LookupIterator::OWN);
1758  return GetOwnPropertyDescriptor(&it, desc);
1759}
1760
1761namespace {
1762
1763Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
1764                                                 PropertyDescriptor* desc) {
1765  Handle<InterceptorInfo> interceptor;
1766
1767  if (it->state() == LookupIterator::ACCESS_CHECK) {
1768    if (it->HasAccess()) {
1769      it->Next();
1770    } else {
1771      interceptor = it->GetInterceptorForFailedAccessCheck();
1772      if (interceptor.is_null() &&
1773          (!JSObject::AllCanRead(it) ||
1774           it->state() != LookupIterator::INTERCEPTOR)) {
1775        it->Restart();
1776        return Just(false);
1777      }
1778    }
1779  }
1780
1781  if (it->state() == LookupIterator::INTERCEPTOR) {
1782    interceptor = it->GetInterceptor();
1783  }
1784  if (interceptor.is_null()) return Just(false);
1785  Isolate* isolate = it->isolate();
1786  if (interceptor->descriptor().IsUndefined(isolate)) return Just(false);
1787
1788  Handle<Object> result;
1789  Handle<JSObject> holder = it->GetHolder<JSObject>();
1790
1791  Handle<Object> receiver = it->GetReceiver();
1792  if (!receiver->IsJSReceiver()) {
1793    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
1794                                     Object::ConvertReceiver(isolate, receiver),
1795                                     Nothing<bool>());
1796  }
1797
1798  PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
1799                                 *holder, Just(kDontThrow));
1800  if (it->IsElement(*holder)) {
1801    result = args.CallIndexedDescriptor(interceptor, it->array_index());
1802  } else {
1803    result = args.CallNamedDescriptor(interceptor, it->name());
1804  }
1805  // An exception was thrown in the interceptor. Propagate.
1806  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
1807  if (!result.is_null()) {
1808    // Request successfully intercepted, try to set the property
1809    // descriptor.
1810    Utils::ApiCheck(
1811        PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
1812        it->IsElement(*holder) ? "v8::IndexedPropertyDescriptorCallback"
1813                               : "v8::NamedPropertyDescriptorCallback",
1814        "Invalid property descriptor.");
1815
1816    return Just(true);
1817  }
1818
1819  it->Next();
1820  return Just(false);
1821}
1822}  // namespace
1823
1824// ES6 9.1.5.1
1825// Returns true on success, false if the property didn't exist, nothing if
1826// an exception was thrown.
1827// static
1828Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
1829                                                 PropertyDescriptor* desc) {
1830  Isolate* isolate = it->isolate();
1831  // "Virtual" dispatch.
1832  if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
1833    return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
1834                                             it->GetName(), desc);
1835  }
1836
1837  Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
1838  MAYBE_RETURN(intercepted, Nothing<bool>());
1839  if (intercepted.FromJust()) {
1840    return Just(true);
1841  }
1842
1843  // Request was not intercepted, continue as normal.
1844  // 1. (Assert)
1845  // 2. If O does not have an own property with key P, return undefined.
1846  Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
1847  MAYBE_RETURN(maybe, Nothing<bool>());
1848  PropertyAttributes attrs = maybe.FromJust();
1849  if (attrs == ABSENT) return Just(false);
1850  DCHECK(!isolate->has_pending_exception());
1851
1852  // 3. Let D be a newly created Property Descriptor with no fields.
1853  DCHECK(desc->is_empty());
1854  // 4. Let X be O's own property whose key is P.
1855  // 5. If X is a data property, then
1856  bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
1857                          it->GetAccessors()->IsAccessorPair();
1858  if (!is_accessor_pair) {
1859    // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
1860    Handle<Object> value;
1861    if (!Object::GetProperty(it).ToHandle(&value)) {
1862      DCHECK(isolate->has_pending_exception());
1863      return Nothing<bool>();
1864    }
1865    desc->set_value(value);
1866    // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
1867    desc->set_writable((attrs & READ_ONLY) == 0);
1868  } else {
1869    // 6. Else X is an accessor property, so
1870    Handle<AccessorPair> accessors =
1871        Handle<AccessorPair>::cast(it->GetAccessors());
1872    Handle<NativeContext> native_context =
1873        it->GetHolder<JSReceiver>()->GetCreationContext().ToHandleChecked();
1874    // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
1875    desc->set_get(AccessorPair::GetComponent(isolate, native_context, accessors,
1876                                             ACCESSOR_GETTER));
1877    // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
1878    desc->set_set(AccessorPair::GetComponent(isolate, native_context, accessors,
1879                                             ACCESSOR_SETTER));
1880  }
1881
1882  // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
1883  desc->set_enumerable((attrs & DONT_ENUM) == 0);
1884  // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
1885  desc->set_configurable((attrs & DONT_DELETE) == 0);
1886  // 9. Return D.
1887  DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
1888         PropertyDescriptor::IsDataDescriptor(desc));
1889  return Just(true);
1890}
1891Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
1892                                          IntegrityLevel level,
1893                                          ShouldThrow should_throw) {
1894  DCHECK(level == SEALED || level == FROZEN);
1895
1896  if (receiver->IsJSObject()) {
1897    Handle<JSObject> object = Handle<JSObject>::cast(receiver);
1898
1899    if (!object->HasSloppyArgumentsElements() &&
1900        !object->IsJSModuleNamespace()) {  // Fast path.
1901      // Prevent memory leaks by not adding unnecessary transitions.
1902      Maybe<bool> test = JSObject::TestIntegrityLevel(object, level);
1903      MAYBE_RETURN(test, Nothing<bool>());
1904      if (test.FromJust()) return test;
1905
1906      if (level == SEALED) {
1907        return JSObject::PreventExtensionsWithTransition<SEALED>(object,
1908                                                                 should_throw);
1909      } else {
1910        return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
1911                                                                 should_throw);
1912      }
1913    }
1914  }
1915
1916  Isolate* isolate = receiver->GetIsolate();
1917
1918  MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
1919               Nothing<bool>());
1920
1921  Handle<FixedArray> keys;
1922  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1923      isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
1924
1925  PropertyDescriptor no_conf;
1926  no_conf.set_configurable(false);
1927
1928  PropertyDescriptor no_conf_no_write;
1929  no_conf_no_write.set_configurable(false);
1930  no_conf_no_write.set_writable(false);
1931
1932  if (level == SEALED) {
1933    for (int i = 0; i < keys->length(); ++i) {
1934      Handle<Object> key(keys->get(i), isolate);
1935      MAYBE_RETURN(DefineOwnProperty(isolate, receiver, key, &no_conf,
1936                                     Just(kThrowOnError)),
1937                   Nothing<bool>());
1938    }
1939    return Just(true);
1940  }
1941
1942  for (int i = 0; i < keys->length(); ++i) {
1943    Handle<Object> key(keys->get(i), isolate);
1944    PropertyDescriptor current_desc;
1945    Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
1946        isolate, receiver, key, &current_desc);
1947    MAYBE_RETURN(owned, Nothing<bool>());
1948    if (owned.FromJust()) {
1949      PropertyDescriptor desc =
1950          PropertyDescriptor::IsAccessorDescriptor(&current_desc)
1951              ? no_conf
1952              : no_conf_no_write;
1953      MAYBE_RETURN(
1954          DefineOwnProperty(isolate, receiver, key, &desc, Just(kThrowOnError)),
1955          Nothing<bool>());
1956    }
1957  }
1958  return Just(true);
1959}
1960
1961namespace {
1962Maybe<bool> GenericTestIntegrityLevel(Handle<JSReceiver> receiver,
1963                                      PropertyAttributes level) {
1964  DCHECK(level == SEALED || level == FROZEN);
1965
1966  Maybe<bool> extensible = JSReceiver::IsExtensible(receiver);
1967  MAYBE_RETURN(extensible, Nothing<bool>());
1968  if (extensible.FromJust()) return Just(false);
1969
1970  Isolate* isolate = receiver->GetIsolate();
1971
1972  Handle<FixedArray> keys;
1973  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1974      isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
1975
1976  for (int i = 0; i < keys->length(); ++i) {
1977    Handle<Object> key(keys->get(i), isolate);
1978    PropertyDescriptor current_desc;
1979    Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
1980        isolate, receiver, key, &current_desc);
1981    MAYBE_RETURN(owned, Nothing<bool>());
1982    if (owned.FromJust()) {
1983      if (current_desc.configurable()) return Just(false);
1984      if (level == FROZEN &&
1985          PropertyDescriptor::IsDataDescriptor(&current_desc) &&
1986          current_desc.writable()) {
1987        return Just(false);
1988      }
1989    }
1990  }
1991  return Just(true);
1992}
1993
1994}  // namespace
1995
1996Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> receiver,
1997                                           IntegrityLevel level) {
1998  if (!receiver->map().IsCustomElementsReceiverMap()) {
1999    return JSObject::TestIntegrityLevel(Handle<JSObject>::cast(receiver),
2000                                        level);
2001  }
2002  return GenericTestIntegrityLevel(receiver, level);
2003}
2004
2005Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
2006                                          ShouldThrow should_throw) {
2007  if (object->IsJSProxy()) {
2008    return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
2009                                      should_throw);
2010  }
2011  DCHECK(object->IsJSObject());
2012  return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
2013                                     should_throw);
2014}
2015
2016Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
2017  if (object->IsJSProxy()) {
2018    return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
2019  }
2020  return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
2021}
2022
2023// static
2024MaybeHandle<Object> JSReceiver::ToPrimitive(Isolate* isolate,
2025                                            Handle<JSReceiver> receiver,
2026                                            ToPrimitiveHint hint) {
2027  Handle<Object> exotic_to_prim;
2028  ASSIGN_RETURN_ON_EXCEPTION(
2029      isolate, exotic_to_prim,
2030      Object::GetMethod(receiver, isolate->factory()->to_primitive_symbol()),
2031      Object);
2032  if (!exotic_to_prim->IsUndefined(isolate)) {
2033    Handle<Object> hint_string =
2034        isolate->factory()->ToPrimitiveHintString(hint);
2035    Handle<Object> result;
2036    ASSIGN_RETURN_ON_EXCEPTION(
2037        isolate, result,
2038        Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
2039        Object);
2040    if (result->IsPrimitive()) return result;
2041    THROW_NEW_ERROR(isolate,
2042                    NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
2043                    Object);
2044  }
2045  return OrdinaryToPrimitive(isolate, receiver,
2046                             (hint == ToPrimitiveHint::kString)
2047                                 ? OrdinaryToPrimitiveHint::kString
2048                                 : OrdinaryToPrimitiveHint::kNumber);
2049}
2050
2051// static
2052MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
2053    Isolate* isolate, Handle<JSReceiver> receiver,
2054    OrdinaryToPrimitiveHint hint) {
2055  Handle<String> method_names[2];
2056  switch (hint) {
2057    case OrdinaryToPrimitiveHint::kNumber:
2058      method_names[0] = isolate->factory()->valueOf_string();
2059      method_names[1] = isolate->factory()->toString_string();
2060      break;
2061    case OrdinaryToPrimitiveHint::kString:
2062      method_names[0] = isolate->factory()->toString_string();
2063      method_names[1] = isolate->factory()->valueOf_string();
2064      break;
2065  }
2066  for (Handle<String> name : method_names) {
2067    Handle<Object> method;
2068    ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
2069                               JSReceiver::GetProperty(isolate, receiver, name),
2070                               Object);
2071    if (method->IsCallable()) {
2072      Handle<Object> result;
2073      ASSIGN_RETURN_ON_EXCEPTION(
2074          isolate, result,
2075          Execution::Call(isolate, method, receiver, 0, nullptr), Object);
2076      if (result->IsPrimitive()) return result;
2077    }
2078  }
2079  THROW_NEW_ERROR(isolate,
2080                  NewTypeError(MessageTemplate::kCannotConvertToPrimitive),
2081                  Object);
2082}
2083
2084V8_WARN_UNUSED_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
2085    Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
2086    Handle<FixedArray>* result) {
2087  Handle<Map> map(JSReceiver::cast(*receiver).map(), isolate);
2088
2089  if (!map->IsJSObjectMap()) return Just(false);
2090  if (!map->OnlyHasSimpleProperties()) return Just(false);
2091
2092  Handle<JSObject> object(JSObject::cast(*receiver), isolate);
2093  Handle<DescriptorArray> descriptors(map->instance_descriptors(isolate),
2094                                      isolate);
2095
2096  int number_of_own_descriptors = map->NumberOfOwnDescriptors();
2097  size_t number_of_own_elements =
2098      object->GetElementsAccessor()->GetCapacity(*object, object->elements());
2099
2100  if (number_of_own_elements >
2101      static_cast<size_t>(FixedArray::kMaxLength - number_of_own_descriptors)) {
2102    isolate->Throw(*isolate->factory()->NewRangeError(
2103        MessageTemplate::kInvalidArrayLength));
2104    return Nothing<bool>();
2105  }
2106  // The static cast is safe after the range check right above.
2107  Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray(
2108      static_cast<int>(number_of_own_descriptors + number_of_own_elements));
2109  int count = 0;
2110
2111  if (object->elements() != ReadOnlyRoots(isolate).empty_fixed_array()) {
2112    MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries(
2113                     isolate, object, values_or_entries, get_entries, &count,
2114                     ENUMERABLE_STRINGS),
2115                 Nothing<bool>());
2116  }
2117
2118  // We may have already lost stability, if CollectValuesOrEntries had
2119  // side-effects.
2120  bool stable = *map == object->map();
2121  if (stable) {
2122    descriptors.PatchValue(map->instance_descriptors(isolate));
2123  }
2124
2125  for (InternalIndex index : InternalIndex::Range(number_of_own_descriptors)) {
2126    HandleScope inner_scope(isolate);
2127
2128    Handle<Name> next_key(descriptors->GetKey(index), isolate);
2129    if (!next_key->IsString()) continue;
2130    Handle<Object> prop_value;
2131
2132    // Directly decode from the descriptor array if |from| did not change shape.
2133    if (stable) {
2134      DCHECK_EQ(object->map(), *map);
2135      DCHECK_EQ(*descriptors, map->instance_descriptors(isolate));
2136
2137      PropertyDetails details = descriptors->GetDetails(index);
2138      if (!details.IsEnumerable()) continue;
2139      if (details.kind() == PropertyKind::kData) {
2140        if (details.location() == PropertyLocation::kDescriptor) {
2141          prop_value = handle(descriptors->GetStrongValue(index), isolate);
2142        } else {
2143          Representation representation = details.representation();
2144          FieldIndex field_index = FieldIndex::ForPropertyIndex(
2145              *map, details.field_index(), representation);
2146          prop_value = JSObject::FastPropertyAt(isolate, object, representation,
2147                                                field_index);
2148        }
2149      } else {
2150        LookupIterator it(isolate, object, next_key,
2151                          LookupIterator::OWN_SKIP_INTERCEPTOR);
2152        DCHECK_EQ(LookupIterator::ACCESSOR, it.state());
2153        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2154            isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2155        stable = object->map() == *map;
2156        descriptors.PatchValue(map->instance_descriptors(isolate));
2157      }
2158    } else {
2159      // If the map did change, do a slower lookup. We are still guaranteed that
2160      // the object has a simple shape, and that the key is a name.
2161      LookupIterator it(isolate, object, next_key,
2162                        LookupIterator::OWN_SKIP_INTERCEPTOR);
2163      if (!it.IsFound()) continue;
2164      DCHECK(it.state() == LookupIterator::DATA ||
2165             it.state() == LookupIterator::ACCESSOR);
2166      if (!it.IsEnumerable()) continue;
2167      ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2168          isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
2169    }
2170
2171    if (get_entries) {
2172      prop_value = MakeEntryPair(isolate, next_key, prop_value);
2173    }
2174
2175    values_or_entries->set(count, *prop_value);
2176    count++;
2177  }
2178
2179  DCHECK_LE(count, values_or_entries->length());
2180  *result = FixedArray::ShrinkOrEmpty(isolate, values_or_entries, count);
2181  return Just(true);
2182}
2183
2184MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
2185                                              Handle<JSReceiver> object,
2186                                              PropertyFilter filter,
2187                                              bool try_fast_path,
2188                                              bool get_entries) {
2189  Handle<FixedArray> values_or_entries;
2190  if (try_fast_path && filter == ENUMERABLE_STRINGS) {
2191    Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
2192        isolate, object, get_entries, &values_or_entries);
2193    if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
2194    if (fast_values_or_entries.FromJust()) return values_or_entries;
2195  }
2196
2197  PropertyFilter key_filter =
2198      static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
2199
2200  Handle<FixedArray> keys;
2201  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2202      isolate, keys,
2203      KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
2204                              GetKeysConversion::kConvertToString),
2205      MaybeHandle<FixedArray>());
2206
2207  values_or_entries = isolate->factory()->NewFixedArray(keys->length());
2208  int length = 0;
2209
2210  for (int i = 0; i < keys->length(); ++i) {
2211    Handle<Name> key =
2212        Handle<Name>::cast(handle(keys->get(isolate, i), isolate));
2213
2214    if (filter & ONLY_ENUMERABLE) {
2215      PropertyDescriptor descriptor;
2216      Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
2217          isolate, object, key, &descriptor);
2218      MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
2219      if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
2220    }
2221
2222    Handle<Object> value;
2223    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2224        isolate, value, Object::GetPropertyOrElement(isolate, object, key),
2225        MaybeHandle<FixedArray>());
2226
2227    if (get_entries) {
2228      Handle<FixedArray> entry_storage = isolate->factory()->NewFixedArray(2);
2229      entry_storage->set(0, *key);
2230      entry_storage->set(1, *value);
2231      value = isolate->factory()->NewJSArrayWithElements(entry_storage,
2232                                                         PACKED_ELEMENTS, 2);
2233    }
2234
2235    values_or_entries->set(length, *value);
2236    length++;
2237  }
2238  DCHECK_LE(length, values_or_entries->length());
2239  return FixedArray::ShrinkOrEmpty(isolate, values_or_entries, length);
2240}
2241
2242MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
2243                                                 PropertyFilter filter,
2244                                                 bool try_fast_path) {
2245  return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
2246                               try_fast_path, false);
2247}
2248
2249MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
2250                                                  PropertyFilter filter,
2251                                                  bool try_fast_path) {
2252  return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
2253                               try_fast_path, true);
2254}
2255
2256Maybe<bool> JSReceiver::SetPrototype(Isolate* isolate,
2257                                     Handle<JSReceiver> object,
2258                                     Handle<Object> value, bool from_javascript,
2259                                     ShouldThrow should_throw) {
2260  if (object->IsJSProxy()) {
2261    return JSProxy::SetPrototype(isolate, Handle<JSProxy>::cast(object), value,
2262                                 from_javascript, should_throw);
2263  }
2264  return JSObject::SetPrototype(isolate, Handle<JSObject>::cast(object), value,
2265                                from_javascript, should_throw);
2266}
2267
2268bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
2269  for (PrototypeIterator iter(isolate, *this, kStartAtReceiver,
2270                              PrototypeIterator::END_AT_NULL);
2271       !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
2272    if (iter.GetCurrent().IsJSProxy()) return true;
2273  }
2274  return false;
2275}
2276
2277bool JSReceiver::IsCodeLike(Isolate* isolate) const {
2278  DisallowGarbageCollection no_gc;
2279  Object maybe_constructor = map().GetConstructor();
2280  if (!maybe_constructor.IsJSFunction()) return false;
2281  if (!JSFunction::cast(maybe_constructor).shared().IsApiFunction()) {
2282    return false;
2283  }
2284  Object instance_template = JSFunction::cast(maybe_constructor)
2285                                 .shared()
2286                                 .get_api_func_data()
2287                                 .GetInstanceTemplate();
2288  if (instance_template.IsUndefined(isolate)) return false;
2289  return ObjectTemplateInfo::cast(instance_template).code_like();
2290}
2291
2292// static
2293MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
2294                                    Handle<JSReceiver> new_target,
2295                                    Handle<AllocationSite> site) {
2296  // If called through new, new.target can be:
2297  // - a subclass of constructor,
2298  // - a proxy wrapper around constructor, or
2299  // - the constructor itself.
2300  // If called through Reflect.construct, it's guaranteed to be a constructor.
2301  Isolate* const isolate = constructor->GetIsolate();
2302  DCHECK(constructor->IsConstructor());
2303  DCHECK(new_target->IsConstructor());
2304  DCHECK(!constructor->has_initial_map() ||
2305         !InstanceTypeChecker::IsJSFunction(
2306             constructor->initial_map().instance_type()));
2307
2308  Handle<Map> initial_map;
2309  ASSIGN_RETURN_ON_EXCEPTION(
2310      isolate, initial_map,
2311      JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
2312  int initial_capacity = V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
2313                             ? SwissNameDictionary::kInitialCapacity
2314                             : NameDictionary::kInitialCapacity;
2315  Handle<JSObject> result = isolate->factory()->NewFastOrSlowJSObjectFromMap(
2316      initial_map, initial_capacity, AllocationType::kYoung, site);
2317  isolate->counters()->constructed_objects()->Increment();
2318  isolate->counters()->constructed_objects_runtime()->Increment();
2319  return result;
2320}
2321
2322// 9.1.12 ObjectCreate ( proto [ , internalSlotsList ] )
2323// Notice: This is NOT 19.1.2.2 Object.create ( O, Properties )
2324MaybeHandle<JSObject> JSObject::ObjectCreate(Isolate* isolate,
2325                                             Handle<Object> prototype) {
2326  // Generate the map with the specified {prototype} based on the Object
2327  // function's initial map from the current native context.
2328  // TODO(bmeurer): Use a dedicated cache for Object.create; think about
2329  // slack tracking for Object.create.
2330  Handle<Map> map =
2331      Map::GetObjectCreateMap(isolate, Handle<HeapObject>::cast(prototype));
2332
2333  // Actually allocate the object.
2334  return isolate->factory()->NewFastOrSlowJSObjectFromMap(map);
2335}
2336
2337void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
2338  DCHECK(object->HasSmiOrObjectElements() ||
2339         object->HasFastStringWrapperElements() ||
2340         object->HasAnyNonextensibleElements());
2341  FixedArray raw_elems = FixedArray::cast(object->elements());
2342  Isolate* isolate = object->GetIsolate();
2343  if (raw_elems.map() != ReadOnlyRoots(isolate).fixed_cow_array_map()) return;
2344  Handle<FixedArray> elems(raw_elems, isolate);
2345  Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
2346      elems, isolate->factory()->fixed_array_map());
2347  object->set_elements(*writable_elems);
2348  isolate->counters()->cow_arrays_converted()->Increment();
2349}
2350
2351int JSObject::GetHeaderSize(InstanceType type,
2352                            bool function_has_prototype_slot) {
2353  switch (type) {
2354    case JS_API_OBJECT_TYPE:
2355    case JS_ITERATOR_PROTOTYPE_TYPE:
2356    case JS_MAP_ITERATOR_PROTOTYPE_TYPE:
2357    case JS_OBJECT_PROTOTYPE_TYPE:
2358    case JS_OBJECT_TYPE:
2359    case JS_PROMISE_PROTOTYPE_TYPE:
2360    case JS_REG_EXP_PROTOTYPE_TYPE:
2361    case JS_SET_ITERATOR_PROTOTYPE_TYPE:
2362    case JS_SET_PROTOTYPE_TYPE:
2363    case JS_SPECIAL_API_OBJECT_TYPE:
2364    case JS_STRING_ITERATOR_PROTOTYPE_TYPE:
2365    case JS_ARRAY_ITERATOR_PROTOTYPE_TYPE:
2366    case JS_TYPED_ARRAY_PROTOTYPE_TYPE:
2367      return JSObject::kHeaderSize;
2368    case JS_GENERATOR_OBJECT_TYPE:
2369      return JSGeneratorObject::kHeaderSize;
2370    case JS_ASYNC_FUNCTION_OBJECT_TYPE:
2371      return JSAsyncFunctionObject::kHeaderSize;
2372    case JS_ASYNC_GENERATOR_OBJECT_TYPE:
2373      return JSAsyncGeneratorObject::kHeaderSize;
2374    case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
2375      return JSAsyncFromSyncIterator::kHeaderSize;
2376    case JS_GLOBAL_PROXY_TYPE:
2377      return JSGlobalProxy::kHeaderSize;
2378    case JS_GLOBAL_OBJECT_TYPE:
2379      return JSGlobalObject::kHeaderSize;
2380    case JS_BOUND_FUNCTION_TYPE:
2381      return JSBoundFunction::kHeaderSize;
2382    case JS_FUNCTION_TYPE:
2383    case JS_CLASS_CONSTRUCTOR_TYPE:
2384    case JS_PROMISE_CONSTRUCTOR_TYPE:
2385    case JS_REG_EXP_CONSTRUCTOR_TYPE:
2386    case JS_ARRAY_CONSTRUCTOR_TYPE:
2387#define TYPED_ARRAY_CONSTRUCTORS_SWITCH(Type, type, TYPE, Ctype) \
2388  case TYPE##_TYPED_ARRAY_CONSTRUCTOR_TYPE:
2389      TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTORS_SWITCH)
2390#undef TYPED_ARRAY_CONSTRUCTORS_SWITCH
2391      return JSFunction::GetHeaderSize(function_has_prototype_slot);
2392    case JS_PRIMITIVE_WRAPPER_TYPE:
2393      return JSPrimitiveWrapper::kHeaderSize;
2394    case JS_DATE_TYPE:
2395      return JSDate::kHeaderSize;
2396    case JS_ARRAY_TYPE:
2397      return JSArray::kHeaderSize;
2398    case JS_ARRAY_BUFFER_TYPE:
2399      return JSArrayBuffer::kHeaderSize;
2400    case JS_ARRAY_ITERATOR_TYPE:
2401      return JSArrayIterator::kHeaderSize;
2402    case JS_TYPED_ARRAY_TYPE:
2403      return JSTypedArray::kHeaderSize;
2404    case JS_DATA_VIEW_TYPE:
2405      return JSDataView::kHeaderSize;
2406    case JS_SET_TYPE:
2407      return JSSet::kHeaderSize;
2408    case JS_MAP_TYPE:
2409      return JSMap::kHeaderSize;
2410    case JS_SET_KEY_VALUE_ITERATOR_TYPE:
2411    case JS_SET_VALUE_ITERATOR_TYPE:
2412      return JSSetIterator::kHeaderSize;
2413    case JS_MAP_KEY_ITERATOR_TYPE:
2414    case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
2415    case JS_MAP_VALUE_ITERATOR_TYPE:
2416      return JSMapIterator::kHeaderSize;
2417    case JS_WEAK_REF_TYPE:
2418      return JSWeakRef::kHeaderSize;
2419    case JS_FINALIZATION_REGISTRY_TYPE:
2420      return JSFinalizationRegistry::kHeaderSize;
2421    case JS_WEAK_MAP_TYPE:
2422      return JSWeakMap::kHeaderSize;
2423    case JS_WEAK_SET_TYPE:
2424      return JSWeakSet::kHeaderSize;
2425    case JS_PROMISE_TYPE:
2426      return JSPromise::kHeaderSize;
2427    case JS_REG_EXP_TYPE:
2428      return JSRegExp::kHeaderSize;
2429    case JS_REG_EXP_STRING_ITERATOR_TYPE:
2430      return JSRegExpStringIterator::kHeaderSize;
2431    case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
2432      return JSObject::kHeaderSize;
2433    case JS_MESSAGE_OBJECT_TYPE:
2434      return JSMessageObject::kHeaderSize;
2435    case JS_ARGUMENTS_OBJECT_TYPE:
2436      return JSObject::kHeaderSize;
2437    case JS_ERROR_TYPE:
2438      return JSObject::kHeaderSize;
2439    case JS_EXTERNAL_OBJECT_TYPE:
2440      return JSExternalObject::kHeaderSize;
2441    case JS_SHADOW_REALM_TYPE:
2442      return JSShadowRealm::kHeaderSize;
2443    case JS_STRING_ITERATOR_TYPE:
2444      return JSStringIterator::kHeaderSize;
2445    case JS_MODULE_NAMESPACE_TYPE:
2446      return JSModuleNamespace::kHeaderSize;
2447    case JS_SHARED_STRUCT_TYPE:
2448      return JSSharedStruct::kHeaderSize;
2449    case JS_TEMPORAL_CALENDAR_TYPE:
2450      return JSTemporalCalendar::kHeaderSize;
2451    case JS_TEMPORAL_DURATION_TYPE:
2452      return JSTemporalDuration::kHeaderSize;
2453    case JS_TEMPORAL_INSTANT_TYPE:
2454      return JSTemporalInstant::kHeaderSize;
2455    case JS_TEMPORAL_PLAIN_DATE_TYPE:
2456      return JSTemporalPlainDate::kHeaderSize;
2457    case JS_TEMPORAL_PLAIN_DATE_TIME_TYPE:
2458      return JSTemporalPlainDateTime::kHeaderSize;
2459    case JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE:
2460      return JSTemporalPlainMonthDay::kHeaderSize;
2461    case JS_TEMPORAL_PLAIN_TIME_TYPE:
2462      return JSTemporalPlainTime::kHeaderSize;
2463    case JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE:
2464      return JSTemporalPlainYearMonth::kHeaderSize;
2465    case JS_TEMPORAL_TIME_ZONE_TYPE:
2466      return JSTemporalTimeZone::kHeaderSize;
2467    case JS_TEMPORAL_ZONED_DATE_TIME_TYPE:
2468      return JSTemporalZonedDateTime::kHeaderSize;
2469    case JS_WRAPPED_FUNCTION_TYPE:
2470      return JSWrappedFunction::kHeaderSize;
2471#ifdef V8_INTL_SUPPORT
2472    case JS_V8_BREAK_ITERATOR_TYPE:
2473      return JSV8BreakIterator::kHeaderSize;
2474    case JS_COLLATOR_TYPE:
2475      return JSCollator::kHeaderSize;
2476    case JS_DATE_TIME_FORMAT_TYPE:
2477      return JSDateTimeFormat::kHeaderSize;
2478    case JS_DISPLAY_NAMES_TYPE:
2479      return JSDisplayNames::kHeaderSize;
2480    case JS_LIST_FORMAT_TYPE:
2481      return JSListFormat::kHeaderSize;
2482    case JS_LOCALE_TYPE:
2483      return JSLocale::kHeaderSize;
2484    case JS_NUMBER_FORMAT_TYPE:
2485      return JSNumberFormat::kHeaderSize;
2486    case JS_PLURAL_RULES_TYPE:
2487      return JSPluralRules::kHeaderSize;
2488    case JS_RELATIVE_TIME_FORMAT_TYPE:
2489      return JSRelativeTimeFormat::kHeaderSize;
2490    case JS_SEGMENT_ITERATOR_TYPE:
2491      return JSSegmentIterator::kHeaderSize;
2492    case JS_SEGMENTER_TYPE:
2493      return JSSegmenter::kHeaderSize;
2494    case JS_SEGMENTS_TYPE:
2495      return JSSegments::kHeaderSize;
2496#endif  // V8_INTL_SUPPORT
2497#if V8_ENABLE_WEBASSEMBLY
2498    case WASM_GLOBAL_OBJECT_TYPE:
2499      return WasmGlobalObject::kHeaderSize;
2500    case WASM_INSTANCE_OBJECT_TYPE:
2501      return WasmInstanceObject::kHeaderSize;
2502    case WASM_MEMORY_OBJECT_TYPE:
2503      return WasmMemoryObject::kHeaderSize;
2504    case WASM_MODULE_OBJECT_TYPE:
2505      return WasmModuleObject::kHeaderSize;
2506    case WASM_SUSPENDER_OBJECT_TYPE:
2507      return WasmSuspenderObject::kHeaderSize;
2508    case WASM_TABLE_OBJECT_TYPE:
2509      return WasmTableObject::kHeaderSize;
2510    case WASM_VALUE_OBJECT_TYPE:
2511      return WasmValueObject::kHeaderSize;
2512    case WASM_TAG_OBJECT_TYPE:
2513      return WasmTagObject::kHeaderSize;
2514#endif  // V8_ENABLE_WEBASSEMBLY
2515    default: {
2516      // Special type check for API Objects because they are in a large variable
2517      // instance type range.
2518      if (InstanceTypeChecker::IsJSApiObject(type)) {
2519        return JSObject::kHeaderSize;
2520      }
2521      std::stringstream ss;
2522      ss << type;
2523      FATAL("unexpected instance type: %s\n", ss.str().c_str());
2524    }
2525  }
2526}
2527
2528// static
2529bool JSObject::AllCanRead(LookupIterator* it) {
2530  // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
2531  // which have already been checked.
2532  DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
2533         it->state() == LookupIterator::INTERCEPTOR);
2534  for (it->Next(); it->IsFound(); it->Next()) {
2535    if (it->state() == LookupIterator::ACCESSOR) {
2536      auto accessors = it->GetAccessors();
2537      if (accessors->IsAccessorInfo()) {
2538        if (AccessorInfo::cast(*accessors).all_can_read()) return true;
2539      }
2540    } else if (it->state() == LookupIterator::INTERCEPTOR) {
2541      if (it->GetInterceptor()->all_can_read()) return true;
2542    } else if (it->state() == LookupIterator::JSPROXY) {
2543      // Stop lookupiterating. And no, AllCanNotRead.
2544      return false;
2545    }
2546  }
2547  return false;
2548}
2549
2550MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
2551    LookupIterator* it) {
2552  Isolate* isolate = it->isolate();
2553  Handle<JSObject> checked = it->GetHolder<JSObject>();
2554  Handle<InterceptorInfo> interceptor =
2555      it->GetInterceptorForFailedAccessCheck();
2556  if (interceptor.is_null()) {
2557    while (AllCanRead(it)) {
2558      if (it->state() == LookupIterator::ACCESSOR) {
2559        return Object::GetPropertyWithAccessor(it);
2560      }
2561      DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
2562      bool done;
2563      Handle<Object> result;
2564      ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
2565                                 GetPropertyWithInterceptor(it, &done), Object);
2566      if (done) return result;
2567    }
2568
2569  } else {
2570    Handle<Object> result;
2571    bool done;
2572    ASSIGN_RETURN_ON_EXCEPTION(
2573        isolate, result,
2574        GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
2575    if (done) return result;
2576  }
2577
2578  // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
2579  // undefined.
2580  Handle<Name> name = it->GetName();
2581  if (name->IsSymbol() && Symbol::cast(*name).is_well_known_symbol()) {
2582    return it->factory()->undefined_value();
2583  }
2584
2585  isolate->ReportFailedAccessCheck(checked);
2586  RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
2587  return it->factory()->undefined_value();
2588}
2589
2590Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
2591    LookupIterator* it) {
2592  Isolate* isolate = it->isolate();
2593  Handle<JSObject> checked = it->GetHolder<JSObject>();
2594  Handle<InterceptorInfo> interceptor =
2595      it->GetInterceptorForFailedAccessCheck();
2596  if (interceptor.is_null()) {
2597    while (AllCanRead(it)) {
2598      if (it->state() == LookupIterator::ACCESSOR) {
2599        return Just(it->property_attributes());
2600      }
2601      DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
2602      auto result = GetPropertyAttributesWithInterceptor(it);
2603      if (isolate->has_scheduled_exception()) break;
2604      if (result.IsJust() && result.FromJust() != ABSENT) return result;
2605    }
2606  } else {
2607    Maybe<PropertyAttributes> result =
2608        GetPropertyAttributesWithInterceptorInternal(it, interceptor);
2609    if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
2610    if (result.FromMaybe(ABSENT) != ABSENT) return result;
2611  }
2612  isolate->ReportFailedAccessCheck(checked);
2613  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
2614  return Just(ABSENT);
2615}
2616
2617// static
2618bool JSObject::AllCanWrite(LookupIterator* it) {
2619  for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
2620    if (it->state() == LookupIterator::ACCESSOR) {
2621      Handle<Object> accessors = it->GetAccessors();
2622      if (accessors->IsAccessorInfo()) {
2623        if (AccessorInfo::cast(*accessors).all_can_write()) return true;
2624      }
2625    }
2626  }
2627  return false;
2628}
2629
2630Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
2631    LookupIterator* it, Handle<Object> value, Maybe<ShouldThrow> should_throw) {
2632  Isolate* isolate = it->isolate();
2633  Handle<JSObject> checked = it->GetHolder<JSObject>();
2634  Handle<InterceptorInfo> interceptor =
2635      it->GetInterceptorForFailedAccessCheck();
2636  if (interceptor.is_null()) {
2637    if (AllCanWrite(it)) {
2638      return Object::SetPropertyWithAccessor(it, value, should_throw);
2639    }
2640  } else {
2641    Maybe<bool> result = SetPropertyWithInterceptorInternal(
2642        it, interceptor, should_throw, value);
2643    if (isolate->has_pending_exception()) return Nothing<bool>();
2644    if (result.IsJust()) return result;
2645  }
2646  isolate->ReportFailedAccessCheck(checked);
2647  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
2648  return Just(true);
2649}
2650
2651void JSObject::SetNormalizedProperty(Handle<JSObject> object, Handle<Name> name,
2652                                     Handle<Object> value,
2653                                     PropertyDetails details) {
2654  DCHECK(!object->HasFastProperties());
2655  DCHECK(name->IsUniqueName());
2656  Isolate* isolate = object->GetIsolate();
2657
2658  uint32_t hash = name->hash();
2659
2660  if (object->IsJSGlobalObject()) {
2661    Handle<JSGlobalObject> global_obj = Handle<JSGlobalObject>::cast(object);
2662    Handle<GlobalDictionary> dictionary(
2663        global_obj->global_dictionary(kAcquireLoad), isolate);
2664    ReadOnlyRoots roots(isolate);
2665    InternalIndex entry = dictionary->FindEntry(isolate, roots, name, hash);
2666
2667    if (entry.is_not_found()) {
2668      DCHECK_IMPLIES(global_obj->map().is_prototype_map(),
2669                     Map::IsPrototypeChainInvalidated(global_obj->map()));
2670      auto cell_type = value->IsUndefined(roots) ? PropertyCellType::kUndefined
2671                                                 : PropertyCellType::kConstant;
2672      details = details.set_cell_type(cell_type);
2673      auto cell = isolate->factory()->NewPropertyCell(name, details, value);
2674      dictionary =
2675          GlobalDictionary::Add(isolate, dictionary, name, cell, details);
2676      global_obj->set_global_dictionary(*dictionary, kReleaseStore);
2677    } else {
2678      PropertyCell::PrepareForAndSetValue(isolate, dictionary, entry, value,
2679                                          details);
2680      DCHECK_EQ(dictionary->CellAt(entry).value(), *value);
2681    }
2682  } else {
2683    if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
2684      Handle<SwissNameDictionary> dictionary(
2685          object->property_dictionary_swiss(), isolate);
2686      InternalIndex entry = dictionary->FindEntry(isolate, *name);
2687      if (entry.is_not_found()) {
2688        DCHECK_IMPLIES(object->map().is_prototype_map(),
2689                       Map::IsPrototypeChainInvalidated(object->map()));
2690        dictionary =
2691            SwissNameDictionary::Add(isolate, dictionary, name, value, details);
2692        object->SetProperties(*dictionary);
2693      } else {
2694        dictionary->ValueAtPut(entry, *value);
2695        dictionary->DetailsAtPut(entry, details);
2696      }
2697    } else {
2698      Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
2699      InternalIndex entry = dictionary->FindEntry(isolate, name);
2700      if (entry.is_not_found()) {
2701        DCHECK_IMPLIES(object->map().is_prototype_map(),
2702                       Map::IsPrototypeChainInvalidated(object->map()));
2703        dictionary =
2704            NameDictionary::Add(isolate, dictionary, name, value, details);
2705        object->SetProperties(*dictionary);
2706      } else {
2707        PropertyDetails original_details = dictionary->DetailsAt(entry);
2708        int enumeration_index = original_details.dictionary_index();
2709        DCHECK_GT(enumeration_index, 0);
2710        details = details.set_index(enumeration_index);
2711        dictionary->SetEntry(entry, *name, *value, details);
2712      }
2713    }
2714  }
2715}
2716
2717void JSObject::SetNormalizedElement(Handle<JSObject> object, uint32_t index,
2718                                    Handle<Object> value,
2719                                    PropertyDetails details) {
2720  DCHECK_EQ(object->GetElementsKind(), DICTIONARY_ELEMENTS);
2721
2722  Isolate* isolate = object->GetIsolate();
2723
2724  Handle<NumberDictionary> dictionary =
2725      handle(NumberDictionary::cast(object->elements()), isolate);
2726  dictionary =
2727      NumberDictionary::Set(isolate, dictionary, index, value, object, details);
2728  object->set_elements(*dictionary);
2729}
2730
2731void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2732  switch (map().instance_type()) {
2733    case JS_ARRAY_TYPE: {
2734      double length = JSArray::cast(*this).length().IsUndefined()
2735                          ? 0
2736                          : JSArray::cast(*this).length().Number();
2737      accumulator->Add("<JSArray[%u]>", static_cast<uint32_t>(length));
2738      break;
2739    }
2740    case JS_BOUND_FUNCTION_TYPE: {
2741      JSBoundFunction bound_function = JSBoundFunction::cast(*this);
2742      accumulator->Add("<JSBoundFunction");
2743      accumulator->Add(" (BoundTargetFunction %p)>",
2744                       reinterpret_cast<void*>(
2745                           bound_function.bound_target_function().ptr()));
2746      break;
2747    }
2748    case JS_WEAK_MAP_TYPE: {
2749      accumulator->Add("<JSWeakMap>");
2750      break;
2751    }
2752    case JS_WEAK_SET_TYPE: {
2753      accumulator->Add("<JSWeakSet>");
2754      break;
2755    }
2756    case JS_REG_EXP_TYPE: {
2757      accumulator->Add("<JSRegExp");
2758      JSRegExp regexp = JSRegExp::cast(*this);
2759      if (regexp.source().IsString()) {
2760        accumulator->Add(" ");
2761        String::cast(regexp.source()).StringShortPrint(accumulator);
2762      }
2763      accumulator->Add(">");
2764
2765      break;
2766    }
2767    case JS_PROMISE_CONSTRUCTOR_TYPE:
2768    case JS_REG_EXP_CONSTRUCTOR_TYPE:
2769    case JS_ARRAY_CONSTRUCTOR_TYPE:
2770#define TYPED_ARRAY_CONSTRUCTORS_SWITCH(Type, type, TYPE, Ctype) \
2771  case TYPE##_TYPED_ARRAY_CONSTRUCTOR_TYPE:
2772      TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTORS_SWITCH)
2773#undef TYPED_ARRAY_CONSTRUCTORS_SWITCH
2774    case JS_CLASS_CONSTRUCTOR_TYPE:
2775    case JS_FUNCTION_TYPE: {
2776      JSFunction function = JSFunction::cast(*this);
2777      std::unique_ptr<char[]> fun_name = function.shared().DebugNameCStr();
2778      if (fun_name[0] != '\0') {
2779        accumulator->Add("<JSFunction ");
2780        accumulator->Add(fun_name.get());
2781      } else {
2782        accumulator->Add("<JSFunction");
2783      }
2784      if (FLAG_trace_file_names) {
2785        Object source_name = Script::cast(function.shared().script()).name();
2786        if (source_name.IsString()) {
2787          String str = String::cast(source_name);
2788          if (str.length() > 0) {
2789            accumulator->Add(" <");
2790            accumulator->Put(str);
2791            accumulator->Add(">");
2792          }
2793        }
2794      }
2795      accumulator->Add(" (sfi = %p)",
2796                       reinterpret_cast<void*>(function.shared().ptr()));
2797      accumulator->Put('>');
2798      break;
2799    }
2800    case JS_GENERATOR_OBJECT_TYPE: {
2801      accumulator->Add("<JSGenerator>");
2802      break;
2803    }
2804    case JS_ASYNC_FUNCTION_OBJECT_TYPE: {
2805      accumulator->Add("<JSAsyncFunctionObject>");
2806      break;
2807    }
2808    case JS_ASYNC_GENERATOR_OBJECT_TYPE: {
2809      accumulator->Add("<JS AsyncGenerator>");
2810      break;
2811    }
2812
2813    // All other JSObjects are rather similar to each other (JSObject,
2814    // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSPrimitiveWrapper).
2815    default: {
2816      Map map_of_this = map();
2817      Heap* heap = GetHeap();
2818      Object constructor = map_of_this.GetConstructor();
2819      bool printed = false;
2820      if (constructor.IsHeapObject() &&
2821          !heap->Contains(HeapObject::cast(constructor))) {
2822        accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2823      } else {
2824        bool is_global_proxy = IsJSGlobalProxy();
2825        if (constructor.IsJSFunction()) {
2826          if (!heap->Contains(JSFunction::cast(constructor).shared())) {
2827            accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2828          } else {
2829            String constructor_name =
2830                JSFunction::cast(constructor).shared().Name();
2831            if (constructor_name.length() > 0) {
2832              accumulator->Add(is_global_proxy ? "<GlobalObject " : "<");
2833              accumulator->Put(constructor_name);
2834              accumulator->Add(" %smap = %p",
2835                               map_of_this.is_deprecated() ? "deprecated-" : "",
2836                               map_of_this);
2837              printed = true;
2838            }
2839          }
2840        } else if (constructor.IsFunctionTemplateInfo()) {
2841          accumulator->Add("<RemoteObject>");
2842          printed = true;
2843        }
2844        if (!printed) {
2845          accumulator->Add("<JS");
2846          if (is_global_proxy) {
2847            accumulator->Add("GlobalProxy");
2848          } else if (IsJSGlobalObject()) {
2849            accumulator->Add("GlobalObject");
2850          } else {
2851            accumulator->Add("Object");
2852          }
2853        }
2854      }
2855      if (IsJSPrimitiveWrapper()) {
2856        accumulator->Add(" value = ");
2857        JSPrimitiveWrapper::cast(*this).value().ShortPrint(accumulator);
2858      }
2859      accumulator->Put('>');
2860      break;
2861    }
2862  }
2863}
2864
2865void JSObject::PrintElementsTransition(FILE* file, Handle<JSObject> object,
2866                                       ElementsKind from_kind,
2867                                       Handle<FixedArrayBase> from_elements,
2868                                       ElementsKind to_kind,
2869                                       Handle<FixedArrayBase> to_elements) {
2870  if (from_kind != to_kind) {
2871    OFStream os(file);
2872    os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2873       << ElementsKindToString(to_kind) << "] in ";
2874    JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2875    PrintF(file, " for ");
2876    object->ShortPrint(file);
2877    PrintF(file, " from ");
2878    from_elements->ShortPrint(file);
2879    PrintF(file, " to ");
2880    to_elements->ShortPrint(file);
2881    PrintF(file, "\n");
2882  }
2883}
2884
2885void JSObject::PrintInstanceMigration(FILE* file, Map original_map,
2886                                      Map new_map) {
2887  if (new_map.is_dictionary_map()) {
2888    PrintF(file, "[migrating to slow]\n");
2889    return;
2890  }
2891  PrintF(file, "[migrating]");
2892  Isolate* isolate = GetIsolate();
2893  DescriptorArray o = original_map.instance_descriptors(isolate);
2894  DescriptorArray n = new_map.instance_descriptors(isolate);
2895  for (InternalIndex i : original_map.IterateOwnDescriptors()) {
2896    Representation o_r = o.GetDetails(i).representation();
2897    Representation n_r = n.GetDetails(i).representation();
2898    if (!o_r.Equals(n_r)) {
2899      String::cast(o.GetKey(i)).PrintOn(file);
2900      PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
2901    } else if (o.GetDetails(i).location() == PropertyLocation::kDescriptor &&
2902               n.GetDetails(i).location() == PropertyLocation::kField) {
2903      Name name = o.GetKey(i);
2904      if (name.IsString()) {
2905        String::cast(name).PrintOn(file);
2906      } else {
2907        PrintF(file, "{symbol %p}", reinterpret_cast<void*>(name.ptr()));
2908      }
2909      PrintF(file, " ");
2910    }
2911  }
2912  if (original_map.elements_kind() != new_map.elements_kind()) {
2913    PrintF(file, "elements_kind[%i->%i]", original_map.elements_kind(),
2914           new_map.elements_kind());
2915  }
2916  PrintF(file, "\n");
2917}
2918
2919bool JSObject::IsUnmodifiedApiObject(FullObjectSlot o) {
2920  Object object = *o;
2921  if (object.IsSmi()) return false;
2922  HeapObject heap_object = HeapObject::cast(object);
2923  if (!object.IsJSObject()) return false;
2924  JSObject js_object = JSObject::cast(object);
2925  if (!js_object.IsDroppableApiObject()) return false;
2926  Object maybe_constructor = js_object.map().GetConstructor();
2927  if (!maybe_constructor.IsJSFunction()) return false;
2928  JSFunction constructor = JSFunction::cast(maybe_constructor);
2929  if (js_object.elements().length() != 0) return false;
2930  // Check that the object is not a key in a WeakMap (over-approximation).
2931  if (!js_object.GetIdentityHash().IsUndefined()) return false;
2932
2933  return constructor.initial_map() == heap_object.map();
2934}
2935
2936// static
2937void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
2938                                               Handle<Map> new_map,
2939                                               Isolate* isolate) {
2940  DCHECK(old_map->is_prototype_map());
2941  DCHECK(new_map->is_prototype_map());
2942  bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
2943  new_map->set_prototype_info(old_map->prototype_info(), kReleaseStore);
2944  old_map->set_prototype_info(Smi::zero(), kReleaseStore);
2945  if (FLAG_trace_prototype_users) {
2946    PrintF("Moving prototype_info %p from map %p to map %p.\n",
2947           reinterpret_cast<void*>(new_map->prototype_info().ptr()),
2948           reinterpret_cast<void*>(old_map->ptr()),
2949           reinterpret_cast<void*>(new_map->ptr()));
2950  }
2951  if (was_registered) {
2952    if (new_map->prototype_info().IsPrototypeInfo()) {
2953      // The new map isn't registered with its prototype yet; reflect this fact
2954      // in the PrototypeInfo it just inherited from the old map.
2955      PrototypeInfo::cast(new_map->prototype_info())
2956          .set_registry_slot(PrototypeInfo::UNREGISTERED);
2957    }
2958    JSObject::LazyRegisterPrototypeUser(new_map, isolate);
2959  }
2960}
2961
2962// static
2963void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
2964                               Isolate* isolate) {
2965  if (!old_map->is_prototype_map()) return;
2966
2967  InvalidatePrototypeChains(*old_map);
2968
2969  // If the map was registered with its prototype before, ensure that it
2970  // registers with its new prototype now. This preserves the invariant that
2971  // when a map on a prototype chain is registered with its prototype, then
2972  // all prototypes further up the chain are also registered with their
2973  // respective prototypes.
2974  UpdatePrototypeUserRegistration(old_map, new_map, isolate);
2975}
2976
2977namespace {
2978
2979// To migrate a fast instance to a fast map:
2980// - First check whether the instance needs to be rewritten. If not, simply
2981//   change the map.
2982// - Otherwise, allocate a fixed array large enough to hold all fields, in
2983//   addition to unused space.
2984// - Copy all existing properties in, in the following order: backing store
2985//   properties, unused fields, inobject properties.
2986// - If all allocation succeeded, commit the state atomically:
2987//   * Copy inobject properties from the backing store back into the object.
2988//   * Trim the difference in instance size of the object. This also cleanly
2989//     frees inobject properties that moved to the backing store.
2990//   * If there are properties left in the backing store, trim of the space used
2991//     to temporarily store the inobject properties.
2992//   * If there are properties left in the backing store, install the backing
2993//     store.
2994void MigrateFastToFast(Isolate* isolate, Handle<JSObject> object,
2995                       Handle<Map> new_map) {
2996  Handle<Map> old_map(object->map(), isolate);
2997  // In case of a regular transition.
2998  if (new_map->GetBackPointer(isolate) == *old_map) {
2999    // If the map does not add named properties, simply set the map.
3000    if (old_map->NumberOfOwnDescriptors() ==
3001        new_map->NumberOfOwnDescriptors()) {
3002      object->set_map(*new_map, kReleaseStore);
3003      return;
3004    }
3005
3006    // If the map adds a new kDescriptor property, simply set the map.
3007    PropertyDetails details = new_map->GetLastDescriptorDetails(isolate);
3008    if (details.location() == PropertyLocation::kDescriptor) {
3009      object->set_map(*new_map, kReleaseStore);
3010      return;
3011    }
3012
3013    // Check if we still have space in the {object}, in which case we
3014    // can also simply set the map (modulo a special case for mutable
3015    // double boxes).
3016    FieldIndex index =
3017        FieldIndex::ForDescriptor(isolate, *new_map, new_map->LastAdded());
3018    if (index.is_inobject() || index.outobject_array_index() <
3019                                   object->property_array(isolate).length()) {
3020      // Allocate HeapNumbers for double fields.
3021      if (index.is_double()) {
3022        auto value = isolate->factory()->NewHeapNumberWithHoleNaN();
3023        object->FastPropertyAtPut(index, *value);
3024      }
3025      object->set_map(*new_map, kReleaseStore);
3026      return;
3027    }
3028
3029    // This migration is a transition from a map that has run out of property
3030    // space. Extend the backing store.
3031    int grow_by = new_map->UnusedPropertyFields() + 1;
3032    Handle<PropertyArray> old_storage(object->property_array(isolate), isolate);
3033    Handle<PropertyArray> new_storage =
3034        isolate->factory()->CopyPropertyArrayAndGrow(old_storage, grow_by);
3035
3036    // Properly initialize newly added property.
3037    Handle<Object> value;
3038    if (details.representation().IsDouble()) {
3039      value = isolate->factory()->NewHeapNumberWithHoleNaN();
3040    } else {
3041      value = isolate->factory()->uninitialized_value();
3042    }
3043    DCHECK_EQ(PropertyLocation::kField, details.location());
3044    DCHECK_EQ(PropertyKind::kData, details.kind());
3045    DCHECK(!index.is_inobject());  // Must be a backing store index.
3046    new_storage->set(index.outobject_array_index(), *value);
3047
3048    // From here on we cannot fail and we shouldn't GC anymore.
3049    DisallowGarbageCollection no_gc;
3050
3051    // Set the new property value and do the map transition.
3052    object->SetProperties(*new_storage);
3053    object->set_map(*new_map, kReleaseStore);
3054    return;
3055  }
3056
3057  int old_number_of_fields;
3058  int number_of_fields = new_map->NumberOfFields(ConcurrencyMode::kSynchronous);
3059  int inobject = new_map->GetInObjectProperties();
3060  int unused = new_map->UnusedPropertyFields();
3061
3062  // Nothing to do if no functions were converted to fields and no smis were
3063  // converted to doubles.
3064  if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
3065                                       unused, &old_number_of_fields,
3066                                       ConcurrencyMode::kSynchronous)) {
3067    object->set_map(*new_map, kReleaseStore);
3068    return;
3069  }
3070
3071  int total_size = number_of_fields + unused;
3072  int external = total_size - inobject;
3073  Handle<PropertyArray> array = isolate->factory()->NewPropertyArray(external);
3074
3075  // We use this array to temporarily store the inobject properties.
3076  Handle<FixedArray> inobject_props =
3077      isolate->factory()->NewFixedArray(inobject);
3078
3079  Handle<DescriptorArray> old_descriptors(
3080      old_map->instance_descriptors(isolate), isolate);
3081  Handle<DescriptorArray> new_descriptors(
3082      new_map->instance_descriptors(isolate), isolate);
3083  int old_nof = old_map->NumberOfOwnDescriptors();
3084  int new_nof = new_map->NumberOfOwnDescriptors();
3085
3086  // This method only supports generalizing instances to at least the same
3087  // number of properties.
3088  DCHECK(old_nof <= new_nof);
3089
3090  for (InternalIndex i : InternalIndex::Range(old_nof)) {
3091    PropertyDetails details = new_descriptors->GetDetails(i);
3092    if (details.location() != PropertyLocation::kField) continue;
3093    DCHECK_EQ(PropertyKind::kData, details.kind());
3094    PropertyDetails old_details = old_descriptors->GetDetails(i);
3095    Representation old_representation = old_details.representation();
3096    Representation representation = details.representation();
3097    Handle<Object> value;
3098    if (old_details.location() == PropertyLocation::kDescriptor) {
3099      if (old_details.kind() == PropertyKind::kAccessor) {
3100        // In case of kAccessor -> kData property reconfiguration, the property
3101        // must already be prepared for data of certain type.
3102        DCHECK(!details.representation().IsNone());
3103        if (details.representation().IsDouble()) {
3104          value = isolate->factory()->NewHeapNumberWithHoleNaN();
3105        } else {
3106          value = isolate->factory()->uninitialized_value();
3107        }
3108      } else {
3109        DCHECK_EQ(PropertyKind::kData, old_details.kind());
3110        value = handle(old_descriptors->GetStrongValue(isolate, i), isolate);
3111        DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
3112      }
3113    } else {
3114      DCHECK_EQ(PropertyLocation::kField, old_details.location());
3115      FieldIndex index = FieldIndex::ForDescriptor(isolate, *old_map, i);
3116      value = handle(object->RawFastPropertyAt(isolate, index), isolate);
3117      if (!old_representation.IsDouble() && representation.IsDouble()) {
3118        DCHECK_IMPLIES(old_representation.IsNone(),
3119                       value->IsUninitialized(isolate));
3120        value = Object::NewStorageFor(isolate, value, representation);
3121      } else if (old_representation.IsDouble() && !representation.IsDouble()) {
3122        value = Object::WrapForRead(isolate, value, old_representation);
3123      }
3124    }
3125    DCHECK(!(representation.IsDouble() && value->IsSmi()));
3126    int target_index = new_descriptors->GetFieldIndex(i);
3127    if (target_index < inobject) {
3128      inobject_props->set(target_index, *value);
3129    } else {
3130      array->set(target_index - inobject, *value);
3131    }
3132  }
3133
3134  for (InternalIndex i : InternalIndex::Range(old_nof, new_nof)) {
3135    PropertyDetails details = new_descriptors->GetDetails(i);
3136    if (details.location() != PropertyLocation::kField) continue;
3137    DCHECK_EQ(PropertyKind::kData, details.kind());
3138    Handle<Object> value;
3139    if (details.representation().IsDouble()) {
3140      value = isolate->factory()->NewHeapNumberWithHoleNaN();
3141    } else {
3142      value = isolate->factory()->uninitialized_value();
3143    }
3144    int target_index = new_descriptors->GetFieldIndex(i);
3145    if (target_index < inobject) {
3146      inobject_props->set(target_index, *value);
3147    } else {
3148      array->set(target_index - inobject, *value);
3149    }
3150  }
3151
3152  // From here on we cannot fail and we shouldn't GC anymore.
3153  DisallowGarbageCollection no_gc;
3154
3155  Heap* heap = isolate->heap();
3156
3157  // Copy (real) inobject properties. If necessary, stop at number_of_fields to
3158  // avoid overwriting |one_pointer_filler_map|.
3159  int limit = std::min(inobject, number_of_fields);
3160  for (int i = 0; i < limit; i++) {
3161    FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3162    Object value = inobject_props->get(isolate, i);
3163    object->FastPropertyAtPut(index, value);
3164  }
3165
3166  object->SetProperties(*array);
3167
3168  // Create filler object past the new instance size.
3169  int old_instance_size = old_map->instance_size();
3170  int new_instance_size = new_map->instance_size();
3171  int instance_size_delta = old_instance_size - new_instance_size;
3172  DCHECK_GE(instance_size_delta, 0);
3173
3174  if (instance_size_delta > 0) {
3175    Address address = object->address();
3176    heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
3177                               ClearRecordedSlots::kYes);
3178  }
3179
3180  // We are storing the new map using release store after creating a filler for
3181  // the left-over space to avoid races with the sweeper thread.
3182  object->set_map(*new_map, kReleaseStore);
3183}
3184
3185void MigrateFastToSlow(Isolate* isolate, Handle<JSObject> object,
3186                       Handle<Map> new_map,
3187                       int expected_additional_properties) {
3188  // The global object is always normalized.
3189  DCHECK(!object->IsJSGlobalObject(isolate));
3190  // JSGlobalProxy must never be normalized
3191  DCHECK(!object->IsJSGlobalProxy(isolate));
3192
3193  DCHECK_IMPLIES(new_map->is_prototype_map(),
3194                 Map::IsPrototypeChainInvalidated(*new_map));
3195
3196  HandleScope scope(isolate);
3197  Handle<Map> map(object->map(isolate), isolate);
3198
3199  // Allocate new content.
3200  int real_size = map->NumberOfOwnDescriptors();
3201  int property_count = real_size;
3202  if (expected_additional_properties > 0) {
3203    property_count += expected_additional_properties;
3204  } else {
3205    // Make space for two more properties.
3206    int initial_capacity = V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
3207                               ? SwissNameDictionary::kInitialCapacity
3208                               : NameDictionary::kInitialCapacity;
3209    property_count += initial_capacity;
3210  }
3211
3212  Handle<NameDictionary> dictionary;
3213  Handle<SwissNameDictionary> ord_dictionary;
3214  if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
3215    ord_dictionary = isolate->factory()->NewSwissNameDictionary(property_count);
3216  } else {
3217    dictionary = isolate->factory()->NewNameDictionary(property_count);
3218  }
3219
3220  Handle<DescriptorArray> descs(map->instance_descriptors(isolate), isolate);
3221  for (InternalIndex i : InternalIndex::Range(real_size)) {
3222    PropertyDetails details = descs->GetDetails(i);
3223    Handle<Name> key(descs->GetKey(isolate, i), isolate);
3224    Handle<Object> value;
3225    if (details.location() == PropertyLocation::kField) {
3226      FieldIndex index = FieldIndex::ForDescriptor(isolate, *map, i);
3227      if (details.kind() == PropertyKind::kData) {
3228        value = handle(object->RawFastPropertyAt(isolate, index), isolate);
3229        if (details.representation().IsDouble()) {
3230          DCHECK(value->IsHeapNumber(isolate));
3231          double old_value = Handle<HeapNumber>::cast(value)->value();
3232          value = isolate->factory()->NewHeapNumber(old_value);
3233        }
3234      } else {
3235        DCHECK_EQ(PropertyKind::kAccessor, details.kind());
3236        value = handle(object->RawFastPropertyAt(isolate, index), isolate);
3237      }
3238
3239    } else {
3240      DCHECK_EQ(PropertyLocation::kDescriptor, details.location());
3241      value = handle(descs->GetStrongValue(isolate, i), isolate);
3242    }
3243    DCHECK(!value.is_null());
3244    PropertyConstness constness = V8_DICT_PROPERTY_CONST_TRACKING_BOOL
3245                                      ? details.constness()
3246                                      : PropertyConstness::kMutable;
3247    PropertyDetails d(details.kind(), details.attributes(), constness);
3248
3249    if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
3250      ord_dictionary =
3251          SwissNameDictionary::Add(isolate, ord_dictionary, key, value, d);
3252    } else {
3253      dictionary = NameDictionary::Add(isolate, dictionary, key, value, d);
3254    }
3255  }
3256
3257  if (!V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
3258    // Copy the next enumeration index from instance descriptor.
3259    dictionary->set_next_enumeration_index(real_size + 1);
3260  }
3261
3262  // From here on we cannot fail and we shouldn't GC anymore.
3263  DisallowGarbageCollection no_gc;
3264
3265  Heap* heap = isolate->heap();
3266
3267  // Resize the object in the heap if necessary.
3268  int old_instance_size = map->instance_size();
3269  int new_instance_size = new_map->instance_size();
3270  int instance_size_delta = old_instance_size - new_instance_size;
3271  DCHECK_GE(instance_size_delta, 0);
3272
3273  if (instance_size_delta > 0) {
3274    heap->CreateFillerObjectAt(object->address() + new_instance_size,
3275                               instance_size_delta, ClearRecordedSlots::kYes);
3276  }
3277
3278  // We are storing the new map using release store after creating a filler for
3279  // the left-over space to avoid races with the sweeper thread.
3280  object->set_map(*new_map, kReleaseStore);
3281
3282  if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
3283    object->SetProperties(*ord_dictionary);
3284  } else {
3285    object->SetProperties(*dictionary);
3286  }
3287
3288  // Ensure that in-object space of slow-mode object does not contain random
3289  // garbage.
3290  int inobject_properties = new_map->GetInObjectProperties();
3291  if (inobject_properties) {
3292    for (int i = 0; i < inobject_properties; i++) {
3293      FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3294      object->FastPropertyAtPut(index, Smi::zero());
3295    }
3296  }
3297
3298  isolate->counters()->props_to_dictionary()->Increment();
3299
3300#ifdef DEBUG
3301  if (FLAG_trace_normalization) {
3302    StdoutStream os;
3303    os << "Object properties have been normalized:\n";
3304    object->Print(os);
3305  }
3306#endif
3307}
3308
3309}  // namespace
3310
3311void JSObject::MigrateToMap(Isolate* isolate, Handle<JSObject> object,
3312                            Handle<Map> new_map,
3313                            int expected_additional_properties) {
3314  if (object->map(isolate) == *new_map) return;
3315  Handle<Map> old_map(object->map(isolate), isolate);
3316  NotifyMapChange(old_map, new_map, isolate);
3317
3318  if (old_map->is_dictionary_map()) {
3319    // For slow-to-fast migrations JSObject::MigrateSlowToFast()
3320    // must be used instead.
3321    CHECK(new_map->is_dictionary_map());
3322
3323    // Slow-to-slow migration is trivial.
3324    object->set_map(*new_map, kReleaseStore);
3325  } else if (!new_map->is_dictionary_map()) {
3326    MigrateFastToFast(isolate, object, new_map);
3327    if (old_map->is_prototype_map()) {
3328      DCHECK(!old_map->is_stable());
3329      DCHECK(new_map->is_stable());
3330      DCHECK(new_map->owns_descriptors());
3331      DCHECK(old_map->owns_descriptors());
3332      // Transfer ownership to the new map. Keep the descriptor pointer of the
3333      // old map intact because the concurrent marker might be iterating the
3334      // object with the old map.
3335      old_map->set_owns_descriptors(false);
3336      DCHECK(old_map->is_abandoned_prototype_map());
3337      // Ensure that no transition was inserted for prototype migrations.
3338      DCHECK_EQ(0,
3339                TransitionsAccessor(isolate, *old_map).NumberOfTransitions());
3340      DCHECK(new_map->GetBackPointer(isolate).IsUndefined(isolate));
3341      DCHECK(object->map(isolate) != *old_map);
3342    }
3343  } else {
3344    MigrateFastToSlow(isolate, object, new_map, expected_additional_properties);
3345  }
3346
3347  // Careful: Don't allocate here!
3348  // For some callers of this method, |object| might be in an inconsistent
3349  // state now: the new map might have a new elements_kind, but the object's
3350  // elements pointer hasn't been updated yet. Callers will fix this, but in
3351  // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
3352  // When adding code here, add a DisallowGarbageCollection too.
3353}
3354
3355void JSObject::ForceSetPrototype(Isolate* isolate, Handle<JSObject> object,
3356                                 Handle<HeapObject> proto) {
3357  // object.__proto__ = proto;
3358  Handle<Map> old_map = Handle<Map>(object->map(), isolate);
3359  Handle<Map> new_map = Map::Copy(isolate, old_map, "ForceSetPrototype");
3360  Map::SetPrototype(isolate, new_map, proto);
3361  JSObject::MigrateToMap(isolate, object, new_map);
3362}
3363
3364Maybe<bool> JSObject::SetPropertyWithInterceptor(
3365    LookupIterator* it, Maybe<ShouldThrow> should_throw, Handle<Object> value) {
3366  DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
3367  return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
3368                                            should_throw, value);
3369}
3370
3371Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
3372                                               ElementsKind to_kind) {
3373  Handle<Map> map(object->map(), object->GetIsolate());
3374  return Map::TransitionElementsTo(object->GetIsolate(), map, to_kind);
3375}
3376
3377void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
3378  DCHECK(object->map().GetInObjectProperties() == map->GetInObjectProperties());
3379  ElementsKind obj_kind = object->map().elements_kind();
3380  ElementsKind map_kind = map->elements_kind();
3381  Isolate* isolate = object->GetIsolate();
3382  if (map_kind != obj_kind) {
3383    ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
3384    if (IsDictionaryElementsKind(obj_kind)) {
3385      to_kind = obj_kind;
3386    }
3387    if (IsDictionaryElementsKind(to_kind)) {
3388      NormalizeElements(object);
3389    } else {
3390      TransitionElementsKind(object, to_kind);
3391    }
3392    map = MapUpdater{isolate, map}.ReconfigureElementsKind(to_kind);
3393  }
3394  int number_of_fields = map->NumberOfFields(ConcurrencyMode::kSynchronous);
3395  int inobject = map->GetInObjectProperties();
3396  int unused = map->UnusedPropertyFields();
3397  int total_size = number_of_fields + unused;
3398  int external = total_size - inobject;
3399  // Allocate mutable double boxes if necessary. It is always necessary if we
3400  // have external properties, but is also necessary if we only have inobject
3401  // properties but don't unbox double fields.
3402
3403  Handle<DescriptorArray> descriptors(map->instance_descriptors(isolate),
3404                                      isolate);
3405  Handle<FixedArray> storage = isolate->factory()->NewFixedArray(inobject);
3406
3407  Handle<PropertyArray> array = isolate->factory()->NewPropertyArray(external);
3408
3409  for (InternalIndex i : map->IterateOwnDescriptors()) {
3410    PropertyDetails details = descriptors->GetDetails(i);
3411    Representation representation = details.representation();
3412    if (!representation.IsDouble()) continue;
3413    FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3414    auto box = isolate->factory()->NewHeapNumberWithHoleNaN();
3415    if (index.is_inobject()) {
3416      storage->set(index.property_index(), *box);
3417    } else {
3418      array->set(index.outobject_array_index(), *box);
3419    }
3420  }
3421
3422  object->SetProperties(*array);
3423  for (int i = 0; i < inobject; i++) {
3424    FieldIndex index = FieldIndex::ForPropertyIndex(*map, i);
3425    Object value = storage->get(i);
3426    object->FastPropertyAtPut(index, value);
3427  }
3428  object->set_map(*map, kReleaseStore);
3429}
3430
3431void JSObject::MigrateInstance(Isolate* isolate, Handle<JSObject> object) {
3432  Handle<Map> original_map(object->map(), isolate);
3433  Handle<Map> map = Map::Update(isolate, original_map);
3434  map->set_is_migration_target(true);
3435  JSObject::MigrateToMap(isolate, object, map);
3436  if (FLAG_trace_migration) {
3437    object->PrintInstanceMigration(stdout, *original_map, *map);
3438  }
3439#if VERIFY_HEAP
3440  if (FLAG_verify_heap) {
3441    object->JSObjectVerify(isolate);
3442  }
3443#endif
3444}
3445
3446// static
3447bool JSObject::TryMigrateInstance(Isolate* isolate, Handle<JSObject> object) {
3448  DisallowDeoptimization no_deoptimization(isolate);
3449  Handle<Map> original_map(object->map(), isolate);
3450  Handle<Map> new_map;
3451  if (!Map::TryUpdate(isolate, original_map).ToHandle(&new_map)) {
3452    return false;
3453  }
3454  JSObject::MigrateToMap(isolate, object, new_map);
3455  if (FLAG_trace_migration && *original_map != object->map()) {
3456    object->PrintInstanceMigration(stdout, *original_map, object->map());
3457  }
3458#if VERIFY_HEAP
3459  if (FLAG_verify_heap) {
3460    object->JSObjectVerify(isolate);
3461  }
3462#endif
3463  return true;
3464}
3465
3466void JSObject::AddProperty(Isolate* isolate, Handle<JSObject> object,
3467                           Handle<Name> name, Handle<Object> value,
3468                           PropertyAttributes attributes) {
3469  LookupIterator it(isolate, object, name, object,
3470                    LookupIterator::OWN_SKIP_INTERCEPTOR);
3471  CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
3472#ifdef DEBUG
3473  uint32_t index;
3474  DCHECK(!object->IsJSProxy());
3475  DCHECK(!name->AsArrayIndex(&index));
3476  Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
3477  DCHECK(maybe.IsJust());
3478  DCHECK(!it.IsFound());
3479  DCHECK(object->map().is_extensible() || name->IsPrivate());
3480#endif
3481  CHECK(Object::AddDataProperty(&it, value, attributes,
3482                                Just(ShouldThrow::kThrowOnError),
3483                                StoreOrigin::kNamed)
3484            .IsJust());
3485}
3486
3487void JSObject::AddProperty(Isolate* isolate, Handle<JSObject> object,
3488                           const char* name, Handle<Object> value,
3489                           PropertyAttributes attributes) {
3490  JSObject::AddProperty(isolate, object,
3491                        isolate->factory()->InternalizeUtf8String(name), value,
3492                        attributes);
3493}
3494
3495// Reconfigures a property to a data property with attributes, even if it is not
3496// reconfigurable.
3497// Requires a LookupIterator that does not look at the prototype chain beyond
3498// hidden prototypes.
3499MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
3500    LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
3501    AccessorInfoHandling handling, EnforceDefineSemantics semantics) {
3502  MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
3503      it, value, attributes, Just(ShouldThrow::kThrowOnError), handling,
3504      semantics));
3505  return value;
3506}
3507
3508Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
3509    LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
3510    Maybe<ShouldThrow> should_throw, AccessorInfoHandling handling,
3511    EnforceDefineSemantics semantics, StoreOrigin store_origin) {
3512  it->UpdateProtector();
3513
3514  for (; it->IsFound(); it->Next()) {
3515    switch (it->state()) {
3516      case LookupIterator::JSPROXY:
3517      case LookupIterator::TRANSITION:
3518      case LookupIterator::NOT_FOUND:
3519        UNREACHABLE();
3520
3521      case LookupIterator::ACCESS_CHECK:
3522        if (!it->HasAccess()) {
3523          it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
3524          RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
3525          return Just(true);
3526        }
3527        break;
3528
3529      // If there's an interceptor, try to store the property with the
3530      // interceptor.
3531      // In case of success, the attributes will have been reset to the default
3532      // attributes of the interceptor, rather than the incoming attributes.
3533      //
3534      // TODO(verwaest): JSProxy afterwards verify the attributes that the
3535      // JSProxy claims it has, and verifies that they are compatible. If not,
3536      // they throw. Here we should do the same.
3537      case LookupIterator::INTERCEPTOR: {
3538        Maybe<bool> result = Just(false);
3539        if (semantics == EnforceDefineSemantics::kDefine) {
3540          PropertyDescriptor descriptor;
3541          descriptor.set_configurable((attributes & DONT_DELETE) != 0);
3542          descriptor.set_enumerable((attributes & DONT_ENUM) != 0);
3543          descriptor.set_writable((attributes & READ_ONLY) != 0);
3544          descriptor.set_value(value);
3545          result = DefinePropertyWithInterceptorInternal(
3546              it, it->GetInterceptor(), should_throw, &descriptor);
3547        } else {
3548          DCHECK_EQ(semantics, EnforceDefineSemantics::kSet);
3549          if (handling == DONT_FORCE_FIELD) {
3550            result =
3551                JSObject::SetPropertyWithInterceptor(it, should_throw, value);
3552          }
3553        }
3554        if (result.IsNothing() || result.FromJust()) return result;
3555
3556        if (semantics == EnforceDefineSemantics::kDefine) {
3557          it->Restart();
3558          Maybe<bool> can_define = JSReceiver::CheckIfCanDefine(
3559              it->isolate(), it, value, should_throw);
3560          if (can_define.IsNothing() || !can_define.FromJust()) {
3561            return can_define;
3562          }
3563        }
3564
3565        // The interceptor declined to handle the operation, so proceed defining
3566        // own property without the interceptor.
3567        Isolate* isolate = it->isolate();
3568        Handle<Object> receiver = it->GetReceiver();
3569        LookupIterator::Configuration c = LookupIterator::OWN_SKIP_INTERCEPTOR;
3570        LookupIterator own_lookup =
3571            it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
3572                            : LookupIterator(isolate, receiver, it->name(), c);
3573        return JSObject::DefineOwnPropertyIgnoreAttributes(
3574            &own_lookup, value, attributes, should_throw, handling, semantics,
3575            store_origin);
3576      }
3577
3578      case LookupIterator::ACCESSOR: {
3579        Handle<Object> accessors = it->GetAccessors();
3580
3581        // Special handling for AccessorInfo, which behaves like a data
3582        // property.
3583        if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
3584          PropertyAttributes current_attributes = it->property_attributes();
3585          // Ensure the context isn't changed after calling into accessors.
3586          AssertNoContextChange ncc(it->isolate());
3587
3588          // Update the attributes before calling the setter. The setter may
3589          // later change the shape of the property.
3590          if (current_attributes != attributes) {
3591            it->TransitionToAccessorPair(accessors, attributes);
3592          }
3593
3594          return Object::SetPropertyWithAccessor(it, value, should_throw);
3595        }
3596
3597        it->ReconfigureDataProperty(value, attributes);
3598        return Just(true);
3599      }
3600      case LookupIterator::INTEGER_INDEXED_EXOTIC:
3601        return Object::RedefineIncompatibleProperty(
3602            it->isolate(), it->GetName(), value, should_throw);
3603
3604      case LookupIterator::DATA: {
3605        // Regular property update if the attributes match.
3606        if (it->property_attributes() == attributes) {
3607          return Object::SetDataProperty(it, value);
3608        }
3609
3610        // The non-matching attribute case for JSTypedArrays has already been
3611        // handled by JSTypedArray::DefineOwnProperty.
3612        DCHECK(!it->IsElement() ||
3613               !Handle<JSObject>::cast(it->GetReceiver())
3614                    ->HasTypedArrayOrRabGsabTypedArrayElements());
3615        // Reconfigure the data property if the attributes mismatch.
3616        it->ReconfigureDataProperty(value, attributes);
3617
3618        return Just(true);
3619      }
3620    }
3621  }
3622
3623  return Object::AddDataProperty(it, value, attributes, should_throw,
3624                                 store_origin, semantics);
3625}
3626
3627MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
3628    Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
3629    PropertyAttributes attributes) {
3630  DCHECK(!value->IsTheHole());
3631  LookupIterator it(object->GetIsolate(), object, name, object,
3632                    LookupIterator::OWN);
3633  return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
3634}
3635
3636MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
3637    Handle<JSObject> object, size_t index, Handle<Object> value,
3638    PropertyAttributes attributes) {
3639  DCHECK(!object->IsJSTypedArray());
3640  Isolate* isolate = object->GetIsolate();
3641  LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
3642  return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
3643}
3644
3645MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
3646    Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
3647    PropertyAttributes attributes) {
3648  Isolate* isolate = object->GetIsolate();
3649  PropertyKey key(isolate, name);
3650  LookupIterator it(isolate, object, key, object, LookupIterator::OWN);
3651  return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
3652}
3653
3654Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
3655    LookupIterator* it) {
3656  return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
3657}
3658
3659void JSObject::NormalizeProperties(Isolate* isolate, Handle<JSObject> object,
3660                                   PropertyNormalizationMode mode,
3661                                   int expected_additional_properties,
3662                                   const char* reason) {
3663  if (!object->HasFastProperties()) return;
3664
3665  Handle<Map> map(object->map(), isolate);
3666  Handle<Map> new_map =
3667      Map::Normalize(isolate, map, map->elements_kind(), mode, reason);
3668
3669  JSObject::MigrateToMap(isolate, object, new_map,
3670                         expected_additional_properties);
3671}
3672
3673void JSObject::MigrateSlowToFast(Handle<JSObject> object,
3674                                 int unused_property_fields,
3675                                 const char* reason) {
3676  if (object->HasFastProperties()) return;
3677  DCHECK(!object->IsJSGlobalObject());
3678  Isolate* isolate = object->GetIsolate();
3679  Factory* factory = isolate->factory();
3680
3681  Handle<NameDictionary> dictionary;
3682  Handle<SwissNameDictionary> swiss_dictionary;
3683  int number_of_elements;
3684  if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
3685    swiss_dictionary = handle(object->property_dictionary_swiss(), isolate);
3686    number_of_elements = swiss_dictionary->NumberOfElements();
3687  } else {
3688    dictionary = handle(object->property_dictionary(), isolate);
3689    number_of_elements = dictionary->NumberOfElements();
3690  }
3691
3692  // Make sure we preserve dictionary representation if there are too many
3693  // descriptors.
3694  if (number_of_elements > kMaxNumberOfDescriptors) return;
3695
3696  Handle<FixedArray> iteration_order;
3697  int iteration_length;
3698  if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
3699    // |iteration_order| remains empty handle, we don't need it.
3700    iteration_length = swiss_dictionary->UsedCapacity();
3701  } else {
3702    iteration_order = NameDictionary::IterationIndices(isolate, dictionary);
3703    iteration_length = dictionary->NumberOfElements();
3704  }
3705
3706  int number_of_fields = 0;
3707
3708  // Compute the length of the instance descriptor.
3709  ReadOnlyRoots roots(isolate);
3710  for (int i = 0; i < iteration_length; i++) {
3711    PropertyKind kind;
3712    if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
3713      InternalIndex index(swiss_dictionary->EntryForEnumerationIndex(i));
3714      Object key = swiss_dictionary->KeyAt(index);
3715      if (!SwissNameDictionary::IsKey(roots, key)) {
3716        // Ignore deleted entries.
3717        continue;
3718      }
3719      kind = swiss_dictionary->DetailsAt(index).kind();
3720    } else {
3721      InternalIndex index(Smi::ToInt(iteration_order->get(i)));
3722      DCHECK(dictionary->IsKey(roots, dictionary->KeyAt(isolate, index)));
3723      kind = dictionary->DetailsAt(index).kind();
3724    }
3725
3726    if (kind == PropertyKind::kData) {
3727      number_of_fields += 1;
3728    }
3729  }
3730
3731  Handle<Map> old_map(object->map(), isolate);
3732
3733  int inobject_props = old_map->GetInObjectProperties();
3734
3735  // Allocate new map.
3736  Handle<Map> new_map = Map::CopyDropDescriptors(isolate, old_map);
3737  // We should not only set this bit if we need to. We should not retain the
3738  // old bit because turning a map into dictionary always sets this bit.
3739  new_map->set_may_have_interesting_symbols(new_map->has_named_interceptor() ||
3740                                            new_map->is_access_check_needed());
3741  new_map->set_is_dictionary_map(false);
3742
3743  NotifyMapChange(old_map, new_map, isolate);
3744
3745  if (number_of_elements == 0) {
3746    DisallowGarbageCollection no_gc;
3747    DCHECK_LE(unused_property_fields, inobject_props);
3748    // Transform the object.
3749    new_map->SetInObjectUnusedPropertyFields(inobject_props);
3750    object->set_map(*new_map, kReleaseStore);
3751    object->SetProperties(ReadOnlyRoots(isolate).empty_fixed_array());
3752    // Check that it really works.
3753    DCHECK(object->HasFastProperties());
3754    if (FLAG_log_maps) {
3755      LOG(isolate, MapEvent("SlowToFast", old_map, new_map, reason));
3756    }
3757    return;
3758  }
3759
3760  // Allocate the instance descriptor.
3761  Handle<DescriptorArray> descriptors =
3762      DescriptorArray::Allocate(isolate, number_of_elements, 0);
3763
3764  int number_of_allocated_fields =
3765      number_of_fields + unused_property_fields - inobject_props;
3766  if (number_of_allocated_fields < 0) {
3767    // There is enough inobject space for all fields (including unused).
3768    number_of_allocated_fields = 0;
3769    unused_property_fields = inobject_props - number_of_fields;
3770  }
3771
3772  // Allocate the property array for the fields.
3773  Handle<PropertyArray> fields =
3774      factory->NewPropertyArray(number_of_allocated_fields);
3775
3776  bool is_transitionable_elements_kind =
3777      IsTransitionableFastElementsKind(old_map->elements_kind());
3778
3779  // Fill in the instance descriptor and the fields.
3780  int current_offset = 0;
3781  int descriptor_index = 0;
3782  for (int i = 0; i < iteration_length; i++) {
3783    Name k;
3784    Object value;
3785    PropertyDetails details = PropertyDetails::Empty();
3786
3787    if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
3788      InternalIndex index(swiss_dictionary->EntryForEnumerationIndex(i));
3789      Object key_obj = swiss_dictionary->KeyAt(index);
3790      if (!SwissNameDictionary::IsKey(roots, key_obj)) {
3791        continue;
3792      }
3793      k = Name::cast(key_obj);
3794
3795      value = swiss_dictionary->ValueAt(index);
3796      details = swiss_dictionary->DetailsAt(index);
3797    } else {
3798      InternalIndex index(Smi::ToInt(iteration_order->get(i)));
3799      k = dictionary->NameAt(index);
3800
3801      value = dictionary->ValueAt(index);
3802      details = dictionary->DetailsAt(index);
3803    }
3804
3805    // Dictionary keys are internalized upon insertion.
3806    // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
3807    CHECK(k.IsUniqueName());
3808    Handle<Name> key(k, isolate);
3809
3810    // Properly mark the {new_map} if the {key} is an "interesting symbol".
3811    if (key->IsInterestingSymbol()) {
3812      new_map->set_may_have_interesting_symbols(true);
3813    }
3814
3815    DCHECK_EQ(PropertyLocation::kField, details.location());
3816    DCHECK_IMPLIES(!V8_DICT_PROPERTY_CONST_TRACKING_BOOL,
3817                   details.constness() == PropertyConstness::kMutable);
3818
3819    Descriptor d;
3820    if (details.kind() == PropertyKind::kData) {
3821      // Ensure that we make constant field only when elements kind is not
3822      // transitionable.
3823      PropertyConstness constness = is_transitionable_elements_kind
3824                                        ? PropertyConstness::kMutable
3825                                        : PropertyConstness::kConst;
3826      // TODO(v8:11248): Consider always setting constness to kMutable
3827      // once all prototypes stay in dictionary mode and we are not interested
3828      // in tracking constness for fast mode properties anymore.
3829
3830      d = Descriptor::DataField(
3831          key, current_offset, details.attributes(), constness,
3832          // TODO(verwaest): value->OptimalRepresentation();
3833          Representation::Tagged(), MaybeObjectHandle(FieldType::Any(isolate)));
3834    } else {
3835      DCHECK_EQ(PropertyKind::kAccessor, details.kind());
3836      d = Descriptor::AccessorConstant(key, handle(value, isolate),
3837                                       details.attributes());
3838    }
3839    details = d.GetDetails();
3840    if (details.location() == PropertyLocation::kField) {
3841      if (current_offset < inobject_props) {
3842        object->InObjectPropertyAtPut(current_offset, value,
3843                                      UPDATE_WRITE_BARRIER);
3844      } else {
3845        int offset = current_offset - inobject_props;
3846        fields->set(offset, value);
3847      }
3848      current_offset += details.field_width_in_words();
3849    }
3850    descriptors->Set(InternalIndex(descriptor_index++), &d);
3851  }
3852  DCHECK_EQ(current_offset, number_of_fields);
3853  DCHECK_EQ(descriptor_index, number_of_elements);
3854
3855  descriptors->Sort();
3856
3857  DisallowGarbageCollection no_gc;
3858  new_map->InitializeDescriptors(isolate, *descriptors);
3859  if (number_of_allocated_fields == 0) {
3860    new_map->SetInObjectUnusedPropertyFields(unused_property_fields);
3861  } else {
3862    new_map->SetOutOfObjectUnusedPropertyFields(unused_property_fields);
3863  }
3864
3865  if (FLAG_log_maps) {
3866    LOG(isolate, MapEvent("SlowToFast", old_map, new_map, reason));
3867  }
3868  // Transform the object.
3869  object->set_map(*new_map, kReleaseStore);
3870
3871  object->SetProperties(*fields);
3872  DCHECK(object->IsJSObject());
3873
3874  // Check that it really works.
3875  DCHECK(object->HasFastProperties());
3876}
3877
3878void JSObject::RequireSlowElements(NumberDictionary dictionary) {
3879  DCHECK_NE(dictionary,
3880            ReadOnlyRoots(GetIsolate()).empty_slow_element_dictionary());
3881  if (dictionary.requires_slow_elements()) return;
3882  dictionary.set_requires_slow_elements();
3883  if (map().is_prototype_map()) {
3884    // If this object is a prototype (the callee will check), invalidate any
3885    // prototype chains involving it.
3886    InvalidatePrototypeChains(map());
3887  }
3888}
3889
3890Handle<NumberDictionary> JSObject::NormalizeElements(Handle<JSObject> object) {
3891  DCHECK(!object->HasTypedArrayOrRabGsabTypedArrayElements());
3892  Isolate* isolate = object->GetIsolate();
3893  bool is_sloppy_arguments = object->HasSloppyArgumentsElements();
3894  {
3895    DisallowGarbageCollection no_gc;
3896    FixedArrayBase elements = object->elements();
3897
3898    if (is_sloppy_arguments) {
3899      elements = SloppyArgumentsElements::cast(elements).arguments();
3900    }
3901
3902    if (elements.IsNumberDictionary()) {
3903      return handle(NumberDictionary::cast(elements), isolate);
3904    }
3905  }
3906
3907  DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements() ||
3908         object->HasFastArgumentsElements() ||
3909         object->HasFastStringWrapperElements() ||
3910         object->HasSealedElements() || object->HasNonextensibleElements());
3911
3912  Handle<NumberDictionary> dictionary =
3913      object->GetElementsAccessor()->Normalize(object);
3914
3915  // Switch to using the dictionary as the backing storage for elements.
3916  ElementsKind target_kind = is_sloppy_arguments
3917                                 ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
3918                                 : object->HasFastStringWrapperElements()
3919                                       ? SLOW_STRING_WRAPPER_ELEMENTS
3920                                       : DICTIONARY_ELEMENTS;
3921  Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
3922  // Set the new map first to satify the elements type assert in set_elements().
3923  JSObject::MigrateToMap(isolate, object, new_map);
3924
3925  if (is_sloppy_arguments) {
3926    SloppyArgumentsElements::cast(object->elements())
3927        .set_arguments(*dictionary);
3928  } else {
3929    object->set_elements(*dictionary);
3930  }
3931
3932  isolate->counters()->elements_to_dictionary()->Increment();
3933
3934#ifdef DEBUG
3935  if (FLAG_trace_normalization) {
3936    StdoutStream os;
3937    os << "Object elements have been normalized:\n";
3938    object->Print(os);
3939  }
3940#endif
3941
3942  DCHECK(object->HasDictionaryElements() ||
3943         object->HasSlowArgumentsElements() ||
3944         object->HasSlowStringWrapperElements());
3945  return dictionary;
3946}
3947
3948Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
3949                                                    ShouldThrow should_throw) {
3950  Isolate* isolate = it->isolate();
3951  // Make sure that the top context does not change when doing callbacks or
3952  // interceptor calls.
3953  AssertNoContextChange ncc(isolate);
3954
3955  DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
3956  Handle<InterceptorInfo> interceptor(it->GetInterceptor());
3957  if (interceptor->deleter().IsUndefined(isolate)) return Nothing<bool>();
3958
3959  Handle<JSObject> holder = it->GetHolder<JSObject>();
3960  Handle<Object> receiver = it->GetReceiver();
3961  if (!receiver->IsJSReceiver()) {
3962    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
3963                                     Object::ConvertReceiver(isolate, receiver),
3964                                     Nothing<bool>());
3965  }
3966
3967  PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
3968                                 *holder, Just(should_throw));
3969  Handle<Object> result;
3970  if (it->IsElement(*holder)) {
3971    result = args.CallIndexedDeleter(interceptor, it->array_index());
3972  } else {
3973    result = args.CallNamedDeleter(interceptor, it->name());
3974  }
3975
3976  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
3977  if (result.is_null()) return Nothing<bool>();
3978
3979  DCHECK(result->IsBoolean());
3980  // Rebox CustomArguments::kReturnValueOffset before returning.
3981  return Just(result->IsTrue(isolate));
3982}
3983
3984Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
3985                                         Handle<Object> value,
3986                                         Maybe<ShouldThrow> should_throw) {
3987  DCHECK(it->GetReceiver()->IsJSObject());
3988  MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
3989  Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
3990  Isolate* isolate = receiver->GetIsolate();
3991
3992  Maybe<bool> can_define =
3993      JSReceiver::CheckIfCanDefine(isolate, it, value, should_throw);
3994  if (can_define.IsNothing() || !can_define.FromJust()) {
3995    return can_define;
3996  }
3997
3998  RETURN_ON_EXCEPTION_VALUE(it->isolate(),
3999                            DefineOwnPropertyIgnoreAttributes(it, value, NONE),
4000                            Nothing<bool>());
4001
4002  return Just(true);
4003}
4004
4005namespace {
4006
4007template <typename Dictionary>
4008bool TestDictionaryPropertiesIntegrityLevel(Dictionary dict,
4009                                            ReadOnlyRoots roots,
4010                                            PropertyAttributes level) {
4011  DCHECK(level == SEALED || level == FROZEN);
4012
4013  for (InternalIndex i : dict.IterateEntries()) {
4014    Object key;
4015    if (!dict.ToKey(roots, i, &key)) continue;
4016    if (key.FilterKey(ALL_PROPERTIES)) continue;
4017    PropertyDetails details = dict.DetailsAt(i);
4018    if (details.IsConfigurable()) return false;
4019    if (level == FROZEN && details.kind() == PropertyKind::kData &&
4020        !details.IsReadOnly()) {
4021      return false;
4022    }
4023  }
4024  return true;
4025}
4026
4027bool TestFastPropertiesIntegrityLevel(Map map, PropertyAttributes level) {
4028  DCHECK(level == SEALED || level == FROZEN);
4029  DCHECK(!map.IsCustomElementsReceiverMap());
4030  DCHECK(!map.is_dictionary_map());
4031
4032  DescriptorArray descriptors = map.instance_descriptors();
4033  for (InternalIndex i : map.IterateOwnDescriptors()) {
4034    if (descriptors.GetKey(i).IsPrivate()) continue;
4035    PropertyDetails details = descriptors.GetDetails(i);
4036    if (details.IsConfigurable()) return false;
4037    if (level == FROZEN && details.kind() == PropertyKind::kData &&
4038        !details.IsReadOnly()) {
4039      return false;
4040    }
4041  }
4042  return true;
4043}
4044
4045bool TestPropertiesIntegrityLevel(JSObject object, PropertyAttributes level) {
4046  DCHECK(!object.map().IsCustomElementsReceiverMap());
4047
4048  if (object.HasFastProperties()) {
4049    return TestFastPropertiesIntegrityLevel(object.map(), level);
4050  }
4051
4052  if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
4053    return TestDictionaryPropertiesIntegrityLevel(
4054        object.property_dictionary_swiss(), object.GetReadOnlyRoots(), level);
4055  } else {
4056    return TestDictionaryPropertiesIntegrityLevel(
4057        object.property_dictionary(), object.GetReadOnlyRoots(), level);
4058  }
4059}
4060
4061bool TestElementsIntegrityLevel(JSObject object, PropertyAttributes level) {
4062  DCHECK(!object.HasSloppyArgumentsElements());
4063
4064  ElementsKind kind = object.GetElementsKind();
4065
4066  if (IsDictionaryElementsKind(kind)) {
4067    return TestDictionaryPropertiesIntegrityLevel(
4068        NumberDictionary::cast(object.elements()), object.GetReadOnlyRoots(),
4069        level);
4070  }
4071  if (IsTypedArrayElementsKind(kind)) {
4072    if (level == FROZEN && JSArrayBufferView::cast(object).byte_length() > 0) {
4073      return false;  // TypedArrays with elements can't be frozen.
4074    }
4075    return TestPropertiesIntegrityLevel(object, level);
4076  }
4077  if (IsFrozenElementsKind(kind)) return true;
4078  if (IsSealedElementsKind(kind) && level != FROZEN) return true;
4079  if (IsNonextensibleElementsKind(kind) && level == NONE) return true;
4080
4081  ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
4082  // Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have
4083  // PropertyAttributes so just test if empty
4084  return accessor->NumberOfElements(object) == 0;
4085}
4086
4087bool FastTestIntegrityLevel(JSObject object, PropertyAttributes level) {
4088  DCHECK(!object.map().IsCustomElementsReceiverMap());
4089
4090  return !object.map().is_extensible() &&
4091         TestElementsIntegrityLevel(object, level) &&
4092         TestPropertiesIntegrityLevel(object, level);
4093}
4094
4095}  // namespace
4096
4097Maybe<bool> JSObject::TestIntegrityLevel(Handle<JSObject> object,
4098                                         IntegrityLevel level) {
4099  if (!object->map().IsCustomElementsReceiverMap() &&
4100      !object->HasSloppyArgumentsElements()) {
4101    return Just(FastTestIntegrityLevel(*object, level));
4102  }
4103  return GenericTestIntegrityLevel(Handle<JSReceiver>::cast(object), level);
4104}
4105
4106Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
4107                                        ShouldThrow should_throw) {
4108  Isolate* isolate = object->GetIsolate();
4109
4110  if (!object->HasSloppyArgumentsElements()) {
4111    return PreventExtensionsWithTransition<NONE>(object, should_throw);
4112  }
4113
4114  if (object->IsAccessCheckNeeded() &&
4115      !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
4116    isolate->ReportFailedAccessCheck(object);
4117    RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
4118    RETURN_FAILURE(isolate, should_throw,
4119                   NewTypeError(MessageTemplate::kNoAccess));
4120  }
4121
4122  if (!object->map().is_extensible()) return Just(true);
4123
4124  if (object->IsJSGlobalProxy()) {
4125    PrototypeIterator iter(isolate, object);
4126    if (iter.IsAtEnd()) return Just(true);
4127    DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4128    return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
4129                             should_throw);
4130  }
4131
4132  if (object->map().has_named_interceptor() ||
4133      object->map().has_indexed_interceptor()) {
4134    RETURN_FAILURE(isolate, should_throw,
4135                   NewTypeError(MessageTemplate::kCannotPreventExt));
4136  }
4137
4138  DCHECK(!object->HasTypedArrayOrRabGsabTypedArrayElements());
4139
4140  // Normalize fast elements.
4141  Handle<NumberDictionary> dictionary = NormalizeElements(object);
4142  DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
4143
4144  // Make sure that we never go back to fast case.
4145  if (*dictionary != ReadOnlyRoots(isolate).empty_slow_element_dictionary()) {
4146    object->RequireSlowElements(*dictionary);
4147  }
4148
4149  // Do a map transition, other objects with this map may still
4150  // be extensible.
4151  // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
4152  Handle<Map> new_map =
4153      Map::Copy(isolate, handle(object->map(), isolate), "PreventExtensions");
4154
4155  new_map->set_is_extensible(false);
4156  JSObject::MigrateToMap(isolate, object, new_map);
4157  DCHECK(!object->map().is_extensible());
4158
4159  return Just(true);
4160}
4161
4162bool JSObject::IsExtensible(Handle<JSObject> object) {
4163  Isolate* isolate = object->GetIsolate();
4164  if (object->IsAccessCheckNeeded() &&
4165      !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
4166    return true;
4167  }
4168  if (object->IsJSGlobalProxy()) {
4169    PrototypeIterator iter(isolate, *object);
4170    if (iter.IsAtEnd()) return false;
4171    DCHECK(iter.GetCurrent().IsJSGlobalObject());
4172    return iter.GetCurrent<JSObject>().map().is_extensible();
4173  }
4174  return object->map().is_extensible();
4175}
4176
4177// static
4178MaybeHandle<Object> JSObject::ReadFromOptionsBag(Handle<Object> options,
4179                                                 Handle<String> option_name,
4180                                                 Isolate* isolate) {
4181  if (options->IsJSReceiver()) {
4182    Handle<JSReceiver> js_options = Handle<JSReceiver>::cast(options);
4183    return JSObject::GetProperty(isolate, js_options, option_name);
4184  }
4185  return MaybeHandle<Object>(isolate->factory()->undefined_value());
4186}
4187
4188template <typename Dictionary>
4189void JSObject::ApplyAttributesToDictionary(
4190    Isolate* isolate, ReadOnlyRoots roots, Handle<Dictionary> dictionary,
4191    const PropertyAttributes attributes) {
4192  for (InternalIndex i : dictionary->IterateEntries()) {
4193    Object k;
4194    if (!dictionary->ToKey(roots, i, &k)) continue;
4195    if (k.FilterKey(ALL_PROPERTIES)) continue;
4196    PropertyDetails details = dictionary->DetailsAt(i);
4197    int attrs = attributes;
4198    // READ_ONLY is an invalid attribute for JS setters/getters.
4199    if ((attributes & READ_ONLY) && details.kind() == PropertyKind::kAccessor) {
4200      Object v = dictionary->ValueAt(i);
4201      if (v.IsAccessorPair()) attrs &= ~READ_ONLY;
4202    }
4203    details = details.CopyAddAttributes(PropertyAttributesFromInt(attrs));
4204    dictionary->DetailsAtPut(i, details);
4205  }
4206}
4207
4208template void JSObject::ApplyAttributesToDictionary(
4209    Isolate* isolate, ReadOnlyRoots roots, Handle<NumberDictionary> dictionary,
4210    const PropertyAttributes attributes);
4211
4212Handle<NumberDictionary> CreateElementDictionary(Isolate* isolate,
4213                                                 Handle<JSObject> object) {
4214  Handle<NumberDictionary> new_element_dictionary;
4215  if (!object->HasTypedArrayOrRabGsabTypedArrayElements() &&
4216      !object->HasDictionaryElements() &&
4217      !object->HasSlowStringWrapperElements()) {
4218    int length = object->IsJSArray()
4219                     ? Smi::ToInt(Handle<JSArray>::cast(object)->length())
4220                     : object->elements().length();
4221    new_element_dictionary =
4222        length == 0 ? isolate->factory()->empty_slow_element_dictionary()
4223                    : object->GetElementsAccessor()->Normalize(object);
4224  }
4225  return new_element_dictionary;
4226}
4227
4228template <PropertyAttributes attrs>
4229Maybe<bool> JSObject::PreventExtensionsWithTransition(
4230    Handle<JSObject> object, ShouldThrow should_throw) {
4231  STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
4232
4233  // Sealing/freezing sloppy arguments or namespace objects should be handled
4234  // elsewhere.
4235  DCHECK(!object->HasSloppyArgumentsElements());
4236  DCHECK_IMPLIES(object->IsJSModuleNamespace(), attrs == NONE);
4237
4238  Isolate* isolate = object->GetIsolate();
4239  if (object->IsAccessCheckNeeded() &&
4240      !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
4241    isolate->ReportFailedAccessCheck(object);
4242    RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
4243    RETURN_FAILURE(isolate, should_throw,
4244                   NewTypeError(MessageTemplate::kNoAccess));
4245  }
4246
4247  if (attrs == NONE && !object->map().is_extensible()) {
4248    return Just(true);
4249  }
4250
4251  {
4252    ElementsKind old_elements_kind = object->map().elements_kind();
4253    if (IsFrozenElementsKind(old_elements_kind)) return Just(true);
4254    if (attrs != FROZEN && IsSealedElementsKind(old_elements_kind)) {
4255      return Just(true);
4256    }
4257  }
4258
4259  if (object->IsJSGlobalProxy()) {
4260    PrototypeIterator iter(isolate, object);
4261    if (iter.IsAtEnd()) return Just(true);
4262    DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4263    return PreventExtensionsWithTransition<attrs>(
4264        PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
4265  }
4266
4267  if (object->map().has_named_interceptor() ||
4268      object->map().has_indexed_interceptor()) {
4269    MessageTemplate message = MessageTemplate::kNone;
4270    switch (attrs) {
4271      case NONE:
4272        message = MessageTemplate::kCannotPreventExt;
4273        break;
4274
4275      case SEALED:
4276        message = MessageTemplate::kCannotSeal;
4277        break;
4278
4279      case FROZEN:
4280        message = MessageTemplate::kCannotFreeze;
4281        break;
4282    }
4283    RETURN_FAILURE(isolate, should_throw, NewTypeError(message));
4284  }
4285
4286  Handle<Symbol> transition_marker;
4287  if (attrs == NONE) {
4288    transition_marker = isolate->factory()->nonextensible_symbol();
4289  } else if (attrs == SEALED) {
4290    transition_marker = isolate->factory()->sealed_symbol();
4291  } else {
4292    DCHECK(attrs == FROZEN);
4293    transition_marker = isolate->factory()->frozen_symbol();
4294  }
4295
4296  // Currently, there are only have sealed/frozen Object element kinds and
4297  // Map::MigrateToMap doesn't handle properties' attributes reconfiguring and
4298  // elements kind change in one go. If seal or freeze with Smi or Double
4299  // elements kind, we will transition to Object elements kind first to make
4300  // sure of valid element access.
4301  if (FLAG_enable_sealed_frozen_elements_kind) {
4302    switch (object->map().elements_kind()) {
4303      case PACKED_SMI_ELEMENTS:
4304      case PACKED_DOUBLE_ELEMENTS:
4305        JSObject::TransitionElementsKind(object, PACKED_ELEMENTS);
4306        break;
4307      case HOLEY_SMI_ELEMENTS:
4308      case HOLEY_DOUBLE_ELEMENTS:
4309        JSObject::TransitionElementsKind(object, HOLEY_ELEMENTS);
4310        break;
4311      default:
4312        break;
4313    }
4314  }
4315
4316  // Make sure we only use this element dictionary in case we can't transition
4317  // to sealed, frozen elements kind.
4318  Handle<NumberDictionary> new_element_dictionary;
4319
4320  Handle<Map> old_map(object->map(), isolate);
4321  old_map = Map::Update(isolate, old_map);
4322  Handle<Map> transition_map;
4323  MaybeHandle<Map> maybe_transition_map =
4324      TransitionsAccessor::SearchSpecial(isolate, old_map, *transition_marker);
4325  if (maybe_transition_map.ToHandle(&transition_map)) {
4326    DCHECK(transition_map->has_dictionary_elements() ||
4327           transition_map->has_typed_array_or_rab_gsab_typed_array_elements() ||
4328           transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS ||
4329           transition_map->has_any_nonextensible_elements());
4330    DCHECK(!transition_map->is_extensible());
4331    if (!transition_map->has_any_nonextensible_elements()) {
4332      new_element_dictionary = CreateElementDictionary(isolate, object);
4333    }
4334    JSObject::MigrateToMap(isolate, object, transition_map);
4335  } else if (TransitionsAccessor::CanHaveMoreTransitions(isolate, old_map)) {
4336    // Create a new descriptor array with the appropriate property attributes
4337    Handle<Map> new_map = Map::CopyForPreventExtensions(
4338        isolate, old_map, attrs, transition_marker, "CopyForPreventExtensions");
4339    if (!new_map->has_any_nonextensible_elements()) {
4340      new_element_dictionary = CreateElementDictionary(isolate, object);
4341    }
4342    JSObject::MigrateToMap(isolate, object, new_map);
4343  } else {
4344    DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
4345    // Slow path: need to normalize properties for safety
4346    NormalizeProperties(isolate, object, CLEAR_INOBJECT_PROPERTIES, 0,
4347                        "SlowPreventExtensions");
4348
4349    // Create a new map, since other objects with this map may be extensible.
4350    // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
4351    Handle<Map> new_map = Map::Copy(isolate, handle(object->map(), isolate),
4352                                    "SlowCopyForPreventExtensions");
4353    new_map->set_is_extensible(false);
4354    new_element_dictionary = CreateElementDictionary(isolate, object);
4355    if (!new_element_dictionary.is_null()) {
4356      ElementsKind new_kind =
4357          IsStringWrapperElementsKind(old_map->elements_kind())
4358              ? SLOW_STRING_WRAPPER_ELEMENTS
4359              : DICTIONARY_ELEMENTS;
4360      new_map->set_elements_kind(new_kind);
4361    }
4362    JSObject::MigrateToMap(isolate, object, new_map);
4363
4364    if (attrs != NONE) {
4365      ReadOnlyRoots roots(isolate);
4366      if (object->IsJSGlobalObject()) {
4367        Handle<GlobalDictionary> dictionary(
4368            JSGlobalObject::cast(*object).global_dictionary(kAcquireLoad),
4369            isolate);
4370        JSObject::ApplyAttributesToDictionary(isolate, roots, dictionary,
4371                                              attrs);
4372      } else if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
4373        Handle<SwissNameDictionary> dictionary(
4374            object->property_dictionary_swiss(), isolate);
4375        JSObject::ApplyAttributesToDictionary(isolate, roots, dictionary,
4376                                              attrs);
4377      } else {
4378        Handle<NameDictionary> dictionary(object->property_dictionary(),
4379                                          isolate);
4380        JSObject::ApplyAttributesToDictionary(isolate, roots, dictionary,
4381                                              attrs);
4382      }
4383    }
4384  }
4385
4386  if (object->map().has_any_nonextensible_elements()) {
4387    DCHECK(new_element_dictionary.is_null());
4388    return Just(true);
4389  }
4390
4391  // Both seal and preventExtensions always go through without modifications to
4392  // typed array elements. Freeze works only if there are no actual elements.
4393  if (object->HasTypedArrayOrRabGsabTypedArrayElements()) {
4394    DCHECK(new_element_dictionary.is_null());
4395    if (attrs == FROZEN && JSTypedArray::cast(*object).GetLength() > 0) {
4396      isolate->Throw(*isolate->factory()->NewTypeError(
4397          MessageTemplate::kCannotFreezeArrayBufferView));
4398      return Nothing<bool>();
4399    }
4400    return Just(true);
4401  }
4402
4403  DCHECK(object->map().has_dictionary_elements() ||
4404         object->map().elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
4405  if (!new_element_dictionary.is_null()) {
4406    object->set_elements(*new_element_dictionary);
4407  }
4408
4409  if (object->elements() !=
4410      ReadOnlyRoots(isolate).empty_slow_element_dictionary()) {
4411    Handle<NumberDictionary> dictionary(object->element_dictionary(), isolate);
4412    // Make sure we never go back to the fast case
4413    object->RequireSlowElements(*dictionary);
4414    if (attrs != NONE) {
4415      JSObject::ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate),
4416                                            dictionary, attrs);
4417    }
4418  }
4419
4420  return Just(true);
4421}
4422
4423Handle<Object> JSObject::FastPropertyAt(Isolate* isolate,
4424                                        Handle<JSObject> object,
4425                                        Representation representation,
4426                                        FieldIndex index) {
4427  Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
4428  return Object::WrapForRead(isolate, raw_value, representation);
4429}
4430
4431Handle<Object> JSObject::FastPropertyAt(Isolate* isolate,
4432                                        Handle<JSObject> object,
4433                                        Representation representation,
4434                                        FieldIndex index, SeqCstAccessTag tag) {
4435  Handle<Object> raw_value(object->RawFastPropertyAt(index, tag), isolate);
4436  return Object::WrapForRead(isolate, raw_value, representation);
4437}
4438
4439// static
4440Handle<Object> JSObject::DictionaryPropertyAt(Isolate* isolate,
4441                                              Handle<JSObject> object,
4442                                              InternalIndex dict_index) {
4443  DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
4444  if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
4445    SwissNameDictionary dict = object->property_dictionary_swiss();
4446    return handle(dict.ValueAt(dict_index), isolate);
4447  } else {
4448    NameDictionary dict = object->property_dictionary();
4449    return handle(dict.ValueAt(dict_index), isolate);
4450  }
4451}
4452
4453// static
4454base::Optional<Object> JSObject::DictionaryPropertyAt(Handle<JSObject> object,
4455                                                      InternalIndex dict_index,
4456                                                      Heap* heap) {
4457  Object backing_store = object->raw_properties_or_hash(kRelaxedLoad);
4458  if (!backing_store.IsHeapObject()) return {};
4459  if (heap->IsPendingAllocation(HeapObject::cast(backing_store))) return {};
4460
4461  base::Optional<Object> maybe_obj;
4462  if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
4463    if (!backing_store.IsSwissNameDictionary()) return {};
4464    maybe_obj = SwissNameDictionary::cast(backing_store).TryValueAt(dict_index);
4465  } else {
4466    if (!backing_store.IsNameDictionary()) return {};
4467    maybe_obj = NameDictionary::cast(backing_store).TryValueAt(dict_index);
4468  }
4469
4470  if (!maybe_obj) return {};
4471  return maybe_obj.value();
4472}
4473
4474// TODO(cbruni/jkummerow): Consider moving this into elements.cc.
4475bool JSObject::HasEnumerableElements() {
4476  // TODO(cbruni): cleanup
4477  JSObject object = *this;
4478  switch (object.GetElementsKind()) {
4479    case PACKED_SMI_ELEMENTS:
4480    case PACKED_ELEMENTS:
4481    case PACKED_FROZEN_ELEMENTS:
4482    case PACKED_SEALED_ELEMENTS:
4483    case PACKED_NONEXTENSIBLE_ELEMENTS:
4484    case PACKED_DOUBLE_ELEMENTS: {
4485      int length = object.IsJSArray()
4486                       ? Smi::ToInt(JSArray::cast(object).length())
4487                       : object.elements().length();
4488      return length > 0;
4489    }
4490    case HOLEY_SMI_ELEMENTS:
4491    case HOLEY_FROZEN_ELEMENTS:
4492    case HOLEY_SEALED_ELEMENTS:
4493    case HOLEY_NONEXTENSIBLE_ELEMENTS:
4494    case HOLEY_ELEMENTS: {
4495      FixedArray elements = FixedArray::cast(object.elements());
4496      int length = object.IsJSArray()
4497                       ? Smi::ToInt(JSArray::cast(object).length())
4498                       : elements.length();
4499      Isolate* isolate = GetIsolate();
4500      for (int i = 0; i < length; i++) {
4501        if (!elements.is_the_hole(isolate, i)) return true;
4502      }
4503      return false;
4504    }
4505    case HOLEY_DOUBLE_ELEMENTS: {
4506      int length = object.IsJSArray()
4507                       ? Smi::ToInt(JSArray::cast(object).length())
4508                       : object.elements().length();
4509      // Zero-length arrays would use the empty FixedArray...
4510      if (length == 0) return false;
4511      // ...so only cast to FixedDoubleArray otherwise.
4512      FixedDoubleArray elements = FixedDoubleArray::cast(object.elements());
4513      for (int i = 0; i < length; i++) {
4514        if (!elements.is_the_hole(i)) return true;
4515      }
4516      return false;
4517    }
4518#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
4519
4520      TYPED_ARRAYS(TYPED_ARRAY_CASE) {
4521        size_t length = JSTypedArray::cast(object).length();
4522        return length > 0;
4523      }
4524
4525      RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE)
4526#undef TYPED_ARRAY_CASE
4527      {
4528        size_t length = JSTypedArray::cast(object).GetLength();
4529        return length > 0;
4530      }
4531    case DICTIONARY_ELEMENTS: {
4532      NumberDictionary elements = NumberDictionary::cast(object.elements());
4533      return elements.NumberOfEnumerableProperties() > 0;
4534    }
4535    case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
4536    case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
4537      // We're approximating non-empty arguments objects here.
4538      return true;
4539    case FAST_STRING_WRAPPER_ELEMENTS:
4540    case SLOW_STRING_WRAPPER_ELEMENTS:
4541      if (String::cast(JSPrimitiveWrapper::cast(object).value()).length() > 0) {
4542        return true;
4543      }
4544      return object.elements().length() > 0;
4545    case WASM_ARRAY_ELEMENTS:
4546      UNIMPLEMENTED();
4547
4548    case NO_ELEMENTS:
4549      return false;
4550  }
4551  UNREACHABLE();
4552}
4553
4554MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
4555                                             Handle<Name> name,
4556                                             Handle<Object> getter,
4557                                             Handle<Object> setter,
4558                                             PropertyAttributes attributes) {
4559  Isolate* isolate = object->GetIsolate();
4560
4561  PropertyKey key(isolate, name);
4562  LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
4563  return DefineAccessor(&it, getter, setter, attributes);
4564}
4565
4566MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
4567                                             Handle<Object> getter,
4568                                             Handle<Object> setter,
4569                                             PropertyAttributes attributes) {
4570  Isolate* isolate = it->isolate();
4571
4572  it->UpdateProtector();
4573
4574  if (it->state() == LookupIterator::ACCESS_CHECK) {
4575    if (!it->HasAccess()) {
4576      isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
4577      RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
4578      return isolate->factory()->undefined_value();
4579    }
4580    it->Next();
4581  }
4582
4583  Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
4584  // Ignore accessors on typed arrays.
4585  if (it->IsElement() && object->HasTypedArrayOrRabGsabTypedArrayElements()) {
4586    return it->factory()->undefined_value();
4587  }
4588
4589  DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
4590         getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
4591  DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
4592         setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
4593  it->TransitionToAccessorProperty(getter, setter, attributes);
4594
4595  return isolate->factory()->undefined_value();
4596}
4597
4598MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
4599                                          Handle<Name> name,
4600                                          Handle<AccessorInfo> info,
4601                                          PropertyAttributes attributes) {
4602  Isolate* isolate = object->GetIsolate();
4603
4604  PropertyKey key(isolate, name);
4605  LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
4606
4607  // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
4608  // the FailedAccessCheckCallbackFunction doesn't throw an exception.
4609  //
4610  // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
4611  // remove reliance on default return values.
4612  if (it.state() == LookupIterator::ACCESS_CHECK) {
4613    if (!it.HasAccess()) {
4614      isolate->ReportFailedAccessCheck(object);
4615      RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
4616      return it.factory()->undefined_value();
4617    }
4618    it.Next();
4619  }
4620
4621  // Ignore accessors on typed arrays.
4622  if (it.IsElement() && object->HasTypedArrayOrRabGsabTypedArrayElements()) {
4623    return it.factory()->undefined_value();
4624  }
4625
4626  CHECK(GetPropertyAttributes(&it).IsJust());
4627
4628  // ES5 forbids turning a property into an accessor if it's not
4629  // configurable. See 8.6.1 (Table 5).
4630  if (it.IsFound() && !it.IsConfigurable()) {
4631    return it.factory()->undefined_value();
4632  }
4633
4634  it.TransitionToAccessorPair(info, attributes);
4635
4636  return object;
4637}
4638
4639Object JSObject::SlowReverseLookup(Object value) {
4640  if (HasFastProperties()) {
4641    DescriptorArray descs = map().instance_descriptors();
4642    bool value_is_number = value.IsNumber();
4643    for (InternalIndex i : map().IterateOwnDescriptors()) {
4644      PropertyDetails details = descs.GetDetails(i);
4645      if (details.location() == PropertyLocation::kField) {
4646        DCHECK_EQ(PropertyKind::kData, details.kind());
4647        FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
4648        Object property = RawFastPropertyAt(field_index);
4649        if (field_index.is_double()) {
4650          DCHECK(property.IsHeapNumber());
4651          if (value_is_number && property.Number() == value.Number()) {
4652            return descs.GetKey(i);
4653          }
4654        } else if (property == value) {
4655          return descs.GetKey(i);
4656        }
4657      } else {
4658        DCHECK_EQ(PropertyLocation::kDescriptor, details.location());
4659        if (details.kind() == PropertyKind::kData) {
4660          if (descs.GetStrongValue(i) == value) {
4661            return descs.GetKey(i);
4662          }
4663        }
4664      }
4665    }
4666    return GetReadOnlyRoots().undefined_value();
4667  } else if (IsJSGlobalObject()) {
4668    return JSGlobalObject::cast(*this)
4669        .global_dictionary(kAcquireLoad)
4670        .SlowReverseLookup(value);
4671  } else if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
4672    return property_dictionary_swiss().SlowReverseLookup(GetIsolate(), value);
4673  } else {
4674    return property_dictionary().SlowReverseLookup(value);
4675  }
4676}
4677
4678void JSObject::PrototypeRegistryCompactionCallback(HeapObject value,
4679                                                   int old_index,
4680                                                   int new_index) {
4681  DCHECK(value.IsMap() && Map::cast(value).is_prototype_map());
4682  Map map = Map::cast(value);
4683  DCHECK(map.prototype_info().IsPrototypeInfo());
4684  PrototypeInfo proto_info = PrototypeInfo::cast(map.prototype_info());
4685  DCHECK_EQ(old_index, proto_info.registry_slot());
4686  proto_info.set_registry_slot(new_index);
4687}
4688
4689// static
4690void JSObject::MakePrototypesFast(Handle<Object> receiver,
4691                                  WhereToStart where_to_start,
4692                                  Isolate* isolate) {
4693  if (!receiver->IsJSReceiver()) return;
4694  for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
4695                              where_to_start);
4696       !iter.IsAtEnd(); iter.Advance()) {
4697    Handle<Object> current = PrototypeIterator::GetCurrent(iter);
4698    if (!current->IsJSObject()) return;
4699    Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
4700    Map current_map = current_obj->map();
4701    if (current_map.is_prototype_map()) {
4702      // If the map is already marked as should be fast, we're done. Its
4703      // prototypes will have been marked already as well.
4704      if (current_map.should_be_fast_prototype_map()) return;
4705      Handle<Map> map(current_map, isolate);
4706      Map::SetShouldBeFastPrototypeMap(map, true, isolate);
4707      JSObject::OptimizeAsPrototype(current_obj);
4708    }
4709  }
4710}
4711
4712static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
4713  DisallowGarbageCollection no_gc;
4714  if (!object->HasFastProperties()) return false;
4715  if (object->IsJSGlobalProxy()) return false;
4716  // TODO(v8:11248) make bootstrapper create dict mode prototypes, too?
4717  if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
4718  if (V8_DICT_PROPERTY_CONST_TRACKING_BOOL) return true;
4719  return !object->map().is_prototype_map() ||
4720         !object->map().should_be_fast_prototype_map();
4721}
4722
4723// static
4724void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
4725                                   bool enable_setup_mode) {
4726  Isolate* isolate = object->GetIsolate();
4727  if (object->IsJSGlobalObject()) return;
4728  if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) {
4729    // First normalize to ensure all JSFunctions are DATA_CONSTANT.
4730    JSObject::NormalizeProperties(isolate, object, KEEP_INOBJECT_PROPERTIES, 0,
4731                                  "NormalizeAsPrototype");
4732  }
4733  if (object->map().is_prototype_map()) {
4734    if (!V8_DICT_PROPERTY_CONST_TRACKING_BOOL &&
4735        object->map().should_be_fast_prototype_map() &&
4736        !object->HasFastProperties()) {
4737      JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
4738    }
4739  } else {
4740    Handle<Map> new_map =
4741        Map::Copy(isolate, handle(object->map(), isolate), "CopyAsPrototype");
4742    new_map->set_is_prototype_map(true);
4743
4744    // Replace the pointer to the exact constructor with the Object function
4745    // from the same context if undetectable from JS. This is to avoid keeping
4746    // memory alive unnecessarily.
4747    Object maybe_constructor = new_map->GetConstructor();
4748    if (maybe_constructor.IsJSFunction()) {
4749      JSFunction constructor = JSFunction::cast(maybe_constructor);
4750      if (!constructor.shared().IsApiFunction()) {
4751        Context context = constructor.native_context();
4752        JSFunction object_function = context.object_function();
4753        new_map->SetConstructor(object_function);
4754      }
4755    }
4756    JSObject::MigrateToMap(isolate, object, new_map);
4757
4758    if (V8_DICT_PROPERTY_CONST_TRACKING_BOOL && !object->HasFastProperties()) {
4759      ReadOnlyRoots roots(isolate);
4760      DisallowHeapAllocation no_gc;
4761
4762      auto make_constant = [&](auto dict) {
4763        for (InternalIndex index : dict.IterateEntries()) {
4764          Object k;
4765          if (!dict.ToKey(roots, index, &k)) continue;
4766
4767          PropertyDetails details = dict.DetailsAt(index);
4768          details = details.CopyWithConstness(PropertyConstness::kConst);
4769          dict.DetailsAtPut(index, details);
4770        }
4771      };
4772      if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
4773        make_constant(object->property_dictionary_swiss());
4774      } else {
4775        make_constant(object->property_dictionary());
4776      }
4777    }
4778  }
4779#ifdef DEBUG
4780  bool should_be_dictionary = V8_DICT_PROPERTY_CONST_TRACKING_BOOL &&
4781                              enable_setup_mode && !object->IsJSGlobalProxy() &&
4782                              !object->GetIsolate()->bootstrapper()->IsActive();
4783  DCHECK_IMPLIES(should_be_dictionary, object->map().is_dictionary_map());
4784#endif
4785}
4786
4787// static
4788void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
4789  if (!object->map().is_prototype_map()) return;
4790  if (!object->map().should_be_fast_prototype_map()) return;
4791  OptimizeAsPrototype(object);
4792}
4793
4794// static
4795void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
4796  // Contract: In line with InvalidatePrototypeChains()'s requirements,
4797  // leaf maps don't need to register as users, only prototypes do.
4798  DCHECK(user->is_prototype_map());
4799
4800  Handle<Map> current_user = user;
4801  Handle<PrototypeInfo> current_user_info =
4802      Map::GetOrCreatePrototypeInfo(user, isolate);
4803  for (PrototypeIterator iter(isolate, user); !iter.IsAtEnd(); iter.Advance()) {
4804    // Walk up the prototype chain as far as links haven't been registered yet.
4805    if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
4806      break;
4807    }
4808    Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
4809    // Proxies on the prototype chain are not supported. They make it
4810    // impossible to make any assumptions about the prototype chain anyway.
4811    if (maybe_proto->IsJSProxy()) return;
4812    Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
4813    Handle<PrototypeInfo> proto_info =
4814        Map::GetOrCreatePrototypeInfo(proto, isolate);
4815    Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
4816    Handle<WeakArrayList> registry =
4817        maybe_registry->IsSmi()
4818            ? handle(ReadOnlyRoots(isolate->heap()).empty_weak_array_list(),
4819                     isolate)
4820            : Handle<WeakArrayList>::cast(maybe_registry);
4821    int slot = 0;
4822    Handle<WeakArrayList> new_array =
4823        PrototypeUsers::Add(isolate, registry, current_user, &slot);
4824    current_user_info->set_registry_slot(slot);
4825    if (!maybe_registry.is_identical_to(new_array)) {
4826      proto_info->set_prototype_users(*new_array);
4827    }
4828    if (FLAG_trace_prototype_users) {
4829      PrintF("Registering %p as a user of prototype %p (map=%p).\n",
4830             reinterpret_cast<void*>(current_user->ptr()),
4831             reinterpret_cast<void*>(proto->ptr()),
4832             reinterpret_cast<void*>(proto->map().ptr()));
4833    }
4834
4835    current_user = handle(proto->map(), isolate);
4836    current_user_info = proto_info;
4837  }
4838}
4839
4840// Can be called regardless of whether |user| was actually registered with
4841// |prototype|. Returns true when there was a registration.
4842// static
4843bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
4844  DCHECK(user->is_prototype_map());
4845  // If it doesn't have a PrototypeInfo, it was never registered.
4846  if (!user->prototype_info().IsPrototypeInfo()) return false;
4847  // If it had no prototype before, see if it had users that might expect
4848  // registration.
4849  if (!user->prototype().IsJSObject()) {
4850    Object users =
4851        PrototypeInfo::cast(user->prototype_info()).prototype_users();
4852    return users.IsWeakArrayList();
4853  }
4854  Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
4855  Handle<PrototypeInfo> user_info =
4856      Map::GetOrCreatePrototypeInfo(user, isolate);
4857  int slot = user_info->registry_slot();
4858  if (slot == PrototypeInfo::UNREGISTERED) return false;
4859  DCHECK(prototype->map().is_prototype_map());
4860  Object maybe_proto_info = prototype->map().prototype_info();
4861  // User knows its registry slot, prototype info and user registry must exist.
4862  DCHECK(maybe_proto_info.IsPrototypeInfo());
4863  Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
4864                                   isolate);
4865  Handle<WeakArrayList> prototype_users(
4866      WeakArrayList::cast(proto_info->prototype_users()), isolate);
4867  DCHECK_EQ(prototype_users->Get(slot), HeapObjectReference::Weak(*user));
4868  PrototypeUsers::MarkSlotEmpty(*prototype_users, slot);
4869  if (FLAG_trace_prototype_users) {
4870    PrintF("Unregistering %p as a user of prototype %p.\n",
4871           reinterpret_cast<void*>(user->ptr()),
4872           reinterpret_cast<void*>(prototype->ptr()));
4873  }
4874  return true;
4875}
4876
4877namespace {
4878
4879// This function must be kept in sync with
4880// AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks
4881// before jumping here.
4882void InvalidateOnePrototypeValidityCellInternal(Map map) {
4883  DCHECK(map.is_prototype_map());
4884  if (FLAG_trace_prototype_users) {
4885    PrintF("Invalidating prototype map %p 's cell\n",
4886           reinterpret_cast<void*>(map.ptr()));
4887  }
4888  Object maybe_cell = map.prototype_validity_cell();
4889  if (maybe_cell.IsCell()) {
4890    // Just set the value; the cell will be replaced lazily.
4891    Cell cell = Cell::cast(maybe_cell);
4892    cell.set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
4893  }
4894  Object maybe_prototype_info = map.prototype_info();
4895  if (maybe_prototype_info.IsPrototypeInfo()) {
4896    PrototypeInfo prototype_info = PrototypeInfo::cast(maybe_prototype_info);
4897    prototype_info.set_prototype_chain_enum_cache(Object());
4898  }
4899
4900  // We may inline accesses to constants stored in dictionary mode protoypes in
4901  // optimized code. When doing so, we install depenendies of group
4902  // |kPrototypeCheckGroup| on each prototype between the receiver's immediate
4903  // prototype and the holder of the constant property. This dependency is used
4904  // both to detect changes to the constant value itself, and other changes to
4905  // the prototype chain that invalidate the access to the given property from
4906  // the given receiver (like adding the property to another prototype between
4907  // the receiver and the (previous) holder). This works by de-opting this group
4908  // whenever the validity cell would be invalidated. However, the actual value
4909  // of the validity cell is not used. Therefore, we always trigger the de-opt
4910  // here, even if the cell was already invalid.
4911  if (V8_DICT_PROPERTY_CONST_TRACKING_BOOL && map.is_dictionary_map()) {
4912    // TODO(11527): pass Isolate as an argument.
4913    Isolate* isolate = GetIsolateFromWritableObject(map);
4914    map.dependent_code().DeoptimizeDependentCodeGroup(
4915        isolate, DependentCode::kPrototypeCheckGroup);
4916  }
4917}
4918
4919void InvalidatePrototypeChainsInternal(Map map) {
4920  // We handle linear prototype chains by looping, and multiple children
4921  // by recursion, in order to reduce the likelihood of running into stack
4922  // overflows. So, conceptually, the outer loop iterates the depth of the
4923  // prototype tree, and the inner loop iterates the breadth of a node.
4924  Map next_map;
4925  for (; !map.is_null(); map = next_map, next_map = Map()) {
4926    InvalidateOnePrototypeValidityCellInternal(map);
4927
4928    Object maybe_proto_info = map.prototype_info();
4929    if (!maybe_proto_info.IsPrototypeInfo()) return;
4930    PrototypeInfo proto_info = PrototypeInfo::cast(maybe_proto_info);
4931    if (!proto_info.prototype_users().IsWeakArrayList()) {
4932      return;
4933    }
4934    WeakArrayList prototype_users =
4935        WeakArrayList::cast(proto_info.prototype_users());
4936    // For now, only maps register themselves as users.
4937    for (int i = PrototypeUsers::kFirstIndex; i < prototype_users.length();
4938         ++i) {
4939      HeapObject heap_object;
4940      if (prototype_users.Get(i)->GetHeapObjectIfWeak(&heap_object) &&
4941          heap_object.IsMap()) {
4942        // Walk the prototype chain (backwards, towards leaf objects) if
4943        // necessary.
4944        if (next_map.is_null()) {
4945          next_map = Map::cast(heap_object);
4946        } else {
4947          InvalidatePrototypeChainsInternal(Map::cast(heap_object));
4948        }
4949      }
4950    }
4951  }
4952}
4953
4954}  // namespace
4955
4956// static
4957Map JSObject::InvalidatePrototypeChains(Map map) {
4958  DisallowGarbageCollection no_gc;
4959  InvalidatePrototypeChainsInternal(map);
4960  return map;
4961}
4962
4963// We also invalidate global objects validity cell when a new lexical
4964// environment variable is added. This is necessary to ensure that
4965// Load/StoreGlobalIC handlers that load/store from global object's prototype
4966// get properly invalidated.
4967// Note, that the normal Load/StoreICs that load/store through the global object
4968// in the prototype chain are not affected by appearance of a new lexical
4969// variable and therefore we don't propagate invalidation down.
4970// static
4971void JSObject::InvalidatePrototypeValidityCell(JSGlobalObject global) {
4972  DisallowGarbageCollection no_gc;
4973  InvalidateOnePrototypeValidityCellInternal(global.map());
4974}
4975
4976Maybe<bool> JSObject::SetPrototype(Isolate* isolate, Handle<JSObject> object,
4977                                   Handle<Object> value, bool from_javascript,
4978                                   ShouldThrow should_throw) {
4979#ifdef DEBUG
4980  int size = object->Size();
4981#endif
4982
4983  if (from_javascript) {
4984    if (object->IsAccessCheckNeeded() &&
4985        !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
4986      isolate->ReportFailedAccessCheck(object);
4987      RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
4988      RETURN_FAILURE(isolate, should_throw,
4989                     NewTypeError(MessageTemplate::kNoAccess));
4990    }
4991  } else {
4992    DCHECK(!object->IsAccessCheckNeeded());
4993  }
4994
4995  // Silently ignore the change if value is not a JSObject or null.
4996  // SpiderMonkey behaves this way.
4997  if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
4998
4999  bool all_extensible = object->map().is_extensible();
5000  Handle<JSObject> real_receiver = object;
5001  if (from_javascript) {
5002    // Find the first object in the chain whose prototype object is not
5003    // hidden.
5004    PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
5005                           PrototypeIterator::END_AT_NON_HIDDEN);
5006    while (!iter.IsAtEnd()) {
5007      // Casting to JSObject is fine because hidden prototypes are never
5008      // JSProxies.
5009      real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
5010      iter.Advance();
5011      all_extensible = all_extensible && real_receiver->map().is_extensible();
5012    }
5013  }
5014  Handle<Map> map(real_receiver->map(), isolate);
5015
5016  // Nothing to do if prototype is already set.
5017  if (map->prototype() == *value) return Just(true);
5018
5019  bool immutable_proto = map->is_immutable_proto();
5020  if (immutable_proto) {
5021    RETURN_FAILURE(
5022        isolate, should_throw,
5023        NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
5024  }
5025
5026  // From 6.1.7.3 Invariants of the Essential Internal Methods
5027  //
5028  // [[SetPrototypeOf]] ( V )
5029  // * ...
5030  // * If target is non-extensible, [[SetPrototypeOf]] must return false,
5031  //   unless V is the SameValue as the target's observed [[GetPrototypeOf]]
5032  //   value.
5033  if (!all_extensible) {
5034    RETURN_FAILURE(isolate, should_throw,
5035                   NewTypeError(MessageTemplate::kNonExtensibleProto, object));
5036  }
5037
5038  // Before we can set the prototype we need to be sure prototype cycles are
5039  // prevented.  It is sufficient to validate that the receiver is not in the
5040  // new prototype chain.
5041  if (value->IsJSReceiver()) {
5042    for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
5043                                kStartAtReceiver);
5044         !iter.IsAtEnd(); iter.Advance()) {
5045      if (iter.GetCurrent<JSReceiver>() == *object) {
5046        // Cycle detected.
5047        RETURN_FAILURE(isolate, should_throw,
5048                       NewTypeError(MessageTemplate::kCyclicProto));
5049      }
5050    }
5051  }
5052
5053  // Set the new prototype of the object.
5054
5055  isolate->UpdateNoElementsProtectorOnSetPrototype(real_receiver);
5056
5057  Handle<Map> new_map =
5058      Map::TransitionToPrototype(isolate, map, Handle<HeapObject>::cast(value));
5059  DCHECK(new_map->prototype() == *value);
5060  JSObject::MigrateToMap(isolate, real_receiver, new_map);
5061
5062  DCHECK(size == object->Size());
5063  return Just(true);
5064}
5065
5066// static
5067void JSObject::SetImmutableProto(Handle<JSObject> object) {
5068  Handle<Map> map(object->map(), object->GetIsolate());
5069
5070  // Nothing to do if prototype is already set.
5071  if (map->is_immutable_proto()) return;
5072
5073  Handle<Map> new_map =
5074      Map::TransitionToImmutableProto(object->GetIsolate(), map);
5075  object->set_map(*new_map, kReleaseStore);
5076}
5077
5078void JSObject::EnsureCanContainElements(Handle<JSObject> object,
5079                                        JavaScriptArguments* args,
5080                                        uint32_t arg_count,
5081                                        EnsureElementsMode mode) {
5082  return EnsureCanContainElements(object, args->first_slot(), arg_count, mode);
5083}
5084
5085void JSObject::ValidateElements(JSObject object) {
5086#ifdef ENABLE_SLOW_DCHECKS
5087  if (FLAG_enable_slow_asserts) {
5088    object.GetElementsAccessor()->Validate(object);
5089  }
5090#endif
5091}
5092
5093bool JSObject::WouldConvertToSlowElements(uint32_t index) {
5094  if (!HasFastElements()) return false;
5095  uint32_t capacity = static_cast<uint32_t>(elements().length());
5096  uint32_t new_capacity;
5097  return ShouldConvertToSlowElements(*this, capacity, index, &new_capacity);
5098}
5099
5100static bool ShouldConvertToFastElements(JSObject object,
5101                                        NumberDictionary dictionary,
5102                                        uint32_t index,
5103                                        uint32_t* new_capacity) {
5104  // If properties with non-standard attributes or accessors were added, we
5105  // cannot go back to fast elements.
5106  if (dictionary.requires_slow_elements()) return false;
5107
5108  // Adding a property with this index will require slow elements.
5109  if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
5110
5111  if (object.IsJSArray()) {
5112    Object length = JSArray::cast(object).length();
5113    if (!length.IsSmi()) return false;
5114    *new_capacity = static_cast<uint32_t>(Smi::ToInt(length));
5115  } else if (object.IsJSArgumentsObject()) {
5116    return false;
5117  } else {
5118    *new_capacity = dictionary.max_number_key() + 1;
5119  }
5120  *new_capacity = std::max(index + 1, *new_capacity);
5121
5122  uint32_t dictionary_size = static_cast<uint32_t>(dictionary.Capacity()) *
5123                             NumberDictionary::kEntrySize;
5124
5125  // Turn fast if the dictionary only saves 50% space.
5126  return 2 * dictionary_size >= *new_capacity;
5127}
5128
5129static ElementsKind BestFittingFastElementsKind(JSObject object) {
5130  if (!object.map().CanHaveFastTransitionableElementsKind()) {
5131    return HOLEY_ELEMENTS;
5132  }
5133  if (object.HasSloppyArgumentsElements()) {
5134    return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
5135  }
5136  if (object.HasStringWrapperElements()) {
5137    return FAST_STRING_WRAPPER_ELEMENTS;
5138  }
5139  DCHECK(object.HasDictionaryElements());
5140  NumberDictionary dictionary = object.element_dictionary();
5141  ElementsKind kind = HOLEY_SMI_ELEMENTS;
5142  for (InternalIndex i : dictionary.IterateEntries()) {
5143    Object key = dictionary.KeyAt(i);
5144    if (key.IsNumber()) {
5145      Object value = dictionary.ValueAt(i);
5146      if (!value.IsNumber()) return HOLEY_ELEMENTS;
5147      if (!value.IsSmi()) {
5148        if (!FLAG_unbox_double_arrays) return HOLEY_ELEMENTS;
5149        kind = HOLEY_DOUBLE_ELEMENTS;
5150      }
5151    }
5152  }
5153  return kind;
5154}
5155
5156// static
5157Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
5158                                     Handle<Object> value,
5159                                     PropertyAttributes attributes) {
5160  Isolate* isolate = object->GetIsolate();
5161
5162  DCHECK(object->map(isolate).is_extensible());
5163
5164  uint32_t old_length = 0;
5165  uint32_t new_capacity = 0;
5166
5167  if (object->IsJSArray(isolate)) {
5168    CHECK(JSArray::cast(*object).length().ToArrayLength(&old_length));
5169  }
5170
5171  ElementsKind kind = object->GetElementsKind(isolate);
5172  FixedArrayBase elements = object->elements(isolate);
5173  ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
5174  if (IsSloppyArgumentsElementsKind(kind)) {
5175    elements = SloppyArgumentsElements::cast(elements).arguments(isolate);
5176    dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
5177  } else if (IsStringWrapperElementsKind(kind)) {
5178    dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
5179  }
5180
5181  if (attributes != NONE) {
5182    kind = dictionary_kind;
5183  } else if (elements.IsNumberDictionary(isolate)) {
5184    kind = ShouldConvertToFastElements(
5185               *object, NumberDictionary::cast(elements), index, &new_capacity)
5186               ? BestFittingFastElementsKind(*object)
5187               : dictionary_kind;
5188  } else if (ShouldConvertToSlowElements(
5189                 *object, static_cast<uint32_t>(elements.length()), index,
5190                 &new_capacity)) {
5191    kind = dictionary_kind;
5192  }
5193
5194  ElementsKind to = value->OptimalElementsKind(isolate);
5195  if (IsHoleyElementsKind(kind) || !object->IsJSArray(isolate) ||
5196      index > old_length) {
5197    to = GetHoleyElementsKind(to);
5198    kind = GetHoleyElementsKind(kind);
5199  }
5200  to = GetMoreGeneralElementsKind(kind, to);
5201  ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
5202  MAYBE_RETURN(accessor->Add(object, index, value, attributes, new_capacity),
5203               Nothing<bool>());
5204
5205  if (object->IsJSArray(isolate) && index >= old_length) {
5206    Handle<Object> new_length =
5207        isolate->factory()->NewNumberFromUint(index + 1);
5208    JSArray::cast(*object).set_length(*new_length);
5209  }
5210  return Just(true);
5211}
5212
5213template <AllocationSiteUpdateMode update_or_check>
5214bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
5215                                    ElementsKind to_kind) {
5216  if (!object->IsJSArray()) return false;
5217
5218  if (!Heap::InYoungGeneration(*object)) return false;
5219
5220  if (Heap::IsLargeObject(*object)) return false;
5221
5222  Handle<AllocationSite> site;
5223  {
5224    DisallowGarbageCollection no_gc;
5225
5226    Heap* heap = object->GetHeap();
5227    AllocationMemento memento =
5228        heap->FindAllocationMemento<Heap::kForRuntime>(object->map(), *object);
5229    if (memento.is_null()) return false;
5230
5231    // Walk through to the Allocation Site
5232    site = handle(memento.GetAllocationSite(), heap->isolate());
5233  }
5234  return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
5235                                                                   to_kind);
5236}
5237
5238template bool
5239JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
5240    Handle<JSObject> object, ElementsKind to_kind);
5241
5242template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
5243    Handle<JSObject> object, ElementsKind to_kind);
5244
5245void JSObject::TransitionElementsKind(Handle<JSObject> object,
5246                                      ElementsKind to_kind) {
5247  ElementsKind from_kind = object->GetElementsKind();
5248
5249  if (IsHoleyElementsKind(from_kind)) {
5250    to_kind = GetHoleyElementsKind(to_kind);
5251  }
5252
5253  if (from_kind == to_kind) return;
5254
5255  // This method should never be called for any other case.
5256  DCHECK(IsFastElementsKind(from_kind) ||
5257         IsNonextensibleElementsKind(from_kind));
5258  DCHECK(IsFastElementsKind(to_kind) || IsNonextensibleElementsKind(to_kind));
5259  DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
5260
5261  UpdateAllocationSite(object, to_kind);
5262  Isolate* isolate = object->GetIsolate();
5263  if (object->elements() == ReadOnlyRoots(isolate).empty_fixed_array() ||
5264      IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) {
5265    // No change is needed to the elements() buffer, the transition
5266    // only requires a map change.
5267    Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
5268    JSObject::MigrateToMap(isolate, object, new_map);
5269    if (FLAG_trace_elements_transitions) {
5270      Handle<FixedArrayBase> elms(object->elements(), isolate);
5271      PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
5272    }
5273  } else {
5274    DCHECK((IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) ||
5275           (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind)));
5276    uint32_t c = static_cast<uint32_t>(object->elements().length());
5277    if (ElementsAccessor::ForKind(to_kind)
5278            ->GrowCapacityAndConvert(object, c)
5279            .IsNothing()) {
5280      // TODO(victorgomes): Temporarily forcing a fatal error here in case of
5281      // overflow, until all users of TransitionElementsKind can handle
5282      // exceptions.
5283      FATAL(
5284          "Fatal JavaScript invalid size error when transitioning elements "
5285          "kind");
5286      UNREACHABLE();
5287    }
5288  }
5289}
5290
5291template <typename BackingStore>
5292static int HoleyElementsUsage(JSObject object, BackingStore store) {
5293  Isolate* isolate = object.GetIsolate();
5294  int limit = object.IsJSArray() ? Smi::ToInt(JSArray::cast(object).length())
5295                                 : store.length();
5296  int used = 0;
5297  for (int i = 0; i < limit; ++i) {
5298    if (!store.is_the_hole(isolate, i)) ++used;
5299  }
5300  return used;
5301}
5302
5303int JSObject::GetFastElementsUsage() {
5304  FixedArrayBase store = elements();
5305  switch (GetElementsKind()) {
5306    case PACKED_SMI_ELEMENTS:
5307    case PACKED_DOUBLE_ELEMENTS:
5308    case PACKED_ELEMENTS:
5309    case PACKED_FROZEN_ELEMENTS:
5310    case PACKED_SEALED_ELEMENTS:
5311    case PACKED_NONEXTENSIBLE_ELEMENTS:
5312      return IsJSArray() ? Smi::ToInt(JSArray::cast(*this).length())
5313                         : store.length();
5314    case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
5315      store = SloppyArgumentsElements::cast(store).arguments();
5316      V8_FALLTHROUGH;
5317    case HOLEY_SMI_ELEMENTS:
5318    case HOLEY_ELEMENTS:
5319    case HOLEY_FROZEN_ELEMENTS:
5320    case HOLEY_SEALED_ELEMENTS:
5321    case HOLEY_NONEXTENSIBLE_ELEMENTS:
5322    case FAST_STRING_WRAPPER_ELEMENTS:
5323      return HoleyElementsUsage(*this, FixedArray::cast(store));
5324    case HOLEY_DOUBLE_ELEMENTS:
5325      if (elements().length() == 0) return 0;
5326      return HoleyElementsUsage(*this, FixedDoubleArray::cast(store));
5327
5328    case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
5329    case SLOW_STRING_WRAPPER_ELEMENTS:
5330    case DICTIONARY_ELEMENTS:
5331    case WASM_ARRAY_ELEMENTS:
5332    case NO_ELEMENTS:
5333#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
5334
5335      TYPED_ARRAYS(TYPED_ARRAY_CASE)
5336      RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE)
5337#undef TYPED_ARRAY_CASE
5338      UNREACHABLE();
5339  }
5340  return 0;
5341}
5342
5343MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
5344                                                         bool* done) {
5345  DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
5346  return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
5347}
5348
5349Maybe<bool> JSObject::HasRealNamedProperty(Isolate* isolate,
5350                                           Handle<JSObject> object,
5351                                           Handle<Name> name) {
5352  PropertyKey key(isolate, name);
5353  LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
5354  return HasProperty(&it);
5355}
5356
5357Maybe<bool> JSObject::HasRealElementProperty(Isolate* isolate,
5358                                             Handle<JSObject> object,
5359                                             uint32_t index) {
5360  LookupIterator it(isolate, object, index, object,
5361                    LookupIterator::OWN_SKIP_INTERCEPTOR);
5362  return HasProperty(&it);
5363}
5364
5365Maybe<bool> JSObject::HasRealNamedCallbackProperty(Isolate* isolate,
5366                                                   Handle<JSObject> object,
5367                                                   Handle<Name> name) {
5368  PropertyKey key(isolate, name);
5369  LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
5370  Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
5371  return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
5372                               : Nothing<bool>();
5373}
5374
5375bool JSGlobalProxy::IsDetached() const {
5376  return native_context().IsNull(GetIsolate());
5377}
5378
5379void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
5380                                            Handle<Name> name) {
5381  Isolate* isolate = global->GetIsolate();
5382  // Regardless of whether the property is there or not invalidate
5383  // Load/StoreGlobalICs that load/store through global object's prototype.
5384  JSObject::InvalidatePrototypeValidityCell(*global);
5385  DCHECK(!global->HasFastProperties());
5386  auto dictionary = handle(global->global_dictionary(kAcquireLoad), isolate);
5387  InternalIndex entry = dictionary->FindEntry(isolate, name);
5388  if (entry.is_not_found()) return;
5389
5390  Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
5391  Handle<Object> value(cell->value(), isolate);
5392  PropertyDetails details = cell->property_details();
5393  details = details.set_cell_type(PropertyCellType::kMutable);
5394  PropertyCell::InvalidateAndReplaceEntry(isolate, dictionary, entry, details,
5395                                          value);
5396}
5397
5398// static
5399MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
5400                                Handle<JSReceiver> new_target, double tv) {
5401  Isolate* const isolate = constructor->GetIsolate();
5402  Handle<JSObject> result;
5403  ASSIGN_RETURN_ON_EXCEPTION(
5404      isolate, result,
5405      JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
5406      JSDate);
5407  if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
5408    tv = DoubleToInteger(tv) + 0.0;
5409  } else {
5410    tv = std::numeric_limits<double>::quiet_NaN();
5411  }
5412  Handle<Object> value = isolate->factory()->NewNumber(tv);
5413  Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
5414  return Handle<JSDate>::cast(result);
5415}
5416
5417// static
5418double JSDate::CurrentTimeValue(Isolate* isolate) {
5419  if (FLAG_log_internal_timer_events) LOG(isolate, CurrentTimeEvent());
5420  if (FLAG_correctness_fuzzer_suppressions) return 4.2;
5421
5422  // According to ECMA-262, section 15.9.1, page 117, the precision of
5423  // the number in a Date object representing a particular instant in
5424  // time is milliseconds. Therefore, we floor the result of getting
5425  // the OS time.
5426  return std::floor(V8::GetCurrentPlatform()->CurrentClockTimeMillis());
5427}
5428
5429// static
5430Address JSDate::GetField(Isolate* isolate, Address raw_object,
5431                         Address smi_index) {
5432  // Called through CallCFunction.
5433  DisallowGarbageCollection no_gc;
5434  DisallowHandleAllocation no_handles;
5435  DisallowJavascriptExecution no_js(isolate);
5436
5437  Object object(raw_object);
5438  Smi index(smi_index);
5439  return JSDate::cast(object)
5440      .DoGetField(isolate, static_cast<FieldIndex>(index.value()))
5441      .ptr();
5442}
5443
5444Object JSDate::DoGetField(Isolate* isolate, FieldIndex index) {
5445  DCHECK_NE(index, kDateValue);
5446
5447  DateCache* date_cache = isolate->date_cache();
5448
5449  if (index < kFirstUncachedField) {
5450    Object stamp = cache_stamp();
5451    if (stamp != date_cache->stamp() && stamp.IsSmi()) {
5452      // Since the stamp is not NaN, the value is also not NaN.
5453      int64_t local_time_ms =
5454          date_cache->ToLocal(static_cast<int64_t>(value().Number()));
5455      SetCachedFields(local_time_ms, date_cache);
5456    }
5457    switch (index) {
5458      case kYear:
5459        return year();
5460      case kMonth:
5461        return month();
5462      case kDay:
5463        return day();
5464      case kWeekday:
5465        return weekday();
5466      case kHour:
5467        return hour();
5468      case kMinute:
5469        return min();
5470      case kSecond:
5471        return sec();
5472      default:
5473        UNREACHABLE();
5474    }
5475  }
5476
5477  if (index >= kFirstUTCField) {
5478    return GetUTCField(index, value().Number(), date_cache);
5479  }
5480
5481  double time = value().Number();
5482  if (std::isnan(time)) return GetReadOnlyRoots().nan_value();
5483
5484  int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
5485  int days = DateCache::DaysFromTime(local_time_ms);
5486
5487  if (index == kDays) return Smi::FromInt(days);
5488
5489  int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
5490  if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
5491  DCHECK_EQ(index, kTimeInDay);
5492  return Smi::FromInt(time_in_day_ms);
5493}
5494
5495Object JSDate::GetUTCField(FieldIndex index, double value,
5496                           DateCache* date_cache) {
5497  DCHECK_GE(index, kFirstUTCField);
5498
5499  if (std::isnan(value)) return GetReadOnlyRoots().nan_value();
5500
5501  int64_t time_ms = static_cast<int64_t>(value);
5502
5503  if (index == kTimezoneOffset) {
5504    return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
5505  }
5506
5507  int days = DateCache::DaysFromTime(time_ms);
5508
5509  if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
5510
5511  if (index <= kDayUTC) {
5512    int year, month, day;
5513    date_cache->YearMonthDayFromDays(days, &year, &month, &day);
5514    if (index == kYearUTC) return Smi::FromInt(year);
5515    if (index == kMonthUTC) return Smi::FromInt(month);
5516    DCHECK_EQ(index, kDayUTC);
5517    return Smi::FromInt(day);
5518  }
5519
5520  int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
5521  switch (index) {
5522    case kHourUTC:
5523      return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
5524    case kMinuteUTC:
5525      return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
5526    case kSecondUTC:
5527      return Smi::FromInt((time_in_day_ms / 1000) % 60);
5528    case kMillisecondUTC:
5529      return Smi::FromInt(time_in_day_ms % 1000);
5530    case kDaysUTC:
5531      return Smi::FromInt(days);
5532    case kTimeInDayUTC:
5533      return Smi::FromInt(time_in_day_ms);
5534    default:
5535      UNREACHABLE();
5536  }
5537
5538  UNREACHABLE();
5539}
5540
5541// static
5542Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
5543  Isolate* const isolate = date->GetIsolate();
5544  Handle<Object> value = isolate->factory()->NewNumber(v);
5545  bool value_is_nan = std::isnan(v);
5546  date->SetValue(*value, value_is_nan);
5547  return value;
5548}
5549
5550void JSDate::SetValue(Object value, bool is_value_nan) {
5551  set_value(value);
5552  if (is_value_nan) {
5553    HeapNumber nan = GetReadOnlyRoots().nan_value();
5554    set_cache_stamp(nan, SKIP_WRITE_BARRIER);
5555    set_year(nan, SKIP_WRITE_BARRIER);
5556    set_month(nan, SKIP_WRITE_BARRIER);
5557    set_day(nan, SKIP_WRITE_BARRIER);
5558    set_hour(nan, SKIP_WRITE_BARRIER);
5559    set_min(nan, SKIP_WRITE_BARRIER);
5560    set_sec(nan, SKIP_WRITE_BARRIER);
5561    set_weekday(nan, SKIP_WRITE_BARRIER);
5562  } else {
5563    set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
5564  }
5565}
5566
5567void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
5568  int days = DateCache::DaysFromTime(local_time_ms);
5569  int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
5570  int year, month, day;
5571  date_cache->YearMonthDayFromDays(days, &year, &month, &day);
5572  int weekday = date_cache->Weekday(days);
5573  int hour = time_in_day_ms / (60 * 60 * 1000);
5574  int min = (time_in_day_ms / (60 * 1000)) % 60;
5575  int sec = (time_in_day_ms / 1000) % 60;
5576  set_cache_stamp(date_cache->stamp());
5577  set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
5578  set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
5579  set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
5580  set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
5581  set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
5582  set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
5583  set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
5584}
5585
5586// static
5587void JSMessageObject::EnsureSourcePositionsAvailable(
5588    Isolate* isolate, Handle<JSMessageObject> message) {
5589  if (!message->DidEnsureSourcePositionsAvailable()) {
5590    DCHECK_EQ(message->start_position(), -1);
5591    DCHECK_GE(message->bytecode_offset().value(), kFunctionEntryBytecodeOffset);
5592    Handle<SharedFunctionInfo> shared_info(
5593        SharedFunctionInfo::cast(message->shared_info()), isolate);
5594    IsCompiledScope is_compiled_scope;
5595    SharedFunctionInfo::EnsureBytecodeArrayAvailable(
5596        isolate, shared_info, &is_compiled_scope, CreateSourcePositions::kYes);
5597    SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
5598    DCHECK(shared_info->HasBytecodeArray());
5599    int position = shared_info->abstract_code(isolate).SourcePosition(
5600        message->bytecode_offset().value());
5601    DCHECK_GE(position, 0);
5602    message->set_start_position(position);
5603    message->set_end_position(position + 1);
5604    message->set_shared_info(ReadOnlyRoots(isolate).undefined_value());
5605  }
5606}
5607
5608int JSMessageObject::GetLineNumber() const {
5609  DCHECK(DidEnsureSourcePositionsAvailable());
5610  if (start_position() == -1) return Message::kNoLineNumberInfo;
5611
5612  Handle<Script> the_script(script(), GetIsolate());
5613
5614  Script::PositionInfo info;
5615  const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
5616  if (!Script::GetPositionInfo(the_script, start_position(), &info,
5617                               offset_flag)) {
5618    return Message::kNoLineNumberInfo;
5619  }
5620
5621  return info.line + 1;
5622}
5623
5624int JSMessageObject::GetColumnNumber() const {
5625  DCHECK(DidEnsureSourcePositionsAvailable());
5626  if (start_position() == -1) return -1;
5627
5628  Handle<Script> the_script(script(), GetIsolate());
5629
5630  Script::PositionInfo info;
5631  const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
5632  if (!Script::GetPositionInfo(the_script, start_position(), &info,
5633                               offset_flag)) {
5634    return -1;
5635  }
5636
5637  return info.column;  // Note: No '+1' in contrast to GetLineNumber.
5638}
5639
5640String JSMessageObject::GetSource() const {
5641  Script script_object = script();
5642  if (script_object.HasValidSource()) {
5643    Object source = script_object.source();
5644    if (source.IsString()) return String::cast(source);
5645  }
5646  return ReadOnlyRoots(GetIsolate()).empty_string();
5647}
5648
5649Handle<String> JSMessageObject::GetSourceLine() const {
5650  Isolate* isolate = GetIsolate();
5651  Handle<Script> the_script(script(), isolate);
5652
5653#if V8_ENABLE_WEBASSEMBLY
5654  if (the_script->type() == Script::TYPE_WASM) {
5655    return isolate->factory()->empty_string();
5656  }
5657#endif  // V8_ENABLE_WEBASSEMBLY
5658
5659  Script::PositionInfo info;
5660  const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
5661  DCHECK(DidEnsureSourcePositionsAvailable());
5662  if (!Script::GetPositionInfo(the_script, start_position(), &info,
5663                               offset_flag)) {
5664    return isolate->factory()->empty_string();
5665  }
5666
5667  Handle<String> src = handle(String::cast(the_script->source()), isolate);
5668  return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
5669}
5670
5671}  // namespace internal
5672}  // namespace v8
5673