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