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