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, ¤t), 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, ¤t, 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, ¤t_desc);
1742 MAYBE_RETURN(owned, Nothing<bool>());
1743 if (owned.FromJust()) {
1744 PropertyDescriptor desc =
1745 PropertyDescriptor::IsAccessorDescriptor(¤t_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, ¤t_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(¤t_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