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 4598299 : Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
76 4705525 : for (; it->IsFound(); it->Next()) {
77 1660907 : 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 28975 : 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 427977 : Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
111 : Handle<Name> name) {
112 427977 : if (object->IsJSModuleNamespace()) {
113 : PropertyDescriptor desc;
114 : return JSReceiver::GetOwnPropertyDescriptor(object->GetIsolate(), object,
115 171 : name, &desc);
116 : }
117 :
118 427806 : if (object->IsJSObject()) { // Shortcut.
119 : LookupIterator it = LookupIterator::PropertyOrElement(
120 426420 : object->GetIsolate(), object, name, object, LookupIterator::OWN);
121 426420 : 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 4122180 : Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
131 5315782 : for (; it->IsFound(); it->Next()) {
132 4666386 : 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 597623 : 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 532533 : 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 3534050 : return it->GetDataValue();
154 : }
155 : }
156 52595 : return it->isolate()->factory()->undefined_value();
157 : }
158 :
159 : // static
160 1286 : Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
161 : Handle<JSReceiver> object,
162 : Handle<Object> proto) {
163 : PrototypeIterator iter(isolate, object, kStartAtReceiver);
164 : while (true) {
165 3688852 : if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
166 3688744 : if (iter.IsAtEnd()) return Just(false);
167 3687952 : 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 1038 : 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 877995 : String JSReceiver::class_name() {
346 : ReadOnlyRoots roots = GetReadOnlyRoots();
347 877995 : if (IsFunction()) return roots.Function_string();
348 877985 : if (IsJSArgumentsObject()) return roots.Arguments_string();
349 877985 : if (IsJSArray()) return roots.Array_string();
350 873957 : if (IsJSArrayBuffer()) {
351 0 : if (JSArrayBuffer::cast(*this)->is_shared()) {
352 : return roots.SharedArrayBuffer_string();
353 : }
354 : return roots.ArrayBuffer_string();
355 : }
356 873957 : if (IsJSArrayIterator()) return roots.ArrayIterator_string();
357 873957 : if (IsJSDate()) return roots.Date_string();
358 873948 : if (IsJSError()) return roots.Error_string();
359 873948 : if (IsJSGeneratorObject()) return roots.Generator_string();
360 873948 : if (IsJSMap()) return roots.Map_string();
361 873948 : if (IsJSMapIterator()) return roots.MapIterator_string();
362 873948 : if (IsJSProxy()) {
363 : return map()->is_callable() ? roots.Function_string()
364 1113 : : roots.Object_string();
365 : }
366 872835 : if (IsJSRegExp()) return roots.RegExp_string();
367 872421 : if (IsJSSet()) return roots.Set_string();
368 872421 : if (IsJSSetIterator()) return roots.SetIterator_string();
369 872421 : 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 871710 : 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 869061 : if (IsJSWeakMap()) return roots.WeakMap_string();
388 869061 : if (IsJSWeakSet()) return roots.WeakSet_string();
389 869061 : if (IsJSGlobalProxy()) return roots.global_string();
390 :
391 815671 : Object maybe_constructor = map()->GetConstructor();
392 815671 : if (maybe_constructor->IsJSFunction()) {
393 : JSFunction constructor = JSFunction::cast(maybe_constructor);
394 815539 : if (constructor->shared()->IsApiFunction()) {
395 : maybe_constructor = constructor->shared()->get_api_func_data();
396 : }
397 : }
398 :
399 815671 : 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 3925963 : 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 11777201 : if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
417 : !receiver->map()->is_prototype_map()) {
418 3754532 : Object maybe_constructor = receiver->map()->GetConstructor();
419 3754532 : if (maybe_constructor->IsJSFunction()) {
420 : JSFunction constructor = JSFunction::cast(maybe_constructor);
421 3515782 : String name = constructor->shared()->DebugName();
422 6435177 : if (name->length() != 0 &&
423 2919395 : !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
424 : return std::make_pair(handle(constructor, isolate),
425 2036464 : 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 1889499 : receiver, isolate->factory()->to_string_tag_symbol());
439 1889499 : if (maybe_tag->IsString())
440 : return std::make_pair(MaybeHandle<JSFunction>(),
441 : Handle<String>::cast(maybe_tag));
442 :
443 1173226 : PrototypeIterator iter(isolate, receiver);
444 1173226 : if (iter.IsAtEnd()) {
445 : return std::make_pair(MaybeHandle<JSFunction>(),
446 959872 : 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 693290 : Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
453 693290 : if (maybe_constructor->IsJSFunction()) {
454 : JSFunction constructor = JSFunction::cast(*maybe_constructor);
455 693290 : String name = constructor->shared()->DebugName();
456 :
457 1333578 : if (name->length() != 0 &&
458 640288 : !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 771816 : 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 3784116 : Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
477 3784116 : return GetConstructorHelper(receiver).second;
478 : }
479 :
480 408203 : Handle<NativeContext> JSReceiver::GetCreationContext() {
481 408203 : JSReceiver receiver = *this;
482 : // Externals are JSObjects with null as a constructor.
483 : DCHECK(!receiver->IsExternal(GetIsolate()));
484 408203 : Object constructor = receiver->map()->GetConstructor();
485 408203 : JSFunction function;
486 408203 : if (constructor->IsJSFunction()) {
487 197202 : 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 408201 : return function->has_context()
501 408201 : ? Handle<NativeContext>(function->context()->native_context(),
502 : receiver->GetIsolate())
503 816402 : : Handle<NativeContext>::null();
504 : }
505 :
506 : // static
507 3422 : MaybeHandle<NativeContext> JSReceiver::GetFunctionRealm(
508 : Handle<JSReceiver> receiver) {
509 3422 : if (receiver->IsJSProxy()) {
510 36 : return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
511 : }
512 :
513 3386 : if (receiver->IsJSFunction()) {
514 3377 : 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 6551 : MaybeHandle<NativeContext> JSReceiver::GetContextForMicrotask(
527 : Handle<JSReceiver> receiver) {
528 : Isolate* isolate = receiver->GetIsolate();
529 13570 : 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 6550 : if (!receiver->IsJSFunction()) return MaybeHandle<NativeContext>();
543 13100 : return handle(Handle<JSFunction>::cast(receiver)->native_context(), isolate);
544 : }
545 :
546 15551399 : Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
547 : LookupIterator* it) {
548 20151890 : for (; it->IsFound(); it->Next()) {
549 12176318 : 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 216297 : 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 39139 : 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 44889 : if (properties == roots.empty_fixed_array() ||
588 44875 : properties == roots.empty_property_array() ||
589 : properties == roots.empty_property_dictionary()) {
590 33781 : 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 41800065 : int GetIdentityHashHelper(JSReceiver object) {
610 : DisallowHeapAllocation no_gc;
611 : Object properties = object->raw_properties_or_hash();
612 41800065 : if (properties->IsSmi()) {
613 39269 : return Smi::ToInt(properties);
614 : }
615 :
616 41760796 : if (properties->IsPropertyArray()) {
617 : return PropertyArray::cast(properties)->Hash();
618 : }
619 :
620 25475405 : if (properties->IsNameDictionary()) {
621 : return NameDictionary::cast(properties)->Hash();
622 : }
623 :
624 22709325 : 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 33851 : void JSReceiver::SetIdentityHash(int hash) {
639 : DisallowHeapAllocation no_gc;
640 : DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
641 : DCHECK(PropertyArray::HashField::is_valid(hash));
642 :
643 33851 : HeapObject existing_properties = HeapObject::cast(raw_properties_or_hash());
644 33851 : Object new_properties = SetHashAndUpdateProperties(existing_properties, hash);
645 33851 : set_raw_properties_or_hash(new_properties);
646 33851 : }
647 :
648 41737327 : 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 41737327 : int hash = GetIdentityHashHelper(*this);
654 41737342 : 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 41737342 : if (hash != PropertyArray::kNoHashSentinel) {
659 5288 : new_properties = SetHashAndUpdateProperties(properties, hash);
660 : }
661 :
662 41737342 : set_raw_properties_or_hash(new_properties);
663 41737327 : }
664 :
665 41122 : Object JSReceiver::GetIdentityHash() {
666 : DisallowHeapAllocation no_gc;
667 :
668 41122 : int hash = GetIdentityHashHelper(*this);
669 41122 : if (hash == PropertyArray::kNoHashSentinel) {
670 2253 : return GetReadOnlyRoots().undefined_value();
671 : }
672 :
673 38869 : return Smi::FromInt(hash);
674 : }
675 :
676 : // static
677 33816 : Smi JSReceiver::CreateIdentityHash(Isolate* isolate, JSReceiver key) {
678 : DisallowHeapAllocation no_gc;
679 33816 : int hash = isolate->GenerateIdentityHash(PropertyArray::HashField::kMax);
680 : DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
681 :
682 33816 : key->SetIdentityHash(hash);
683 33816 : return Smi::FromInt(hash);
684 : }
685 :
686 21588 : Smi JSReceiver::GetOrCreateIdentityHash(Isolate* isolate) {
687 : DisallowHeapAllocation no_gc;
688 :
689 21588 : int hash = GetIdentityHashHelper(*this);
690 21588 : if (hash != PropertyArray::kNoHashSentinel) {
691 : return Smi::FromInt(hash);
692 : }
693 :
694 21078 : return JSReceiver::CreateIdentityHash(isolate, *this);
695 : }
696 :
697 54298 : void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
698 : int entry) {
699 : DCHECK(!object->HasFastProperties());
700 : Isolate* isolate = object->GetIsolate();
701 :
702 54298 : if (object->IsJSGlobalObject()) {
703 : // If we have a global object, invalidate the cell and swap in a new one.
704 : Handle<GlobalDictionary> dictionary(
705 22594 : 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 86002 : Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
714 : DCHECK_NE(NameDictionary::kNotFound, entry);
715 :
716 43001 : dictionary = NameDictionary::DeleteEntry(isolate, dictionary, entry);
717 86002 : object->SetProperties(*dictionary);
718 : }
719 54298 : 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 54298 : }
725 :
726 6391032 : Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
727 : LanguageMode language_mode) {
728 6391032 : it->UpdateProtector();
729 :
730 : Isolate* isolate = it->isolate();
731 :
732 6391032 : if (it->state() == LookupIterator::JSPROXY) {
733 : return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
734 28928 : it->GetName(), language_mode);
735 : }
736 :
737 6362104 : 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 6381899 : for (; it->IsFound(); it->Next()) {
748 170365 : 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 160343 : if (!it->IsConfigurable()) {
776 : // Fail if the property is not configurable.
777 2546 : if (is_strict(language_mode)) {
778 1486 : isolate->Throw(*isolate->factory()->NewTypeError(
779 : MessageTemplate::kStrictDeleteProperty, it->GetName(),
780 2229 : receiver));
781 : return Nothing<bool>();
782 : }
783 : return Just(false);
784 : }
785 :
786 157797 : 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 114568 : 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 114568 : 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 229010 : 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 114505 : 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 114370 : Just(kThrowOnError));
844 : // 7. ReturnIfAbrupt(success).
845 115406 : MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
846 113334 : 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 586750 : Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
931 : Handle<JSReceiver> object,
932 : Handle<Object> key,
933 : PropertyDescriptor* desc,
934 : Maybe<ShouldThrow> should_throw) {
935 586750 : if (object->IsJSArray()) {
936 : return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
937 29594 : key, desc, should_throw);
938 : }
939 557156 : if (object->IsJSProxy()) {
940 : return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
941 55749 : key, desc, should_throw);
942 : }
943 501407 : 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 497797 : desc, should_throw);
953 : }
954 :
955 : // static
956 536667 : Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(
957 : Isolate* isolate, Handle<JSObject> object, Handle<Object> key,
958 : PropertyDescriptor* desc, Maybe<ShouldThrow> should_throw) {
959 536667 : bool success = false;
960 : DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
961 : LookupIterator it = LookupIterator::PropertyOrElement(
962 536667 : isolate, object, key, &success, LookupIterator::OWN);
963 : DCHECK(success); // ...so creating a LookupIterator can't fail.
964 :
965 : // Deal with access checks first.
966 536668 : 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 536638 : return OrdinaryDefineOwnProperty(&it, desc, should_throw);
976 : }
977 :
978 : namespace {
979 :
980 125805 : MaybeHandle<Object> GetPropertyWithInterceptorInternal(
981 : LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
982 125805 : *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 125805 : 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 125551 : 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 125551 : *holder, Just(kDontThrow));
1001 :
1002 125551 : if (it->IsElement()) {
1003 2350 : result = args.CallIndexedGetter(interceptor, it->index());
1004 : } else {
1005 123201 : result = args.CallNamedGetter(interceptor, it->name());
1006 : }
1007 :
1008 125551 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1009 247787 : 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 536636 : 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 1073275 : MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>());
1160 :
1161 536621 : it->Restart();
1162 : // Handle interceptor
1163 909914 : for (; it->IsFound(); it->Next()) {
1164 186702 : 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 536564 : it->Restart();
1180 : // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
1181 536564 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
1182 536564 : bool extensible = JSObject::IsExtensible(object);
1183 :
1184 : return ValidateAndApplyPropertyDescriptor(
1185 536565 : 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 541171 : 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 541171 : if (current->is_empty()) {
1218 : // 2a. If extensible is false, return false.
1219 355170 : if (!extensible) {
1220 258 : 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 355071 : 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 287001 : if (it != nullptr) {
1236 284445 : if (!desc->has_writable()) desc->set_writable(false);
1237 284445 : if (!desc->has_enumerable()) desc->set_enumerable(false);
1238 284445 : if (!desc->has_configurable()) desc->set_configurable(false);
1239 : Handle<Object> value(
1240 : desc->has_value()
1241 : ? desc->value()
1242 293956 : : Handle<Object>::cast(isolate->factory()->undefined_value()));
1243 : MaybeHandle<Object> result =
1244 : JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
1245 284445 : desc->ToAttributes());
1246 284450 : 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 68070 : if (it != nullptr) {
1257 67926 : if (!desc->has_enumerable()) desc->set_enumerable(false);
1258 67926 : if (!desc->has_configurable()) desc->set_configurable(false);
1259 : Handle<Object> getter(
1260 : desc->has_get()
1261 : ? desc->get()
1262 80679 : : Handle<Object>::cast(isolate->factory()->null_value()));
1263 : Handle<Object> setter(
1264 : desc->has_set()
1265 : ? desc->set()
1266 109814 : : Handle<Object>::cast(isolate->factory()->null_value()));
1267 : MaybeHandle<Object> result =
1268 67926 : JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
1269 67926 : 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 329941 : if ((!desc->has_enumerable() ||
1280 69844 : desc->enumerable() == current->enumerable()) &&
1281 46657 : (!desc->has_configurable() ||
1282 67468 : desc->configurable() == current->configurable()) &&
1283 49839 : (!desc->has_value() ||
1284 278745 : (current->has_value() && current->value()->SameValue(*desc->value()))) &&
1285 26503 : (!desc->has_writable() ||
1286 68744 : (current->has_writable() && current->writable() == desc->writable())) &&
1287 5803 : (!desc->has_get() ||
1288 412651 : (current->has_get() && current->get()->SameValue(*desc->get()))) &&
1289 7206 : (!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 156431 : if (!current->configurable()) {
1295 : // 5a. Return false, if the [[Configurable]] field of Desc is true.
1296 7826 : 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 7162 : 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 156132 : 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 155224 : } else if (current_is_data_descriptor != desc_is_data_descriptor) {
1322 : // 7a. Return false, if the [[Configurable]] field of current is false.
1323 118083 : 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 37141 : } else if (current_is_data_descriptor && desc_is_data_descriptor) {
1349 : // 8a. If the [[Configurable]] field of current is false, then:
1350 26128 : 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 4244 : 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 3811 : 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 470 : if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
1364 775 : 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 155626 : 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 155365 : if (desc->has_enumerable()) {
1404 : attrs = static_cast<PropertyAttributes>(
1405 121184 : attrs | (desc->enumerable() ? NONE : DONT_ENUM));
1406 : } else {
1407 : attrs = static_cast<PropertyAttributes>(
1408 34181 : attrs | (current->enumerable() ? NONE : DONT_ENUM));
1409 : }
1410 155365 : if (desc->has_configurable()) {
1411 : attrs = static_cast<PropertyAttributes>(
1412 133292 : attrs | (desc->configurable() ? NONE : DONT_DELETE));
1413 : } else {
1414 : attrs = static_cast<PropertyAttributes>(
1415 22073 : attrs | (current->configurable() ? NONE : DONT_DELETE));
1416 : }
1417 284586 : if (desc_is_data_descriptor ||
1418 129221 : (desc_is_generic_descriptor && current_is_data_descriptor)) {
1419 26953 : if (desc->has_writable()) {
1420 : attrs = static_cast<PropertyAttributes>(
1421 24077 : attrs | (desc->writable() ? NONE : READ_ONLY));
1422 : } else {
1423 : attrs = static_cast<PropertyAttributes>(
1424 2876 : 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 29765 : isolate->factory()->undefined_value()));
1432 : return JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs,
1433 26953 : 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 135906 : : 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 365772 : : Handle<Object>::cast(isolate->factory()->null_value()));
1450 : MaybeHandle<Object> result =
1451 128412 : JSObject::DefineAccessor(it, getter, setter, attrs);
1452 128412 : if (result.is_null()) return Nothing<bool>();
1453 : }
1454 : }
1455 :
1456 : // 11. Return true.
1457 : return Just(true);
1458 : }
1459 :
1460 : // static
1461 104657 : 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 104657 : LookupIterator::OWN);
1468 104657 : return CreateDataProperty(&it, value, should_throw);
1469 : }
1470 :
1471 : // static
1472 1125847 : 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 1125847 : if (receiver->IsJSObject()) {
1480 1124801 : 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 2092 : &new_desc, should_throw);
1491 : }
1492 :
1493 : // static
1494 3188994 : Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
1495 : Handle<JSReceiver> object,
1496 : Handle<Object> key,
1497 : PropertyDescriptor* desc) {
1498 3188994 : bool success = false;
1499 : DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
1500 : LookupIterator it = LookupIterator::PropertyOrElement(
1501 3188994 : isolate, object, key, &success, LookupIterator::OWN);
1502 : DCHECK(success); // ...so creating a LookupIterator can't fail.
1503 3188995 : return GetOwnPropertyDescriptor(&it, desc);
1504 : }
1505 :
1506 : namespace {
1507 :
1508 3696428 : Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
1509 : PropertyDescriptor* desc) {
1510 3696428 : 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 3696378 : 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 3727996 : Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
1565 : PropertyDescriptor* desc) {
1566 : Isolate* isolate = it->isolate();
1567 : // "Virtual" dispatch.
1568 7072639 : if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
1569 : return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
1570 31568 : it->GetName(), desc);
1571 : }
1572 :
1573 3696428 : Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
1574 3696429 : MAYBE_RETURN(intercepted, Nothing<bool>());
1575 3696430 : 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 3696418 : Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
1583 3696416 : MAYBE_RETURN(maybe, Nothing<bool>());
1584 : PropertyAttributes attrs = maybe.FromJust();
1585 3696228 : 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 3485215 : bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
1593 172655 : it->GetAccessors()->IsAccessorPair();
1594 3312560 : if (!is_accessor_pair) {
1595 : // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
1596 : Handle<Object> value;
1597 6532773 : 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 3266285 : desc->set_writable((attrs & READ_ONLY) == 0);
1604 : } else {
1605 : // 6. Else X is an accessor property, so
1606 : Handle<AccessorPair> accessors =
1607 46174 : Handle<AccessorPair>::cast(it->GetAccessors());
1608 : // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
1609 46174 : desc->set_get(
1610 : AccessorPair::GetComponent(isolate, accessors, ACCESSOR_GETTER));
1611 : // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
1612 46174 : 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 3312459 : desc->set_enumerable((attrs & DONT_ENUM) == 0);
1618 : // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
1619 3312459 : 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 10983301 : Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
1626 : IntegrityLevel level,
1627 : ShouldThrow should_throw) {
1628 : DCHECK(level == SEALED || level == FROZEN);
1629 :
1630 10983301 : if (receiver->IsJSObject()) {
1631 : Handle<JSObject> object = Handle<JSObject>::cast(receiver);
1632 :
1633 32948624 : if (!object->HasSloppyArgumentsElements() &&
1634 : !object->IsJSModuleNamespace()) { // Fast path.
1635 : // Prevent memory leaks by not adding unnecessary transitions.
1636 10982774 : Maybe<bool> test = JSObject::TestIntegrityLevel(object, level);
1637 10982774 : MAYBE_RETURN(test, Nothing<bool>());
1638 10982776 : if (test.FromJust()) return test;
1639 :
1640 232088 : if (level == SEALED) {
1641 : return JSObject::PreventExtensionsWithTransition<SEALED>(object,
1642 752 : should_throw);
1643 : } else {
1644 : return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
1645 231336 : should_throw);
1646 : }
1647 : }
1648 : }
1649 :
1650 : Isolate* isolate = receiver->GetIsolate();
1651 :
1652 1055 : 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 280 : Maybe<bool> GenericTestIntegrityLevel(Handle<JSReceiver> receiver,
1697 : PropertyAttributes level) {
1698 : DCHECK(level == SEALED || level == FROZEN);
1699 :
1700 280 : Maybe<bool> extensible = JSReceiver::IsExtensible(receiver);
1701 280 : MAYBE_RETURN(extensible, Nothing<bool>());
1702 280 : 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 1423 : Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> receiver,
1731 : IntegrityLevel level) {
1732 1423 : if (!receiver->map()->IsCustomElementsReceiverMap()) {
1733 : return JSObject::TestIntegrityLevel(Handle<JSObject>::cast(receiver),
1734 1270 : level);
1735 : }
1736 153 : return GenericTestIntegrityLevel(receiver, level);
1737 : }
1738 :
1739 86067 : Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
1740 : ShouldThrow should_throw) {
1741 86067 : if (object->IsJSProxy()) {
1742 : return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
1743 81828 : should_throw);
1744 : }
1745 : DCHECK(object->IsJSObject());
1746 : return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
1747 4239 : should_throw);
1748 : }
1749 :
1750 1013449 : Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
1751 1013449 : if (object->IsJSProxy()) {
1752 81801 : return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
1753 : }
1754 931648 : return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
1755 : }
1756 :
1757 : // static
1758 1881182 : MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
1759 : ToPrimitiveHint hint) {
1760 : Isolate* const isolate = receiver->GetIsolate();
1761 : Handle<Object> exotic_to_prim;
1762 3762364 : ASSIGN_RETURN_ON_EXCEPTION(
1763 : isolate, exotic_to_prim,
1764 : Object::GetMethod(receiver, isolate->factory()->to_primitive_symbol()),
1765 : Object);
1766 1881177 : if (!exotic_to_prim->IsUndefined(isolate)) {
1767 : Handle<Object> hint_string =
1768 3094 : isolate->factory()->ToPrimitiveHintString(hint);
1769 : Handle<Object> result;
1770 6188 : ASSIGN_RETURN_ON_EXCEPTION(
1771 : isolate, result,
1772 : Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string),
1773 : Object);
1774 2959 : 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 1878083 : : OrdinaryToPrimitiveHint::kNumber);
1782 : }
1783 :
1784 : // static
1785 1878083 : MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
1786 : Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) {
1787 : Isolate* const isolate = receiver->GetIsolate();
1788 9390415 : Handle<String> method_names[2];
1789 1878083 : switch (hint) {
1790 : case OrdinaryToPrimitiveHint::kNumber:
1791 6118 : method_names[0] = isolate->factory()->valueOf_string();
1792 6118 : method_names[1] = isolate->factory()->toString_string();
1793 6118 : break;
1794 : case OrdinaryToPrimitiveHint::kString:
1795 1871965 : method_names[0] = isolate->factory()->toString_string();
1796 1871965 : method_names[1] = isolate->factory()->valueOf_string();
1797 1871965 : break;
1798 : }
1799 1881551 : for (Handle<String> name : method_names) {
1800 : Handle<Object> method;
1801 3759544 : ASSIGN_RETURN_ON_EXCEPTION(isolate, method,
1802 : JSReceiver::GetProperty(isolate, receiver, name),
1803 : Object);
1804 1879754 : if (method->IsCallable()) {
1805 : Handle<Object> result;
1806 3758860 : ASSIGN_RETURN_ON_EXCEPTION(
1807 : isolate, result,
1808 : Execution::Call(isolate, method, receiver, 0, nullptr), Object);
1809 1870605 : 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 4242 : 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 3024 : 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 3954 : 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 0 : 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 280902 : Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
1979 : Handle<Object> value, bool from_javascript,
1980 : ShouldThrow should_throw) {
1981 280902 : if (object->IsJSProxy()) {
1982 : return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
1983 72666 : from_javascript, should_throw);
1984 : }
1985 : return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
1986 208236 : from_javascript, should_throw);
1987 : }
1988 :
1989 4216 : bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
1990 30592 : for (PrototypeIterator iter(isolate, *this, kStartAtReceiver,
1991 : PrototypeIterator::END_AT_NULL);
1992 13188 : !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
1993 13215 : if (iter.GetCurrent()->IsJSProxy()) return true;
1994 : }
1995 4189 : 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 2794833 : 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 5589680 : ASSIGN_RETURN_ON_EXCEPTION(
2025 : isolate, initial_map,
2026 : JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
2027 : Handle<JSObject> result = isolate->factory()->NewJSObjectFromMap(
2028 2794766 : initial_map, AllocationType::kYoung, site);
2029 2794762 : if (initial_map->is_dictionary_map()) {
2030 : Handle<NameDictionary> dictionary =
2031 0 : NameDictionary::New(isolate, NameDictionary::kInitialCapacity);
2032 0 : result->SetProperties(*dictionary);
2033 : }
2034 2794762 : isolate->counters()->constructed_objects()->Increment();
2035 2794766 : isolate->counters()->constructed_objects_runtime()->Increment();
2036 2794772 : 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 121132 : 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 121132 : Map::GetObjectCreateMap(isolate, Handle<HeapObject>::cast(prototype));
2049 :
2050 : // Actually allocate the object.
2051 : Handle<JSObject> object;
2052 121132 : if (map->is_dictionary_map()) {
2053 365 : object = isolate->factory()->NewSlowJSObjectFromMap(map);
2054 : } else {
2055 120767 : object = isolate->factory()->NewJSObjectFromMap(map);
2056 : }
2057 121132 : return object;
2058 : }
2059 :
2060 4325121 : void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
2061 : DCHECK(object->HasSmiOrObjectElements() ||
2062 : object->HasFastStringWrapperElements());
2063 : FixedArray raw_elems = FixedArray::cast(object->elements());
2064 : Isolate* isolate = object->GetIsolate();
2065 8636305 : if (raw_elems->map() != ReadOnlyRoots(isolate).fixed_cow_array_map()) return;
2066 : Handle<FixedArray> elems(raw_elems, isolate);
2067 : Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
2068 13937 : elems, isolate->factory()->fixed_array_map());
2069 27874 : object->set_elements(*writable_elems);
2070 13937 : isolate->counters()->cow_arrays_converted()->Increment();
2071 : }
2072 :
2073 82859135 : int JSObject::GetHeaderSize(InstanceType type,
2074 : bool function_has_prototype_slot) {
2075 82859135 : switch (type) {
2076 : case JS_OBJECT_TYPE:
2077 : case JS_API_OBJECT_TYPE:
2078 : case JS_SPECIAL_API_OBJECT_TYPE:
2079 : return JSObject::kHeaderSize;
2080 : case JS_GENERATOR_OBJECT_TYPE:
2081 1321199 : return JSGeneratorObject::kSize;
2082 : case JS_ASYNC_FUNCTION_OBJECT_TYPE:
2083 1836 : return JSAsyncFunctionObject::kSize;
2084 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
2085 2857 : return JSAsyncGeneratorObject::kSize;
2086 : case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
2087 139 : return JSAsyncFromSyncIterator::kSize;
2088 : case JS_GLOBAL_PROXY_TYPE:
2089 418502 : return JSGlobalProxy::kSize;
2090 : case JS_GLOBAL_OBJECT_TYPE:
2091 298745 : return JSGlobalObject::kSize;
2092 : case JS_BOUND_FUNCTION_TYPE:
2093 563616 : return JSBoundFunction::kSize;
2094 : case JS_FUNCTION_TYPE:
2095 67952335 : return JSFunction::GetHeaderSize(function_has_prototype_slot);
2096 : case JS_VALUE_TYPE:
2097 1464777 : return JSValue::kSize;
2098 : case JS_DATE_TYPE:
2099 16810 : return JSDate::kSize;
2100 : case JS_ARRAY_TYPE:
2101 2105428 : return JSArray::kSize;
2102 : case JS_ARRAY_BUFFER_TYPE:
2103 1450060 : return JSArrayBuffer::kHeaderSize;
2104 : case JS_ARRAY_ITERATOR_TYPE:
2105 3709 : return JSArrayIterator::kSize;
2106 : case JS_TYPED_ARRAY_TYPE:
2107 234858 : return JSTypedArray::kHeaderSize;
2108 : case JS_DATA_VIEW_TYPE:
2109 8901 : return JSDataView::kHeaderSize;
2110 : case JS_SET_TYPE:
2111 22202 : return JSSet::kSize;
2112 : case JS_MAP_TYPE:
2113 17617 : return JSMap::kSize;
2114 : case JS_SET_KEY_VALUE_ITERATOR_TYPE:
2115 : case JS_SET_VALUE_ITERATOR_TYPE:
2116 381 : return JSSetIterator::kSize;
2117 : case JS_MAP_KEY_ITERATOR_TYPE:
2118 : case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
2119 : case JS_MAP_VALUE_ITERATOR_TYPE:
2120 438 : return JSMapIterator::kSize;
2121 : case WEAK_CELL_TYPE:
2122 0 : return WeakCell::kSize;
2123 : case JS_WEAK_REF_TYPE:
2124 352 : return JSWeakRef::kSize;
2125 : case JS_FINALIZATION_GROUP_TYPE:
2126 730 : return JSFinalizationGroup::kSize;
2127 : case JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE:
2128 436 : return JSFinalizationGroupCleanupIterator::kSize;
2129 : case JS_WEAK_MAP_TYPE:
2130 38052 : return JSWeakMap::kSize;
2131 : case JS_WEAK_SET_TYPE:
2132 9134 : return JSWeakSet::kSize;
2133 : case JS_PROMISE_TYPE:
2134 552506 : return JSPromise::kSize;
2135 : case JS_REGEXP_TYPE:
2136 260094 : return JSRegExp::kSize;
2137 : case JS_REGEXP_STRING_ITERATOR_TYPE:
2138 90174 : return JSRegExpStringIterator::kSize;
2139 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
2140 : return JSObject::kHeaderSize;
2141 : case JS_MESSAGE_OBJECT_TYPE:
2142 432 : return JSMessageObject::kSize;
2143 : case JS_ARGUMENTS_TYPE:
2144 : return JSObject::kHeaderSize;
2145 : case JS_ERROR_TYPE:
2146 : return JSObject::kHeaderSize;
2147 : case JS_STRING_ITERATOR_TYPE:
2148 133 : return JSStringIterator::kSize;
2149 : case JS_MODULE_NAMESPACE_TYPE:
2150 1366 : return JSModuleNamespace::kHeaderSize;
2151 : #ifdef V8_INTL_SUPPORT
2152 : case JS_INTL_V8_BREAK_ITERATOR_TYPE:
2153 148 : return JSV8BreakIterator::kSize;
2154 : case JS_INTL_COLLATOR_TYPE:
2155 144 : return JSCollator::kSize;
2156 : case JS_INTL_DATE_TIME_FORMAT_TYPE:
2157 175 : return JSDateTimeFormat::kSize;
2158 : case JS_INTL_LIST_FORMAT_TYPE:
2159 182 : return JSListFormat::kSize;
2160 : case JS_INTL_LOCALE_TYPE:
2161 90264 : return JSLocale::kSize;
2162 : case JS_INTL_NUMBER_FORMAT_TYPE:
2163 204 : return JSNumberFormat::kSize;
2164 : case JS_INTL_PLURAL_RULES_TYPE:
2165 114 : return JSPluralRules::kSize;
2166 : case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
2167 162 : return JSRelativeTimeFormat::kSize;
2168 : case JS_INTL_SEGMENT_ITERATOR_TYPE:
2169 598 : return JSSegmentIterator::kSize;
2170 : case JS_INTL_SEGMENTER_TYPE:
2171 646 : return JSSegmenter::kSize;
2172 : #endif // V8_INTL_SUPPORT
2173 : case WASM_GLOBAL_TYPE:
2174 80754 : return WasmGlobalObject::kSize;
2175 : case WASM_INSTANCE_TYPE:
2176 33845 : return WasmInstanceObject::kSize;
2177 : case WASM_MEMORY_TYPE:
2178 84658 : return WasmMemoryObject::kSize;
2179 : case WASM_MODULE_TYPE:
2180 691959 : return WasmModuleObject::kSize;
2181 : case WASM_TABLE_TYPE:
2182 82675 : return WasmTableObject::kSize;
2183 : case WASM_EXCEPTION_TYPE:
2184 228 : return WasmExceptionObject::kSize;
2185 : default:
2186 0 : UNREACHABLE();
2187 : }
2188 : }
2189 :
2190 : // static
2191 1240 : bool JSObject::AllCanRead(LookupIterator* it) {
2192 : // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
2193 : // which have already been checked.
2194 : DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
2195 : it->state() == LookupIterator::INTERCEPTOR);
2196 2411 : for (it->Next(); it->IsFound(); it->Next()) {
2197 1241 : if (it->state() == LookupIterator::ACCESSOR) {
2198 122 : auto accessors = it->GetAccessors();
2199 122 : if (accessors->IsAccessorInfo()) {
2200 77 : if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
2201 : }
2202 1119 : } else if (it->state() == LookupIterator::INTERCEPTOR) {
2203 1260 : if (it->GetInterceptor()->all_can_read()) return true;
2204 489 : } else if (it->state() == LookupIterator::JSPROXY) {
2205 : // Stop lookupiterating. And no, AllCanNotRead.
2206 : return false;
2207 : }
2208 : }
2209 : return false;
2210 : }
2211 :
2212 1174 : MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
2213 : LookupIterator* it) {
2214 : Isolate* isolate = it->isolate();
2215 1174 : Handle<JSObject> checked = it->GetHolder<JSObject>();
2216 : Handle<InterceptorInfo> interceptor =
2217 1174 : it->GetInterceptorForFailedAccessCheck();
2218 1174 : if (interceptor.is_null()) {
2219 1079 : while (AllCanRead(it)) {
2220 46 : if (it->state() == LookupIterator::ACCESSOR) {
2221 52 : return Object::GetPropertyWithAccessor(it);
2222 : }
2223 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
2224 : bool done;
2225 : Handle<Object> result;
2226 30 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
2227 : GetPropertyWithInterceptor(it, &done), Object);
2228 30 : if (done) return result;
2229 : }
2230 :
2231 : } else {
2232 : Handle<Object> result;
2233 : bool done;
2234 230 : ASSIGN_RETURN_ON_EXCEPTION(
2235 : isolate, result,
2236 : GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
2237 105 : if (done) return result;
2238 : }
2239 :
2240 : // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns
2241 : // undefined.
2242 1083 : Handle<Name> name = it->GetName();
2243 1140 : if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) {
2244 52 : return it->factory()->undefined_value();
2245 : }
2246 :
2247 1031 : isolate->ReportFailedAccessCheck(checked);
2248 1031 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
2249 0 : return it->factory()->undefined_value();
2250 : }
2251 :
2252 121 : Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
2253 : LookupIterator* it) {
2254 : Isolate* isolate = it->isolate();
2255 121 : Handle<JSObject> checked = it->GetHolder<JSObject>();
2256 : Handle<InterceptorInfo> interceptor =
2257 121 : it->GetInterceptorForFailedAccessCheck();
2258 121 : if (interceptor.is_null()) {
2259 121 : while (AllCanRead(it)) {
2260 10 : if (it->state() == LookupIterator::ACCESSOR) {
2261 : return Just(it->property_attributes());
2262 : }
2263 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
2264 : auto result = GetPropertyAttributesWithInterceptor(it);
2265 0 : if (isolate->has_scheduled_exception()) break;
2266 0 : if (result.IsJust() && result.FromJust() != ABSENT) return result;
2267 : }
2268 : } else {
2269 : Maybe<PropertyAttributes> result =
2270 0 : GetPropertyAttributesWithInterceptorInternal(it, interceptor);
2271 0 : if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
2272 0 : if (result.FromMaybe(ABSENT) != ABSENT) return result;
2273 : }
2274 111 : isolate->ReportFailedAccessCheck(checked);
2275 111 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
2276 : return Just(ABSENT);
2277 : }
2278 :
2279 : // static
2280 78 : bool JSObject::AllCanWrite(LookupIterator* it) {
2281 304 : for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
2282 123 : if (it->state() == LookupIterator::ACCESSOR) {
2283 25 : Handle<Object> accessors = it->GetAccessors();
2284 25 : if (accessors->IsAccessorInfo()) {
2285 15 : if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
2286 : }
2287 : }
2288 : }
2289 : return false;
2290 : }
2291 :
2292 108 : Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
2293 : LookupIterator* it, Handle<Object> value, Maybe<ShouldThrow> should_throw) {
2294 : Isolate* isolate = it->isolate();
2295 108 : Handle<JSObject> checked = it->GetHolder<JSObject>();
2296 : Handle<InterceptorInfo> interceptor =
2297 108 : it->GetInterceptorForFailedAccessCheck();
2298 108 : if (interceptor.is_null()) {
2299 78 : if (AllCanWrite(it)) {
2300 10 : return Object::SetPropertyWithAccessor(it, value, should_throw);
2301 : }
2302 : } else {
2303 : Maybe<bool> result = SetPropertyWithInterceptorInternal(
2304 30 : it, interceptor, should_throw, value);
2305 60 : if (isolate->has_pending_exception()) return Nothing<bool>();
2306 20 : if (result.IsJust()) return result;
2307 : }
2308 68 : isolate->ReportFailedAccessCheck(checked);
2309 68 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
2310 : return Just(true);
2311 : }
2312 :
2313 338258 : void JSObject::SetNormalizedProperty(Handle<JSObject> object, Handle<Name> name,
2314 : Handle<Object> value,
2315 : PropertyDetails details) {
2316 : DCHECK(!object->HasFastProperties());
2317 : DCHECK(name->IsUniqueName());
2318 : Isolate* isolate = object->GetIsolate();
2319 :
2320 338258 : uint32_t hash = name->Hash();
2321 :
2322 338258 : if (object->IsJSGlobalObject()) {
2323 : Handle<JSGlobalObject> global_obj = Handle<JSGlobalObject>::cast(object);
2324 : Handle<GlobalDictionary> dictionary(global_obj->global_dictionary(),
2325 19254 : isolate);
2326 19254 : int entry = dictionary->FindEntry(ReadOnlyRoots(isolate), name, hash);
2327 :
2328 9627 : if (entry == GlobalDictionary::kNotFound) {
2329 : DCHECK_IMPLIES(global_obj->map()->is_prototype_map(),
2330 : Map::IsPrototypeChainInvalidated(global_obj->map()));
2331 1020 : auto cell = isolate->factory()->NewPropertyCell(name);
2332 1020 : cell->set_value(*value);
2333 : auto cell_type = value->IsUndefined(isolate)
2334 : ? PropertyCellType::kUndefined
2335 1020 : : PropertyCellType::kConstant;
2336 : details = details.set_cell_type(cell_type);
2337 : value = cell;
2338 : dictionary =
2339 1020 : GlobalDictionary::Add(isolate, dictionary, name, value, details);
2340 2040 : global_obj->set_global_dictionary(*dictionary);
2341 : } else {
2342 : Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
2343 8607 : isolate, dictionary, entry, value, details);
2344 8607 : cell->set_value(*value);
2345 : }
2346 : } else {
2347 657262 : Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
2348 :
2349 328631 : int entry = dictionary->FindEntry(isolate, name);
2350 328631 : if (entry == NameDictionary::kNotFound) {
2351 : DCHECK_IMPLIES(object->map()->is_prototype_map(),
2352 : Map::IsPrototypeChainInvalidated(object->map()));
2353 : dictionary =
2354 97850 : NameDictionary::Add(isolate, dictionary, name, value, details);
2355 195700 : object->SetProperties(*dictionary);
2356 : } else {
2357 230781 : PropertyDetails original_details = dictionary->DetailsAt(entry);
2358 : int enumeration_index = original_details.dictionary_index();
2359 : DCHECK_GT(enumeration_index, 0);
2360 : details = details.set_index(enumeration_index);
2361 461562 : dictionary->SetEntry(isolate, entry, *name, *value, details);
2362 : }
2363 : }
2364 338258 : }
2365 :
2366 34856 : void JSObject::JSObjectShortPrint(StringStream* accumulator) {
2367 34856 : switch (map()->instance_type()) {
2368 : case JS_ARRAY_TYPE: {
2369 : double length = JSArray::cast(*this)->length()->IsUndefined()
2370 : ? 0
2371 1005 : : JSArray::cast(*this)->length()->Number();
2372 1005 : accumulator->Add("<JSArray[%u]>", static_cast<uint32_t>(length));
2373 1005 : break;
2374 : }
2375 : case JS_BOUND_FUNCTION_TYPE: {
2376 : JSBoundFunction bound_function = JSBoundFunction::cast(*this);
2377 0 : accumulator->Add("<JSBoundFunction");
2378 0 : accumulator->Add(" (BoundTargetFunction %p)>",
2379 : reinterpret_cast<void*>(
2380 0 : bound_function->bound_target_function().ptr()));
2381 : break;
2382 : }
2383 : case JS_WEAK_MAP_TYPE: {
2384 0 : accumulator->Add("<JSWeakMap>");
2385 0 : break;
2386 : }
2387 : case JS_WEAK_SET_TYPE: {
2388 0 : accumulator->Add("<JSWeakSet>");
2389 0 : break;
2390 : }
2391 : case JS_REGEXP_TYPE: {
2392 18 : accumulator->Add("<JSRegExp");
2393 : JSRegExp regexp = JSRegExp::cast(*this);
2394 18 : if (regexp->source()->IsString()) {
2395 18 : accumulator->Add(" ");
2396 18 : String::cast(regexp->source())->StringShortPrint(accumulator);
2397 : }
2398 18 : accumulator->Add(">");
2399 :
2400 : break;
2401 : }
2402 : case JS_FUNCTION_TYPE: {
2403 : JSFunction function = JSFunction::cast(*this);
2404 22374 : Object fun_name = function->shared()->DebugName();
2405 : bool printed = false;
2406 22374 : if (fun_name->IsString()) {
2407 : String str = String::cast(fun_name);
2408 22374 : if (str->length() > 0) {
2409 17682 : accumulator->Add("<JSFunction ");
2410 17682 : accumulator->Put(str);
2411 : printed = true;
2412 : }
2413 : }
2414 22374 : if (!printed) {
2415 4692 : accumulator->Add("<JSFunction");
2416 : }
2417 22374 : if (FLAG_trace_file_names) {
2418 0 : Object source_name = Script::cast(function->shared()->script())->name();
2419 0 : if (source_name->IsString()) {
2420 : String str = String::cast(source_name);
2421 0 : if (str->length() > 0) {
2422 0 : accumulator->Add(" <");
2423 0 : accumulator->Put(str);
2424 0 : accumulator->Add(">");
2425 : }
2426 : }
2427 : }
2428 22374 : accumulator->Add(" (sfi = %p)",
2429 22374 : reinterpret_cast<void*>(function->shared().ptr()));
2430 22374 : accumulator->Put('>');
2431 : break;
2432 : }
2433 : case JS_GENERATOR_OBJECT_TYPE: {
2434 0 : accumulator->Add("<JSGenerator>");
2435 0 : break;
2436 : }
2437 : case JS_ASYNC_FUNCTION_OBJECT_TYPE: {
2438 0 : accumulator->Add("<JSAsyncFunctionObject>");
2439 0 : break;
2440 : }
2441 : case JS_ASYNC_GENERATOR_OBJECT_TYPE: {
2442 0 : accumulator->Add("<JS AsyncGenerator>");
2443 0 : break;
2444 : }
2445 :
2446 : // All other JSObjects are rather similar to each other (JSObject,
2447 : // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
2448 : default: {
2449 11459 : Map map_of_this = map();
2450 : Heap* heap = GetHeap();
2451 11459 : Object constructor = map_of_this->GetConstructor();
2452 : bool printed = false;
2453 22918 : if (constructor->IsHeapObject() &&
2454 11459 : !heap->Contains(HeapObject::cast(constructor))) {
2455 0 : accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
2456 : } else {
2457 : bool global_object = IsJSGlobalProxy();
2458 11459 : if (constructor->IsJSFunction()) {
2459 11459 : if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
2460 0 : accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
2461 : } else {
2462 : String constructor_name =
2463 11459 : JSFunction::cast(constructor)->shared()->Name();
2464 11459 : if (constructor_name->length() > 0) {
2465 10066 : accumulator->Add(global_object ? "<GlobalObject " : "<");
2466 10066 : accumulator->Put(constructor_name);
2467 10066 : accumulator->Add(
2468 : " %smap = %p",
2469 : map_of_this->is_deprecated() ? "deprecated-" : "",
2470 10066 : map_of_this);
2471 : printed = true;
2472 : }
2473 : }
2474 0 : } else if (constructor->IsFunctionTemplateInfo()) {
2475 0 : accumulator->Add(global_object ? "<RemoteObject>" : "<RemoteObject>");
2476 : printed = true;
2477 : }
2478 11459 : if (!printed) {
2479 1393 : accumulator->Add("<JS%sObject", global_object ? "Global " : "");
2480 : }
2481 : }
2482 11459 : if (IsJSValue()) {
2483 84 : accumulator->Add(" value = ");
2484 84 : JSValue::cast(*this)->value()->ShortPrint(accumulator);
2485 : }
2486 11459 : accumulator->Put('>');
2487 : break;
2488 : }
2489 : }
2490 34856 : }
2491 :
2492 0 : void JSObject::PrintElementsTransition(FILE* file, Handle<JSObject> object,
2493 : ElementsKind from_kind,
2494 : Handle<FixedArrayBase> from_elements,
2495 : ElementsKind to_kind,
2496 : Handle<FixedArrayBase> to_elements) {
2497 0 : if (from_kind != to_kind) {
2498 0 : OFStream os(file);
2499 0 : os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
2500 0 : << ElementsKindToString(to_kind) << "] in ";
2501 0 : JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
2502 0 : PrintF(file, " for ");
2503 0 : object->ShortPrint(file);
2504 0 : PrintF(file, " from ");
2505 0 : from_elements->ShortPrint(file);
2506 0 : PrintF(file, " to ");
2507 0 : to_elements->ShortPrint(file);
2508 0 : PrintF(file, "\n");
2509 : }
2510 0 : }
2511 :
2512 0 : void JSObject::PrintInstanceMigration(FILE* file, Map original_map,
2513 : Map new_map) {
2514 0 : if (new_map->is_dictionary_map()) {
2515 0 : PrintF(file, "[migrating to slow]\n");
2516 0 : return;
2517 : }
2518 0 : PrintF(file, "[migrating]");
2519 0 : DescriptorArray o = original_map->instance_descriptors();
2520 0 : DescriptorArray n = new_map->instance_descriptors();
2521 0 : for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
2522 0 : Representation o_r = o->GetDetails(i).representation();
2523 0 : Representation n_r = n->GetDetails(i).representation();
2524 0 : if (!o_r.Equals(n_r)) {
2525 0 : String::cast(o->GetKey(i))->PrintOn(file);
2526 0 : PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
2527 0 : } else if (o->GetDetails(i).location() == kDescriptor &&
2528 0 : n->GetDetails(i).location() == kField) {
2529 0 : Name name = o->GetKey(i);
2530 0 : if (name->IsString()) {
2531 0 : String::cast(name)->PrintOn(file);
2532 : } else {
2533 0 : PrintF(file, "{symbol %p}", reinterpret_cast<void*>(name.ptr()));
2534 : }
2535 0 : PrintF(file, " ");
2536 : }
2537 : }
2538 0 : if (original_map->elements_kind() != new_map->elements_kind()) {
2539 0 : PrintF(file, "elements_kind[%i->%i]", original_map->elements_kind(),
2540 0 : new_map->elements_kind());
2541 : }
2542 0 : PrintF(file, "\n");
2543 : }
2544 :
2545 113149 : bool JSObject::IsUnmodifiedApiObject(FullObjectSlot o) {
2546 : Object object = *o;
2547 113149 : if (object->IsSmi()) return false;
2548 : HeapObject heap_object = HeapObject::cast(object);
2549 113149 : if (!object->IsJSObject()) return false;
2550 14417 : JSObject js_object = JSObject::cast(object);
2551 14417 : if (!js_object->IsDroppableApiWrapper()) return false;
2552 66 : Object maybe_constructor = js_object->map()->GetConstructor();
2553 66 : if (!maybe_constructor->IsJSFunction()) return false;
2554 : JSFunction constructor = JSFunction::cast(maybe_constructor);
2555 66 : if (js_object->elements()->length() != 0) return false;
2556 :
2557 : return constructor->initial_map() == heap_object->map();
2558 : }
2559 :
2560 : // static
2561 4376988 : void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
2562 : Handle<Map> new_map,
2563 : Isolate* isolate) {
2564 : DCHECK(old_map->is_prototype_map());
2565 : DCHECK(new_map->is_prototype_map());
2566 4376988 : bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
2567 4376982 : new_map->set_prototype_info(old_map->prototype_info());
2568 4376986 : old_map->set_prototype_info(Smi::kZero);
2569 4376991 : if (FLAG_trace_prototype_users) {
2570 0 : PrintF("Moving prototype_info %p from map %p to map %p.\n",
2571 : reinterpret_cast<void*>(new_map->prototype_info()->ptr()),
2572 : reinterpret_cast<void*>(old_map->ptr()),
2573 0 : reinterpret_cast<void*>(new_map->ptr()));
2574 : }
2575 4376987 : if (was_registered) {
2576 194237 : if (new_map->prototype_info()->IsPrototypeInfo()) {
2577 : // The new map isn't registered with its prototype yet; reflect this fact
2578 : // in the PrototypeInfo it just inherited from the old map.
2579 : PrototypeInfo::cast(new_map->prototype_info())
2580 : ->set_registry_slot(PrototypeInfo::UNREGISTERED);
2581 : }
2582 194237 : JSObject::LazyRegisterPrototypeUser(new_map, isolate);
2583 : }
2584 4376987 : }
2585 :
2586 : // static
2587 30615042 : void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
2588 : Isolate* isolate) {
2589 30615042 : if (!old_map->is_prototype_map()) return;
2590 :
2591 : InvalidatePrototypeChains(*old_map);
2592 :
2593 : // If the map was registered with its prototype before, ensure that it
2594 : // registers with its new prototype now. This preserves the invariant that
2595 : // when a map on a prototype chain is registered with its prototype, then
2596 : // all prototypes further up the chain are also registered with their
2597 : // respective prototypes.
2598 4376989 : UpdatePrototypeUserRegistration(old_map, new_map, isolate);
2599 : }
2600 :
2601 : namespace {
2602 : // To migrate a fast instance to a fast map:
2603 : // - First check whether the instance needs to be rewritten. If not, simply
2604 : // change the map.
2605 : // - Otherwise, allocate a fixed array large enough to hold all fields, in
2606 : // addition to unused space.
2607 : // - Copy all existing properties in, in the following order: backing store
2608 : // properties, unused fields, inobject properties.
2609 : // - If all allocation succeeded, commit the state atomically:
2610 : // * Copy inobject properties from the backing store back into the object.
2611 : // * Trim the difference in instance size of the object. This also cleanly
2612 : // frees inobject properties that moved to the backing store.
2613 : // * If there are properties left in the backing store, trim of the space used
2614 : // to temporarily store the inobject properties.
2615 : // * If there are properties left in the backing store, install the backing
2616 : // store.
2617 28957721 : void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
2618 : Isolate* isolate = object->GetIsolate();
2619 : Handle<Map> old_map(object->map(), isolate);
2620 : // In case of a regular transition.
2621 57915442 : if (new_map->GetBackPointer() == *old_map) {
2622 : // If the map does not add named properties, simply set the map.
2623 12965296 : if (old_map->NumberOfOwnDescriptors() ==
2624 : new_map->NumberOfOwnDescriptors()) {
2625 526376 : object->synchronized_set_map(*new_map);
2626 526378 : return;
2627 : }
2628 :
2629 12438920 : PropertyDetails details = new_map->GetLastDescriptorDetails();
2630 12438916 : int target_index = details.field_index() - new_map->GetInObjectProperties();
2631 24877841 : int property_array_length = object->property_array()->length();
2632 28398644 : bool have_space = old_map->UnusedPropertyFields() > 0 ||
2633 7019734 : (details.location() == kField && target_index >= 0 &&
2634 3509867 : property_array_length > target_index);
2635 : // Either new_map adds an kDescriptor property, or a kField property for
2636 : // which there is still space, and which does not require a mutable double
2637 : // box (an out-of-object double).
2638 24877856 : if (details.location() == kDescriptor ||
2639 8909723 : (have_space && ((FLAG_unbox_double_fields && target_index < 0) ||
2640 : !details.representation().IsDouble()))) {
2641 8913983 : object->synchronized_set_map(*new_map);
2642 8913982 : return;
2643 : }
2644 :
2645 : // If there is still space in the object, we need to allocate a mutable
2646 : // double box.
2647 3524945 : if (have_space) {
2648 : FieldIndex index =
2649 15326 : FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
2650 : DCHECK(details.representation().IsDouble());
2651 : DCHECK(!new_map->IsUnboxedDoubleField(index));
2652 : auto value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
2653 30652 : object->RawFastPropertyAtPut(index, *value);
2654 15326 : object->synchronized_set_map(*new_map);
2655 : return;
2656 : }
2657 :
2658 : // This migration is a transition from a map that has run out of property
2659 : // space. Extend the backing store.
2660 3509619 : int grow_by = new_map->UnusedPropertyFields() + 1;
2661 7019238 : Handle<PropertyArray> old_storage(object->property_array(), isolate);
2662 : Handle<PropertyArray> new_storage =
2663 3509619 : isolate->factory()->CopyPropertyArrayAndGrow(old_storage, grow_by);
2664 :
2665 : // Properly initialize newly added property.
2666 : Handle<Object> value;
2667 3509619 : if (details.representation().IsDouble()) {
2668 : value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
2669 : } else {
2670 : value = isolate->factory()->uninitialized_value();
2671 : }
2672 : DCHECK_EQ(kField, details.location());
2673 : DCHECK_EQ(kData, details.kind());
2674 : DCHECK_GE(target_index, 0); // Must be a backing store index.
2675 3509619 : new_storage->set(target_index, *value);
2676 :
2677 : // From here on we cannot fail and we shouldn't GC anymore.
2678 : DisallowHeapAllocation no_allocation;
2679 :
2680 : // Set the new property value and do the map transition.
2681 7019238 : object->SetProperties(*new_storage);
2682 3509619 : object->synchronized_set_map(*new_map);
2683 3509619 : return;
2684 : }
2685 :
2686 : int old_number_of_fields;
2687 15992423 : int number_of_fields = new_map->NumberOfFields();
2688 15992433 : int inobject = new_map->GetInObjectProperties();
2689 15992441 : int unused = new_map->UnusedPropertyFields();
2690 :
2691 : // Nothing to do if no functions were converted to fields and no smis were
2692 : // converted to doubles.
2693 15992443 : if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
2694 : unused, &old_number_of_fields)) {
2695 6229174 : object->synchronized_set_map(*new_map);
2696 6229174 : return;
2697 : }
2698 :
2699 9763296 : int total_size = number_of_fields + unused;
2700 9763296 : int external = total_size - inobject;
2701 9763296 : Handle<PropertyArray> array = isolate->factory()->NewPropertyArray(external);
2702 :
2703 : // We use this array to temporarily store the inobject properties.
2704 : Handle<FixedArray> inobject_props =
2705 9763274 : isolate->factory()->NewFixedArray(inobject);
2706 :
2707 : Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors(),
2708 : isolate);
2709 : Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors(),
2710 : isolate);
2711 : int old_nof = old_map->NumberOfOwnDescriptors();
2712 : int new_nof = new_map->NumberOfOwnDescriptors();
2713 :
2714 : // This method only supports generalizing instances to at least the same
2715 : // number of properties.
2716 : DCHECK(old_nof <= new_nof);
2717 :
2718 171125678 : for (int i = 0; i < old_nof; i++) {
2719 80681175 : PropertyDetails details = new_descriptors->GetDetails(i);
2720 80681192 : if (details.location() != kField) continue;
2721 : DCHECK_EQ(kData, details.kind());
2722 76776315 : PropertyDetails old_details = old_descriptors->GetDetails(i);
2723 : Representation old_representation = old_details.representation();
2724 : Representation representation = details.representation();
2725 : Handle<Object> value;
2726 76776321 : if (old_details.location() == kDescriptor) {
2727 16094 : if (old_details.kind() == kAccessor) {
2728 : // In case of kAccessor -> kData property reconfiguration, the property
2729 : // must already be prepared for data of certain type.
2730 : DCHECK(!details.representation().IsNone());
2731 16094 : if (details.representation().IsDouble()) {
2732 : value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
2733 : } else {
2734 : value = isolate->factory()->uninitialized_value();
2735 : }
2736 : } else {
2737 : DCHECK_EQ(kData, old_details.kind());
2738 0 : value = handle(old_descriptors->GetStrongValue(i), isolate);
2739 : DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
2740 : }
2741 : } else {
2742 : DCHECK_EQ(kField, old_details.location());
2743 76760227 : FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
2744 : if (object->IsUnboxedDoubleField(index)) {
2745 : uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
2746 : if (representation.IsDouble()) {
2747 : value = isolate->factory()->NewMutableHeapNumberFromBits(old_bits);
2748 : } else {
2749 : value = isolate->factory()->NewHeapNumberFromBits(old_bits);
2750 : }
2751 : } else {
2752 153520453 : value = handle(object->RawFastPropertyAt(index), isolate);
2753 76760211 : if (!old_representation.IsDouble() && representation.IsDouble()) {
2754 : DCHECK_IMPLIES(old_representation.IsNone(),
2755 : value->IsUninitialized(isolate));
2756 2117 : value = Object::NewStorageFor(isolate, value, representation);
2757 76758094 : } else if (old_representation.IsDouble() &&
2758 : !representation.IsDouble()) {
2759 961 : value = Object::WrapForRead(isolate, value, old_representation);
2760 : }
2761 : }
2762 : }
2763 : DCHECK(!(representation.IsDouble() && value->IsSmi()));
2764 153552645 : int target_index = new_descriptors->GetFieldIndex(i);
2765 76776340 : if (target_index < inobject) {
2766 5314777 : inobject_props->set(target_index, *value);
2767 : } else {
2768 142923126 : array->set(target_index - inobject, *value);
2769 : }
2770 : }
2771 :
2772 29252613 : for (int i = old_nof; i < new_nof; i++) {
2773 9744647 : PropertyDetails details = new_descriptors->GetDetails(i);
2774 9744650 : if (details.location() != kField) continue;
2775 : DCHECK_EQ(kData, details.kind());
2776 : Handle<Object> value;
2777 9744656 : if (details.representation().IsDouble()) {
2778 : value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
2779 : } else {
2780 : value = isolate->factory()->uninitialized_value();
2781 : }
2782 19489319 : int target_index = new_descriptors->GetFieldIndex(i);
2783 9744663 : if (target_index < inobject) {
2784 5603017 : inobject_props->set(target_index, *value);
2785 : } else {
2786 8283292 : array->set(target_index - inobject, *value);
2787 : }
2788 : }
2789 :
2790 : // From here on we cannot fail and we shouldn't GC anymore.
2791 : DisallowHeapAllocation no_allocation;
2792 :
2793 : Heap* heap = isolate->heap();
2794 :
2795 : int old_instance_size = old_map->instance_size();
2796 :
2797 9763306 : heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
2798 :
2799 : // Copy (real) inobject properties. If necessary, stop at number_of_fields to
2800 : // avoid overwriting |one_pointer_filler_map|.
2801 : int limit = Min(inobject, number_of_fields);
2802 31598863 : for (int i = 0; i < limit; i++) {
2803 10917784 : FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
2804 10917787 : Object value = inobject_props->get(i);
2805 : // Can't use JSObject::FastPropertyAtPut() because proper map was not set
2806 : // yet.
2807 : if (new_map->IsUnboxedDoubleField(index)) {
2808 : DCHECK(value->IsMutableHeapNumber());
2809 : // Ensure that all bits of the double value are preserved.
2810 : object->RawFastDoublePropertyAsBitsAtPut(
2811 : index, MutableHeapNumber::cast(value)->value_as_bits());
2812 : if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
2813 : // Transition from tagged to untagged slot.
2814 : heap->ClearRecordedSlot(*object, object->RawField(index.offset()));
2815 : } else {
2816 : #ifdef DEBUG
2817 : heap->VerifyClearedSlot(*object, object->RawField(index.offset()));
2818 : #endif
2819 : }
2820 : } else {
2821 10917787 : object->RawFastPropertyAtPut(index, value);
2822 : }
2823 : }
2824 :
2825 19526602 : object->SetProperties(*array);
2826 :
2827 : // Create filler object past the new instance size.
2828 : int new_instance_size = new_map->instance_size();
2829 9763291 : int instance_size_delta = old_instance_size - new_instance_size;
2830 : DCHECK_GE(instance_size_delta, 0);
2831 :
2832 9763291 : if (instance_size_delta > 0) {
2833 : Address address = object->address();
2834 : heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
2835 29 : ClearRecordedSlots::kYes);
2836 : }
2837 :
2838 : // We are storing the new map using release store after creating a filler for
2839 : // the left-over space to avoid races with the sweeper thread.
2840 9763291 : object->synchronized_set_map(*new_map);
2841 : }
2842 :
2843 676620 : void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
2844 : int expected_additional_properties) {
2845 : // The global object is always normalized.
2846 : DCHECK(!object->IsJSGlobalObject());
2847 : // JSGlobalProxy must never be normalized
2848 : DCHECK(!object->IsJSGlobalProxy());
2849 :
2850 : DCHECK_IMPLIES(new_map->is_prototype_map(),
2851 : Map::IsPrototypeChainInvalidated(*new_map));
2852 :
2853 : Isolate* isolate = object->GetIsolate();
2854 : HandleScope scope(isolate);
2855 : Handle<Map> map(object->map(), isolate);
2856 :
2857 : // Allocate new content.
2858 : int real_size = map->NumberOfOwnDescriptors();
2859 : int property_count = real_size;
2860 676620 : if (expected_additional_properties > 0) {
2861 566 : property_count += expected_additional_properties;
2862 : } else {
2863 : // Make space for two more properties.
2864 676054 : property_count += NameDictionary::kInitialCapacity;
2865 : }
2866 : Handle<NameDictionary> dictionary =
2867 676620 : NameDictionary::New(isolate, property_count);
2868 :
2869 : Handle<DescriptorArray> descs(map->instance_descriptors(), isolate);
2870 4656975 : for (int i = 0; i < real_size; i++) {
2871 1990178 : PropertyDetails details = descs->GetDetails(i);
2872 3980356 : Handle<Name> key(descs->GetKey(i), isolate);
2873 : Handle<Object> value;
2874 1990178 : if (details.location() == kField) {
2875 1723292 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
2876 1723292 : if (details.kind() == kData) {
2877 : if (object->IsUnboxedDoubleField(index)) {
2878 : double old_value = object->RawFastDoublePropertyAt(index);
2879 : value = isolate->factory()->NewHeapNumber(old_value);
2880 : } else {
2881 3446584 : value = handle(object->RawFastPropertyAt(index), isolate);
2882 1723292 : if (details.representation().IsDouble()) {
2883 : DCHECK(value->IsMutableHeapNumber());
2884 : double old_value = Handle<MutableHeapNumber>::cast(value)->value();
2885 683 : value = isolate->factory()->NewHeapNumber(old_value);
2886 : }
2887 : }
2888 : } else {
2889 : DCHECK_EQ(kAccessor, details.kind());
2890 0 : value = handle(object->RawFastPropertyAt(index), isolate);
2891 : }
2892 :
2893 : } else {
2894 : DCHECK_EQ(kDescriptor, details.location());
2895 533772 : value = handle(descs->GetStrongValue(i), isolate);
2896 : }
2897 : DCHECK(!value.is_null());
2898 : PropertyDetails d(details.kind(), details.attributes(),
2899 : PropertyCellType::kNoCell);
2900 1990178 : dictionary = NameDictionary::Add(isolate, dictionary, key, value, d);
2901 : }
2902 :
2903 : // Copy the next enumeration index from instance descriptor.
2904 676620 : dictionary->SetNextEnumerationIndex(real_size + 1);
2905 :
2906 : // From here on we cannot fail and we shouldn't GC anymore.
2907 : DisallowHeapAllocation no_allocation;
2908 :
2909 : Heap* heap = isolate->heap();
2910 : int old_instance_size = map->instance_size();
2911 676620 : heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation);
2912 :
2913 : // Resize the object in the heap if necessary.
2914 : int new_instance_size = new_map->instance_size();
2915 676620 : int instance_size_delta = old_instance_size - new_instance_size;
2916 : DCHECK_GE(instance_size_delta, 0);
2917 :
2918 676620 : if (instance_size_delta > 0) {
2919 : heap->CreateFillerObjectAt(object->address() + new_instance_size,
2920 300037 : instance_size_delta, ClearRecordedSlots::kYes);
2921 : }
2922 :
2923 : // We are storing the new map using release store after creating a filler for
2924 : // the left-over space to avoid races with the sweeper thread.
2925 676620 : object->synchronized_set_map(*new_map);
2926 :
2927 1353240 : object->SetProperties(*dictionary);
2928 :
2929 : // Ensure that in-object space of slow-mode object does not contain random
2930 : // garbage.
2931 676620 : int inobject_properties = new_map->GetInObjectProperties();
2932 676620 : if (inobject_properties) {
2933 : Heap* heap = isolate->heap();
2934 562926 : heap->ClearRecordedSlotRange(
2935 : object->address() + map->GetInObjectPropertyOffset(0),
2936 281463 : object->address() + new_instance_size);
2937 :
2938 2724725 : for (int i = 0; i < inobject_properties; i++) {
2939 1221631 : FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
2940 1221631 : object->RawFastPropertyAtPut(index, Smi::kZero);
2941 : }
2942 : }
2943 :
2944 676620 : isolate->counters()->props_to_dictionary()->Increment();
2945 :
2946 : #ifdef DEBUG
2947 : if (FLAG_trace_normalization) {
2948 : StdoutStream os;
2949 : os << "Object properties have been normalized:\n";
2950 : object->Print(os);
2951 : }
2952 : #endif
2953 676620 : }
2954 :
2955 : } // namespace
2956 :
2957 33128191 : void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
2958 : int expected_additional_properties) {
2959 33128191 : if (object->map() == *new_map) return;
2960 : Handle<Map> old_map(object->map(), object->GetIsolate());
2961 30187844 : NotifyMapChange(old_map, new_map, object->GetIsolate());
2962 :
2963 30187868 : if (old_map->is_dictionary_map()) {
2964 : // For slow-to-fast migrations JSObject::MigrateSlowToFast()
2965 : // must be used instead.
2966 553531 : CHECK(new_map->is_dictionary_map());
2967 :
2968 : // Slow-to-slow migration is trivial.
2969 553531 : object->synchronized_set_map(*new_map);
2970 29634337 : } else if (!new_map->is_dictionary_map()) {
2971 28957717 : MigrateFastToFast(object, new_map);
2972 28957743 : if (old_map->is_prototype_map()) {
2973 : DCHECK(!old_map->is_stable());
2974 : DCHECK(new_map->is_stable());
2975 : DCHECK(new_map->owns_descriptors());
2976 : DCHECK(old_map->owns_descriptors());
2977 : // Transfer ownership to the new map. Keep the descriptor pointer of the
2978 : // old map intact because the concurrent marker might be iterating the
2979 : // object with the old map.
2980 3952798 : old_map->set_owns_descriptors(false);
2981 : DCHECK(old_map->is_abandoned_prototype_map());
2982 : // Ensure that no transition was inserted for prototype migrations.
2983 : DCHECK_EQ(0, TransitionsAccessor(object->GetIsolate(), old_map)
2984 : .NumberOfTransitions());
2985 : DCHECK(new_map->GetBackPointer()->IsUndefined());
2986 : DCHECK(object->map() != *old_map);
2987 : }
2988 : } else {
2989 676620 : MigrateFastToSlow(object, new_map, expected_additional_properties);
2990 : }
2991 :
2992 : // Careful: Don't allocate here!
2993 : // For some callers of this method, |object| might be in an inconsistent
2994 : // state now: the new map might have a new elements_kind, but the object's
2995 : // elements pointer hasn't been updated yet. Callers will fix this, but in
2996 : // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
2997 : // When adding code here, add a DisallowHeapAllocation too.
2998 : }
2999 :
3000 295159 : void JSObject::ForceSetPrototype(Handle<JSObject> object,
3001 : Handle<Object> proto) {
3002 : // object.__proto__ = proto;
3003 : Handle<Map> old_map = Handle<Map>(object->map(), object->GetIsolate());
3004 : Handle<Map> new_map =
3005 295160 : Map::Copy(object->GetIsolate(), old_map, "ForceSetPrototype");
3006 295160 : Map::SetPrototype(object->GetIsolate(), new_map, proto);
3007 295160 : JSObject::MigrateToMap(object, new_map);
3008 295159 : }
3009 :
3010 193061 : Maybe<bool> JSObject::SetPropertyWithInterceptor(
3011 : LookupIterator* it, Maybe<ShouldThrow> should_throw, Handle<Object> value) {
3012 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
3013 : return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
3014 193268 : should_throw, value);
3015 : }
3016 :
3017 1172243 : Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
3018 : ElementsKind to_kind) {
3019 : Handle<Map> map(object->map(), object->GetIsolate());
3020 2344486 : return Map::TransitionElementsTo(object->GetIsolate(), map, to_kind);
3021 : }
3022 :
3023 : // static
3024 0 : MaybeHandle<NativeContext> JSObject::GetFunctionRealm(Handle<JSObject> object) {
3025 : DCHECK(object->map()->is_constructor());
3026 : DCHECK(!object->IsJSFunction());
3027 0 : return object->GetCreationContext();
3028 : }
3029 :
3030 7690895 : void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
3031 : DCHECK(object->map()->GetInObjectProperties() ==
3032 : map->GetInObjectProperties());
3033 : ElementsKind obj_kind = object->map()->elements_kind();
3034 : ElementsKind map_kind = map->elements_kind();
3035 7690895 : if (map_kind != obj_kind) {
3036 : ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind);
3037 27 : if (IsDictionaryElementsKind(obj_kind)) {
3038 : to_kind = obj_kind;
3039 : }
3040 27 : if (IsDictionaryElementsKind(to_kind)) {
3041 27 : NormalizeElements(object);
3042 : } else {
3043 0 : TransitionElementsKind(object, to_kind);
3044 : }
3045 54 : map = Map::ReconfigureElementsKind(object->GetIsolate(), map, to_kind);
3046 : }
3047 7690895 : int number_of_fields = map->NumberOfFields();
3048 7690895 : int inobject = map->GetInObjectProperties();
3049 7690895 : int unused = map->UnusedPropertyFields();
3050 7690895 : int total_size = number_of_fields + unused;
3051 7690895 : int external = total_size - inobject;
3052 : // Allocate mutable double boxes if necessary. It is always necessary if we
3053 : // have external properties, but is also necessary if we only have inobject
3054 : // properties but don't unbox double fields.
3055 : if (!FLAG_unbox_double_fields || external > 0) {
3056 : Isolate* isolate = object->GetIsolate();
3057 :
3058 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
3059 : Handle<FixedArray> storage;
3060 : if (!FLAG_unbox_double_fields) {
3061 7690895 : storage = isolate->factory()->NewFixedArray(inobject);
3062 : }
3063 :
3064 : Handle<PropertyArray> array =
3065 7690895 : isolate->factory()->NewPropertyArray(external);
3066 :
3067 74183879 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
3068 33246492 : PropertyDetails details = descriptors->GetDetails(i);
3069 : Representation representation = details.representation();
3070 66465131 : if (!representation.IsDouble()) continue;
3071 27853 : FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3072 : if (map->IsUnboxedDoubleField(index)) continue;
3073 : auto box = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
3074 27853 : if (index.is_inobject()) {
3075 55490 : storage->set(index.property_index(), *box);
3076 : } else {
3077 216 : array->set(index.outobject_array_index(), *box);
3078 : }
3079 : }
3080 :
3081 15381790 : object->SetProperties(*array);
3082 :
3083 : if (!FLAG_unbox_double_fields) {
3084 69218055 : for (int i = 0; i < inobject; i++) {
3085 30763580 : FieldIndex index = FieldIndex::ForPropertyIndex(*map, i);
3086 30763580 : Object value = storage->get(i);
3087 30763580 : object->RawFastPropertyAtPut(index, value);
3088 : }
3089 : }
3090 : }
3091 7690895 : object->synchronized_set_map(*map);
3092 7690895 : }
3093 :
3094 2228 : void JSObject::MigrateInstance(Handle<JSObject> object) {
3095 : Handle<Map> original_map(object->map(), object->GetIsolate());
3096 2228 : Handle<Map> map = Map::Update(object->GetIsolate(), original_map);
3097 2228 : map->set_is_migration_target(true);
3098 2228 : MigrateToMap(object, map);
3099 2228 : if (FLAG_trace_migration) {
3100 0 : object->PrintInstanceMigration(stdout, *original_map, *map);
3101 : }
3102 : #if VERIFY_HEAP
3103 : if (FLAG_verify_heap) {
3104 : object->JSObjectVerify(object->GetIsolate());
3105 : }
3106 : #endif
3107 2228 : }
3108 :
3109 : // static
3110 6702 : bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
3111 : Isolate* isolate = object->GetIsolate();
3112 : DisallowDeoptimization no_deoptimization(isolate);
3113 : Handle<Map> original_map(object->map(), isolate);
3114 : Handle<Map> new_map;
3115 13404 : if (!Map::TryUpdate(isolate, original_map).ToHandle(&new_map)) {
3116 : return false;
3117 : }
3118 6687 : JSObject::MigrateToMap(object, new_map);
3119 6687 : if (FLAG_trace_migration && *original_map != object->map()) {
3120 0 : object->PrintInstanceMigration(stdout, *original_map, object->map());
3121 : }
3122 : #if VERIFY_HEAP
3123 : if (FLAG_verify_heap) {
3124 : object->JSObjectVerify(isolate);
3125 : }
3126 : #endif
3127 : return true;
3128 : }
3129 :
3130 18972790 : void JSObject::AddProperty(Isolate* isolate, Handle<JSObject> object,
3131 : Handle<Name> name, Handle<Object> value,
3132 : PropertyAttributes attributes) {
3133 : LookupIterator it(isolate, object, name, object,
3134 18972790 : LookupIterator::OWN_SKIP_INTERCEPTOR);
3135 18972819 : CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
3136 : #ifdef DEBUG
3137 : uint32_t index;
3138 : DCHECK(!object->IsJSProxy());
3139 : DCHECK(!name->AsArrayIndex(&index));
3140 : Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
3141 : DCHECK(maybe.IsJust());
3142 : DCHECK(!it.IsFound());
3143 : DCHECK(object->map()->is_extensible() || name->IsPrivate());
3144 : #endif
3145 37945596 : CHECK(Object::AddDataProperty(&it, value, attributes,
3146 : Just(ShouldThrow::kThrowOnError),
3147 : StoreOrigin::kNamed)
3148 : .IsJust());
3149 18972777 : }
3150 :
3151 182679 : void JSObject::AddProperty(Isolate* isolate, Handle<JSObject> object,
3152 : const char* name, Handle<Object> value,
3153 : PropertyAttributes attributes) {
3154 365358 : JSObject::AddProperty(isolate, object,
3155 : isolate->factory()->InternalizeUtf8String(name), value,
3156 182679 : attributes);
3157 182679 : }
3158 :
3159 : // Reconfigures a property to a data property with attributes, even if it is not
3160 : // reconfigurable.
3161 : // Requires a LookupIterator that does not look at the prototype chain beyond
3162 : // hidden prototypes.
3163 10503045 : MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
3164 : LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
3165 : AccessorInfoHandling handling) {
3166 21006094 : MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
3167 : it, value, attributes, Just(ShouldThrow::kThrowOnError), handling));
3168 10503031 : return value;
3169 : }
3170 :
3171 10829543 : Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
3172 : LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
3173 : Maybe<ShouldThrow> should_throw, AccessorInfoHandling handling) {
3174 10829543 : it->UpdateProtector();
3175 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
3176 :
3177 10830798 : for (; it->IsFound(); it->Next()) {
3178 551979 : switch (it->state()) {
3179 : case LookupIterator::JSPROXY:
3180 : case LookupIterator::NOT_FOUND:
3181 : case LookupIterator::TRANSITION:
3182 0 : UNREACHABLE();
3183 :
3184 : case LookupIterator::ACCESS_CHECK:
3185 421 : if (!it->HasAccess()) {
3186 0 : it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>());
3187 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
3188 : return Just(true);
3189 : }
3190 : break;
3191 :
3192 : // If there's an interceptor, try to store the property with the
3193 : // interceptor.
3194 : // In case of success, the attributes will have been reset to the default
3195 : // attributes of the interceptor, rather than the incoming attributes.
3196 : //
3197 : // TODO(verwaest): JSProxy afterwards verify the attributes that the
3198 : // JSProxy claims it has, and verifies that they are compatible. If not,
3199 : // they throw. Here we should do the same.
3200 : case LookupIterator::INTERCEPTOR:
3201 207 : if (handling == DONT_FORCE_FIELD) {
3202 : Maybe<bool> result =
3203 : JSObject::SetPropertyWithInterceptor(it, should_throw, value);
3204 414 : if (result.IsNothing() || result.FromJust()) return result;
3205 : }
3206 : break;
3207 :
3208 : case LookupIterator::ACCESSOR: {
3209 5304 : Handle<Object> accessors = it->GetAccessors();
3210 :
3211 : // Special handling for AccessorInfo, which behaves like a data
3212 : // property.
3213 5304 : if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
3214 : PropertyAttributes current_attributes = it->property_attributes();
3215 : // Ensure the context isn't changed after calling into accessors.
3216 : AssertNoContextChange ncc(it->isolate());
3217 :
3218 : // Update the attributes before calling the setter. The setter may
3219 : // later change the shape of the property.
3220 4698 : if (current_attributes != attributes) {
3221 1160 : it->TransitionToAccessorPair(accessors, attributes);
3222 : }
3223 :
3224 4698 : return Object::SetPropertyWithAccessor(it, value, should_throw);
3225 : }
3226 :
3227 606 : it->ReconfigureDataProperty(value, attributes);
3228 : return Just(true);
3229 : }
3230 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
3231 : return Object::RedefineIncompatibleProperty(
3232 18 : it->isolate(), it->GetName(), value, should_throw);
3233 :
3234 : case LookupIterator::DATA: {
3235 : // Regular property update if the attributes match.
3236 546038 : if (it->property_attributes() == attributes) {
3237 524685 : return Object::SetDataProperty(it, value);
3238 : }
3239 :
3240 : // Special case: properties of typed arrays cannot be reconfigured to
3241 : // non-writable nor to non-enumerable.
3242 40704 : if (it->IsElement() && object->HasFixedTypedArrayElements()) {
3243 : return Object::RedefineIncompatibleProperty(
3244 0 : it->isolate(), it->GetName(), value, should_throw);
3245 : }
3246 :
3247 : // Reconfigure the data property if the attributes mismatch.
3248 21353 : it->ReconfigureDataProperty(value, attributes);
3249 :
3250 : return Just(true);
3251 : }
3252 : }
3253 : }
3254 :
3255 : return Object::AddDataProperty(it, value, attributes, should_throw,
3256 10278197 : StoreOrigin::kNamed);
3257 : }
3258 :
3259 3960873 : MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
3260 : Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
3261 : PropertyAttributes attributes) {
3262 : DCHECK(!value->IsTheHole());
3263 : LookupIterator it(object, name, object, LookupIterator::OWN);
3264 3960874 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
3265 : }
3266 :
3267 2471110 : MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
3268 : Handle<JSObject> object, uint32_t index, Handle<Object> value,
3269 : PropertyAttributes attributes) {
3270 : Isolate* isolate = object->GetIsolate();
3271 : LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
3272 2471110 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
3273 : }
3274 :
3275 433744 : MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
3276 : Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
3277 : PropertyAttributes attributes) {
3278 : Isolate* isolate = object->GetIsolate();
3279 : LookupIterator it = LookupIterator::PropertyOrElement(
3280 433744 : isolate, object, name, object, LookupIterator::OWN);
3281 433744 : return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
3282 : }
3283 :
3284 249502 : Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
3285 : LookupIterator* it) {
3286 292441 : return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
3287 : }
3288 :
3289 679770 : void JSObject::NormalizeProperties(Handle<JSObject> object,
3290 : PropertyNormalizationMode mode,
3291 : int expected_additional_properties,
3292 : const char* reason) {
3293 934132 : if (!object->HasFastProperties()) return;
3294 :
3295 : Handle<Map> map(object->map(), object->GetIsolate());
3296 425408 : Handle<Map> new_map = Map::Normalize(object->GetIsolate(), map, mode, reason);
3297 :
3298 425408 : MigrateToMap(object, new_map, expected_additional_properties);
3299 : }
3300 :
3301 1099410 : void JSObject::MigrateSlowToFast(Handle<JSObject> object,
3302 : int unused_property_fields,
3303 : const char* reason) {
3304 1926868 : if (object->HasFastProperties()) return;
3305 : DCHECK(!object->IsJSGlobalObject());
3306 : Isolate* isolate = object->GetIsolate();
3307 : Factory* factory = isolate->factory();
3308 674638 : Handle<NameDictionary> dictionary(object->property_dictionary(), isolate);
3309 :
3310 : // Make sure we preserve dictionary representation if there are too many
3311 : // descriptors.
3312 : int number_of_elements = dictionary->NumberOfElements();
3313 337319 : if (number_of_elements > kMaxNumberOfDescriptors) return;
3314 :
3315 : Handle<FixedArray> iteration_order =
3316 336724 : NameDictionary::IterationIndices(isolate, dictionary);
3317 :
3318 : int instance_descriptor_length = iteration_order->length();
3319 : int number_of_fields = 0;
3320 :
3321 : // Compute the length of the instance descriptor.
3322 : ReadOnlyRoots roots(isolate);
3323 3744478 : for (int i = 0; i < instance_descriptor_length; i++) {
3324 : int index = Smi::ToInt(iteration_order->get(i));
3325 : DCHECK(dictionary->IsKey(roots, dictionary->KeyAt(index)));
3326 :
3327 3407754 : PropertyKind kind = dictionary->DetailsAt(index).kind();
3328 1703877 : if (kind == kData) {
3329 : if (FLAG_track_constant_fields) {
3330 1293522 : number_of_fields += 1;
3331 : } else {
3332 : Object value = dictionary->ValueAt(index);
3333 : if (!value->IsJSFunction()) {
3334 : number_of_fields += 1;
3335 : }
3336 : }
3337 : }
3338 : }
3339 :
3340 : Handle<Map> old_map(object->map(), isolate);
3341 :
3342 336724 : int inobject_props = old_map->GetInObjectProperties();
3343 :
3344 : // Allocate new map.
3345 336724 : Handle<Map> new_map = Map::CopyDropDescriptors(isolate, old_map);
3346 : // We should not only set this bit if we need to. We should not retain the
3347 : // old bit because turning a map into dictionary always sets this bit.
3348 1010025 : new_map->set_may_have_interesting_symbols(new_map->has_named_interceptor() ||
3349 336724 : new_map->is_access_check_needed());
3350 336724 : new_map->set_is_dictionary_map(false);
3351 :
3352 336724 : NotifyMapChange(old_map, new_map, isolate);
3353 :
3354 336724 : if (instance_descriptor_length == 0) {
3355 : DisallowHeapAllocation no_gc;
3356 : DCHECK_LE(unused_property_fields, inobject_props);
3357 : // Transform the object.
3358 64771 : new_map->SetInObjectUnusedPropertyFields(inobject_props);
3359 64771 : object->synchronized_set_map(*new_map);
3360 129542 : object->SetProperties(ReadOnlyRoots(isolate).empty_fixed_array());
3361 : // Check that it really works.
3362 : DCHECK(object->HasFastProperties());
3363 64771 : if (FLAG_trace_maps) {
3364 0 : LOG(isolate, MapEvent("SlowToFast", *old_map, *new_map, reason));
3365 : }
3366 : return;
3367 : }
3368 :
3369 : // Allocate the instance descriptor.
3370 : Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
3371 271953 : isolate, instance_descriptor_length, 0, AllocationType::kOld);
3372 :
3373 : int number_of_allocated_fields =
3374 271953 : number_of_fields + unused_property_fields - inobject_props;
3375 271953 : if (number_of_allocated_fields < 0) {
3376 : // There is enough inobject space for all fields (including unused).
3377 : number_of_allocated_fields = 0;
3378 42207 : unused_property_fields = inobject_props - number_of_fields;
3379 : }
3380 :
3381 : // Allocate the property array for the fields.
3382 : Handle<PropertyArray> fields =
3383 271953 : factory->NewPropertyArray(number_of_allocated_fields);
3384 :
3385 : bool is_transitionable_elements_kind =
3386 : IsTransitionableFastElementsKind(old_map->elements_kind());
3387 :
3388 : // Fill in the instance descriptor and the fields.
3389 : int current_offset = 0;
3390 3679707 : for (int i = 0; i < instance_descriptor_length; i++) {
3391 : int index = Smi::ToInt(iteration_order->get(i));
3392 3407754 : Name k = dictionary->NameAt(index);
3393 : // Dictionary keys are internalized upon insertion.
3394 : // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
3395 1703877 : CHECK(k->IsUniqueName());
3396 : Handle<Name> key(k, isolate);
3397 :
3398 : // Properly mark the {new_map} if the {key} is an "interesting symbol".
3399 1703877 : if (key->IsInterestingSymbol()) {
3400 1832 : new_map->set_may_have_interesting_symbols(true);
3401 : }
3402 :
3403 1703877 : Object value = dictionary->ValueAt(index);
3404 :
3405 1703877 : PropertyDetails details = dictionary->DetailsAt(index);
3406 : DCHECK_EQ(kField, details.location());
3407 : DCHECK_EQ(PropertyConstness::kMutable, details.constness());
3408 :
3409 1703877 : Descriptor d;
3410 1703877 : if (details.kind() == kData) {
3411 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
3412 : d = Descriptor::DataConstant(key, handle(value, isolate),
3413 : details.attributes());
3414 : } else {
3415 : // Ensure that we make constant field only when elements kind is not
3416 : // transitionable.
3417 : PropertyConstness constness =
3418 : FLAG_track_constant_fields && !is_transitionable_elements_kind
3419 : ? PropertyConstness::kConst
3420 1293522 : : PropertyConstness::kMutable;
3421 2587044 : d = Descriptor::DataField(
3422 : key, current_offset, details.attributes(), constness,
3423 : // TODO(verwaest): value->OptimalRepresentation();
3424 : Representation::Tagged(),
3425 3880566 : MaybeObjectHandle(FieldType::Any(isolate)));
3426 : }
3427 : } else {
3428 : DCHECK_EQ(kAccessor, details.kind());
3429 820710 : d = Descriptor::AccessorConstant(key, handle(value, isolate),
3430 410355 : details.attributes());
3431 : }
3432 : details = d.GetDetails();
3433 1703877 : if (details.location() == kField) {
3434 1293522 : if (current_offset < inobject_props) {
3435 : object->InObjectPropertyAtPut(current_offset, value,
3436 59147 : UPDATE_WRITE_BARRIER);
3437 : } else {
3438 1234375 : int offset = current_offset - inobject_props;
3439 1234375 : fields->set(offset, value);
3440 : }
3441 1293522 : current_offset += details.field_width_in_words();
3442 : }
3443 1703877 : descriptors->Set(i, &d);
3444 : }
3445 : DCHECK(current_offset == number_of_fields);
3446 :
3447 271953 : descriptors->Sort();
3448 :
3449 : Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
3450 271953 : isolate, new_map, descriptors, descriptors->number_of_descriptors());
3451 :
3452 : DisallowHeapAllocation no_gc;
3453 271953 : new_map->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
3454 271953 : if (number_of_allocated_fields == 0) {
3455 51671 : new_map->SetInObjectUnusedPropertyFields(unused_property_fields);
3456 : } else {
3457 220282 : new_map->SetOutOfObjectUnusedPropertyFields(unused_property_fields);
3458 : }
3459 :
3460 271953 : if (FLAG_trace_maps) {
3461 818 : LOG(isolate, MapEvent("SlowToFast", *old_map, *new_map, reason));
3462 : }
3463 : // Transform the object.
3464 271953 : object->synchronized_set_map(*new_map);
3465 :
3466 543906 : object->SetProperties(*fields);
3467 : DCHECK(object->IsJSObject());
3468 :
3469 : // Check that it really works.
3470 : DCHECK(object->HasFastProperties());
3471 : }
3472 :
3473 74425 : void JSObject::RequireSlowElements(NumberDictionary dictionary) {
3474 74425 : if (dictionary->requires_slow_elements()) return;
3475 : dictionary->set_requires_slow_elements();
3476 42086 : if (map()->is_prototype_map()) {
3477 : // If this object is a prototype (the callee will check), invalidate any
3478 : // prototype chains involving it.
3479 : InvalidatePrototypeChains(map());
3480 : }
3481 : }
3482 :
3483 290820 : Handle<NumberDictionary> JSObject::NormalizeElements(Handle<JSObject> object) {
3484 : DCHECK(!object->HasFixedTypedArrayElements());
3485 : Isolate* isolate = object->GetIsolate();
3486 581640 : bool is_sloppy_arguments = object->HasSloppyArgumentsElements();
3487 : {
3488 : DisallowHeapAllocation no_gc;
3489 : FixedArrayBase elements = object->elements();
3490 :
3491 290820 : if (is_sloppy_arguments) {
3492 : elements = SloppyArgumentsElements::cast(elements)->arguments();
3493 : }
3494 :
3495 290820 : if (elements->IsNumberDictionary()) {
3496 : return handle(NumberDictionary::cast(elements), isolate);
3497 : }
3498 : }
3499 :
3500 : DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements() ||
3501 : object->HasFastArgumentsElements() ||
3502 : object->HasFastStringWrapperElements());
3503 :
3504 : Handle<NumberDictionary> dictionary =
3505 573080 : object->GetElementsAccessor()->Normalize(object);
3506 :
3507 : // Switch to using the dictionary as the backing storage for elements.
3508 : ElementsKind target_kind = is_sloppy_arguments
3509 : ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
3510 858142 : : object->HasFastStringWrapperElements()
3511 : ? SLOW_STRING_WRAPPER_ELEMENTS
3512 573080 : : DICTIONARY_ELEMENTS;
3513 286540 : Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
3514 : // Set the new map first to satify the elements type assert in set_elements().
3515 286540 : JSObject::MigrateToMap(object, new_map);
3516 :
3517 286540 : if (is_sloppy_arguments) {
3518 1478 : SloppyArgumentsElements::cast(object->elements())
3519 : ->set_arguments(*dictionary);
3520 : } else {
3521 571602 : object->set_elements(*dictionary);
3522 : }
3523 :
3524 286540 : isolate->counters()->elements_to_dictionary()->Increment();
3525 :
3526 : #ifdef DEBUG
3527 : if (FLAG_trace_normalization) {
3528 : StdoutStream os;
3529 : os << "Object elements have been normalized:\n";
3530 : object->Print(os);
3531 : }
3532 : #endif
3533 :
3534 : DCHECK(object->HasDictionaryElements() ||
3535 : object->HasSlowArgumentsElements() ||
3536 : object->HasSlowStringWrapperElements());
3537 286540 : return dictionary;
3538 : }
3539 :
3540 100 : Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
3541 : ShouldThrow should_throw) {
3542 : Isolate* isolate = it->isolate();
3543 : // Make sure that the top context does not change when doing callbacks or
3544 : // interceptor calls.
3545 : AssertNoContextChange ncc(isolate);
3546 :
3547 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
3548 100 : Handle<InterceptorInfo> interceptor(it->GetInterceptor());
3549 100 : if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
3550 :
3551 : Handle<JSObject> holder = it->GetHolder<JSObject>();
3552 : Handle<Object> receiver = it->GetReceiver();
3553 58 : if (!receiver->IsJSReceiver()) {
3554 0 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
3555 : Object::ConvertReceiver(isolate, receiver),
3556 : Nothing<bool>());
3557 : }
3558 :
3559 : PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
3560 58 : *holder, Just(should_throw));
3561 : Handle<Object> result;
3562 58 : if (it->IsElement()) {
3563 23 : result = args.CallIndexedDeleter(interceptor, it->index());
3564 : } else {
3565 35 : result = args.CallNamedDeleter(interceptor, it->name());
3566 : }
3567 :
3568 58 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
3569 58 : if (result.is_null()) return Nothing<bool>();
3570 :
3571 : DCHECK(result->IsBoolean());
3572 : // Rebox CustomArguments::kReturnValueOffset before returning.
3573 : return Just(result->IsTrue(isolate));
3574 : }
3575 :
3576 1127102 : Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
3577 : Handle<Object> value,
3578 : Maybe<ShouldThrow> should_throw) {
3579 : DCHECK(it->GetReceiver()->IsJSObject());
3580 2254204 : MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
3581 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
3582 : Isolate* isolate = receiver->GetIsolate();
3583 :
3584 1127097 : if (it->IsFound()) {
3585 405 : Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
3586 442 : MAYBE_RETURN(attributes, Nothing<bool>());
3587 405 : if ((attributes.FromJust() & DONT_DELETE) != 0) {
3588 118 : RETURN_FAILURE(
3589 : isolate, GetShouldThrow(isolate, should_throw),
3590 : NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
3591 : }
3592 : } else {
3593 1126692 : if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
3594 329 : RETURN_FAILURE(
3595 : isolate, GetShouldThrow(isolate, should_throw),
3596 : NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
3597 : }
3598 : }
3599 :
3600 2253948 : RETURN_ON_EXCEPTION_VALUE(it->isolate(),
3601 : DefineOwnPropertyIgnoreAttributes(it, value, NONE),
3602 : Nothing<bool>());
3603 :
3604 : return Just(true);
3605 : }
3606 :
3607 : namespace {
3608 :
3609 : template <typename Dictionary>
3610 10752076 : bool TestDictionaryPropertiesIntegrityLevel(Dictionary dict,
3611 : ReadOnlyRoots roots,
3612 : PropertyAttributes level) {
3613 : DCHECK(level == SEALED || level == FROZEN);
3614 :
3615 10752076 : uint32_t capacity = dict->Capacity();
3616 32270198 : for (uint32_t i = 0; i < capacity; i++) {
3617 10759325 : Object key;
3618 21515144 : if (!dict->ToKey(roots, i, &key)) continue;
3619 3524 : if (key->FilterKey(ALL_PROPERTIES)) continue;
3620 1434 : PropertyDetails details = dict->DetailsAt(i);
3621 3770 : if (details.IsConfigurable()) return false;
3622 8049 : if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
3623 : return false;
3624 : }
3625 : }
3626 : return true;
3627 : }
3628 :
3629 10751664 : bool TestFastPropertiesIntegrityLevel(Map map, PropertyAttributes level) {
3630 : DCHECK(level == SEALED || level == FROZEN);
3631 : DCHECK(!map->IsCustomElementsReceiverMap());
3632 : DCHECK(!map->is_dictionary_map());
3633 :
3634 10751664 : DescriptorArray descriptors = map->instance_descriptors();
3635 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
3636 10755482 : for (int i = 0; i < number_of_own_descriptors; i++) {
3637 2108 : if (descriptors->GetKey(i)->IsPrivate()) continue;
3638 2090 : PropertyDetails details = descriptors->GetDetails(i);
3639 2090 : if (details.IsConfigurable()) return false;
3640 4403 : if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
3641 : return false;
3642 : }
3643 : }
3644 : return true;
3645 : }
3646 :
3647 10751762 : bool TestPropertiesIntegrityLevel(JSObject object, PropertyAttributes level) {
3648 : DCHECK(!object->map()->IsCustomElementsReceiverMap());
3649 :
3650 10751762 : if (object->HasFastProperties()) {
3651 10751664 : return TestFastPropertiesIntegrityLevel(object->map(), level);
3652 : }
3653 :
3654 98 : return TestDictionaryPropertiesIntegrityLevel(
3655 98 : object->property_dictionary(), object->GetReadOnlyRoots(), level);
3656 : }
3657 :
3658 10751982 : bool TestElementsIntegrityLevel(JSObject object, PropertyAttributes level) {
3659 : DCHECK(!object->HasSloppyArgumentsElements());
3660 :
3661 10751982 : ElementsKind kind = object->GetElementsKind();
3662 :
3663 10751982 : if (IsDictionaryElementsKind(kind)) {
3664 : return TestDictionaryPropertiesIntegrityLevel(
3665 : NumberDictionary::cast(object->elements()), object->GetReadOnlyRoots(),
3666 10751978 : level);
3667 : }
3668 4 : if (IsFixedTypedArrayElementsKind(kind)) {
3669 4 : return TestPropertiesIntegrityLevel(object, level);
3670 : }
3671 :
3672 : ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
3673 : // Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have
3674 : // PropertyAttributes so just test if empty
3675 0 : return accessor->NumberOfElements(object) == 0;
3676 : }
3677 :
3678 10983916 : bool FastTestIntegrityLevel(JSObject object, PropertyAttributes level) {
3679 : DCHECK(!object->map()->IsCustomElementsReceiverMap());
3680 :
3681 10751982 : return !object->map()->is_extensible() &&
3682 21735674 : TestElementsIntegrityLevel(object, level) &&
3683 21735674 : TestPropertiesIntegrityLevel(object, level);
3684 : }
3685 :
3686 : } // namespace
3687 :
3688 10984044 : Maybe<bool> JSObject::TestIntegrityLevel(Handle<JSObject> object,
3689 : IntegrityLevel level) {
3690 32952031 : if (!object->map()->IsCustomElementsReceiverMap() &&
3691 21967987 : !object->HasSloppyArgumentsElements()) {
3692 10983917 : return Just(FastTestIntegrityLevel(*object, level));
3693 : }
3694 127 : return GenericTestIntegrityLevel(Handle<JSReceiver>::cast(object), level);
3695 : }
3696 :
3697 4698 : Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
3698 : ShouldThrow should_throw) {
3699 : Isolate* isolate = object->GetIsolate();
3700 :
3701 9396 : if (!object->HasSloppyArgumentsElements()) {
3702 4645 : return PreventExtensionsWithTransition<NONE>(object, should_throw);
3703 : }
3704 :
3705 53 : if (object->IsAccessCheckNeeded() &&
3706 0 : !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
3707 0 : isolate->ReportFailedAccessCheck(object);
3708 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
3709 0 : RETURN_FAILURE(isolate, should_throw,
3710 : NewTypeError(MessageTemplate::kNoAccess));
3711 : }
3712 :
3713 53 : if (!object->map()->is_extensible()) return Just(true);
3714 :
3715 53 : if (object->IsJSGlobalProxy()) {
3716 0 : PrototypeIterator iter(isolate, object);
3717 0 : if (iter.IsAtEnd()) return Just(true);
3718 : DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
3719 : return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter),
3720 0 : should_throw);
3721 : }
3722 :
3723 106 : if (object->map()->has_named_interceptor() ||
3724 : object->map()->has_indexed_interceptor()) {
3725 0 : RETURN_FAILURE(isolate, should_throw,
3726 : NewTypeError(MessageTemplate::kCannotPreventExt));
3727 : }
3728 :
3729 53 : if (!object->HasFixedTypedArrayElements()) {
3730 : // If there are fast elements we normalize.
3731 53 : Handle<NumberDictionary> dictionary = NormalizeElements(object);
3732 : DCHECK(object->HasDictionaryElements() ||
3733 : object->HasSlowArgumentsElements());
3734 :
3735 : // Make sure that we never go back to fast case.
3736 53 : object->RequireSlowElements(*dictionary);
3737 : }
3738 :
3739 : // Do a map transition, other objects with this map may still
3740 : // be extensible.
3741 : // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
3742 : Handle<Map> new_map =
3743 53 : Map::Copy(isolate, handle(object->map(), isolate), "PreventExtensions");
3744 :
3745 : new_map->set_is_extensible(false);
3746 53 : JSObject::MigrateToMap(object, new_map);
3747 : DCHECK(!object->map()->is_extensible());
3748 :
3749 : return Just(true);
3750 : }
3751 :
3752 2595085 : bool JSObject::IsExtensible(Handle<JSObject> object) {
3753 : Isolate* isolate = object->GetIsolate();
3754 2595125 : if (object->IsAccessCheckNeeded() &&
3755 40 : !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
3756 : return true;
3757 : }
3758 2595055 : if (object->IsJSGlobalProxy()) {
3759 : PrototypeIterator iter(isolate, *object);
3760 2802 : if (iter.IsAtEnd()) return false;
3761 : DCHECK(iter.GetCurrent()->IsJSGlobalObject());
3762 : return iter.GetCurrent<JSObject>()->map()->is_extensible();
3763 : }
3764 : return object->map()->is_extensible();
3765 : }
3766 :
3767 : namespace {
3768 :
3769 : template <typename Dictionary>
3770 6542 : void ApplyAttributesToDictionary(Isolate* isolate, ReadOnlyRoots roots,
3771 : Handle<Dictionary> dictionary,
3772 : const PropertyAttributes attributes) {
3773 : int capacity = dictionary->Capacity();
3774 141830 : for (int i = 0; i < capacity; i++) {
3775 67644 : Object k;
3776 105105 : if (!dictionary->ToKey(roots, i, &k)) continue;
3777 30201 : if (k->FilterKey(ALL_PROPERTIES)) continue;
3778 9421 : PropertyDetails details = dictionary->DetailsAt(i);
3779 30183 : int attrs = attributes;
3780 : // READ_ONLY is an invalid attribute for JS setters/getters.
3781 58393 : if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
3782 45 : Object v = dictionary->ValueAt(i);
3783 45 : if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
3784 : }
3785 : details = details.CopyAddAttributes(static_cast<PropertyAttributes>(attrs));
3786 9279 : dictionary->DetailsAtPut(isolate, i, details);
3787 : }
3788 6542 : }
3789 :
3790 : } // namespace
3791 :
3792 : template <PropertyAttributes attrs>
3793 236818 : Maybe<bool> JSObject::PreventExtensionsWithTransition(
3794 : Handle<JSObject> object, ShouldThrow should_throw) {
3795 : STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
3796 :
3797 : // Sealing/freezing sloppy arguments or namespace objects should be handled
3798 : // elsewhere.
3799 : DCHECK(!object->HasSloppyArgumentsElements());
3800 : DCHECK_IMPLIES(object->IsJSModuleNamespace(), attrs == NONE);
3801 :
3802 : Isolate* isolate = object->GetIsolate();
3803 236843 : if (object->IsAccessCheckNeeded() &&
3804 25 : !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
3805 20 : isolate->ReportFailedAccessCheck(object);
3806 20 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
3807 0 : RETURN_FAILURE(isolate, should_throw,
3808 : NewTypeError(MessageTemplate::kNoAccess));
3809 : }
3810 :
3811 4644 : if (attrs == NONE && !object->map()->is_extensible()) return Just(true);
3812 :
3813 236717 : if (object->IsJSGlobalProxy()) {
3814 90 : PrototypeIterator iter(isolate, object);
3815 90 : if (iter.IsAtEnd()) return Just(true);
3816 : DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
3817 : return PreventExtensionsWithTransition<attrs>(
3818 90 : PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
3819 : }
3820 :
3821 473253 : if (object->map()->has_named_interceptor() ||
3822 : object->map()->has_indexed_interceptor()) {
3823 : MessageTemplate message = MessageTemplate::kNone;
3824 : switch (attrs) {
3825 : case NONE:
3826 : message = MessageTemplate::kCannotPreventExt;
3827 : break;
3828 :
3829 : case SEALED:
3830 : message = MessageTemplate::kCannotSeal;
3831 : break;
3832 :
3833 : case FROZEN:
3834 : message = MessageTemplate::kCannotFreeze;
3835 : break;
3836 : }
3837 3 : RETURN_FAILURE(isolate, should_throw, NewTypeError(message));
3838 : }
3839 :
3840 : Handle<NumberDictionary> new_element_dictionary;
3841 946059 : if (!object->HasFixedTypedArrayElements() &&
3842 473197 : !object->HasDictionaryElements() &&
3843 472862 : !object->HasSlowStringWrapperElements()) {
3844 : int length = object->IsJSArray()
3845 : ? Smi::ToInt(Handle<JSArray>::cast(object)->length())
3846 236234 : : object->elements()->length();
3847 472468 : new_element_dictionary =
3848 : length == 0 ? isolate->factory()->empty_slow_element_dictionary()
3849 256226 : : object->GetElementsAccessor()->Normalize(object);
3850 : }
3851 :
3852 : Handle<Symbol> transition_marker;
3853 : if (attrs == NONE) {
3854 : transition_marker = isolate->factory()->nonextensible_symbol();
3855 : } else if (attrs == SEALED) {
3856 : transition_marker = isolate->factory()->sealed_symbol();
3857 : } else {
3858 : DCHECK(attrs == FROZEN);
3859 : transition_marker = isolate->factory()->frozen_symbol();
3860 : }
3861 :
3862 : Handle<Map> old_map(object->map(), isolate);
3863 : TransitionsAccessor transitions(isolate, old_map);
3864 236631 : Map transition = transitions.SearchSpecial(*transition_marker);
3865 236629 : if (!transition.is_null()) {
3866 : Handle<Map> transition_map(transition, isolate);
3867 : DCHECK(transition_map->has_dictionary_elements() ||
3868 : transition_map->has_fixed_typed_array_elements() ||
3869 : transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
3870 : DCHECK(!transition_map->is_extensible());
3871 99943 : JSObject::MigrateToMap(object, transition_map);
3872 136686 : } else if (transitions.CanHaveMoreTransitions()) {
3873 : // Create a new descriptor array with the appropriate property attributes
3874 : Handle<Map> new_map = Map::CopyForPreventExtensions(
3875 135870 : isolate, old_map, attrs, transition_marker, "CopyForPreventExtensions");
3876 135871 : JSObject::MigrateToMap(object, new_map);
3877 : } else {
3878 : DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
3879 : // Slow path: need to normalize properties for safety
3880 818 : NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
3881 : "SlowPreventExtensions");
3882 :
3883 : // Create a new map, since other objects with this map may be extensible.
3884 : // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
3885 : Handle<Map> new_map = Map::Copy(isolate, handle(object->map(), isolate),
3886 818 : "SlowCopyForPreventExtensions");
3887 : new_map->set_is_extensible(false);
3888 818 : if (!new_element_dictionary.is_null()) {
3889 : ElementsKind new_kind =
3890 : IsStringWrapperElementsKind(old_map->elements_kind())
3891 : ? SLOW_STRING_WRAPPER_ELEMENTS
3892 809 : : DICTIONARY_ELEMENTS;
3893 1618 : new_map->set_elements_kind(new_kind);
3894 : }
3895 818 : JSObject::MigrateToMap(object, new_map);
3896 :
3897 : if (attrs != NONE) {
3898 : ReadOnlyRoots roots(isolate);
3899 161 : if (object->IsJSGlobalObject()) {
3900 : Handle<GlobalDictionary> dictionary(
3901 162 : JSGlobalObject::cast(*object)->global_dictionary(), isolate);
3902 81 : ApplyAttributesToDictionary(isolate, roots, dictionary, attrs);
3903 : } else {
3904 160 : Handle<NameDictionary> dictionary(object->property_dictionary(),
3905 80 : isolate);
3906 80 : ApplyAttributesToDictionary(isolate, roots, dictionary, attrs);
3907 : }
3908 : }
3909 : }
3910 :
3911 : // Both seal and preventExtensions always go through without modifications to
3912 : // typed array elements. Freeze works only if there are no actual elements.
3913 236635 : if (object->HasFixedTypedArrayElements()) {
3914 36 : if (attrs == FROZEN &&
3915 : JSArrayBufferView::cast(*object)->byte_length() > 0) {
3916 54 : isolate->Throw(*isolate->factory()->NewTypeError(
3917 : MessageTemplate::kCannotFreezeArrayBufferView));
3918 : return Nothing<bool>();
3919 : }
3920 : return Just(true);
3921 : }
3922 :
3923 : DCHECK(object->map()->has_dictionary_elements() ||
3924 : object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
3925 236570 : if (!new_element_dictionary.is_null()) {
3926 472466 : object->set_elements(*new_element_dictionary);
3927 : }
3928 :
3929 236571 : if (object->elements() !=
3930 : ReadOnlyRoots(isolate).empty_slow_element_dictionary()) {
3931 : Handle<NumberDictionary> dictionary(object->element_dictionary(), isolate);
3932 : // Make sure we never go back to the fast case
3933 6911 : object->RequireSlowElements(*dictionary);
3934 : if (attrs != NONE) {
3935 6381 : ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate), dictionary,
3936 : attrs);
3937 : }
3938 : }
3939 :
3940 : return Just(true);
3941 : }
3942 :
3943 11766481 : Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
3944 : Representation representation,
3945 : FieldIndex index) {
3946 : Isolate* isolate = object->GetIsolate();
3947 : if (object->IsUnboxedDoubleField(index)) {
3948 : double value = object->RawFastDoublePropertyAt(index);
3949 : return isolate->factory()->NewHeapNumber(value);
3950 : }
3951 23532959 : Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
3952 11766478 : return Object::WrapForRead(isolate, raw_value, representation);
3953 : }
3954 :
3955 : // TODO(cbruni/jkummerow): Consider moving this into elements.cc.
3956 144108 : bool JSObject::HasEnumerableElements() {
3957 : // TODO(cbruni): cleanup
3958 144108 : JSObject object = *this;
3959 144108 : switch (object->GetElementsKind()) {
3960 : case PACKED_SMI_ELEMENTS:
3961 : case PACKED_ELEMENTS:
3962 : case PACKED_DOUBLE_ELEMENTS: {
3963 : int length = object->IsJSArray()
3964 : ? Smi::ToInt(JSArray::cast(object)->length())
3965 29778 : : object->elements()->length();
3966 29778 : return length > 0;
3967 : }
3968 : case HOLEY_SMI_ELEMENTS:
3969 : case HOLEY_ELEMENTS: {
3970 : FixedArray elements = FixedArray::cast(object->elements());
3971 : int length = object->IsJSArray()
3972 : ? Smi::ToInt(JSArray::cast(object)->length())
3973 113988 : : elements->length();
3974 : Isolate* isolate = GetIsolate();
3975 5019294 : for (int i = 0; i < length; i++) {
3976 2463786 : if (!elements->is_the_hole(isolate, i)) return true;
3977 : }
3978 : return false;
3979 : }
3980 : case HOLEY_DOUBLE_ELEMENTS: {
3981 : int length = object->IsJSArray()
3982 : ? Smi::ToInt(JSArray::cast(object)->length())
3983 45 : : object->elements()->length();
3984 : // Zero-length arrays would use the empty FixedArray...
3985 45 : if (length == 0) return false;
3986 : // ...so only cast to FixedDoubleArray otherwise.
3987 : FixedDoubleArray elements = FixedDoubleArray::cast(object->elements());
3988 45 : for (int i = 0; i < length; i++) {
3989 45 : if (!elements->is_the_hole(i)) return true;
3990 : }
3991 : return false;
3992 : }
3993 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
3994 :
3995 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
3996 : #undef TYPED_ARRAY_CASE
3997 : {
3998 : int length = object->elements()->length();
3999 0 : return length > 0;
4000 : }
4001 : case DICTIONARY_ELEMENTS: {
4002 216 : NumberDictionary elements = NumberDictionary::cast(object->elements());
4003 216 : return elements->NumberOfEnumerableProperties() > 0;
4004 : }
4005 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
4006 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
4007 : // We're approximating non-empty arguments objects here.
4008 : return true;
4009 : case FAST_STRING_WRAPPER_ELEMENTS:
4010 : case SLOW_STRING_WRAPPER_ELEMENTS:
4011 0 : if (String::cast(JSValue::cast(object)->value())->length() > 0) {
4012 : return true;
4013 : }
4014 0 : return object->elements()->length() > 0;
4015 : case NO_ELEMENTS:
4016 0 : return false;
4017 : }
4018 0 : UNREACHABLE();
4019 : }
4020 :
4021 1338022 : MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
4022 : Handle<Name> name,
4023 : Handle<Object> getter,
4024 : Handle<Object> setter,
4025 : PropertyAttributes attributes) {
4026 : Isolate* isolate = object->GetIsolate();
4027 :
4028 : LookupIterator it = LookupIterator::PropertyOrElement(
4029 1338022 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
4030 1338028 : return DefineAccessor(&it, getter, setter, attributes);
4031 : }
4032 :
4033 1534362 : MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
4034 : Handle<Object> getter,
4035 : Handle<Object> setter,
4036 : PropertyAttributes attributes) {
4037 : Isolate* isolate = it->isolate();
4038 :
4039 1534362 : it->UpdateProtector();
4040 :
4041 1534363 : if (it->state() == LookupIterator::ACCESS_CHECK) {
4042 1738 : if (!it->HasAccess()) {
4043 5 : isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
4044 5 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
4045 0 : return isolate->factory()->undefined_value();
4046 : }
4047 1733 : it->Next();
4048 : }
4049 :
4050 : Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
4051 : // Ignore accessors on typed arrays.
4052 1561768 : if (it->IsElement() && object->HasFixedTypedArrayElements()) {
4053 0 : return it->factory()->undefined_value();
4054 : }
4055 :
4056 : DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
4057 : getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
4058 : DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
4059 : setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
4060 1534357 : it->TransitionToAccessorProperty(getter, setter, attributes);
4061 :
4062 1534366 : return isolate->factory()->undefined_value();
4063 : }
4064 :
4065 61725 : MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
4066 : Handle<Name> name,
4067 : Handle<AccessorInfo> info,
4068 : PropertyAttributes attributes) {
4069 : Isolate* isolate = object->GetIsolate();
4070 :
4071 : LookupIterator it = LookupIterator::PropertyOrElement(
4072 61725 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
4073 :
4074 : // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
4075 : // the FailedAccessCheckCallbackFunction doesn't throw an exception.
4076 : //
4077 : // TODO(verwaest): Force throw an exception if the callback doesn't, so we can
4078 : // remove reliance on default return values.
4079 61725 : if (it.state() == LookupIterator::ACCESS_CHECK) {
4080 7780 : if (!it.HasAccess()) {
4081 5 : isolate->ReportFailedAccessCheck(object);
4082 5 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
4083 0 : return it.factory()->undefined_value();
4084 : }
4085 7775 : it.Next();
4086 : }
4087 :
4088 : // Ignore accessors on typed arrays.
4089 61732 : if (it.IsElement() && object->HasFixedTypedArrayElements()) {
4090 0 : return it.factory()->undefined_value();
4091 : }
4092 :
4093 123440 : CHECK(GetPropertyAttributes(&it).IsJust());
4094 :
4095 : // ES5 forbids turning a property into an accessor if it's not
4096 : // configurable. See 8.6.1 (Table 5).
4097 61781 : if (it.IsFound() && !it.IsConfigurable()) {
4098 25 : return it.factory()->undefined_value();
4099 : }
4100 :
4101 61695 : it.TransitionToAccessorPair(info, attributes);
4102 :
4103 61695 : return object;
4104 : }
4105 :
4106 237 : Object JSObject::SlowReverseLookup(Object value) {
4107 237 : if (HasFastProperties()) {
4108 : int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
4109 180 : DescriptorArray descs = map()->instance_descriptors();
4110 : bool value_is_number = value->IsNumber();
4111 1806 : for (int i = 0; i < number_of_own_descriptors; i++) {
4112 822 : PropertyDetails details = descs->GetDetails(i);
4113 822 : if (details.location() == kField) {
4114 : DCHECK_EQ(kData, details.kind());
4115 765 : FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
4116 : if (IsUnboxedDoubleField(field_index)) {
4117 : if (value_is_number) {
4118 : double property = RawFastDoublePropertyAt(field_index);
4119 : if (property == value->Number()) {
4120 : return descs->GetKey(i);
4121 : }
4122 : }
4123 : } else {
4124 765 : Object property = RawFastPropertyAt(field_index);
4125 765 : if (field_index.is_double()) {
4126 : DCHECK(property->IsMutableHeapNumber());
4127 0 : if (value_is_number && property->Number() == value->Number()) {
4128 0 : return descs->GetKey(i);
4129 : }
4130 765 : } else if (property == value) {
4131 9 : return descs->GetKey(i);
4132 : }
4133 : }
4134 : } else {
4135 : DCHECK_EQ(kDescriptor, details.location());
4136 57 : if (details.kind() == kData) {
4137 0 : if (descs->GetStrongValue(i) == value) {
4138 0 : return descs->GetKey(i);
4139 : }
4140 : }
4141 : }
4142 : }
4143 171 : return GetReadOnlyRoots().undefined_value();
4144 57 : } else if (IsJSGlobalObject()) {
4145 114 : return JSGlobalObject::cast(*this)->global_dictionary()->SlowReverseLookup(
4146 57 : value);
4147 : } else {
4148 0 : return property_dictionary()->SlowReverseLookup(value);
4149 : }
4150 : }
4151 :
4152 0 : void JSObject::PrototypeRegistryCompactionCallback(HeapObject value,
4153 : int old_index,
4154 : int new_index) {
4155 : DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
4156 : Map map = Map::cast(value);
4157 : DCHECK(map->prototype_info()->IsPrototypeInfo());
4158 : PrototypeInfo proto_info = PrototypeInfo::cast(map->prototype_info());
4159 : DCHECK_EQ(old_index, proto_info->registry_slot());
4160 : proto_info->set_registry_slot(new_index);
4161 0 : }
4162 :
4163 : // static
4164 4670410 : void JSObject::MakePrototypesFast(Handle<Object> receiver,
4165 : WhereToStart where_to_start,
4166 : Isolate* isolate) {
4167 4670410 : if (!receiver->IsJSReceiver()) return;
4168 11645557 : for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
4169 4623829 : where_to_start);
4170 3510828 : !iter.IsAtEnd(); iter.Advance()) {
4171 : Handle<Object> current = PrototypeIterator::GetCurrent(iter);
4172 12722387 : if (!current->IsJSObject()) return;
4173 : Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
4174 8110113 : Map current_map = current_obj->map();
4175 8110113 : if (current_map->is_prototype_map()) {
4176 : // If the map is already marked as should be fast, we're done. Its
4177 : // prototypes will have been marked already as well.
4178 9654903 : if (current_map->should_be_fast_prototype_map()) return;
4179 : Handle<Map> map(current_map, isolate);
4180 456332 : Map::SetShouldBeFastPrototypeMap(map, true, isolate);
4181 456332 : JSObject::OptimizeAsPrototype(current_obj);
4182 : }
4183 : }
4184 : }
4185 :
4186 26480507 : static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
4187 : DisallowHeapAllocation no_gc;
4188 26480507 : if (!object->HasFastProperties()) return false;
4189 25240092 : if (object->IsJSGlobalProxy()) return false;
4190 25218789 : if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
4191 9454099 : return !object->map()->is_prototype_map() ||
4192 9454099 : !object->map()->should_be_fast_prototype_map();
4193 : }
4194 :
4195 : // static
4196 26590657 : void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
4197 : bool enable_setup_mode) {
4198 26590657 : if (object->IsJSGlobalObject()) return;
4199 26493654 : if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) {
4200 : // First normalize to ensure all JSFunctions are DATA_CONSTANT.
4201 : JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
4202 330054 : "NormalizeAsPrototype");
4203 : }
4204 26493725 : if (object->map()->is_prototype_map()) {
4205 62757584 : if (object->map()->should_be_fast_prototype_map() &&
4206 40629226 : !object->HasFastProperties()) {
4207 283471 : JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
4208 : }
4209 : } else {
4210 : Handle<Map> new_map = Map::Copy(object->GetIsolate(),
4211 : handle(object->map(), object->GetIsolate()),
4212 4365369 : "CopyAsPrototype");
4213 4365356 : JSObject::MigrateToMap(object, new_map);
4214 : object->map()->set_is_prototype_map(true);
4215 :
4216 : // Replace the pointer to the exact constructor with the Object function
4217 : // from the same context if undetectable from JS. This is to avoid keeping
4218 : // memory alive unnecessarily.
4219 4365365 : Object maybe_constructor = object->map()->GetConstructor();
4220 4365369 : if (maybe_constructor->IsJSFunction()) {
4221 : JSFunction constructor = JSFunction::cast(maybe_constructor);
4222 4364675 : if (!constructor->shared()->IsApiFunction()) {
4223 4308493 : Context context = constructor->context()->native_context();
4224 4308495 : JSFunction object_function = context->object_function();
4225 4308501 : object->map()->SetConstructor(object_function);
4226 : }
4227 : }
4228 : }
4229 : }
4230 :
4231 : // static
4232 361993 : void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
4233 361993 : if (!object->map()->is_prototype_map()) return;
4234 57534 : if (!object->map()->should_be_fast_prototype_map()) return;
4235 39496 : OptimizeAsPrototype(object);
4236 : }
4237 :
4238 : // static
4239 1816393 : void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
4240 : // Contract: In line with InvalidatePrototypeChains()'s requirements,
4241 : // leaf maps don't need to register as users, only prototypes do.
4242 : DCHECK(user->is_prototype_map());
4243 :
4244 1816393 : Handle<Map> current_user = user;
4245 : Handle<PrototypeInfo> current_user_info =
4246 1816393 : Map::GetOrCreatePrototypeInfo(user, isolate);
4247 2321440 : for (PrototypeIterator iter(isolate, user); !iter.IsAtEnd(); iter.Advance()) {
4248 : // Walk up the prototype chain as far as links haven't been registered yet.
4249 1682557 : if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
4250 : break;
4251 : }
4252 : Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
4253 : // Proxies on the prototype chain are not supported. They make it
4254 : // impossible to make any assumptions about the prototype chain anyway.
4255 505671 : if (maybe_proto->IsJSProxy()) return;
4256 : Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
4257 : Handle<PrototypeInfo> proto_info =
4258 505049 : Map::GetOrCreatePrototypeInfo(proto, isolate);
4259 : Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
4260 : Handle<WeakArrayList> registry =
4261 : maybe_registry->IsSmi()
4262 : ? handle(ReadOnlyRoots(isolate->heap()).empty_weak_array_list(),
4263 : isolate)
4264 622821 : : Handle<WeakArrayList>::cast(maybe_registry);
4265 505049 : int slot = 0;
4266 : Handle<WeakArrayList> new_array =
4267 505049 : PrototypeUsers::Add(isolate, registry, current_user, &slot);
4268 505049 : current_user_info->set_registry_slot(slot);
4269 505049 : if (!maybe_registry.is_identical_to(new_array)) {
4270 266448 : proto_info->set_prototype_users(*new_array);
4271 : }
4272 505049 : if (FLAG_trace_prototype_users) {
4273 0 : PrintF("Registering %p as a user of prototype %p (map=%p).\n",
4274 : reinterpret_cast<void*>(current_user->ptr()),
4275 : reinterpret_cast<void*>(proto->ptr()),
4276 0 : reinterpret_cast<void*>(proto->map()->ptr()));
4277 : }
4278 :
4279 : current_user = handle(proto->map(), isolate);
4280 : current_user_info = proto_info;
4281 : }
4282 : }
4283 :
4284 : // Can be called regardless of whether |user| was actually registered with
4285 : // |prototype|. Returns true when there was a registration.
4286 : // static
4287 4376983 : bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
4288 : DCHECK(user->is_prototype_map());
4289 : // If it doesn't have a PrototypeInfo, it was never registered.
4290 4376983 : if (!user->prototype_info()->IsPrototypeInfo()) return false;
4291 : // If it had no prototype before, see if it had users that might expect
4292 : // registration.
4293 1834947 : if (!user->prototype()->IsJSObject()) {
4294 : Object users =
4295 : PrototypeInfo::cast(user->prototype_info())->prototype_users();
4296 : return users->IsWeakArrayList();
4297 : }
4298 : Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
4299 : Handle<PrototypeInfo> user_info =
4300 1765147 : Map::GetOrCreatePrototypeInfo(user, isolate);
4301 : int slot = user_info->registry_slot();
4302 1765145 : if (slot == PrototypeInfo::UNREGISTERED) return false;
4303 : DCHECK(prototype->map()->is_prototype_map());
4304 : Object maybe_proto_info = prototype->map()->prototype_info();
4305 : // User knows its registry slot, prototype info and user registry must exist.
4306 : DCHECK(maybe_proto_info->IsPrototypeInfo());
4307 : Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
4308 : isolate);
4309 : Handle<WeakArrayList> prototype_users(
4310 : WeakArrayList::cast(proto_info->prototype_users()), isolate);
4311 : DCHECK_EQ(prototype_users->Get(slot), HeapObjectReference::Weak(*user));
4312 127335 : PrototypeUsers::MarkSlotEmpty(*prototype_users, slot);
4313 127335 : if (FLAG_trace_prototype_users) {
4314 0 : PrintF("Unregistering %p as a user of prototype %p.\n",
4315 : reinterpret_cast<void*>(user->ptr()),
4316 0 : reinterpret_cast<void*>(prototype->ptr()));
4317 : }
4318 : return true;
4319 : }
4320 :
4321 : namespace {
4322 :
4323 : // This function must be kept in sync with
4324 : // AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks
4325 : // before jumping here.
4326 16429490 : void InvalidateOnePrototypeValidityCellInternal(Map map) {
4327 : DCHECK(map->is_prototype_map());
4328 16429490 : if (FLAG_trace_prototype_users) {
4329 0 : PrintF("Invalidating prototype map %p 's cell\n",
4330 0 : reinterpret_cast<void*>(map.ptr()));
4331 : }
4332 : Object maybe_cell = map->prototype_validity_cell();
4333 16429498 : if (maybe_cell->IsCell()) {
4334 : // Just set the value; the cell will be replaced lazily.
4335 16364800 : Cell cell = Cell::cast(maybe_cell);
4336 16364800 : cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
4337 : }
4338 16429500 : }
4339 :
4340 15522495 : void InvalidatePrototypeChainsInternal(Map map) {
4341 15522495 : InvalidateOnePrototypeValidityCellInternal(map);
4342 :
4343 : Object maybe_proto_info = map->prototype_info();
4344 15522504 : if (!maybe_proto_info->IsPrototypeInfo()) return;
4345 : PrototypeInfo proto_info = PrototypeInfo::cast(maybe_proto_info);
4346 4675404 : if (!proto_info->prototype_users()->IsWeakArrayList()) {
4347 : return;
4348 : }
4349 : WeakArrayList prototype_users =
4350 : WeakArrayList::cast(proto_info->prototype_users());
4351 : // For now, only maps register themselves as users.
4352 11977516 : for (int i = PrototypeUsers::kFirstIndex; i < prototype_users->length();
4353 : ++i) {
4354 : HeapObject heap_object;
4355 7185355 : if (prototype_users->Get(i)->GetHeapObjectIfWeak(&heap_object) &&
4356 : heap_object->IsMap()) {
4357 : // Walk the prototype chain (backwards, towards leaf objects) if
4358 : // necessary.
4359 2453923 : InvalidatePrototypeChainsInternal(Map::cast(heap_object));
4360 : }
4361 : }
4362 : }
4363 :
4364 : } // namespace
4365 :
4366 : // static
4367 8646015 : Map JSObject::InvalidatePrototypeChains(Map map) {
4368 : DisallowHeapAllocation no_gc;
4369 13068572 : InvalidatePrototypeChainsInternal(map);
4370 8646026 : return map;
4371 : }
4372 :
4373 : // We also invalidate global objects validity cell when a new lexical
4374 : // environment variable is added. This is necessary to ensure that
4375 : // Load/StoreGlobalIC handlers that load/store from global object's prototype
4376 : // get properly invalidated.
4377 : // Note, that the normal Load/StoreICs that load/store through the global object
4378 : // in the prototype chain are not affected by appearance of a new lexical
4379 : // variable and therefore we don't propagate invalidation down.
4380 : // static
4381 906999 : void JSObject::InvalidatePrototypeValidityCell(JSGlobalObject global) {
4382 : DisallowHeapAllocation no_gc;
4383 906999 : InvalidateOnePrototypeValidityCellInternal(global->map());
4384 906999 : }
4385 :
4386 210678 : Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
4387 : Handle<Object> value, bool from_javascript,
4388 : ShouldThrow should_throw) {
4389 : Isolate* isolate = object->GetIsolate();
4390 :
4391 : #ifdef DEBUG
4392 : int size = object->Size();
4393 : #endif
4394 :
4395 210678 : if (from_javascript) {
4396 190844 : if (object->IsAccessCheckNeeded() &&
4397 35 : !isolate->MayAccess(handle(isolate->context(), isolate), object)) {
4398 0 : isolate->ReportFailedAccessCheck(object);
4399 0 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
4400 0 : RETURN_FAILURE(isolate, should_throw,
4401 : NewTypeError(MessageTemplate::kNoAccess));
4402 : }
4403 : } else {
4404 : DCHECK(!object->IsAccessCheckNeeded());
4405 : }
4406 :
4407 : // Silently ignore the change if value is not a JSObject or null.
4408 : // SpiderMonkey behaves this way.
4409 222385 : if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
4410 :
4411 : bool all_extensible = object->map()->is_extensible();
4412 : Handle<JSObject> real_receiver = object;
4413 210663 : if (from_javascript) {
4414 : // Find the first object in the chain whose prototype object is not
4415 : // hidden.
4416 : PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
4417 190809 : PrototypeIterator::END_AT_NON_HIDDEN);
4418 193983 : while (!iter.IsAtEnd()) {
4419 : // Casting to JSObject is fine because hidden prototypes are never
4420 : // JSProxies.
4421 : real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
4422 3174 : iter.Advance();
4423 6348 : all_extensible = all_extensible && real_receiver->map()->is_extensible();
4424 : }
4425 : }
4426 : Handle<Map> map(real_receiver->map(), isolate);
4427 :
4428 : // Nothing to do if prototype is already set.
4429 210663 : if (map->prototype() == *value) return Just(true);
4430 :
4431 : bool immutable_proto = map->is_immutable_proto();
4432 184982 : if (immutable_proto) {
4433 171 : RETURN_FAILURE(
4434 : isolate, should_throw,
4435 : NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
4436 : }
4437 :
4438 : // From 8.6.2 Object Internal Methods
4439 : // ...
4440 : // In addition, if [[Extensible]] is false the value of the [[Class]] and
4441 : // [[Prototype]] internal properties of the object may not be modified.
4442 : // ...
4443 : // Implementation specific extensions that modify [[Class]], [[Prototype]]
4444 : // or [[Extensible]] must not violate the invariants defined in the preceding
4445 : // paragraph.
4446 184919 : if (!all_extensible) {
4447 495 : RETURN_FAILURE(isolate, should_throw,
4448 : NewTypeError(MessageTemplate::kNonExtensibleProto, object));
4449 : }
4450 :
4451 : // Before we can set the prototype we need to be sure prototype cycles are
4452 : // prevented. It is sufficient to validate that the receiver is not in the
4453 : // new prototype chain.
4454 184676 : if (value->IsJSReceiver()) {
4455 927859 : for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
4456 : kStartAtReceiver);
4457 377427 : !iter.IsAtEnd(); iter.Advance()) {
4458 377505 : if (iter.GetCurrent<JSReceiver>() == *object) {
4459 : // Cycle detected.
4460 198 : RETURN_FAILURE(isolate, should_throw,
4461 : NewTypeError(MessageTemplate::kCyclicProto));
4462 : }
4463 : }
4464 : }
4465 :
4466 : // Set the new prototype of the object.
4467 :
4468 : isolate->UpdateNoElementsProtectorOnSetPrototype(real_receiver);
4469 :
4470 184598 : Handle<Map> new_map = Map::TransitionToPrototype(isolate, map, value);
4471 : DCHECK(new_map->prototype() == *value);
4472 184598 : JSObject::MigrateToMap(real_receiver, new_map);
4473 :
4474 : DCHECK(size == object->Size());
4475 : return Just(true);
4476 : }
4477 :
4478 : // static
4479 24 : void JSObject::SetImmutableProto(Handle<JSObject> object) {
4480 : DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS
4481 : Handle<Map> map(object->map(), object->GetIsolate());
4482 :
4483 : // Nothing to do if prototype is already set.
4484 42 : if (map->is_immutable_proto()) return;
4485 :
4486 : Handle<Map> new_map =
4487 6 : Map::TransitionToImmutableProto(object->GetIsolate(), map);
4488 6 : object->synchronized_set_map(*new_map);
4489 : }
4490 :
4491 442277 : void JSObject::EnsureCanContainElements(Handle<JSObject> object,
4492 : Arguments* args, uint32_t first_arg,
4493 : uint32_t arg_count,
4494 : EnsureElementsMode mode) {
4495 : // Elements in |Arguments| are ordered backwards (because they're on the
4496 : // stack), but the method that's called here iterates over them in forward
4497 : // direction.
4498 442277 : return EnsureCanContainElements(
4499 884554 : object, args->slot_at(first_arg + arg_count - 1), arg_count, mode);
4500 : }
4501 :
4502 245344785 : ElementsAccessor* JSObject::GetElementsAccessor() {
4503 490985196 : return ElementsAccessor::ForKind(GetElementsKind());
4504 : }
4505 :
4506 8291236 : void JSObject::ValidateElements(JSObject object) {
4507 : #ifdef ENABLE_SLOW_DCHECKS
4508 : if (FLAG_enable_slow_asserts) {
4509 : object->GetElementsAccessor()->Validate(object);
4510 : }
4511 : #endif
4512 8291236 : }
4513 :
4514 13249 : bool JSObject::WouldConvertToSlowElements(uint32_t index) {
4515 13249 : if (!HasFastElements()) return false;
4516 12941 : uint32_t capacity = static_cast<uint32_t>(elements()->length());
4517 : uint32_t new_capacity;
4518 12941 : return ShouldConvertToSlowElements(*this, capacity, index, &new_capacity);
4519 : }
4520 :
4521 878477 : static bool ShouldConvertToFastElements(JSObject object,
4522 : NumberDictionary dictionary,
4523 : uint32_t index,
4524 : uint32_t* new_capacity) {
4525 : // If properties with non-standard attributes or accessors were added, we
4526 : // cannot go back to fast elements.
4527 878477 : if (dictionary->requires_slow_elements()) return false;
4528 :
4529 : // Adding a property with this index will require slow elements.
4530 855097 : if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false;
4531 :
4532 854974 : if (object->IsJSArray()) {
4533 : Object length = JSArray::cast(object)->length();
4534 569737 : if (!length->IsSmi()) return false;
4535 569719 : *new_capacity = static_cast<uint32_t>(Smi::ToInt(length));
4536 285237 : } else if (object->IsJSSloppyArgumentsObject()) {
4537 : return false;
4538 : } else {
4539 186111 : *new_capacity = dictionary->max_number_key() + 1;
4540 : }
4541 1511660 : *new_capacity = Max(index + 1, *new_capacity);
4542 :
4543 755830 : uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
4544 755830 : NumberDictionary::kEntrySize;
4545 :
4546 : // Turn fast if the dictionary only saves 50% space.
4547 755830 : return 2 * dictionary_size >= *new_capacity;
4548 : }
4549 :
4550 488 : static ElementsKind BestFittingFastElementsKind(JSObject object) {
4551 488 : if (!object->map()->CanHaveFastTransitionableElementsKind()) {
4552 : return HOLEY_ELEMENTS;
4553 : }
4554 222 : if (object->HasSloppyArgumentsElements()) {
4555 : return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
4556 : }
4557 222 : if (object->HasStringWrapperElements()) {
4558 : return FAST_STRING_WRAPPER_ELEMENTS;
4559 : }
4560 : DCHECK(object->HasDictionaryElements());
4561 213 : NumberDictionary dictionary = object->element_dictionary();
4562 : ElementsKind kind = HOLEY_SMI_ELEMENTS;
4563 435721 : for (int i = 0; i < dictionary->Capacity(); i++) {
4564 217799 : Object key = dictionary->KeyAt(i);
4565 217799 : if (key->IsNumber()) {
4566 72427 : Object value = dictionary->ValueAt(i);
4567 72427 : if (!value->IsNumber()) return HOLEY_ELEMENTS;
4568 72382 : if (!value->IsSmi()) {
4569 6838 : if (!FLAG_unbox_double_arrays) return HOLEY_ELEMENTS;
4570 : kind = HOLEY_DOUBLE_ELEMENTS;
4571 : }
4572 : }
4573 : }
4574 : return kind;
4575 : }
4576 :
4577 : // static
4578 5014917 : void JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
4579 : Handle<Object> value,
4580 : PropertyAttributes attributes) {
4581 : DCHECK(object->map()->is_extensible());
4582 :
4583 : Isolate* isolate = object->GetIsolate();
4584 :
4585 5014917 : uint32_t old_length = 0;
4586 5014917 : uint32_t new_capacity = 0;
4587 :
4588 5014917 : if (object->IsJSArray()) {
4589 3344424 : CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
4590 : }
4591 :
4592 5014917 : ElementsKind kind = object->GetElementsKind();
4593 : FixedArrayBase elements = object->elements();
4594 : ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
4595 5014917 : if (IsSloppyArgumentsElementsKind(kind)) {
4596 : elements = SloppyArgumentsElements::cast(elements)->arguments();
4597 : dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
4598 4895295 : } else if (IsStringWrapperElementsKind(kind)) {
4599 : dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
4600 : }
4601 :
4602 5014917 : if (attributes != NONE) {
4603 : kind = dictionary_kind;
4604 4995683 : } else if (elements->IsNumberDictionary()) {
4605 878477 : kind = ShouldConvertToFastElements(
4606 : *object, NumberDictionary::cast(elements), index, &new_capacity)
4607 : ? BestFittingFastElementsKind(*object)
4608 878965 : : dictionary_kind;
4609 8234412 : } else if (ShouldConvertToSlowElements(
4610 : *object, static_cast<uint32_t>(elements->length()), index,
4611 : &new_capacity)) {
4612 : kind = dictionary_kind;
4613 : }
4614 :
4615 5014917 : ElementsKind to = value->OptimalElementsKind();
4616 6395373 : if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) {
4617 : to = GetHoleyElementsKind(to);
4618 : kind = GetHoleyElementsKind(kind);
4619 : }
4620 : to = GetMoreGeneralElementsKind(kind, to);
4621 : ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
4622 5014917 : accessor->Add(object, index, value, attributes, new_capacity);
4623 :
4624 5014917 : if (object->IsJSArray() && index >= old_length) {
4625 : Handle<Object> new_length =
4626 1542321 : isolate->factory()->NewNumberFromUint(index + 1);
4627 1542321 : JSArray::cast(*object)->set_length(*new_length);
4628 : }
4629 5014917 : }
4630 :
4631 : template <AllocationSiteUpdateMode update_or_check>
4632 865668 : bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
4633 : ElementsKind to_kind) {
4634 865668 : if (!object->IsJSArray()) return false;
4635 :
4636 614486 : if (!Heap::InYoungGeneration(*object)) return false;
4637 :
4638 602851 : if (Heap::IsLargeObject(*object)) return false;
4639 :
4640 : Handle<AllocationSite> site;
4641 : {
4642 : DisallowHeapAllocation no_allocation;
4643 :
4644 : Heap* heap = object->GetHeap();
4645 : AllocationMemento memento =
4646 1205702 : heap->FindAllocationMemento<Heap::kForRuntime>(object->map(), *object);
4647 602851 : if (memento.is_null()) return false;
4648 :
4649 : // Walk through to the Allocation Site
4650 390961 : site = handle(memento->GetAllocationSite(), heap->isolate());
4651 : }
4652 390961 : return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
4653 390961 : to_kind);
4654 : }
4655 :
4656 : template bool
4657 : JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
4658 : Handle<JSObject> object, ElementsKind to_kind);
4659 :
4660 : template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
4661 : Handle<JSObject> object, ElementsKind to_kind);
4662 :
4663 139934 : void JSObject::TransitionElementsKind(Handle<JSObject> object,
4664 : ElementsKind to_kind) {
4665 139934 : ElementsKind from_kind = object->GetElementsKind();
4666 :
4667 139934 : if (IsHoleyElementsKind(from_kind)) {
4668 : to_kind = GetHoleyElementsKind(to_kind);
4669 : }
4670 :
4671 139934 : if (from_kind == to_kind) return;
4672 :
4673 : // This method should never be called for any other case.
4674 : DCHECK(IsFastElementsKind(from_kind));
4675 : DCHECK(IsFastElementsKind(to_kind));
4676 : DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
4677 :
4678 139792 : UpdateAllocationSite(object, to_kind);
4679 277081 : if (object->elements() == object->GetReadOnlyRoots().empty_fixed_array() ||
4680 : IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) {
4681 : // No change is needed to the elements() buffer, the transition
4682 : // only requires a map change.
4683 135077 : Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
4684 135077 : MigrateToMap(object, new_map);
4685 : if (FLAG_trace_elements_transitions) {
4686 : Handle<FixedArrayBase> elms(object->elements(), object->GetIsolate());
4687 : PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
4688 : }
4689 : } else {
4690 : DCHECK((IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) ||
4691 : (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind)));
4692 4715 : uint32_t c = static_cast<uint32_t>(object->elements()->length());
4693 4715 : ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
4694 : }
4695 : }
4696 :
4697 : template <typename BackingStore>
4698 283239 : static int HoleyElementsUsage(JSObject object, BackingStore store) {
4699 : Isolate* isolate = object->GetIsolate();
4700 : int limit = object->IsJSArray() ? Smi::ToInt(JSArray::cast(object)->length())
4701 283239 : : store->length();
4702 : int used = 0;
4703 1181369977 : for (int i = 0; i < limit; ++i) {
4704 604653656 : if (!store->is_the_hole(isolate, i)) ++used;
4705 : }
4706 283239 : return used;
4707 : }
4708 :
4709 295487 : int JSObject::GetFastElementsUsage() {
4710 : FixedArrayBase store = elements();
4711 295487 : switch (GetElementsKind()) {
4712 : case PACKED_SMI_ELEMENTS:
4713 : case PACKED_DOUBLE_ELEMENTS:
4714 : case PACKED_ELEMENTS:
4715 : return IsJSArray() ? Smi::ToInt(JSArray::cast(*this)->length())
4716 12221 : : store->length();
4717 : case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
4718 : store = SloppyArgumentsElements::cast(store)->arguments();
4719 : V8_FALLTHROUGH;
4720 : case HOLEY_SMI_ELEMENTS:
4721 : case HOLEY_ELEMENTS:
4722 : case FAST_STRING_WRAPPER_ELEMENTS:
4723 283034 : return HoleyElementsUsage(*this, FixedArray::cast(store));
4724 : case HOLEY_DOUBLE_ELEMENTS:
4725 232 : if (elements()->length() == 0) return 0;
4726 205 : return HoleyElementsUsage(*this, FixedDoubleArray::cast(store));
4727 :
4728 : case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
4729 : case SLOW_STRING_WRAPPER_ELEMENTS:
4730 : case DICTIONARY_ELEMENTS:
4731 : case NO_ELEMENTS:
4732 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
4733 :
4734 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
4735 : #undef TYPED_ARRAY_CASE
4736 0 : UNREACHABLE();
4737 : }
4738 : return 0;
4739 : }
4740 :
4741 125660 : MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
4742 : bool* done) {
4743 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
4744 125690 : return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
4745 : }
4746 :
4747 5842 : Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
4748 : Handle<Name> name) {
4749 : LookupIterator it = LookupIterator::PropertyOrElement(
4750 5842 : object->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
4751 5842 : return HasProperty(&it);
4752 : }
4753 :
4754 17 : Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
4755 : uint32_t index) {
4756 : Isolate* isolate = object->GetIsolate();
4757 : LookupIterator it(isolate, object, index, object,
4758 : LookupIterator::OWN_SKIP_INTERCEPTOR);
4759 17 : return HasProperty(&it);
4760 : }
4761 :
4762 5 : Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
4763 : Handle<Name> name) {
4764 : LookupIterator it = LookupIterator::PropertyOrElement(
4765 5 : object->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
4766 5 : Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
4767 0 : return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR)
4768 10 : : Nothing<bool>();
4769 : }
4770 :
4771 0 : bool JSObject::IsApiWrapper() {
4772 : // These object types can carry information relevant for embedders. The
4773 : // *_API_* types are generated through templates which can have embedder
4774 : // fields. The other types have their embedder fields added at compile time.
4775 : auto instance_type = map()->instance_type();
4776 0 : return instance_type == JS_API_OBJECT_TYPE ||
4777 0 : instance_type == JS_ARRAY_BUFFER_TYPE ||
4778 0 : instance_type == JS_DATA_VIEW_TYPE ||
4779 0 : instance_type == JS_SPECIAL_API_OBJECT_TYPE ||
4780 0 : instance_type == JS_TYPED_ARRAY_TYPE;
4781 : }
4782 :
4783 14417 : bool JSObject::IsDroppableApiWrapper() {
4784 : auto instance_type = map()->instance_type();
4785 14417 : return instance_type == JS_API_OBJECT_TYPE ||
4786 14417 : instance_type == JS_SPECIAL_API_OBJECT_TYPE;
4787 : }
4788 :
4789 : // static
4790 9 : MaybeHandle<NativeContext> JSBoundFunction::GetFunctionRealm(
4791 : Handle<JSBoundFunction> function) {
4792 : DCHECK(function->map()->is_constructor());
4793 : return JSReceiver::GetFunctionRealm(
4794 9 : handle(function->bound_target_function(), function->GetIsolate()));
4795 : }
4796 :
4797 : // static
4798 82 : MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
4799 : Handle<JSBoundFunction> function) {
4800 : Handle<String> prefix = isolate->factory()->bound__string();
4801 : Handle<String> target_name = prefix;
4802 : Factory* factory = isolate->factory();
4803 : // Concatenate the "bound " up to the last non-bound target.
4804 82 : while (function->bound_target_function()->IsJSBoundFunction()) {
4805 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
4806 : factory->NewConsString(prefix, target_name),
4807 : String);
4808 : function = handle(JSBoundFunction::cast(function->bound_target_function()),
4809 : isolate);
4810 : }
4811 82 : if (function->bound_target_function()->IsJSFunction()) {
4812 : Handle<JSFunction> target(
4813 : JSFunction::cast(function->bound_target_function()), isolate);
4814 82 : Handle<Object> name = JSFunction::GetName(isolate, target);
4815 82 : if (!name->IsString()) return target_name;
4816 82 : return factory->NewConsString(target_name, Handle<String>::cast(name));
4817 : }
4818 : // This will omit the proper target name for bound JSProxies.
4819 0 : return target_name;
4820 : }
4821 :
4822 : // static
4823 316 : Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
4824 : Handle<JSBoundFunction> function) {
4825 : int nof_bound_arguments = function->bound_arguments()->length();
4826 694 : while (function->bound_target_function()->IsJSBoundFunction()) {
4827 : function = handle(JSBoundFunction::cast(function->bound_target_function()),
4828 : isolate);
4829 : // Make sure we never overflow {nof_bound_arguments}, the number of
4830 : // arguments of a function is strictly limited by the max length of an
4831 : // JSAarray, Smi::kMaxValue is thus a reasonably good overestimate.
4832 : int length = function->bound_arguments()->length();
4833 378 : if (V8_LIKELY(Smi::kMaxValue - nof_bound_arguments > length)) {
4834 378 : nof_bound_arguments += length;
4835 : } else {
4836 : nof_bound_arguments = Smi::kMaxValue;
4837 : }
4838 : }
4839 : // All non JSFunction targets get a direct property and don't use this
4840 : // accessor.
4841 : Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
4842 : isolate);
4843 316 : Maybe<int> target_length = JSFunction::GetLength(isolate, target);
4844 316 : if (target_length.IsNothing()) return target_length;
4845 :
4846 316 : int length = Max(0, target_length.FromJust() - nof_bound_arguments);
4847 : return Just(length);
4848 : }
4849 :
4850 : // static
4851 60 : Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
4852 : Isolate* const isolate = function->GetIsolate();
4853 60 : return isolate->factory()->function_native_code_string();
4854 : }
4855 :
4856 : // static
4857 130535 : Handle<Object> JSFunction::GetName(Isolate* isolate,
4858 : Handle<JSFunction> function) {
4859 130535 : if (function->shared()->name_should_print_as_anonymous()) {
4860 20 : return isolate->factory()->anonymous_string();
4861 : }
4862 261030 : return handle(function->shared()->Name(), isolate);
4863 : }
4864 :
4865 : // static
4866 54330 : Maybe<int> JSFunction::GetLength(Isolate* isolate,
4867 : Handle<JSFunction> function) {
4868 : int length = 0;
4869 54330 : IsCompiledScope is_compiled_scope(function->shared()->is_compiled_scope());
4870 54330 : if (is_compiled_scope.is_compiled()) {
4871 53210 : length = function->shared()->GetLength();
4872 : } else {
4873 : // If the function isn't compiled yet, the length is not computed
4874 : // correctly yet. Compile it now and return the right length.
4875 1120 : if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION,
4876 : &is_compiled_scope)) {
4877 738 : length = function->shared()->GetLength();
4878 : }
4879 1120 : if (isolate->has_pending_exception()) return Nothing<int>();
4880 : }
4881 : DCHECK_GE(length, 0);
4882 : return Just(length);
4883 : }
4884 :
4885 : // static
4886 3377 : Handle<NativeContext> JSFunction::GetFunctionRealm(
4887 : Handle<JSFunction> function) {
4888 : DCHECK(function->map()->is_constructor());
4889 6754 : return handle(function->context()->native_context(), function->GetIsolate());
4890 : }
4891 :
4892 488915 : void JSFunction::MarkForOptimization(ConcurrencyMode mode) {
4893 : Isolate* isolate = GetIsolate();
4894 488915 : if (!isolate->concurrent_recompilation_enabled() ||
4895 : isolate->bootstrapper()->IsActive()) {
4896 : mode = ConcurrencyMode::kNotConcurrent;
4897 : }
4898 :
4899 : DCHECK(!is_compiled() || IsInterpreted());
4900 : DCHECK(shared()->IsInterpreted());
4901 : DCHECK(!IsOptimized());
4902 : DCHECK(!HasOptimizedCode());
4903 : DCHECK(shared()->allows_lazy_compilation() ||
4904 : !shared()->optimization_disabled());
4905 :
4906 488915 : if (mode == ConcurrencyMode::kConcurrent) {
4907 25534 : if (IsInOptimizationQueue()) {
4908 0 : if (FLAG_trace_concurrent_recompilation) {
4909 0 : PrintF(" ** Not marking ");
4910 0 : ShortPrint();
4911 0 : PrintF(" -- already in optimization queue.\n");
4912 : }
4913 : return;
4914 : }
4915 25534 : if (FLAG_trace_concurrent_recompilation) {
4916 0 : PrintF(" ** Marking ");
4917 0 : ShortPrint();
4918 0 : PrintF(" for concurrent recompilation.\n");
4919 : }
4920 : }
4921 :
4922 488922 : SetOptimizationMarker(mode == ConcurrencyMode::kConcurrent
4923 : ? OptimizationMarker::kCompileOptimizedConcurrent
4924 : : OptimizationMarker::kCompileOptimized);
4925 : }
4926 :
4927 : // static
4928 3082417 : void JSFunction::EnsureClosureFeedbackCellArray(Handle<JSFunction> function) {
4929 : Isolate* const isolate = function->GetIsolate();
4930 : DCHECK(function->shared()->is_compiled());
4931 : DCHECK(function->shared()->HasFeedbackMetadata());
4932 9247256 : if (function->has_closure_feedback_cell_array() ||
4933 6164840 : function->has_feedback_vector()) {
4934 0 : return;
4935 : }
4936 3082420 : if (function->shared()->HasAsmWasmData()) return;
4937 :
4938 : Handle<SharedFunctionInfo> shared(function->shared(), isolate);
4939 : DCHECK(function->shared()->HasBytecodeArray());
4940 : Handle<HeapObject> feedback_cell_array =
4941 3082424 : FeedbackVector::NewClosureFeedbackCellArray(isolate, shared);
4942 : // Many closure cell is used as a way to specify that there is no
4943 : // feedback cell for this function and a new feedback cell has to be
4944 : // allocated for this funciton. For ex: for eval functions, we have to create
4945 : // a feedback cell and cache it along with the code. It is safe to use
4946 : // many_closure_cell to indicate this because in regular cases, it should
4947 : // already have a feedback_vector / feedback cell array allocated.
4948 3082426 : if (function->raw_feedback_cell() == isolate->heap()->many_closures_cell()) {
4949 : Handle<FeedbackCell> feedback_cell =
4950 1520565 : isolate->factory()->NewOneClosureCell(feedback_cell_array);
4951 1520568 : function->set_raw_feedback_cell(*feedback_cell);
4952 : } else {
4953 1561861 : function->raw_feedback_cell()->set_value(*feedback_cell_array);
4954 : }
4955 : }
4956 :
4957 : // static
4958 8694107 : void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function) {
4959 : Isolate* const isolate = function->GetIsolate();
4960 : DCHECK(function->shared()->is_compiled());
4961 : DCHECK(function->shared()->HasFeedbackMetadata());
4962 14305811 : if (function->has_feedback_vector()) return;
4963 3084227 : if (function->shared()->HasAsmWasmData()) return;
4964 :
4965 : Handle<SharedFunctionInfo> shared(function->shared(), isolate);
4966 : DCHECK(function->shared()->HasBytecodeArray());
4967 :
4968 3082419 : EnsureClosureFeedbackCellArray(function);
4969 : Handle<FixedArray> closure_feedback_cell_array =
4970 6164848 : handle(function->closure_feedback_cell_array(), isolate);
4971 : Handle<HeapObject> feedback_vector =
4972 3082425 : FeedbackVector::New(isolate, shared, closure_feedback_cell_array);
4973 : // EnsureClosureFeedbackCellArray should handle the special case where we need
4974 : // to allocate a new feedback cell. Please look at comment in that function
4975 : // for more details.
4976 : DCHECK(function->raw_feedback_cell() !=
4977 : isolate->heap()->many_closures_cell());
4978 3082425 : function->raw_feedback_cell()->set_value(*feedback_vector);
4979 : }
4980 :
4981 : // static
4982 8176495 : void JSFunction::InitializeFeedbackCell(Handle<JSFunction> function) {
4983 : if (FLAG_lite_mode) {
4984 : EnsureClosureFeedbackCellArray(function);
4985 : } else {
4986 8176495 : EnsureFeedbackVector(function);
4987 : }
4988 8176517 : }
4989 :
4990 : namespace {
4991 :
4992 263901 : void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
4993 : Handle<JSReceiver> value) {
4994 : // Now some logic for the maps of the objects that are created by using this
4995 : // function as a constructor.
4996 263901 : if (function->has_initial_map()) {
4997 : // If the function has allocated the initial map replace it with a
4998 : // copy containing the new prototype. Also complete any in-object
4999 : // slack tracking that is in progress at this point because it is
5000 : // still tracking the old copy.
5001 115360 : function->CompleteInobjectSlackTrackingIfActive();
5002 :
5003 : Handle<Map> initial_map(function->initial_map(), isolate);
5004 :
5005 229943 : if (!isolate->bootstrapper()->IsActive() &&
5006 : initial_map->instance_type() == JS_OBJECT_TYPE) {
5007 : // Put the value in the initial map field until an initial map is needed.
5008 : // At that point, a new initial map is created and the prototype is put
5009 : // into the initial map where it belongs.
5010 228500 : function->set_prototype_or_initial_map(*value);
5011 : } else {
5012 : Handle<Map> new_map =
5013 1110 : Map::Copy(isolate, initial_map, "SetInstancePrototype");
5014 1110 : JSFunction::SetInitialMap(function, new_map, value);
5015 :
5016 : // If the function is used as the global Array function, cache the
5017 : // updated initial maps (and transitioned versions) in the native context.
5018 2220 : Handle<Context> native_context(function->context()->native_context(),
5019 : isolate);
5020 : Handle<Object> array_function(
5021 : native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
5022 2109 : if (array_function->IsJSFunction() &&
5023 : *function == JSFunction::cast(*array_function)) {
5024 111 : CacheInitialJSArrayMaps(native_context, new_map);
5025 : }
5026 : }
5027 :
5028 : // Deoptimize all code that embeds the previous initial map.
5029 230720 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
5030 115360 : isolate, DependentCode::kInitialMapChangedGroup);
5031 : } else {
5032 : // Put the value in the initial map field until an initial map is
5033 : // needed. At that point, a new initial map is created and the
5034 : // prototype is put into the initial map where it belongs.
5035 297084 : function->set_prototype_or_initial_map(*value);
5036 148541 : if (value->IsJSObject()) {
5037 : // Optimize as prototype to detach it from its transition tree.
5038 148478 : JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
5039 : }
5040 : }
5041 263902 : }
5042 :
5043 : } // anonymous namespace
5044 :
5045 263901 : void JSFunction::SetPrototype(Handle<JSFunction> function,
5046 : Handle<Object> value) {
5047 : DCHECK(function->IsConstructor() ||
5048 : IsGeneratorFunction(function->shared()->kind()));
5049 : Isolate* isolate = function->GetIsolate();
5050 : Handle<JSReceiver> construct_prototype;
5051 :
5052 : // If the value is not a JSReceiver, store the value in the map's
5053 : // constructor field so it can be accessed. Also, set the prototype
5054 : // used for constructing objects to the original object prototype.
5055 : // See ECMA-262 13.2.2.
5056 263901 : if (!value->IsJSReceiver()) {
5057 : // Copy the map so this does not affect unrelated functions.
5058 : // Remove map transitions because they point to maps with a
5059 : // different prototype.
5060 : Handle<Map> new_map =
5061 94222 : Map::Copy(isolate, handle(function->map(), isolate), "SetPrototype");
5062 :
5063 94222 : JSObject::MigrateToMap(function, new_map);
5064 94222 : new_map->SetConstructor(*value);
5065 94222 : new_map->set_has_non_instance_prototype(true);
5066 :
5067 : FunctionKind kind = function->shared()->kind();
5068 188444 : Handle<Context> native_context(function->context()->native_context(),
5069 : isolate);
5070 :
5071 : construct_prototype = Handle<JSReceiver>(
5072 : IsGeneratorFunction(kind)
5073 : ? IsAsyncFunction(kind)
5074 94240 : ? native_context->initial_async_generator_prototype()
5075 94294 : : native_context->initial_generator_prototype()
5076 188363 : : native_context->initial_object_prototype(),
5077 376960 : isolate);
5078 : } else {
5079 169679 : construct_prototype = Handle<JSReceiver>::cast(value);
5080 169679 : function->map()->set_has_non_instance_prototype(false);
5081 : }
5082 :
5083 263901 : SetInstancePrototype(isolate, function, construct_prototype);
5084 263902 : }
5085 :
5086 4677854 : void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
5087 : Handle<Object> prototype) {
5088 4677854 : if (map->prototype() != *prototype)
5089 4677312 : Map::SetPrototype(function->GetIsolate(), map, prototype);
5090 9355694 : function->set_prototype_or_initial_map(*map);
5091 9355722 : map->SetConstructor(*function);
5092 4677863 : if (FLAG_trace_maps) {
5093 3078 : LOG(function->GetIsolate(), MapEvent("InitialMap", Map(), *map, "",
5094 : function->shared()->DebugName()));
5095 : }
5096 4677863 : }
5097 :
5098 18828376 : void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
5099 : DCHECK(function->has_prototype_slot());
5100 : DCHECK(function->IsConstructor() ||
5101 : IsResumableFunction(function->shared()->kind()));
5102 37355205 : if (function->has_initial_map()) return;
5103 : Isolate* isolate = function->GetIsolate();
5104 :
5105 : // First create a new map with the size and number of in-object properties
5106 : // suggested by the function.
5107 : InstanceType instance_type;
5108 301578 : if (IsResumableFunction(function->shared()->kind())) {
5109 : instance_type = IsAsyncGeneratorFunction(function->shared()->kind())
5110 : ? JS_ASYNC_GENERATOR_OBJECT_TYPE
5111 8688 : : JS_GENERATOR_OBJECT_TYPE;
5112 : } else {
5113 : instance_type = JS_OBJECT_TYPE;
5114 : }
5115 :
5116 : int instance_size;
5117 : int inobject_properties;
5118 : int expected_nof_properties =
5119 301578 : CalculateExpectedNofProperties(isolate, function);
5120 301577 : CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties,
5121 301577 : &instance_size, &inobject_properties);
5122 :
5123 : Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size,
5124 : TERMINAL_FAST_ELEMENTS_KIND,
5125 301576 : inobject_properties);
5126 :
5127 : // Fetch or allocate prototype.
5128 : Handle<Object> prototype;
5129 301578 : if (function->has_instance_prototype()) {
5130 482605 : prototype = handle(function->instance_prototype(), isolate);
5131 : } else {
5132 60275 : prototype = isolate->factory()->NewFunctionPrototype(function);
5133 : }
5134 : DCHECK(map->has_fast_object_elements());
5135 :
5136 : // Finally link initial map and constructor function.
5137 : DCHECK(prototype->IsJSReceiver());
5138 301577 : JSFunction::SetInitialMap(function, map, prototype);
5139 301577 : map->StartInobjectSlackTracking();
5140 : }
5141 :
5142 : #ifdef DEBUG
5143 : namespace {
5144 :
5145 : bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
5146 : switch (instance_type) {
5147 : case JS_API_OBJECT_TYPE:
5148 : case JS_ARRAY_BUFFER_TYPE:
5149 : case JS_ARRAY_TYPE:
5150 : case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
5151 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
5152 : case JS_DATA_VIEW_TYPE:
5153 : case JS_DATE_TYPE:
5154 : case JS_FUNCTION_TYPE:
5155 : case JS_GENERATOR_OBJECT_TYPE:
5156 : #ifdef V8_INTL_SUPPORT
5157 : case JS_INTL_COLLATOR_TYPE:
5158 : case JS_INTL_DATE_TIME_FORMAT_TYPE:
5159 : case JS_INTL_LIST_FORMAT_TYPE:
5160 : case JS_INTL_LOCALE_TYPE:
5161 : case JS_INTL_NUMBER_FORMAT_TYPE:
5162 : case JS_INTL_PLURAL_RULES_TYPE:
5163 : case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
5164 : case JS_INTL_SEGMENT_ITERATOR_TYPE:
5165 : case JS_INTL_SEGMENTER_TYPE:
5166 : case JS_INTL_V8_BREAK_ITERATOR_TYPE:
5167 : #endif
5168 : case JS_ASYNC_FUNCTION_OBJECT_TYPE:
5169 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
5170 : case JS_MAP_TYPE:
5171 : case JS_MESSAGE_OBJECT_TYPE:
5172 : case JS_OBJECT_TYPE:
5173 : case JS_ERROR_TYPE:
5174 : case JS_ARGUMENTS_TYPE:
5175 : case JS_PROMISE_TYPE:
5176 : case JS_REGEXP_TYPE:
5177 : case JS_SET_TYPE:
5178 : case JS_SPECIAL_API_OBJECT_TYPE:
5179 : case JS_TYPED_ARRAY_TYPE:
5180 : case JS_VALUE_TYPE:
5181 : case JS_WEAK_MAP_TYPE:
5182 : case JS_WEAK_SET_TYPE:
5183 : case WASM_GLOBAL_TYPE:
5184 : case WASM_INSTANCE_TYPE:
5185 : case WASM_MEMORY_TYPE:
5186 : case WASM_MODULE_TYPE:
5187 : case WASM_TABLE_TYPE:
5188 : return true;
5189 :
5190 : case BIGINT_TYPE:
5191 : case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
5192 : case BYTECODE_ARRAY_TYPE:
5193 : case BYTE_ARRAY_TYPE:
5194 : case CELL_TYPE:
5195 : case CODE_TYPE:
5196 : case FILLER_TYPE:
5197 : case FIXED_ARRAY_TYPE:
5198 : case SCRIPT_CONTEXT_TABLE_TYPE:
5199 : case FIXED_DOUBLE_ARRAY_TYPE:
5200 : case FEEDBACK_METADATA_TYPE:
5201 : case FOREIGN_TYPE:
5202 : case FREE_SPACE_TYPE:
5203 : case HASH_TABLE_TYPE:
5204 : case ORDERED_HASH_MAP_TYPE:
5205 : case ORDERED_HASH_SET_TYPE:
5206 : case ORDERED_NAME_DICTIONARY_TYPE:
5207 : case NAME_DICTIONARY_TYPE:
5208 : case GLOBAL_DICTIONARY_TYPE:
5209 : case NUMBER_DICTIONARY_TYPE:
5210 : case SIMPLE_NUMBER_DICTIONARY_TYPE:
5211 : case STRING_TABLE_TYPE:
5212 : case HEAP_NUMBER_TYPE:
5213 : case JS_BOUND_FUNCTION_TYPE:
5214 : case JS_GLOBAL_OBJECT_TYPE:
5215 : case JS_GLOBAL_PROXY_TYPE:
5216 : case JS_PROXY_TYPE:
5217 : case MAP_TYPE:
5218 : case MUTABLE_HEAP_NUMBER_TYPE:
5219 : case ODDBALL_TYPE:
5220 : case PROPERTY_CELL_TYPE:
5221 : case SHARED_FUNCTION_INFO_TYPE:
5222 : case SYMBOL_TYPE:
5223 : case ALLOCATION_SITE_TYPE:
5224 :
5225 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
5226 : case FIXED_##TYPE##_ARRAY_TYPE:
5227 : #undef TYPED_ARRAY_CASE
5228 :
5229 : #define MAKE_STRUCT_CASE(TYPE, Name, name) case TYPE:
5230 : STRUCT_LIST(MAKE_STRUCT_CASE)
5231 : #undef MAKE_STRUCT_CASE
5232 : // We must not end up here for these instance types at all.
5233 : UNREACHABLE();
5234 : // Fall through.
5235 : default:
5236 : return false;
5237 : }
5238 : }
5239 :
5240 : } // namespace
5241 : #endif
5242 :
5243 : namespace {
5244 :
5245 312989 : bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
5246 : Handle<JSFunction> constructor,
5247 : Handle<Map> constructor_initial_map) {
5248 : // Use the default intrinsic prototype instead.
5249 312989 : if (!new_target->has_prototype_slot()) return false;
5250 : // Check that |function|'s initial map still in sync with the |constructor|,
5251 : // otherwise we must create a new initial map for |function|.
5252 927864 : if (new_target->has_initial_map() &&
5253 614916 : new_target->initial_map()->GetConstructor() == *constructor) {
5254 : DCHECK(new_target->instance_prototype()->IsJSReceiver());
5255 : return true;
5256 : }
5257 : InstanceType instance_type = constructor_initial_map->instance_type();
5258 : DCHECK(CanSubclassHaveInobjectProperties(instance_type));
5259 : // Create a new map with the size and number of in-object properties
5260 : // suggested by |function|.
5261 :
5262 : // Link initial map and constructor function if the new.target is actually a
5263 : // subclass constructor.
5264 306206 : if (!IsDerivedConstructor(new_target->shared()->kind())) return false;
5265 :
5266 : int instance_size;
5267 : int in_object_properties;
5268 : int embedder_fields =
5269 9308 : JSObject::GetEmbedderFieldCount(*constructor_initial_map);
5270 : int expected_nof_properties =
5271 9308 : JSFunction::CalculateExpectedNofProperties(isolate, new_target);
5272 9308 : JSFunction::CalculateInstanceSizeHelper(
5273 : instance_type, true, embedder_fields, expected_nof_properties,
5274 9308 : &instance_size, &in_object_properties);
5275 :
5276 18616 : int pre_allocated = constructor_initial_map->GetInObjectProperties() -
5277 9308 : constructor_initial_map->UnusedPropertyFields();
5278 18616 : CHECK_LE(constructor_initial_map->UsedInstanceSize(), instance_size);
5279 9308 : int unused_property_fields = in_object_properties - pre_allocated;
5280 : Handle<Map> map =
5281 : Map::CopyInitialMap(isolate, constructor_initial_map, instance_size,
5282 9308 : in_object_properties, unused_property_fields);
5283 9308 : map->set_new_target_is_base(false);
5284 18616 : Handle<Object> prototype(new_target->instance_prototype(), isolate);
5285 9308 : JSFunction::SetInitialMap(new_target, map, prototype);
5286 : DCHECK(new_target->instance_prototype()->IsJSReceiver());
5287 18616 : map->SetConstructor(*constructor);
5288 9308 : map->set_construction_counter(Map::kNoSlackTracking);
5289 9308 : map->StartInobjectSlackTracking();
5290 9308 : return true;
5291 : }
5292 :
5293 : } // namespace
5294 :
5295 : // static
5296 3242391 : MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
5297 : Handle<JSFunction> constructor,
5298 : Handle<JSReceiver> new_target) {
5299 3242391 : EnsureHasInitialMap(constructor);
5300 :
5301 : Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
5302 3242415 : if (*new_target == *constructor) return constructor_initial_map;
5303 :
5304 : Handle<Map> result_map;
5305 : // Fast case, new.target is a subclass of constructor. The map is cacheable
5306 : // (and may already have been cached). new.target.prototype is guaranteed to
5307 : // be a JSReceiver.
5308 314476 : if (new_target->IsJSFunction()) {
5309 : Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
5310 312991 : if (FastInitializeDerivedMap(isolate, function, constructor,
5311 : constructor_initial_map)) {
5312 16051 : return handle(function->initial_map(), isolate);
5313 : }
5314 : }
5315 :
5316 : // Slow path, new.target is either a proxy or can't cache the map.
5317 : // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
5318 : // fall back to the intrinsicDefaultProto.
5319 : Handle<Object> prototype;
5320 298419 : if (new_target->IsJSFunction()) {
5321 : Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
5322 296934 : if (function->has_prototype_slot()) {
5323 : // Make sure the new.target.prototype is cached.
5324 296898 : EnsureHasInitialMap(function);
5325 593797 : prototype = handle(function->prototype(), isolate);
5326 : } else {
5327 : // No prototype property, use the intrinsict default proto further down.
5328 : prototype = isolate->factory()->undefined_value();
5329 : }
5330 : } else {
5331 : Handle<String> prototype_string = isolate->factory()->prototype_string();
5332 2970 : ASSIGN_RETURN_ON_EXCEPTION(
5333 : isolate, prototype,
5334 : JSReceiver::GetProperty(isolate, new_target, prototype_string), Map);
5335 : // The above prototype lookup might change the constructor and its
5336 : // prototype, hence we have to reload the initial map.
5337 1404 : EnsureHasInitialMap(constructor);
5338 : constructor_initial_map = handle(constructor->initial_map(), isolate);
5339 : }
5340 :
5341 : // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
5342 : // correct realm. Rather than directly fetching the .prototype, we fetch the
5343 : // constructor that points to the .prototype. This relies on
5344 : // constructor.prototype being FROZEN for those constructors.
5345 298345 : if (!prototype->IsJSReceiver()) {
5346 : Handle<Context> context;
5347 2754 : ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
5348 : JSReceiver::GetFunctionRealm(new_target), Map);
5349 : DCHECK(context->IsNativeContext());
5350 : Handle<Object> maybe_index = JSReceiver::GetDataProperty(
5351 1377 : constructor, isolate->factory()->native_context_index_symbol());
5352 : int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index)
5353 1377 : : Context::OBJECT_FUNCTION_INDEX;
5354 : Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)),
5355 : isolate);
5356 2754 : prototype = handle(realm_constructor->prototype(), isolate);
5357 : }
5358 :
5359 298345 : Handle<Map> map = Map::CopyInitialMap(isolate, constructor_initial_map);
5360 298340 : map->set_new_target_is_base(false);
5361 298340 : CHECK(prototype->IsJSReceiver());
5362 298340 : if (map->prototype() != *prototype)
5363 297558 : Map::SetPrototype(isolate, map, prototype);
5364 596676 : map->SetConstructor(*constructor);
5365 298340 : return map;
5366 : }
5367 :
5368 3731729 : int JSFunction::ComputeInstanceSizeWithMinSlack(Isolate* isolate) {
5369 3731729 : CHECK(has_initial_map());
5370 3731737 : if (initial_map()->IsInobjectSlackTrackingInProgress()) {
5371 6456 : int slack = initial_map()->ComputeMinObjectSlack(isolate);
5372 : return initial_map()->InstanceSizeFromSlack(slack);
5373 : }
5374 : return initial_map()->instance_size();
5375 : }
5376 :
5377 0 : void JSFunction::PrintName(FILE* out) {
5378 0 : std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
5379 0 : PrintF(out, "%s", name.get());
5380 0 : }
5381 :
5382 520179 : Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
5383 : Isolate* isolate = function->GetIsolate();
5384 : Handle<Object> name =
5385 520179 : JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
5386 520179 : if (name->IsString()) return Handle<String>::cast(name);
5387 1038972 : return handle(function->shared()->DebugName(), isolate);
5388 : }
5389 :
5390 408354 : Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
5391 : Isolate* isolate = function->GetIsolate();
5392 : Handle<Object> name = JSReceiver::GetDataProperty(
5393 408354 : function, isolate->factory()->display_name_string());
5394 408354 : if (name->IsString()) return Handle<String>::cast(name);
5395 408320 : return JSFunction::GetName(function);
5396 : }
5397 :
5398 6967 : bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
5399 : Handle<String> prefix) {
5400 : Isolate* isolate = function->GetIsolate();
5401 : Handle<String> function_name;
5402 13934 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name,
5403 : Name::ToFunctionName(isolate, name), false);
5404 6958 : if (prefix->length() > 0) {
5405 3237 : IncrementalStringBuilder builder(isolate);
5406 3237 : builder.AppendString(prefix);
5407 : builder.AppendCharacter(' ');
5408 3237 : builder.AppendString(function_name);
5409 6474 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, builder.Finish(),
5410 : false);
5411 : }
5412 13880 : RETURN_ON_EXCEPTION_VALUE(
5413 : isolate,
5414 : JSObject::DefinePropertyOrElementIgnoreAttributes(
5415 : function, isolate->factory()->name_string(), function_name,
5416 : static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)),
5417 : false);
5418 6940 : return true;
5419 : }
5420 :
5421 : namespace {
5422 :
5423 1082735 : Handle<String> NativeCodeFunctionSourceString(
5424 : Handle<SharedFunctionInfo> shared_info) {
5425 : Isolate* const isolate = shared_info->GetIsolate();
5426 1082735 : IncrementalStringBuilder builder(isolate);
5427 : builder.AppendCString("function ");
5428 2165470 : builder.AppendString(handle(shared_info->Name(), isolate));
5429 : builder.AppendCString("() { [native code] }");
5430 2165470 : return builder.Finish().ToHandleChecked();
5431 : }
5432 :
5433 : } // namespace
5434 :
5435 : // static
5436 1889735 : Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
5437 : Isolate* const isolate = function->GetIsolate();
5438 : Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
5439 :
5440 : // Check if {function} should hide its source code.
5441 1889735 : if (!shared_info->IsUserJavaScript()) {
5442 1082663 : return NativeCodeFunctionSourceString(shared_info);
5443 : }
5444 :
5445 : // Check if we should print {function} as a class.
5446 : Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
5447 807072 : function, isolate->factory()->class_positions_symbol());
5448 807072 : if (maybe_class_positions->IsClassPositions()) {
5449 : ClassPositions class_positions =
5450 : ClassPositions::cast(*maybe_class_positions);
5451 : int start_position = class_positions->start();
5452 : int end_position = class_positions->end();
5453 : Handle<String> script_source(
5454 43444 : String::cast(Script::cast(shared_info->script())->source()), isolate);
5455 : return isolate->factory()->NewSubString(script_source, start_position,
5456 21722 : end_position);
5457 : }
5458 :
5459 : // Check if we have source code for the {function}.
5460 785350 : if (!shared_info->HasSourceCode()) {
5461 0 : return NativeCodeFunctionSourceString(shared_info);
5462 : }
5463 :
5464 1570700 : if (shared_info->function_token_position() == kNoSourcePosition) {
5465 : // If the function token position isn't valid, return [native code] to
5466 : // ensure calling eval on the returned source code throws rather than
5467 : // giving inconsistent call behaviour.
5468 : isolate->CountUsage(
5469 72 : v8::Isolate::UseCounterFeature::kFunctionTokenOffsetTooLongForToString);
5470 72 : return NativeCodeFunctionSourceString(shared_info);
5471 : }
5472 : return Handle<String>::cast(
5473 785278 : SharedFunctionInfo::GetSourceCodeHarmony(shared_info));
5474 : }
5475 :
5476 : // static
5477 310885 : int JSFunction::CalculateExpectedNofProperties(Isolate* isolate,
5478 : Handle<JSFunction> function) {
5479 : int expected_nof_properties = 0;
5480 635714 : for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
5481 635714 : !iter.IsAtEnd(); iter.Advance()) {
5482 : Handle<JSReceiver> current =
5483 : PrototypeIterator::GetCurrent<JSReceiver>(iter);
5484 946592 : if (!current->IsJSFunction()) break;
5485 : Handle<JSFunction> func = Handle<JSFunction>::cast(current);
5486 : // The super constructor should be compiled for the number of expected
5487 : // properties to be available.
5488 : Handle<SharedFunctionInfo> shared(func->shared(), isolate);
5489 635943 : IsCompiledScope is_compiled_scope(shared->is_compiled_scope());
5490 664287 : if (is_compiled_scope.is_compiled() ||
5491 28344 : Compiler::Compile(func, Compiler::CLEAR_EXCEPTION,
5492 : &is_compiled_scope)) {
5493 : DCHECK(shared->is_compiled());
5494 635934 : int count = shared->expected_nof_properties();
5495 : // Check that the estimate is sane.
5496 635934 : if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
5497 635714 : expected_nof_properties += count;
5498 : } else {
5499 220 : return JSObject::kMaxInObjectProperties;
5500 : }
5501 : } else {
5502 : // In case there was a compilation error for the constructor we will
5503 : // throw an error during instantiation.
5504 : break;
5505 : }
5506 : }
5507 : // Inobject slack tracking will reclaim redundant inobject space
5508 : // later, so we can afford to adjust the estimate generously,
5509 : // meaning we over-allocate by at least 8 slots in the beginning.
5510 310664 : if (expected_nof_properties > 0) {
5511 227014 : expected_nof_properties += 8;
5512 227014 : if (expected_nof_properties > JSObject::kMaxInObjectProperties) {
5513 : expected_nof_properties = JSObject::kMaxInObjectProperties;
5514 : }
5515 : }
5516 : return expected_nof_properties;
5517 : }
5518 :
5519 : // static
5520 310884 : void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
5521 : bool has_prototype_slot,
5522 : int requested_embedder_fields,
5523 : int requested_in_object_properties,
5524 : int* instance_size,
5525 : int* in_object_properties) {
5526 : DCHECK_LE(static_cast<unsigned>(requested_embedder_fields),
5527 : JSObject::kMaxEmbedderFields);
5528 310884 : int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
5529 310884 : if (requested_embedder_fields) {
5530 : // If there are embedder fields, then the embedder fields start offset must
5531 : // be properly aligned (embedder fields are located between object header
5532 : // and inobject fields).
5533 : header_size = RoundUp<kSystemPointerSize>(header_size);
5534 4521 : requested_embedder_fields *= kEmbedderDataSlotSizeInTaggedSlots;
5535 : }
5536 : int max_nof_fields =
5537 310884 : (JSObject::kMaxInstanceSize - header_size) >> kTaggedSizeLog2;
5538 310884 : CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
5539 310884 : CHECK_LE(static_cast<unsigned>(requested_embedder_fields),
5540 : static_cast<unsigned>(max_nof_fields));
5541 310884 : *in_object_properties = Min(requested_in_object_properties,
5542 310884 : max_nof_fields - requested_embedder_fields);
5543 : *instance_size =
5544 310884 : header_size +
5545 621768 : ((requested_embedder_fields + *in_object_properties) << kTaggedSizeLog2);
5546 310884 : CHECK_EQ(*in_object_properties,
5547 : ((*instance_size - header_size) >> kTaggedSizeLog2) -
5548 : requested_embedder_fields);
5549 310884 : CHECK_LE(static_cast<unsigned>(*instance_size),
5550 : static_cast<unsigned>(JSObject::kMaxInstanceSize));
5551 310884 : }
5552 :
5553 52398 : void JSFunction::ClearTypeFeedbackInfo() {
5554 52398 : ResetIfBytecodeFlushed();
5555 52398 : if (has_feedback_vector()) {
5556 52354 : FeedbackVector vector = feedback_vector();
5557 : Isolate* isolate = GetIsolate();
5558 52354 : if (vector->ClearSlots(isolate)) {
5559 : IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(), *this,
5560 27636 : "ClearTypeFeedbackInfo");
5561 : }
5562 : }
5563 52398 : }
5564 :
5565 906999 : void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
5566 : Handle<Name> name) {
5567 : // Regardless of whether the property is there or not invalidate
5568 : // Load/StoreGlobalICs that load/store through global object's prototype.
5569 906999 : JSObject::InvalidatePrototypeValidityCell(*global);
5570 :
5571 : DCHECK(!global->HasFastProperties());
5572 1813998 : auto dictionary = handle(global->global_dictionary(), global->GetIsolate());
5573 906999 : int entry = dictionary->FindEntry(global->GetIsolate(), name);
5574 906999 : if (entry == GlobalDictionary::kNotFound) return;
5575 87 : PropertyCell::InvalidateEntry(global->GetIsolate(), dictionary, entry);
5576 : }
5577 :
5578 8222059 : Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
5579 : Handle<JSGlobalObject> global, Handle<Name> name,
5580 : PropertyCellType cell_type, int* entry_out) {
5581 : Isolate* isolate = global->GetIsolate();
5582 : DCHECK(!global->HasFastProperties());
5583 16444119 : Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
5584 8222060 : int entry = dictionary->FindEntry(isolate, name);
5585 : Handle<PropertyCell> cell;
5586 8222069 : if (entry != GlobalDictionary::kNotFound) {
5587 3043 : if (entry_out) *entry_out = entry;
5588 : cell = handle(dictionary->CellAt(entry), isolate);
5589 : PropertyCellType original_cell_type = cell->property_details().cell_type();
5590 : DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
5591 : original_cell_type == PropertyCellType::kUninitialized);
5592 : DCHECK(cell->value()->IsTheHole(isolate));
5593 3043 : if (original_cell_type == PropertyCellType::kInvalidated) {
5594 481 : cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry);
5595 : }
5596 : PropertyDetails details(kData, NONE, cell_type);
5597 6086 : cell->set_property_details(details);
5598 3043 : return cell;
5599 : }
5600 8219026 : cell = isolate->factory()->NewPropertyCell(name);
5601 : PropertyDetails details(kData, NONE, cell_type);
5602 : dictionary = GlobalDictionary::Add(isolate, dictionary, name, cell, details,
5603 8218996 : entry_out);
5604 : // {*entry_out} is initialized inside GlobalDictionary::Add().
5605 16438004 : global->SetProperties(*dictionary);
5606 8219004 : return cell;
5607 : }
5608 :
5609 : // static
5610 149028 : MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
5611 : Handle<JSReceiver> new_target, double tv) {
5612 : Isolate* const isolate = constructor->GetIsolate();
5613 : Handle<JSObject> result;
5614 298056 : ASSIGN_RETURN_ON_EXCEPTION(
5615 : isolate, result,
5616 : JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
5617 : JSDate);
5618 149028 : if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
5619 148533 : tv = DoubleToInteger(tv) + 0.0;
5620 : } else {
5621 : tv = std::numeric_limits<double>::quiet_NaN();
5622 : }
5623 149028 : Handle<Object> value = isolate->factory()->NewNumber(tv);
5624 298056 : Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
5625 149028 : return Handle<JSDate>::cast(result);
5626 : }
5627 :
5628 : // static
5629 1121433 : double JSDate::CurrentTimeValue(Isolate* isolate) {
5630 1121433 : if (FLAG_log_internal_timer_events) LOG(isolate, CurrentTimeEvent());
5631 :
5632 : // According to ECMA-262, section 15.9.1, page 117, the precision of
5633 : // the number in a Date object representing a particular instant in
5634 : // time is milliseconds. Therefore, we floor the result of getting
5635 : // the OS time.
5636 1121433 : return std::floor(V8::GetCurrentPlatform()->CurrentClockTimeMillis());
5637 : }
5638 :
5639 : // static
5640 11142 : Address JSDate::GetField(Address raw_object, Address smi_index) {
5641 : Object object(raw_object);
5642 : Smi index(smi_index);
5643 22284 : return JSDate::cast(object)
5644 33426 : ->DoGetField(static_cast<FieldIndex>(index->value()))
5645 11142 : ->ptr();
5646 : }
5647 :
5648 11142 : Object JSDate::DoGetField(FieldIndex index) {
5649 : DCHECK_NE(index, kDateValue);
5650 :
5651 : DateCache* date_cache = GetIsolate()->date_cache();
5652 :
5653 11142 : if (index < kFirstUncachedField) {
5654 : Object stamp = cache_stamp();
5655 10854 : if (stamp != date_cache->stamp() && stamp->IsSmi()) {
5656 : // Since the stamp is not NaN, the value is also not NaN.
5657 : int64_t local_time_ms =
5658 378 : date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
5659 378 : SetCachedFields(local_time_ms, date_cache);
5660 : }
5661 5427 : switch (index) {
5662 : case kYear:
5663 : return year();
5664 : case kMonth:
5665 : return month();
5666 : case kDay:
5667 : return day();
5668 : case kWeekday:
5669 : return weekday();
5670 : case kHour:
5671 : return hour();
5672 : case kMinute:
5673 : return min();
5674 : case kSecond:
5675 : return sec();
5676 : default:
5677 0 : UNREACHABLE();
5678 : }
5679 : }
5680 :
5681 5715 : if (index >= kFirstUTCField) {
5682 5553 : return GetUTCField(index, value()->Number(), date_cache);
5683 : }
5684 :
5685 : double time = value()->Number();
5686 216 : if (std::isnan(time)) return GetReadOnlyRoots().nan_value();
5687 :
5688 108 : int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
5689 : int days = DateCache::DaysFromTime(local_time_ms);
5690 :
5691 108 : if (index == kDays) return Smi::FromInt(days);
5692 :
5693 : int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
5694 216 : if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
5695 : DCHECK_EQ(index, kTimeInDay);
5696 0 : return Smi::FromInt(time_in_day_ms);
5697 : }
5698 :
5699 5553 : Object JSDate::GetUTCField(FieldIndex index, double value,
5700 : DateCache* date_cache) {
5701 : DCHECK_GE(index, kFirstUTCField);
5702 :
5703 10656 : if (std::isnan(value)) return GetReadOnlyRoots().nan_value();
5704 :
5705 450 : int64_t time_ms = static_cast<int64_t>(value);
5706 :
5707 450 : if (index == kTimezoneOffset) {
5708 126 : GetIsolate()->CountUsage(v8::Isolate::kDateGetTimezoneOffset);
5709 126 : return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
5710 : }
5711 :
5712 : int days = DateCache::DaysFromTime(time_ms);
5713 :
5714 333 : if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
5715 :
5716 315 : if (index <= kDayUTC) {
5717 : int year, month, day;
5718 117 : date_cache->YearMonthDayFromDays(days, &year, &month, &day);
5719 153 : if (index == kYearUTC) return Smi::FromInt(year);
5720 117 : if (index == kMonthUTC) return Smi::FromInt(month);
5721 : DCHECK_EQ(index, kDayUTC);
5722 90 : return Smi::FromInt(day);
5723 : }
5724 :
5725 : int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
5726 198 : switch (index) {
5727 : case kHourUTC:
5728 180 : return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
5729 : case kMinuteUTC:
5730 90 : return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
5731 : case kSecondUTC:
5732 72 : return Smi::FromInt((time_in_day_ms / 1000) % 60);
5733 : case kMillisecondUTC:
5734 54 : return Smi::FromInt(time_in_day_ms % 1000);
5735 : case kDaysUTC:
5736 0 : return Smi::FromInt(days);
5737 : case kTimeInDayUTC:
5738 0 : return Smi::FromInt(time_in_day_ms);
5739 : default:
5740 0 : UNREACHABLE();
5741 : }
5742 :
5743 : UNREACHABLE();
5744 : }
5745 :
5746 : // static
5747 11151 : Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
5748 : Isolate* const isolate = date->GetIsolate();
5749 11151 : Handle<Object> value = isolate->factory()->NewNumber(v);
5750 : bool value_is_nan = std::isnan(v);
5751 22302 : date->SetValue(*value, value_is_nan);
5752 11151 : return value;
5753 : }
5754 :
5755 160179 : void JSDate::SetValue(Object value, bool is_value_nan) {
5756 160179 : set_value(value);
5757 160179 : if (is_value_nan) {
5758 : HeapNumber nan = GetReadOnlyRoots().nan_value();
5759 : set_cache_stamp(nan, SKIP_WRITE_BARRIER);
5760 : set_year(nan, SKIP_WRITE_BARRIER);
5761 : set_month(nan, SKIP_WRITE_BARRIER);
5762 : set_day(nan, SKIP_WRITE_BARRIER);
5763 : set_hour(nan, SKIP_WRITE_BARRIER);
5764 : set_min(nan, SKIP_WRITE_BARRIER);
5765 : set_sec(nan, SKIP_WRITE_BARRIER);
5766 : set_weekday(nan, SKIP_WRITE_BARRIER);
5767 : } else {
5768 : set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
5769 : }
5770 160179 : }
5771 :
5772 378 : void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
5773 : int days = DateCache::DaysFromTime(local_time_ms);
5774 : int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
5775 : int year, month, day;
5776 378 : date_cache->YearMonthDayFromDays(days, &year, &month, &day);
5777 : int weekday = date_cache->Weekday(days);
5778 378 : int hour = time_in_day_ms / (60 * 60 * 1000);
5779 378 : int min = (time_in_day_ms / (60 * 1000)) % 60;
5780 378 : int sec = (time_in_day_ms / 1000) % 60;
5781 378 : set_cache_stamp(date_cache->stamp());
5782 378 : set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
5783 378 : set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
5784 378 : set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
5785 : set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
5786 : set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
5787 : set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
5788 : set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
5789 378 : }
5790 :
5791 9175 : int JSMessageObject::GetLineNumber() const {
5792 9175 : if (start_position() == -1) return Message::kNoLineNumberInfo;
5793 :
5794 : Handle<Script> the_script(script(), GetIsolate());
5795 :
5796 : Script::PositionInfo info;
5797 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
5798 9055 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
5799 : offset_flag)) {
5800 : return Message::kNoLineNumberInfo;
5801 : }
5802 :
5803 9055 : return info.line + 1;
5804 : }
5805 :
5806 15206 : int JSMessageObject::GetColumnNumber() const {
5807 15206 : if (start_position() == -1) return -1;
5808 :
5809 : Handle<Script> the_script(script(), GetIsolate());
5810 :
5811 : Script::PositionInfo info;
5812 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
5813 15031 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
5814 : offset_flag)) {
5815 : return -1;
5816 : }
5817 :
5818 15031 : return info.column; // Note: No '+1' in contrast to GetLineNumber.
5819 : }
5820 :
5821 6325 : Handle<String> JSMessageObject::GetSourceLine() const {
5822 : Isolate* isolate = GetIsolate();
5823 : Handle<Script> the_script(script(), isolate);
5824 :
5825 6325 : if (the_script->type() == Script::TYPE_WASM) {
5826 : return isolate->factory()->empty_string();
5827 : }
5828 :
5829 : Script::PositionInfo info;
5830 : const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
5831 6325 : if (!Script::GetPositionInfo(the_script, start_position(), &info,
5832 : offset_flag)) {
5833 : return isolate->factory()->empty_string();
5834 : }
5835 :
5836 6325 : Handle<String> src = handle(String::cast(the_script->source()), isolate);
5837 6325 : return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
5838 : }
5839 :
5840 : } // namespace internal
5841 120216 : } // namespace v8
|