• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
85 namespace v8 {
86 namespace internal {
87 
88 // static
HasProperty(LookupIterator * it)89 Maybe<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
HasOwnProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Name> name)124 Maybe<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 
GetDataProperty(LookupIterator * it,AllocationPolicy allocation_policy)144 Handle<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
HasInPrototypeChain(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> proto)175 Maybe<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
CheckPrivateNameStore(LookupIterator * it,bool is_define)189 bool 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
CheckIfCanDefine(Isolate * isolate,LookupIterator * it,Handle<Object> value,Maybe<ShouldThrow> should_throw)238 Maybe<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 
258 namespace {
259 
HasExcludedProperty(const base::ScopedVector<Handle<Object>> * excluded_properties,Handle<Object> search_element)260 bool 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 
FastAssign(Handle<JSReceiver> target,Handle<Object> source,PropertiesEnumerationMode mode,const base::ScopedVector<Handle<Object>> * excluded_properties,bool use_set)273 V8_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
SetOrCopyDataProperties(Isolate * isolate,Handle<JSReceiver> target,Handle<Object> source,PropertiesEnumerationMode mode,const base::ScopedVector<Handle<Object>> * excluded_properties,bool use_set)414 Maybe<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 
class_name()502 String 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 
551 namespace {
GetConstructorHelper(Isolate * isolate,Handle<JSReceiver> receiver)552 std::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
GetConstructor(Isolate * isolate,Handle<JSReceiver> receiver)622 MaybeHandle<JSFunction> JSReceiver::GetConstructor(
623     Isolate* isolate, Handle<JSReceiver> receiver) {
624   return GetConstructorHelper(isolate, receiver).first;
625 }
626 
627 // static
GetConstructorName(Isolate * isolate,Handle<JSReceiver> receiver)628 Handle<String> JSReceiver::GetConstructorName(Isolate* isolate,
629                                               Handle<JSReceiver> receiver) {
630   return GetConstructorHelper(isolate, receiver).second;
631 }
632 
GetCreationContext()633 MaybeHandle<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
GetFunctionRealm(Handle<JSReceiver> receiver)659 MaybeHandle<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
GetContextForMicrotask(Handle<JSReceiver> receiver)700 MaybeHandle<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 
GetPropertyAttributes(LookupIterator * it)720 Maybe<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 
754 namespace {
755 
SetHashAndUpdateProperties(HeapObject properties,int hash)756 Object 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 
GetIdentityHashHelper(JSReceiver object)789 int 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 
SetIdentityHash(int hash)824 void 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 
SetProperties(HeapObject properties)834 void 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 
GetIdentityHash()851 Object 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
CreateIdentityHash(Isolate * isolate,JSReceiver key)863 Smi 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 
GetOrCreateIdentityHash(Isolate * isolate)872 Smi 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 
DeleteNormalizedProperty(Handle<JSReceiver> object,InternalIndex entry)883 void 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 
DeleteProperty(LookupIterator * it,LanguageMode language_mode)924 Maybe<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 
DeleteElement(Handle<JSReceiver> object,uint32_t index,LanguageMode language_mode)997 Maybe<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 
DeleteProperty(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)1004 Maybe<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 
DeletePropertyOrElement(Handle<JSReceiver> object,Handle<Name> name,LanguageMode language_mode)1012 Maybe<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
DefineProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> attributes)1023 Object 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
DefineProperties(Isolate * isolate,Handle<Object> object,Handle<Object> properties)1056 MaybeHandle<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
DefineOwnProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc,Maybe<ShouldThrow> should_throw)1131 Maybe<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
OrdinaryDefineOwnProperty(Isolate * isolate,Handle<JSObject> object,Handle<Object> key,PropertyDescriptor * desc,Maybe<ShouldThrow> should_throw)1162 Maybe<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 
OrdinaryDefineOwnProperty(Isolate * isolate,Handle<JSObject> object,const PropertyKey & key,PropertyDescriptor * desc,Maybe<ShouldThrow> should_throw)1171 Maybe<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 
1189 namespace {
1190 
GetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,bool * done)1191 MaybeHandle<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 
GetPropertyAttributesWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor)1226 Maybe<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 
SetPropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,Maybe<ShouldThrow> should_throw,Handle<Object> value)1274 Maybe<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 
DefinePropertyWithInterceptorInternal(LookupIterator * it,Handle<InterceptorInfo> interceptor,Maybe<ShouldThrow> should_throw,PropertyDescriptor * desc)1308 Maybe<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
OrdinaryDefineOwnProperty(LookupIterator * it,PropertyDescriptor * desc,Maybe<ShouldThrow> should_throw)1367 Maybe<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
IsCompatiblePropertyDescriptor(Isolate * isolate,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,Handle<Name> property_name,Maybe<ShouldThrow> should_throw)1405 Maybe<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
ValidateAndApplyPropertyDescriptor(Isolate * isolate,LookupIterator * it,bool extensible,PropertyDescriptor * desc,PropertyDescriptor * current,Maybe<ShouldThrow> should_throw,Handle<Name> property_name)1417 Maybe<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
CreateDataProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Name> key,Handle<Object> value,Maybe<ShouldThrow> should_throw)1675 Maybe<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
CreateDataProperty(LookupIterator * it,Handle<Object> value,Maybe<ShouldThrow> should_throw)1686 Maybe<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
AddPrivateField(LookupIterator * it,Handle<Object> value,Maybe<ShouldThrow> should_throw)1708 Maybe<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
GetOwnPropertyDescriptor(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key,PropertyDescriptor * desc)1751 Maybe<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 
1761 namespace {
1762 
GetPropertyDescriptorWithInterceptor(LookupIterator * it,PropertyDescriptor * desc)1763 Maybe<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
GetOwnPropertyDescriptor(LookupIterator * it,PropertyDescriptor * desc)1828 Maybe<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 }
SetIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level,ShouldThrow should_throw)1891 Maybe<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 
1961 namespace {
GenericTestIntegrityLevel(Handle<JSReceiver> receiver,PropertyAttributes level)1962 Maybe<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 
TestIntegrityLevel(Handle<JSReceiver> receiver,IntegrityLevel level)1996 Maybe<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 
PreventExtensions(Handle<JSReceiver> object,ShouldThrow should_throw)2005 Maybe<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 
IsExtensible(Handle<JSReceiver> object)2016 Maybe<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
ToPrimitive(Isolate * isolate,Handle<JSReceiver> receiver,ToPrimitiveHint hint)2024 MaybeHandle<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
OrdinaryToPrimitive(Isolate * isolate,Handle<JSReceiver> receiver,OrdinaryToPrimitiveHint hint)2052 MaybeHandle<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 
FastGetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> receiver,bool get_entries,Handle<FixedArray> * result)2084 V8_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 
GetOwnValuesOrEntries(Isolate * isolate,Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path,bool get_entries)2184 MaybeHandle<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 
GetOwnValues(Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path)2242 MaybeHandle<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 
GetOwnEntries(Handle<JSReceiver> object,PropertyFilter filter,bool try_fast_path)2249 MaybeHandle<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 
SetPrototype(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)2256 Maybe<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 
HasProxyInPrototype(Isolate * isolate)2268 bool 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 
IsCodeLike(Isolate * isolate) const2277 bool 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
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,Handle<AllocationSite> site)2293 MaybeHandle<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 )
ObjectCreate(Isolate * isolate,Handle<Object> prototype)2324 MaybeHandle<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 
EnsureWritableFastElements(Handle<JSObject> object)2337 void 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 
GetHeaderSize(InstanceType type,bool function_has_prototype_slot)2351 int 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
AllCanRead(LookupIterator * it)2529 bool 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 
GetPropertyWithFailedAccessCheck(LookupIterator * it)2550 MaybeHandle<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 
GetPropertyAttributesWithFailedAccessCheck(LookupIterator * it)2590 Maybe<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
AllCanWrite(LookupIterator * it)2618 bool 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 
SetPropertyWithFailedAccessCheck(LookupIterator * it,Handle<Object> value,Maybe<ShouldThrow> should_throw)2630 Maybe<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 
SetNormalizedProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyDetails details)2651 void 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 
SetNormalizedElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyDetails details)2717 void 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 
JSObjectShortPrint(StringStream * accumulator)2731 void 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 
PrintElementsTransition(FILE * file,Handle<JSObject> object,ElementsKind from_kind,Handle<FixedArrayBase> from_elements,ElementsKind to_kind,Handle<FixedArrayBase> to_elements)2865 void 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 
PrintInstanceMigration(FILE * file,Map original_map,Map new_map)2885 void 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 
IsUnmodifiedApiObject(FullObjectSlot o)2919 bool 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
UpdatePrototypeUserRegistration(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)2937 void 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
NotifyMapChange(Handle<Map> old_map,Handle<Map> new_map,Isolate * isolate)2963 void 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 
2977 namespace {
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.
MigrateFastToFast(Isolate * isolate,Handle<JSObject> object,Handle<Map> new_map)2994 void 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 
MigrateFastToSlow(Isolate * isolate,Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)3185 void 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 
MigrateToMap(Isolate * isolate,Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)3311 void 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 
ForceSetPrototype(Isolate * isolate,Handle<JSObject> object,Handle<HeapObject> proto)3355 void 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 
SetPropertyWithInterceptor(LookupIterator * it,Maybe<ShouldThrow> should_throw,Handle<Object> value)3364 Maybe<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 
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)3371 Handle<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 
AllocateStorageForMap(Handle<JSObject> object,Handle<Map> map)3377 void 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 
MigrateInstance(Isolate * isolate,Handle<JSObject> object)3431 void 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
TryMigrateInstance(Isolate * isolate,Handle<JSObject> object)3447 bool 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 
AddProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)3466 void 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 
AddProperty(Isolate * isolate,Handle<JSObject> object,const char * name,Handle<Object> value,PropertyAttributes attributes)3487 void 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.
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,AccessorInfoHandling handling,EnforceDefineSemantics semantics)3499 MaybeHandle<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 
DefineOwnPropertyIgnoreAttributes(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,Maybe<ShouldThrow> should_throw,AccessorInfoHandling handling,EnforceDefineSemantics semantics,StoreOrigin store_origin)3508 Maybe<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 
SetOwnPropertyIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)3627 MaybeHandle<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 
SetOwnElementIgnoreAttributes(Handle<JSObject> object,size_t index,Handle<Object> value,PropertyAttributes attributes)3636 MaybeHandle<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 
DefinePropertyOrElementIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)3645 MaybeHandle<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 
GetPropertyAttributesWithInterceptor(LookupIterator * it)3654 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
3655     LookupIterator* it) {
3656   return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
3657 }
3658 
NormalizeProperties(Isolate * isolate,Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties,const char * reason)3659 void 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 
MigrateSlowToFast(Handle<JSObject> object,int unused_property_fields,const char * reason)3673 void 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 
RequireSlowElements(NumberDictionary dictionary)3878 void 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 
NormalizeElements(Handle<JSObject> object)3890 Handle<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 
DeletePropertyWithInterceptor(LookupIterator * it,ShouldThrow should_throw)3948 Maybe<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 
CreateDataProperty(LookupIterator * it,Handle<Object> value,Maybe<ShouldThrow> should_throw)3984 Maybe<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 
4005 namespace {
4006 
4007 template <typename Dictionary>
TestDictionaryPropertiesIntegrityLevel(Dictionary dict,ReadOnlyRoots roots,PropertyAttributes level)4008 bool 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 
TestFastPropertiesIntegrityLevel(Map map,PropertyAttributes level)4027 bool 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 
TestPropertiesIntegrityLevel(JSObject object,PropertyAttributes level)4045 bool 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 
TestElementsIntegrityLevel(JSObject object,PropertyAttributes level)4061 bool 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 
FastTestIntegrityLevel(JSObject object,PropertyAttributes level)4087 bool 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 
TestIntegrityLevel(Handle<JSObject> object,IntegrityLevel level)4097 Maybe<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 
PreventExtensions(Handle<JSObject> object,ShouldThrow should_throw)4106 Maybe<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 
IsExtensible(Handle<JSObject> object)4162 bool 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
ReadFromOptionsBag(Handle<Object> options,Handle<String> option_name,Isolate * isolate)4178 MaybeHandle<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 
4188 template <typename Dictionary>
ApplyAttributesToDictionary(Isolate * isolate,ReadOnlyRoots roots,Handle<Dictionary> dictionary,const PropertyAttributes attributes)4189 void 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 
4208 template void JSObject::ApplyAttributesToDictionary(
4209     Isolate* isolate, ReadOnlyRoots roots, Handle<NumberDictionary> dictionary,
4210     const PropertyAttributes attributes);
4211 
CreateElementDictionary(Isolate * isolate,Handle<JSObject> object)4212 Handle<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 
4228 template <PropertyAttributes attrs>
PreventExtensionsWithTransition(Handle<JSObject> object,ShouldThrow should_throw)4229 Maybe<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 
FastPropertyAt(Isolate * isolate,Handle<JSObject> object,Representation representation,FieldIndex index)4423 Handle<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 
FastPropertyAt(Isolate * isolate,Handle<JSObject> object,Representation representation,FieldIndex index,SeqCstAccessTag tag)4431 Handle<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
DictionaryPropertyAt(Isolate * isolate,Handle<JSObject> object,InternalIndex dict_index)4440 Handle<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
DictionaryPropertyAt(Handle<JSObject> object,InternalIndex dict_index,Heap * heap)4454 base::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.
HasEnumerableElements()4475 bool 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 
DefineAccessor(Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)4554 MaybeHandle<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 
DefineAccessor(LookupIterator * it,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)4566 MaybeHandle<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 
SetAccessor(Handle<JSObject> object,Handle<Name> name,Handle<AccessorInfo> info,PropertyAttributes attributes)4598 MaybeHandle<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 
SlowReverseLookup(Object value)4639 Object 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 
PrototypeRegistryCompactionCallback(HeapObject value,int old_index,int new_index)4678 void 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
MakePrototypesFast(Handle<Object> receiver,WhereToStart where_to_start,Isolate * isolate)4690 void 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 
PrototypeBenefitsFromNormalization(Handle<JSObject> object)4712 static 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
OptimizeAsPrototype(Handle<JSObject> object,bool enable_setup_mode)4724 void 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
ReoptimizeIfPrototype(Handle<JSObject> object)4788 void 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
LazyRegisterPrototypeUser(Handle<Map> user,Isolate * isolate)4795 void 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
UnregisterPrototypeUser(Handle<Map> user,Isolate * isolate)4843 bool 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 
4877 namespace {
4878 
4879 // This function must be kept in sync with
4880 // AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks
4881 // before jumping here.
InvalidateOnePrototypeValidityCellInternal(Map map)4882 void 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 
InvalidatePrototypeChainsInternal(Map map)4919 void 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
InvalidatePrototypeChains(Map map)4957 Map 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
InvalidatePrototypeValidityCell(JSGlobalObject global)4971 void JSObject::InvalidatePrototypeValidityCell(JSGlobalObject global) {
4972   DisallowGarbageCollection no_gc;
4973   InvalidateOnePrototypeValidityCellInternal(global.map());
4974 }
4975 
SetPrototype(Isolate * isolate,Handle<JSObject> object,Handle<Object> value,bool from_javascript,ShouldThrow should_throw)4976 Maybe<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
SetImmutableProto(Handle<JSObject> object)5067 void 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 
EnsureCanContainElements(Handle<JSObject> object,JavaScriptArguments * args,uint32_t arg_count,EnsureElementsMode mode)5078 void 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 
ValidateElements(JSObject object)5085 void 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 
WouldConvertToSlowElements(uint32_t index)5093 bool 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 
ShouldConvertToFastElements(JSObject object,NumberDictionary dictionary,uint32_t index,uint32_t * new_capacity)5100 static 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 
BestFittingFastElementsKind(JSObject object)5129 static 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
AddDataElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes)5157 Maybe<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 
5213 template <AllocationSiteUpdateMode update_or_check>
UpdateAllocationSite(Handle<JSObject> object,ElementsKind to_kind)5214 bool 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 
5238 template bool
5239 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
5240     Handle<JSObject> object, ElementsKind to_kind);
5241 
5242 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
5243     Handle<JSObject> object, ElementsKind to_kind);
5244 
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)5245 void 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 
5291 template <typename BackingStore>
HoleyElementsUsage(JSObject object,BackingStore store)5292 static 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 
GetFastElementsUsage()5303 int 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 
GetPropertyWithInterceptor(LookupIterator * it,bool * done)5343 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
5344                                                          bool* done) {
5345   DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
5346   return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
5347 }
5348 
HasRealNamedProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name)5349 Maybe<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 
HasRealElementProperty(Isolate * isolate,Handle<JSObject> object,uint32_t index)5357 Maybe<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 
HasRealNamedCallbackProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name)5365 Maybe<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 
IsDetached() const5375 bool JSGlobalProxy::IsDetached() const {
5376   return native_context().IsNull(GetIsolate());
5377 }
5378 
InvalidatePropertyCell(Handle<JSGlobalObject> global,Handle<Name> name)5379 void 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
New(Handle<JSFunction> constructor,Handle<JSReceiver> new_target,double tv)5399 MaybeHandle<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
CurrentTimeValue(Isolate * isolate)5418 double 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
GetField(Isolate * isolate,Address raw_object,Address smi_index)5430 Address 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 
DoGetField(Isolate * isolate,FieldIndex index)5444 Object 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 
GetUTCField(FieldIndex index,double value,DateCache * date_cache)5495 Object 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
SetValue(Handle<JSDate> date,double v)5542 Handle<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 
SetValue(Object value,bool is_value_nan)5550 void 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 
SetCachedFields(int64_t local_time_ms,DateCache * date_cache)5567 void 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
EnsureSourcePositionsAvailable(Isolate * isolate,Handle<JSMessageObject> message)5587 void 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 
GetLineNumber() const5608 int 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 
GetColumnNumber() const5624 int 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 
GetSource() const5640 String 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 
GetSourceLine() const5649 Handle<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