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