1// Copyright 2015 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/objects.h" 6 7#include <algorithm> 8#include <cmath> 9#include <memory> 10#include <sstream> 11#include <vector> 12 13#include "src/api/api-arguments-inl.h" 14#include "src/api/api-natives.h" 15#include "src/api/api.h" 16#include "src/ast/ast.h" 17#include "src/ast/scopes.h" 18#include "src/base/bits.h" 19#include "src/base/debug/stack_trace.h" 20#include "src/base/overflowing-math.h" 21#include "src/base/utils/random-number-generator.h" 22#include "src/builtins/accessors.h" 23#include "src/builtins/builtins.h" 24#include "src/codegen/compiler.h" 25#include "src/common/globals.h" 26#include "src/common/message-template.h" 27#include "src/date/date.h" 28#include "src/debug/debug.h" 29#include "src/diagnostics/code-tracer.h" 30#include "src/execution/arguments.h" 31#include "src/execution/execution.h" 32#include "src/execution/frames-inl.h" 33#include "src/execution/isolate-inl.h" 34#include "src/execution/isolate-utils-inl.h" 35#include "src/execution/isolate-utils.h" 36#include "src/execution/microtask-queue.h" 37#include "src/execution/protectors-inl.h" 38#include "src/heap/factory-inl.h" 39#include "src/heap/heap-inl.h" 40#include "src/heap/local-factory-inl.h" 41#include "src/heap/read-only-heap.h" 42#include "src/ic/ic.h" 43#include "src/init/bootstrapper.h" 44#include "src/logging/counters.h" 45#include "src/logging/log.h" 46#include "src/logging/runtime-call-stats-scope.h" 47#include "src/objects/allocation-site-inl.h" 48#include "src/objects/allocation-site-scopes.h" 49#include "src/objects/api-callbacks.h" 50#include "src/objects/arguments-inl.h" 51#include "src/objects/bigint.h" 52#include "src/objects/call-site-info-inl.h" 53#include "src/objects/cell-inl.h" 54#include "src/objects/code-inl.h" 55#include "src/objects/compilation-cache-table-inl.h" 56#include "src/objects/debug-objects-inl.h" 57#include "src/objects/elements.h" 58#include "src/objects/embedder-data-array-inl.h" 59#include "src/objects/field-index-inl.h" 60#include "src/objects/field-index.h" 61#include "src/objects/field-type.h" 62#include "src/objects/foreign.h" 63#include "src/objects/free-space-inl.h" 64#include "src/objects/function-kind.h" 65#include "src/objects/hash-table-inl.h" 66#include "src/objects/instance-type.h" 67#include "src/objects/js-array-buffer-inl.h" 68#include "src/objects/js-array-inl.h" 69#include "src/objects/keys.h" 70#include "src/objects/lookup-inl.h" 71#include "src/objects/map-updater.h" 72#include "src/objects/objects-body-descriptors-inl.h" 73#include "src/objects/objects-inl.h" 74#include "src/objects/property-details.h" 75#include "src/roots/roots.h" 76#include "src/snapshot/deserializer.h" 77#include "src/utils/identity-map.h" 78#ifdef V8_INTL_SUPPORT 79#include "src/objects/js-break-iterator.h" 80#include "src/objects/js-collator.h" 81#endif // V8_INTL_SUPPORT 82#include "src/objects/js-collection-inl.h" 83#ifdef V8_INTL_SUPPORT 84#include "src/objects/js-date-time-format.h" 85#endif // V8_INTL_SUPPORT 86#include "src/objects/js-generator-inl.h" 87#ifdef V8_INTL_SUPPORT 88#include "src/objects/js-list-format.h" 89#include "src/objects/js-locale.h" 90#include "src/objects/js-number-format.h" 91#include "src/objects/js-plural-rules.h" 92#endif // V8_INTL_SUPPORT 93#include "src/objects/js-regexp-inl.h" 94#include "src/objects/js-regexp-string-iterator.h" 95#ifdef V8_INTL_SUPPORT 96#include "src/objects/js-relative-time-format.h" 97#include "src/objects/js-segment-iterator.h" 98#include "src/objects/js-segmenter.h" 99#include "src/objects/js-segments.h" 100#endif // V8_INTL_SUPPORT 101#include "src/codegen/source-position-table.h" 102#include "src/objects/js-weak-refs-inl.h" 103#include "src/objects/literal-objects-inl.h" 104#include "src/objects/map-inl.h" 105#include "src/objects/map.h" 106#include "src/objects/megadom-handler-inl.h" 107#include "src/objects/microtask-inl.h" 108#include "src/objects/module-inl.h" 109#include "src/objects/promise-inl.h" 110#include "src/objects/property-descriptor-object-inl.h" 111#include "src/objects/property-descriptor.h" 112#include "src/objects/prototype.h" 113#include "src/objects/slots-atomic-inl.h" 114#include "src/objects/string-comparator.h" 115#include "src/objects/string-set-inl.h" 116#include "src/objects/struct-inl.h" 117#include "src/objects/template-objects-inl.h" 118#include "src/objects/transitions-inl.h" 119#include "src/parsing/preparse-data.h" 120#include "src/regexp/regexp.h" 121#include "src/strings/string-builder-inl.h" 122#include "src/strings/string-search.h" 123#include "src/strings/string-stream.h" 124#include "src/strings/unicode-decoder.h" 125#include "src/strings/unicode-inl.h" 126#include "src/utils/ostreams.h" 127#include "src/utils/utils-inl.h" 128#include "src/zone/zone.h" 129 130#if V8_ENABLE_WEBASSEMBLY 131#include "src/wasm/wasm-objects.h" 132#endif // V8_ENABLE_WEBASSEMBLY 133 134namespace v8 { 135namespace internal { 136 137ShouldThrow GetShouldThrow(Isolate* isolate, Maybe<ShouldThrow> should_throw) { 138 if (should_throw.IsJust()) return should_throw.FromJust(); 139 140 LanguageMode mode = isolate->context().scope_info().language_mode(); 141 if (mode == LanguageMode::kStrict) return kThrowOnError; 142 143 for (StackFrameIterator it(isolate); !it.done(); it.Advance()) { 144 if (!(it.frame()->is_optimized() || it.frame()->is_unoptimized())) { 145 continue; 146 } 147 // Get the language mode from closure. 148 JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(it.frame()); 149 std::vector<SharedFunctionInfo> functions; 150 js_frame->GetFunctions(&functions); 151 LanguageMode closure_language_mode = functions.back().language_mode(); 152 if (closure_language_mode > mode) { 153 mode = closure_language_mode; 154 } 155 break; 156 } 157 158 return is_sloppy(mode) ? kDontThrow : kThrowOnError; 159} 160 161bool ComparisonResultToBool(Operation op, ComparisonResult result) { 162 switch (op) { 163 case Operation::kLessThan: 164 return result == ComparisonResult::kLessThan; 165 case Operation::kLessThanOrEqual: 166 return result == ComparisonResult::kLessThan || 167 result == ComparisonResult::kEqual; 168 case Operation::kGreaterThan: 169 return result == ComparisonResult::kGreaterThan; 170 case Operation::kGreaterThanOrEqual: 171 return result == ComparisonResult::kGreaterThan || 172 result == ComparisonResult::kEqual; 173 default: 174 break; 175 } 176 UNREACHABLE(); 177} 178 179std::ostream& operator<<(std::ostream& os, InstanceType instance_type) { 180 switch (instance_type) { 181#define WRITE_TYPE(TYPE) \ 182 case TYPE: \ 183 return os << #TYPE; 184 INSTANCE_TYPE_LIST(WRITE_TYPE) 185#undef WRITE_TYPE 186 } 187 UNREACHABLE(); 188} 189 190std::ostream& operator<<(std::ostream& os, PropertyCellType type) { 191 switch (type) { 192 case PropertyCellType::kUndefined: 193 return os << "Undefined"; 194 case PropertyCellType::kConstant: 195 return os << "Constant"; 196 case PropertyCellType::kConstantType: 197 return os << "ConstantType"; 198 case PropertyCellType::kMutable: 199 return os << "Mutable"; 200 case PropertyCellType::kInTransition: 201 return os << "InTransition"; 202 } 203 UNREACHABLE(); 204} 205 206Handle<FieldType> Object::OptimalType(Isolate* isolate, 207 Representation representation) { 208 if (representation.IsNone()) return FieldType::None(isolate); 209 if (FLAG_track_field_types) { 210 if (representation.IsHeapObject() && IsHeapObject()) { 211 // We can track only JavaScript objects with stable maps. 212 Handle<Map> map(HeapObject::cast(*this).map(), isolate); 213 if (map->is_stable() && map->IsJSReceiverMap()) { 214 return FieldType::Class(map, isolate); 215 } 216 } 217 } 218 return FieldType::Any(isolate); 219} 220 221Handle<Object> Object::NewStorageFor(Isolate* isolate, Handle<Object> object, 222 Representation representation) { 223 if (!representation.IsDouble()) return object; 224 auto result = isolate->factory()->NewHeapNumberWithHoleNaN(); 225 if (object->IsUninitialized(isolate)) { 226 result->set_value_as_bits(kHoleNanInt64, kRelaxedStore); 227 } else if (object->IsHeapNumber()) { 228 // Ensure that all bits of the double value are preserved. 229 result->set_value_as_bits( 230 HeapNumber::cast(*object).value_as_bits(kRelaxedLoad), kRelaxedStore); 231 } else { 232 result->set_value(object->Number(), kRelaxedStore); 233 } 234 return result; 235} 236 237template <AllocationType allocation_type, typename IsolateT> 238Handle<Object> Object::WrapForRead(IsolateT* isolate, Handle<Object> object, 239 Representation representation) { 240 DCHECK(!object->IsUninitialized(isolate)); 241 if (!representation.IsDouble()) { 242 DCHECK(object->FitsRepresentation(representation)); 243 return object; 244 } 245 return isolate->factory()->template NewHeapNumberFromBits<allocation_type>( 246 HeapNumber::cast(*object).value_as_bits(kRelaxedLoad)); 247} 248 249template Handle<Object> Object::WrapForRead<AllocationType::kYoung>( 250 Isolate* isolate, Handle<Object> object, Representation representation); 251template Handle<Object> Object::WrapForRead<AllocationType::kOld>( 252 LocalIsolate* isolate, Handle<Object> object, 253 Representation representation); 254 255MaybeHandle<JSReceiver> Object::ToObjectImpl(Isolate* isolate, 256 Handle<Object> object, 257 const char* method_name) { 258 DCHECK(!object->IsJSReceiver()); // Use ToObject() for fast path. 259 Handle<Context> native_context = isolate->native_context(); 260 Handle<JSFunction> constructor; 261 if (object->IsSmi()) { 262 constructor = handle(native_context->number_function(), isolate); 263 } else { 264 int constructor_function_index = 265 Handle<HeapObject>::cast(object)->map().GetConstructorFunctionIndex(); 266 if (constructor_function_index == Map::kNoConstructorFunctionIndex) { 267 if (method_name != nullptr) { 268 THROW_NEW_ERROR( 269 isolate, 270 NewTypeError( 271 MessageTemplate::kCalledOnNullOrUndefined, 272 isolate->factory()->NewStringFromAsciiChecked(method_name)), 273 JSReceiver); 274 } 275 THROW_NEW_ERROR(isolate, 276 NewTypeError(MessageTemplate::kUndefinedOrNullToObject), 277 JSReceiver); 278 } 279 constructor = handle( 280 JSFunction::cast(native_context->get(constructor_function_index)), 281 isolate); 282 } 283 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); 284 Handle<JSPrimitiveWrapper>::cast(result)->set_value(*object); 285 return result; 286} 287 288// ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee. 289// static 290MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate, 291 Handle<Object> object) { 292 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); 293 if (object->IsNullOrUndefined(isolate)) { 294 return isolate->global_proxy(); 295 } 296 return Object::ToObject(isolate, object); 297} 298 299// static 300MaybeHandle<Object> Object::ConvertToNumberOrNumeric(Isolate* isolate, 301 Handle<Object> input, 302 Conversion mode) { 303 while (true) { 304 if (input->IsNumber()) { 305 return input; 306 } 307 if (input->IsString()) { 308 return String::ToNumber(isolate, Handle<String>::cast(input)); 309 } 310 if (input->IsOddball()) { 311 return Oddball::ToNumber(isolate, Handle<Oddball>::cast(input)); 312 } 313 if (input->IsSymbol()) { 314 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber), 315 Object); 316 } 317 if (input->IsBigInt()) { 318 if (mode == Conversion::kToNumeric) return input; 319 DCHECK_EQ(mode, Conversion::kToNumber); 320 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntToNumber), 321 Object); 322 } 323 ASSIGN_RETURN_ON_EXCEPTION( 324 isolate, input, 325 JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(input), 326 ToPrimitiveHint::kNumber), 327 Object); 328 } 329} 330 331// static 332MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate, 333 Handle<Object> input) { 334 ASSIGN_RETURN_ON_EXCEPTION( 335 isolate, input, 336 ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); 337 if (input->IsSmi()) return input; 338 return isolate->factory()->NewNumber(DoubleToInteger(input->Number())); 339} 340 341// static 342MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate, 343 Handle<Object> input) { 344 ASSIGN_RETURN_ON_EXCEPTION( 345 isolate, input, 346 ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); 347 if (input->IsSmi()) return input; 348 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number())); 349} 350 351// static 352MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate, 353 Handle<Object> input) { 354 ASSIGN_RETURN_ON_EXCEPTION( 355 isolate, input, 356 ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); 357 if (input->IsSmi()) return handle(Smi::cast(*input).ToUint32Smi(), isolate); 358 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number())); 359} 360 361// static 362MaybeHandle<Name> Object::ConvertToName(Isolate* isolate, 363 Handle<Object> input) { 364 ASSIGN_RETURN_ON_EXCEPTION( 365 isolate, input, 366 Object::ToPrimitive(isolate, input, ToPrimitiveHint::kString), Name); 367 if (input->IsName()) return Handle<Name>::cast(input); 368 return ToString(isolate, input); 369} 370 371// ES6 7.1.14 372// static 373MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate, 374 Handle<Object> value) { 375 // 1. Let key be ToPrimitive(argument, hint String). 376 MaybeHandle<Object> maybe_key = 377 Object::ToPrimitive(isolate, value, ToPrimitiveHint::kString); 378 // 2. ReturnIfAbrupt(key). 379 Handle<Object> key; 380 if (!maybe_key.ToHandle(&key)) return key; 381 // 3. If Type(key) is Symbol, then return key. 382 if (key->IsSymbol()) return key; 383 // 4. Return ToString(key). 384 // Extending spec'ed behavior, we'd be happy to return an element index. 385 if (key->IsSmi()) return key; 386 if (key->IsHeapNumber()) { 387 uint32_t uint_value; 388 if (value->ToArrayLength(&uint_value) && 389 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) { 390 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate); 391 } 392 } 393 return Object::ToString(isolate, key); 394} 395 396// static 397MaybeHandle<String> Object::ConvertToString(Isolate* isolate, 398 Handle<Object> input) { 399 while (true) { 400 if (input->IsOddball()) { 401 return handle(Handle<Oddball>::cast(input)->to_string(), isolate); 402 } 403 if (input->IsNumber()) { 404 return isolate->factory()->NumberToString(input); 405 } 406 if (input->IsSymbol()) { 407 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString), 408 String); 409 } 410 if (input->IsBigInt()) { 411 return BigInt::ToString(isolate, Handle<BigInt>::cast(input)); 412 } 413 ASSIGN_RETURN_ON_EXCEPTION( 414 isolate, input, 415 JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(input), 416 ToPrimitiveHint::kString), 417 String); 418 // The previous isString() check happened in Object::ToString and thus we 419 // put it at the end of the loop in this helper. 420 if (input->IsString()) { 421 return Handle<String>::cast(input); 422 } 423 } 424} 425 426namespace { 427 428bool IsErrorObject(Isolate* isolate, Handle<Object> object) { 429 if (!object->IsJSReceiver()) return false; 430 Handle<Symbol> symbol = isolate->factory()->error_stack_symbol(); 431 return JSReceiver::HasOwnProperty(isolate, Handle<JSReceiver>::cast(object), 432 symbol) 433 .FromMaybe(false); 434} 435 436Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) { 437 return object->IsString() ? Handle<String>::cast(object) 438 : isolate->factory()->empty_string(); 439} 440 441Handle<String> NoSideEffectsErrorToString(Isolate* isolate, 442 Handle<JSReceiver> error) { 443 Handle<Name> name_key = isolate->factory()->name_string(); 444 Handle<Object> name = JSReceiver::GetDataProperty(isolate, error, name_key); 445 Handle<String> name_str = AsStringOrEmpty(isolate, name); 446 447 Handle<Name> msg_key = isolate->factory()->message_string(); 448 Handle<Object> msg = JSReceiver::GetDataProperty(isolate, error, msg_key); 449 Handle<String> msg_str = AsStringOrEmpty(isolate, msg); 450 451 if (name_str->length() == 0) return msg_str; 452 if (msg_str->length() == 0) return name_str; 453 454 IncrementalStringBuilder builder(isolate); 455 builder.AppendString(name_str); 456 builder.AppendCStringLiteral(": "); 457 458 if (builder.Length() + msg_str->length() <= String::kMaxLength) { 459 builder.AppendString(msg_str); 460 } else { 461 builder.AppendCStringLiteral("<a very large string>"); 462 } 463 464 return builder.Finish().ToHandleChecked(); 465} 466 467} // namespace 468 469// static 470MaybeHandle<String> Object::NoSideEffectsToMaybeString(Isolate* isolate, 471 Handle<Object> input) { 472 DisallowJavascriptExecution no_js(isolate); 473 474 if (input->IsString() || input->IsNumber() || input->IsOddball()) { 475 return Object::ToString(isolate, input).ToHandleChecked(); 476 } else if (input->IsJSProxy()) { 477 Handle<Object> currInput = input; 478 do { 479 HeapObject target = Handle<JSProxy>::cast(currInput)->target(isolate); 480 currInput = Handle<Object>(target, isolate); 481 } while (currInput->IsJSProxy()); 482 return NoSideEffectsToString(isolate, currInput); 483 } else if (input->IsBigInt()) { 484 MaybeHandle<String> maybe_string = 485 BigInt::ToString(isolate, Handle<BigInt>::cast(input), 10, kDontThrow); 486 Handle<String> result; 487 if (maybe_string.ToHandle(&result)) return result; 488 // BigInt-to-String conversion can fail on 32-bit platforms where 489 // String::kMaxLength is too small to fit this BigInt. 490 return isolate->factory()->NewStringFromStaticChars( 491 "<a very large BigInt>"); 492 } else if (input->IsFunction()) { 493 // -- F u n c t i o n 494 Handle<String> fun_str; 495 if (input->IsJSBoundFunction()) { 496 fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input)); 497 } else if (input->IsJSWrappedFunction()) { 498 fun_str = 499 JSWrappedFunction::ToString(Handle<JSWrappedFunction>::cast(input)); 500 } else { 501 DCHECK(input->IsJSFunction()); 502 fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input)); 503 } 504 505 if (fun_str->length() > 128) { 506 IncrementalStringBuilder builder(isolate); 507 builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111)); 508 builder.AppendCStringLiteral("...<omitted>..."); 509 builder.AppendString(isolate->factory()->NewSubString( 510 fun_str, fun_str->length() - 2, fun_str->length())); 511 512 return builder.Finish().ToHandleChecked(); 513 } 514 return fun_str; 515 } else if (input->IsSymbol()) { 516 // -- S y m b o l 517 Handle<Symbol> symbol = Handle<Symbol>::cast(input); 518 519 if (symbol->is_private_name()) { 520 return Handle<String>(String::cast(symbol->description()), isolate); 521 } 522 523 IncrementalStringBuilder builder(isolate); 524 builder.AppendCStringLiteral("Symbol("); 525 if (symbol->description().IsString()) { 526 builder.AppendString( 527 handle(String::cast(symbol->description()), isolate)); 528 } 529 builder.AppendCharacter(')'); 530 531 return builder.Finish().ToHandleChecked(); 532 } else if (input->IsJSReceiver()) { 533 // -- J S R e c e i v e r 534 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input); 535 Handle<Object> to_string = JSReceiver::GetDataProperty( 536 isolate, receiver, isolate->factory()->toString_string()); 537 538 if (IsErrorObject(isolate, input) || 539 *to_string == *isolate->error_to_string()) { 540 // When internally formatting error objects, use a side-effects-free 541 // version of Error.prototype.toString independent of the actually 542 // installed toString method. 543 return NoSideEffectsErrorToString(isolate, 544 Handle<JSReceiver>::cast(input)); 545 } else if (*to_string == *isolate->object_to_string()) { 546 Handle<Object> ctor = JSReceiver::GetDataProperty( 547 isolate, receiver, isolate->factory()->constructor_string()); 548 if (ctor->IsFunction()) { 549 Handle<String> ctor_name; 550 if (ctor->IsJSBoundFunction()) { 551 ctor_name = JSBoundFunction::GetName( 552 isolate, Handle<JSBoundFunction>::cast(ctor)) 553 .ToHandleChecked(); 554 } else if (ctor->IsJSFunction()) { 555 ctor_name = 556 JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor)); 557 } 558 559 if (ctor_name->length() != 0) { 560 IncrementalStringBuilder builder(isolate); 561 builder.AppendCStringLiteral("#<"); 562 builder.AppendString(ctor_name); 563 builder.AppendCharacter('>'); 564 565 return builder.Finish().ToHandleChecked(); 566 } 567 } 568 } 569 } 570 return MaybeHandle<String>(kNullMaybeHandle); 571} 572 573// static 574Handle<String> Object::NoSideEffectsToString(Isolate* isolate, 575 Handle<Object> input) { 576 DisallowJavascriptExecution no_js(isolate); 577 578 // Try to convert input to a meaningful string. 579 MaybeHandle<String> maybe_string = NoSideEffectsToMaybeString(isolate, input); 580 Handle<String> string_handle; 581 if (maybe_string.ToHandle(&string_handle)) { 582 return string_handle; 583 } 584 585 // At this point, input is either none of the above or a JSReceiver. 586 587 Handle<JSReceiver> receiver; 588 if (input->IsJSReceiver()) { 589 receiver = Handle<JSReceiver>::cast(input); 590 } else { 591 // This is the only case where Object::ToObject throws. 592 DCHECK(!input->IsSmi()); 593 int constructor_function_index = 594 Handle<HeapObject>::cast(input)->map().GetConstructorFunctionIndex(); 595 if (constructor_function_index == Map::kNoConstructorFunctionIndex) { 596 return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]"); 597 } 598 599 receiver = Object::ToObjectImpl(isolate, input).ToHandleChecked(); 600 } 601 602 Handle<String> builtin_tag = handle(receiver->class_name(), isolate); 603 Handle<Object> tag_obj = JSReceiver::GetDataProperty( 604 isolate, receiver, isolate->factory()->to_string_tag_symbol()); 605 Handle<String> tag = 606 tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag; 607 608 IncrementalStringBuilder builder(isolate); 609 builder.AppendCStringLiteral("[object "); 610 builder.AppendString(tag); 611 builder.AppendCharacter(']'); 612 613 return builder.Finish().ToHandleChecked(); 614} 615 616// static 617MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate, 618 Handle<Object> input) { 619 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object); 620 if (input->IsSmi()) { 621 int value = std::max(Smi::ToInt(*input), 0); 622 return handle(Smi::FromInt(value), isolate); 623 } 624 double len = DoubleToInteger(input->Number()); 625 if (len <= 0.0) { 626 return handle(Smi::zero(), isolate); 627 } else if (len >= kMaxSafeInteger) { 628 len = kMaxSafeInteger; 629 } 630 return isolate->factory()->NewNumber(len); 631} 632 633// static 634MaybeHandle<Object> Object::ConvertToIndex(Isolate* isolate, 635 Handle<Object> input, 636 MessageTemplate error_index) { 637 if (input->IsUndefined(isolate)) return handle(Smi::zero(), isolate); 638 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object); 639 if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input; 640 double len = DoubleToInteger(input->Number()); 641 auto js_len = isolate->factory()->NewNumber(len); 642 if (len < 0.0 || len > kMaxSafeInteger) { 643 THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object); 644 } 645 return js_len; 646} 647 648bool Object::BooleanValue(Isolate* isolate) { 649 if (IsSmi()) return Smi::ToInt(*this) != 0; 650 DCHECK(IsHeapObject()); 651 if (IsBoolean()) return IsTrue(isolate); 652 if (IsNullOrUndefined(isolate)) return false; 653 if (IsUndetectable()) return false; // Undetectable object is false. 654 if (IsString()) return String::cast(*this).length() != 0; 655 if (IsHeapNumber()) return DoubleToBoolean(HeapNumber::cast(*this).value()); 656 if (IsBigInt()) return BigInt::cast(*this).ToBoolean(); 657 return true; 658} 659 660Object Object::ToBoolean(Isolate* isolate) { 661 if (IsBoolean()) return *this; 662 return isolate->heap()->ToBoolean(BooleanValue(isolate)); 663} 664 665namespace { 666 667// TODO(bmeurer): Maybe we should introduce a marker interface Number, 668// where we put all these methods at some point? 669ComparisonResult StrictNumberCompare(double x, double y) { 670 if (std::isnan(x) || std::isnan(y)) { 671 return ComparisonResult::kUndefined; 672 } else if (x < y) { 673 return ComparisonResult::kLessThan; 674 } else if (x > y) { 675 return ComparisonResult::kGreaterThan; 676 } else { 677 return ComparisonResult::kEqual; 678 } 679} 680 681// See Number case of ES6#sec-strict-equality-comparison 682// Returns false if x or y is NaN, treats -0.0 as equal to 0.0. 683bool StrictNumberEquals(double x, double y) { 684 // Must check explicitly for NaN's on Windows, but -0 works fine. 685 if (std::isnan(x) || std::isnan(y)) return false; 686 return x == y; 687} 688 689bool StrictNumberEquals(const Object x, const Object y) { 690 return StrictNumberEquals(x.Number(), y.Number()); 691} 692 693bool StrictNumberEquals(Handle<Object> x, Handle<Object> y) { 694 return StrictNumberEquals(*x, *y); 695} 696 697ComparisonResult Reverse(ComparisonResult result) { 698 if (result == ComparisonResult::kLessThan) { 699 return ComparisonResult::kGreaterThan; 700 } 701 if (result == ComparisonResult::kGreaterThan) { 702 return ComparisonResult::kLessThan; 703 } 704 return result; 705} 706 707} // anonymous namespace 708 709// static 710Maybe<ComparisonResult> Object::Compare(Isolate* isolate, Handle<Object> x, 711 Handle<Object> y) { 712 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4. 713 if (!Object::ToPrimitive(isolate, x, ToPrimitiveHint::kNumber).ToHandle(&x) || 714 !Object::ToPrimitive(isolate, y, ToPrimitiveHint::kNumber).ToHandle(&y)) { 715 return Nothing<ComparisonResult>(); 716 } 717 if (x->IsString() && y->IsString()) { 718 // ES6 section 7.2.11 Abstract Relational Comparison step 5. 719 return Just(String::Compare(isolate, Handle<String>::cast(x), 720 Handle<String>::cast(y))); 721 } 722 if (x->IsBigInt() && y->IsString()) { 723 return BigInt::CompareToString(isolate, Handle<BigInt>::cast(x), 724 Handle<String>::cast(y)); 725 } 726 if (x->IsString() && y->IsBigInt()) { 727 Maybe<ComparisonResult> maybe_result = BigInt::CompareToString( 728 isolate, Handle<BigInt>::cast(y), Handle<String>::cast(x)); 729 ComparisonResult result; 730 if (maybe_result.To(&result)) { 731 return Just(Reverse(result)); 732 } else { 733 return Nothing<ComparisonResult>(); 734 } 735 } 736 // ES6 section 7.2.11 Abstract Relational Comparison step 6. 737 if (!Object::ToNumeric(isolate, x).ToHandle(&x) || 738 !Object::ToNumeric(isolate, y).ToHandle(&y)) { 739 return Nothing<ComparisonResult>(); 740 } 741 742 bool x_is_number = x->IsNumber(); 743 bool y_is_number = y->IsNumber(); 744 if (x_is_number && y_is_number) { 745 return Just(StrictNumberCompare(x->Number(), y->Number())); 746 } else if (!x_is_number && !y_is_number) { 747 return Just(BigInt::CompareToBigInt(Handle<BigInt>::cast(x), 748 Handle<BigInt>::cast(y))); 749 } else if (x_is_number) { 750 return Just(Reverse(BigInt::CompareToNumber(Handle<BigInt>::cast(y), x))); 751 } else { 752 return Just(BigInt::CompareToNumber(Handle<BigInt>::cast(x), y)); 753 } 754} 755 756// static 757Maybe<bool> Object::Equals(Isolate* isolate, Handle<Object> x, 758 Handle<Object> y) { 759 // This is the generic version of Abstract Equality Comparison. Must be in 760 // sync with CodeStubAssembler::Equal. 761 while (true) { 762 if (x->IsNumber()) { 763 if (y->IsNumber()) { 764 return Just(StrictNumberEquals(x, y)); 765 } else if (y->IsBoolean()) { 766 return Just( 767 StrictNumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); 768 } else if (y->IsString()) { 769 return Just(StrictNumberEquals( 770 x, String::ToNumber(isolate, Handle<String>::cast(y)))); 771 } else if (y->IsBigInt()) { 772 return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x)); 773 } else if (y->IsJSReceiver()) { 774 if (!JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(y)) 775 .ToHandle(&y)) { 776 return Nothing<bool>(); 777 } 778 } else { 779 return Just(false); 780 } 781 } else if (x->IsString()) { 782 if (y->IsString()) { 783 return Just(String::Equals(isolate, Handle<String>::cast(x), 784 Handle<String>::cast(y))); 785 } else if (y->IsNumber()) { 786 x = String::ToNumber(isolate, Handle<String>::cast(x)); 787 return Just(StrictNumberEquals(x, y)); 788 } else if (y->IsBoolean()) { 789 x = String::ToNumber(isolate, Handle<String>::cast(x)); 790 return Just( 791 StrictNumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); 792 } else if (y->IsBigInt()) { 793 return BigInt::EqualToString(isolate, Handle<BigInt>::cast(y), 794 Handle<String>::cast(x)); 795 } else if (y->IsJSReceiver()) { 796 if (!JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(y)) 797 .ToHandle(&y)) { 798 return Nothing<bool>(); 799 } 800 } else { 801 return Just(false); 802 } 803 } else if (x->IsBoolean()) { 804 if (y->IsOddball()) { 805 return Just(x.is_identical_to(y)); 806 } else if (y->IsNumber()) { 807 return Just( 808 StrictNumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); 809 } else if (y->IsString()) { 810 y = String::ToNumber(isolate, Handle<String>::cast(y)); 811 return Just( 812 StrictNumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); 813 } else if (y->IsBigInt()) { 814 x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x)); 815 return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x)); 816 } else if (y->IsJSReceiver()) { 817 if (!JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(y)) 818 .ToHandle(&y)) { 819 return Nothing<bool>(); 820 } 821 x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x)); 822 } else { 823 return Just(false); 824 } 825 } else if (x->IsSymbol()) { 826 if (y->IsSymbol()) { 827 return Just(x.is_identical_to(y)); 828 } else if (y->IsJSReceiver()) { 829 if (!JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(y)) 830 .ToHandle(&y)) { 831 return Nothing<bool>(); 832 } 833 } else { 834 return Just(false); 835 } 836 } else if (x->IsBigInt()) { 837 if (y->IsBigInt()) { 838 return Just(BigInt::EqualToBigInt(BigInt::cast(*x), BigInt::cast(*y))); 839 } 840 return Equals(isolate, y, x); 841 } else if (x->IsJSReceiver()) { 842 if (y->IsJSReceiver()) { 843 return Just(x.is_identical_to(y)); 844 } else if (y->IsUndetectable()) { 845 return Just(x->IsUndetectable()); 846 } else if (y->IsBoolean()) { 847 y = Oddball::ToNumber(isolate, Handle<Oddball>::cast(y)); 848 } else if (!JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(x)) 849 .ToHandle(&x)) { 850 return Nothing<bool>(); 851 } 852 } else { 853 return Just(x->IsUndetectable() && y->IsUndetectable()); 854 } 855 } 856} 857 858bool Object::StrictEquals(Object that) { 859 if (this->IsNumber()) { 860 if (!that.IsNumber()) return false; 861 return StrictNumberEquals(*this, that); 862 } else if (this->IsString()) { 863 if (!that.IsString()) return false; 864 return String::cast(*this).Equals(String::cast(that)); 865 } else if (this->IsBigInt()) { 866 if (!that.IsBigInt()) return false; 867 return BigInt::EqualToBigInt(BigInt::cast(*this), BigInt::cast(that)); 868 } 869 return *this == that; 870} 871 872// static 873Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) { 874 if (object->IsNumber()) return isolate->factory()->number_string(); 875 if (object->IsOddball()) 876 return handle(Oddball::cast(*object).type_of(), isolate); 877 if (object->IsUndetectable()) { 878 return isolate->factory()->undefined_string(); 879 } 880 if (object->IsString()) return isolate->factory()->string_string(); 881 if (object->IsSymbol()) return isolate->factory()->symbol_string(); 882 if (object->IsBigInt()) return isolate->factory()->bigint_string(); 883 if (object->IsCallable()) return isolate->factory()->function_string(); 884 return isolate->factory()->object_string(); 885} 886 887// static 888MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs, 889 Handle<Object> rhs) { 890 if (lhs->IsNumber() && rhs->IsNumber()) { 891 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); 892 } else if (lhs->IsString() && rhs->IsString()) { 893 return isolate->factory()->NewConsString(Handle<String>::cast(lhs), 894 Handle<String>::cast(rhs)); 895 } 896 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(isolate, lhs), 897 Object); 898 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(isolate, rhs), 899 Object); 900 if (lhs->IsString() || rhs->IsString()) { 901 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs), 902 Object); 903 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs), 904 Object); 905 return isolate->factory()->NewConsString(Handle<String>::cast(lhs), 906 Handle<String>::cast(rhs)); 907 } 908 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(isolate, rhs), 909 Object); 910 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(isolate, lhs), 911 Object); 912 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); 913} 914 915// static 916MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate, 917 Handle<Object> callable, 918 Handle<Object> object) { 919 // The {callable} must have a [[Call]] internal method. 920 if (!callable->IsCallable()) return isolate->factory()->false_value(); 921 922 // Check if {callable} is a bound function, and if so retrieve its 923 // [[BoundTargetFunction]] and use that instead of {callable}. 924 if (callable->IsJSBoundFunction()) { 925 // Since there is a mutual recursion here, we might run out of stack 926 // space for long chains of bound functions. 927 STACK_CHECK(isolate, MaybeHandle<Object>()); 928 Handle<Object> bound_callable( 929 Handle<JSBoundFunction>::cast(callable)->bound_target_function(), 930 isolate); 931 return Object::InstanceOf(isolate, object, bound_callable); 932 } 933 934 // If {object} is not a receiver, return false. 935 if (!object->IsJSReceiver()) return isolate->factory()->false_value(); 936 937 // Get the "prototype" of {callable}; raise an error if it's not a receiver. 938 Handle<Object> prototype; 939 ASSIGN_RETURN_ON_EXCEPTION( 940 isolate, prototype, 941 Object::GetProperty(isolate, callable, 942 isolate->factory()->prototype_string()), 943 Object); 944 if (!prototype->IsJSReceiver()) { 945 THROW_NEW_ERROR( 946 isolate, 947 NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype), 948 Object); 949 } 950 951 // Return whether or not {prototype} is in the prototype chain of {object}. 952 Maybe<bool> result = JSReceiver::HasInPrototypeChain( 953 isolate, Handle<JSReceiver>::cast(object), prototype); 954 if (result.IsNothing()) return MaybeHandle<Object>(); 955 return isolate->factory()->ToBoolean(result.FromJust()); 956} 957 958// static 959MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object, 960 Handle<Object> callable) { 961 // The {callable} must be a receiver. 962 if (!callable->IsJSReceiver()) { 963 THROW_NEW_ERROR(isolate, 964 NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck), 965 Object); 966 } 967 968 // Lookup the @@hasInstance method on {callable}. 969 Handle<Object> inst_of_handler; 970 ASSIGN_RETURN_ON_EXCEPTION( 971 isolate, inst_of_handler, 972 Object::GetMethod(Handle<JSReceiver>::cast(callable), 973 isolate->factory()->has_instance_symbol()), 974 Object); 975 if (!inst_of_handler->IsUndefined(isolate)) { 976 // Call the {inst_of_handler} on the {callable}. 977 Handle<Object> result; 978 ASSIGN_RETURN_ON_EXCEPTION( 979 isolate, result, 980 Execution::Call(isolate, inst_of_handler, callable, 1, &object), 981 Object); 982 return isolate->factory()->ToBoolean(result->BooleanValue(isolate)); 983 } 984 985 // The {callable} must have a [[Call]] internal method. 986 if (!callable->IsCallable()) { 987 THROW_NEW_ERROR( 988 isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck), 989 Object); 990 } 991 992 // Fall back to OrdinaryHasInstance with {callable} and {object}. 993 Handle<Object> result; 994 ASSIGN_RETURN_ON_EXCEPTION( 995 isolate, result, Object::OrdinaryHasInstance(isolate, callable, object), 996 Object); 997 return result; 998} 999 1000// static 1001MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver, 1002 Handle<Name> name) { 1003 Handle<Object> func; 1004 Isolate* isolate = receiver->GetIsolate(); 1005 ASSIGN_RETURN_ON_EXCEPTION( 1006 isolate, func, JSReceiver::GetProperty(isolate, receiver, name), Object); 1007 if (func->IsNullOrUndefined(isolate)) { 1008 return isolate->factory()->undefined_value(); 1009 } 1010 if (!func->IsCallable()) { 1011 THROW_NEW_ERROR(isolate, 1012 NewTypeError(MessageTemplate::kPropertyNotFunction, func, 1013 name, receiver), 1014 Object); 1015 } 1016 return func; 1017} 1018 1019namespace { 1020 1021MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath( 1022 Isolate* isolate, Handle<Object> object, ElementTypes element_types) { 1023 if (element_types == ElementTypes::kAll) { 1024 if (object->IsJSArray()) { 1025 Handle<JSArray> array = Handle<JSArray>::cast(object); 1026 uint32_t length; 1027 if (!array->HasArrayPrototype(isolate) || 1028 !array->length().ToUint32(&length) || !array->HasFastElements() || 1029 !JSObject::PrototypeHasNoElements(isolate, *array)) { 1030 return MaybeHandle<FixedArray>(); 1031 } 1032 return array->GetElementsAccessor()->CreateListFromArrayLike( 1033 isolate, array, length); 1034 } else if (object->IsJSTypedArray()) { 1035 Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(object); 1036 size_t length = array->length(); 1037 if (array->WasDetached() || 1038 length > static_cast<size_t>(FixedArray::kMaxLength)) { 1039 return MaybeHandle<FixedArray>(); 1040 } 1041 STATIC_ASSERT(FixedArray::kMaxLength <= 1042 std::numeric_limits<uint32_t>::max()); 1043 return array->GetElementsAccessor()->CreateListFromArrayLike( 1044 isolate, array, static_cast<uint32_t>(length)); 1045 } 1046 } 1047 return MaybeHandle<FixedArray>(); 1048} 1049 1050} // namespace 1051 1052// static 1053MaybeHandle<FixedArray> Object::CreateListFromArrayLike( 1054 Isolate* isolate, Handle<Object> object, ElementTypes element_types) { 1055 // Fast-path for JSArray and JSTypedArray. 1056 MaybeHandle<FixedArray> fast_result = 1057 CreateListFromArrayLikeFastPath(isolate, object, element_types); 1058 if (!fast_result.is_null()) return fast_result; 1059 // 1. ReturnIfAbrupt(object). 1060 // 2. (default elementTypes -- not applicable.) 1061 // 3. If Type(obj) is not Object, throw a TypeError exception. 1062 if (!object->IsJSReceiver()) { 1063 THROW_NEW_ERROR(isolate, 1064 NewTypeError(MessageTemplate::kCalledOnNonObject, 1065 isolate->factory()->NewStringFromAsciiChecked( 1066 "CreateListFromArrayLike")), 1067 FixedArray); 1068 } 1069 1070 // 4. Let len be ? ToLength(? Get(obj, "length")). 1071 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); 1072 Handle<Object> raw_length_number; 1073 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number, 1074 Object::GetLengthFromArrayLike(isolate, receiver), 1075 FixedArray); 1076 uint32_t len; 1077 if (!raw_length_number->ToUint32(&len) || 1078 len > static_cast<uint32_t>(FixedArray::kMaxLength)) { 1079 THROW_NEW_ERROR(isolate, 1080 NewRangeError(MessageTemplate::kInvalidArrayLength), 1081 FixedArray); 1082 } 1083 // 5. Let list be an empty List. 1084 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len); 1085 // 6. Let index be 0. 1086 // 7. Repeat while index < len: 1087 for (uint32_t index = 0; index < len; ++index) { 1088 // 7a. Let indexName be ToString(index). 1089 // 7b. Let next be ? Get(obj, indexName). 1090 Handle<Object> next; 1091 ASSIGN_RETURN_ON_EXCEPTION(isolate, next, 1092 JSReceiver::GetElement(isolate, receiver, index), 1093 FixedArray); 1094 switch (element_types) { 1095 case ElementTypes::kAll: 1096 // Nothing to do. 1097 break; 1098 case ElementTypes::kStringAndSymbol: { 1099 // 7c. If Type(next) is not an element of elementTypes, throw a 1100 // TypeError exception. 1101 if (!next->IsName()) { 1102 THROW_NEW_ERROR(isolate, 1103 NewTypeError(MessageTemplate::kNotPropertyName, next), 1104 FixedArray); 1105 } 1106 // 7d. Append next as the last element of list. 1107 // Internalize on the fly so we can use pointer identity later. 1108 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next)); 1109 break; 1110 } 1111 } 1112 list->set(index, *next); 1113 // 7e. Set index to index + 1. (See loop header.) 1114 } 1115 // 8. Return list. 1116 return list; 1117} 1118 1119// static 1120MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate, 1121 Handle<JSReceiver> object) { 1122 Handle<Object> val; 1123 Handle<Name> key = isolate->factory()->length_string(); 1124 ASSIGN_RETURN_ON_EXCEPTION( 1125 isolate, val, JSReceiver::GetProperty(isolate, object, key), Object); 1126 return Object::ToLength(isolate, val); 1127} 1128 1129// static 1130MaybeHandle<Object> Object::GetProperty(LookupIterator* it, 1131 bool is_global_reference) { 1132 for (; it->IsFound(); it->Next()) { 1133 switch (it->state()) { 1134 case LookupIterator::NOT_FOUND: 1135 case LookupIterator::TRANSITION: 1136 UNREACHABLE(); 1137 case LookupIterator::JSPROXY: { 1138 bool was_found; 1139 Handle<Object> receiver = it->GetReceiver(); 1140 // In case of global IC, the receiver is the global object. Replace by 1141 // the global proxy. 1142 if (receiver->IsJSGlobalObject()) { 1143 receiver = handle(JSGlobalObject::cast(*receiver).global_proxy(), 1144 it->isolate()); 1145 } 1146 if (is_global_reference) { 1147 Maybe<bool> maybe = JSProxy::HasProperty( 1148 it->isolate(), it->GetHolder<JSProxy>(), it->GetName()); 1149 if (maybe.IsNothing()) return MaybeHandle<Object>(); 1150 if (!maybe.FromJust()) { 1151 it->NotFound(); 1152 return it->isolate()->factory()->undefined_value(); 1153 } 1154 } 1155 MaybeHandle<Object> result = 1156 JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(), 1157 it->GetName(), receiver, &was_found); 1158 if (!was_found && !is_global_reference) it->NotFound(); 1159 return result; 1160 } 1161 case LookupIterator::INTERCEPTOR: { 1162 bool done; 1163 Handle<Object> result; 1164 ASSIGN_RETURN_ON_EXCEPTION( 1165 it->isolate(), result, 1166 JSObject::GetPropertyWithInterceptor(it, &done), Object); 1167 if (done) return result; 1168 break; 1169 } 1170 case LookupIterator::ACCESS_CHECK: 1171 if (it->HasAccess()) break; 1172 return JSObject::GetPropertyWithFailedAccessCheck(it); 1173 case LookupIterator::ACCESSOR: 1174 return GetPropertyWithAccessor(it); 1175 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1176 return it->isolate()->factory()->undefined_value(); 1177 case LookupIterator::DATA: 1178 return it->GetDataValue(); 1179 } 1180 } 1181 1182 return it->isolate()->factory()->undefined_value(); 1183} 1184 1185// static 1186MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate, 1187 Handle<JSProxy> proxy, 1188 Handle<Name> name, 1189 Handle<Object> receiver, 1190 bool* was_found) { 1191 *was_found = true; 1192 1193 DCHECK(!name->IsPrivate()); 1194 STACK_CHECK(isolate, MaybeHandle<Object>()); 1195 Handle<Name> trap_name = isolate->factory()->get_string(); 1196 // 1. Assert: IsPropertyKey(P) is true. 1197 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 1198 Handle<Object> handler(proxy->handler(), isolate); 1199 // 3. If handler is null, throw a TypeError exception. 1200 // 4. Assert: Type(handler) is Object. 1201 if (proxy->IsRevoked()) { 1202 THROW_NEW_ERROR(isolate, 1203 NewTypeError(MessageTemplate::kProxyRevoked, trap_name), 1204 Object); 1205 } 1206 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 1207 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 1208 // 6. Let trap be ? GetMethod(handler, "get"). 1209 Handle<Object> trap; 1210 ASSIGN_RETURN_ON_EXCEPTION( 1211 isolate, trap, 1212 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object); 1213 // 7. If trap is undefined, then 1214 if (trap->IsUndefined(isolate)) { 1215 // 7.a Return target.[[Get]](P, Receiver). 1216 PropertyKey key(isolate, name); 1217 LookupIterator it(isolate, receiver, key, target); 1218 MaybeHandle<Object> result = Object::GetProperty(&it); 1219 *was_found = it.IsFound(); 1220 return result; 1221 } 1222 // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»). 1223 Handle<Object> trap_result; 1224 Handle<Object> args[] = {target, name, receiver}; 1225 ASSIGN_RETURN_ON_EXCEPTION( 1226 isolate, trap_result, 1227 Execution::Call(isolate, trap, handler, arraysize(args), args), Object); 1228 1229 MaybeHandle<Object> result = 1230 JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet); 1231 if (result.is_null()) { 1232 return result; 1233 } 1234 1235 // 11. Return trap_result 1236 return trap_result; 1237} 1238 1239// static 1240MaybeHandle<Object> JSProxy::CheckGetSetTrapResult(Isolate* isolate, 1241 Handle<Name> name, 1242 Handle<JSReceiver> target, 1243 Handle<Object> trap_result, 1244 AccessKind access_kind) { 1245 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P). 1246 PropertyDescriptor target_desc; 1247 Maybe<bool> target_found = 1248 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 1249 MAYBE_RETURN_NULL(target_found); 1250 // 10. If targetDesc is not undefined, then 1251 if (target_found.FromJust()) { 1252 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is 1253 // false and targetDesc.[[Writable]] is false, then 1254 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false, 1255 // throw a TypeError exception. 1256 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) && 1257 !target_desc.configurable() && 1258 !target_desc.writable() && 1259 !trap_result->SameValue(*target_desc.value()); 1260 if (inconsistent) { 1261 if (access_kind == kGet) { 1262 THROW_NEW_ERROR( 1263 isolate, 1264 NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name, 1265 target_desc.value(), trap_result), 1266 Object); 1267 } else { 1268 isolate->Throw(*isolate->factory()->NewTypeError( 1269 MessageTemplate::kProxySetFrozenData, name)); 1270 return MaybeHandle<Object>(); 1271 } 1272 } 1273 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]] 1274 // is false and targetDesc.[[Get]] is undefined, then 1275 // 10.b.i. If trapResult is not undefined, throw a TypeError exception. 1276 if (access_kind == kGet) { 1277 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && 1278 !target_desc.configurable() && 1279 target_desc.get()->IsUndefined(isolate) && 1280 !trap_result->IsUndefined(isolate); 1281 } else { 1282 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && 1283 !target_desc.configurable() && 1284 target_desc.set()->IsUndefined(isolate); 1285 } 1286 if (inconsistent) { 1287 if (access_kind == kGet) { 1288 THROW_NEW_ERROR( 1289 isolate, 1290 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, 1291 name, trap_result), 1292 Object); 1293 } else { 1294 isolate->Throw(*isolate->factory()->NewTypeError( 1295 MessageTemplate::kProxySetFrozenAccessor, name)); 1296 return MaybeHandle<Object>(); 1297 } 1298 } 1299 } 1300 return isolate->factory()->undefined_value(); 1301} 1302 1303bool Object::ToInt32(int32_t* value) { 1304 if (IsSmi()) { 1305 *value = Smi::ToInt(*this); 1306 return true; 1307 } 1308 if (IsHeapNumber()) { 1309 double num = HeapNumber::cast(*this).value(); 1310 // Check range before conversion to avoid undefined behavior. 1311 if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) { 1312 *value = FastD2I(num); 1313 return true; 1314 } 1315 } 1316 return false; 1317} 1318 1319// static 1320Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) { 1321 Handle<FixedArray> list = 1322 isolate->factory()->NewFixedArray(kLengthIndex + size); 1323 list->set(kLengthIndex, Smi::zero()); 1324 return Handle<TemplateList>::cast(list); 1325} 1326 1327// static 1328Handle<TemplateList> TemplateList::Add(Isolate* isolate, 1329 Handle<TemplateList> list, 1330 Handle<i::Object> value) { 1331 STATIC_ASSERT(kFirstElementIndex == 1); 1332 int index = list->length() + 1; 1333 Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list); 1334 fixed_array = FixedArray::SetAndGrow(isolate, fixed_array, index, value); 1335 fixed_array->set(kLengthIndex, Smi::FromInt(index)); 1336 return Handle<TemplateList>::cast(fixed_array); 1337} 1338 1339// ES6 9.5.1 1340// static 1341MaybeHandle<HeapObject> JSProxy::GetPrototype(Handle<JSProxy> proxy) { 1342 Isolate* isolate = proxy->GetIsolate(); 1343 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string(); 1344 1345 STACK_CHECK(isolate, MaybeHandle<HeapObject>()); 1346 1347 // 1. Let handler be the value of the [[ProxyHandler]] internal slot. 1348 // 2. If handler is null, throw a TypeError exception. 1349 // 3. Assert: Type(handler) is Object. 1350 // 4. Let target be the value of the [[ProxyTarget]] internal slot. 1351 if (proxy->IsRevoked()) { 1352 THROW_NEW_ERROR(isolate, 1353 NewTypeError(MessageTemplate::kProxyRevoked, trap_name), 1354 HeapObject); 1355 } 1356 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 1357 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 1358 1359 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). 1360 Handle<Object> trap; 1361 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, 1362 Object::GetMethod(handler, trap_name), HeapObject); 1363 // 6. If trap is undefined, then return target.[[GetPrototypeOf]](). 1364 if (trap->IsUndefined(isolate)) { 1365 return JSReceiver::GetPrototype(isolate, target); 1366 } 1367 // 7. Let handlerProto be ? Call(trap, handler, «target»). 1368 Handle<Object> argv[] = {target}; 1369 Handle<Object> handler_proto; 1370 ASSIGN_RETURN_ON_EXCEPTION( 1371 isolate, handler_proto, 1372 Execution::Call(isolate, trap, handler, arraysize(argv), argv), 1373 HeapObject); 1374 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError. 1375 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) { 1376 THROW_NEW_ERROR(isolate, 1377 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid), 1378 HeapObject); 1379 } 1380 // 9. Let extensibleTarget be ? IsExtensible(target). 1381 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target); 1382 MAYBE_RETURN(is_extensible, MaybeHandle<HeapObject>()); 1383 // 10. If extensibleTarget is true, return handlerProto. 1384 if (is_extensible.FromJust()) return Handle<HeapObject>::cast(handler_proto); 1385 // 11. Let targetProto be ? target.[[GetPrototypeOf]](). 1386 Handle<HeapObject> target_proto; 1387 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto, 1388 JSReceiver::GetPrototype(isolate, target), 1389 HeapObject); 1390 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError. 1391 if (!handler_proto->SameValue(*target_proto)) { 1392 THROW_NEW_ERROR( 1393 isolate, 1394 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible), 1395 HeapObject); 1396 } 1397 // 13. Return handlerProto. 1398 return Handle<HeapObject>::cast(handler_proto); 1399} 1400 1401MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) { 1402 Isolate* isolate = it->isolate(); 1403 Handle<Object> structure = it->GetAccessors(); 1404 Handle<Object> receiver = it->GetReceiver(); 1405 // In case of global IC, the receiver is the global object. Replace by the 1406 // global proxy. 1407 if (receiver->IsJSGlobalObject()) { 1408 receiver = handle(JSGlobalObject::cast(*receiver).global_proxy(), isolate); 1409 } 1410 1411 // We should never get here to initialize a const with the hole value since a 1412 // const declaration would conflict with the getter. 1413 DCHECK(!structure->IsForeign()); 1414 1415 // API style callbacks. 1416 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1417 if (structure->IsAccessorInfo()) { 1418 Handle<Name> name = it->GetName(); 1419 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); 1420 if (!info->IsCompatibleReceiver(*receiver)) { 1421 THROW_NEW_ERROR(isolate, 1422 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, 1423 name, receiver), 1424 Object); 1425 } 1426 1427 if (!info->has_getter()) return isolate->factory()->undefined_value(); 1428 1429 if (info->is_sloppy() && !receiver->IsJSReceiver()) { 1430 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver, 1431 Object::ConvertReceiver(isolate, receiver), 1432 Object); 1433 } 1434 1435 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, 1436 Just(kDontThrow)); 1437 Handle<Object> result = args.CallAccessorGetter(info, name); 1438 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1439 if (result.is_null()) return isolate->factory()->undefined_value(); 1440 Handle<Object> reboxed_result = handle(*result, isolate); 1441 if (info->replace_on_access() && receiver->IsJSReceiver()) { 1442 RETURN_ON_EXCEPTION(isolate, 1443 Accessors::ReplaceAccessorWithDataProperty( 1444 isolate, receiver, holder, name, result), 1445 Object); 1446 } 1447 return reboxed_result; 1448 } 1449 1450 Handle<AccessorPair> accessor_pair = Handle<AccessorPair>::cast(structure); 1451 // AccessorPair with 'cached' private property. 1452 if (it->TryLookupCachedProperty(accessor_pair)) { 1453 return Object::GetProperty(it); 1454 } 1455 1456 // Regular accessor. 1457 Handle<Object> getter(accessor_pair->getter(), isolate); 1458 if (getter->IsFunctionTemplateInfo()) { 1459 SaveAndSwitchContext save(isolate, 1460 *holder->GetCreationContext().ToHandleChecked()); 1461 return Builtins::InvokeApiFunction( 1462 isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0, 1463 nullptr, isolate->factory()->undefined_value()); 1464 } else if (getter->IsCallable()) { 1465 // TODO(rossberg): nicer would be to cast to some JSCallable here... 1466 return Object::GetPropertyWithDefinedGetter( 1467 receiver, Handle<JSReceiver>::cast(getter)); 1468 } 1469 // Getter is not a function. 1470 return isolate->factory()->undefined_value(); 1471} 1472 1473// static 1474Address AccessorInfo::redirect(Address address, AccessorComponent component) { 1475 ApiFunction fun(address); 1476 DCHECK_EQ(ACCESSOR_GETTER, component); 1477 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; 1478 return ExternalReference::Create(&fun, type).address(); 1479} 1480 1481Address AccessorInfo::redirected_getter() const { 1482 Address accessor = v8::ToCData<Address>(getter()); 1483 if (accessor == kNullAddress) return kNullAddress; 1484 return redirect(accessor, ACCESSOR_GETTER); 1485} 1486 1487Address CallHandlerInfo::redirected_callback() const { 1488 Address address = v8::ToCData<Address>(callback()); 1489 ApiFunction fun(address); 1490 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; 1491 return ExternalReference::Create(&fun, type).address(); 1492} 1493 1494bool AccessorInfo::IsCompatibleReceiverMap(Handle<AccessorInfo> info, 1495 Handle<Map> map) { 1496 if (!info->HasExpectedReceiverType()) return true; 1497 if (!map->IsJSObjectMap()) return false; 1498 return FunctionTemplateInfo::cast(info->expected_receiver_type()) 1499 .IsTemplateFor(*map); 1500} 1501 1502Maybe<bool> Object::SetPropertyWithAccessor( 1503 LookupIterator* it, Handle<Object> value, 1504 Maybe<ShouldThrow> maybe_should_throw) { 1505 Isolate* isolate = it->isolate(); 1506 Handle<Object> structure = it->GetAccessors(); 1507 Handle<Object> receiver = it->GetReceiver(); 1508 // In case of global IC, the receiver is the global object. Replace by the 1509 // global proxy. 1510 if (receiver->IsJSGlobalObject()) { 1511 receiver = handle(JSGlobalObject::cast(*receiver).global_proxy(), isolate); 1512 } 1513 1514 // We should never get here to initialize a const with the hole value since a 1515 // const declaration would conflict with the setter. 1516 DCHECK(!structure->IsForeign()); 1517 1518 // API style callbacks. 1519 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1520 if (structure->IsAccessorInfo()) { 1521 Handle<Name> name = it->GetName(); 1522 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); 1523 if (!info->IsCompatibleReceiver(*receiver)) { 1524 isolate->Throw(*isolate->factory()->NewTypeError( 1525 MessageTemplate::kIncompatibleMethodReceiver, name, receiver)); 1526 return Nothing<bool>(); 1527 } 1528 1529 if (!info->has_setter()) { 1530 // TODO(verwaest): We should not get here anymore once all AccessorInfos 1531 // are marked as special_data_property. They cannot both be writable and 1532 // not have a setter. 1533 return Just(true); 1534 } 1535 1536 if (info->is_sloppy() && !receiver->IsJSReceiver()) { 1537 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1538 isolate, receiver, Object::ConvertReceiver(isolate, receiver), 1539 Nothing<bool>()); 1540 } 1541 1542 // The actual type of setter callback is either 1543 // v8::AccessorNameSetterCallback or 1544 // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the 1545 // AccessorInfo was created by the API or internally (see accessors.cc). 1546 // Here we handle both cases using GenericNamedPropertySetterCallback and 1547 // its Call method. 1548 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, 1549 maybe_should_throw); 1550 Handle<Object> result = args.CallAccessorSetter(info, name, value); 1551 // In the case of AccessorNameSetterCallback, we know that the result value 1552 // cannot have been set, so the result of Call will be null. In the case of 1553 // AccessorNameBooleanSetterCallback, the result will either be null 1554 // (signalling an exception) or a boolean Oddball. 1555 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 1556 if (result.is_null()) return Just(true); 1557 DCHECK(result->BooleanValue(isolate) || 1558 GetShouldThrow(isolate, maybe_should_throw) == kDontThrow); 1559 return Just(result->BooleanValue(isolate)); 1560 } 1561 1562 // Regular accessor. 1563 Handle<Object> setter(AccessorPair::cast(*structure).setter(), isolate); 1564 if (setter->IsFunctionTemplateInfo()) { 1565 SaveAndSwitchContext save(isolate, 1566 *holder->GetCreationContext().ToHandleChecked()); 1567 Handle<Object> argv[] = {value}; 1568 RETURN_ON_EXCEPTION_VALUE( 1569 isolate, 1570 Builtins::InvokeApiFunction(isolate, false, 1571 Handle<FunctionTemplateInfo>::cast(setter), 1572 receiver, arraysize(argv), argv, 1573 isolate->factory()->undefined_value()), 1574 Nothing<bool>()); 1575 return Just(true); 1576 } else if (setter->IsCallable()) { 1577 // TODO(rossberg): nicer would be to cast to some JSCallable here... 1578 return SetPropertyWithDefinedSetter( 1579 receiver, Handle<JSReceiver>::cast(setter), value, maybe_should_throw); 1580 } 1581 1582 RETURN_FAILURE(isolate, GetShouldThrow(isolate, maybe_should_throw), 1583 NewTypeError(MessageTemplate::kNoSetterInCallback, 1584 it->GetName(), it->GetHolder<JSObject>())); 1585} 1586 1587MaybeHandle<Object> Object::GetPropertyWithDefinedGetter( 1588 Handle<Object> receiver, Handle<JSReceiver> getter) { 1589 Isolate* isolate = getter->GetIsolate(); 1590 1591 // Platforms with simulators like arm/arm64 expose a funny issue. If the 1592 // simulator has a separate JS stack pointer from the C++ stack pointer, it 1593 // can miss C++ stack overflows in the stack guard at the start of JavaScript 1594 // functions. It would be very expensive to check the C++ stack pointer at 1595 // that location. The best solution seems to be to break the impasse by 1596 // adding checks at possible recursion points. What's more, we don't put 1597 // this stack check behind the USE_SIMULATOR define in order to keep 1598 // behavior the same between hardware and simulators. 1599 StackLimitCheck check(isolate); 1600 if (check.JsHasOverflowed()) { 1601 isolate->StackOverflow(); 1602 return MaybeHandle<Object>(); 1603 } 1604 1605 return Execution::Call(isolate, getter, receiver, 0, nullptr); 1606} 1607 1608Maybe<bool> Object::SetPropertyWithDefinedSetter( 1609 Handle<Object> receiver, Handle<JSReceiver> setter, Handle<Object> value, 1610 Maybe<ShouldThrow> should_throw) { 1611 Isolate* isolate = setter->GetIsolate(); 1612 1613 Handle<Object> argv[] = {value}; 1614 RETURN_ON_EXCEPTION_VALUE( 1615 isolate, 1616 Execution::Call(isolate, setter, receiver, arraysize(argv), argv), 1617 Nothing<bool>()); 1618 return Just(true); 1619} 1620 1621Map Object::GetPrototypeChainRootMap(Isolate* isolate) const { 1622 DisallowGarbageCollection no_alloc; 1623 if (IsSmi()) { 1624 Context native_context = isolate->context().native_context(); 1625 return native_context.number_function().initial_map(); 1626 } 1627 1628 const HeapObject heap_object = HeapObject::cast(*this); 1629 return heap_object.map().GetPrototypeChainRootMap(isolate); 1630} 1631 1632Smi Object::GetOrCreateHash(Isolate* isolate) { 1633 DisallowGarbageCollection no_gc; 1634 Object hash = Object::GetSimpleHash(*this); 1635 if (hash.IsSmi()) return Smi::cast(hash); 1636 1637 DCHECK(IsJSReceiver()); 1638 return JSReceiver::cast(*this).GetOrCreateIdentityHash(isolate); 1639} 1640 1641bool Object::SameValue(Object other) { 1642 if (other == *this) return true; 1643 1644 if (IsNumber() && other.IsNumber()) { 1645 return SameNumberValue(Number(), other.Number()); 1646 } 1647 if (IsString() && other.IsString()) { 1648 return String::cast(*this).Equals(String::cast(other)); 1649 } 1650 if (IsBigInt() && other.IsBigInt()) { 1651 return BigInt::EqualToBigInt(BigInt::cast(*this), BigInt::cast(other)); 1652 } 1653 return false; 1654} 1655 1656bool Object::SameValueZero(Object other) { 1657 if (other == *this) return true; 1658 1659 if (IsNumber() && other.IsNumber()) { 1660 double this_value = Number(); 1661 double other_value = other.Number(); 1662 // +0 == -0 is true 1663 return this_value == other_value || 1664 (std::isnan(this_value) && std::isnan(other_value)); 1665 } 1666 if (IsString() && other.IsString()) { 1667 return String::cast(*this).Equals(String::cast(other)); 1668 } 1669 if (IsBigInt() && other.IsBigInt()) { 1670 return BigInt::EqualToBigInt(BigInt::cast(*this), BigInt::cast(other)); 1671 } 1672 return false; 1673} 1674 1675MaybeHandle<Object> Object::ArraySpeciesConstructor( 1676 Isolate* isolate, Handle<Object> original_array) { 1677 Handle<Object> default_species = isolate->array_function(); 1678 if (!FLAG_builtin_subclassing) return default_species; 1679 if (original_array->IsJSArray() && 1680 Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) && 1681 Protectors::IsArraySpeciesLookupChainIntact(isolate)) { 1682 return default_species; 1683 } 1684 Handle<Object> constructor = isolate->factory()->undefined_value(); 1685 Maybe<bool> is_array = Object::IsArray(original_array); 1686 MAYBE_RETURN_NULL(is_array); 1687 if (is_array.FromJust()) { 1688 ASSIGN_RETURN_ON_EXCEPTION( 1689 isolate, constructor, 1690 Object::GetProperty(isolate, original_array, 1691 isolate->factory()->constructor_string()), 1692 Object); 1693 if (constructor->IsConstructor()) { 1694 Handle<Context> constructor_context; 1695 ASSIGN_RETURN_ON_EXCEPTION( 1696 isolate, constructor_context, 1697 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)), 1698 Object); 1699 if (*constructor_context != *isolate->native_context() && 1700 *constructor == constructor_context->array_function()) { 1701 constructor = isolate->factory()->undefined_value(); 1702 } 1703 } 1704 if (constructor->IsJSReceiver()) { 1705 ASSIGN_RETURN_ON_EXCEPTION( 1706 isolate, constructor, 1707 JSReceiver::GetProperty(isolate, 1708 Handle<JSReceiver>::cast(constructor), 1709 isolate->factory()->species_symbol()), 1710 Object); 1711 if (constructor->IsNull(isolate)) { 1712 constructor = isolate->factory()->undefined_value(); 1713 } 1714 } 1715 } 1716 if (constructor->IsUndefined(isolate)) { 1717 return default_species; 1718 } else { 1719 if (!constructor->IsConstructor()) { 1720 THROW_NEW_ERROR(isolate, 1721 NewTypeError(MessageTemplate::kSpeciesNotConstructor), 1722 Object); 1723 } 1724 return constructor; 1725 } 1726} 1727 1728// ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor ) 1729V8_WARN_UNUSED_RESULT MaybeHandle<Object> Object::SpeciesConstructor( 1730 Isolate* isolate, Handle<JSReceiver> recv, 1731 Handle<JSFunction> default_ctor) { 1732 Handle<Object> ctor_obj; 1733 ASSIGN_RETURN_ON_EXCEPTION( 1734 isolate, ctor_obj, 1735 JSObject::GetProperty(isolate, recv, 1736 isolate->factory()->constructor_string()), 1737 Object); 1738 1739 if (ctor_obj->IsUndefined(isolate)) return default_ctor; 1740 1741 if (!ctor_obj->IsJSReceiver()) { 1742 THROW_NEW_ERROR(isolate, 1743 NewTypeError(MessageTemplate::kConstructorNotReceiver), 1744 Object); 1745 } 1746 1747 Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj); 1748 1749 Handle<Object> species; 1750 ASSIGN_RETURN_ON_EXCEPTION( 1751 isolate, species, 1752 JSObject::GetProperty(isolate, ctor, 1753 isolate->factory()->species_symbol()), 1754 Object); 1755 1756 if (species->IsNullOrUndefined(isolate)) { 1757 return default_ctor; 1758 } 1759 1760 if (species->IsConstructor()) return species; 1761 1762 THROW_NEW_ERROR( 1763 isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object); 1764} 1765 1766bool Object::IterationHasObservableEffects() { 1767 // Check that this object is an array. 1768 if (!IsJSArray()) return true; 1769 JSArray array = JSArray::cast(*this); 1770 Isolate* isolate = array.GetIsolate(); 1771 1772 // Check that we have the original ArrayPrototype. 1773 i::HandleScope handle_scope(isolate); 1774 i::Handle<i::Context> context; 1775 if (!array.GetCreationContext().ToHandle(&context)) return false; 1776 if (!array.map().prototype().IsJSObject()) return true; 1777 JSObject array_proto = JSObject::cast(array.map().prototype()); 1778 auto initial_array_prototype = 1779 context->native_context().initial_array_prototype(); 1780 if (initial_array_prototype != array_proto) return true; 1781 1782 // Check that the ArrayPrototype hasn't been modified in a way that would 1783 // affect iteration. 1784 if (!Protectors::IsArrayIteratorLookupChainIntact(isolate)) return true; 1785 1786 // For FastPacked kinds, iteration will have the same effect as simply 1787 // accessing each property in order. 1788 ElementsKind array_kind = array.GetElementsKind(); 1789 if (IsFastPackedElementsKind(array_kind)) return false; 1790 1791 // For FastHoley kinds, an element access on a hole would cause a lookup on 1792 // the prototype. This could have different results if the prototype has been 1793 // changed. 1794 if (IsHoleyElementsKind(array_kind) && 1795 Protectors::IsNoElementsIntact(isolate)) { 1796 return false; 1797 } 1798 return true; 1799} 1800 1801bool Object::IsCodeLike(Isolate* isolate) const { 1802 DisallowGarbageCollection no_gc; 1803 return IsJSReceiver() && JSReceiver::cast(*this).IsCodeLike(isolate); 1804} 1805 1806void Object::ShortPrint(FILE* out) const { 1807 OFStream os(out); 1808 os << Brief(*this); 1809} 1810 1811void Object::ShortPrint(StringStream* accumulator) const { 1812 std::ostringstream os; 1813 os << Brief(*this); 1814 accumulator->Add(os.str().c_str()); 1815} 1816 1817void Object::ShortPrint(std::ostream& os) const { os << Brief(*this); } 1818 1819std::ostream& operator<<(std::ostream& os, const Object& obj) { 1820 obj.ShortPrint(os); 1821 return os; 1822} 1823 1824std::ostream& operator<<(std::ostream& os, const Brief& v) { 1825 MaybeObject maybe_object(v.value); 1826 Smi smi; 1827 HeapObject heap_object; 1828 if (maybe_object->ToSmi(&smi)) { 1829 smi.SmiPrint(os); 1830 } else if (maybe_object->IsCleared()) { 1831 os << "[cleared]"; 1832 } else if (maybe_object->GetHeapObjectIfWeak(&heap_object)) { 1833 os << "[weak] "; 1834 heap_object.HeapObjectShortPrint(os); 1835 } else if (maybe_object->GetHeapObjectIfStrong(&heap_object)) { 1836 heap_object.HeapObjectShortPrint(os); 1837 } else { 1838 UNREACHABLE(); 1839 } 1840 return os; 1841} 1842 1843void Smi::SmiPrint(std::ostream& os) const { os << value(); } 1844 1845void HeapObject::HeapObjectShortPrint(std::ostream& os) { 1846 PtrComprCageBase cage_base = GetPtrComprCageBaseSlow(*this); 1847 os << AsHex::Address(this->ptr()) << " "; 1848 1849 if (IsString(cage_base)) { 1850 HeapStringAllocator allocator; 1851 StringStream accumulator(&allocator); 1852 String::cast(*this).StringShortPrint(&accumulator); 1853 os << accumulator.ToCString().get(); 1854 return; 1855 } 1856 if (IsJSObject(cage_base)) { 1857 HeapStringAllocator allocator; 1858 StringStream accumulator(&allocator); 1859 JSObject::cast(*this).JSObjectShortPrint(&accumulator); 1860 os << accumulator.ToCString().get(); 1861 return; 1862 } 1863 switch (map(cage_base).instance_type()) { 1864 case MAP_TYPE: { 1865 os << "<Map"; 1866 Map mapInstance = Map::cast(*this); 1867 if (mapInstance.IsJSObjectMap()) { 1868 os << "(" << ElementsKindToString(mapInstance.elements_kind()) << ")"; 1869 } else if (mapInstance.instance_size() != kVariableSizeSentinel) { 1870 os << "[" << mapInstance.instance_size() << "]"; 1871 } 1872 os << ">"; 1873 } break; 1874 case AWAIT_CONTEXT_TYPE: { 1875 os << "<AwaitContext generator= "; 1876 HeapStringAllocator allocator; 1877 StringStream accumulator(&allocator); 1878 Context::cast(*this).extension().ShortPrint(&accumulator); 1879 os << accumulator.ToCString().get(); 1880 os << '>'; 1881 break; 1882 } 1883 case BLOCK_CONTEXT_TYPE: 1884 os << "<BlockContext[" << Context::cast(*this).length() << "]>"; 1885 break; 1886 case CATCH_CONTEXT_TYPE: 1887 os << "<CatchContext[" << Context::cast(*this).length() << "]>"; 1888 break; 1889 case DEBUG_EVALUATE_CONTEXT_TYPE: 1890 os << "<DebugEvaluateContext[" << Context::cast(*this).length() << "]>"; 1891 break; 1892 case EVAL_CONTEXT_TYPE: 1893 os << "<EvalContext[" << Context::cast(*this).length() << "]>"; 1894 break; 1895 case FUNCTION_CONTEXT_TYPE: 1896 os << "<FunctionContext[" << Context::cast(*this).length() << "]>"; 1897 break; 1898 case MODULE_CONTEXT_TYPE: 1899 os << "<ModuleContext[" << Context::cast(*this).length() << "]>"; 1900 break; 1901 case NATIVE_CONTEXT_TYPE: 1902 os << "<NativeContext[" << Context::cast(*this).length() << "]>"; 1903 break; 1904 case SCRIPT_CONTEXT_TYPE: 1905 os << "<ScriptContext[" << Context::cast(*this).length() << "]>"; 1906 break; 1907 case WITH_CONTEXT_TYPE: 1908 os << "<WithContext[" << Context::cast(*this).length() << "]>"; 1909 break; 1910 case SCRIPT_CONTEXT_TABLE_TYPE: 1911 os << "<ScriptContextTable[" << FixedArray::cast(*this).length() << "]>"; 1912 break; 1913 case HASH_TABLE_TYPE: 1914 os << "<HashTable[" << FixedArray::cast(*this).length() << "]>"; 1915 break; 1916 case ORDERED_HASH_MAP_TYPE: 1917 os << "<OrderedHashMap[" << FixedArray::cast(*this).length() << "]>"; 1918 break; 1919 case ORDERED_HASH_SET_TYPE: 1920 os << "<OrderedHashSet[" << FixedArray::cast(*this).length() << "]>"; 1921 break; 1922 case ORDERED_NAME_DICTIONARY_TYPE: 1923 os << "<OrderedNameDictionary[" << FixedArray::cast(*this).length() 1924 << "]>"; 1925 break; 1926 case NAME_DICTIONARY_TYPE: 1927 os << "<NameDictionary[" << FixedArray::cast(*this).length() << "]>"; 1928 break; 1929 case SWISS_NAME_DICTIONARY_TYPE: 1930 os << "<SwissNameDictionary[" 1931 << SwissNameDictionary::cast(*this).Capacity() << "]>"; 1932 break; 1933 case GLOBAL_DICTIONARY_TYPE: 1934 os << "<GlobalDictionary[" << FixedArray::cast(*this).length() << "]>"; 1935 break; 1936 case NUMBER_DICTIONARY_TYPE: 1937 os << "<NumberDictionary[" << FixedArray::cast(*this).length() << "]>"; 1938 break; 1939 case SIMPLE_NUMBER_DICTIONARY_TYPE: 1940 os << "<SimpleNumberDictionary[" << FixedArray::cast(*this).length() 1941 << "]>"; 1942 break; 1943 case FIXED_ARRAY_TYPE: 1944 os << "<FixedArray[" << FixedArray::cast(*this).length() << "]>"; 1945 break; 1946 case OBJECT_BOILERPLATE_DESCRIPTION_TYPE: 1947 os << "<ObjectBoilerplateDescription[" << FixedArray::cast(*this).length() 1948 << "]>"; 1949 break; 1950 case FIXED_DOUBLE_ARRAY_TYPE: 1951 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(*this).length() 1952 << "]>"; 1953 break; 1954 case BYTE_ARRAY_TYPE: 1955 os << "<ByteArray[" << ByteArray::cast(*this).length() << "]>"; 1956 break; 1957 case BYTECODE_ARRAY_TYPE: 1958 os << "<BytecodeArray[" << BytecodeArray::cast(*this).length() << "]>"; 1959 break; 1960 case DESCRIPTOR_ARRAY_TYPE: 1961 os << "<DescriptorArray[" 1962 << DescriptorArray::cast(*this).number_of_descriptors() << "]>"; 1963 break; 1964 case TRANSITION_ARRAY_TYPE: 1965 os << "<TransitionArray[" << TransitionArray::cast(*this).length() 1966 << "]>"; 1967 break; 1968 case PROPERTY_ARRAY_TYPE: 1969 os << "<PropertyArray[" << PropertyArray::cast(*this).length() << "]>"; 1970 break; 1971 case FEEDBACK_CELL_TYPE: { 1972 { 1973 ReadOnlyRoots roots = GetReadOnlyRoots(); 1974 os << "<FeedbackCell["; 1975 if (map() == roots.no_closures_cell_map()) { 1976 os << "no feedback"; 1977 } else if (map() == roots.one_closure_cell_map()) { 1978 os << "one closure"; 1979 } else if (map() == roots.many_closures_cell_map()) { 1980 os << "many closures"; 1981 } else { 1982 os << "!!!INVALID MAP!!!"; 1983 } 1984 os << "]>"; 1985 } 1986 break; 1987 } 1988 case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE: 1989 os << "<ClosureFeedbackCellArray[" 1990 << ClosureFeedbackCellArray::cast(*this).length() << "]>"; 1991 break; 1992 case FEEDBACK_VECTOR_TYPE: 1993 os << "<FeedbackVector[" << FeedbackVector::cast(*this).length() << "]>"; 1994 break; 1995 case FREE_SPACE_TYPE: 1996 os << "<FreeSpace[" << FreeSpace::cast(*this).size(kRelaxedLoad) << "]>"; 1997 break; 1998 1999 case PREPARSE_DATA_TYPE: { 2000 PreparseData data = PreparseData::cast(*this); 2001 os << "<PreparseData[data=" << data.data_length() 2002 << " children=" << data.children_length() << "]>"; 2003 break; 2004 } 2005 2006 case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE: { 2007 UncompiledDataWithoutPreparseData data = 2008 UncompiledDataWithoutPreparseData::cast(*this); 2009 os << "<UncompiledDataWithoutPreparseData (" << data.start_position() 2010 << ", " << data.end_position() << ")]>"; 2011 break; 2012 } 2013 2014 case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE: { 2015 UncompiledDataWithPreparseData data = 2016 UncompiledDataWithPreparseData::cast(*this); 2017 os << "<UncompiledDataWithPreparseData (" << data.start_position() << ", " 2018 << data.end_position() << ") preparsed=" << Brief(data.preparse_data()) 2019 << ">"; 2020 break; 2021 } 2022 2023 case SHARED_FUNCTION_INFO_TYPE: { 2024 SharedFunctionInfo shared = SharedFunctionInfo::cast(*this); 2025 std::unique_ptr<char[]> debug_name = shared.DebugNameCStr(); 2026 if (debug_name[0] != '\0') { 2027 os << "<SharedFunctionInfo " << debug_name.get() << ">"; 2028 } else { 2029 os << "<SharedFunctionInfo>"; 2030 } 2031 break; 2032 } 2033 case JS_MESSAGE_OBJECT_TYPE: 2034 os << "<JSMessageObject>"; 2035 break; 2036#define MAKE_STRUCT_CASE(TYPE, Name, name) \ 2037 case TYPE: \ 2038 os << "<" #Name; \ 2039 Name::cast(*this).BriefPrintDetails(os); \ 2040 os << ">"; \ 2041 break; 2042 STRUCT_LIST(MAKE_STRUCT_CASE) 2043#undef MAKE_STRUCT_CASE 2044 case ALLOCATION_SITE_TYPE: { 2045 os << "<AllocationSite"; 2046 AllocationSite::cast(*this).BriefPrintDetails(os); 2047 os << ">"; 2048 break; 2049 } 2050 case SCOPE_INFO_TYPE: { 2051 ScopeInfo scope = ScopeInfo::cast(*this); 2052 os << "<ScopeInfo"; 2053 if (!scope.IsEmpty()) os << " " << scope.scope_type(); 2054 os << ">"; 2055 break; 2056 } 2057 case CODE_TYPE: { 2058 Code code = Code::cast(*this); 2059 os << "<Code " << CodeKindToString(code.kind()); 2060 if (code.is_builtin()) { 2061 os << " " << Builtins::name(code.builtin_id()); 2062 } 2063 os << ">"; 2064 break; 2065 } 2066 case ODDBALL_TYPE: { 2067 if (IsUndefined()) { 2068 os << "<undefined>"; 2069 } else if (IsTheHole()) { 2070 os << "<the_hole>"; 2071 } else if (IsNull()) { 2072 os << "<null>"; 2073 } else if (IsTrue()) { 2074 os << "<true>"; 2075 } else if (IsFalse()) { 2076 os << "<false>"; 2077 } else { 2078 os << "<Odd Oddball: "; 2079 os << Oddball::cast(*this).to_string().ToCString().get(); 2080 os << ">"; 2081 } 2082 break; 2083 } 2084 case SYMBOL_TYPE: { 2085 Symbol symbol = Symbol::cast(*this); 2086 symbol.SymbolShortPrint(os); 2087 break; 2088 } 2089 case HEAP_NUMBER_TYPE: { 2090 os << "<HeapNumber "; 2091 HeapNumber::cast(*this).HeapNumberShortPrint(os); 2092 os << ">"; 2093 break; 2094 } 2095 case BIGINT_TYPE: { 2096 os << "<BigInt "; 2097 BigInt::cast(*this).BigIntShortPrint(os); 2098 os << ">"; 2099 break; 2100 } 2101 case JS_PROXY_TYPE: 2102 os << "<JSProxy>"; 2103 break; 2104 case FOREIGN_TYPE: 2105 os << "<Foreign>"; 2106 break; 2107 case CELL_TYPE: { 2108 os << "<Cell value= "; 2109 HeapStringAllocator allocator; 2110 StringStream accumulator(&allocator); 2111 Cell::cast(*this).value().ShortPrint(&accumulator); 2112 os << accumulator.ToCString().get(); 2113 os << '>'; 2114 break; 2115 } 2116 case PROPERTY_CELL_TYPE: { 2117 PropertyCell cell = PropertyCell::cast(*this); 2118 os << "<PropertyCell name="; 2119 cell.name().ShortPrint(os); 2120 os << " value="; 2121 HeapStringAllocator allocator; 2122 StringStream accumulator(&allocator); 2123 cell.value(kAcquireLoad).ShortPrint(&accumulator); 2124 os << accumulator.ToCString().get(); 2125 os << '>'; 2126 break; 2127 } 2128 case CALL_HANDLER_INFO_TYPE: { 2129 CallHandlerInfo info = CallHandlerInfo::cast(*this); 2130 os << "<CallHandlerInfo "; 2131 os << "callback= " << Brief(info.callback()); 2132 os << ", js_callback= " << Brief(info.js_callback()); 2133 os << ", data= " << Brief(info.data()); 2134 if (info.IsSideEffectFreeCallHandlerInfo()) { 2135 os << ", side_effect_free= true>"; 2136 } else { 2137 os << ", side_effect_free= false>"; 2138 } 2139 break; 2140 } 2141 default: 2142 os << "<Other heap object (" << map().instance_type() << ")>"; 2143 break; 2144 } 2145} 2146 2147void Struct::BriefPrintDetails(std::ostream& os) {} 2148 2149void Tuple2::BriefPrintDetails(std::ostream& os) { 2150 os << " " << Brief(value1()) << ", " << Brief(value2()); 2151} 2152 2153void MegaDomHandler::BriefPrintDetails(std::ostream& os) { 2154 os << " " << Brief(accessor()) << ", " << Brief(context()); 2155} 2156 2157void ClassPositions::BriefPrintDetails(std::ostream& os) { 2158 os << " " << start() << ", " << end(); 2159} 2160 2161void CallableTask::BriefPrintDetails(std::ostream& os) { 2162 os << " callable=" << Brief(callable()); 2163} 2164 2165void HeapObject::Iterate(PtrComprCageBase cage_base, ObjectVisitor* v) { 2166 IterateFast<ObjectVisitor>(cage_base, v); 2167} 2168 2169void HeapObject::IterateBody(PtrComprCageBase cage_base, ObjectVisitor* v) { 2170 Map m = map(cage_base); 2171 IterateBodyFast<ObjectVisitor>(m, SizeFromMap(m), v); 2172} 2173 2174void HeapObject::IterateBody(Map map, int object_size, ObjectVisitor* v) { 2175 IterateBodyFast<ObjectVisitor>(map, object_size, v); 2176} 2177 2178struct CallIsValidSlot { 2179 template <typename BodyDescriptor> 2180 static bool apply(Map map, HeapObject obj, int offset) { 2181 return BodyDescriptor::IsValidSlot(map, obj, offset); 2182 } 2183}; 2184 2185bool HeapObject::IsValidSlot(Map map, int offset) { 2186 DCHECK_NE(0, offset); 2187 return BodyDescriptorApply<CallIsValidSlot>(map.instance_type(), map, *this, 2188 offset); 2189} 2190 2191int HeapObject::SizeFromMap(Map map) const { 2192 int instance_size = map.instance_size(); 2193 if (instance_size != kVariableSizeSentinel) return instance_size; 2194 // Only inline the most frequent cases. 2195 InstanceType instance_type = map.instance_type(); 2196 if (base::IsInRange(instance_type, FIRST_FIXED_ARRAY_TYPE, 2197 LAST_FIXED_ARRAY_TYPE)) { 2198 return FixedArray::SizeFor( 2199 FixedArray::unchecked_cast(*this).length(kAcquireLoad)); 2200 } 2201 if (base::IsInRange(instance_type, FIRST_CONTEXT_TYPE, LAST_CONTEXT_TYPE)) { 2202 if (instance_type == NATIVE_CONTEXT_TYPE) return NativeContext::kSize; 2203 return Context::SizeFor(Context::unchecked_cast(*this).length()); 2204 } 2205 if (instance_type == ONE_BYTE_STRING_TYPE || 2206 instance_type == ONE_BYTE_INTERNALIZED_STRING_TYPE || 2207 instance_type == SHARED_ONE_BYTE_STRING_TYPE) { 2208 // Strings may get concurrently truncated, hence we have to access its 2209 // length synchronized. 2210 return SeqOneByteString::SizeFor( 2211 SeqOneByteString::unchecked_cast(*this).length(kAcquireLoad)); 2212 } 2213 if (instance_type == BYTE_ARRAY_TYPE) { 2214 return ByteArray::SizeFor( 2215 ByteArray::unchecked_cast(*this).length(kAcquireLoad)); 2216 } 2217 if (instance_type == BYTECODE_ARRAY_TYPE) { 2218 return BytecodeArray::SizeFor( 2219 BytecodeArray::unchecked_cast(*this).length(kAcquireLoad)); 2220 } 2221 if (instance_type == FREE_SPACE_TYPE) { 2222 return FreeSpace::unchecked_cast(*this).size(kRelaxedLoad); 2223 } 2224 if (instance_type == STRING_TYPE || 2225 instance_type == INTERNALIZED_STRING_TYPE || 2226 instance_type == SHARED_STRING_TYPE) { 2227 // Strings may get concurrently truncated, hence we have to access its 2228 // length synchronized. 2229 return SeqTwoByteString::SizeFor( 2230 SeqTwoByteString::unchecked_cast(*this).length(kAcquireLoad)); 2231 } 2232 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) { 2233 return FixedDoubleArray::SizeFor( 2234 FixedDoubleArray::unchecked_cast(*this).length(kAcquireLoad)); 2235 } 2236 if (instance_type == FEEDBACK_METADATA_TYPE) { 2237 return FeedbackMetadata::SizeFor( 2238 FeedbackMetadata::unchecked_cast(*this).slot_count(kAcquireLoad)); 2239 } 2240 if (base::IsInRange(instance_type, FIRST_DESCRIPTOR_ARRAY_TYPE, 2241 LAST_DESCRIPTOR_ARRAY_TYPE)) { 2242 return DescriptorArray::SizeFor( 2243 DescriptorArray::unchecked_cast(*this).number_of_all_descriptors()); 2244 } 2245 if (base::IsInRange(instance_type, FIRST_WEAK_FIXED_ARRAY_TYPE, 2246 LAST_WEAK_FIXED_ARRAY_TYPE)) { 2247 return WeakFixedArray::SizeFor( 2248 WeakFixedArray::unchecked_cast(*this).length(kAcquireLoad)); 2249 } 2250 if (instance_type == WEAK_ARRAY_LIST_TYPE) { 2251 return WeakArrayList::SizeForCapacity( 2252 WeakArrayList::unchecked_cast(*this).capacity()); 2253 } 2254 if (instance_type == SMALL_ORDERED_HASH_SET_TYPE) { 2255 return SmallOrderedHashSet::SizeFor( 2256 SmallOrderedHashSet::unchecked_cast(*this).Capacity()); 2257 } 2258 if (instance_type == SMALL_ORDERED_HASH_MAP_TYPE) { 2259 return SmallOrderedHashMap::SizeFor( 2260 SmallOrderedHashMap::unchecked_cast(*this).Capacity()); 2261 } 2262 if (instance_type == SMALL_ORDERED_NAME_DICTIONARY_TYPE) { 2263 return SmallOrderedNameDictionary::SizeFor( 2264 SmallOrderedNameDictionary::unchecked_cast(*this).Capacity()); 2265 } 2266 if (instance_type == SWISS_NAME_DICTIONARY_TYPE) { 2267 return SwissNameDictionary::SizeFor( 2268 SwissNameDictionary::unchecked_cast(*this).Capacity()); 2269 } 2270 if (instance_type == PROPERTY_ARRAY_TYPE) { 2271 return PropertyArray::SizeFor( 2272 PropertyArray::cast(*this).length(kAcquireLoad)); 2273 } 2274 if (instance_type == FEEDBACK_VECTOR_TYPE) { 2275 return FeedbackVector::SizeFor( 2276 FeedbackVector::unchecked_cast(*this).length()); 2277 } 2278 if (instance_type == BIGINT_TYPE) { 2279 return BigInt::SizeFor(BigInt::unchecked_cast(*this).length()); 2280 } 2281 if (instance_type == PREPARSE_DATA_TYPE) { 2282 PreparseData data = PreparseData::unchecked_cast(*this); 2283 return PreparseData::SizeFor(data.data_length(), data.children_length()); 2284 } 2285#define MAKE_TORQUE_SIZE_FOR(TYPE, TypeName) \ 2286 if (instance_type == TYPE) { \ 2287 return TypeName::unchecked_cast(*this).AllocatedSize(); \ 2288 } 2289 TORQUE_INSTANCE_TYPE_TO_BODY_DESCRIPTOR_LIST(MAKE_TORQUE_SIZE_FOR) 2290#undef MAKE_TORQUE_SIZE_FOR 2291 2292 if (instance_type == CODE_TYPE) { 2293 return Code::unchecked_cast(*this).CodeSize(); 2294 } 2295 if (instance_type == COVERAGE_INFO_TYPE) { 2296 return CoverageInfo::SizeFor( 2297 CoverageInfo::unchecked_cast(*this).slot_count()); 2298 } 2299#if V8_ENABLE_WEBASSEMBLY 2300 if (instance_type == WASM_STRUCT_TYPE) { 2301 return WasmStruct::GcSafeSize(map); 2302 } 2303 if (instance_type == WASM_ARRAY_TYPE) { 2304 return WasmArray::SizeFor(map, WasmArray::cast(*this).length()); 2305 } 2306#endif // V8_ENABLE_WEBASSEMBLY 2307 DCHECK_EQ(instance_type, EMBEDDER_DATA_ARRAY_TYPE); 2308 return EmbedderDataArray::SizeFor( 2309 EmbedderDataArray::unchecked_cast(*this).length()); 2310} 2311 2312bool HeapObject::NeedsRehashing(PtrComprCageBase cage_base) const { 2313 return NeedsRehashing(map(cage_base).instance_type()); 2314} 2315 2316bool HeapObject::NeedsRehashing(InstanceType instance_type) const { 2317 if (V8_EXTERNAL_CODE_SPACE_BOOL) { 2318 // Use map() only when it's guaranteed that it's not a Code object. 2319 DCHECK_IMPLIES(instance_type != CODE_TYPE, 2320 instance_type == map().instance_type()); 2321 } else { 2322 DCHECK_EQ(instance_type, map().instance_type()); 2323 } 2324 switch (instance_type) { 2325 case DESCRIPTOR_ARRAY_TYPE: 2326 case STRONG_DESCRIPTOR_ARRAY_TYPE: 2327 return DescriptorArray::cast(*this).number_of_descriptors() > 1; 2328 case TRANSITION_ARRAY_TYPE: 2329 return TransitionArray::cast(*this).number_of_entries() > 1; 2330 case ORDERED_HASH_MAP_TYPE: 2331 case ORDERED_HASH_SET_TYPE: 2332 return false; // We'll rehash from the JSMap or JSSet referencing them. 2333 case NAME_DICTIONARY_TYPE: 2334 case NAME_TO_INDEX_HASH_TABLE_TYPE: 2335 case REGISTERED_SYMBOL_TABLE_TYPE: 2336 case GLOBAL_DICTIONARY_TYPE: 2337 case NUMBER_DICTIONARY_TYPE: 2338 case SIMPLE_NUMBER_DICTIONARY_TYPE: 2339 case HASH_TABLE_TYPE: 2340 case SMALL_ORDERED_HASH_MAP_TYPE: 2341 case SMALL_ORDERED_HASH_SET_TYPE: 2342 case SMALL_ORDERED_NAME_DICTIONARY_TYPE: 2343 case SWISS_NAME_DICTIONARY_TYPE: 2344 case JS_MAP_TYPE: 2345 case JS_SET_TYPE: 2346 return true; 2347 default: 2348 return false; 2349 } 2350} 2351 2352bool HeapObject::CanBeRehashed(PtrComprCageBase cage_base) const { 2353 DCHECK(NeedsRehashing(cage_base)); 2354 switch (map(cage_base).instance_type()) { 2355 case JS_MAP_TYPE: 2356 case JS_SET_TYPE: 2357 return true; 2358 case ORDERED_HASH_MAP_TYPE: 2359 case ORDERED_HASH_SET_TYPE: 2360 UNREACHABLE(); // We'll rehash from the JSMap or JSSet referencing them. 2361 case ORDERED_NAME_DICTIONARY_TYPE: 2362 return false; 2363 case NAME_DICTIONARY_TYPE: 2364 case NAME_TO_INDEX_HASH_TABLE_TYPE: 2365 case REGISTERED_SYMBOL_TABLE_TYPE: 2366 case GLOBAL_DICTIONARY_TYPE: 2367 case NUMBER_DICTIONARY_TYPE: 2368 case SIMPLE_NUMBER_DICTIONARY_TYPE: 2369 case SWISS_NAME_DICTIONARY_TYPE: 2370 return true; 2371 case DESCRIPTOR_ARRAY_TYPE: 2372 case STRONG_DESCRIPTOR_ARRAY_TYPE: 2373 return true; 2374 case TRANSITION_ARRAY_TYPE: 2375 return true; 2376 case SMALL_ORDERED_HASH_MAP_TYPE: 2377 return SmallOrderedHashMap::cast(*this).NumberOfElements() == 0; 2378 case SMALL_ORDERED_HASH_SET_TYPE: 2379 return SmallOrderedHashMap::cast(*this).NumberOfElements() == 0; 2380 case SMALL_ORDERED_NAME_DICTIONARY_TYPE: 2381 return SmallOrderedNameDictionary::cast(*this).NumberOfElements() == 0; 2382 default: 2383 return false; 2384 } 2385} 2386 2387template <typename IsolateT> 2388void HeapObject::RehashBasedOnMap(IsolateT* isolate) { 2389 switch (map(isolate).instance_type()) { 2390 case HASH_TABLE_TYPE: 2391 UNREACHABLE(); 2392 case NAME_DICTIONARY_TYPE: 2393 NameDictionary::cast(*this).Rehash(isolate); 2394 break; 2395 case NAME_TO_INDEX_HASH_TABLE_TYPE: 2396 NameToIndexHashTable::cast(*this).Rehash(isolate); 2397 break; 2398 case REGISTERED_SYMBOL_TABLE_TYPE: 2399 RegisteredSymbolTable::cast(*this).Rehash(isolate); 2400 break; 2401 case SWISS_NAME_DICTIONARY_TYPE: 2402 SwissNameDictionary::cast(*this).Rehash(isolate); 2403 break; 2404 case GLOBAL_DICTIONARY_TYPE: 2405 GlobalDictionary::cast(*this).Rehash(isolate); 2406 break; 2407 case NUMBER_DICTIONARY_TYPE: 2408 NumberDictionary::cast(*this).Rehash(isolate); 2409 break; 2410 case SIMPLE_NUMBER_DICTIONARY_TYPE: 2411 SimpleNumberDictionary::cast(*this).Rehash(isolate); 2412 break; 2413 case DESCRIPTOR_ARRAY_TYPE: 2414 DCHECK_LE(1, DescriptorArray::cast(*this).number_of_descriptors()); 2415 DescriptorArray::cast(*this).Sort(); 2416 break; 2417 case TRANSITION_ARRAY_TYPE: 2418 TransitionArray::cast(*this).Sort(); 2419 break; 2420 case SMALL_ORDERED_HASH_MAP_TYPE: 2421 DCHECK_EQ(0, SmallOrderedHashMap::cast(*this).NumberOfElements()); 2422 break; 2423 case SMALL_ORDERED_HASH_SET_TYPE: 2424 DCHECK_EQ(0, SmallOrderedHashSet::cast(*this).NumberOfElements()); 2425 break; 2426 case ORDERED_HASH_MAP_TYPE: 2427 case ORDERED_HASH_SET_TYPE: 2428 UNREACHABLE(); // We'll rehash from the JSMap or JSSet referencing them. 2429 case JS_MAP_TYPE: { 2430 JSMap::cast(*this).Rehash(isolate->AsIsolate()); 2431 break; 2432 } 2433 case JS_SET_TYPE: { 2434 JSSet::cast(*this).Rehash(isolate->AsIsolate()); 2435 break; 2436 } 2437 case SMALL_ORDERED_NAME_DICTIONARY_TYPE: 2438 DCHECK_EQ(0, SmallOrderedNameDictionary::cast(*this).NumberOfElements()); 2439 break; 2440 case ONE_BYTE_INTERNALIZED_STRING_TYPE: 2441 case INTERNALIZED_STRING_TYPE: 2442 // Rare case, rehash read-only space strings before they are sealed. 2443 DCHECK(ReadOnlyHeap::Contains(*this)); 2444 String::cast(*this).EnsureHash(); 2445 break; 2446 default: 2447 UNREACHABLE(); 2448 } 2449} 2450template void HeapObject::RehashBasedOnMap(Isolate* isolate); 2451template void HeapObject::RehashBasedOnMap(LocalIsolate* isolate); 2452 2453void DescriptorArray::GeneralizeAllFields() { 2454 int length = number_of_descriptors(); 2455 for (InternalIndex i : InternalIndex::Range(length)) { 2456 PropertyDetails details = GetDetails(i); 2457 details = details.CopyWithRepresentation(Representation::Tagged()); 2458 if (details.location() == PropertyLocation::kField) { 2459 DCHECK_EQ(PropertyKind::kData, details.kind()); 2460 details = details.CopyWithConstness(PropertyConstness::kMutable); 2461 SetValue(i, MaybeObject::FromObject(FieldType::Any())); 2462 } 2463 SetDetails(i, details); 2464 } 2465} 2466 2467MaybeHandle<Object> Object::SetProperty(Isolate* isolate, Handle<Object> object, 2468 Handle<Name> name, Handle<Object> value, 2469 StoreOrigin store_origin, 2470 Maybe<ShouldThrow> should_throw) { 2471 LookupIterator it(isolate, object, name); 2472 MAYBE_RETURN_NULL(SetProperty(&it, value, store_origin, should_throw)); 2473 return value; 2474} 2475 2476Maybe<bool> Object::SetPropertyInternal(LookupIterator* it, 2477 Handle<Object> value, 2478 Maybe<ShouldThrow> should_throw, 2479 StoreOrigin store_origin, bool* found) { 2480 it->UpdateProtector(); 2481 DCHECK(it->IsFound()); 2482 2483 // Make sure that the top context does not change when doing callbacks or 2484 // interceptor calls. 2485 AssertNoContextChange ncc(it->isolate()); 2486 2487 do { 2488 switch (it->state()) { 2489 case LookupIterator::NOT_FOUND: 2490 UNREACHABLE(); 2491 2492 case LookupIterator::ACCESS_CHECK: 2493 if (it->HasAccess()) break; 2494 // Check whether it makes sense to reuse the lookup iterator. Here it 2495 // might still call into setters up the prototype chain. 2496 return JSObject::SetPropertyWithFailedAccessCheck(it, value, 2497 should_throw); 2498 2499 case LookupIterator::JSPROXY: { 2500 Handle<Object> receiver = it->GetReceiver(); 2501 // In case of global IC, the receiver is the global object. Replace by 2502 // the global proxy. 2503 if (receiver->IsJSGlobalObject()) { 2504 receiver = handle(JSGlobalObject::cast(*receiver).global_proxy(), 2505 it->isolate()); 2506 } 2507 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(), 2508 value, receiver, should_throw); 2509 } 2510 2511 case LookupIterator::INTERCEPTOR: { 2512 if (it->HolderIsReceiverOrHiddenPrototype()) { 2513 Maybe<bool> result = 2514 JSObject::SetPropertyWithInterceptor(it, should_throw, value); 2515 if (result.IsNothing() || result.FromJust()) return result; 2516 // Assuming that the callback have side effects, we use 2517 // Object::SetSuperProperty() which works properly regardless on 2518 // whether the property was present on the receiver or not when 2519 // storing to the receiver. 2520 // Proceed lookup from the next state. 2521 it->Next(); 2522 } else { 2523 Maybe<PropertyAttributes> maybe_attributes = 2524 JSObject::GetPropertyAttributesWithInterceptor(it); 2525 if (maybe_attributes.IsNothing()) return Nothing<bool>(); 2526 if ((maybe_attributes.FromJust() & READ_ONLY) != 0) { 2527 return WriteToReadOnlyProperty(it, value, should_throw); 2528 } 2529 // At this point we might have called interceptor's query or getter 2530 // callback. Assuming that the callbacks have side effects, we use 2531 // Object::SetSuperProperty() which works properly regardless on 2532 // whether the property was present on the receiver or not when 2533 // storing to the receiver. 2534 if (maybe_attributes.FromJust() == ABSENT) { 2535 // Proceed lookup from the next state. 2536 it->Next(); 2537 } else { 2538 // Finish lookup in order to make Object::SetSuperProperty() store 2539 // property to the receiver. 2540 it->NotFound(); 2541 } 2542 } 2543 return Object::SetSuperProperty(it, value, store_origin, should_throw); 2544 } 2545 2546 case LookupIterator::ACCESSOR: { 2547 if (it->IsReadOnly()) { 2548 return WriteToReadOnlyProperty(it, value, should_throw); 2549 } 2550 Handle<Object> accessors = it->GetAccessors(); 2551 if (accessors->IsAccessorInfo() && 2552 !it->HolderIsReceiverOrHiddenPrototype() && 2553 AccessorInfo::cast(*accessors).is_special_data_property()) { 2554 *found = false; 2555 return Nothing<bool>(); 2556 } 2557 return SetPropertyWithAccessor(it, value, should_throw); 2558 } 2559 case LookupIterator::INTEGER_INDEXED_EXOTIC: { 2560 // IntegerIndexedElementSet converts value to a Number/BigInt prior to 2561 // the bounds check. The bounds check has already happened here, but 2562 // perform the possibly effectful ToNumber (or ToBigInt) operation 2563 // anyways. 2564 auto holder = it->GetHolder<JSTypedArray>(); 2565 Handle<Object> throwaway_value; 2566 if (holder->type() == kExternalBigInt64Array || 2567 holder->type() == kExternalBigUint64Array) { 2568 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2569 it->isolate(), throwaway_value, 2570 BigInt::FromObject(it->isolate(), value), Nothing<bool>()); 2571 } else { 2572 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2573 it->isolate(), throwaway_value, 2574 Object::ToNumber(it->isolate(), value), Nothing<bool>()); 2575 } 2576 2577 // FIXME: Throw a TypeError if the holder is detached here 2578 // (IntegerIndexedElementSpec step 5). 2579 2580 // TODO(verwaest): Per spec, we should return false here (steps 6-9 2581 // in IntegerIndexedElementSpec), resulting in an exception being thrown 2582 // on OOB accesses in strict code. Historically, v8 has not done made 2583 // this change due to uncertainty about web compat. (v8:4901) 2584 return Just(true); 2585 } 2586 2587 case LookupIterator::DATA: 2588 if (it->IsReadOnly()) { 2589 return WriteToReadOnlyProperty(it, value, should_throw); 2590 } 2591 if (it->HolderIsReceiverOrHiddenPrototype()) { 2592 return SetDataProperty(it, value); 2593 } 2594 V8_FALLTHROUGH; 2595 case LookupIterator::TRANSITION: 2596 *found = false; 2597 return Nothing<bool>(); 2598 } 2599 it->Next(); 2600 } while (it->IsFound()); 2601 2602 *found = false; 2603 return Nothing<bool>(); 2604} 2605 2606bool Object::CheckContextualStoreToJSGlobalObject( 2607 LookupIterator* it, Maybe<ShouldThrow> should_throw) { 2608 Isolate* isolate = it->isolate(); 2609 2610 if (it->GetReceiver()->IsJSGlobalObject(isolate) && 2611 (GetShouldThrow(isolate, should_throw) == ShouldThrow::kThrowOnError)) { 2612 if (it->state() == LookupIterator::TRANSITION) { 2613 // The property cell that we have created is garbage because we are going 2614 // to throw now instead of putting it into the global dictionary. However, 2615 // the cell might already have been stored into the feedback vector, so 2616 // we must invalidate it nevertheless. 2617 it->transition_cell()->ClearAndInvalidate(ReadOnlyRoots(isolate)); 2618 } 2619 isolate->Throw(*isolate->factory()->NewReferenceError( 2620 MessageTemplate::kNotDefined, it->GetName())); 2621 return false; 2622 } 2623 return true; 2624} 2625 2626Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value, 2627 StoreOrigin store_origin, 2628 Maybe<ShouldThrow> should_throw) { 2629 if (it->IsFound()) { 2630 bool found = true; 2631 Maybe<bool> result = 2632 SetPropertyInternal(it, value, should_throw, store_origin, &found); 2633 if (found) return result; 2634 } 2635 2636 if (!CheckContextualStoreToJSGlobalObject(it, should_throw)) { 2637 return Nothing<bool>(); 2638 } 2639 return AddDataProperty(it, value, NONE, should_throw, store_origin); 2640} 2641 2642Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, 2643 StoreOrigin store_origin, 2644 Maybe<ShouldThrow> should_throw) { 2645 Isolate* isolate = it->isolate(); 2646 2647 if (it->IsFound()) { 2648 bool found = true; 2649 Maybe<bool> result = 2650 SetPropertyInternal(it, value, should_throw, store_origin, &found); 2651 if (found) return result; 2652 } 2653 2654 it->UpdateProtector(); 2655 2656 // The property either doesn't exist on the holder or exists there as a data 2657 // property. 2658 2659 if (!it->GetReceiver()->IsJSReceiver()) { 2660 return WriteToReadOnlyProperty(it, value, should_throw); 2661 } 2662 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 2663 2664 // Note, the callers rely on the fact that this code is redoing the full own 2665 // lookup from scratch. 2666 LookupIterator::Configuration c = LookupIterator::OWN; 2667 LookupIterator own_lookup = 2668 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c) 2669 : LookupIterator(isolate, receiver, it->name(), c); 2670 2671 for (; own_lookup.IsFound(); own_lookup.Next()) { 2672 switch (own_lookup.state()) { 2673 case LookupIterator::ACCESS_CHECK: 2674 if (!own_lookup.HasAccess()) { 2675 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value, 2676 should_throw); 2677 } 2678 break; 2679 2680 case LookupIterator::ACCESSOR: 2681 if (own_lookup.GetAccessors()->IsAccessorInfo()) { 2682 if (own_lookup.IsReadOnly()) { 2683 return WriteToReadOnlyProperty(&own_lookup, value, should_throw); 2684 } 2685 return Object::SetPropertyWithAccessor(&own_lookup, value, 2686 should_throw); 2687 } 2688 V8_FALLTHROUGH; 2689 case LookupIterator::INTEGER_INDEXED_EXOTIC: 2690 return RedefineIncompatibleProperty(isolate, it->GetName(), value, 2691 should_throw); 2692 2693 case LookupIterator::DATA: { 2694 if (own_lookup.IsReadOnly()) { 2695 return WriteToReadOnlyProperty(&own_lookup, value, should_throw); 2696 } 2697 return SetDataProperty(&own_lookup, value); 2698 } 2699 2700 case LookupIterator::INTERCEPTOR: 2701 case LookupIterator::JSPROXY: { 2702 PropertyDescriptor desc; 2703 Maybe<bool> owned = 2704 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc); 2705 MAYBE_RETURN(owned, Nothing<bool>()); 2706 if (!owned.FromJust()) { 2707 if (!CheckContextualStoreToJSGlobalObject(&own_lookup, 2708 should_throw)) { 2709 return Nothing<bool>(); 2710 } 2711 return JSReceiver::CreateDataProperty(&own_lookup, value, 2712 should_throw); 2713 } 2714 if (PropertyDescriptor::IsAccessorDescriptor(&desc) || 2715 !desc.writable()) { 2716 return RedefineIncompatibleProperty(isolate, it->GetName(), value, 2717 should_throw); 2718 } 2719 2720 PropertyDescriptor value_desc; 2721 value_desc.set_value(value); 2722 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(), 2723 &value_desc, should_throw); 2724 } 2725 2726 case LookupIterator::NOT_FOUND: 2727 case LookupIterator::TRANSITION: 2728 UNREACHABLE(); 2729 } 2730 } 2731 2732 if (!CheckContextualStoreToJSGlobalObject(&own_lookup, should_throw)) { 2733 return Nothing<bool>(); 2734 } 2735 return AddDataProperty(&own_lookup, value, NONE, should_throw, store_origin); 2736} 2737 2738Maybe<bool> Object::CannotCreateProperty(Isolate* isolate, 2739 Handle<Object> receiver, 2740 Handle<Object> name, 2741 Handle<Object> value, 2742 Maybe<ShouldThrow> should_throw) { 2743 RETURN_FAILURE( 2744 isolate, GetShouldThrow(isolate, should_throw), 2745 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name, 2746 Object::TypeOf(isolate, receiver), receiver)); 2747} 2748 2749Maybe<bool> Object::WriteToReadOnlyProperty( 2750 LookupIterator* it, Handle<Object> value, 2751 Maybe<ShouldThrow> maybe_should_throw) { 2752 ShouldThrow should_throw = GetShouldThrow(it->isolate(), maybe_should_throw); 2753 if (it->IsFound() && !it->HolderIsReceiver()) { 2754 // "Override mistake" attempted, record a use count to track this per 2755 // v8:8175 2756 v8::Isolate::UseCounterFeature feature = 2757 should_throw == kThrowOnError 2758 ? v8::Isolate::kAttemptOverrideReadOnlyOnPrototypeStrict 2759 : v8::Isolate::kAttemptOverrideReadOnlyOnPrototypeSloppy; 2760 it->isolate()->CountUsage(feature); 2761 } 2762 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), 2763 it->GetName(), value, should_throw); 2764} 2765 2766Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate, 2767 Handle<Object> receiver, 2768 Handle<Object> name, 2769 Handle<Object> value, 2770 ShouldThrow should_throw) { 2771 RETURN_FAILURE(isolate, should_throw, 2772 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name, 2773 Object::TypeOf(isolate, receiver), receiver)); 2774} 2775 2776Maybe<bool> Object::RedefineIncompatibleProperty( 2777 Isolate* isolate, Handle<Object> name, Handle<Object> value, 2778 Maybe<ShouldThrow> should_throw) { 2779 RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw), 2780 NewTypeError(MessageTemplate::kRedefineDisallowed, name)); 2781} 2782 2783Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { 2784 Isolate* isolate = it->isolate(); 2785 DCHECK_IMPLIES(it->GetReceiver()->IsJSProxy(isolate), 2786 it->GetName()->IsPrivateName(isolate)); 2787 DCHECK_IMPLIES(!it->IsElement() && it->GetName()->IsPrivateName(isolate), 2788 it->state() == LookupIterator::DATA); 2789 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 2790 2791 // Store on the holder which may be hidden behind the receiver. 2792 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); 2793 2794 Handle<Object> to_assign = value; 2795 // Convert the incoming value to a number for storing into typed arrays. 2796 if (it->IsElement() && receiver->IsJSObject(isolate) && 2797 JSObject::cast(*receiver).HasTypedArrayOrRabGsabTypedArrayElements( 2798 isolate)) { 2799 ElementsKind elements_kind = JSObject::cast(*receiver).GetElementsKind(); 2800 if (IsBigIntTypedArrayElementsKind(elements_kind)) { 2801 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, to_assign, 2802 BigInt::FromObject(isolate, value), 2803 Nothing<bool>()); 2804 // We have to recheck the length. However, it can only change if the 2805 // underlying buffer was detached, so just check that. 2806 if (Handle<JSArrayBufferView>::cast(receiver)->WasDetached()) { 2807 return Just(true); 2808 // TODO(neis): According to the spec, this should throw a TypeError. 2809 } 2810 } else if (!value->IsNumber() && !value->IsUndefined(isolate)) { 2811 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, to_assign, 2812 Object::ToNumber(isolate, value), 2813 Nothing<bool>()); 2814 // We have to recheck the length. However, it can only change if the 2815 // underlying buffer was detached, so just check that. 2816 if (Handle<JSArrayBufferView>::cast(receiver)->WasDetached()) { 2817 return Just(true); 2818 // TODO(neis): According to the spec, this should throw a TypeError. 2819 } 2820 } 2821 } 2822 2823#if V8_ENABLE_WEBASSEMBLY 2824 if (receiver->IsWasmObject(isolate)) { 2825 // Prepares given value for being stored into a field of given Wasm type 2826 // or throw if the value can't be stored into the field. 2827 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2828 isolate, to_assign, 2829 WasmObject::ToWasmValue(isolate, it->wasm_value_type(), to_assign), 2830 Nothing<bool>()); 2831 2832 // Store prepared value. 2833 it->WriteDataValueToWasmObject(to_assign); 2834 2835 } else // NOLINT(readability/braces) 2836#endif // V8_ENABLE_WEBASSEMBLY 2837 // clang-format off 2838 if (V8_UNLIKELY(receiver->IsJSSharedStruct(isolate))) { 2839 // clang-format on 2840 2841 // Shared structs can only point to primitives or shared values. 2842 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2843 isolate, to_assign, Object::Share(isolate, to_assign, kThrowOnError), 2844 Nothing<bool>()); 2845 it->WriteDataValue(to_assign, false); 2846 } else { 2847 // Possibly migrate to the most up-to-date map that will be able to store 2848 // |value| under it->name(). 2849 it->PrepareForDataProperty(to_assign); 2850 2851 // Write the property value. 2852 it->WriteDataValue(to_assign, false); 2853 } 2854 2855#if VERIFY_HEAP 2856 if (FLAG_verify_heap) { 2857 receiver->HeapObjectVerify(isolate); 2858 } 2859#endif 2860 return Just(true); 2861} 2862 2863Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, 2864 PropertyAttributes attributes, 2865 Maybe<ShouldThrow> should_throw, 2866 StoreOrigin store_origin, 2867 EnforceDefineSemantics semantics) { 2868 if (!it->GetReceiver()->IsJSReceiver()) { 2869 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(), 2870 value, should_throw); 2871 } 2872 2873 // Private symbols should be installed on JSProxy using 2874 // JSProxy::SetPrivateSymbol. 2875 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate() && 2876 !it->GetName()->IsPrivateName()) { 2877 RETURN_FAILURE(it->isolate(), GetShouldThrow(it->isolate(), should_throw), 2878 NewTypeError(MessageTemplate::kProxyPrivate)); 2879 } 2880 2881 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state()); 2882 2883 Handle<JSReceiver> receiver = it->GetStoreTarget<JSReceiver>(); 2884 DCHECK_IMPLIES(receiver->IsJSProxy(), it->GetName()->IsPrivateName()); 2885 DCHECK_IMPLIES(receiver->IsJSProxy(), 2886 it->state() == LookupIterator::NOT_FOUND); 2887 2888 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) 2889 // instead. If the prototype is Null, the proxy is detached. 2890 if (receiver->IsJSGlobalProxy()) return Just(true); 2891 2892 Isolate* isolate = it->isolate(); 2893 2894 if (it->ExtendingNonExtensible(receiver)) { 2895 RETURN_FAILURE(isolate, GetShouldThrow(it->isolate(), should_throw), 2896 NewTypeError(semantics == EnforceDefineSemantics::kDefine 2897 ? MessageTemplate::kDefineDisallowed 2898 : MessageTemplate::kObjectNotExtensible, 2899 it->GetName())); 2900 } 2901 2902 if (it->IsElement(*receiver)) { 2903 if (receiver->IsJSArray()) { 2904 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 2905 if (JSArray::WouldChangeReadOnlyLength(array, it->array_index())) { 2906 RETURN_FAILURE(isolate, GetShouldThrow(it->isolate(), should_throw), 2907 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, 2908 isolate->factory()->length_string(), 2909 Object::TypeOf(isolate, array), array)); 2910 } 2911 } 2912 2913 Handle<JSObject> receiver_obj = Handle<JSObject>::cast(receiver); 2914 MAYBE_RETURN(JSObject::AddDataElement(receiver_obj, it->array_index(), 2915 value, attributes), 2916 Nothing<bool>()); 2917 JSObject::ValidateElements(*receiver_obj); 2918 return Just(true); 2919 } 2920 2921 return Object::TransitionAndWriteDataProperty(it, value, attributes, 2922 should_throw, store_origin); 2923} 2924 2925// static 2926Maybe<bool> Object::TransitionAndWriteDataProperty( 2927 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, 2928 Maybe<ShouldThrow> should_throw, StoreOrigin store_origin) { 2929 Handle<JSReceiver> receiver = it->GetStoreTarget<JSReceiver>(); 2930 it->UpdateProtector(); 2931 // Migrate to the most up-to-date map that will be able to store |value| 2932 // under it->name() with |attributes|. 2933 it->PrepareTransitionToDataProperty(receiver, value, attributes, 2934 store_origin); 2935 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); 2936 it->ApplyTransitionToDataProperty(receiver); 2937 2938 // Write the property value. 2939 it->WriteDataValue(value, true); 2940 2941#if VERIFY_HEAP 2942 if (FLAG_verify_heap) { 2943 receiver->HeapObjectVerify(it->isolate()); 2944 } 2945#endif 2946 2947 return Just(true); 2948} 2949// static 2950MaybeHandle<Object> Object::ShareSlow(Isolate* isolate, 2951 Handle<HeapObject> value, 2952 ShouldThrow throw_if_cannot_be_shared) { 2953 // Use Object::Share() if value might already be shared. 2954 DCHECK(!value->IsShared()); 2955 2956 if (value->IsString()) { 2957 return String::Share(isolate, Handle<String>::cast(value)); 2958 } 2959 2960 if (value->IsHeapNumber()) { 2961 uint64_t bits = HeapNumber::cast(*value).value_as_bits(kRelaxedLoad); 2962 return isolate->factory() 2963 ->NewHeapNumberFromBits<AllocationType::kSharedOld>(bits); 2964 } 2965 2966 if (throw_if_cannot_be_shared == kThrowOnError) { 2967 THROW_NEW_ERROR( 2968 isolate, NewTypeError(MessageTemplate::kCannotBeShared, value), Object); 2969 } 2970 return MaybeHandle<Object>(); 2971} 2972 2973template <class T> 2974static int AppendUniqueCallbacks(Isolate* isolate, 2975 Handle<TemplateList> callbacks, 2976 Handle<typename T::Array> array, 2977 int valid_descriptors) { 2978 int nof_callbacks = callbacks->length(); 2979 2980 // Fill in new callback descriptors. Process the callbacks from 2981 // back to front so that the last callback with a given name takes 2982 // precedence over previously added callbacks with that name. 2983 for (int i = nof_callbacks - 1; i >= 0; i--) { 2984 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)), isolate); 2985 Handle<Name> key(Name::cast(entry->name()), isolate); 2986 DCHECK(key->IsUniqueName()); 2987 // Check if a descriptor with this name already exists before writing. 2988 if (!T::Contains(key, entry, valid_descriptors, array)) { 2989 T::Insert(key, entry, valid_descriptors, array); 2990 valid_descriptors++; 2991 } 2992 } 2993 2994 return valid_descriptors; 2995} 2996 2997struct FixedArrayAppender { 2998 using Array = FixedArray; 2999 static bool Contains(Handle<Name> key, Handle<AccessorInfo> entry, 3000 int valid_descriptors, Handle<FixedArray> array) { 3001 for (int i = 0; i < valid_descriptors; i++) { 3002 if (*key == AccessorInfo::cast(array->get(i)).name()) return true; 3003 } 3004 return false; 3005 } 3006 static void Insert(Handle<Name> key, Handle<AccessorInfo> entry, 3007 int valid_descriptors, Handle<FixedArray> array) { 3008 DisallowGarbageCollection no_gc; 3009 array->set(valid_descriptors, *entry); 3010 } 3011}; 3012 3013int AccessorInfo::AppendUnique(Isolate* isolate, Handle<Object> descriptors, 3014 Handle<FixedArray> array, 3015 int valid_descriptors) { 3016 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors); 3017 DCHECK_GE(array->length(), callbacks->length() + valid_descriptors); 3018 return AppendUniqueCallbacks<FixedArrayAppender>(isolate, callbacks, array, 3019 valid_descriptors); 3020} 3021 3022void JSProxy::Revoke(Handle<JSProxy> proxy) { 3023 Isolate* isolate = proxy->GetIsolate(); 3024 // ES#sec-proxy-revocation-functions 3025 if (!proxy->IsRevoked()) { 3026 // 5. Set p.[[ProxyTarget]] to null. 3027 proxy->set_target(ReadOnlyRoots(isolate).null_value()); 3028 // 6. Set p.[[ProxyHandler]] to null. 3029 proxy->set_handler(ReadOnlyRoots(isolate).null_value()); 3030 } 3031 DCHECK(proxy->IsRevoked()); 3032} 3033 3034// static 3035Maybe<bool> JSProxy::IsArray(Handle<JSProxy> proxy) { 3036 Isolate* isolate = proxy->GetIsolate(); 3037 Handle<JSReceiver> object = Handle<JSReceiver>::cast(proxy); 3038 for (int i = 0; i < JSProxy::kMaxIterationLimit; i++) { 3039 proxy = Handle<JSProxy>::cast(object); 3040 if (proxy->IsRevoked()) { 3041 isolate->Throw(*isolate->factory()->NewTypeError( 3042 MessageTemplate::kProxyRevoked, 3043 isolate->factory()->NewStringFromAsciiChecked("IsArray"))); 3044 return Nothing<bool>(); 3045 } 3046 object = handle(JSReceiver::cast(proxy->target()), isolate); 3047 if (object->IsJSArray()) return Just(true); 3048 if (!object->IsJSProxy()) return Just(false); 3049 } 3050 3051 // Too deep recursion, throw a RangeError. 3052 isolate->StackOverflow(); 3053 return Nothing<bool>(); 3054} 3055 3056Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy, 3057 Handle<Name> name) { 3058 DCHECK(!name->IsPrivate()); 3059 STACK_CHECK(isolate, Nothing<bool>()); 3060 // 1. (Assert) 3061 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 3062 Handle<Object> handler(proxy->handler(), isolate); 3063 // 3. If handler is null, throw a TypeError exception. 3064 // 4. Assert: Type(handler) is Object. 3065 if (proxy->IsRevoked()) { 3066 isolate->Throw(*isolate->factory()->NewTypeError( 3067 MessageTemplate::kProxyRevoked, isolate->factory()->has_string())); 3068 return Nothing<bool>(); 3069 } 3070 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 3071 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 3072 // 6. Let trap be ? GetMethod(handler, "has"). 3073 Handle<Object> trap; 3074 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3075 isolate, trap, 3076 Object::GetMethod(Handle<JSReceiver>::cast(handler), 3077 isolate->factory()->has_string()), 3078 Nothing<bool>()); 3079 // 7. If trap is undefined, then 3080 if (trap->IsUndefined(isolate)) { 3081 // 7a. Return target.[[HasProperty]](P). 3082 return JSReceiver::HasProperty(isolate, target, name); 3083 } 3084 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)). 3085 Handle<Object> trap_result_obj; 3086 Handle<Object> args[] = {target, name}; 3087 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3088 isolate, trap_result_obj, 3089 Execution::Call(isolate, trap, handler, arraysize(args), args), 3090 Nothing<bool>()); 3091 bool boolean_trap_result = trap_result_obj->BooleanValue(isolate); 3092 // 9. If booleanTrapResult is false, then: 3093 if (!boolean_trap_result) { 3094 MAYBE_RETURN(JSProxy::CheckHasTrap(isolate, name, target), Nothing<bool>()); 3095 } 3096 // 10. Return booleanTrapResult. 3097 return Just(boolean_trap_result); 3098} 3099 3100Maybe<bool> JSProxy::CheckHasTrap(Isolate* isolate, Handle<Name> name, 3101 Handle<JSReceiver> target) { 3102 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P). 3103 PropertyDescriptor target_desc; 3104 Maybe<bool> target_found = 3105 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 3106 MAYBE_RETURN(target_found, Nothing<bool>()); 3107 // 9b. If targetDesc is not undefined, then: 3108 if (target_found.FromJust()) { 3109 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError 3110 // exception. 3111 if (!target_desc.configurable()) { 3112 isolate->Throw(*isolate->factory()->NewTypeError( 3113 MessageTemplate::kProxyHasNonConfigurable, name)); 3114 return Nothing<bool>(); 3115 } 3116 // 9b ii. Let extensibleTarget be ? IsExtensible(target). 3117 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 3118 MAYBE_RETURN(extensible_target, Nothing<bool>()); 3119 // 9b iii. If extensibleTarget is false, throw a TypeError exception. 3120 if (!extensible_target.FromJust()) { 3121 isolate->Throw(*isolate->factory()->NewTypeError( 3122 MessageTemplate::kProxyHasNonExtensible, name)); 3123 return Nothing<bool>(); 3124 } 3125 } 3126 return Just(true); 3127} 3128 3129Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name, 3130 Handle<Object> value, Handle<Object> receiver, 3131 Maybe<ShouldThrow> should_throw) { 3132 DCHECK(!name->IsPrivate()); 3133 Isolate* isolate = proxy->GetIsolate(); 3134 STACK_CHECK(isolate, Nothing<bool>()); 3135 Factory* factory = isolate->factory(); 3136 Handle<String> trap_name = factory->set_string(); 3137 3138 if (proxy->IsRevoked()) { 3139 isolate->Throw( 3140 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 3141 return Nothing<bool>(); 3142 } 3143 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 3144 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 3145 3146 Handle<Object> trap; 3147 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3148 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 3149 if (trap->IsUndefined(isolate)) { 3150 PropertyKey key(isolate, name); 3151 LookupIterator it(isolate, receiver, key, target); 3152 3153 return Object::SetSuperProperty(&it, value, StoreOrigin::kMaybeKeyed, 3154 should_throw); 3155 } 3156 3157 Handle<Object> trap_result; 3158 Handle<Object> args[] = {target, name, value, receiver}; 3159 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3160 isolate, trap_result, 3161 Execution::Call(isolate, trap, handler, arraysize(args), args), 3162 Nothing<bool>()); 3163 if (!trap_result->BooleanValue(isolate)) { 3164 RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw), 3165 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 3166 trap_name, name)); 3167 } 3168 3169 MaybeHandle<Object> result = 3170 JSProxy::CheckGetSetTrapResult(isolate, name, target, value, kSet); 3171 3172 if (result.is_null()) { 3173 return Nothing<bool>(); 3174 } 3175 return Just(true); 3176} 3177 3178Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy, 3179 Handle<Name> name, 3180 LanguageMode language_mode) { 3181 DCHECK(!name->IsPrivate()); 3182 ShouldThrow should_throw = 3183 is_sloppy(language_mode) ? kDontThrow : kThrowOnError; 3184 Isolate* isolate = proxy->GetIsolate(); 3185 STACK_CHECK(isolate, Nothing<bool>()); 3186 Factory* factory = isolate->factory(); 3187 Handle<String> trap_name = factory->deleteProperty_string(); 3188 3189 if (proxy->IsRevoked()) { 3190 isolate->Throw( 3191 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 3192 return Nothing<bool>(); 3193 } 3194 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 3195 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 3196 3197 Handle<Object> trap; 3198 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3199 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 3200 if (trap->IsUndefined(isolate)) { 3201 return JSReceiver::DeletePropertyOrElement(target, name, language_mode); 3202 } 3203 3204 Handle<Object> trap_result; 3205 Handle<Object> args[] = {target, name}; 3206 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3207 isolate, trap_result, 3208 Execution::Call(isolate, trap, handler, arraysize(args), args), 3209 Nothing<bool>()); 3210 if (!trap_result->BooleanValue(isolate)) { 3211 RETURN_FAILURE(isolate, should_throw, 3212 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 3213 trap_name, name)); 3214 } 3215 3216 // Enforce the invariant. 3217 return JSProxy::CheckDeleteTrap(isolate, name, target); 3218} 3219 3220Maybe<bool> JSProxy::CheckDeleteTrap(Isolate* isolate, Handle<Name> name, 3221 Handle<JSReceiver> target) { 3222 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). 3223 PropertyDescriptor target_desc; 3224 Maybe<bool> target_found = 3225 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 3226 MAYBE_RETURN(target_found, Nothing<bool>()); 3227 // 11. If targetDesc is undefined, return true. 3228 if (target_found.FromJust()) { 3229 // 12. If targetDesc.[[Configurable]] is false, throw a TypeError exception. 3230 if (!target_desc.configurable()) { 3231 isolate->Throw(*isolate->factory()->NewTypeError( 3232 MessageTemplate::kProxyDeletePropertyNonConfigurable, name)); 3233 return Nothing<bool>(); 3234 } 3235 // 13. Let extensibleTarget be ? IsExtensible(target). 3236 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 3237 MAYBE_RETURN(extensible_target, Nothing<bool>()); 3238 // 14. If extensibleTarget is false, throw a TypeError exception. 3239 if (!extensible_target.FromJust()) { 3240 isolate->Throw(*isolate->factory()->NewTypeError( 3241 MessageTemplate::kProxyDeletePropertyNonExtensible, name)); 3242 return Nothing<bool>(); 3243 } 3244 } 3245 return Just(true); 3246} 3247 3248// static 3249MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target, 3250 Handle<Object> handler) { 3251 if (!target->IsJSReceiver()) { 3252 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject), 3253 JSProxy); 3254 } 3255 if (!handler->IsJSReceiver()) { 3256 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject), 3257 JSProxy); 3258 } 3259 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target), 3260 Handle<JSReceiver>::cast(handler)); 3261} 3262 3263Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) { 3264 PropertyDescriptor desc; 3265 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor( 3266 it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc); 3267 MAYBE_RETURN(found, Nothing<PropertyAttributes>()); 3268 if (!found.FromJust()) return Just(ABSENT); 3269 return Just(desc.ToAttributes()); 3270} 3271 3272// TODO(jkummerow): Consider unification with FastAsArrayLength() in 3273// accessors.cc. 3274bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) { 3275 DCHECK(value->IsNumber() || value->IsName()); 3276 if (value->ToArrayLength(length)) return true; 3277 if (value->IsString()) return String::cast(*value).AsArrayIndex(length); 3278 return false; 3279} 3280 3281bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) { 3282 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32; 3283} 3284 3285// ES6 9.4.2.1 3286// static 3287Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o, 3288 Handle<Object> name, 3289 PropertyDescriptor* desc, 3290 Maybe<ShouldThrow> should_throw) { 3291 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.) 3292 // 2. If P is "length", then: 3293 // TODO(jkummerow): Check if we need slow string comparison. 3294 if (*name == ReadOnlyRoots(isolate).length_string()) { 3295 // 2a. Return ArraySetLength(A, Desc). 3296 return ArraySetLength(isolate, o, desc, should_throw); 3297 } 3298 // 3. Else if P is an array index, then: 3299 uint32_t index = 0; 3300 if (PropertyKeyToArrayIndex(name, &index)) { 3301 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). 3302 PropertyDescriptor old_len_desc; 3303 Maybe<bool> success = GetOwnPropertyDescriptor( 3304 isolate, o, isolate->factory()->length_string(), &old_len_desc); 3305 // 3b. (Assert) 3306 DCHECK(success.FromJust()); 3307 USE(success); 3308 // 3c. Let oldLen be oldLenDesc.[[Value]]. 3309 uint32_t old_len = 0; 3310 CHECK(old_len_desc.value()->ToArrayLength(&old_len)); 3311 // 3d. Let index be ToUint32(P). 3312 // (Already done above.) 3313 // 3e. (Assert) 3314 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false, 3315 // return false. 3316 if (index >= old_len && old_len_desc.has_writable() && 3317 !old_len_desc.writable()) { 3318 RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw), 3319 NewTypeError(MessageTemplate::kDefineDisallowed, name)); 3320 } 3321 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc). 3322 Maybe<bool> succeeded = 3323 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); 3324 // 3h. Assert: succeeded is not an abrupt completion. 3325 // In our case, if should_throw == kThrowOnError, it can be! 3326 // 3i. If succeeded is false, return false. 3327 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded; 3328 // 3j. If index >= oldLen, then: 3329 if (index >= old_len) { 3330 // 3j i. Set oldLenDesc.[[Value]] to index + 1. 3331 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1)); 3332 // 3j ii. Let succeeded be 3333 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc). 3334 succeeded = OrdinaryDefineOwnProperty(isolate, o, 3335 isolate->factory()->length_string(), 3336 &old_len_desc, should_throw); 3337 // 3j iii. Assert: succeeded is true. 3338 DCHECK(succeeded.FromJust()); 3339 USE(succeeded); 3340 } 3341 // 3k. Return true. 3342 return Just(true); 3343 } 3344 3345 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc). 3346 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); 3347} 3348 3349// Part of ES6 9.4.2.4 ArraySetLength. 3350// static 3351bool JSArray::AnythingToArrayLength(Isolate* isolate, 3352 Handle<Object> length_object, 3353 uint32_t* output) { 3354 // Fast path: check numbers and strings that can be converted directly 3355 // and unobservably. 3356 if (length_object->ToArrayLength(output)) return true; 3357 if (length_object->IsString() && 3358 Handle<String>::cast(length_object)->AsArrayIndex(output)) { 3359 return true; 3360 } 3361 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength". 3362 // 3. Let newLen be ToUint32(Desc.[[Value]]). 3363 Handle<Object> uint32_v; 3364 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) { 3365 // 4. ReturnIfAbrupt(newLen). 3366 return false; 3367 } 3368 // 5. Let numberLen be ToNumber(Desc.[[Value]]). 3369 Handle<Object> number_v; 3370 if (!Object::ToNumber(isolate, length_object).ToHandle(&number_v)) { 3371 // 6. ReturnIfAbrupt(newLen). 3372 return false; 3373 } 3374 // 7. If newLen != numberLen, throw a RangeError exception. 3375 if (uint32_v->Number() != number_v->Number()) { 3376 Handle<Object> exception = 3377 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength); 3378 isolate->Throw(*exception); 3379 return false; 3380 } 3381 CHECK(uint32_v->ToArrayLength(output)); 3382 return true; 3383} 3384 3385// ES6 9.4.2.4 3386// static 3387Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a, 3388 PropertyDescriptor* desc, 3389 Maybe<ShouldThrow> should_throw) { 3390 // 1. If the [[Value]] field of Desc is absent, then 3391 if (!desc->has_value()) { 3392 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc). 3393 return OrdinaryDefineOwnProperty( 3394 isolate, a, isolate->factory()->length_string(), desc, should_throw); 3395 } 3396 // 2. Let newLenDesc be a copy of Desc. 3397 // (Actual copying is not necessary.) 3398 PropertyDescriptor* new_len_desc = desc; 3399 // 3. - 7. Convert Desc.[[Value]] to newLen. 3400 uint32_t new_len = 0; 3401 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) { 3402 DCHECK(isolate->has_pending_exception()); 3403 return Nothing<bool>(); 3404 } 3405 // 8. Set newLenDesc.[[Value]] to newLen. 3406 // (Done below, if needed.) 3407 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). 3408 PropertyDescriptor old_len_desc; 3409 Maybe<bool> success = GetOwnPropertyDescriptor( 3410 isolate, a, isolate->factory()->length_string(), &old_len_desc); 3411 // 10. (Assert) 3412 DCHECK(success.FromJust()); 3413 USE(success); 3414 // 11. Let oldLen be oldLenDesc.[[Value]]. 3415 uint32_t old_len = 0; 3416 CHECK(old_len_desc.value()->ToArrayLength(&old_len)); 3417 // 12. If newLen >= oldLen, then 3418 if (new_len >= old_len) { 3419 // 8. Set newLenDesc.[[Value]] to newLen. 3420 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc). 3421 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len)); 3422 return OrdinaryDefineOwnProperty(isolate, a, 3423 isolate->factory()->length_string(), 3424 new_len_desc, should_throw); 3425 } 3426 // 13. If oldLenDesc.[[Writable]] is false, return false. 3427 if (!old_len_desc.writable() || 3428 // Also handle the {configurable: true} and enumerable changes 3429 // since we later use JSArray::SetLength instead of 3430 // OrdinaryDefineOwnProperty to change the length, 3431 // and it doesn't have access to the descriptor anymore. 3432 new_len_desc->configurable() || 3433 (new_len_desc->has_enumerable() && 3434 (old_len_desc.enumerable() != new_len_desc->enumerable()))) { 3435 RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw), 3436 NewTypeError(MessageTemplate::kRedefineDisallowed, 3437 isolate->factory()->length_string())); 3438 } 3439 // 14. If newLenDesc.[[Writable]] is absent or has the value true, 3440 // let newWritable be true. 3441 bool new_writable = false; 3442 if (!new_len_desc->has_writable() || new_len_desc->writable()) { 3443 new_writable = true; 3444 } else { 3445 // 15. Else, 3446 // 15a. Need to defer setting the [[Writable]] attribute to false in case 3447 // any elements cannot be deleted. 3448 // 15b. Let newWritable be false. (It's initialized as "false" anyway.) 3449 // 15c. Set newLenDesc.[[Writable]] to true. 3450 // (Not needed.) 3451 } 3452 // Most of steps 16 through 19 is implemented by JSArray::SetLength. 3453 MAYBE_RETURN(JSArray::SetLength(a, new_len), Nothing<bool>()); 3454 // Steps 19d-ii, 20. 3455 if (!new_writable) { 3456 PropertyDescriptor readonly; 3457 readonly.set_writable(false); 3458 success = OrdinaryDefineOwnProperty(isolate, a, 3459 isolate->factory()->length_string(), 3460 &readonly, should_throw); 3461 DCHECK(success.FromJust()); 3462 USE(success); 3463 } 3464 uint32_t actual_new_len = 0; 3465 CHECK(a->length().ToArrayLength(&actual_new_len)); 3466 // Steps 19d-v, 21. Return false if there were non-deletable elements. 3467 bool result = actual_new_len == new_len; 3468 if (!result) { 3469 RETURN_FAILURE( 3470 isolate, GetShouldThrow(isolate, should_throw), 3471 NewTypeError(MessageTemplate::kStrictDeleteProperty, 3472 isolate->factory()->NewNumberFromUint(actual_new_len - 1), 3473 a)); 3474 } 3475 return Just(result); 3476} 3477 3478// ES6 9.5.6 3479// static 3480Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy, 3481 Handle<Object> key, 3482 PropertyDescriptor* desc, 3483 Maybe<ShouldThrow> should_throw) { 3484 STACK_CHECK(isolate, Nothing<bool>()); 3485 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) { 3486 DCHECK(!Handle<Symbol>::cast(key)->IsPrivateName()); 3487 return JSProxy::SetPrivateSymbol(isolate, proxy, Handle<Symbol>::cast(key), 3488 desc, should_throw); 3489 } 3490 Handle<String> trap_name = isolate->factory()->defineProperty_string(); 3491 // 1. Assert: IsPropertyKey(P) is true. 3492 DCHECK(key->IsName() || key->IsNumber()); 3493 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 3494 Handle<Object> handler(proxy->handler(), isolate); 3495 // 3. If handler is null, throw a TypeError exception. 3496 // 4. Assert: Type(handler) is Object. 3497 if (proxy->IsRevoked()) { 3498 isolate->Throw(*isolate->factory()->NewTypeError( 3499 MessageTemplate::kProxyRevoked, trap_name)); 3500 return Nothing<bool>(); 3501 } 3502 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 3503 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 3504 // 6. Let trap be ? GetMethod(handler, "defineProperty"). 3505 Handle<Object> trap; 3506 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3507 isolate, trap, 3508 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 3509 Nothing<bool>()); 3510 // 7. If trap is undefined, then: 3511 if (trap->IsUndefined(isolate)) { 3512 // 7a. Return target.[[DefineOwnProperty]](P, Desc). 3513 return JSReceiver::DefineOwnProperty(isolate, target, key, desc, 3514 should_throw); 3515 } 3516 // 8. Let descObj be FromPropertyDescriptor(Desc). 3517 Handle<Object> desc_obj = desc->ToObject(isolate); 3518 // 9. Let booleanTrapResult be 3519 // ToBoolean(? Call(trap, handler, «target, P, descObj»)). 3520 Handle<Name> property_name = 3521 key->IsName() 3522 ? Handle<Name>::cast(key) 3523 : Handle<Name>::cast(isolate->factory()->NumberToString(key)); 3524 // Do not leak private property names. 3525 DCHECK(!property_name->IsPrivate()); 3526 Handle<Object> trap_result_obj; 3527 Handle<Object> args[] = {target, property_name, desc_obj}; 3528 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3529 isolate, trap_result_obj, 3530 Execution::Call(isolate, trap, handler, arraysize(args), args), 3531 Nothing<bool>()); 3532 // 10. If booleanTrapResult is false, return false. 3533 if (!trap_result_obj->BooleanValue(isolate)) { 3534 RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw), 3535 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 3536 trap_name, property_name)); 3537 } 3538 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P). 3539 PropertyDescriptor target_desc; 3540 Maybe<bool> target_found = 3541 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc); 3542 MAYBE_RETURN(target_found, Nothing<bool>()); 3543 // 12. Let extensibleTarget be ? IsExtensible(target). 3544 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target); 3545 MAYBE_RETURN(maybe_extensible, Nothing<bool>()); 3546 bool extensible_target = maybe_extensible.FromJust(); 3547 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] 3548 // is false, then: 3549 // 13a. Let settingConfigFalse be true. 3550 // 14. Else let settingConfigFalse be false. 3551 bool setting_config_false = desc->has_configurable() && !desc->configurable(); 3552 // 15. If targetDesc is undefined, then 3553 if (!target_found.FromJust()) { 3554 // 15a. If extensibleTarget is false, throw a TypeError exception. 3555 if (!extensible_target) { 3556 isolate->Throw(*isolate->factory()->NewTypeError( 3557 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name)); 3558 return Nothing<bool>(); 3559 } 3560 // 15b. If settingConfigFalse is true, throw a TypeError exception. 3561 if (setting_config_false) { 3562 isolate->Throw(*isolate->factory()->NewTypeError( 3563 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); 3564 return Nothing<bool>(); 3565 } 3566 } else { 3567 // 16. Else targetDesc is not undefined, 3568 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, 3569 // targetDesc) is false, throw a TypeError exception. 3570 Maybe<bool> valid = IsCompatiblePropertyDescriptor( 3571 isolate, extensible_target, desc, &target_desc, property_name, 3572 Just(kDontThrow)); 3573 MAYBE_RETURN(valid, Nothing<bool>()); 3574 if (!valid.FromJust()) { 3575 isolate->Throw(*isolate->factory()->NewTypeError( 3576 MessageTemplate::kProxyDefinePropertyIncompatible, property_name)); 3577 return Nothing<bool>(); 3578 } 3579 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is 3580 // true, throw a TypeError exception. 3581 if (setting_config_false && target_desc.configurable()) { 3582 isolate->Throw(*isolate->factory()->NewTypeError( 3583 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); 3584 return Nothing<bool>(); 3585 } 3586 // 16c. If IsDataDescriptor(targetDesc) is true, 3587 // targetDesc.[[Configurable]] is 3588 // false, and targetDesc.[[Writable]] is true, then 3589 if (PropertyDescriptor::IsDataDescriptor(&target_desc) && 3590 !target_desc.configurable() && target_desc.writable()) { 3591 // 16c i. If Desc has a [[Writable]] field and Desc.[[Writable]] is false, 3592 // throw a TypeError exception. 3593 if (desc->has_writable() && !desc->writable()) { 3594 isolate->Throw(*isolate->factory()->NewTypeError( 3595 MessageTemplate::kProxyDefinePropertyNonConfigurableWritable, 3596 property_name)); 3597 return Nothing<bool>(); 3598 } 3599 } 3600 } 3601 // 17. Return true. 3602 return Just(true); 3603} 3604 3605// static 3606Maybe<bool> JSProxy::SetPrivateSymbol(Isolate* isolate, Handle<JSProxy> proxy, 3607 Handle<Symbol> private_name, 3608 PropertyDescriptor* desc, 3609 Maybe<ShouldThrow> should_throw) { 3610 // Despite the generic name, this can only add private data properties. 3611 if (!PropertyDescriptor::IsDataDescriptor(desc) || 3612 desc->ToAttributes() != DONT_ENUM) { 3613 RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw), 3614 NewTypeError(MessageTemplate::kProxyPrivate)); 3615 } 3616 DCHECK(proxy->map().is_dictionary_map()); 3617 Handle<Object> value = 3618 desc->has_value() 3619 ? desc->value() 3620 : Handle<Object>::cast(isolate->factory()->undefined_value()); 3621 3622 LookupIterator it(isolate, proxy, private_name, proxy); 3623 3624 if (it.IsFound()) { 3625 DCHECK_EQ(LookupIterator::DATA, it.state()); 3626 DCHECK_EQ(DONT_ENUM, it.property_attributes()); 3627 // We are not tracking constness for private symbols added to JSProxy 3628 // objects. 3629 DCHECK_EQ(PropertyConstness::kMutable, it.property_details().constness()); 3630 it.WriteDataValue(value, false); 3631 return Just(true); 3632 } 3633 3634 PropertyDetails details(PropertyKind::kData, DONT_ENUM, 3635 PropertyConstness::kMutable); 3636 if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { 3637 Handle<SwissNameDictionary> dict(proxy->property_dictionary_swiss(), 3638 isolate); 3639 Handle<SwissNameDictionary> result = 3640 SwissNameDictionary::Add(isolate, dict, private_name, value, details); 3641 if (!dict.is_identical_to(result)) proxy->SetProperties(*result); 3642 } else { 3643 Handle<NameDictionary> dict(proxy->property_dictionary(), isolate); 3644 Handle<NameDictionary> result = 3645 NameDictionary::Add(isolate, dict, private_name, value, details); 3646 if (!dict.is_identical_to(result)) proxy->SetProperties(*result); 3647 } 3648 return Just(true); 3649} 3650 3651// ES6 9.5.5 3652// static 3653Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate, 3654 Handle<JSProxy> proxy, 3655 Handle<Name> name, 3656 PropertyDescriptor* desc) { 3657 DCHECK(!name->IsPrivate()); 3658 STACK_CHECK(isolate, Nothing<bool>()); 3659 3660 Handle<String> trap_name = 3661 isolate->factory()->getOwnPropertyDescriptor_string(); 3662 // 1. (Assert) 3663 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 3664 Handle<Object> handler(proxy->handler(), isolate); 3665 // 3. If handler is null, throw a TypeError exception. 3666 // 4. Assert: Type(handler) is Object. 3667 if (proxy->IsRevoked()) { 3668 isolate->Throw(*isolate->factory()->NewTypeError( 3669 MessageTemplate::kProxyRevoked, trap_name)); 3670 return Nothing<bool>(); 3671 } 3672 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 3673 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 3674 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor"). 3675 Handle<Object> trap; 3676 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3677 isolate, trap, 3678 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 3679 Nothing<bool>()); 3680 // 7. If trap is undefined, then 3681 if (trap->IsUndefined(isolate)) { 3682 // 7a. Return target.[[GetOwnProperty]](P). 3683 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc); 3684 } 3685 // 8. Let trapResultObj be ? Call(trap, handler, «target, P»). 3686 Handle<Object> trap_result_obj; 3687 Handle<Object> args[] = {target, name}; 3688 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3689 isolate, trap_result_obj, 3690 Execution::Call(isolate, trap, handler, arraysize(args), args), 3691 Nothing<bool>()); 3692 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a 3693 // TypeError exception. 3694 if (!trap_result_obj->IsJSReceiver() && 3695 !trap_result_obj->IsUndefined(isolate)) { 3696 isolate->Throw(*isolate->factory()->NewTypeError( 3697 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name)); 3698 return Nothing<bool>(); 3699 } 3700 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). 3701 PropertyDescriptor target_desc; 3702 Maybe<bool> found = 3703 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 3704 MAYBE_RETURN(found, Nothing<bool>()); 3705 // 11. If trapResultObj is undefined, then 3706 if (trap_result_obj->IsUndefined(isolate)) { 3707 // 11a. If targetDesc is undefined, return undefined. 3708 if (!found.FromJust()) return Just(false); 3709 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError 3710 // exception. 3711 if (!target_desc.configurable()) { 3712 isolate->Throw(*isolate->factory()->NewTypeError( 3713 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name)); 3714 return Nothing<bool>(); 3715 } 3716 // 11c. Let extensibleTarget be ? IsExtensible(target). 3717 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 3718 MAYBE_RETURN(extensible_target, Nothing<bool>()); 3719 // 11d. (Assert) 3720 // 11e. If extensibleTarget is false, throw a TypeError exception. 3721 if (!extensible_target.FromJust()) { 3722 isolate->Throw(*isolate->factory()->NewTypeError( 3723 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name)); 3724 return Nothing<bool>(); 3725 } 3726 // 11f. Return undefined. 3727 return Just(false); 3728 } 3729 // 12. Let extensibleTarget be ? IsExtensible(target). 3730 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 3731 MAYBE_RETURN(extensible_target, Nothing<bool>()); 3732 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj). 3733 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj, 3734 desc)) { 3735 DCHECK(isolate->has_pending_exception()); 3736 return Nothing<bool>(); 3737 } 3738 // 14. Call CompletePropertyDescriptor(resultDesc). 3739 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc); 3740 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget, 3741 // resultDesc, targetDesc). 3742 Maybe<bool> valid = IsCompatiblePropertyDescriptor( 3743 isolate, extensible_target.FromJust(), desc, &target_desc, name, 3744 Just(kDontThrow)); 3745 MAYBE_RETURN(valid, Nothing<bool>()); 3746 // 16. If valid is false, throw a TypeError exception. 3747 if (!valid.FromJust()) { 3748 isolate->Throw(*isolate->factory()->NewTypeError( 3749 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name)); 3750 return Nothing<bool>(); 3751 } 3752 // 17. If resultDesc.[[Configurable]] is false, then 3753 if (!desc->configurable()) { 3754 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true: 3755 if (target_desc.is_empty() || target_desc.configurable()) { 3756 // 17a i. Throw a TypeError exception. 3757 isolate->Throw(*isolate->factory()->NewTypeError( 3758 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable, 3759 name)); 3760 return Nothing<bool>(); 3761 } 3762 // 17b. If resultDesc has a [[Writable]] field and resultDesc.[[Writable]] 3763 // is false, then 3764 if (desc->has_writable() && !desc->writable()) { 3765 // 17b i. If targetDesc.[[Writable]] is true, throw a TypeError exception. 3766 if (target_desc.writable()) { 3767 isolate->Throw(*isolate->factory()->NewTypeError( 3768 MessageTemplate:: 3769 kProxyGetOwnPropertyDescriptorNonConfigurableWritable, 3770 name)); 3771 return Nothing<bool>(); 3772 } 3773 } 3774 } 3775 // 18. Return resultDesc. 3776 return Just(true); 3777} 3778 3779Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy, 3780 ShouldThrow should_throw) { 3781 Isolate* isolate = proxy->GetIsolate(); 3782 STACK_CHECK(isolate, Nothing<bool>()); 3783 Factory* factory = isolate->factory(); 3784 Handle<String> trap_name = factory->preventExtensions_string(); 3785 3786 if (proxy->IsRevoked()) { 3787 isolate->Throw( 3788 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 3789 return Nothing<bool>(); 3790 } 3791 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 3792 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 3793 3794 Handle<Object> trap; 3795 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3796 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 3797 if (trap->IsUndefined(isolate)) { 3798 return JSReceiver::PreventExtensions(target, should_throw); 3799 } 3800 3801 Handle<Object> trap_result; 3802 Handle<Object> args[] = {target}; 3803 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3804 isolate, trap_result, 3805 Execution::Call(isolate, trap, handler, arraysize(args), args), 3806 Nothing<bool>()); 3807 if (!trap_result->BooleanValue(isolate)) { 3808 RETURN_FAILURE( 3809 isolate, should_throw, 3810 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 3811 } 3812 3813 // Enforce the invariant. 3814 Maybe<bool> target_result = JSReceiver::IsExtensible(target); 3815 MAYBE_RETURN(target_result, Nothing<bool>()); 3816 if (target_result.FromJust()) { 3817 isolate->Throw(*factory->NewTypeError( 3818 MessageTemplate::kProxyPreventExtensionsExtensible)); 3819 return Nothing<bool>(); 3820 } 3821 return Just(true); 3822} 3823 3824Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) { 3825 Isolate* isolate = proxy->GetIsolate(); 3826 STACK_CHECK(isolate, Nothing<bool>()); 3827 Factory* factory = isolate->factory(); 3828 Handle<String> trap_name = factory->isExtensible_string(); 3829 3830 if (proxy->IsRevoked()) { 3831 isolate->Throw( 3832 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 3833 return Nothing<bool>(); 3834 } 3835 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 3836 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 3837 3838 Handle<Object> trap; 3839 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3840 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 3841 if (trap->IsUndefined(isolate)) { 3842 return JSReceiver::IsExtensible(target); 3843 } 3844 3845 Handle<Object> trap_result; 3846 Handle<Object> args[] = {target}; 3847 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 3848 isolate, trap_result, 3849 Execution::Call(isolate, trap, handler, arraysize(args), args), 3850 Nothing<bool>()); 3851 3852 // Enforce the invariant. 3853 Maybe<bool> target_result = JSReceiver::IsExtensible(target); 3854 MAYBE_RETURN(target_result, Nothing<bool>()); 3855 if (target_result.FromJust() != trap_result->BooleanValue(isolate)) { 3856 isolate->Throw( 3857 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent, 3858 factory->ToBoolean(target_result.FromJust()))); 3859 return Nothing<bool>(); 3860 } 3861 return target_result; 3862} 3863 3864Handle<DescriptorArray> DescriptorArray::CopyUpTo(Isolate* isolate, 3865 Handle<DescriptorArray> desc, 3866 int enumeration_index, 3867 int slack) { 3868 return DescriptorArray::CopyUpToAddAttributes(isolate, desc, 3869 enumeration_index, NONE, slack); 3870} 3871 3872Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes( 3873 Isolate* isolate, Handle<DescriptorArray> source_handle, 3874 int enumeration_index, PropertyAttributes attributes, int slack) { 3875 if (enumeration_index + slack == 0) { 3876 return isolate->factory()->empty_descriptor_array(); 3877 } 3878 3879 int size = enumeration_index; 3880 Handle<DescriptorArray> copy_handle = 3881 DescriptorArray::Allocate(isolate, size, slack); 3882 3883 DisallowGarbageCollection no_gc; 3884 auto source = *source_handle; 3885 auto copy = *copy_handle; 3886 3887 if (attributes != NONE) { 3888 for (InternalIndex i : InternalIndex::Range(size)) { 3889 MaybeObject value_or_field_type = source.GetValue(i); 3890 Name key = source.GetKey(i); 3891 PropertyDetails details = source.GetDetails(i); 3892 // Bulk attribute changes never affect private properties. 3893 if (!key.IsPrivate()) { 3894 int mask = DONT_DELETE | DONT_ENUM; 3895 // READ_ONLY is an invalid attribute for JS setters/getters. 3896 HeapObject heap_object; 3897 if (details.kind() != PropertyKind::kAccessor || 3898 !(value_or_field_type->GetHeapObjectIfStrong(&heap_object) && 3899 heap_object.IsAccessorPair())) { 3900 mask |= READ_ONLY; 3901 } 3902 details = details.CopyAddAttributes( 3903 static_cast<PropertyAttributes>(attributes & mask)); 3904 } 3905 copy.Set(i, key, value_or_field_type, details); 3906 } 3907 } else { 3908 for (InternalIndex i : InternalIndex::Range(size)) { 3909 copy.CopyFrom(i, source); 3910 } 3911 } 3912 3913 if (source.number_of_descriptors() != enumeration_index) copy.Sort(); 3914 3915 return copy_handle; 3916} 3917 3918// Create a new descriptor array with only enumerable, configurable, writeable 3919// data properties, but identical field locations. 3920Handle<DescriptorArray> DescriptorArray::CopyForFastObjectClone( 3921 Isolate* isolate, Handle<DescriptorArray> src_handle, int enumeration_index, 3922 int slack) { 3923 if (enumeration_index + slack == 0) { 3924 return isolate->factory()->empty_descriptor_array(); 3925 } 3926 3927 int size = enumeration_index; 3928 Handle<DescriptorArray> descriptors_handle = 3929 DescriptorArray::Allocate(isolate, size, slack); 3930 3931 DisallowGarbageCollection no_gc; 3932 auto src = *src_handle; 3933 auto descriptors = *descriptors_handle; 3934 3935 for (InternalIndex i : InternalIndex::Range(size)) { 3936 Name key = src.GetKey(i); 3937 PropertyDetails details = src.GetDetails(i); 3938 Representation new_representation = details.representation(); 3939 3940 DCHECK(!key.IsPrivateName()); 3941 DCHECK(details.IsEnumerable()); 3942 DCHECK_EQ(details.kind(), PropertyKind::kData); 3943 // If the new representation is an in-place changeable field, make it 3944 // generic as possible (under in-place changes) to avoid type confusion if 3945 // the source representation changes after this feedback has been collected. 3946 MaybeObject type = src.GetValue(i); 3947 if (details.location() == PropertyLocation::kField) { 3948 type = MaybeObject::FromObject(FieldType::Any()); 3949 // TODO(bmeurer,ishell): Igor suggested to use some kind of dynamic 3950 // checks in the fast-path for CloneObjectIC instead to avoid the 3951 // need to generalize the descriptors here. That will also enable 3952 // us to skip the defensive copying of the target map whenever a 3953 // CloneObjectIC misses. 3954 new_representation = new_representation.MostGenericInPlaceChange(); 3955 } 3956 3957 // Ensure the ObjectClone property details are NONE, and that all source 3958 // details did not contain DONT_ENUM. 3959 PropertyDetails new_details(PropertyKind::kData, NONE, details.location(), 3960 details.constness(), new_representation, 3961 details.field_index()); 3962 3963 descriptors.Set(i, key, type, new_details); 3964 } 3965 3966 descriptors.Sort(); 3967 3968 return descriptors_handle; 3969} 3970 3971bool DescriptorArray::IsEqualUpTo(DescriptorArray desc, int nof_descriptors) { 3972 for (InternalIndex i : InternalIndex::Range(nof_descriptors)) { 3973 if (GetKey(i) != desc.GetKey(i) || GetValue(i) != desc.GetValue(i)) { 3974 return false; 3975 } 3976 PropertyDetails details = GetDetails(i); 3977 PropertyDetails other_details = desc.GetDetails(i); 3978 if (details.kind() != other_details.kind() || 3979 details.location() != other_details.location() || 3980 !details.representation().Equals(other_details.representation())) { 3981 return false; 3982 } 3983 } 3984 return true; 3985} 3986 3987Handle<FixedArray> FixedArray::SetAndGrow(Isolate* isolate, 3988 Handle<FixedArray> array, int index, 3989 Handle<Object> value) { 3990 if (index < array->length()) { 3991 array->set(index, *value); 3992 return array; 3993 } 3994 int capacity = array->length(); 3995 do { 3996 capacity = JSObject::NewElementsCapacity(capacity); 3997 } while (capacity <= index); 3998 Handle<FixedArray> new_array = isolate->factory()->NewFixedArray(capacity); 3999 array->CopyTo(0, *new_array, 0, array->length()); 4000 new_array->FillWithHoles(array->length(), new_array->length()); 4001 new_array->set(index, *value); 4002 return new_array; 4003} 4004 4005Handle<FixedArray> FixedArray::ShrinkOrEmpty(Isolate* isolate, 4006 Handle<FixedArray> array, 4007 int new_length) { 4008 if (new_length == 0) { 4009 return array->GetReadOnlyRoots().empty_fixed_array_handle(); 4010 } else { 4011 array->Shrink(isolate, new_length); 4012 return array; 4013 } 4014} 4015 4016void FixedArray::Shrink(Isolate* isolate, int new_length) { 4017 DCHECK(0 < new_length && new_length <= length()); 4018 if (new_length < length()) { 4019 isolate->heap()->RightTrimFixedArray(*this, length() - new_length); 4020 } 4021} 4022 4023void FixedArray::CopyTo(int pos, FixedArray dest, int dest_pos, int len) const { 4024 DisallowGarbageCollection no_gc; 4025 // Return early if len == 0 so that we don't try to read the write barrier off 4026 // a canonical read-only empty fixed array. 4027 if (len == 0) return; 4028 WriteBarrierMode mode = dest.GetWriteBarrierMode(no_gc); 4029 for (int index = 0; index < len; index++) { 4030 dest.set(dest_pos + index, get(pos + index), mode); 4031 } 4032} 4033 4034// static 4035Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array, 4036 Handle<Object> obj) { 4037 int length = array->Length(); 4038 array = EnsureSpace(isolate, array, length + 1); 4039 // Check that GC didn't remove elements from the array. 4040 DCHECK_EQ(array->Length(), length); 4041 { 4042 DisallowGarbageCollection no_gc; 4043 ArrayList raw_array = *array; 4044 raw_array.Set(length, *obj); 4045 raw_array.SetLength(length + 1); 4046 } 4047 return array; 4048} 4049 4050// static 4051Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array, 4052 Handle<Object> obj1, Handle<Object> obj2) { 4053 int length = array->Length(); 4054 array = EnsureSpace(isolate, array, length + 2); 4055 // Check that GC didn't remove elements from the array. 4056 DCHECK_EQ(array->Length(), length); 4057 { 4058 DisallowGarbageCollection no_gc; 4059 ArrayList raw_array = *array; 4060 raw_array.Set(length, *obj1); 4061 raw_array.Set(length + 1, *obj2); 4062 raw_array.SetLength(length + 2); 4063 } 4064 return array; 4065} 4066 4067Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array, 4068 Handle<Object> obj1, Smi obj2, Smi obj3, 4069 Smi obj4) { 4070 int length = array->Length(); 4071 array = EnsureSpace(isolate, array, length + 4); 4072 // Check that GC didn't remove elements from the array. 4073 DCHECK_EQ(array->Length(), length); 4074 { 4075 DisallowGarbageCollection no_gc; 4076 ArrayList raw_array = *array; 4077 raw_array.Set(length, *obj1); 4078 raw_array.Set(length + 1, obj2); 4079 raw_array.Set(length + 2, obj3); 4080 raw_array.Set(length + 3, obj4); 4081 raw_array.SetLength(length + 4); 4082 } 4083 return array; 4084} 4085 4086// static 4087Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) { 4088 return isolate->factory()->NewArrayList(size); 4089} 4090 4091Handle<FixedArray> ArrayList::Elements(Isolate* isolate, 4092 Handle<ArrayList> array) { 4093 int length = array->Length(); 4094 Handle<FixedArray> result = isolate->factory()->NewFixedArray(length); 4095 // Do not copy the first entry, i.e., the length. 4096 array->CopyTo(kFirstIndex, *result, 0, length); 4097 return result; 4098} 4099 4100namespace { 4101 4102Handle<FixedArray> EnsureSpaceInFixedArray(Isolate* isolate, 4103 Handle<FixedArray> array, 4104 int length) { 4105 int capacity = array->length(); 4106 if (capacity < length) { 4107 int new_capacity = length; 4108 new_capacity = new_capacity + std::max(new_capacity / 2, 2); 4109 int grow_by = new_capacity - capacity; 4110 array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by); 4111 } 4112 return array; 4113} 4114 4115} // namespace 4116 4117// static 4118Handle<ArrayList> ArrayList::EnsureSpace(Isolate* isolate, 4119 Handle<ArrayList> array, int length) { 4120 DCHECK_LT(0, length); 4121 auto new_array = Handle<ArrayList>::cast( 4122 EnsureSpaceInFixedArray(isolate, array, kFirstIndex + length)); 4123 DCHECK_EQ(array->Length(), new_array->Length()); 4124 return new_array; 4125} 4126 4127// static 4128Handle<WeakArrayList> WeakArrayList::AddToEnd(Isolate* isolate, 4129 Handle<WeakArrayList> array, 4130 const MaybeObjectHandle& value) { 4131 int length = array->length(); 4132 array = EnsureSpace(isolate, array, length + 1); 4133 { 4134 DisallowGarbageCollection no_gc; 4135 WeakArrayList raw = *array; 4136 // Reload length; GC might have removed elements from the array. 4137 length = raw.length(); 4138 raw.Set(length, *value); 4139 raw.set_length(length + 1); 4140 } 4141 return array; 4142} 4143 4144Handle<WeakArrayList> WeakArrayList::AddToEnd(Isolate* isolate, 4145 Handle<WeakArrayList> array, 4146 const MaybeObjectHandle& value1, 4147 const MaybeObjectHandle& value2) { 4148 int length = array->length(); 4149 array = EnsureSpace(isolate, array, length + 2); 4150 { 4151 DisallowGarbageCollection no_gc; 4152 WeakArrayList raw = *array; 4153 // Reload length; GC might have removed elements from the array. 4154 length = array->length(); 4155 raw.Set(length, *value1); 4156 raw.Set(length + 1, *value2); 4157 raw.set_length(length + 2); 4158 } 4159 return array; 4160} 4161 4162// static 4163Handle<WeakArrayList> WeakArrayList::Append(Isolate* isolate, 4164 Handle<WeakArrayList> array, 4165 const MaybeObjectHandle& value, 4166 AllocationType allocation) { 4167 int length = 0; 4168 int new_length = 0; 4169 { 4170 DisallowGarbageCollection no_gc; 4171 WeakArrayList raw = *array; 4172 length = raw.length(); 4173 4174 if (length < raw.capacity()) { 4175 raw.Set(length, *value); 4176 raw.set_length(length + 1); 4177 return array; 4178 } 4179 4180 // Not enough space in the array left, either grow, shrink or 4181 // compact the array. 4182 new_length = raw.CountLiveElements() + 1; 4183 } 4184 4185 bool shrink = new_length < length / 4; 4186 bool grow = 3 * (length / 4) < new_length; 4187 4188 if (shrink || grow) { 4189 // Grow or shrink array and compact out-of-place. 4190 int new_capacity = CapacityForLength(new_length); 4191 array = isolate->factory()->CompactWeakArrayList(array, new_capacity, 4192 allocation); 4193 4194 } else { 4195 // Perform compaction in the current array. 4196 array->Compact(isolate); 4197 } 4198 4199 // Now append value to the array, there should always be enough space now. 4200 DCHECK_LT(array->length(), array->capacity()); 4201 4202 { 4203 DisallowGarbageCollection no_gc; 4204 WeakArrayList raw = *array; 4205 // Reload length, allocation might have killed some weak refs. 4206 int index = raw.length(); 4207 raw.Set(index, *value); 4208 raw.set_length(index + 1); 4209 } 4210 return array; 4211} 4212 4213void WeakArrayList::Compact(Isolate* isolate) { 4214 DisallowGarbageCollection no_gc; 4215 int length = this->length(); 4216 int new_length = 0; 4217 4218 for (int i = 0; i < length; i++) { 4219 MaybeObject value = Get(isolate, i); 4220 4221 if (!value->IsCleared()) { 4222 if (new_length != i) { 4223 Set(new_length, value); 4224 } 4225 ++new_length; 4226 } 4227 } 4228 4229 set_length(new_length); 4230} 4231 4232bool WeakArrayList::IsFull() const { return length() == capacity(); } 4233 4234// static 4235Handle<WeakArrayList> WeakArrayList::EnsureSpace(Isolate* isolate, 4236 Handle<WeakArrayList> array, 4237 int length, 4238 AllocationType allocation) { 4239 int capacity = array->capacity(); 4240 if (capacity < length) { 4241 int grow_by = CapacityForLength(length) - capacity; 4242 array = isolate->factory()->CopyWeakArrayListAndGrow(array, grow_by, 4243 allocation); 4244 } 4245 return array; 4246} 4247 4248int WeakArrayList::CountLiveWeakReferences() const { 4249 int live_weak_references = 0; 4250 for (int i = 0; i < length(); i++) { 4251 if (Get(i)->IsWeak()) { 4252 ++live_weak_references; 4253 } 4254 } 4255 return live_weak_references; 4256} 4257 4258int WeakArrayList::CountLiveElements() const { 4259 int non_cleared_objects = 0; 4260 for (int i = 0; i < length(); i++) { 4261 if (!Get(i)->IsCleared()) { 4262 ++non_cleared_objects; 4263 } 4264 } 4265 return non_cleared_objects; 4266} 4267 4268bool WeakArrayList::RemoveOne(const MaybeObjectHandle& value) { 4269 if (length() == 0) return false; 4270 // Optimize for the most recently added element to be removed again. 4271 MaybeObject cleared_weak_ref = 4272 HeapObjectReference::ClearedValue(GetIsolate()); 4273 int last_index = length() - 1; 4274 for (int i = last_index; i >= 0; --i) { 4275 if (Get(i) == *value) { 4276 // Move the last element into the this slot (or no-op, if this is the 4277 // last slot). 4278 Set(i, Get(last_index)); 4279 Set(last_index, cleared_weak_ref); 4280 set_length(last_index); 4281 return true; 4282 } 4283 } 4284 return false; 4285} 4286 4287// static 4288Handle<WeakArrayList> PrototypeUsers::Add(Isolate* isolate, 4289 Handle<WeakArrayList> array, 4290 Handle<Map> value, 4291 int* assigned_index) { 4292 int length = array->length(); 4293 if (length == 0) { 4294 // Uninitialized WeakArrayList; need to initialize empty_slot_index. 4295 array = WeakArrayList::EnsureSpace(isolate, array, kFirstIndex + 1); 4296 set_empty_slot_index(*array, kNoEmptySlotsMarker); 4297 array->Set(kFirstIndex, HeapObjectReference::Weak(*value)); 4298 array->set_length(kFirstIndex + 1); 4299 if (assigned_index != nullptr) *assigned_index = kFirstIndex; 4300 return array; 4301 } 4302 4303 // If the array has unfilled space at the end, use it. 4304 if (!array->IsFull()) { 4305 array->Set(length, HeapObjectReference::Weak(*value)); 4306 array->set_length(length + 1); 4307 if (assigned_index != nullptr) *assigned_index = length; 4308 return array; 4309 } 4310 4311 // If there are empty slots, use one of them. 4312 int empty_slot = Smi::ToInt(empty_slot_index(*array)); 4313 4314 if (empty_slot == kNoEmptySlotsMarker) { 4315 // GCs might have cleared some references, rescan the array for empty slots. 4316 PrototypeUsers::ScanForEmptySlots(*array); 4317 empty_slot = Smi::ToInt(empty_slot_index(*array)); 4318 } 4319 4320 if (empty_slot != kNoEmptySlotsMarker) { 4321 DCHECK_GE(empty_slot, kFirstIndex); 4322 CHECK_LT(empty_slot, array->length()); 4323 int next_empty_slot = array->Get(empty_slot).ToSmi().value(); 4324 4325 array->Set(empty_slot, HeapObjectReference::Weak(*value)); 4326 if (assigned_index != nullptr) *assigned_index = empty_slot; 4327 4328 set_empty_slot_index(*array, next_empty_slot); 4329 return array; 4330 } else { 4331 DCHECK_EQ(empty_slot, kNoEmptySlotsMarker); 4332 } 4333 4334 // Array full and no empty slots. Grow the array. 4335 array = WeakArrayList::EnsureSpace(isolate, array, length + 1); 4336 array->Set(length, HeapObjectReference::Weak(*value)); 4337 array->set_length(length + 1); 4338 if (assigned_index != nullptr) *assigned_index = length; 4339 return array; 4340} 4341 4342// static 4343void PrototypeUsers::ScanForEmptySlots(WeakArrayList array) { 4344 for (int i = kFirstIndex; i < array.length(); i++) { 4345 if (array.Get(i)->IsCleared()) { 4346 PrototypeUsers::MarkSlotEmpty(array, i); 4347 } 4348 } 4349} 4350 4351WeakArrayList PrototypeUsers::Compact(Handle<WeakArrayList> array, Heap* heap, 4352 CompactionCallback callback, 4353 AllocationType allocation) { 4354 if (array->length() == 0) { 4355 return *array; 4356 } 4357 int new_length = kFirstIndex + array->CountLiveWeakReferences(); 4358 if (new_length == array->length()) { 4359 return *array; 4360 } 4361 4362 Handle<WeakArrayList> new_array = WeakArrayList::EnsureSpace( 4363 heap->isolate(), 4364 handle(ReadOnlyRoots(heap).empty_weak_array_list(), heap->isolate()), 4365 new_length, allocation); 4366 // Allocation might have caused GC and turned some of the elements into 4367 // cleared weak heap objects. Count the number of live objects again. 4368 int copy_to = kFirstIndex; 4369 for (int i = kFirstIndex; i < array->length(); i++) { 4370 MaybeObject element = array->Get(i); 4371 HeapObject value; 4372 if (element->GetHeapObjectIfWeak(&value)) { 4373 callback(value, i, copy_to); 4374 new_array->Set(copy_to++, element); 4375 } else { 4376 DCHECK(element->IsCleared() || element->IsSmi()); 4377 } 4378 } 4379 new_array->set_length(copy_to); 4380 set_empty_slot_index(*new_array, kNoEmptySlotsMarker); 4381 return *new_array; 4382} 4383 4384Handle<RegExpMatchInfo> RegExpMatchInfo::New(Isolate* isolate, 4385 int capture_count) { 4386 Handle<RegExpMatchInfo> match_info = isolate->factory()->NewRegExpMatchInfo(); 4387 return ReserveCaptures(isolate, match_info, capture_count); 4388} 4389 4390Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures( 4391 Isolate* isolate, Handle<RegExpMatchInfo> match_info, int capture_count) { 4392 DCHECK_GE(match_info->length(), kLastMatchOverhead); 4393 4394 int capture_register_count = 4395 JSRegExp::RegistersForCaptureCount(capture_count); 4396 const int required_length = kFirstCaptureIndex + capture_register_count; 4397 Handle<RegExpMatchInfo> result = Handle<RegExpMatchInfo>::cast( 4398 EnsureSpaceInFixedArray(isolate, match_info, required_length)); 4399 result->SetNumberOfCaptureRegisters(capture_register_count); 4400 return result; 4401} 4402 4403template <typename IsolateT> 4404Handle<DescriptorArray> DescriptorArray::Allocate(IsolateT* isolate, 4405 int nof_descriptors, 4406 int slack, 4407 AllocationType allocation) { 4408 return nof_descriptors + slack == 0 4409 ? isolate->factory()->empty_descriptor_array() 4410 : isolate->factory()->NewDescriptorArray(nof_descriptors, slack, 4411 allocation); 4412} 4413template Handle<DescriptorArray> DescriptorArray::Allocate( 4414 Isolate* isolate, int nof_descriptors, int slack, 4415 AllocationType allocation); 4416template Handle<DescriptorArray> DescriptorArray::Allocate( 4417 LocalIsolate* isolate, int nof_descriptors, int slack, 4418 AllocationType allocation); 4419 4420void DescriptorArray::Initialize(EnumCache empty_enum_cache, 4421 HeapObject undefined_value, 4422 int nof_descriptors, int slack) { 4423 DCHECK_GE(nof_descriptors, 0); 4424 DCHECK_GE(slack, 0); 4425 DCHECK_LE(nof_descriptors + slack, kMaxNumberOfDescriptors); 4426 set_number_of_all_descriptors(nof_descriptors + slack); 4427 set_number_of_descriptors(nof_descriptors); 4428 set_raw_number_of_marked_descriptors(0); 4429 set_filler16bits(0); 4430 set_enum_cache(empty_enum_cache, SKIP_WRITE_BARRIER); 4431 MemsetTagged(GetDescriptorSlot(0), undefined_value, 4432 number_of_all_descriptors() * kEntrySize); 4433} 4434 4435void DescriptorArray::ClearEnumCache() { 4436 set_enum_cache(GetReadOnlyRoots().empty_enum_cache(), SKIP_WRITE_BARRIER); 4437} 4438 4439void DescriptorArray::Replace(InternalIndex index, Descriptor* descriptor) { 4440 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index.as_int())); 4441 Set(index, descriptor); 4442} 4443 4444// static 4445void DescriptorArray::InitializeOrChangeEnumCache( 4446 Handle<DescriptorArray> descriptors, Isolate* isolate, 4447 Handle<FixedArray> keys, Handle<FixedArray> indices) { 4448 EnumCache enum_cache = descriptors->enum_cache(); 4449 if (enum_cache == ReadOnlyRoots(isolate).empty_enum_cache()) { 4450 enum_cache = *isolate->factory()->NewEnumCache(keys, indices); 4451 descriptors->set_enum_cache(enum_cache); 4452 } else { 4453 enum_cache.set_keys(*keys); 4454 enum_cache.set_indices(*indices); 4455 } 4456} 4457 4458void DescriptorArray::CopyFrom(InternalIndex index, DescriptorArray src) { 4459 PropertyDetails details = src.GetDetails(index); 4460 Set(index, src.GetKey(index), src.GetValue(index), details); 4461} 4462 4463void DescriptorArray::Sort() { 4464 // In-place heap sort. 4465 const int len = number_of_descriptors(); 4466 // Reset sorting since the descriptor array might contain invalid pointers. 4467 for (int i = 0; i < len; ++i) SetSortedKey(i, i); 4468 // Bottom-up max-heap construction. 4469 // Index of the last node with children. 4470 int max_parent_index = (len / 2) - 1; 4471 for (int i = max_parent_index; i >= 0; --i) { 4472 int parent_index = i; 4473 const uint32_t parent_hash = GetSortedKey(i).hash(); 4474 while (parent_index <= max_parent_index) { 4475 int child_index = 2 * parent_index + 1; 4476 uint32_t child_hash = GetSortedKey(child_index).hash(); 4477 if (child_index + 1 < len) { 4478 uint32_t right_child_hash = GetSortedKey(child_index + 1).hash(); 4479 if (right_child_hash > child_hash) { 4480 child_index++; 4481 child_hash = right_child_hash; 4482 } 4483 } 4484 if (child_hash <= parent_hash) break; 4485 SwapSortedKeys(parent_index, child_index); 4486 // Now element at child_index could be < its children. 4487 parent_index = child_index; // parent_hash remains correct. 4488 } 4489 } 4490 4491 // Extract elements and create sorted array. 4492 for (int i = len - 1; i > 0; --i) { 4493 // Put max element at the back of the array. 4494 SwapSortedKeys(0, i); 4495 // Shift down the new top element. 4496 int parent_index = 0; 4497 const uint32_t parent_hash = GetSortedKey(parent_index).hash(); 4498 max_parent_index = (i / 2) - 1; 4499 while (parent_index <= max_parent_index) { 4500 int child_index = parent_index * 2 + 1; 4501 uint32_t child_hash = GetSortedKey(child_index).hash(); 4502 if (child_index + 1 < i) { 4503 uint32_t right_child_hash = GetSortedKey(child_index + 1).hash(); 4504 if (right_child_hash > child_hash) { 4505 child_index++; 4506 child_hash = right_child_hash; 4507 } 4508 } 4509 if (child_hash <= parent_hash) break; 4510 SwapSortedKeys(parent_index, child_index); 4511 parent_index = child_index; 4512 } 4513 } 4514 DCHECK(IsSortedNoDuplicates()); 4515} 4516 4517int16_t DescriptorArray::UpdateNumberOfMarkedDescriptors( 4518 unsigned mark_compact_epoch, int16_t new_marked) { 4519 STATIC_ASSERT(kMaxNumberOfDescriptors <= 4520 NumberOfMarkedDescriptors::kMaxNumberOfMarkedDescriptors); 4521 int16_t old_raw_marked = raw_number_of_marked_descriptors(); 4522 int16_t old_marked = 4523 NumberOfMarkedDescriptors::decode(mark_compact_epoch, old_raw_marked); 4524 int16_t new_raw_marked = 4525 NumberOfMarkedDescriptors::encode(mark_compact_epoch, new_marked); 4526 while (old_marked < new_marked) { 4527 int16_t actual_raw_marked = CompareAndSwapRawNumberOfMarkedDescriptors( 4528 old_raw_marked, new_raw_marked); 4529 if (actual_raw_marked == old_raw_marked) { 4530 break; 4531 } 4532 old_raw_marked = actual_raw_marked; 4533 old_marked = 4534 NumberOfMarkedDescriptors::decode(mark_compact_epoch, old_raw_marked); 4535 } 4536 return old_marked; 4537} 4538 4539Handle<AccessorPair> AccessorPair::Copy(Isolate* isolate, 4540 Handle<AccessorPair> pair) { 4541 Handle<AccessorPair> copy = isolate->factory()->NewAccessorPair(); 4542 copy->set_getter(pair->getter()); 4543 copy->set_setter(pair->setter()); 4544 return copy; 4545} 4546 4547Handle<Object> AccessorPair::GetComponent(Isolate* isolate, 4548 Handle<NativeContext> native_context, 4549 Handle<AccessorPair> accessor_pair, 4550 AccessorComponent component) { 4551 Handle<Object> accessor(accessor_pair->get(component), isolate); 4552 if (accessor->IsFunctionTemplateInfo()) { 4553 auto function = ApiNatives::InstantiateFunction( 4554 isolate, native_context, 4555 Handle<FunctionTemplateInfo>::cast(accessor)) 4556 .ToHandleChecked(); 4557 accessor_pair->set(component, *function, kReleaseStore); 4558 return function; 4559 } 4560 if (accessor->IsNull(isolate)) { 4561 return isolate->factory()->undefined_value(); 4562 } 4563 return accessor; 4564} 4565 4566#ifdef DEBUG 4567bool DescriptorArray::IsEqualTo(DescriptorArray other) { 4568 if (number_of_all_descriptors() != other.number_of_all_descriptors()) { 4569 return false; 4570 } 4571 for (InternalIndex i : InternalIndex::Range(number_of_descriptors())) { 4572 if (GetKey(i) != other.GetKey(i)) return false; 4573 if (GetDetails(i).AsSmi() != other.GetDetails(i).AsSmi()) return false; 4574 if (GetValue(i) != other.GetValue(i)) return false; 4575 } 4576 return true; 4577} 4578#endif 4579 4580// static 4581MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name) { 4582 if (name->IsString()) return Handle<String>::cast(name); 4583 // ES6 section 9.2.11 SetFunctionName, step 4. 4584 Handle<Object> description(Handle<Symbol>::cast(name)->description(), 4585 isolate); 4586 if (description->IsUndefined(isolate)) { 4587 return isolate->factory()->empty_string(); 4588 } 4589 IncrementalStringBuilder builder(isolate); 4590 builder.AppendCharacter('['); 4591 builder.AppendString(Handle<String>::cast(description)); 4592 builder.AppendCharacter(']'); 4593 return builder.Finish(); 4594} 4595 4596// static 4597MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name, 4598 Handle<String> prefix) { 4599 Handle<String> name_string; 4600 ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, 4601 ToFunctionName(isolate, name), String); 4602 IncrementalStringBuilder builder(isolate); 4603 builder.AppendString(prefix); 4604 builder.AppendCharacter(' '); 4605 builder.AppendString(name_string); 4606 return builder.Finish(); 4607} 4608 4609void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) { 4610 Relocatable* current = isolate->relocatable_top(); 4611 while (current != nullptr) { 4612 current->PostGarbageCollection(); 4613 current = current->prev_; 4614 } 4615} 4616 4617// Reserve space for statics needing saving and restoring. 4618int Relocatable::ArchiveSpacePerThread() { return sizeof(Relocatable*); } 4619 4620// Archive statics that are thread-local. 4621char* Relocatable::ArchiveState(Isolate* isolate, char* to) { 4622 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top(); 4623 isolate->set_relocatable_top(nullptr); 4624 return to + ArchiveSpacePerThread(); 4625} 4626 4627// Restore statics that are thread-local. 4628char* Relocatable::RestoreState(Isolate* isolate, char* from) { 4629 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from)); 4630 return from + ArchiveSpacePerThread(); 4631} 4632 4633char* Relocatable::Iterate(RootVisitor* v, char* thread_storage) { 4634 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage); 4635 Iterate(v, top); 4636 return thread_storage + ArchiveSpacePerThread(); 4637} 4638 4639void Relocatable::Iterate(Isolate* isolate, RootVisitor* v) { 4640 Iterate(v, isolate->relocatable_top()); 4641} 4642 4643void Relocatable::Iterate(RootVisitor* v, Relocatable* top) { 4644 Relocatable* current = top; 4645 while (current != nullptr) { 4646 current->IterateInstance(v); 4647 current = current->prev_; 4648 } 4649} 4650 4651namespace { 4652 4653template <typename sinkchar> 4654void WriteFixedArrayToFlat(FixedArray fixed_array, int length, String separator, 4655 sinkchar* sink, int sink_length) { 4656 DisallowGarbageCollection no_gc; 4657 CHECK_GT(length, 0); 4658 CHECK_LE(length, fixed_array.length()); 4659#ifdef DEBUG 4660 sinkchar* sink_end = sink + sink_length; 4661#endif 4662 4663 const int separator_length = separator.length(); 4664 const bool use_one_byte_separator_fast_path = 4665 separator_length == 1 && sizeof(sinkchar) == 1 && 4666 StringShape(separator).IsSequentialOneByte(); 4667 uint8_t separator_one_char; 4668 if (use_one_byte_separator_fast_path) { 4669 CHECK(StringShape(separator).IsSequentialOneByte()); 4670 CHECK_EQ(separator.length(), 1); 4671 separator_one_char = SeqOneByteString::cast(separator).GetChars(no_gc)[0]; 4672 } 4673 4674 uint32_t num_separators = 0; 4675 for (int i = 0; i < length; i++) { 4676 Object element = fixed_array.get(i); 4677 const bool element_is_separator_sequence = element.IsSmi(); 4678 4679 // If element is a Smi, it represents the number of separators to write. 4680 if (V8_UNLIKELY(element_is_separator_sequence)) { 4681 CHECK(element.ToUint32(&num_separators)); 4682 // Verify that Smis (number of separators) only occur when necessary: 4683 // 1) at the beginning 4684 // 2) at the end 4685 // 3) when the number of separators > 1 4686 // - It is assumed that consecutive Strings will have one separator, 4687 // so there is no need for a Smi. 4688 DCHECK(i == 0 || i == length - 1 || num_separators > 1); 4689 } 4690 4691 // Write separator(s) if necessary. 4692 if (num_separators > 0 && separator_length > 0) { 4693 // TODO(pwong): Consider doubling strategy employed by runtime-strings.cc 4694 // WriteRepeatToFlat(). 4695 // Fast path for single character, single byte separators. 4696 if (use_one_byte_separator_fast_path) { 4697 DCHECK_LE(sink + num_separators, sink_end); 4698 memset(sink, separator_one_char, num_separators); 4699 DCHECK_EQ(separator_length, 1); 4700 sink += num_separators; 4701 } else { 4702 for (uint32_t j = 0; j < num_separators; j++) { 4703 DCHECK_LE(sink + separator_length, sink_end); 4704 String::WriteToFlat(separator, sink, 0, separator_length); 4705 sink += separator_length; 4706 } 4707 } 4708 } 4709 4710 if (V8_UNLIKELY(element_is_separator_sequence)) { 4711 num_separators = 0; 4712 } else { 4713 DCHECK(element.IsString()); 4714 String string = String::cast(element); 4715 const int string_length = string.length(); 4716 4717 DCHECK(string_length == 0 || sink < sink_end); 4718 String::WriteToFlat(string, sink, 0, string_length); 4719 sink += string_length; 4720 4721 // Next string element, needs at least one separator preceding it. 4722 num_separators = 1; 4723 } 4724 } 4725 4726 // Verify we have written to the end of the sink. 4727 DCHECK_EQ(sink, sink_end); 4728} 4729 4730} // namespace 4731 4732// static 4733Address JSArray::ArrayJoinConcatToSequentialString(Isolate* isolate, 4734 Address raw_fixed_array, 4735 intptr_t length, 4736 Address raw_separator, 4737 Address raw_dest) { 4738 DisallowGarbageCollection no_gc; 4739 DisallowJavascriptExecution no_js(isolate); 4740 FixedArray fixed_array = FixedArray::cast(Object(raw_fixed_array)); 4741 String separator = String::cast(Object(raw_separator)); 4742 String dest = String::cast(Object(raw_dest)); 4743 DCHECK(fixed_array.IsFixedArray()); 4744 DCHECK(StringShape(dest).IsSequentialOneByte() || 4745 StringShape(dest).IsSequentialTwoByte()); 4746 4747 if (StringShape(dest).IsSequentialOneByte()) { 4748 WriteFixedArrayToFlat(fixed_array, static_cast<int>(length), separator, 4749 SeqOneByteString::cast(dest).GetChars(no_gc), 4750 dest.length()); 4751 } else { 4752 DCHECK(StringShape(dest).IsSequentialTwoByte()); 4753 WriteFixedArrayToFlat(fixed_array, static_cast<int>(length), separator, 4754 SeqTwoByteString::cast(dest).GetChars(no_gc), 4755 dest.length()); 4756 } 4757 return dest.ptr(); 4758} 4759 4760uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) { 4761 // For array indexes mix the length into the hash as an array index could 4762 // be zero. 4763 DCHECK_GT(length, 0); 4764 DCHECK_LE(length, String::kMaxArrayIndexSize); 4765 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < 4766 (1 << String::kArrayIndexValueBits)); 4767 4768 value <<= String::ArrayIndexValueBits::kShift; 4769 value |= length << String::ArrayIndexLengthBits::kShift; 4770 4771 DCHECK(String::IsIntegerIndex(value)); 4772 DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength, 4773 Name::ContainsCachedArrayIndex(value)); 4774 return value; 4775} 4776 4777STATIC_ASSERT_FIELD_OFFSETS_EQUAL(HeapNumber::kValueOffset, 4778 Oddball::kToNumberRawOffset); 4779 4780void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball, 4781 const char* to_string, Handle<Object> to_number, 4782 const char* type_of, byte kind) { 4783 Handle<String> internalized_to_string = 4784 isolate->factory()->InternalizeUtf8String(to_string); 4785 Handle<String> internalized_type_of = 4786 isolate->factory()->InternalizeUtf8String(type_of); 4787 if (to_number->IsHeapNumber()) { 4788 oddball->set_to_number_raw_as_bits( 4789 Handle<HeapNumber>::cast(to_number)->value_as_bits(kRelaxedLoad)); 4790 } else { 4791 oddball->set_to_number_raw(to_number->Number()); 4792 } 4793 oddball->set_to_number(*to_number); 4794 oddball->set_to_string(*internalized_to_string); 4795 oddball->set_type_of(*internalized_type_of); 4796 oddball->set_kind(kind); 4797} 4798 4799// static 4800int Script::GetEvalPosition(Isolate* isolate, Handle<Script> script) { 4801 DCHECK(script->compilation_type() == Script::COMPILATION_TYPE_EVAL); 4802 int position = script->eval_from_position(); 4803 if (position < 0) { 4804 // Due to laziness, the position may not have been translated from code 4805 // offset yet, which would be encoded as negative integer. In that case, 4806 // translate and set the position. 4807 if (!script->has_eval_from_shared()) { 4808 position = 0; 4809 } else { 4810 Handle<SharedFunctionInfo> shared = 4811 handle(script->eval_from_shared(), isolate); 4812 SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared); 4813 position = shared->abstract_code(isolate).SourcePosition(-position); 4814 } 4815 DCHECK_GE(position, 0); 4816 script->set_eval_from_position(position); 4817 } 4818 return position; 4819} 4820 4821template <typename IsolateT> 4822// static 4823void Script::InitLineEnds(IsolateT* isolate, Handle<Script> script) { 4824 if (!script->line_ends().IsUndefined(isolate)) return; 4825#if V8_ENABLE_WEBASSEMBLY 4826 DCHECK(script->type() != Script::TYPE_WASM || 4827 script->source_mapping_url().IsString()); 4828#endif // V8_ENABLE_WEBASSEMBLY 4829 4830 Object src_obj = script->source(); 4831 if (!src_obj.IsString()) { 4832 DCHECK(src_obj.IsUndefined(isolate)); 4833 script->set_line_ends(ReadOnlyRoots(isolate).empty_fixed_array()); 4834 } else { 4835 DCHECK(src_obj.IsString()); 4836 Handle<String> src(String::cast(src_obj), isolate); 4837 Handle<FixedArray> array = String::CalculateLineEnds(isolate, src, true); 4838 script->set_line_ends(*array); 4839 } 4840 4841 DCHECK(script->line_ends().IsFixedArray()); 4842} 4843 4844template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void Script::InitLineEnds( 4845 Isolate* isolate, Handle<Script> script); 4846template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void Script::InitLineEnds( 4847 LocalIsolate* isolate, Handle<Script> script); 4848 4849bool Script::GetPositionInfo(Handle<Script> script, int position, 4850 PositionInfo* info, OffsetFlag offset_flag) { 4851 bool init_line_ends = true; 4852#if V8_ENABLE_WEBASSEMBLY 4853 // For wasm, we do not create an artificial line_ends array, but do the 4854 // translation directly. 4855 init_line_ends = script->type() != Script::TYPE_WASM; 4856#endif // V8_ENABLE_WEBASSEMBLY 4857 if (init_line_ends) InitLineEnds(script->GetIsolate(), script); 4858 return script->GetPositionInfo(position, info, offset_flag); 4859} 4860 4861bool Script::IsSubjectToDebugging() const { 4862 switch (type()) { 4863 case TYPE_NORMAL: 4864#if V8_ENABLE_WEBASSEMBLY 4865 case TYPE_WASM: 4866#endif // V8_ENABLE_WEBASSEMBLY 4867 return true; 4868 } 4869 return false; 4870} 4871 4872bool Script::IsUserJavaScript() const { return type() == Script::TYPE_NORMAL; } 4873 4874#if V8_ENABLE_WEBASSEMBLY 4875bool Script::ContainsAsmModule() { 4876 DisallowGarbageCollection no_gc; 4877 SharedFunctionInfo::ScriptIterator iter(this->GetIsolate(), *this); 4878 for (SharedFunctionInfo info = iter.Next(); !info.is_null(); 4879 info = iter.Next()) { 4880 if (info.HasAsmWasmData()) return true; 4881 } 4882 return false; 4883} 4884#endif // V8_ENABLE_WEBASSEMBLY 4885 4886namespace { 4887 4888template <typename Char> 4889bool GetPositionInfoSlowImpl(const base::Vector<Char>& source, int position, 4890 Script::PositionInfo* info) { 4891 if (position < 0) { 4892 position = 0; 4893 } 4894 int line = 0; 4895 const auto begin = std::cbegin(source); 4896 const auto end = std::cend(source); 4897 for (auto line_begin = begin; line_begin < end;) { 4898 const auto line_end = std::find(line_begin, end, '\n'); 4899 if (position <= (line_end - begin)) { 4900 info->line = line; 4901 info->column = static_cast<int>((begin + position) - line_begin); 4902 info->line_start = static_cast<int>(line_begin - begin); 4903 info->line_end = static_cast<int>(line_end - begin); 4904 return true; 4905 } 4906 ++line; 4907 line_begin = line_end + 1; 4908 } 4909 return false; 4910} 4911bool GetPositionInfoSlow(const Script script, int position, 4912 const DisallowGarbageCollection& no_gc, 4913 Script::PositionInfo* info) { 4914 if (!script.source().IsString()) { 4915 return false; 4916 } 4917 auto source = String::cast(script.source()); 4918 const auto flat = source.GetFlatContent(no_gc); 4919 return flat.IsOneByte() 4920 ? GetPositionInfoSlowImpl(flat.ToOneByteVector(), position, info) 4921 : GetPositionInfoSlowImpl(flat.ToUC16Vector(), position, info); 4922} 4923 4924} // namespace 4925 4926bool Script::GetPositionInfo(int position, PositionInfo* info, 4927 OffsetFlag offset_flag) const { 4928 DisallowGarbageCollection no_gc; 4929 4930#if V8_ENABLE_WEBASSEMBLY 4931 // For wasm, we use the byte offset as the column. 4932 if (type() == Script::TYPE_WASM) { 4933 DCHECK_LE(0, position); 4934 wasm::NativeModule* native_module = wasm_native_module(); 4935 const wasm::WasmModule* module = native_module->module(); 4936 if (module->functions.size() == 0) return false; 4937 info->line = 0; 4938 info->column = position; 4939 info->line_start = module->functions[0].code.offset(); 4940 info->line_end = module->functions.back().code.end_offset(); 4941 return true; 4942 } 4943#endif // V8_ENABLE_WEBASSEMBLY 4944 4945 if (line_ends().IsUndefined()) { 4946 // Slow mode: we do not have line_ends. We have to iterate through source. 4947 if (!GetPositionInfoSlow(*this, position, no_gc, info)) { 4948 return false; 4949 } 4950 } else { 4951 DCHECK(line_ends().IsFixedArray()); 4952 FixedArray ends = FixedArray::cast(line_ends()); 4953 4954 const int ends_len = ends.length(); 4955 if (ends_len == 0) return false; 4956 4957 // Return early on invalid positions. Negative positions behave as if 0 was 4958 // passed, and positions beyond the end of the script return as failure. 4959 if (position < 0) { 4960 position = 0; 4961 } else if (position > Smi::ToInt(ends.get(ends_len - 1))) { 4962 return false; 4963 } 4964 4965 // Determine line number by doing a binary search on the line ends array. 4966 if (Smi::ToInt(ends.get(0)) >= position) { 4967 info->line = 0; 4968 info->line_start = 0; 4969 info->column = position; 4970 } else { 4971 int left = 0; 4972 int right = ends_len - 1; 4973 4974 while (right > 0) { 4975 DCHECK_LE(left, right); 4976 const int mid = (left + right) / 2; 4977 if (position > Smi::ToInt(ends.get(mid))) { 4978 left = mid + 1; 4979 } else if (position <= Smi::ToInt(ends.get(mid - 1))) { 4980 right = mid - 1; 4981 } else { 4982 info->line = mid; 4983 break; 4984 } 4985 } 4986 DCHECK(Smi::ToInt(ends.get(info->line)) >= position && 4987 Smi::ToInt(ends.get(info->line - 1)) < position); 4988 info->line_start = Smi::ToInt(ends.get(info->line - 1)) + 1; 4989 info->column = position - info->line_start; 4990 } 4991 4992 // Line end is position of the linebreak character. 4993 info->line_end = Smi::ToInt(ends.get(info->line)); 4994 if (info->line_end > 0) { 4995 DCHECK(source().IsString()); 4996 String src = String::cast(source()); 4997 if (src.length() >= info->line_end && 4998 src.Get(info->line_end - 1) == '\r') { 4999 info->line_end--; 5000 } 5001 } 5002 } 5003 5004 // Add offsets if requested. 5005 if (offset_flag == WITH_OFFSET) { 5006 if (info->line == 0) { 5007 info->column += column_offset(); 5008 } 5009 info->line += line_offset(); 5010 } 5011 5012 return true; 5013} 5014 5015int Script::GetColumnNumber(Handle<Script> script, int code_pos) { 5016 PositionInfo info; 5017 GetPositionInfo(script, code_pos, &info, WITH_OFFSET); 5018 return info.column; 5019} 5020 5021int Script::GetColumnNumber(int code_pos) const { 5022 PositionInfo info; 5023 GetPositionInfo(code_pos, &info, WITH_OFFSET); 5024 return info.column; 5025} 5026 5027int Script::GetLineNumber(Handle<Script> script, int code_pos) { 5028 PositionInfo info; 5029 GetPositionInfo(script, code_pos, &info, WITH_OFFSET); 5030 return info.line; 5031} 5032 5033int Script::GetLineNumber(int code_pos) const { 5034 PositionInfo info; 5035 GetPositionInfo(code_pos, &info, WITH_OFFSET); 5036 return info.line; 5037} 5038 5039Object Script::GetNameOrSourceURL() { 5040 // Keep in sync with ScriptNameOrSourceURL in messages.js. 5041 if (!source_url().IsUndefined()) return source_url(); 5042 return name(); 5043} 5044 5045template <typename IsolateT> 5046MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( 5047 Handle<Script> script, IsolateT* isolate, 5048 FunctionLiteral* function_literal) { 5049 int function_literal_id = function_literal->function_literal_id(); 5050 if V8_UNLIKELY (script->type() == Script::TYPE_WEB_SNAPSHOT && 5051 function_literal_id >= script->shared_function_info_count()) { 5052 return FindWebSnapshotSharedFunctionInfo(script, isolate, function_literal); 5053 } 5054 5055 CHECK_NE(function_literal_id, kFunctionLiteralIdInvalid); 5056 // If this check fails, the problem is most probably the function id 5057 // renumbering done by AstFunctionLiteralIdReindexer; in particular, that 5058 // AstTraversalVisitor doesn't recurse properly in the construct which 5059 // triggers the mismatch. 5060 CHECK_LT(function_literal_id, script->shared_function_info_count()); 5061 MaybeObject shared = script->shared_function_infos().Get(function_literal_id); 5062 HeapObject heap_object; 5063 if (!shared->GetHeapObject(&heap_object) || 5064 heap_object.IsUndefined(isolate)) { 5065 return MaybeHandle<SharedFunctionInfo>(); 5066 } 5067 return handle(SharedFunctionInfo::cast(heap_object), isolate); 5068} 5069template MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( 5070 Handle<Script> script, Isolate* isolate, FunctionLiteral* function_literal); 5071template MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( 5072 Handle<Script> script, LocalIsolate* isolate, 5073 FunctionLiteral* function_literal); 5074 5075MaybeHandle<SharedFunctionInfo> Script::FindWebSnapshotSharedFunctionInfo( 5076 Handle<Script> script, Isolate* isolate, 5077 FunctionLiteral* function_literal) { 5078 // We might be able to de-dupe the SFI against a SFI that was 5079 // created when deserializing the snapshot (or when calling a function which 5080 // was included in the snapshot). In that case, we can find it based on the 5081 // start position in shared_function_info_table. 5082 Handle<ObjectHashTable> shared_function_info_table = handle( 5083 ObjectHashTable::cast(script->shared_function_info_table()), isolate); 5084 { 5085 DisallowHeapAllocation no_gc; 5086 Object index_object = shared_function_info_table->Lookup( 5087 handle(Smi::FromInt(function_literal->start_position()), isolate)); 5088 if (!index_object.IsTheHole()) { 5089 int index = Smi::cast(index_object).value(); 5090 DCHECK_LT(index, script->shared_function_info_count()); 5091 MaybeObject maybe_shared = script->shared_function_infos().Get(index); 5092 HeapObject heap_object; 5093 if (!maybe_shared->GetHeapObject(&heap_object)) { 5094 // We found the correct location but it's not filled in (e.g., the weak 5095 // pointer to the SharedFunctionInfo has been cleared). Record the 5096 // location in the FunctionLiteral, so that it will be refilled later. 5097 // SharedFunctionInfo::SetScript will write the SharedFunctionInfo in 5098 // the shared_function_infos. 5099 function_literal->set_function_literal_id(index); 5100 return MaybeHandle<SharedFunctionInfo>(); 5101 } 5102 SharedFunctionInfo shared = SharedFunctionInfo::cast(heap_object); 5103 DCHECK_EQ(shared.StartPosition(), function_literal->start_position()); 5104 DCHECK_EQ(shared.EndPosition(), function_literal->end_position()); 5105 return handle(shared, isolate); 5106 } 5107 } 5108 5109 // It's possible that FunctionLiterals which were processed before this one 5110 // were deduplicated against existing ones. Decrease function_literal_id to 5111 // avoid holes in shared_function_infos. 5112 int old_length = script->shared_function_info_count(); 5113 int function_literal_id = old_length; 5114 function_literal->set_function_literal_id(function_literal_id); 5115 5116 // Also add to shared_function_info_table. 5117 shared_function_info_table = ObjectHashTable::Put( 5118 shared_function_info_table, 5119 handle(Smi::FromInt(function_literal->start_position()), isolate), 5120 handle(Smi::FromInt(function_literal_id), isolate)); 5121 script->set_shared_function_info_table(*shared_function_info_table); 5122 5123 // Grow shared_function_infos if needed (we don't know the correct amount of 5124 // space needed upfront). 5125 int new_length = old_length + 1; 5126 Handle<WeakFixedArray> old_infos = 5127 handle(script->shared_function_infos(), isolate); 5128 if (new_length > old_infos->length()) { 5129 int capacity = WeakArrayList::CapacityForLength(new_length); 5130 Handle<WeakFixedArray> new_infos( 5131 isolate->factory()->NewWeakFixedArray(capacity, AllocationType::kOld)); 5132 new_infos->CopyElements(isolate, 0, *old_infos, 0, old_length, 5133 WriteBarrierMode::UPDATE_WRITE_BARRIER); 5134 script->set_shared_function_infos(*new_infos); 5135 } 5136 return MaybeHandle<SharedFunctionInfo>(); 5137} 5138 5139MaybeHandle<SharedFunctionInfo> Script::FindWebSnapshotSharedFunctionInfo( 5140 Handle<Script> script, LocalIsolate* isolate, 5141 FunctionLiteral* function_literal) { 5142 // Off-thread serialization of web snapshots is not implemented. 5143 UNREACHABLE(); 5144} 5145 5146Script::Iterator::Iterator(Isolate* isolate) 5147 : iterator_(isolate->heap()->script_list()) {} 5148 5149Script Script::Iterator::Next() { 5150 Object o = iterator_.Next(); 5151 if (o != Object()) { 5152 return Script::cast(o); 5153 } 5154 return Script(); 5155} 5156 5157// static 5158void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { 5159 DCHECK_GE(capacity, 0); 5160 array->GetIsolate()->factory()->NewJSArrayStorage( 5161 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 5162} 5163 5164Maybe<bool> JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) { 5165 if (array->SetLengthWouldNormalize(new_length)) { 5166 JSObject::NormalizeElements(array); 5167 } 5168 return array->GetElementsAccessor()->SetLength(array, new_length); 5169} 5170 5171// ES6: 9.5.2 [[SetPrototypeOf]] (V) 5172// static 5173Maybe<bool> JSProxy::SetPrototype(Isolate* isolate, Handle<JSProxy> proxy, 5174 Handle<Object> value, bool from_javascript, 5175 ShouldThrow should_throw) { 5176 STACK_CHECK(isolate, Nothing<bool>()); 5177 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string(); 5178 // 1. Assert: Either Type(V) is Object or Type(V) is Null. 5179 DCHECK(value->IsJSReceiver() || value->IsNull(isolate)); 5180 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 5181 Handle<Object> handler(proxy->handler(), isolate); 5182 // 3. If handler is null, throw a TypeError exception. 5183 // 4. Assert: Type(handler) is Object. 5184 if (proxy->IsRevoked()) { 5185 isolate->Throw(*isolate->factory()->NewTypeError( 5186 MessageTemplate::kProxyRevoked, trap_name)); 5187 return Nothing<bool>(); 5188 } 5189 // 5. Let target be the value of the [[ProxyTarget]] internal slot. 5190 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 5191 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf"). 5192 Handle<Object> trap; 5193 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5194 isolate, trap, 5195 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 5196 Nothing<bool>()); 5197 // 7. If trap is undefined, then return target.[[SetPrototypeOf]](). 5198 if (trap->IsUndefined(isolate)) { 5199 return JSReceiver::SetPrototype(isolate, target, value, from_javascript, 5200 should_throw); 5201 } 5202 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)). 5203 Handle<Object> argv[] = {target, value}; 5204 Handle<Object> trap_result; 5205 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5206 isolate, trap_result, 5207 Execution::Call(isolate, trap, handler, arraysize(argv), argv), 5208 Nothing<bool>()); 5209 bool bool_trap_result = trap_result->BooleanValue(isolate); 5210 // 9. If booleanTrapResult is false, return false. 5211 if (!bool_trap_result) { 5212 RETURN_FAILURE( 5213 isolate, should_throw, 5214 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 5215 } 5216 // 10. Let extensibleTarget be ? IsExtensible(target). 5217 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target); 5218 if (is_extensible.IsNothing()) return Nothing<bool>(); 5219 // 11. If extensibleTarget is true, return true. 5220 if (is_extensible.FromJust()) { 5221 if (bool_trap_result) return Just(true); 5222 RETURN_FAILURE( 5223 isolate, should_throw, 5224 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 5225 } 5226 // 12. Let targetProto be ? target.[[GetPrototypeOf]](). 5227 Handle<Object> target_proto; 5228 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto, 5229 JSReceiver::GetPrototype(isolate, target), 5230 Nothing<bool>()); 5231 // 13. If SameValue(V, targetProto) is false, throw a TypeError exception. 5232 if (bool_trap_result && !value->SameValue(*target_proto)) { 5233 isolate->Throw(*isolate->factory()->NewTypeError( 5234 MessageTemplate::kProxySetPrototypeOfNonExtensible)); 5235 return Nothing<bool>(); 5236 } 5237 // 14. Return true. 5238 return Just(true); 5239} 5240 5241bool JSArray::SetLengthWouldNormalize(uint32_t new_length) { 5242 if (!HasFastElements()) return false; 5243 uint32_t capacity = static_cast<uint32_t>(elements().length()); 5244 uint32_t new_capacity; 5245 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) && 5246 ShouldConvertToSlowElements(*this, capacity, new_length - 1, 5247 &new_capacity); 5248} 5249 5250const double AllocationSite::kPretenureRatio = 0.85; 5251 5252void AllocationSite::ResetPretenureDecision() { 5253 set_pretenure_decision(kUndecided); 5254 set_memento_found_count(0); 5255 set_memento_create_count(0); 5256} 5257 5258AllocationType AllocationSite::GetAllocationType() const { 5259 PretenureDecision mode = pretenure_decision(); 5260 // Zombie objects "decide" to be untenured. 5261 return mode == kTenure ? AllocationType::kOld : AllocationType::kYoung; 5262} 5263 5264bool AllocationSite::IsNested() { 5265 DCHECK(FLAG_trace_track_allocation_sites); 5266 Object current = boilerplate().GetHeap()->allocation_sites_list(); 5267 while (current.IsAllocationSite()) { 5268 AllocationSite current_site = AllocationSite::cast(current); 5269 if (current_site.nested_site() == *this) { 5270 return true; 5271 } 5272 current = current_site.weak_next(); 5273 } 5274 return false; 5275} 5276 5277bool AllocationSite::ShouldTrack(ElementsKind from, ElementsKind to) { 5278 if (!V8_ALLOCATION_SITE_TRACKING_BOOL) return false; 5279 return IsMoreGeneralElementsKindTransition(from, to); 5280} 5281 5282const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) { 5283 switch (decision) { 5284 case kUndecided: 5285 return "undecided"; 5286 case kDontTenure: 5287 return "don't tenure"; 5288 case kMaybeTenure: 5289 return "maybe tenure"; 5290 case kTenure: 5291 return "tenure"; 5292 case kZombie: 5293 return "zombie"; 5294 default: 5295 UNREACHABLE(); 5296 } 5297} 5298 5299// static 5300bool JSArray::MayHaveReadOnlyLength(Map js_array_map) { 5301 DCHECK(js_array_map.IsJSArrayMap()); 5302 if (js_array_map.is_dictionary_map()) return true; 5303 5304 // Fast path: "length" is the first fast property of arrays with non 5305 // dictionary properties. Since it's not configurable, it's guaranteed to be 5306 // the first in the descriptor array. 5307 InternalIndex first(0); 5308 DCHECK(js_array_map.instance_descriptors().GetKey(first) == 5309 js_array_map.GetReadOnlyRoots().length_string()); 5310 return js_array_map.instance_descriptors().GetDetails(first).IsReadOnly(); 5311} 5312 5313bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { 5314 Map map = array->map(); 5315 5316 // If map guarantees that there can't be a read-only length, we are done. 5317 if (!MayHaveReadOnlyLength(map)) return false; 5318 5319 // Look at the object. 5320 Isolate* isolate = array->GetIsolate(); 5321 LookupIterator it(isolate, array, isolate->factory()->length_string(), array, 5322 LookupIterator::OWN_SKIP_INTERCEPTOR); 5323 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); 5324 return it.IsReadOnly(); 5325} 5326 5327bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array, uint32_t index) { 5328 uint32_t length = 0; 5329 CHECK(array->length().ToArrayLength(&length)); 5330 if (length <= index) return HasReadOnlyLength(array); 5331 return false; 5332} 5333 5334int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) { 5335 return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >> 5336 ElementsKindToShiftSize(kind)); 5337} 5338 5339bool FixedArrayBase::IsCowArray() const { 5340 return map() == GetReadOnlyRoots().fixed_cow_array_map(); 5341} 5342 5343const char* Symbol::PrivateSymbolToName() const { 5344 ReadOnlyRoots roots = GetReadOnlyRoots(); 5345#define SYMBOL_CHECK_AND_PRINT(_, name) \ 5346 if (*this == roots.name()) return #name; 5347 PRIVATE_SYMBOL_LIST_GENERATOR(SYMBOL_CHECK_AND_PRINT, /* not used */) 5348#undef SYMBOL_CHECK_AND_PRINT 5349 return "UNKNOWN"; 5350} 5351 5352void Symbol::SymbolShortPrint(std::ostream& os) { 5353 os << "<Symbol:"; 5354 if (!description().IsUndefined()) { 5355 os << " "; 5356 String description_as_string = String::cast(description()); 5357 description_as_string.PrintUC16(os, 0, description_as_string.length()); 5358 } else { 5359 os << " (" << PrivateSymbolToName() << ")"; 5360 } 5361 os << ">"; 5362} 5363 5364v8::Promise::PromiseState JSPromise::status() const { 5365 int value = flags() & StatusBits::kMask; 5366 DCHECK(value == 0 || value == 1 || value == 2); 5367 return static_cast<v8::Promise::PromiseState>(value); 5368} 5369 5370void JSPromise::set_status(Promise::PromiseState status) { 5371 int value = flags() & ~StatusBits::kMask; 5372 set_flags(value | status); 5373} 5374 5375// static 5376const char* JSPromise::Status(v8::Promise::PromiseState status) { 5377 switch (status) { 5378 case v8::Promise::kFulfilled: 5379 return "fulfilled"; 5380 case v8::Promise::kPending: 5381 return "pending"; 5382 case v8::Promise::kRejected: 5383 return "rejected"; 5384 } 5385 UNREACHABLE(); 5386} 5387 5388int JSPromise::async_task_id() const { 5389 return AsyncTaskIdBits::decode(flags()); 5390} 5391 5392void JSPromise::set_async_task_id(int id) { 5393 set_flags(AsyncTaskIdBits::update(flags(), id)); 5394} 5395 5396// static 5397Handle<Object> JSPromise::Fulfill(Handle<JSPromise> promise, 5398 Handle<Object> value) { 5399 Isolate* const isolate = promise->GetIsolate(); 5400 5401#ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS 5402 if (isolate->HasContextPromiseHooks()) { 5403 isolate->raw_native_context().RunPromiseHook( 5404 PromiseHookType::kResolve, promise, 5405 isolate->factory()->undefined_value()); 5406 } 5407#endif 5408 5409 // 1. Assert: The value of promise.[[PromiseState]] is "pending". 5410 CHECK_EQ(Promise::kPending, promise->status()); 5411 5412 // 2. Let reactions be promise.[[PromiseFulfillReactions]]. 5413 Handle<Object> reactions(promise->reactions(), isolate); 5414 5415 // 3. Set promise.[[PromiseResult]] to value. 5416 // 4. Set promise.[[PromiseFulfillReactions]] to undefined. 5417 // 5. Set promise.[[PromiseRejectReactions]] to undefined. 5418 promise->set_reactions_or_result(*value); 5419 5420 // 6. Set promise.[[PromiseState]] to "fulfilled". 5421 promise->set_status(Promise::kFulfilled); 5422 5423 // 7. Return TriggerPromiseReactions(reactions, value). 5424 return TriggerPromiseReactions(isolate, reactions, value, 5425 PromiseReaction::kFulfill); 5426} 5427 5428static void MoveMessageToPromise(Isolate* isolate, Handle<JSPromise> promise) { 5429 if (!isolate->has_pending_message()) return; 5430 5431 Handle<Object> message = handle(isolate->pending_message(), isolate); 5432 Handle<Symbol> key = isolate->factory()->promise_debug_message_symbol(); 5433 Object::SetProperty(isolate, promise, key, message, StoreOrigin::kMaybeKeyed, 5434 Just(ShouldThrow::kThrowOnError)) 5435 .Assert(); 5436 5437 // The message object for a rejected promise was only stored for this purpose. 5438 // Clear it, otherwise we might leak memory. 5439 isolate->clear_pending_message(); 5440} 5441 5442// static 5443Handle<Object> JSPromise::Reject(Handle<JSPromise> promise, 5444 Handle<Object> reason, bool debug_event) { 5445 Isolate* const isolate = promise->GetIsolate(); 5446 DCHECK( 5447 !reinterpret_cast<v8::Isolate*>(isolate)->GetCurrentContext().IsEmpty()); 5448 5449 if (isolate->debug()->is_active()) MoveMessageToPromise(isolate, promise); 5450 5451 if (debug_event) isolate->debug()->OnPromiseReject(promise, reason); 5452 isolate->RunAllPromiseHooks(PromiseHookType::kResolve, promise, 5453 isolate->factory()->undefined_value()); 5454 5455 // 1. Assert: The value of promise.[[PromiseState]] is "pending". 5456 CHECK_EQ(Promise::kPending, promise->status()); 5457 5458 // 2. Let reactions be promise.[[PromiseRejectReactions]]. 5459 Handle<Object> reactions(promise->reactions(), isolate); 5460 5461 // 3. Set promise.[[PromiseResult]] to reason. 5462 // 4. Set promise.[[PromiseFulfillReactions]] to undefined. 5463 // 5. Set promise.[[PromiseRejectReactions]] to undefined. 5464 promise->set_reactions_or_result(*reason); 5465 5466 // 6. Set promise.[[PromiseState]] to "rejected". 5467 promise->set_status(Promise::kRejected); 5468 5469 // 7. If promise.[[PromiseIsHandled]] is false, perform 5470 // HostPromiseRejectionTracker(promise, "reject"). 5471 if (!promise->has_handler()) { 5472 isolate->ReportPromiseReject(promise, reason, kPromiseRejectWithNoHandler); 5473 } 5474 5475 // 8. Return TriggerPromiseReactions(reactions, reason). 5476 return TriggerPromiseReactions(isolate, reactions, reason, 5477 PromiseReaction::kReject); 5478} 5479 5480// https://tc39.es/ecma262/#sec-promise-resolve-functions 5481// static 5482MaybeHandle<Object> JSPromise::Resolve(Handle<JSPromise> promise, 5483 Handle<Object> resolution) { 5484 Isolate* const isolate = promise->GetIsolate(); 5485 DCHECK( 5486 !reinterpret_cast<v8::Isolate*>(isolate)->GetCurrentContext().IsEmpty()); 5487 5488 isolate->RunPromiseHook(PromiseHookType::kResolve, promise, 5489 isolate->factory()->undefined_value()); 5490 5491 // 7. If SameValue(resolution, promise) is true, then 5492 if (promise.is_identical_to(resolution)) { 5493 // a. Let selfResolutionError be a newly created TypeError object. 5494 Handle<Object> self_resolution_error = isolate->factory()->NewTypeError( 5495 MessageTemplate::kPromiseCyclic, resolution); 5496 // b. Return RejectPromise(promise, selfResolutionError). 5497 return Reject(promise, self_resolution_error); 5498 } 5499 5500 // 8. If Type(resolution) is not Object, then 5501 if (!resolution->IsJSReceiver()) { 5502 // a. Return FulfillPromise(promise, resolution). 5503 return Fulfill(promise, resolution); 5504 } 5505 5506 // 9. Let then be Get(resolution, "then"). 5507 MaybeHandle<Object> then; 5508 Handle<JSReceiver> receiver(Handle<JSReceiver>::cast(resolution)); 5509 5510 // Make sure a lookup of "then" on any JSPromise whose [[Prototype]] is the 5511 // initial %PromisePrototype% yields the initial method. In addition this 5512 // protector also guards the negative lookup of "then" on the intrinsic 5513 // %ObjectPrototype%, meaning that such lookups are guaranteed to yield 5514 // undefined without triggering any side-effects. 5515 if (receiver->IsJSPromise() && 5516 isolate->IsInAnyContext(receiver->map().prototype(), 5517 Context::PROMISE_PROTOTYPE_INDEX) && 5518 Protectors::IsPromiseThenLookupChainIntact(isolate)) { 5519 // We can skip the "then" lookup on {resolution} if its [[Prototype]] 5520 // is the (initial) Promise.prototype and the Promise#then protector 5521 // is intact, as that guards the lookup path for the "then" property 5522 // on JSPromise instances which have the (initial) %PromisePrototype%. 5523 then = isolate->promise_then(); 5524 } else { 5525 then = JSReceiver::GetProperty(isolate, receiver, 5526 isolate->factory()->then_string()); 5527 } 5528 5529 // 10. If then is an abrupt completion, then 5530 Handle<Object> then_action; 5531 if (!then.ToHandle(&then_action)) { 5532 // The "then" lookup can cause termination. 5533 if (!isolate->is_catchable_by_javascript(isolate->pending_exception())) { 5534 return kNullMaybeHandle; 5535 } 5536 5537 // a. Return RejectPromise(promise, then.[[Value]]). 5538 Handle<Object> reason(isolate->pending_exception(), isolate); 5539 isolate->clear_pending_exception(); 5540 return Reject(promise, reason, false); 5541 } 5542 5543 // 11. Let thenAction be then.[[Value]]. 5544 // 12. If IsCallable(thenAction) is false, then 5545 if (!then_action->IsCallable()) { 5546 // a. Return FulfillPromise(promise, resolution). 5547 return Fulfill(promise, resolution); 5548 } 5549 5550 // 13. Let job be NewPromiseResolveThenableJob(promise, resolution, 5551 // thenAction). 5552 Handle<NativeContext> then_context; 5553 if (!JSReceiver::GetContextForMicrotask(Handle<JSReceiver>::cast(then_action)) 5554 .ToHandle(&then_context)) { 5555 then_context = isolate->native_context(); 5556 } 5557 5558 Handle<PromiseResolveThenableJobTask> task = 5559 isolate->factory()->NewPromiseResolveThenableJobTask( 5560 promise, Handle<JSReceiver>::cast(resolution), 5561 Handle<JSReceiver>::cast(then_action), then_context); 5562 if (isolate->debug()->is_active() && resolution->IsJSPromise()) { 5563 // Mark the dependency of the new {promise} on the {resolution}. 5564 Object::SetProperty(isolate, resolution, 5565 isolate->factory()->promise_handled_by_symbol(), 5566 promise) 5567 .Check(); 5568 } 5569 MicrotaskQueue* microtask_queue = then_context->microtask_queue(); 5570 if (microtask_queue) microtask_queue->EnqueueMicrotask(*task); 5571 5572 // 15. Return undefined. 5573 return isolate->factory()->undefined_value(); 5574} 5575 5576// static 5577Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate, 5578 Handle<Object> reactions, 5579 Handle<Object> argument, 5580 PromiseReaction::Type type) { 5581 CHECK(reactions->IsSmi() || reactions->IsPromiseReaction()); 5582 5583 // We need to reverse the {reactions} here, since we record them 5584 // on the JSPromise in the reverse order. 5585 { 5586 DisallowGarbageCollection no_gc; 5587 Object current = *reactions; 5588 Object reversed = Smi::zero(); 5589 while (!current.IsSmi()) { 5590 Object next = PromiseReaction::cast(current).next(); 5591 PromiseReaction::cast(current).set_next(reversed); 5592 reversed = current; 5593 current = next; 5594 } 5595 reactions = handle(reversed, isolate); 5596 } 5597 5598 // Morph the {reactions} into PromiseReactionJobTasks 5599 // and push them onto the microtask queue. 5600 while (!reactions->IsSmi()) { 5601 Handle<HeapObject> task = Handle<HeapObject>::cast(reactions); 5602 Handle<PromiseReaction> reaction = Handle<PromiseReaction>::cast(task); 5603 reactions = handle(reaction->next(), isolate); 5604 5605 // According to HTML, we use the context of the appropriate handler as the 5606 // context of the microtask. See step 3 of HTML's EnqueueJob: 5607 // https://html.spec.whatwg.org/C/#enqueuejob(queuename,-job,-arguments) 5608 Handle<NativeContext> handler_context; 5609 5610 Handle<HeapObject> primary_handler; 5611 Handle<HeapObject> secondary_handler; 5612 if (type == PromiseReaction::kFulfill) { 5613 primary_handler = handle(reaction->fulfill_handler(), isolate); 5614 secondary_handler = handle(reaction->reject_handler(), isolate); 5615 } else { 5616 primary_handler = handle(reaction->reject_handler(), isolate); 5617 secondary_handler = handle(reaction->fulfill_handler(), isolate); 5618 } 5619 5620 bool has_handler_context = false; 5621 if (primary_handler->IsJSReceiver()) { 5622 has_handler_context = JSReceiver::GetContextForMicrotask( 5623 Handle<JSReceiver>::cast(primary_handler)) 5624 .ToHandle(&handler_context); 5625 } 5626 if (!has_handler_context && secondary_handler->IsJSReceiver()) { 5627 has_handler_context = JSReceiver::GetContextForMicrotask( 5628 Handle<JSReceiver>::cast(secondary_handler)) 5629 .ToHandle(&handler_context); 5630 } 5631 if (!has_handler_context) handler_context = isolate->native_context(); 5632 5633 STATIC_ASSERT( 5634 static_cast<int>(PromiseReaction::kSize) == 5635 static_cast<int>( 5636 PromiseReactionJobTask::kSizeOfAllPromiseReactionJobTasks)); 5637 if (type == PromiseReaction::kFulfill) { 5638 task->set_map( 5639 ReadOnlyRoots(isolate).promise_fulfill_reaction_job_task_map(), 5640 kReleaseStore); 5641 Handle<PromiseFulfillReactionJobTask>::cast(task)->set_argument( 5642 *argument); 5643 Handle<PromiseFulfillReactionJobTask>::cast(task)->set_context( 5644 *handler_context); 5645 STATIC_ASSERT( 5646 static_cast<int>(PromiseReaction::kFulfillHandlerOffset) == 5647 static_cast<int>(PromiseFulfillReactionJobTask::kHandlerOffset)); 5648 STATIC_ASSERT( 5649 static_cast<int>(PromiseReaction::kPromiseOrCapabilityOffset) == 5650 static_cast<int>( 5651 PromiseFulfillReactionJobTask::kPromiseOrCapabilityOffset)); 5652 STATIC_ASSERT( 5653 static_cast<int>( 5654 PromiseReaction::kContinuationPreservedEmbedderDataOffset) == 5655 static_cast<int>(PromiseFulfillReactionJobTask:: 5656 kContinuationPreservedEmbedderDataOffset)); 5657 } else { 5658 DisallowGarbageCollection no_gc; 5659 task->set_map( 5660 ReadOnlyRoots(isolate).promise_reject_reaction_job_task_map(), 5661 kReleaseStore); 5662 Handle<PromiseRejectReactionJobTask>::cast(task)->set_argument(*argument); 5663 Handle<PromiseRejectReactionJobTask>::cast(task)->set_context( 5664 *handler_context); 5665 Handle<PromiseRejectReactionJobTask>::cast(task)->set_handler( 5666 *primary_handler); 5667 STATIC_ASSERT( 5668 static_cast<int>(PromiseReaction::kPromiseOrCapabilityOffset) == 5669 static_cast<int>( 5670 PromiseRejectReactionJobTask::kPromiseOrCapabilityOffset)); 5671 STATIC_ASSERT( 5672 static_cast<int>( 5673 PromiseReaction::kContinuationPreservedEmbedderDataOffset) == 5674 static_cast<int>(PromiseRejectReactionJobTask:: 5675 kContinuationPreservedEmbedderDataOffset)); 5676 } 5677 5678 MicrotaskQueue* microtask_queue = handler_context->microtask_queue(); 5679 if (microtask_queue) { 5680 microtask_queue->EnqueueMicrotask( 5681 *Handle<PromiseReactionJobTask>::cast(task)); 5682 } 5683 } 5684 5685 return isolate->factory()->undefined_value(); 5686} 5687 5688template <typename Derived, typename Shape> 5689void HashTable<Derived, Shape>::IteratePrefix(ObjectVisitor* v) { 5690 BodyDescriptorBase::IteratePointers(*this, 0, kElementsStartOffset, v); 5691} 5692 5693template <typename Derived, typename Shape> 5694void HashTable<Derived, Shape>::IterateElements(ObjectVisitor* v) { 5695 BodyDescriptorBase::IteratePointers(*this, kElementsStartOffset, 5696 SizeFor(length()), v); 5697} 5698 5699template <typename Derived, typename Shape> 5700template <typename IsolateT> 5701Handle<Derived> HashTable<Derived, Shape>::New( 5702 IsolateT* isolate, int at_least_space_for, AllocationType allocation, 5703 MinimumCapacity capacity_option) { 5704 DCHECK_LE(0, at_least_space_for); 5705 DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY, 5706 base::bits::IsPowerOfTwo(at_least_space_for)); 5707 5708 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY) 5709 ? at_least_space_for 5710 : ComputeCapacity(at_least_space_for); 5711 if (capacity > HashTable::kMaxCapacity) { 5712 isolate->FatalProcessOutOfHeapMemory("invalid table size"); 5713 } 5714 return NewInternal(isolate, capacity, allocation); 5715} 5716 5717template <typename Derived, typename Shape> 5718template <typename IsolateT> 5719Handle<Derived> HashTable<Derived, Shape>::NewInternal( 5720 IsolateT* isolate, int capacity, AllocationType allocation) { 5721 auto* factory = isolate->factory(); 5722 int length = EntryToIndex(InternalIndex(capacity)); 5723 Handle<FixedArray> array = factory->NewFixedArrayWithMap( 5724 Derived::GetMap(ReadOnlyRoots(isolate)), length, allocation); 5725 Handle<Derived> table = Handle<Derived>::cast(array); 5726 5727 table->SetNumberOfElements(0); 5728 table->SetNumberOfDeletedElements(0); 5729 table->SetCapacity(capacity); 5730 return table; 5731} 5732 5733template <typename Derived, typename Shape> 5734void HashTable<Derived, Shape>::Rehash(PtrComprCageBase cage_base, 5735 Derived new_table) { 5736 DisallowGarbageCollection no_gc; 5737 WriteBarrierMode mode = new_table.GetWriteBarrierMode(no_gc); 5738 5739 DCHECK_LT(NumberOfElements(), new_table.Capacity()); 5740 5741 // Copy prefix to new array. 5742 for (int i = kPrefixStartIndex; i < kElementsStartIndex; i++) { 5743 new_table.set(i, get(cage_base, i), mode); 5744 } 5745 5746 // Rehash the elements. 5747 ReadOnlyRoots roots = GetReadOnlyRoots(cage_base); 5748 for (InternalIndex i : this->IterateEntries()) { 5749 uint32_t from_index = EntryToIndex(i); 5750 Object k = this->get(cage_base, from_index); 5751 if (!IsKey(roots, k)) continue; 5752 uint32_t hash = Shape::HashForObject(roots, k); 5753 uint32_t insertion_index = 5754 EntryToIndex(new_table.FindInsertionEntry(cage_base, roots, hash)); 5755 new_table.set_key(insertion_index, get(cage_base, from_index), mode); 5756 for (int j = 1; j < Shape::kEntrySize; j++) { 5757 new_table.set(insertion_index + j, get(cage_base, from_index + j), mode); 5758 } 5759 } 5760 new_table.SetNumberOfElements(NumberOfElements()); 5761 new_table.SetNumberOfDeletedElements(0); 5762} 5763 5764template <typename Derived, typename Shape> 5765InternalIndex HashTable<Derived, Shape>::EntryForProbe(ReadOnlyRoots roots, 5766 Object k, int probe, 5767 InternalIndex expected) { 5768 uint32_t hash = Shape::HashForObject(roots, k); 5769 uint32_t capacity = this->Capacity(); 5770 InternalIndex entry = FirstProbe(hash, capacity); 5771 for (int i = 1; i < probe; i++) { 5772 if (entry == expected) return expected; 5773 entry = NextProbe(entry, i, capacity); 5774 } 5775 return entry; 5776} 5777 5778template <typename Derived, typename Shape> 5779void HashTable<Derived, Shape>::Swap(InternalIndex entry1, InternalIndex entry2, 5780 WriteBarrierMode mode) { 5781 int index1 = EntryToIndex(entry1); 5782 int index2 = EntryToIndex(entry2); 5783 Object temp[Shape::kEntrySize]; 5784 Derived* self = static_cast<Derived*>(this); 5785 for (int j = 0; j < Shape::kEntrySize; j++) { 5786 temp[j] = get(index1 + j); 5787 } 5788 self->set_key(index1, get(index2), mode); 5789 for (int j = 1; j < Shape::kEntrySize; j++) { 5790 set(index1 + j, get(index2 + j), mode); 5791 } 5792 self->set_key(index2, temp[0], mode); 5793 for (int j = 1; j < Shape::kEntrySize; j++) { 5794 set(index2 + j, temp[j], mode); 5795 } 5796} 5797 5798template <typename Derived, typename Shape> 5799void HashTable<Derived, Shape>::Rehash(PtrComprCageBase cage_base) { 5800 DisallowGarbageCollection no_gc; 5801 WriteBarrierMode mode = GetWriteBarrierMode(no_gc); 5802 ReadOnlyRoots roots = GetReadOnlyRoots(cage_base); 5803 uint32_t capacity = Capacity(); 5804 bool done = false; 5805 for (int probe = 1; !done; probe++) { 5806 // All elements at entries given by one of the first _probe_ probes 5807 // are placed correctly. Other elements might need to be moved. 5808 done = true; 5809 for (InternalIndex current(0); current.raw_value() < capacity; 5810 /* {current} is advanced manually below, when appropriate.*/) { 5811 Object current_key = KeyAt(cage_base, current); 5812 if (!IsKey(roots, current_key)) { 5813 ++current; // Advance to next entry. 5814 continue; 5815 } 5816 InternalIndex target = EntryForProbe(roots, current_key, probe, current); 5817 if (current == target) { 5818 ++current; // Advance to next entry. 5819 continue; 5820 } 5821 Object target_key = KeyAt(cage_base, target); 5822 if (!IsKey(roots, target_key) || 5823 EntryForProbe(roots, target_key, probe, target) != target) { 5824 // Put the current element into the correct position. 5825 Swap(current, target, mode); 5826 // The other element will be processed on the next iteration, 5827 // so don't advance {current} here! 5828 } else { 5829 // The place for the current element is occupied. Leave the element 5830 // for the next probe. 5831 done = false; 5832 ++current; // Advance to next entry. 5833 } 5834 } 5835 } 5836 // Wipe deleted entries. 5837 Object the_hole = roots.the_hole_value(); 5838 HeapObject undefined = roots.undefined_value(); 5839 Derived* self = static_cast<Derived*>(this); 5840 for (InternalIndex current : InternalIndex::Range(capacity)) { 5841 if (KeyAt(cage_base, current) == the_hole) { 5842 self->set_key(EntryToIndex(current) + kEntryKeyIndex, undefined, 5843 SKIP_WRITE_BARRIER); 5844 } 5845 } 5846 SetNumberOfDeletedElements(0); 5847} 5848 5849template <typename Derived, typename Shape> 5850template <typename IsolateT> 5851Handle<Derived> HashTable<Derived, Shape>::EnsureCapacity( 5852 IsolateT* isolate, Handle<Derived> table, int n, 5853 AllocationType allocation) { 5854 if (table->HasSufficientCapacityToAdd(n)) return table; 5855 5856 int capacity = table->Capacity(); 5857 int new_nof = table->NumberOfElements() + n; 5858 5859 bool should_pretenure = allocation == AllocationType::kOld || 5860 ((capacity > kMinCapacityForPretenure) && 5861 !Heap::InYoungGeneration(*table)); 5862 Handle<Derived> new_table = HashTable::New( 5863 isolate, new_nof, 5864 should_pretenure ? AllocationType::kOld : AllocationType::kYoung); 5865 5866 table->Rehash(isolate, *new_table); 5867 return new_table; 5868} 5869 5870template <typename Derived, typename Shape> 5871bool HashTable<Derived, Shape>::HasSufficientCapacityToAdd( 5872 int number_of_additional_elements) { 5873 return HasSufficientCapacityToAdd(Capacity(), NumberOfElements(), 5874 NumberOfDeletedElements(), 5875 number_of_additional_elements); 5876} 5877 5878// static 5879template <typename Derived, typename Shape> 5880bool HashTable<Derived, Shape>::HasSufficientCapacityToAdd( 5881 int capacity, int number_of_elements, int number_of_deleted_elements, 5882 int number_of_additional_elements) { 5883 int nof = number_of_elements + number_of_additional_elements; 5884 // Return true if: 5885 // 50% is still free after adding number_of_additional_elements elements and 5886 // at most 50% of the free elements are deleted elements. 5887 if ((nof < capacity) && 5888 ((number_of_deleted_elements <= (capacity - nof) / 2))) { 5889 int needed_free = nof / 2; 5890 if (nof + needed_free <= capacity) return true; 5891 } 5892 return false; 5893} 5894 5895// static 5896template <typename Derived, typename Shape> 5897int HashTable<Derived, Shape>::ComputeCapacityWithShrink( 5898 int current_capacity, int at_least_room_for) { 5899 // Shrink to fit the number of elements if only a quarter of the 5900 // capacity is filled with elements. 5901 if (at_least_room_for > (current_capacity / 4)) return current_capacity; 5902 // Recalculate the smaller capacity actually needed. 5903 int new_capacity = ComputeCapacity(at_least_room_for); 5904 DCHECK_GE(new_capacity, at_least_room_for); 5905 // Don't go lower than room for {kMinShrinkCapacity} elements. 5906 if (new_capacity < Derived::kMinShrinkCapacity) return current_capacity; 5907 return new_capacity; 5908} 5909 5910// static 5911template <typename Derived, typename Shape> 5912Handle<Derived> HashTable<Derived, Shape>::Shrink(Isolate* isolate, 5913 Handle<Derived> table, 5914 int additional_capacity) { 5915 int new_capacity = ComputeCapacityWithShrink( 5916 table->Capacity(), table->NumberOfElements() + additional_capacity); 5917 if (new_capacity == table->Capacity()) return table; 5918 DCHECK_GE(new_capacity, Derived::kMinShrinkCapacity); 5919 5920 bool pretenure = (new_capacity > kMinCapacityForPretenure) && 5921 !Heap::InYoungGeneration(*table); 5922 Handle<Derived> new_table = 5923 HashTable::New(isolate, new_capacity, 5924 pretenure ? AllocationType::kOld : AllocationType::kYoung, 5925 USE_CUSTOM_MINIMUM_CAPACITY); 5926 5927 table->Rehash(isolate, *new_table); 5928 return new_table; 5929} 5930 5931template <typename Derived, typename Shape> 5932InternalIndex HashTable<Derived, Shape>::FindInsertionEntry( 5933 PtrComprCageBase cage_base, ReadOnlyRoots roots, uint32_t hash) { 5934 uint32_t capacity = Capacity(); 5935 uint32_t count = 1; 5936 // EnsureCapacity will guarantee the hash table is never full. 5937 for (InternalIndex entry = FirstProbe(hash, capacity);; 5938 entry = NextProbe(entry, count++, capacity)) { 5939 if (!IsKey(roots, KeyAt(cage_base, entry))) return entry; 5940 } 5941} 5942 5943base::Optional<PropertyCell> 5944GlobalDictionary::TryFindPropertyCellForConcurrentLookupIterator( 5945 Isolate* isolate, Handle<Name> name, RelaxedLoadTag tag) { 5946 // This reimplements HashTable::FindEntry for use in a concurrent setting. 5947 // 1) Atomic loads. 5948 // 2) IsPendingAllocation checks. 5949 // 3) Return the PropertyCell value instead of the InternalIndex to avoid a 5950 // repeated load (unsafe with concurrent modifications). 5951 5952 DisallowGarbageCollection no_gc; 5953 PtrComprCageBase cage_base{isolate}; 5954 ReadOnlyRoots roots(isolate); 5955 const int32_t hash = ShapeT::Hash(roots, name); 5956 const uint32_t capacity = Capacity(); 5957 uint32_t count = 1; 5958 Object undefined = roots.undefined_value(); 5959 Object the_hole = roots.the_hole_value(); 5960 // EnsureCapacity will guarantee the hash table is never full. 5961 for (InternalIndex entry = FirstProbe(hash, capacity);; 5962 entry = NextProbe(entry, count++, capacity)) { 5963 Object element = KeyAt(cage_base, entry, kRelaxedLoad); 5964 if (isolate->heap()->IsPendingAllocation(element)) return {}; 5965 if (element == undefined) return {}; 5966 if (ShapeT::kMatchNeedsHoleCheck && element == the_hole) continue; 5967 if (!ShapeT::IsMatch(name, element)) continue; 5968 CHECK(element.IsPropertyCell(cage_base)); 5969 return PropertyCell::cast(element); 5970 } 5971} 5972 5973Handle<StringSet> StringSet::New(Isolate* isolate) { 5974 return HashTable::New(isolate, 0); 5975} 5976 5977Handle<StringSet> StringSet::Add(Isolate* isolate, Handle<StringSet> stringset, 5978 Handle<String> name) { 5979 if (!stringset->Has(isolate, name)) { 5980 stringset = EnsureCapacity(isolate, stringset); 5981 uint32_t hash = ShapeT::Hash(ReadOnlyRoots(isolate), *name); 5982 InternalIndex entry = stringset->FindInsertionEntry(isolate, hash); 5983 stringset->set(EntryToIndex(entry), *name); 5984 stringset->ElementAdded(); 5985 } 5986 return stringset; 5987} 5988 5989bool StringSet::Has(Isolate* isolate, Handle<String> name) { 5990 return FindEntry(isolate, *name).is_found(); 5991} 5992 5993Handle<RegisteredSymbolTable> RegisteredSymbolTable::Add( 5994 Isolate* isolate, Handle<RegisteredSymbolTable> table, Handle<String> key, 5995 Handle<Symbol> symbol) { 5996 // Validate that the key is absent. 5997 SLOW_DCHECK(table->FindEntry(isolate, key).is_not_found()); 5998 5999 table = EnsureCapacity(isolate, table); 6000 uint32_t hash = ShapeT::Hash(ReadOnlyRoots(isolate), key); 6001 InternalIndex entry = table->FindInsertionEntry(isolate, hash); 6002 table->set(EntryToIndex(entry), *key); 6003 table->set(EntryToValueIndex(entry), *symbol); 6004 table->ElementAdded(); 6005 return table; 6006} 6007 6008Handle<ObjectHashSet> ObjectHashSet::Add(Isolate* isolate, 6009 Handle<ObjectHashSet> set, 6010 Handle<Object> key) { 6011 int32_t hash = key->GetOrCreateHash(isolate).value(); 6012 if (!set->Has(isolate, key, hash)) { 6013 set = EnsureCapacity(isolate, set); 6014 InternalIndex entry = set->FindInsertionEntry(isolate, hash); 6015 set->set(EntryToIndex(entry), *key); 6016 set->ElementAdded(); 6017 } 6018 return set; 6019} 6020 6021template <typename Derived, typename Shape> 6022template <typename IsolateT> 6023Handle<Derived> BaseNameDictionary<Derived, Shape>::New( 6024 IsolateT* isolate, int at_least_space_for, AllocationType allocation, 6025 MinimumCapacity capacity_option) { 6026 DCHECK_LE(0, at_least_space_for); 6027 Handle<Derived> dict = Dictionary<Derived, Shape>::New( 6028 isolate, at_least_space_for, allocation, capacity_option); 6029 dict->SetHash(PropertyArray::kNoHashSentinel); 6030 dict->set_next_enumeration_index(PropertyDetails::kInitialIndex); 6031 return dict; 6032} 6033 6034template <typename Derived, typename Shape> 6035int BaseNameDictionary<Derived, Shape>::NextEnumerationIndex( 6036 Isolate* isolate, Handle<Derived> dictionary) { 6037 int index = dictionary->next_enumeration_index(); 6038 // Check whether the next enumeration index is valid. 6039 if (!PropertyDetails::IsValidIndex(index)) { 6040 // If not, we generate new indices for the properties. 6041 Handle<FixedArray> iteration_order = IterationIndices(isolate, dictionary); 6042 int length = iteration_order->length(); 6043 DCHECK_LE(length, dictionary->NumberOfElements()); 6044 6045 // Iterate over the dictionary using the enumeration order and update 6046 // the dictionary with new enumeration indices. 6047 for (int i = 0; i < length; i++) { 6048 InternalIndex internal_index(Smi::ToInt(iteration_order->get(i))); 6049 DCHECK(dictionary->IsKey(dictionary->GetReadOnlyRoots(), 6050 dictionary->KeyAt(isolate, internal_index))); 6051 6052 int enum_index = PropertyDetails::kInitialIndex + i; 6053 6054 PropertyDetails details = dictionary->DetailsAt(internal_index); 6055 PropertyDetails new_details = details.set_index(enum_index); 6056 dictionary->DetailsAtPut(internal_index, new_details); 6057 } 6058 6059 index = PropertyDetails::kInitialIndex + length; 6060 } 6061 6062 // Don't update the next enumeration index here, since we might be looking at 6063 // an immutable empty dictionary. 6064 return index; 6065} 6066 6067template <typename Derived, typename Shape> 6068Handle<Derived> Dictionary<Derived, Shape>::DeleteEntry( 6069 Isolate* isolate, Handle<Derived> dictionary, InternalIndex entry) { 6070 DCHECK(Shape::kEntrySize != 3 || 6071 dictionary->DetailsAt(entry).IsConfigurable()); 6072 dictionary->ClearEntry(entry); 6073 dictionary->ElementRemoved(); 6074 return Shrink(isolate, dictionary); 6075} 6076 6077template <typename Derived, typename Shape> 6078Handle<Derived> Dictionary<Derived, Shape>::AtPut(Isolate* isolate, 6079 Handle<Derived> dictionary, 6080 Key key, Handle<Object> value, 6081 PropertyDetails details) { 6082 InternalIndex entry = dictionary->FindEntry(isolate, key); 6083 6084 // If the entry is present set the value; 6085 if (entry.is_not_found()) { 6086 return Derived::Add(isolate, dictionary, key, value, details); 6087 } 6088 6089 // We don't need to copy over the enumeration index. 6090 dictionary->ValueAtPut(entry, *value); 6091 if (Shape::kEntrySize == 3) dictionary->DetailsAtPut(entry, details); 6092 return dictionary; 6093} 6094 6095template <typename Derived, typename Shape> 6096template <typename IsolateT> 6097Handle<Derived> 6098BaseNameDictionary<Derived, Shape>::AddNoUpdateNextEnumerationIndex( 6099 IsolateT* isolate, Handle<Derived> dictionary, Key key, 6100 Handle<Object> value, PropertyDetails details, InternalIndex* entry_out) { 6101 // Insert element at empty or deleted entry. 6102 return Dictionary<Derived, Shape>::Add(isolate, dictionary, key, value, 6103 details, entry_out); 6104} 6105 6106template <typename Derived, typename Shape> 6107Handle<Derived> BaseNameDictionary<Derived, Shape>::Add( 6108 Isolate* isolate, Handle<Derived> dictionary, Key key, Handle<Object> value, 6109 PropertyDetails details, InternalIndex* entry_out) { 6110 // Insert element at empty or deleted entry 6111 DCHECK_EQ(0, details.dictionary_index()); 6112 // Assign an enumeration index to the property and update 6113 // SetNextEnumerationIndex. 6114 int index = Derived::NextEnumerationIndex(isolate, dictionary); 6115 details = details.set_index(index); 6116 dictionary = AddNoUpdateNextEnumerationIndex(isolate, dictionary, key, value, 6117 details, entry_out); 6118 // Update enumeration index here in order to avoid potential modification of 6119 // the canonical empty dictionary which lives in read only space. 6120 dictionary->set_next_enumeration_index(index + 1); 6121 return dictionary; 6122} 6123 6124template <typename Derived, typename Shape> 6125template <typename IsolateT> 6126Handle<Derived> Dictionary<Derived, Shape>::Add(IsolateT* isolate, 6127 Handle<Derived> dictionary, 6128 Key key, Handle<Object> value, 6129 PropertyDetails details, 6130 InternalIndex* entry_out) { 6131 ReadOnlyRoots roots(isolate); 6132 uint32_t hash = Shape::Hash(roots, key); 6133 // Validate that the key is absent. 6134 SLOW_DCHECK(dictionary->FindEntry(isolate, key).is_not_found()); 6135 // Check whether the dictionary should be extended. 6136 dictionary = Derived::EnsureCapacity(isolate, dictionary); 6137 6138 // Compute the key object. 6139 Handle<Object> k = Shape::AsHandle(isolate, key); 6140 6141 InternalIndex entry = dictionary->FindInsertionEntry(isolate, roots, hash); 6142 dictionary->SetEntry(entry, *k, *value, details); 6143 DCHECK(dictionary->KeyAt(isolate, entry).IsNumber() || 6144 Shape::Unwrap(dictionary->KeyAt(isolate, entry)).IsUniqueName()); 6145 dictionary->ElementAdded(); 6146 if (entry_out) *entry_out = entry; 6147 return dictionary; 6148} 6149 6150template <typename Derived, typename Shape> 6151Handle<Derived> Dictionary<Derived, Shape>::ShallowCopy( 6152 Isolate* isolate, Handle<Derived> dictionary) { 6153 return Handle<Derived>::cast(isolate->factory()->CopyFixedArrayWithMap( 6154 dictionary, Derived::GetMap(ReadOnlyRoots(isolate)))); 6155} 6156 6157// static 6158Handle<SimpleNumberDictionary> SimpleNumberDictionary::Set( 6159 Isolate* isolate, Handle<SimpleNumberDictionary> dictionary, uint32_t key, 6160 Handle<Object> value) { 6161 return AtPut(isolate, dictionary, key, value, PropertyDetails::Empty()); 6162} 6163 6164void NumberDictionary::UpdateMaxNumberKey(uint32_t key, 6165 Handle<JSObject> dictionary_holder) { 6166 DisallowGarbageCollection no_gc; 6167 // If the dictionary requires slow elements an element has already 6168 // been added at a high index. 6169 if (requires_slow_elements()) return; 6170 // Check if this index is high enough that we should require slow 6171 // elements. 6172 if (key > kRequiresSlowElementsLimit) { 6173 if (!dictionary_holder.is_null()) { 6174 dictionary_holder->RequireSlowElements(*this); 6175 } 6176 set_requires_slow_elements(); 6177 return; 6178 } 6179 // Update max key value. 6180 Object max_index_object = get(kMaxNumberKeyIndex); 6181 if (!max_index_object.IsSmi() || max_number_key() < key) { 6182 FixedArray::set(kMaxNumberKeyIndex, 6183 Smi::FromInt(key << kRequiresSlowElementsTagSize)); 6184 } 6185} 6186 6187Handle<NumberDictionary> NumberDictionary::Set( 6188 Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key, 6189 Handle<Object> value, Handle<JSObject> dictionary_holder, 6190 PropertyDetails details) { 6191 // We could call Set with empty dictionaries. UpdateMaxNumberKey doesn't 6192 // expect empty dictionaries so make sure to call AtPut that correctly handles 6193 // them by creating new dictionary when required. 6194 Handle<NumberDictionary> new_dictionary = 6195 AtPut(isolate, dictionary, key, value, details); 6196 new_dictionary->UpdateMaxNumberKey(key, dictionary_holder); 6197 return new_dictionary; 6198} 6199 6200void NumberDictionary::CopyValuesTo(FixedArray elements) { 6201 ReadOnlyRoots roots = GetReadOnlyRoots(); 6202 int pos = 0; 6203 DisallowGarbageCollection no_gc; 6204 WriteBarrierMode mode = elements.GetWriteBarrierMode(no_gc); 6205 for (InternalIndex i : this->IterateEntries()) { 6206 Object k; 6207 if (this->ToKey(roots, i, &k)) { 6208 elements.set(pos++, this->ValueAt(i), mode); 6209 } 6210 } 6211 DCHECK_EQ(pos, elements.length()); 6212} 6213 6214template <typename Derived, typename Shape> 6215int Dictionary<Derived, Shape>::NumberOfEnumerableProperties() { 6216 ReadOnlyRoots roots = this->GetReadOnlyRoots(); 6217 int result = 0; 6218 for (InternalIndex i : this->IterateEntries()) { 6219 Object k; 6220 if (!this->ToKey(roots, i, &k)) continue; 6221 if (k.FilterKey(ENUMERABLE_STRINGS)) continue; 6222 PropertyDetails details = this->DetailsAt(i); 6223 PropertyAttributes attr = details.attributes(); 6224 if ((attr & ONLY_ENUMERABLE) == 0) result++; 6225 } 6226 return result; 6227} 6228 6229template <typename Derived, typename Shape> 6230Handle<FixedArray> BaseNameDictionary<Derived, Shape>::IterationIndices( 6231 Isolate* isolate, Handle<Derived> dictionary) { 6232 Handle<FixedArray> array = 6233 isolate->factory()->NewFixedArray(dictionary->NumberOfElements()); 6234 ReadOnlyRoots roots(isolate); 6235 int array_size = 0; 6236 { 6237 DisallowGarbageCollection no_gc; 6238 Derived raw_dictionary = *dictionary; 6239 for (InternalIndex i : dictionary->IterateEntries()) { 6240 Object k; 6241 if (!raw_dictionary.ToKey(roots, i, &k)) continue; 6242 array->set(array_size++, Smi::FromInt(i.as_int())); 6243 } 6244 6245 // The global dictionary doesn't track its deletion count, so we may iterate 6246 // fewer entries than the count of elements claimed by the dictionary. 6247 if (std::is_same<Derived, GlobalDictionary>::value) { 6248 DCHECK_LE(array_size, dictionary->NumberOfElements()); 6249 } else { 6250 DCHECK_EQ(array_size, dictionary->NumberOfElements()); 6251 } 6252 6253 EnumIndexComparator<Derived> cmp(raw_dictionary); 6254 // Use AtomicSlot wrapper to ensure that std::sort uses atomic load and 6255 // store operations that are safe for concurrent marking. 6256 AtomicSlot start(array->GetFirstElementAddress()); 6257 std::sort(start, start + array_size, cmp); 6258 } 6259 return FixedArray::ShrinkOrEmpty(isolate, array, array_size); 6260} 6261 6262// Backwards lookup (slow). 6263template <typename Derived, typename Shape> 6264Object Dictionary<Derived, Shape>::SlowReverseLookup(Object value) { 6265 Derived dictionary = Derived::cast(*this); 6266 ReadOnlyRoots roots = dictionary.GetReadOnlyRoots(); 6267 for (InternalIndex i : dictionary.IterateEntries()) { 6268 Object k; 6269 if (!dictionary.ToKey(roots, i, &k)) continue; 6270 Object e = dictionary.ValueAt(i); 6271 if (e == value) return k; 6272 } 6273 return roots.undefined_value(); 6274} 6275 6276template <typename Derived, typename Shape> 6277void ObjectHashTableBase<Derived, Shape>::FillEntriesWithHoles( 6278 Handle<Derived> table) { 6279 int length = table->length(); 6280 for (int i = Derived::EntryToIndex(InternalIndex(0)); i < length; i++) { 6281 table->set_the_hole(i); 6282 } 6283} 6284 6285template <typename Derived, typename Shape> 6286Object ObjectHashTableBase<Derived, Shape>::Lookup(PtrComprCageBase cage_base, 6287 Handle<Object> key, 6288 int32_t hash) { 6289 DisallowGarbageCollection no_gc; 6290 ReadOnlyRoots roots = this->GetReadOnlyRoots(cage_base); 6291 DCHECK(this->IsKey(roots, *key)); 6292 6293 InternalIndex entry = this->FindEntry(cage_base, roots, key, hash); 6294 if (entry.is_not_found()) return roots.the_hole_value(); 6295 return this->get(Derived::EntryToIndex(entry) + 1); 6296} 6297 6298// The implementation should be in sync with 6299// CodeStubAssembler::NameToIndexHashTableLookup. 6300int NameToIndexHashTable::Lookup(Handle<Name> key) { 6301 DisallowGarbageCollection no_gc; 6302 PtrComprCageBase cage_base = GetPtrComprCageBase(*this); 6303 ReadOnlyRoots roots = this->GetReadOnlyRoots(cage_base); 6304 6305 InternalIndex entry = this->FindEntry(cage_base, roots, key, key->hash()); 6306 if (entry.is_not_found()) return -1; 6307 return Smi::cast(this->get(EntryToValueIndex(entry))).value(); 6308} 6309 6310template <typename Derived, typename Shape> 6311Object ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key) { 6312 DisallowGarbageCollection no_gc; 6313 6314 PtrComprCageBase cage_base = GetPtrComprCageBase(*this); 6315 ReadOnlyRoots roots = this->GetReadOnlyRoots(cage_base); 6316 DCHECK(this->IsKey(roots, *key)); 6317 6318 // If the object does not have an identity hash, it was never used as a key. 6319 Object hash = key->GetHash(); 6320 if (hash.IsUndefined(roots)) { 6321 return roots.the_hole_value(); 6322 } 6323 return Lookup(cage_base, key, Smi::ToInt(hash)); 6324} 6325 6326template <typename Derived, typename Shape> 6327Object ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key, 6328 int32_t hash) { 6329 return Lookup(GetPtrComprCageBase(*this), key, hash); 6330} 6331 6332template <typename Derived, typename Shape> 6333Object ObjectHashTableBase<Derived, Shape>::ValueAt(InternalIndex entry) { 6334 return this->get(EntryToValueIndex(entry)); 6335} 6336 6337Object RegisteredSymbolTable::ValueAt(InternalIndex entry) { 6338 return this->get(EntryToValueIndex(entry)); 6339} 6340 6341Object NameToIndexHashTable::ValueAt(InternalIndex entry) { 6342 return this->get(EntryToValueIndex(entry)); 6343} 6344 6345int NameToIndexHashTable::IndexAt(InternalIndex entry) { 6346 Object value = ValueAt(entry); 6347 if (value.IsSmi()) { 6348 int index = Smi::ToInt(value); 6349 DCHECK_LE(0, index); 6350 return index; 6351 } 6352 return -1; 6353} 6354 6355template <typename Derived, typename Shape> 6356Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table, 6357 Handle<Object> key, 6358 Handle<Object> value) { 6359 Isolate* isolate = Heap::FromWritableHeapObject(*table)->isolate(); 6360 DCHECK(table->IsKey(ReadOnlyRoots(isolate), *key)); 6361 DCHECK(!value->IsTheHole(ReadOnlyRoots(isolate))); 6362 6363 // Make sure the key object has an identity hash code. 6364 int32_t hash = key->GetOrCreateHash(isolate).value(); 6365 6366 return ObjectHashTableBase<Derived, Shape>::Put(isolate, table, key, value, 6367 hash); 6368} 6369 6370template <typename Derived, typename Shape> 6371Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Isolate* isolate, 6372 Handle<Derived> table, 6373 Handle<Object> key, 6374 Handle<Object> value, 6375 int32_t hash) { 6376 ReadOnlyRoots roots(isolate); 6377 DCHECK(table->IsKey(roots, *key)); 6378 DCHECK(!value->IsTheHole(roots)); 6379 6380 InternalIndex entry = table->FindEntry(isolate, roots, key, hash); 6381 6382 // Key is already in table, just overwrite value. 6383 if (entry.is_found()) { 6384 table->set(Derived::EntryToValueIndex(entry), *value); 6385 return table; 6386 } 6387 6388 // Rehash if more than 33% of the entries are deleted entries. 6389 // TODO(verwaest): Consider to shrink the fixed array in place. 6390 if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) { 6391 table->Rehash(isolate); 6392 } 6393 // If we're out of luck, we didn't get a GC recently, and so rehashing 6394 // isn't enough to avoid a crash. 6395 if (!table->HasSufficientCapacityToAdd(1)) { 6396 int nof = table->NumberOfElements() + 1; 6397 int capacity = ObjectHashTable::ComputeCapacity(nof * 2); 6398 if (capacity > ObjectHashTable::kMaxCapacity) { 6399 for (size_t i = 0; i < 2; ++i) { 6400 isolate->heap()->CollectAllGarbage( 6401 Heap::kNoGCFlags, GarbageCollectionReason::kFullHashtable); 6402 } 6403 table->Rehash(isolate); 6404 } 6405 } 6406 6407 // Check whether the hash table should be extended. 6408 table = Derived::EnsureCapacity(isolate, table); 6409 table->AddEntry(table->FindInsertionEntry(isolate, hash), *key, *value); 6410 return table; 6411} 6412 6413template <typename Derived, typename Shape> 6414Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove( 6415 Isolate* isolate, Handle<Derived> table, Handle<Object> key, 6416 bool* was_present) { 6417 DCHECK(table->IsKey(table->GetReadOnlyRoots(), *key)); 6418 6419 Object hash = key->GetHash(); 6420 if (hash.IsUndefined()) { 6421 *was_present = false; 6422 return table; 6423 } 6424 6425 return Remove(isolate, table, key, was_present, Smi::ToInt(hash)); 6426} 6427 6428template <typename Derived, typename Shape> 6429Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove( 6430 Isolate* isolate, Handle<Derived> table, Handle<Object> key, 6431 bool* was_present, int32_t hash) { 6432 ReadOnlyRoots roots = table->GetReadOnlyRoots(); 6433 DCHECK(table->IsKey(roots, *key)); 6434 6435 InternalIndex entry = table->FindEntry(isolate, roots, key, hash); 6436 if (entry.is_not_found()) { 6437 *was_present = false; 6438 return table; 6439 } 6440 6441 *was_present = true; 6442 table->RemoveEntry(entry); 6443 return Derived::Shrink(isolate, table); 6444} 6445 6446template <typename Derived, typename Shape> 6447void ObjectHashTableBase<Derived, Shape>::AddEntry(InternalIndex entry, 6448 Object key, Object value) { 6449 Derived* self = static_cast<Derived*>(this); 6450 self->set_key(Derived::EntryToIndex(entry), key); 6451 self->set(Derived::EntryToValueIndex(entry), value); 6452 self->ElementAdded(); 6453} 6454 6455template <typename Derived, typename Shape> 6456void ObjectHashTableBase<Derived, Shape>::RemoveEntry(InternalIndex entry) { 6457 this->set_the_hole(Derived::EntryToIndex(entry)); 6458 this->set_the_hole(Derived::EntryToValueIndex(entry)); 6459 this->ElementRemoved(); 6460} 6461 6462void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) { 6463 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet(); 6464 set->set_table(*table); 6465} 6466 6467void JSSet::Clear(Isolate* isolate, Handle<JSSet> set) { 6468 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()), isolate); 6469 table = OrderedHashSet::Clear(isolate, table); 6470 set->set_table(*table); 6471} 6472 6473void JSSet::Rehash(Isolate* isolate) { 6474 Handle<OrderedHashSet> table_handle(OrderedHashSet::cast(table()), isolate); 6475 Handle<OrderedHashSet> new_table = 6476 OrderedHashSet::Rehash(isolate, table_handle).ToHandleChecked(); 6477 set_table(*new_table); 6478} 6479 6480void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) { 6481 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap(); 6482 map->set_table(*table); 6483} 6484 6485void JSMap::Clear(Isolate* isolate, Handle<JSMap> map) { 6486 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()), isolate); 6487 table = OrderedHashMap::Clear(isolate, table); 6488 map->set_table(*table); 6489} 6490 6491void JSMap::Rehash(Isolate* isolate) { 6492 Handle<OrderedHashMap> table_handle(OrderedHashMap::cast(table()), isolate); 6493 Handle<OrderedHashMap> new_table = 6494 OrderedHashMap::Rehash(isolate, table_handle).ToHandleChecked(); 6495 set_table(*new_table); 6496} 6497 6498void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection, 6499 Isolate* isolate) { 6500 Handle<EphemeronHashTable> table = EphemeronHashTable::New(isolate, 0); 6501 weak_collection->set_table(*table); 6502} 6503 6504void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection, 6505 Handle<Object> key, Handle<Object> value, 6506 int32_t hash) { 6507 DCHECK(key->IsJSReceiver() || key->IsSymbol()); 6508 Handle<EphemeronHashTable> table( 6509 EphemeronHashTable::cast(weak_collection->table()), 6510 weak_collection->GetIsolate()); 6511 DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key)); 6512 Handle<EphemeronHashTable> new_table = EphemeronHashTable::Put( 6513 weak_collection->GetIsolate(), table, key, value, hash); 6514 weak_collection->set_table(*new_table); 6515 if (*table != *new_table) { 6516 // Zap the old table since we didn't record slots for its elements. 6517 EphemeronHashTable::FillEntriesWithHoles(table); 6518 } 6519} 6520 6521bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection, 6522 Handle<Object> key, int32_t hash) { 6523 DCHECK(key->IsJSReceiver() || key->IsSymbol()); 6524 Handle<EphemeronHashTable> table( 6525 EphemeronHashTable::cast(weak_collection->table()), 6526 weak_collection->GetIsolate()); 6527 DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key)); 6528 bool was_present = false; 6529 Handle<EphemeronHashTable> new_table = EphemeronHashTable::Remove( 6530 weak_collection->GetIsolate(), table, key, &was_present, hash); 6531 weak_collection->set_table(*new_table); 6532 if (*table != *new_table) { 6533 // Zap the old table since we didn't record slots for its elements. 6534 EphemeronHashTable::FillEntriesWithHoles(table); 6535 } 6536 return was_present; 6537} 6538 6539Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder, 6540 int max_entries) { 6541 Isolate* isolate = holder->GetIsolate(); 6542 Handle<EphemeronHashTable> table(EphemeronHashTable::cast(holder->table()), 6543 isolate); 6544 if (max_entries == 0 || max_entries > table->NumberOfElements()) { 6545 max_entries = table->NumberOfElements(); 6546 } 6547 int values_per_entry = holder->IsJSWeakMap() ? 2 : 1; 6548 Handle<FixedArray> entries = 6549 isolate->factory()->NewFixedArray(max_entries * values_per_entry); 6550 // Recompute max_values because GC could have removed elements from the table. 6551 if (max_entries > table->NumberOfElements()) { 6552 max_entries = table->NumberOfElements(); 6553 } 6554 6555 { 6556 DisallowGarbageCollection no_gc; 6557 ReadOnlyRoots roots = ReadOnlyRoots(isolate); 6558 int count = 0; 6559 for (int i = 0; 6560 count / values_per_entry < max_entries && i < table->Capacity(); i++) { 6561 Object key; 6562 if (table->ToKey(roots, InternalIndex(i), &key)) { 6563 entries->set(count++, key); 6564 if (values_per_entry > 1) { 6565 Object value = table->Lookup(handle(key, isolate)); 6566 entries->set(count++, value); 6567 } 6568 } 6569 } 6570 DCHECK_EQ(max_entries * values_per_entry, count); 6571 } 6572 return isolate->factory()->NewJSArrayWithElements(entries); 6573} 6574 6575void PropertyCell::ClearAndInvalidate(ReadOnlyRoots roots) { 6576 DCHECK(!value().IsTheHole(roots)); 6577 PropertyDetails details = property_details(); 6578 details = details.set_cell_type(PropertyCellType::kConstant); 6579 Transition(details, roots.the_hole_value_handle()); 6580 // TODO(11527): pass Isolate as an argument. 6581 Isolate* isolate = GetIsolateFromWritableObject(*this); 6582 dependent_code().DeoptimizeDependentCodeGroup( 6583 isolate, DependentCode::kPropertyCellChangedGroup); 6584} 6585 6586// static 6587Handle<PropertyCell> PropertyCell::InvalidateAndReplaceEntry( 6588 Isolate* isolate, Handle<GlobalDictionary> dictionary, InternalIndex entry, 6589 PropertyDetails new_details, Handle<Object> new_value) { 6590 Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate); 6591 Handle<Name> name(cell->name(), isolate); 6592 DCHECK(cell->property_details().IsConfigurable()); 6593 DCHECK(!cell->value().IsTheHole(isolate)); 6594 6595 // Swap with a new property cell. 6596 Handle<PropertyCell> new_cell = 6597 isolate->factory()->NewPropertyCell(name, new_details, new_value); 6598 dictionary->ValueAtPut(entry, *new_cell); 6599 6600 cell->ClearAndInvalidate(ReadOnlyRoots(isolate)); 6601 return new_cell; 6602} 6603 6604static bool RemainsConstantType(PropertyCell cell, Object value) { 6605 DisallowGarbageCollection no_gc; 6606 // TODO(dcarney): double->smi and smi->double transition from kConstant 6607 if (cell.value().IsSmi() && value.IsSmi()) { 6608 return true; 6609 } else if (cell.value().IsHeapObject() && value.IsHeapObject()) { 6610 Map map = HeapObject::cast(value).map(); 6611 return HeapObject::cast(cell.value()).map() == map && map.is_stable(); 6612 } 6613 return false; 6614} 6615 6616// static 6617PropertyCellType PropertyCell::InitialType(Isolate* isolate, Object value) { 6618 return value.IsUndefined(isolate) ? PropertyCellType::kUndefined 6619 : PropertyCellType::kConstant; 6620} 6621 6622// static 6623PropertyCellType PropertyCell::UpdatedType(Isolate* isolate, PropertyCell cell, 6624 Object value, 6625 PropertyDetails details) { 6626 DisallowGarbageCollection no_gc; 6627 DCHECK(!value.IsTheHole(isolate)); 6628 DCHECK(!cell.value().IsTheHole(isolate)); 6629 switch (details.cell_type()) { 6630 case PropertyCellType::kUndefined: 6631 return PropertyCellType::kConstant; 6632 case PropertyCellType::kConstant: 6633 if (value == cell.value()) return PropertyCellType::kConstant; 6634 V8_FALLTHROUGH; 6635 case PropertyCellType::kConstantType: 6636 if (RemainsConstantType(cell, value)) { 6637 return PropertyCellType::kConstantType; 6638 } 6639 V8_FALLTHROUGH; 6640 case PropertyCellType::kMutable: 6641 return PropertyCellType::kMutable; 6642 case PropertyCellType::kInTransition: 6643 UNREACHABLE(); 6644 } 6645} 6646 6647Handle<PropertyCell> PropertyCell::PrepareForAndSetValue( 6648 Isolate* isolate, Handle<GlobalDictionary> dictionary, InternalIndex entry, 6649 Handle<Object> value, PropertyDetails details) { 6650 DCHECK(!value->IsTheHole(isolate)); 6651 PropertyCell raw_cell = dictionary->CellAt(entry); 6652 CHECK(!raw_cell.value().IsTheHole(isolate)); 6653 const PropertyDetails original_details = raw_cell.property_details(); 6654 // Data accesses could be cached in ics or optimized code. 6655 bool invalidate = original_details.kind() == PropertyKind::kData && 6656 details.kind() == PropertyKind::kAccessor; 6657 int index = original_details.dictionary_index(); 6658 DCHECK_LT(0, index); 6659 details = details.set_index(index); 6660 6661 PropertyCellType new_type = 6662 UpdatedType(isolate, raw_cell, *value, original_details); 6663 details = details.set_cell_type(new_type); 6664 6665 Handle<PropertyCell> cell(raw_cell, isolate); 6666 6667 if (invalidate) { 6668 cell = PropertyCell::InvalidateAndReplaceEntry(isolate, dictionary, entry, 6669 details, value); 6670 } else { 6671 cell->Transition(details, value); 6672 // Deopt when transitioning from a constant type or when making a writable 6673 // property read-only. Making a read-only property writable again is not 6674 // interesting because Turbofan does not currently rely on read-only unless 6675 // the property is also configurable, in which case it will stay read-only 6676 // forever. 6677 if (original_details.cell_type() != new_type || 6678 (!original_details.IsReadOnly() && details.IsReadOnly())) { 6679 cell->dependent_code().DeoptimizeDependentCodeGroup( 6680 isolate, DependentCode::kPropertyCellChangedGroup); 6681 } 6682 } 6683 return cell; 6684} 6685 6686// static 6687void PropertyCell::InvalidateProtector() { 6688 if (value() != Smi::FromInt(Protectors::kProtectorInvalid)) { 6689 DCHECK_EQ(value(), Smi::FromInt(Protectors::kProtectorValid)); 6690 set_value(Smi::FromInt(Protectors::kProtectorInvalid), kReleaseStore); 6691 // TODO(11527): pass Isolate as an argument. 6692 Isolate* isolate = GetIsolateFromWritableObject(*this); 6693 dependent_code().DeoptimizeDependentCodeGroup( 6694 isolate, DependentCode::kPropertyCellChangedGroup); 6695 } 6696} 6697 6698// static 6699bool PropertyCell::CheckDataIsCompatible(PropertyDetails details, 6700 Object value) { 6701 DisallowGarbageCollection no_gc; 6702 PropertyCellType cell_type = details.cell_type(); 6703 CHECK_NE(cell_type, PropertyCellType::kInTransition); 6704 if (value.IsTheHole()) { 6705 CHECK_EQ(cell_type, PropertyCellType::kConstant); 6706 } else { 6707 CHECK_EQ(value.IsAccessorInfo() || value.IsAccessorPair(), 6708 details.kind() == PropertyKind::kAccessor); 6709 DCHECK_IMPLIES(cell_type == PropertyCellType::kUndefined, 6710 value.IsUndefined()); 6711 } 6712 return true; 6713} 6714 6715#ifdef DEBUG 6716bool PropertyCell::CanTransitionTo(PropertyDetails new_details, 6717 Object new_value) const { 6718 // Extending the implementation of PropertyCells with additional states 6719 // and/or transitions likely requires changes to PropertyCellData::Serialize. 6720 DisallowGarbageCollection no_gc; 6721 DCHECK(CheckDataIsCompatible(new_details, new_value)); 6722 switch (property_details().cell_type()) { 6723 case PropertyCellType::kUndefined: 6724 return new_details.cell_type() != PropertyCellType::kUndefined; 6725 case PropertyCellType::kConstant: 6726 return !value().IsTheHole() && 6727 new_details.cell_type() != PropertyCellType::kUndefined; 6728 case PropertyCellType::kConstantType: 6729 return new_details.cell_type() == PropertyCellType::kConstantType || 6730 new_details.cell_type() == PropertyCellType::kMutable || 6731 (new_details.cell_type() == PropertyCellType::kConstant && 6732 new_value.IsTheHole()); 6733 case PropertyCellType::kMutable: 6734 return new_details.cell_type() == PropertyCellType::kMutable || 6735 (new_details.cell_type() == PropertyCellType::kConstant && 6736 new_value.IsTheHole()); 6737 case PropertyCellType::kInTransition: 6738 UNREACHABLE(); 6739 } 6740} 6741#endif // DEBUG 6742 6743int JSGeneratorObject::source_position() const { 6744 CHECK(is_suspended()); 6745 DCHECK(function().shared().HasBytecodeArray()); 6746 Isolate* isolate = GetIsolate(); 6747 DCHECK( 6748 function().shared().GetBytecodeArray(isolate).HasSourcePositionTable()); 6749 6750 int code_offset = Smi::ToInt(input_or_debug_pos()); 6751 6752 // The stored bytecode offset is relative to a different base than what 6753 // is used in the source position table, hence the subtraction. 6754 code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag; 6755 AbstractCode code = 6756 AbstractCode::cast(function().shared().GetBytecodeArray(isolate)); 6757 return code.SourcePosition(code_offset); 6758} 6759 6760// static 6761AccessCheckInfo AccessCheckInfo::Get(Isolate* isolate, 6762 Handle<JSObject> receiver) { 6763 DisallowGarbageCollection no_gc; 6764 DCHECK(receiver->map().is_access_check_needed()); 6765 Object maybe_constructor = receiver->map().GetConstructor(); 6766 if (maybe_constructor.IsFunctionTemplateInfo()) { 6767 Object data_obj = 6768 FunctionTemplateInfo::cast(maybe_constructor).GetAccessCheckInfo(); 6769 if (data_obj.IsUndefined(isolate)) return AccessCheckInfo(); 6770 return AccessCheckInfo::cast(data_obj); 6771 } 6772 // Might happen for a detached context. 6773 if (!maybe_constructor.IsJSFunction()) return AccessCheckInfo(); 6774 JSFunction constructor = JSFunction::cast(maybe_constructor); 6775 // Might happen for the debug context. 6776 if (!constructor.shared().IsApiFunction()) return AccessCheckInfo(); 6777 6778 Object data_obj = 6779 constructor.shared().get_api_func_data().GetAccessCheckInfo(); 6780 if (data_obj.IsUndefined(isolate)) return AccessCheckInfo(); 6781 6782 return AccessCheckInfo::cast(data_obj); 6783} 6784 6785Address Smi::LexicographicCompare(Isolate* isolate, Smi x, Smi y) { 6786 DisallowGarbageCollection no_gc; 6787 DisallowJavascriptExecution no_js(isolate); 6788 6789 int x_value = Smi::ToInt(x); 6790 int y_value = Smi::ToInt(y); 6791 6792 // If the integers are equal so are the string representations. 6793 if (x_value == y_value) return Smi::FromInt(0).ptr(); 6794 6795 // If one of the integers is zero the normal integer order is the 6796 // same as the lexicographic order of the string representations. 6797 if (x_value == 0 || y_value == 0) { 6798 return Smi::FromInt(x_value < y_value ? -1 : 1).ptr(); 6799 } 6800 6801 // If only one of the integers is negative the negative number is 6802 // smallest because the char code of '-' is less than the char code 6803 // of any digit. Otherwise, we make both values positive. 6804 6805 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on 6806 // architectures using 32-bit Smis. 6807 uint32_t x_scaled = x_value; 6808 uint32_t y_scaled = y_value; 6809 if (x_value < 0) { 6810 if (y_value >= 0) { 6811 return Smi::FromInt(-1).ptr(); 6812 } else { 6813 y_scaled = base::NegateWithWraparound(y_value); 6814 } 6815 x_scaled = base::NegateWithWraparound(x_value); 6816 } else if (y_value < 0) { 6817 return Smi::FromInt(1).ptr(); 6818 } 6819 6820 // clang-format off 6821 static const uint32_t kPowersOf10[] = { 6822 1, 10, 100, 1000, 6823 10 * 1000, 100 * 1000, 1000 * 1000, 10 * 1000 * 1000, 6824 100 * 1000 * 1000, 1000 * 1000 * 1000}; 6825 // clang-format on 6826 6827 // If the integers have the same number of decimal digits they can be 6828 // compared directly as the numeric order is the same as the 6829 // lexicographic order. If one integer has fewer digits, it is scaled 6830 // by some power of 10 to have the same number of digits as the longer 6831 // integer. If the scaled integers are equal it means the shorter 6832 // integer comes first in the lexicographic order. 6833 6834 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 6835 int x_log2 = 31 - base::bits::CountLeadingZeros(x_scaled); 6836 int x_log10 = ((x_log2 + 1) * 1233) >> 12; 6837 x_log10 -= x_scaled < kPowersOf10[x_log10]; 6838 6839 int y_log2 = 31 - base::bits::CountLeadingZeros(y_scaled); 6840 int y_log10 = ((y_log2 + 1) * 1233) >> 12; 6841 y_log10 -= y_scaled < kPowersOf10[y_log10]; 6842 6843 int tie = 0; 6844 6845 if (x_log10 < y_log10) { 6846 // X has fewer digits. We would like to simply scale up X but that 6847 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would 6848 // be scaled up to 9_000_000_000. So we scale up by the next 6849 // smallest power and scale down Y to drop one digit. It is OK to 6850 // drop one digit from the longer integer since the final digit is 6851 // past the length of the shorter integer. 6852 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1]; 6853 y_scaled /= 10; 6854 tie = -1; 6855 } else if (y_log10 < x_log10) { 6856 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1]; 6857 x_scaled /= 10; 6858 tie = 1; 6859 } 6860 6861 if (x_scaled < y_scaled) return Smi::FromInt(-1).ptr(); 6862 if (x_scaled > y_scaled) return Smi::FromInt(1).ptr(); 6863 return Smi::FromInt(tie).ptr(); 6864} 6865 6866// Force instantiation of template instances class. 6867// Please note this list is compiler dependent. 6868// Keep this at the end of this file 6869 6870#define EXTERN_DEFINE_HASH_TABLE(DERIVED, SHAPE) \ 6871 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) \ 6872 HashTable<DERIVED, SHAPE>; \ 6873 \ 6874 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<DERIVED> \ 6875 HashTable<DERIVED, SHAPE>::New(Isolate*, int, AllocationType, \ 6876 MinimumCapacity); \ 6877 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<DERIVED> \ 6878 HashTable<DERIVED, SHAPE>::New(LocalIsolate*, int, AllocationType, \ 6879 MinimumCapacity); \ 6880 \ 6881 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<DERIVED> \ 6882 HashTable<DERIVED, SHAPE>::EnsureCapacity(Isolate*, Handle<DERIVED>, int, \ 6883 AllocationType); \ 6884 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<DERIVED> \ 6885 HashTable<DERIVED, SHAPE>::EnsureCapacity(LocalIsolate*, Handle<DERIVED>, \ 6886 int, AllocationType); 6887 6888#define EXTERN_DEFINE_OBJECT_BASE_HASH_TABLE(DERIVED, SHAPE) \ 6889 EXTERN_DEFINE_HASH_TABLE(DERIVED, SHAPE) \ 6890 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) \ 6891 ObjectHashTableBase<DERIVED, SHAPE>; 6892 6893#define EXTERN_DEFINE_DICTIONARY(DERIVED, SHAPE) \ 6894 EXTERN_DEFINE_HASH_TABLE(DERIVED, SHAPE) \ 6895 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) \ 6896 Dictionary<DERIVED, SHAPE>; \ 6897 \ 6898 template V8_EXPORT_PRIVATE Handle<DERIVED> Dictionary<DERIVED, SHAPE>::Add( \ 6899 Isolate* isolate, Handle<DERIVED>, Key, Handle<Object>, PropertyDetails, \ 6900 InternalIndex*); \ 6901 template V8_EXPORT_PRIVATE Handle<DERIVED> Dictionary<DERIVED, SHAPE>::Add( \ 6902 LocalIsolate* isolate, Handle<DERIVED>, Key, Handle<Object>, \ 6903 PropertyDetails, InternalIndex*); 6904 6905#define EXTERN_DEFINE_BASE_NAME_DICTIONARY(DERIVED, SHAPE) \ 6906 EXTERN_DEFINE_DICTIONARY(DERIVED, SHAPE) \ 6907 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) \ 6908 BaseNameDictionary<DERIVED, SHAPE>; \ 6909 \ 6910 template V8_EXPORT_PRIVATE Handle<DERIVED> \ 6911 BaseNameDictionary<DERIVED, SHAPE>::New(Isolate*, int, AllocationType, \ 6912 MinimumCapacity); \ 6913 template V8_EXPORT_PRIVATE Handle<DERIVED> \ 6914 BaseNameDictionary<DERIVED, SHAPE>::New(LocalIsolate*, int, AllocationType, \ 6915 MinimumCapacity); \ 6916 \ 6917 template Handle<DERIVED> \ 6918 BaseNameDictionary<DERIVED, SHAPE>::AddNoUpdateNextEnumerationIndex( \ 6919 Isolate* isolate, Handle<DERIVED>, Key, Handle<Object>, PropertyDetails, \ 6920 InternalIndex*); \ 6921 template Handle<DERIVED> \ 6922 BaseNameDictionary<DERIVED, SHAPE>::AddNoUpdateNextEnumerationIndex( \ 6923 LocalIsolate* isolate, Handle<DERIVED>, Key, Handle<Object>, \ 6924 PropertyDetails, InternalIndex*); 6925 6926EXTERN_DEFINE_HASH_TABLE(StringSet, StringSetShape) 6927EXTERN_DEFINE_HASH_TABLE(CompilationCacheTable, CompilationCacheShape) 6928EXTERN_DEFINE_HASH_TABLE(ObjectHashSet, ObjectHashSetShape) 6929EXTERN_DEFINE_HASH_TABLE(NameToIndexHashTable, NameToIndexShape) 6930EXTERN_DEFINE_HASH_TABLE(RegisteredSymbolTable, RegisteredSymbolTableShape) 6931 6932EXTERN_DEFINE_OBJECT_BASE_HASH_TABLE(ObjectHashTable, ObjectHashTableShape) 6933EXTERN_DEFINE_OBJECT_BASE_HASH_TABLE(EphemeronHashTable, ObjectHashTableShape) 6934 6935EXTERN_DEFINE_DICTIONARY(SimpleNumberDictionary, SimpleNumberDictionaryShape) 6936EXTERN_DEFINE_DICTIONARY(NumberDictionary, NumberDictionaryShape) 6937 6938EXTERN_DEFINE_BASE_NAME_DICTIONARY(NameDictionary, NameDictionaryShape) 6939EXTERN_DEFINE_BASE_NAME_DICTIONARY(GlobalDictionary, GlobalDictionaryShape) 6940 6941#undef EXTERN_DEFINE_HASH_TABLE 6942#undef EXTERN_DEFINE_OBJECT_BASE_HASH_TABLE 6943#undef EXTERN_DEFINE_DICTIONARY 6944#undef EXTERN_DEFINE_BASE_NAME_DICTIONARY 6945 6946void JSFinalizationRegistry::RemoveCellFromUnregisterTokenMap( 6947 Isolate* isolate, Address raw_finalization_registry, 6948 Address raw_weak_cell) { 6949 DisallowGarbageCollection no_gc; 6950 JSFinalizationRegistry finalization_registry = 6951 JSFinalizationRegistry::cast(Object(raw_finalization_registry)); 6952 WeakCell weak_cell = WeakCell::cast(Object(raw_weak_cell)); 6953 DCHECK(!weak_cell.unregister_token().IsUndefined(isolate)); 6954 HeapObject undefined = ReadOnlyRoots(isolate).undefined_value(); 6955 6956 // Remove weak_cell from the linked list of other WeakCells with the same 6957 // unregister token and remove its unregister token from key_map if necessary 6958 // without shrinking it. Since shrinking may allocate, it is performed by the 6959 // caller after looping, or on exception. 6960 if (weak_cell.key_list_prev().IsUndefined(isolate)) { 6961 SimpleNumberDictionary key_map = 6962 SimpleNumberDictionary::cast(finalization_registry.key_map()); 6963 HeapObject unregister_token = weak_cell.unregister_token(); 6964 uint32_t key = Smi::ToInt(unregister_token.GetHash()); 6965 InternalIndex entry = key_map.FindEntry(isolate, key); 6966 DCHECK(entry.is_found()); 6967 6968 if (weak_cell.key_list_next().IsUndefined(isolate)) { 6969 // weak_cell is the only one associated with its key; remove the key 6970 // from the hash table. 6971 key_map.ClearEntry(entry); 6972 key_map.ElementRemoved(); 6973 } else { 6974 // weak_cell is the list head for its key; we need to change the value 6975 // of the key in the hash table. 6976 WeakCell next = WeakCell::cast(weak_cell.key_list_next()); 6977 DCHECK_EQ(next.key_list_prev(), weak_cell); 6978 next.set_key_list_prev(undefined); 6979 key_map.ValueAtPut(entry, next); 6980 } 6981 } else { 6982 // weak_cell is somewhere in the middle of its key list. 6983 WeakCell prev = WeakCell::cast(weak_cell.key_list_prev()); 6984 prev.set_key_list_next(weak_cell.key_list_next()); 6985 if (!weak_cell.key_list_next().IsUndefined()) { 6986 WeakCell next = WeakCell::cast(weak_cell.key_list_next()); 6987 next.set_key_list_prev(weak_cell.key_list_prev()); 6988 } 6989 } 6990 6991 // weak_cell is now removed from the unregister token map, so clear its 6992 // unregister token-related fields. 6993 weak_cell.set_unregister_token(undefined); 6994 weak_cell.set_key_list_prev(undefined); 6995 weak_cell.set_key_list_next(undefined); 6996} 6997 6998} // namespace internal 6999} // namespace v8 7000