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