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.h" 6 7 #include <cmath> 8 #include <iomanip> 9 #include <memory> 10 #include <sstream> 11 #include <vector> 12 13 #include "src/objects-inl.h" 14 15 #include "src/accessors.h" 16 #include "src/allocation-site-scopes.h" 17 #include "src/api-arguments-inl.h" 18 #include "src/api-natives.h" 19 #include "src/api.h" 20 #include "src/arguments.h" 21 #include "src/ast/ast.h" 22 #include "src/ast/scopes.h" 23 #include "src/base/bits.h" 24 #include "src/base/utils/random-number-generator.h" 25 #include "src/bootstrapper.h" 26 #include "src/builtins/builtins.h" 27 #include "src/code-stubs.h" 28 #include "src/compiler.h" 29 #include "src/counters-inl.h" 30 #include "src/counters.h" 31 #include "src/date.h" 32 #include "src/debug/debug.h" 33 #include "src/deoptimizer.h" 34 #include "src/elements.h" 35 #include "src/execution.h" 36 #include "src/field-index-inl.h" 37 #include "src/field-index.h" 38 #include "src/field-type.h" 39 #include "src/frames-inl.h" 40 #include "src/globals.h" 41 #include "src/ic/ic.h" 42 #include "src/identity-map.h" 43 #include "src/interpreter/bytecode-array-iterator.h" 44 #include "src/interpreter/bytecode-decoder.h" 45 #include "src/interpreter/interpreter.h" 46 #include "src/isolate-inl.h" 47 #include "src/keys.h" 48 #include "src/log.h" 49 #include "src/lookup-inl.h" 50 #include "src/macro-assembler.h" 51 #include "src/map-updater.h" 52 #include "src/messages.h" 53 #include "src/objects-body-descriptors-inl.h" 54 #include "src/objects/api-callbacks.h" 55 #include "src/objects/arguments-inl.h" 56 #include "src/objects/bigint.h" 57 #include "src/objects/code-inl.h" 58 #include "src/objects/compilation-cache-inl.h" 59 #include "src/objects/debug-objects-inl.h" 60 #include "src/objects/frame-array-inl.h" 61 #include "src/objects/hash-table-inl.h" 62 #include "src/objects/js-array-inl.h" 63 #ifdef V8_INTL_SUPPORT 64 #include "src/objects/js-collator.h" 65 #endif // V8_INTL_SUPPORT 66 #include "src/objects/js-collection-inl.h" 67 #include "src/objects/js-generator-inl.h" 68 #ifdef V8_INTL_SUPPORT 69 #include "src/objects/js-list-format.h" 70 #include "src/objects/js-locale.h" 71 #endif // V8_INTL_SUPPORT 72 #include "src/objects/js-regexp-inl.h" 73 #include "src/objects/js-regexp-string-iterator.h" 74 #ifdef V8_INTL_SUPPORT 75 #include "src/objects/js-plural-rules.h" 76 #include "src/objects/js-relative-time-format.h" 77 #endif // V8_INTL_SUPPORT 78 #include "src/objects/literal-objects-inl.h" 79 #include "src/objects/map.h" 80 #include "src/objects/microtask-inl.h" 81 #include "src/objects/module-inl.h" 82 #include "src/objects/promise-inl.h" 83 #include "src/parsing/preparsed-scope-data.h" 84 #include "src/property-descriptor.h" 85 #include "src/prototype.h" 86 #include "src/regexp/jsregexp.h" 87 #include "src/safepoint-table.h" 88 #include "src/snapshot/code-serializer.h" 89 #include "src/snapshot/snapshot.h" 90 #include "src/source-position-table.h" 91 #include "src/string-builder-inl.h" 92 #include "src/string-search.h" 93 #include "src/string-stream.h" 94 #include "src/unicode-cache-inl.h" 95 #include "src/unicode-decoder.h" 96 #include "src/utils-inl.h" 97 #include "src/wasm/wasm-engine.h" 98 #include "src/wasm/wasm-objects.h" 99 #include "src/zone/zone.h" 100 101 #ifdef ENABLE_DISASSEMBLER 102 #include "src/disasm.h" 103 #include "src/disassembler.h" 104 #include "src/eh-frame.h" 105 #endif 106 107 namespace v8 { 108 namespace internal { 109 110 bool ComparisonResultToBool(Operation op, ComparisonResult result) { 111 switch (op) { 112 case Operation::kLessThan: 113 return result == ComparisonResult::kLessThan; 114 case Operation::kLessThanOrEqual: 115 return result == ComparisonResult::kLessThan || 116 result == ComparisonResult::kEqual; 117 case Operation::kGreaterThan: 118 return result == ComparisonResult::kGreaterThan; 119 case Operation::kGreaterThanOrEqual: 120 return result == ComparisonResult::kGreaterThan || 121 result == ComparisonResult::kEqual; 122 default: 123 break; 124 } 125 UNREACHABLE(); 126 } 127 128 std::ostream& operator<<(std::ostream& os, InstanceType instance_type) { 129 switch (instance_type) { 130 #define WRITE_TYPE(TYPE) \ 131 case TYPE: \ 132 return os << #TYPE; 133 INSTANCE_TYPE_LIST(WRITE_TYPE) 134 #undef WRITE_TYPE 135 } 136 UNREACHABLE(); 137 } 138 139 Handle<FieldType> Object::OptimalType(Isolate* isolate, 140 Representation representation) { 141 if (representation.IsNone()) return FieldType::None(isolate); 142 if (FLAG_track_field_types) { 143 if (representation.IsHeapObject() && IsHeapObject()) { 144 // We can track only JavaScript objects with stable maps. 145 Handle<Map> map(HeapObject::cast(this)->map(), isolate); 146 if (map->is_stable() && map->IsJSReceiverMap()) { 147 return FieldType::Class(map, isolate); 148 } 149 } 150 } 151 return FieldType::Any(isolate); 152 } 153 154 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate, 155 Handle<Object> object, 156 Handle<Context> native_context, 157 const char* method_name) { 158 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); 159 Handle<JSFunction> constructor; 160 if (object->IsSmi()) { 161 constructor = handle(native_context->number_function(), isolate); 162 } else { 163 int constructor_function_index = 164 Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex(); 165 if (constructor_function_index == Map::kNoConstructorFunctionIndex) { 166 if (method_name != nullptr) { 167 THROW_NEW_ERROR( 168 isolate, 169 NewTypeError( 170 MessageTemplate::kCalledOnNullOrUndefined, 171 isolate->factory()->NewStringFromAsciiChecked(method_name)), 172 JSReceiver); 173 } 174 THROW_NEW_ERROR(isolate, 175 NewTypeError(MessageTemplate::kUndefinedOrNullToObject), 176 JSReceiver); 177 } 178 constructor = handle( 179 JSFunction::cast(native_context->get(constructor_function_index)), 180 isolate); 181 } 182 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); 183 Handle<JSValue>::cast(result)->set_value(*object); 184 return result; 185 } 186 187 // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee. 188 // static 189 MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate, 190 Handle<Object> object) { 191 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); 192 if (object->IsNullOrUndefined(isolate)) { 193 return isolate->global_proxy(); 194 } 195 return Object::ToObject(isolate, object); 196 } 197 198 // static 199 MaybeHandle<Object> Object::ConvertToNumberOrNumeric(Isolate* isolate, 200 Handle<Object> input, 201 Conversion mode) { 202 while (true) { 203 if (input->IsNumber()) { 204 return input; 205 } 206 if (input->IsString()) { 207 return String::ToNumber(isolate, Handle<String>::cast(input)); 208 } 209 if (input->IsOddball()) { 210 return Oddball::ToNumber(isolate, Handle<Oddball>::cast(input)); 211 } 212 if (input->IsSymbol()) { 213 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber), 214 Object); 215 } 216 if (input->IsBigInt()) { 217 if (mode == Conversion::kToNumeric) return input; 218 DCHECK_EQ(mode, Conversion::kToNumber); 219 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntToNumber), 220 Object); 221 } 222 ASSIGN_RETURN_ON_EXCEPTION( 223 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), 224 ToPrimitiveHint::kNumber), 225 Object); 226 } 227 } 228 229 // static 230 MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate, 231 Handle<Object> input) { 232 ASSIGN_RETURN_ON_EXCEPTION( 233 isolate, input, 234 ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); 235 if (input->IsSmi()) return input; 236 return isolate->factory()->NewNumber(DoubleToInteger(input->Number())); 237 } 238 239 // static 240 MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate, 241 Handle<Object> input) { 242 ASSIGN_RETURN_ON_EXCEPTION( 243 isolate, input, 244 ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); 245 if (input->IsSmi()) return input; 246 return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number())); 247 } 248 249 // static 250 MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate, 251 Handle<Object> input) { 252 ASSIGN_RETURN_ON_EXCEPTION( 253 isolate, input, 254 ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); 255 if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate); 256 return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number())); 257 } 258 259 // static 260 MaybeHandle<Name> Object::ConvertToName(Isolate* isolate, 261 Handle<Object> input) { 262 ASSIGN_RETURN_ON_EXCEPTION( 263 isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString), 264 Name); 265 if (input->IsName()) return Handle<Name>::cast(input); 266 return ToString(isolate, input); 267 } 268 269 // ES6 7.1.14 270 // static 271 MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate, 272 Handle<Object> value) { 273 // 1. Let key be ToPrimitive(argument, hint String). 274 MaybeHandle<Object> maybe_key = 275 Object::ToPrimitive(value, ToPrimitiveHint::kString); 276 // 2. ReturnIfAbrupt(key). 277 Handle<Object> key; 278 if (!maybe_key.ToHandle(&key)) return key; 279 // 3. If Type(key) is Symbol, then return key. 280 if (key->IsSymbol()) return key; 281 // 4. Return ToString(key). 282 // Extending spec'ed behavior, we'd be happy to return an element index. 283 if (key->IsSmi()) return key; 284 if (key->IsHeapNumber()) { 285 uint32_t uint_value; 286 if (value->ToArrayLength(&uint_value) && 287 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) { 288 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate); 289 } 290 } 291 return Object::ToString(isolate, key); 292 } 293 294 // static 295 MaybeHandle<String> Object::ConvertToString(Isolate* isolate, 296 Handle<Object> input) { 297 while (true) { 298 if (input->IsOddball()) { 299 return handle(Handle<Oddball>::cast(input)->to_string(), isolate); 300 } 301 if (input->IsNumber()) { 302 return isolate->factory()->NumberToString(input); 303 } 304 if (input->IsSymbol()) { 305 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString), 306 String); 307 } 308 if (input->IsBigInt()) { 309 return BigInt::ToString(isolate, Handle<BigInt>::cast(input)); 310 } 311 ASSIGN_RETURN_ON_EXCEPTION( 312 isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), 313 ToPrimitiveHint::kString), 314 String); 315 // The previous isString() check happened in Object::ToString and thus we 316 // put it at the end of the loop in this helper. 317 if (input->IsString()) { 318 return Handle<String>::cast(input); 319 } 320 } 321 } 322 323 namespace { 324 325 bool IsErrorObject(Isolate* isolate, Handle<Object> object) { 326 if (!object->IsJSReceiver()) return false; 327 Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol(); 328 return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol) 329 .FromMaybe(false); 330 } 331 332 Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) { 333 return object->IsString() ? Handle<String>::cast(object) 334 : isolate->factory()->empty_string(); 335 } 336 337 Handle<String> NoSideEffectsErrorToString(Isolate* isolate, 338 Handle<Object> input) { 339 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input); 340 341 Handle<Name> name_key = isolate->factory()->name_string(); 342 Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key); 343 Handle<String> name_str = AsStringOrEmpty(isolate, name); 344 345 Handle<Name> msg_key = isolate->factory()->message_string(); 346 Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key); 347 Handle<String> msg_str = AsStringOrEmpty(isolate, msg); 348 349 if (name_str->length() == 0) return msg_str; 350 if (msg_str->length() == 0) return name_str; 351 352 IncrementalStringBuilder builder(isolate); 353 builder.AppendString(name_str); 354 builder.AppendCString(": "); 355 builder.AppendString(msg_str); 356 357 return builder.Finish().ToHandleChecked(); 358 } 359 360 } // namespace 361 362 // static 363 Handle<String> Object::NoSideEffectsToString(Isolate* isolate, 364 Handle<Object> input) { 365 DisallowJavascriptExecution no_js(isolate); 366 367 if (input->IsString() || input->IsNumeric() || input->IsOddball()) { 368 return Object::ToString(isolate, input).ToHandleChecked(); 369 } else if (input->IsFunction()) { 370 // -- F u n c t i o n 371 Handle<String> fun_str; 372 if (input->IsJSBoundFunction()) { 373 fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input)); 374 } else { 375 DCHECK(input->IsJSFunction()); 376 fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input)); 377 } 378 379 if (fun_str->length() > 128) { 380 IncrementalStringBuilder builder(isolate); 381 builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111)); 382 builder.AppendCString("...<omitted>..."); 383 builder.AppendString(isolate->factory()->NewSubString( 384 fun_str, fun_str->length() - 2, fun_str->length())); 385 386 return builder.Finish().ToHandleChecked(); 387 } 388 return fun_str; 389 } else if (input->IsSymbol()) { 390 // -- S y m b o l 391 Handle<Symbol> symbol = Handle<Symbol>::cast(input); 392 393 IncrementalStringBuilder builder(isolate); 394 builder.AppendCString("Symbol("); 395 if (symbol->name()->IsString()) { 396 builder.AppendString(handle(String::cast(symbol->name()), isolate)); 397 } 398 builder.AppendCharacter(')'); 399 400 return builder.Finish().ToHandleChecked(); 401 } else if (input->IsJSReceiver()) { 402 // -- J S R e c e i v e r 403 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input); 404 Handle<Object> to_string = JSReceiver::GetDataProperty( 405 receiver, isolate->factory()->toString_string()); 406 407 if (IsErrorObject(isolate, input) || 408 *to_string == *isolate->error_to_string()) { 409 // When internally formatting error objects, use a side-effects-free 410 // version of Error.prototype.toString independent of the actually 411 // installed toString method. 412 return NoSideEffectsErrorToString(isolate, input); 413 } else if (*to_string == *isolate->object_to_string()) { 414 Handle<Object> ctor = JSReceiver::GetDataProperty( 415 receiver, isolate->factory()->constructor_string()); 416 if (ctor->IsFunction()) { 417 Handle<String> ctor_name; 418 if (ctor->IsJSBoundFunction()) { 419 ctor_name = JSBoundFunction::GetName( 420 isolate, Handle<JSBoundFunction>::cast(ctor)) 421 .ToHandleChecked(); 422 } else if (ctor->IsJSFunction()) { 423 Handle<Object> ctor_name_obj = 424 JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor)); 425 ctor_name = AsStringOrEmpty(isolate, ctor_name_obj); 426 } 427 428 if (ctor_name->length() != 0) { 429 IncrementalStringBuilder builder(isolate); 430 builder.AppendCString("#<"); 431 builder.AppendString(ctor_name); 432 builder.AppendCString(">"); 433 434 return builder.Finish().ToHandleChecked(); 435 } 436 } 437 } 438 } 439 440 // At this point, input is either none of the above or a JSReceiver. 441 442 Handle<JSReceiver> receiver; 443 if (input->IsJSReceiver()) { 444 receiver = Handle<JSReceiver>::cast(input); 445 } else { 446 // This is the only case where Object::ToObject throws. 447 DCHECK(!input->IsSmi()); 448 int constructor_function_index = 449 Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex(); 450 if (constructor_function_index == Map::kNoConstructorFunctionIndex) { 451 return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]"); 452 } 453 454 receiver = Object::ToObject(isolate, input, isolate->native_context()) 455 .ToHandleChecked(); 456 } 457 458 Handle<String> builtin_tag = handle(receiver->class_name(), isolate); 459 Handle<Object> tag_obj = JSReceiver::GetDataProperty( 460 receiver, isolate->factory()->to_string_tag_symbol()); 461 Handle<String> tag = 462 tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag; 463 464 IncrementalStringBuilder builder(isolate); 465 builder.AppendCString("[object "); 466 builder.AppendString(tag); 467 builder.AppendCString("]"); 468 469 return builder.Finish().ToHandleChecked(); 470 } 471 472 // static 473 MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate, 474 Handle<Object> input) { 475 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object); 476 if (input->IsSmi()) { 477 int value = std::max(Smi::ToInt(*input), 0); 478 return handle(Smi::FromInt(value), isolate); 479 } 480 double len = DoubleToInteger(input->Number()); 481 if (len <= 0.0) { 482 return handle(Smi::kZero, isolate); 483 } else if (len >= kMaxSafeInteger) { 484 len = kMaxSafeInteger; 485 } 486 return isolate->factory()->NewNumber(len); 487 } 488 489 // static 490 MaybeHandle<Object> Object::ConvertToIndex( 491 Isolate* isolate, Handle<Object> input, 492 MessageTemplate::Template error_index) { 493 if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate); 494 ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object); 495 if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input; 496 double len = DoubleToInteger(input->Number()) + 0.0; 497 auto js_len = isolate->factory()->NewNumber(len); 498 if (len < 0.0 || len > kMaxSafeInteger) { 499 THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object); 500 } 501 return js_len; 502 } 503 504 bool Object::BooleanValue(Isolate* isolate) { 505 if (IsSmi()) return Smi::ToInt(this) != 0; 506 DCHECK(IsHeapObject()); 507 if (IsBoolean()) return IsTrue(isolate); 508 if (IsNullOrUndefined(isolate)) return false; 509 if (IsUndetectable()) return false; // Undetectable object is false. 510 if (IsString()) return String::cast(this)->length() != 0; 511 if (IsHeapNumber()) return DoubleToBoolean(HeapNumber::cast(this)->value()); 512 if (IsBigInt()) return BigInt::cast(this)->ToBoolean(); 513 return true; 514 } 515 516 517 namespace { 518 519 // TODO(bmeurer): Maybe we should introduce a marker interface Number, 520 // where we put all these methods at some point? 521 ComparisonResult NumberCompare(double x, double y) { 522 if (std::isnan(x) || std::isnan(y)) { 523 return ComparisonResult::kUndefined; 524 } else if (x < y) { 525 return ComparisonResult::kLessThan; 526 } else if (x > y) { 527 return ComparisonResult::kGreaterThan; 528 } else { 529 return ComparisonResult::kEqual; 530 } 531 } 532 533 bool NumberEquals(double x, double y) { 534 // Must check explicitly for NaN's on Windows, but -0 works fine. 535 if (std::isnan(x)) return false; 536 if (std::isnan(y)) return false; 537 return x == y; 538 } 539 540 bool NumberEquals(const Object* x, const Object* y) { 541 return NumberEquals(x->Number(), y->Number()); 542 } 543 544 bool NumberEquals(Handle<Object> x, Handle<Object> y) { 545 return NumberEquals(*x, *y); 546 } 547 548 ComparisonResult Reverse(ComparisonResult result) { 549 if (result == ComparisonResult::kLessThan) { 550 return ComparisonResult::kGreaterThan; 551 } 552 if (result == ComparisonResult::kGreaterThan) { 553 return ComparisonResult::kLessThan; 554 } 555 return result; 556 } 557 558 } // anonymous namespace 559 560 // static 561 Maybe<ComparisonResult> Object::Compare(Isolate* isolate, Handle<Object> x, 562 Handle<Object> y) { 563 // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4. 564 if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) || 565 !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) { 566 return Nothing<ComparisonResult>(); 567 } 568 if (x->IsString() && y->IsString()) { 569 // ES6 section 7.2.11 Abstract Relational Comparison step 5. 570 return Just(String::Compare(isolate, Handle<String>::cast(x), 571 Handle<String>::cast(y))); 572 } 573 if (x->IsBigInt() && y->IsString()) { 574 return Just(BigInt::CompareToString(isolate, Handle<BigInt>::cast(x), 575 Handle<String>::cast(y))); 576 } 577 if (x->IsString() && y->IsBigInt()) { 578 return Just(Reverse(BigInt::CompareToString( 579 isolate, Handle<BigInt>::cast(y), Handle<String>::cast(x)))); 580 } 581 // ES6 section 7.2.11 Abstract Relational Comparison step 6. 582 if (!Object::ToNumeric(isolate, x).ToHandle(&x) || 583 !Object::ToNumeric(isolate, y).ToHandle(&y)) { 584 return Nothing<ComparisonResult>(); 585 } 586 587 bool x_is_number = x->IsNumber(); 588 bool y_is_number = y->IsNumber(); 589 if (x_is_number && y_is_number) { 590 return Just(NumberCompare(x->Number(), y->Number())); 591 } else if (!x_is_number && !y_is_number) { 592 return Just(BigInt::CompareToBigInt(Handle<BigInt>::cast(x), 593 Handle<BigInt>::cast(y))); 594 } else if (x_is_number) { 595 return Just(Reverse(BigInt::CompareToNumber(Handle<BigInt>::cast(y), x))); 596 } else { 597 return Just(BigInt::CompareToNumber(Handle<BigInt>::cast(x), y)); 598 } 599 } 600 601 602 // static 603 Maybe<bool> Object::Equals(Isolate* isolate, Handle<Object> x, 604 Handle<Object> y) { 605 // This is the generic version of Abstract Equality Comparison. Must be in 606 // sync with CodeStubAssembler::Equal. 607 while (true) { 608 if (x->IsNumber()) { 609 if (y->IsNumber()) { 610 return Just(NumberEquals(x, y)); 611 } else if (y->IsBoolean()) { 612 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); 613 } else if (y->IsString()) { 614 return Just(NumberEquals( 615 x, String::ToNumber(isolate, Handle<String>::cast(y)))); 616 } else if (y->IsBigInt()) { 617 return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x)); 618 } else if (y->IsJSReceiver()) { 619 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 620 .ToHandle(&y)) { 621 return Nothing<bool>(); 622 } 623 } else { 624 return Just(false); 625 } 626 } else if (x->IsString()) { 627 if (y->IsString()) { 628 return Just(String::Equals(isolate, Handle<String>::cast(x), 629 Handle<String>::cast(y))); 630 } else if (y->IsNumber()) { 631 x = String::ToNumber(isolate, Handle<String>::cast(x)); 632 return Just(NumberEquals(x, y)); 633 } else if (y->IsBoolean()) { 634 x = String::ToNumber(isolate, Handle<String>::cast(x)); 635 return Just(NumberEquals(*x, Handle<Oddball>::cast(y)->to_number())); 636 } else if (y->IsBigInt()) { 637 return Just(BigInt::EqualToString(isolate, Handle<BigInt>::cast(y), 638 Handle<String>::cast(x))); 639 } else if (y->IsJSReceiver()) { 640 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 641 .ToHandle(&y)) { 642 return Nothing<bool>(); 643 } 644 } else { 645 return Just(false); 646 } 647 } else if (x->IsBoolean()) { 648 if (y->IsOddball()) { 649 return Just(x.is_identical_to(y)); 650 } else if (y->IsNumber()) { 651 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); 652 } else if (y->IsString()) { 653 y = String::ToNumber(isolate, Handle<String>::cast(y)); 654 return Just(NumberEquals(Handle<Oddball>::cast(x)->to_number(), *y)); 655 } else if (y->IsBigInt()) { 656 x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x)); 657 return Just(BigInt::EqualToNumber(Handle<BigInt>::cast(y), x)); 658 } else if (y->IsJSReceiver()) { 659 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 660 .ToHandle(&y)) { 661 return Nothing<bool>(); 662 } 663 x = Oddball::ToNumber(isolate, Handle<Oddball>::cast(x)); 664 } else { 665 return Just(false); 666 } 667 } else if (x->IsSymbol()) { 668 if (y->IsSymbol()) { 669 return Just(x.is_identical_to(y)); 670 } else if (y->IsJSReceiver()) { 671 if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y)) 672 .ToHandle(&y)) { 673 return Nothing<bool>(); 674 } 675 } else { 676 return Just(false); 677 } 678 } else if (x->IsBigInt()) { 679 if (y->IsBigInt()) { 680 return Just(BigInt::EqualToBigInt(BigInt::cast(*x), BigInt::cast(*y))); 681 } 682 return Equals(isolate, y, x); 683 } else if (x->IsJSReceiver()) { 684 if (y->IsJSReceiver()) { 685 return Just(x.is_identical_to(y)); 686 } else if (y->IsUndetectable()) { 687 return Just(x->IsUndetectable()); 688 } else if (y->IsBoolean()) { 689 y = Oddball::ToNumber(isolate, Handle<Oddball>::cast(y)); 690 } else if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(x)) 691 .ToHandle(&x)) { 692 return Nothing<bool>(); 693 } 694 } else { 695 return Just(x->IsUndetectable() && y->IsUndetectable()); 696 } 697 } 698 } 699 700 701 bool Object::StrictEquals(Object* that) { 702 if (this->IsNumber()) { 703 if (!that->IsNumber()) return false; 704 return NumberEquals(this, that); 705 } else if (this->IsString()) { 706 if (!that->IsString()) return false; 707 return String::cast(this)->Equals(String::cast(that)); 708 } else if (this->IsBigInt()) { 709 if (!that->IsBigInt()) return false; 710 return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(that)); 711 } 712 return this == that; 713 } 714 715 716 // static 717 Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) { 718 if (object->IsNumber()) return isolate->factory()->number_string(); 719 if (object->IsOddball()) 720 return handle(Oddball::cast(*object)->type_of(), isolate); 721 if (object->IsUndetectable()) { 722 return isolate->factory()->undefined_string(); 723 } 724 if (object->IsString()) return isolate->factory()->string_string(); 725 if (object->IsSymbol()) return isolate->factory()->symbol_string(); 726 if (object->IsBigInt()) return isolate->factory()->bigint_string(); 727 if (object->IsCallable()) return isolate->factory()->function_string(); 728 return isolate->factory()->object_string(); 729 } 730 731 732 // static 733 MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs, 734 Handle<Object> rhs) { 735 if (lhs->IsNumber() && rhs->IsNumber()) { 736 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); 737 } else if (lhs->IsString() && rhs->IsString()) { 738 return isolate->factory()->NewConsString(Handle<String>::cast(lhs), 739 Handle<String>::cast(rhs)); 740 } 741 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object); 742 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object); 743 if (lhs->IsString() || rhs->IsString()) { 744 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs), 745 Object); 746 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs), 747 Object); 748 return isolate->factory()->NewConsString(Handle<String>::cast(lhs), 749 Handle<String>::cast(rhs)); 750 } 751 ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(isolate, rhs), 752 Object); 753 ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(isolate, lhs), 754 Object); 755 return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); 756 } 757 758 759 // static 760 MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate, 761 Handle<Object> callable, 762 Handle<Object> object) { 763 // The {callable} must have a [[Call]] internal method. 764 if (!callable->IsCallable()) return isolate->factory()->false_value(); 765 766 // Check if {callable} is a bound function, and if so retrieve its 767 // [[BoundTargetFunction]] and use that instead of {callable}. 768 if (callable->IsJSBoundFunction()) { 769 Handle<Object> bound_callable( 770 Handle<JSBoundFunction>::cast(callable)->bound_target_function(), 771 isolate); 772 return Object::InstanceOf(isolate, object, bound_callable); 773 } 774 775 // If {object} is not a receiver, return false. 776 if (!object->IsJSReceiver()) return isolate->factory()->false_value(); 777 778 // Get the "prototype" of {callable}; raise an error if it's not a receiver. 779 Handle<Object> prototype; 780 ASSIGN_RETURN_ON_EXCEPTION( 781 isolate, prototype, 782 Object::GetProperty(isolate, callable, 783 isolate->factory()->prototype_string()), 784 Object); 785 if (!prototype->IsJSReceiver()) { 786 THROW_NEW_ERROR( 787 isolate, 788 NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype), 789 Object); 790 } 791 792 // Return whether or not {prototype} is in the prototype chain of {object}. 793 Maybe<bool> result = JSReceiver::HasInPrototypeChain( 794 isolate, Handle<JSReceiver>::cast(object), prototype); 795 if (result.IsNothing()) return MaybeHandle<Object>(); 796 return isolate->factory()->ToBoolean(result.FromJust()); 797 } 798 799 // static 800 MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object, 801 Handle<Object> callable) { 802 // The {callable} must be a receiver. 803 if (!callable->IsJSReceiver()) { 804 THROW_NEW_ERROR(isolate, 805 NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck), 806 Object); 807 } 808 809 // Lookup the @@hasInstance method on {callable}. 810 Handle<Object> inst_of_handler; 811 ASSIGN_RETURN_ON_EXCEPTION( 812 isolate, inst_of_handler, 813 JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable), 814 isolate->factory()->has_instance_symbol()), 815 Object); 816 if (!inst_of_handler->IsUndefined(isolate)) { 817 // Call the {inst_of_handler} on the {callable}. 818 Handle<Object> result; 819 ASSIGN_RETURN_ON_EXCEPTION( 820 isolate, result, 821 Execution::Call(isolate, inst_of_handler, callable, 1, &object), 822 Object); 823 return isolate->factory()->ToBoolean(result->BooleanValue(isolate)); 824 } 825 826 // The {callable} must have a [[Call]] internal method. 827 if (!callable->IsCallable()) { 828 THROW_NEW_ERROR( 829 isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck), 830 Object); 831 } 832 833 // Fall back to OrdinaryHasInstance with {callable} and {object}. 834 Handle<Object> result; 835 ASSIGN_RETURN_ON_EXCEPTION( 836 isolate, result, 837 JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object); 838 return result; 839 } 840 841 // static 842 MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver, 843 Handle<Name> name) { 844 Handle<Object> func; 845 Isolate* isolate = receiver->GetIsolate(); 846 ASSIGN_RETURN_ON_EXCEPTION( 847 isolate, func, JSReceiver::GetProperty(isolate, receiver, name), Object); 848 if (func->IsNullOrUndefined(isolate)) { 849 return isolate->factory()->undefined_value(); 850 } 851 if (!func->IsCallable()) { 852 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction, 853 func, name, receiver), 854 Object); 855 } 856 return func; 857 } 858 859 namespace { 860 861 MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath( 862 Isolate* isolate, Handle<Object> object, ElementTypes element_types) { 863 if (element_types == ElementTypes::kAll) { 864 if (object->IsJSArray()) { 865 Handle<JSArray> array = Handle<JSArray>::cast(object); 866 uint32_t length; 867 if (!array->HasArrayPrototype(isolate) || 868 !array->length()->ToUint32(&length) || !array->HasFastElements() || 869 !JSObject::PrototypeHasNoElements(isolate, *array)) { 870 return MaybeHandle<FixedArray>(); 871 } 872 return array->GetElementsAccessor()->CreateListFromArrayLike( 873 isolate, array, length); 874 } else if (object->IsJSTypedArray()) { 875 Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(object); 876 size_t length = array->length_value(); 877 if (array->WasNeutered() || 878 length > static_cast<size_t>(FixedArray::kMaxLength)) { 879 return MaybeHandle<FixedArray>(); 880 } 881 return array->GetElementsAccessor()->CreateListFromArrayLike( 882 isolate, array, static_cast<uint32_t>(length)); 883 } 884 } 885 return MaybeHandle<FixedArray>(); 886 } 887 888 } // namespace 889 890 // static 891 MaybeHandle<FixedArray> Object::CreateListFromArrayLike( 892 Isolate* isolate, Handle<Object> object, ElementTypes element_types) { 893 // Fast-path for JSArray and JSTypedArray. 894 MaybeHandle<FixedArray> fast_result = 895 CreateListFromArrayLikeFastPath(isolate, object, element_types); 896 if (!fast_result.is_null()) return fast_result; 897 // 1. ReturnIfAbrupt(object). 898 // 2. (default elementTypes -- not applicable.) 899 // 3. If Type(obj) is not Object, throw a TypeError exception. 900 if (!object->IsJSReceiver()) { 901 THROW_NEW_ERROR(isolate, 902 NewTypeError(MessageTemplate::kCalledOnNonObject, 903 isolate->factory()->NewStringFromAsciiChecked( 904 "CreateListFromArrayLike")), 905 FixedArray); 906 } 907 908 // 4. Let len be ? ToLength(? Get(obj, "length")). 909 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); 910 Handle<Object> raw_length_number; 911 ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number, 912 Object::GetLengthFromArrayLike(isolate, receiver), 913 FixedArray); 914 uint32_t len; 915 if (!raw_length_number->ToUint32(&len) || 916 len > static_cast<uint32_t>(FixedArray::kMaxLength)) { 917 THROW_NEW_ERROR(isolate, 918 NewRangeError(MessageTemplate::kInvalidArrayLength), 919 FixedArray); 920 } 921 // 5. Let list be an empty List. 922 Handle<FixedArray> list = isolate->factory()->NewFixedArray(len); 923 // 6. Let index be 0. 924 // 7. Repeat while index < len: 925 for (uint32_t index = 0; index < len; ++index) { 926 // 7a. Let indexName be ToString(index). 927 // 7b. Let next be ? Get(obj, indexName). 928 Handle<Object> next; 929 ASSIGN_RETURN_ON_EXCEPTION(isolate, next, 930 JSReceiver::GetElement(isolate, receiver, index), 931 FixedArray); 932 switch (element_types) { 933 case ElementTypes::kAll: 934 // Nothing to do. 935 break; 936 case ElementTypes::kStringAndSymbol: { 937 // 7c. If Type(next) is not an element of elementTypes, throw a 938 // TypeError exception. 939 if (!next->IsName()) { 940 THROW_NEW_ERROR(isolate, 941 NewTypeError(MessageTemplate::kNotPropertyName, next), 942 FixedArray); 943 } 944 // 7d. Append next as the last element of list. 945 // Internalize on the fly so we can use pointer identity later. 946 next = isolate->factory()->InternalizeName(Handle<Name>::cast(next)); 947 break; 948 } 949 } 950 list->set(index, *next); 951 // 7e. Set index to index + 1. (See loop header.) 952 } 953 // 8. Return list. 954 return list; 955 } 956 957 958 // static 959 MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate, 960 Handle<JSReceiver> object) { 961 Handle<Object> val; 962 Handle<Name> key = isolate->factory()->length_string(); 963 ASSIGN_RETURN_ON_EXCEPTION( 964 isolate, val, JSReceiver::GetProperty(isolate, object, key), Object); 965 return Object::ToLength(isolate, val); 966 } 967 968 // static 969 Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) { 970 for (; it->IsFound(); it->Next()) { 971 switch (it->state()) { 972 case LookupIterator::NOT_FOUND: 973 case LookupIterator::TRANSITION: 974 UNREACHABLE(); 975 case LookupIterator::JSPROXY: 976 return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(), 977 it->GetName()); 978 case LookupIterator::INTERCEPTOR: { 979 Maybe<PropertyAttributes> result = 980 JSObject::GetPropertyAttributesWithInterceptor(it); 981 if (result.IsNothing()) return Nothing<bool>(); 982 if (result.FromJust() != ABSENT) return Just(true); 983 break; 984 } 985 case LookupIterator::ACCESS_CHECK: { 986 if (it->HasAccess()) break; 987 Maybe<PropertyAttributes> result = 988 JSObject::GetPropertyAttributesWithFailedAccessCheck(it); 989 if (result.IsNothing()) return Nothing<bool>(); 990 return Just(result.FromJust() != ABSENT); 991 } 992 case LookupIterator::INTEGER_INDEXED_EXOTIC: 993 // TypedArray out-of-bounds access. 994 return Just(false); 995 case LookupIterator::ACCESSOR: 996 case LookupIterator::DATA: 997 return Just(true); 998 } 999 } 1000 return Just(false); 1001 } 1002 1003 // static 1004 Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object, 1005 Handle<Name> name) { 1006 if (object->IsJSModuleNamespace()) { 1007 PropertyDescriptor desc; 1008 return JSReceiver::GetOwnPropertyDescriptor(object->GetIsolate(), object, 1009 name, &desc); 1010 } 1011 1012 if (object->IsJSObject()) { // Shortcut. 1013 LookupIterator it = LookupIterator::PropertyOrElement( 1014 object->GetIsolate(), object, name, object, LookupIterator::OWN); 1015 return HasProperty(&it); 1016 } 1017 1018 Maybe<PropertyAttributes> attributes = 1019 JSReceiver::GetOwnPropertyAttributes(object, name); 1020 MAYBE_RETURN(attributes, Nothing<bool>()); 1021 return Just(attributes.FromJust() != ABSENT); 1022 } 1023 1024 // static 1025 MaybeHandle<Object> Object::GetProperty(LookupIterator* it, 1026 OnNonExistent on_non_existent) { 1027 for (; it->IsFound(); it->Next()) { 1028 switch (it->state()) { 1029 case LookupIterator::NOT_FOUND: 1030 case LookupIterator::TRANSITION: 1031 UNREACHABLE(); 1032 case LookupIterator::JSPROXY: { 1033 bool was_found; 1034 MaybeHandle<Object> result = 1035 JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(), 1036 it->GetName(), it->GetReceiver(), &was_found); 1037 if (!was_found) it->NotFound(); 1038 return result; 1039 } 1040 case LookupIterator::INTERCEPTOR: { 1041 bool done; 1042 Handle<Object> result; 1043 ASSIGN_RETURN_ON_EXCEPTION( 1044 it->isolate(), result, 1045 JSObject::GetPropertyWithInterceptor(it, &done), Object); 1046 if (done) return result; 1047 break; 1048 } 1049 case LookupIterator::ACCESS_CHECK: 1050 if (it->HasAccess()) break; 1051 return JSObject::GetPropertyWithFailedAccessCheck(it); 1052 case LookupIterator::ACCESSOR: 1053 return GetPropertyWithAccessor(it); 1054 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1055 return it->isolate()->factory()->undefined_value(); 1056 case LookupIterator::DATA: 1057 return it->GetDataValue(); 1058 } 1059 } 1060 1061 if (on_non_existent == OnNonExistent::kThrowReferenceError) { 1062 THROW_NEW_ERROR(it->isolate(), 1063 NewReferenceError(MessageTemplate::kNotDefined, it->name()), 1064 Object); 1065 } 1066 return it->isolate()->factory()->undefined_value(); 1067 } 1068 1069 1070 // static 1071 MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate, 1072 Handle<JSProxy> proxy, 1073 Handle<Name> name, 1074 Handle<Object> receiver, 1075 bool* was_found) { 1076 *was_found = true; 1077 1078 DCHECK(!name->IsPrivate()); 1079 STACK_CHECK(isolate, MaybeHandle<Object>()); 1080 Handle<Name> trap_name = isolate->factory()->get_string(); 1081 // 1. Assert: IsPropertyKey(P) is true. 1082 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 1083 Handle<Object> handler(proxy->handler(), isolate); 1084 // 3. If handler is null, throw a TypeError exception. 1085 // 4. Assert: Type(handler) is Object. 1086 if (proxy->IsRevoked()) { 1087 THROW_NEW_ERROR(isolate, 1088 NewTypeError(MessageTemplate::kProxyRevoked, trap_name), 1089 Object); 1090 } 1091 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 1092 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 1093 // 6. Let trap be ? GetMethod(handler, "get"). 1094 Handle<Object> trap; 1095 ASSIGN_RETURN_ON_EXCEPTION( 1096 isolate, trap, 1097 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object); 1098 // 7. If trap is undefined, then 1099 if (trap->IsUndefined(isolate)) { 1100 // 7.a Return target.[[Get]](P, Receiver). 1101 LookupIterator it = 1102 LookupIterator::PropertyOrElement(isolate, receiver, name, target); 1103 MaybeHandle<Object> result = Object::GetProperty(&it); 1104 *was_found = it.IsFound(); 1105 return result; 1106 } 1107 // 8. Let trapResult be ? Call(trap, handler, target, P, Receiver). 1108 Handle<Object> trap_result; 1109 Handle<Object> args[] = {target, name, receiver}; 1110 ASSIGN_RETURN_ON_EXCEPTION( 1111 isolate, trap_result, 1112 Execution::Call(isolate, trap, handler, arraysize(args), args), Object); 1113 1114 MaybeHandle<Object> result = 1115 JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet); 1116 if (result.is_null()) { 1117 return result; 1118 } 1119 1120 // 11. Return trap_result 1121 return trap_result; 1122 } 1123 1124 // static 1125 MaybeHandle<Object> JSProxy::CheckGetSetTrapResult(Isolate* isolate, 1126 Handle<Name> name, 1127 Handle<JSReceiver> target, 1128 Handle<Object> trap_result, 1129 AccessKind access_kind) { 1130 // 9. Let targetDesc be ? target.[[GetOwnProperty]](P). 1131 PropertyDescriptor target_desc; 1132 Maybe<bool> target_found = 1133 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 1134 MAYBE_RETURN_NULL(target_found); 1135 // 10. If targetDesc is not undefined, then 1136 if (target_found.FromJust()) { 1137 // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is 1138 // false and targetDesc.[[Writable]] is false, then 1139 // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false, 1140 // throw a TypeError exception. 1141 bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) && 1142 !target_desc.configurable() && 1143 !target_desc.writable() && 1144 !trap_result->SameValue(*target_desc.value()); 1145 if (inconsistent) { 1146 if (access_kind == kGet) { 1147 THROW_NEW_ERROR( 1148 isolate, 1149 NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name, 1150 target_desc.value(), trap_result), 1151 Object); 1152 } else { 1153 isolate->Throw(*isolate->factory()->NewTypeError( 1154 MessageTemplate::kProxySetFrozenData, name)); 1155 return MaybeHandle<Object>(); 1156 } 1157 } 1158 // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]] 1159 // is false and targetDesc.[[Get]] is undefined, then 1160 // 10.b.i. If trapResult is not undefined, throw a TypeError exception. 1161 if (access_kind == kGet) { 1162 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && 1163 !target_desc.configurable() && 1164 target_desc.get()->IsUndefined(isolate) && 1165 !trap_result->IsUndefined(isolate); 1166 } else { 1167 inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && 1168 !target_desc.configurable() && 1169 target_desc.set()->IsUndefined(isolate); 1170 } 1171 if (inconsistent) { 1172 if (access_kind == kGet) { 1173 THROW_NEW_ERROR( 1174 isolate, 1175 NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, 1176 name, trap_result), 1177 Object); 1178 } else { 1179 isolate->Throw(*isolate->factory()->NewTypeError( 1180 MessageTemplate::kProxySetFrozenAccessor, name)); 1181 return MaybeHandle<Object>(); 1182 } 1183 } 1184 } 1185 return isolate->factory()->undefined_value(); 1186 } 1187 1188 1189 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) { 1190 for (; it->IsFound(); it->Next()) { 1191 switch (it->state()) { 1192 case LookupIterator::INTERCEPTOR: 1193 case LookupIterator::NOT_FOUND: 1194 case LookupIterator::TRANSITION: 1195 UNREACHABLE(); 1196 case LookupIterator::ACCESS_CHECK: 1197 // Support calling this method without an active context, but refuse 1198 // access to access-checked objects in that case. 1199 if (it->isolate()->context() != nullptr && it->HasAccess()) continue; 1200 V8_FALLTHROUGH; 1201 case LookupIterator::JSPROXY: 1202 it->NotFound(); 1203 return it->isolate()->factory()->undefined_value(); 1204 case LookupIterator::ACCESSOR: 1205 // TODO(verwaest): For now this doesn't call into AccessorInfo, since 1206 // clients don't need it. Update once relevant. 1207 it->NotFound(); 1208 return it->isolate()->factory()->undefined_value(); 1209 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1210 return it->isolate()->factory()->undefined_value(); 1211 case LookupIterator::DATA: 1212 return it->GetDataValue(); 1213 } 1214 } 1215 return it->isolate()->factory()->undefined_value(); 1216 } 1217 1218 1219 bool Object::ToInt32(int32_t* value) { 1220 if (IsSmi()) { 1221 *value = Smi::ToInt(this); 1222 return true; 1223 } 1224 if (IsHeapNumber()) { 1225 double num = HeapNumber::cast(this)->value(); 1226 // Check range before conversion to avoid undefined behavior. 1227 if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) { 1228 *value = FastD2I(num); 1229 return true; 1230 } 1231 } 1232 return false; 1233 } 1234 1235 Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo( 1236 Isolate* isolate, Handle<FunctionTemplateInfo> info, 1237 MaybeHandle<Name> maybe_name) { 1238 Object* current_info = info->shared_function_info(); 1239 if (current_info->IsSharedFunctionInfo()) { 1240 return handle(SharedFunctionInfo::cast(current_info), isolate); 1241 } 1242 Handle<Name> name; 1243 Handle<String> name_string; 1244 if (maybe_name.ToHandle(&name) && name->IsString()) { 1245 name_string = Handle<String>::cast(name); 1246 } else if (info->class_name()->IsString()) { 1247 name_string = handle(String::cast(info->class_name()), isolate); 1248 } else { 1249 name_string = isolate->factory()->empty_string(); 1250 } 1251 FunctionKind function_kind; 1252 if (info->remove_prototype()) { 1253 function_kind = kConciseMethod; 1254 } else { 1255 function_kind = kNormalFunction; 1256 } 1257 Handle<SharedFunctionInfo> result = 1258 isolate->factory()->NewSharedFunctionInfoForApiFunction(name_string, info, 1259 function_kind); 1260 1261 result->set_length(info->length()); 1262 result->DontAdaptArguments(); 1263 DCHECK(result->IsApiFunction()); 1264 1265 info->set_shared_function_info(*result); 1266 return result; 1267 } 1268 1269 bool FunctionTemplateInfo::IsTemplateFor(Map* map) { 1270 // There is a constraint on the object; check. 1271 if (!map->IsJSObjectMap()) return false; 1272 // Fetch the constructor function of the object. 1273 Object* cons_obj = map->GetConstructor(); 1274 Object* type; 1275 if (cons_obj->IsJSFunction()) { 1276 JSFunction* fun = JSFunction::cast(cons_obj); 1277 type = fun->shared()->function_data(); 1278 } else if (cons_obj->IsFunctionTemplateInfo()) { 1279 type = FunctionTemplateInfo::cast(cons_obj); 1280 } else { 1281 return false; 1282 } 1283 // Iterate through the chain of inheriting function templates to 1284 // see if the required one occurs. 1285 while (type->IsFunctionTemplateInfo()) { 1286 if (type == this) return true; 1287 type = FunctionTemplateInfo::cast(type)->parent_template(); 1288 } 1289 // Didn't find the required type in the inheritance chain. 1290 return false; 1291 } 1292 1293 1294 // static 1295 Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) { 1296 Handle<FixedArray> list = 1297 isolate->factory()->NewFixedArray(kLengthIndex + size); 1298 list->set(kLengthIndex, Smi::kZero); 1299 return Handle<TemplateList>::cast(list); 1300 } 1301 1302 // static 1303 Handle<TemplateList> TemplateList::Add(Isolate* isolate, 1304 Handle<TemplateList> list, 1305 Handle<i::Object> value) { 1306 STATIC_ASSERT(kFirstElementIndex == 1); 1307 int index = list->length() + 1; 1308 Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list); 1309 fixed_array = FixedArray::SetAndGrow(isolate, fixed_array, index, value); 1310 fixed_array->set(kLengthIndex, Smi::FromInt(index)); 1311 return Handle<TemplateList>::cast(fixed_array); 1312 } 1313 1314 // static 1315 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor, 1316 Handle<JSReceiver> new_target, 1317 Handle<AllocationSite> site) { 1318 // If called through new, new.target can be: 1319 // - a subclass of constructor, 1320 // - a proxy wrapper around constructor, or 1321 // - the constructor itself. 1322 // If called through Reflect.construct, it's guaranteed to be a constructor. 1323 Isolate* const isolate = constructor->GetIsolate(); 1324 DCHECK(constructor->IsConstructor()); 1325 DCHECK(new_target->IsConstructor()); 1326 DCHECK(!constructor->has_initial_map() || 1327 constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE); 1328 1329 Handle<Map> initial_map; 1330 ASSIGN_RETURN_ON_EXCEPTION( 1331 isolate, initial_map, 1332 JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject); 1333 Handle<JSObject> result = 1334 isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site); 1335 if (initial_map->is_dictionary_map()) { 1336 Handle<NameDictionary> dictionary = 1337 NameDictionary::New(isolate, NameDictionary::kInitialCapacity); 1338 result->SetProperties(*dictionary); 1339 } 1340 isolate->counters()->constructed_objects()->Increment(); 1341 isolate->counters()->constructed_objects_runtime()->Increment(); 1342 return result; 1343 } 1344 1345 // 9.1.12 ObjectCreate ( proto [ , internalSlotsList ] ) 1346 // Notice: This is NOT 19.1.2.2 Object.create ( O, Properties ) 1347 MaybeHandle<JSObject> JSObject::ObjectCreate(Isolate* isolate, 1348 Handle<Object> prototype) { 1349 // Generate the map with the specified {prototype} based on the Object 1350 // function's initial map from the current native context. 1351 // TODO(bmeurer): Use a dedicated cache for Object.create; think about 1352 // slack tracking for Object.create. 1353 Handle<Map> map = 1354 Map::GetObjectCreateMap(isolate, Handle<HeapObject>::cast(prototype)); 1355 1356 // Actually allocate the object. 1357 Handle<JSObject> object; 1358 if (map->is_dictionary_map()) { 1359 object = isolate->factory()->NewSlowJSObjectFromMap(map); 1360 } else { 1361 object = isolate->factory()->NewJSObjectFromMap(map); 1362 } 1363 return object; 1364 } 1365 1366 void JSObject::EnsureWritableFastElements(Handle<JSObject> object) { 1367 DCHECK(object->HasSmiOrObjectElements() || 1368 object->HasFastStringWrapperElements()); 1369 FixedArray* raw_elems = FixedArray::cast(object->elements()); 1370 Heap* heap = object->GetHeap(); 1371 if (raw_elems->map() != ReadOnlyRoots(heap).fixed_cow_array_map()) return; 1372 Isolate* isolate = heap->isolate(); 1373 Handle<FixedArray> elems(raw_elems, isolate); 1374 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap( 1375 elems, isolate->factory()->fixed_array_map()); 1376 object->set_elements(*writable_elems); 1377 isolate->counters()->cow_arrays_converted()->Increment(); 1378 } 1379 1380 int JSObject::GetHeaderSize(InstanceType type, 1381 bool function_has_prototype_slot) { 1382 switch (type) { 1383 case JS_OBJECT_TYPE: 1384 case JS_API_OBJECT_TYPE: 1385 case JS_SPECIAL_API_OBJECT_TYPE: 1386 return JSObject::kHeaderSize; 1387 case JS_GENERATOR_OBJECT_TYPE: 1388 return JSGeneratorObject::kSize; 1389 case JS_ASYNC_GENERATOR_OBJECT_TYPE: 1390 return JSAsyncGeneratorObject::kSize; 1391 case JS_GLOBAL_PROXY_TYPE: 1392 return JSGlobalProxy::kSize; 1393 case JS_GLOBAL_OBJECT_TYPE: 1394 return JSGlobalObject::kSize; 1395 case JS_BOUND_FUNCTION_TYPE: 1396 return JSBoundFunction::kSize; 1397 case JS_FUNCTION_TYPE: 1398 return JSFunction::GetHeaderSize(function_has_prototype_slot); 1399 case JS_VALUE_TYPE: 1400 return JSValue::kSize; 1401 case JS_DATE_TYPE: 1402 return JSDate::kSize; 1403 case JS_ARRAY_TYPE: 1404 return JSArray::kSize; 1405 case JS_ARRAY_BUFFER_TYPE: 1406 return JSArrayBuffer::kSize; 1407 case JS_ARRAY_ITERATOR_TYPE: 1408 return JSArrayIterator::kSize; 1409 case JS_TYPED_ARRAY_TYPE: 1410 return JSTypedArray::kSize; 1411 case JS_DATA_VIEW_TYPE: 1412 return JSDataView::kSize; 1413 case JS_SET_TYPE: 1414 return JSSet::kSize; 1415 case JS_MAP_TYPE: 1416 return JSMap::kSize; 1417 case JS_SET_KEY_VALUE_ITERATOR_TYPE: 1418 case JS_SET_VALUE_ITERATOR_TYPE: 1419 return JSSetIterator::kSize; 1420 case JS_MAP_KEY_ITERATOR_TYPE: 1421 case JS_MAP_KEY_VALUE_ITERATOR_TYPE: 1422 case JS_MAP_VALUE_ITERATOR_TYPE: 1423 return JSMapIterator::kSize; 1424 case JS_WEAK_MAP_TYPE: 1425 return JSWeakMap::kSize; 1426 case JS_WEAK_SET_TYPE: 1427 return JSWeakSet::kSize; 1428 case JS_PROMISE_TYPE: 1429 return JSPromise::kSize; 1430 case JS_REGEXP_TYPE: 1431 return JSRegExp::kSize; 1432 case JS_REGEXP_STRING_ITERATOR_TYPE: 1433 return JSRegExpStringIterator::kSize; 1434 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 1435 return JSObject::kHeaderSize; 1436 case JS_MESSAGE_OBJECT_TYPE: 1437 return JSMessageObject::kSize; 1438 case JS_ARGUMENTS_TYPE: 1439 return JSObject::kHeaderSize; 1440 case JS_ERROR_TYPE: 1441 return JSObject::kHeaderSize; 1442 case JS_STRING_ITERATOR_TYPE: 1443 return JSStringIterator::kSize; 1444 case JS_MODULE_NAMESPACE_TYPE: 1445 return JSModuleNamespace::kHeaderSize; 1446 #ifdef V8_INTL_SUPPORT 1447 case JS_INTL_COLLATOR_TYPE: 1448 return JSCollator::kSize; 1449 case JS_INTL_LIST_FORMAT_TYPE: 1450 return JSListFormat::kSize; 1451 case JS_INTL_LOCALE_TYPE: 1452 return JSLocale::kSize; 1453 case JS_INTL_PLURAL_RULES_TYPE: 1454 return JSPluralRules::kSize; 1455 case JS_INTL_RELATIVE_TIME_FORMAT_TYPE: 1456 return JSRelativeTimeFormat::kSize; 1457 #endif // V8_INTL_SUPPORT 1458 case WASM_GLOBAL_TYPE: 1459 return WasmGlobalObject::kSize; 1460 case WASM_INSTANCE_TYPE: 1461 return WasmInstanceObject::kSize; 1462 case WASM_MEMORY_TYPE: 1463 return WasmMemoryObject::kSize; 1464 case WASM_MODULE_TYPE: 1465 return WasmModuleObject::kSize; 1466 case WASM_TABLE_TYPE: 1467 return WasmTableObject::kSize; 1468 default: 1469 UNREACHABLE(); 1470 } 1471 } 1472 1473 // ES6 9.5.1 1474 // static 1475 MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) { 1476 Isolate* isolate = proxy->GetIsolate(); 1477 Handle<String> trap_name = isolate->factory()->getPrototypeOf_string(); 1478 1479 STACK_CHECK(isolate, MaybeHandle<Object>()); 1480 1481 // 1. Let handler be the value of the [[ProxyHandler]] internal slot. 1482 // 2. If handler is null, throw a TypeError exception. 1483 // 3. Assert: Type(handler) is Object. 1484 // 4. Let target be the value of the [[ProxyTarget]] internal slot. 1485 if (proxy->IsRevoked()) { 1486 THROW_NEW_ERROR(isolate, 1487 NewTypeError(MessageTemplate::kProxyRevoked, trap_name), 1488 Object); 1489 } 1490 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 1491 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 1492 1493 // 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). 1494 Handle<Object> trap; 1495 ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name), 1496 Object); 1497 // 6. If trap is undefined, then return target.[[GetPrototypeOf]](). 1498 if (trap->IsUndefined(isolate)) { 1499 return JSReceiver::GetPrototype(isolate, target); 1500 } 1501 // 7. Let handlerProto be ? Call(trap, handler, target). 1502 Handle<Object> argv[] = {target}; 1503 Handle<Object> handler_proto; 1504 ASSIGN_RETURN_ON_EXCEPTION( 1505 isolate, handler_proto, 1506 Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object); 1507 // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError. 1508 if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) { 1509 THROW_NEW_ERROR(isolate, 1510 NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid), 1511 Object); 1512 } 1513 // 9. Let extensibleTarget be ? IsExtensible(target). 1514 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target); 1515 MAYBE_RETURN_NULL(is_extensible); 1516 // 10. If extensibleTarget is true, return handlerProto. 1517 if (is_extensible.FromJust()) return handler_proto; 1518 // 11. Let targetProto be ? target.[[GetPrototypeOf]](). 1519 Handle<Object> target_proto; 1520 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto, 1521 JSReceiver::GetPrototype(isolate, target), Object); 1522 // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError. 1523 if (!handler_proto->SameValue(*target_proto)) { 1524 THROW_NEW_ERROR( 1525 isolate, 1526 NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible), 1527 Object); 1528 } 1529 // 13. Return handlerProto. 1530 return handler_proto; 1531 } 1532 1533 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) { 1534 Isolate* isolate = it->isolate(); 1535 Handle<Object> structure = it->GetAccessors(); 1536 Handle<Object> receiver = it->GetReceiver(); 1537 // In case of global IC, the receiver is the global object. Replace by the 1538 // global proxy. 1539 if (receiver->IsJSGlobalObject()) { 1540 receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate); 1541 } 1542 1543 // We should never get here to initialize a const with the hole value since a 1544 // const declaration would conflict with the getter. 1545 DCHECK(!structure->IsForeign()); 1546 1547 // API style callbacks. 1548 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1549 if (structure->IsAccessorInfo()) { 1550 Handle<Name> name = it->GetName(); 1551 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); 1552 if (!info->IsCompatibleReceiver(*receiver)) { 1553 THROW_NEW_ERROR(isolate, 1554 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, 1555 name, receiver), 1556 Object); 1557 } 1558 1559 if (!info->has_getter()) return isolate->factory()->undefined_value(); 1560 1561 if (info->is_sloppy() && !receiver->IsJSReceiver()) { 1562 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver, 1563 Object::ConvertReceiver(isolate, receiver), 1564 Object); 1565 } 1566 1567 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, 1568 kDontThrow); 1569 Handle<Object> result = args.CallAccessorGetter(info, name); 1570 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1571 if (result.is_null()) return isolate->factory()->undefined_value(); 1572 Handle<Object> reboxed_result = handle(*result, isolate); 1573 if (info->replace_on_access() && receiver->IsJSReceiver()) { 1574 RETURN_ON_EXCEPTION(isolate, 1575 Accessors::ReplaceAccessorWithDataProperty( 1576 receiver, holder, name, result), 1577 Object); 1578 } 1579 return reboxed_result; 1580 } 1581 1582 // AccessorPair with 'cached' private property. 1583 if (it->TryLookupCachedProperty()) { 1584 return Object::GetProperty(it); 1585 } 1586 1587 // Regular accessor. 1588 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate); 1589 if (getter->IsFunctionTemplateInfo()) { 1590 SaveContext save(isolate); 1591 isolate->set_context(*holder->GetCreationContext()); 1592 return Builtins::InvokeApiFunction( 1593 isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0, 1594 nullptr, isolate->factory()->undefined_value()); 1595 } else if (getter->IsCallable()) { 1596 // TODO(rossberg): nicer would be to cast to some JSCallable here... 1597 return Object::GetPropertyWithDefinedGetter( 1598 receiver, Handle<JSReceiver>::cast(getter)); 1599 } 1600 // Getter is not a function. 1601 return isolate->factory()->undefined_value(); 1602 } 1603 1604 // static 1605 Address AccessorInfo::redirect(Address address, AccessorComponent component) { 1606 ApiFunction fun(address); 1607 DCHECK_EQ(ACCESSOR_GETTER, component); 1608 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; 1609 return ExternalReference::Create(&fun, type).address(); 1610 } 1611 1612 Address AccessorInfo::redirected_getter() const { 1613 Address accessor = v8::ToCData<Address>(getter()); 1614 if (accessor == kNullAddress) return kNullAddress; 1615 return redirect(accessor, ACCESSOR_GETTER); 1616 } 1617 1618 Address CallHandlerInfo::redirected_callback() const { 1619 Address address = v8::ToCData<Address>(callback()); 1620 ApiFunction fun(address); 1621 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; 1622 return ExternalReference::Create(&fun, type).address(); 1623 } 1624 1625 bool AccessorInfo::IsCompatibleReceiverMap(Handle<AccessorInfo> info, 1626 Handle<Map> map) { 1627 if (!info->HasExpectedReceiverType()) return true; 1628 if (!map->IsJSObjectMap()) return false; 1629 return FunctionTemplateInfo::cast(info->expected_receiver_type()) 1630 ->IsTemplateFor(*map); 1631 } 1632 1633 Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it, 1634 Handle<Object> value, 1635 ShouldThrow should_throw) { 1636 Isolate* isolate = it->isolate(); 1637 Handle<Object> structure = it->GetAccessors(); 1638 Handle<Object> receiver = it->GetReceiver(); 1639 // In case of global IC, the receiver is the global object. Replace by the 1640 // global proxy. 1641 if (receiver->IsJSGlobalObject()) { 1642 receiver = handle(JSGlobalObject::cast(*receiver)->global_proxy(), isolate); 1643 } 1644 1645 // We should never get here to initialize a const with the hole value since a 1646 // const declaration would conflict with the setter. 1647 DCHECK(!structure->IsForeign()); 1648 1649 // API style callbacks. 1650 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1651 if (structure->IsAccessorInfo()) { 1652 Handle<Name> name = it->GetName(); 1653 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); 1654 if (!info->IsCompatibleReceiver(*receiver)) { 1655 isolate->Throw(*isolate->factory()->NewTypeError( 1656 MessageTemplate::kIncompatibleMethodReceiver, name, receiver)); 1657 return Nothing<bool>(); 1658 } 1659 1660 if (!info->has_setter()) { 1661 // TODO(verwaest): We should not get here anymore once all AccessorInfos 1662 // are marked as special_data_property. They cannot both be writable and 1663 // not have a setter. 1664 return Just(true); 1665 } 1666 1667 if (info->is_sloppy() && !receiver->IsJSReceiver()) { 1668 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1669 isolate, receiver, Object::ConvertReceiver(isolate, receiver), 1670 Nothing<bool>()); 1671 } 1672 1673 // The actual type of setter callback is either 1674 // v8::AccessorNameSetterCallback or 1675 // i::Accesors::AccessorNameBooleanSetterCallback, depending on whether the 1676 // AccessorInfo was created by the API or internally (see accessors.cc). 1677 // Here we handle both cases using GenericNamedPropertySetterCallback and 1678 // its Call method. 1679 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, 1680 should_throw); 1681 Handle<Object> result = args.CallAccessorSetter(info, name, value); 1682 // In the case of AccessorNameSetterCallback, we know that the result value 1683 // cannot have been set, so the result of Call will be null. In the case of 1684 // AccessorNameBooleanSetterCallback, the result will either be null 1685 // (signalling an exception) or a boolean Oddball. 1686 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 1687 if (result.is_null()) return Just(true); 1688 DCHECK(result->BooleanValue(isolate) || should_throw == kDontThrow); 1689 return Just(result->BooleanValue(isolate)); 1690 } 1691 1692 // Regular accessor. 1693 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate); 1694 if (setter->IsFunctionTemplateInfo()) { 1695 SaveContext save(isolate); 1696 isolate->set_context(*holder->GetCreationContext()); 1697 Handle<Object> argv[] = {value}; 1698 RETURN_ON_EXCEPTION_VALUE( 1699 isolate, Builtins::InvokeApiFunction( 1700 isolate, false, Handle<FunctionTemplateInfo>::cast(setter), 1701 receiver, arraysize(argv), argv, 1702 isolate->factory()->undefined_value()), 1703 Nothing<bool>()); 1704 return Just(true); 1705 } else if (setter->IsCallable()) { 1706 // TODO(rossberg): nicer would be to cast to some JSCallable here... 1707 return SetPropertyWithDefinedSetter( 1708 receiver, Handle<JSReceiver>::cast(setter), value, should_throw); 1709 } 1710 1711 RETURN_FAILURE(isolate, should_throw, 1712 NewTypeError(MessageTemplate::kNoSetterInCallback, 1713 it->GetName(), it->GetHolder<JSObject>())); 1714 } 1715 1716 1717 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter( 1718 Handle<Object> receiver, 1719 Handle<JSReceiver> getter) { 1720 Isolate* isolate = getter->GetIsolate(); 1721 1722 // Platforms with simulators like arm/arm64 expose a funny issue. If the 1723 // simulator has a separate JS stack pointer from the C++ stack pointer, it 1724 // can miss C++ stack overflows in the stack guard at the start of JavaScript 1725 // functions. It would be very expensive to check the C++ stack pointer at 1726 // that location. The best solution seems to be to break the impasse by 1727 // adding checks at possible recursion points. What's more, we don't put 1728 // this stack check behind the USE_SIMULATOR define in order to keep 1729 // behavior the same between hardware and simulators. 1730 StackLimitCheck check(isolate); 1731 if (check.JsHasOverflowed()) { 1732 isolate->StackOverflow(); 1733 return MaybeHandle<Object>(); 1734 } 1735 1736 return Execution::Call(isolate, getter, receiver, 0, nullptr); 1737 } 1738 1739 1740 Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver, 1741 Handle<JSReceiver> setter, 1742 Handle<Object> value, 1743 ShouldThrow should_throw) { 1744 Isolate* isolate = setter->GetIsolate(); 1745 1746 Handle<Object> argv[] = { value }; 1747 RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver, 1748 arraysize(argv), argv), 1749 Nothing<bool>()); 1750 return Just(true); 1751 } 1752 1753 1754 // static 1755 bool JSObject::AllCanRead(LookupIterator* it) { 1756 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of 1757 // which have already been checked. 1758 DCHECK(it->state() == LookupIterator::ACCESS_CHECK || 1759 it->state() == LookupIterator::INTERCEPTOR); 1760 for (it->Next(); it->IsFound(); it->Next()) { 1761 if (it->state() == LookupIterator::ACCESSOR) { 1762 auto accessors = it->GetAccessors(); 1763 if (accessors->IsAccessorInfo()) { 1764 if (AccessorInfo::cast(*accessors)->all_can_read()) return true; 1765 } 1766 } else if (it->state() == LookupIterator::INTERCEPTOR) { 1767 if (it->GetInterceptor()->all_can_read()) return true; 1768 } else if (it->state() == LookupIterator::JSPROXY) { 1769 // Stop lookupiterating. And no, AllCanNotRead. 1770 return false; 1771 } 1772 } 1773 return false; 1774 } 1775 1776 namespace { 1777 1778 MaybeHandle<Object> GetPropertyWithInterceptorInternal( 1779 LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) { 1780 *done = false; 1781 Isolate* isolate = it->isolate(); 1782 // Make sure that the top context does not change when doing callbacks or 1783 // interceptor calls. 1784 AssertNoContextChange ncc(isolate); 1785 1786 if (interceptor->getter()->IsUndefined(isolate)) { 1787 return isolate->factory()->undefined_value(); 1788 } 1789 1790 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1791 Handle<Object> result; 1792 Handle<Object> receiver = it->GetReceiver(); 1793 if (!receiver->IsJSReceiver()) { 1794 ASSIGN_RETURN_ON_EXCEPTION( 1795 isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object); 1796 } 1797 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1798 *holder, kDontThrow); 1799 1800 if (it->IsElement()) { 1801 result = args.CallIndexedGetter(interceptor, it->index()); 1802 } else { 1803 result = args.CallNamedGetter(interceptor, it->name()); 1804 } 1805 1806 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1807 if (result.is_null()) return isolate->factory()->undefined_value(); 1808 *done = true; 1809 // Rebox handle before return 1810 return handle(*result, isolate); 1811 } 1812 1813 Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal( 1814 LookupIterator* it, Handle<InterceptorInfo> interceptor) { 1815 Isolate* isolate = it->isolate(); 1816 // Make sure that the top context does not change when doing 1817 // callbacks or interceptor calls. 1818 AssertNoContextChange ncc(isolate); 1819 HandleScope scope(isolate); 1820 1821 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1822 DCHECK_IMPLIES(!it->IsElement() && it->name()->IsSymbol(), 1823 interceptor->can_intercept_symbols()); 1824 Handle<Object> receiver = it->GetReceiver(); 1825 if (!receiver->IsJSReceiver()) { 1826 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1827 Object::ConvertReceiver(isolate, receiver), 1828 Nothing<PropertyAttributes>()); 1829 } 1830 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1831 *holder, kDontThrow); 1832 if (!interceptor->query()->IsUndefined(isolate)) { 1833 Handle<Object> result; 1834 if (it->IsElement()) { 1835 result = args.CallIndexedQuery(interceptor, it->index()); 1836 } else { 1837 result = args.CallNamedQuery(interceptor, it->name()); 1838 } 1839 if (!result.is_null()) { 1840 int32_t value; 1841 CHECK(result->ToInt32(&value)); 1842 return Just(static_cast<PropertyAttributes>(value)); 1843 } 1844 } else if (!interceptor->getter()->IsUndefined(isolate)) { 1845 // TODO(verwaest): Use GetPropertyWithInterceptor? 1846 Handle<Object> result; 1847 if (it->IsElement()) { 1848 result = args.CallIndexedGetter(interceptor, it->index()); 1849 } else { 1850 result = args.CallNamedGetter(interceptor, it->name()); 1851 } 1852 if (!result.is_null()) return Just(DONT_ENUM); 1853 } 1854 1855 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); 1856 return Just(ABSENT); 1857 } 1858 1859 Maybe<bool> SetPropertyWithInterceptorInternal( 1860 LookupIterator* it, Handle<InterceptorInfo> interceptor, 1861 ShouldThrow should_throw, Handle<Object> value) { 1862 Isolate* isolate = it->isolate(); 1863 // Make sure that the top context does not change when doing callbacks or 1864 // interceptor calls. 1865 AssertNoContextChange ncc(isolate); 1866 1867 if (interceptor->setter()->IsUndefined(isolate)) return Just(false); 1868 1869 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1870 bool result; 1871 Handle<Object> receiver = it->GetReceiver(); 1872 if (!receiver->IsJSReceiver()) { 1873 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1874 Object::ConvertReceiver(isolate, receiver), 1875 Nothing<bool>()); 1876 } 1877 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1878 *holder, should_throw); 1879 1880 if (it->IsElement()) { 1881 // TODO(neis): In the future, we may want to actually return the 1882 // interceptor's result, which then should be a boolean. 1883 result = !args.CallIndexedSetter(interceptor, it->index(), value).is_null(); 1884 } else { 1885 result = !args.CallNamedSetter(interceptor, it->name(), value).is_null(); 1886 } 1887 1888 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 1889 return Just(result); 1890 } 1891 1892 Maybe<bool> DefinePropertyWithInterceptorInternal( 1893 LookupIterator* it, Handle<InterceptorInfo> interceptor, 1894 ShouldThrow should_throw, PropertyDescriptor& desc) { 1895 Isolate* isolate = it->isolate(); 1896 // Make sure that the top context does not change when doing callbacks or 1897 // interceptor calls. 1898 AssertNoContextChange ncc(isolate); 1899 1900 if (interceptor->definer()->IsUndefined(isolate)) return Just(false); 1901 1902 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1903 bool result; 1904 Handle<Object> receiver = it->GetReceiver(); 1905 if (!receiver->IsJSReceiver()) { 1906 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 1907 Object::ConvertReceiver(isolate, receiver), 1908 Nothing<bool>()); 1909 } 1910 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 1911 *holder, should_throw); 1912 1913 std::unique_ptr<v8::PropertyDescriptor> descriptor( 1914 new v8::PropertyDescriptor()); 1915 if (PropertyDescriptor::IsAccessorDescriptor(&desc)) { 1916 descriptor.reset(new v8::PropertyDescriptor( 1917 v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set()))); 1918 } else if (PropertyDescriptor::IsDataDescriptor(&desc)) { 1919 if (desc.has_writable()) { 1920 descriptor.reset(new v8::PropertyDescriptor( 1921 v8::Utils::ToLocal(desc.value()), desc.writable())); 1922 } else { 1923 descriptor.reset( 1924 new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value()))); 1925 } 1926 } 1927 if (desc.has_enumerable()) { 1928 descriptor->set_enumerable(desc.enumerable()); 1929 } 1930 if (desc.has_configurable()) { 1931 descriptor->set_configurable(desc.configurable()); 1932 } 1933 1934 if (it->IsElement()) { 1935 result = !args.CallIndexedDefiner(interceptor, it->index(), *descriptor) 1936 .is_null(); 1937 } else { 1938 result = 1939 !args.CallNamedDefiner(interceptor, it->name(), *descriptor).is_null(); 1940 } 1941 1942 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 1943 return Just(result); 1944 } 1945 1946 } // namespace 1947 1948 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck( 1949 LookupIterator* it) { 1950 Isolate* isolate = it->isolate(); 1951 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1952 Handle<InterceptorInfo> interceptor = 1953 it->GetInterceptorForFailedAccessCheck(); 1954 if (interceptor.is_null()) { 1955 while (AllCanRead(it)) { 1956 if (it->state() == LookupIterator::ACCESSOR) { 1957 return GetPropertyWithAccessor(it); 1958 } 1959 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 1960 bool done; 1961 Handle<Object> result; 1962 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 1963 GetPropertyWithInterceptor(it, &done), Object); 1964 if (done) return result; 1965 } 1966 1967 } else { 1968 Handle<Object> result; 1969 bool done; 1970 ASSIGN_RETURN_ON_EXCEPTION( 1971 isolate, result, 1972 GetPropertyWithInterceptorInternal(it, interceptor, &done), Object); 1973 if (done) return result; 1974 } 1975 1976 // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns 1977 // undefined. 1978 Handle<Name> name = it->GetName(); 1979 if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) { 1980 return it->factory()->undefined_value(); 1981 } 1982 1983 isolate->ReportFailedAccessCheck(checked); 1984 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 1985 return it->factory()->undefined_value(); 1986 } 1987 1988 1989 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck( 1990 LookupIterator* it) { 1991 Isolate* isolate = it->isolate(); 1992 Handle<JSObject> checked = it->GetHolder<JSObject>(); 1993 Handle<InterceptorInfo> interceptor = 1994 it->GetInterceptorForFailedAccessCheck(); 1995 if (interceptor.is_null()) { 1996 while (AllCanRead(it)) { 1997 if (it->state() == LookupIterator::ACCESSOR) { 1998 return Just(it->property_attributes()); 1999 } 2000 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 2001 auto result = GetPropertyAttributesWithInterceptor(it); 2002 if (isolate->has_scheduled_exception()) break; 2003 if (result.IsJust() && result.FromJust() != ABSENT) return result; 2004 } 2005 } else { 2006 Maybe<PropertyAttributes> result = 2007 GetPropertyAttributesWithInterceptorInternal(it, interceptor); 2008 if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>(); 2009 if (result.FromMaybe(ABSENT) != ABSENT) return result; 2010 } 2011 isolate->ReportFailedAccessCheck(checked); 2012 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); 2013 return Just(ABSENT); 2014 } 2015 2016 2017 // static 2018 bool JSObject::AllCanWrite(LookupIterator* it) { 2019 for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) { 2020 if (it->state() == LookupIterator::ACCESSOR) { 2021 Handle<Object> accessors = it->GetAccessors(); 2022 if (accessors->IsAccessorInfo()) { 2023 if (AccessorInfo::cast(*accessors)->all_can_write()) return true; 2024 } 2025 } 2026 } 2027 return false; 2028 } 2029 2030 2031 Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck( 2032 LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) { 2033 Isolate* isolate = it->isolate(); 2034 Handle<JSObject> checked = it->GetHolder<JSObject>(); 2035 Handle<InterceptorInfo> interceptor = 2036 it->GetInterceptorForFailedAccessCheck(); 2037 if (interceptor.is_null()) { 2038 if (AllCanWrite(it)) { 2039 return SetPropertyWithAccessor(it, value, should_throw); 2040 } 2041 } else { 2042 Maybe<bool> result = SetPropertyWithInterceptorInternal( 2043 it, interceptor, should_throw, value); 2044 if (isolate->has_pending_exception()) return Nothing<bool>(); 2045 if (result.IsJust()) return result; 2046 } 2047 isolate->ReportFailedAccessCheck(checked); 2048 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 2049 return Just(true); 2050 } 2051 2052 2053 void JSObject::SetNormalizedProperty(Handle<JSObject> object, 2054 Handle<Name> name, 2055 Handle<Object> value, 2056 PropertyDetails details) { 2057 DCHECK(!object->HasFastProperties()); 2058 DCHECK(name->IsUniqueName()); 2059 Isolate* isolate = object->GetIsolate(); 2060 2061 uint32_t hash = name->Hash(); 2062 2063 if (object->IsJSGlobalObject()) { 2064 Handle<JSGlobalObject> global_obj = Handle<JSGlobalObject>::cast(object); 2065 Handle<GlobalDictionary> dictionary(global_obj->global_dictionary(), 2066 isolate); 2067 int entry = dictionary->FindEntry(ReadOnlyRoots(isolate), name, hash); 2068 2069 if (entry == GlobalDictionary::kNotFound) { 2070 DCHECK_IMPLIES(global_obj->map()->is_prototype_map(), 2071 Map::IsPrototypeChainInvalidated(global_obj->map())); 2072 auto cell = isolate->factory()->NewPropertyCell(name); 2073 cell->set_value(*value); 2074 auto cell_type = value->IsUndefined(isolate) 2075 ? PropertyCellType::kUndefined 2076 : PropertyCellType::kConstant; 2077 details = details.set_cell_type(cell_type); 2078 value = cell; 2079 dictionary = 2080 GlobalDictionary::Add(isolate, dictionary, name, value, details); 2081 global_obj->set_global_dictionary(*dictionary); 2082 } else { 2083 Handle<PropertyCell> cell = PropertyCell::PrepareForValue( 2084 isolate, dictionary, entry, value, details); 2085 cell->set_value(*value); 2086 } 2087 } else { 2088 Handle<NameDictionary> dictionary(object->property_dictionary(), isolate); 2089 2090 int entry = dictionary->FindEntry(isolate, name); 2091 if (entry == NameDictionary::kNotFound) { 2092 DCHECK_IMPLIES(object->map()->is_prototype_map(), 2093 Map::IsPrototypeChainInvalidated(object->map())); 2094 dictionary = 2095 NameDictionary::Add(isolate, dictionary, name, value, details); 2096 object->SetProperties(*dictionary); 2097 } else { 2098 PropertyDetails original_details = dictionary->DetailsAt(entry); 2099 int enumeration_index = original_details.dictionary_index(); 2100 DCHECK_GT(enumeration_index, 0); 2101 details = details.set_index(enumeration_index); 2102 dictionary->SetEntry(isolate, entry, *name, *value, details); 2103 } 2104 } 2105 } 2106 2107 // static 2108 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate, 2109 Handle<JSReceiver> object, 2110 Handle<Object> proto) { 2111 PrototypeIterator iter(isolate, object, kStartAtReceiver); 2112 while (true) { 2113 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); 2114 if (iter.IsAtEnd()) return Just(false); 2115 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) { 2116 return Just(true); 2117 } 2118 } 2119 } 2120 2121 namespace { 2122 2123 bool HasExcludedProperty( 2124 const ScopedVector<Handle<Object>>* excluded_properties, 2125 Handle<Object> search_element) { 2126 // TODO(gsathya): Change this to be a hashtable. 2127 for (int i = 0; i < excluded_properties->length(); i++) { 2128 if (search_element->SameValue(*excluded_properties->at(i))) { 2129 return true; 2130 } 2131 } 2132 2133 return false; 2134 } 2135 2136 V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign( 2137 Handle<JSReceiver> target, Handle<Object> source, 2138 const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) { 2139 // Non-empty strings are the only non-JSReceivers that need to be handled 2140 // explicitly by Object.assign. 2141 if (!source->IsJSReceiver()) { 2142 return Just(!source->IsString() || String::cast(*source)->length() == 0); 2143 } 2144 2145 // If the target is deprecated, the object will be updated on first store. If 2146 // the source for that store equals the target, this will invalidate the 2147 // cached representation of the source. Preventively upgrade the target. 2148 // Do this on each iteration since any property load could cause deprecation. 2149 if (target->map()->is_deprecated()) { 2150 JSObject::MigrateInstance(Handle<JSObject>::cast(target)); 2151 } 2152 2153 Isolate* isolate = target->GetIsolate(); 2154 Handle<Map> map(JSReceiver::cast(*source)->map(), isolate); 2155 2156 if (!map->IsJSObjectMap()) return Just(false); 2157 if (!map->OnlyHasSimpleProperties()) return Just(false); 2158 2159 Handle<JSObject> from = Handle<JSObject>::cast(source); 2160 if (from->elements() != ReadOnlyRoots(isolate).empty_fixed_array()) { 2161 return Just(false); 2162 } 2163 2164 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 2165 int length = map->NumberOfOwnDescriptors(); 2166 2167 bool stable = true; 2168 2169 for (int i = 0; i < length; i++) { 2170 Handle<Name> next_key(descriptors->GetKey(i), isolate); 2171 Handle<Object> prop_value; 2172 // Directly decode from the descriptor array if |from| did not change shape. 2173 if (stable) { 2174 PropertyDetails details = descriptors->GetDetails(i); 2175 if (!details.IsEnumerable()) continue; 2176 if (details.kind() == kData) { 2177 if (details.location() == kDescriptor) { 2178 prop_value = handle(descriptors->GetStrongValue(i), isolate); 2179 } else { 2180 Representation representation = details.representation(); 2181 FieldIndex index = FieldIndex::ForDescriptor(*map, i); 2182 prop_value = JSObject::FastPropertyAt(from, representation, index); 2183 } 2184 } else { 2185 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2186 isolate, prop_value, 2187 JSReceiver::GetProperty(isolate, from, next_key), Nothing<bool>()); 2188 stable = from->map() == *map; 2189 } 2190 } else { 2191 // If the map did change, do a slower lookup. We are still guaranteed that 2192 // the object has a simple shape, and that the key is a name. 2193 LookupIterator it(from, next_key, from, 2194 LookupIterator::OWN_SKIP_INTERCEPTOR); 2195 if (!it.IsFound()) continue; 2196 DCHECK(it.state() == LookupIterator::DATA || 2197 it.state() == LookupIterator::ACCESSOR); 2198 if (!it.IsEnumerable()) continue; 2199 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2200 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); 2201 } 2202 2203 if (use_set) { 2204 LookupIterator it(target, next_key, target); 2205 Maybe<bool> result = 2206 Object::SetProperty(&it, prop_value, LanguageMode::kStrict, 2207 Object::CERTAINLY_NOT_STORE_FROM_KEYED); 2208 if (result.IsNothing()) return result; 2209 if (stable) stable = from->map() == *map; 2210 } else { 2211 if (excluded_properties != nullptr && 2212 HasExcludedProperty(excluded_properties, next_key)) { 2213 continue; 2214 } 2215 2216 // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue). 2217 bool success; 2218 LookupIterator it = LookupIterator::PropertyOrElement( 2219 isolate, target, next_key, &success, LookupIterator::OWN); 2220 CHECK(success); 2221 CHECK(JSObject::CreateDataProperty(&it, prop_value, kThrowOnError) 2222 .FromJust()); 2223 } 2224 } 2225 2226 return Just(true); 2227 } 2228 } // namespace 2229 2230 // static 2231 Maybe<bool> JSReceiver::SetOrCopyDataProperties( 2232 Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source, 2233 const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) { 2234 Maybe<bool> fast_assign = 2235 FastAssign(target, source, excluded_properties, use_set); 2236 if (fast_assign.IsNothing()) return Nothing<bool>(); 2237 if (fast_assign.FromJust()) return Just(true); 2238 2239 Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked(); 2240 // 3b. Let keys be ? from.[[OwnPropertyKeys]](). 2241 Handle<FixedArray> keys; 2242 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2243 isolate, keys, 2244 KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, 2245 GetKeysConversion::kKeepNumbers), 2246 Nothing<bool>()); 2247 2248 // 4. Repeat for each element nextKey of keys in List order, 2249 for (int j = 0; j < keys->length(); ++j) { 2250 Handle<Object> next_key(keys->get(j), isolate); 2251 // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey). 2252 PropertyDescriptor desc; 2253 Maybe<bool> found = 2254 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc); 2255 if (found.IsNothing()) return Nothing<bool>(); 2256 // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then 2257 if (found.FromJust() && desc.enumerable()) { 2258 // 4a ii 1. Let propValue be ? Get(from, nextKey). 2259 Handle<Object> prop_value; 2260 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2261 isolate, prop_value, 2262 Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>()); 2263 2264 if (use_set) { 2265 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true). 2266 Handle<Object> status; 2267 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 2268 isolate, status, 2269 Runtime::SetObjectProperty(isolate, target, next_key, prop_value, 2270 LanguageMode::kStrict), 2271 Nothing<bool>()); 2272 } else { 2273 if (excluded_properties != nullptr && 2274 HasExcludedProperty(excluded_properties, next_key)) { 2275 continue; 2276 } 2277 2278 // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue). 2279 bool success; 2280 LookupIterator it = LookupIterator::PropertyOrElement( 2281 isolate, target, next_key, &success, LookupIterator::OWN); 2282 CHECK(success); 2283 CHECK(JSObject::CreateDataProperty(&it, prop_value, kThrowOnError) 2284 .FromJust()); 2285 } 2286 } 2287 } 2288 2289 return Just(true); 2290 } 2291 2292 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) const { 2293 DisallowHeapAllocation no_alloc; 2294 if (IsSmi()) { 2295 Context* native_context = isolate->context()->native_context(); 2296 return native_context->number_function()->initial_map(); 2297 } 2298 2299 const HeapObject* heap_object = HeapObject::cast(this); 2300 return heap_object->map()->GetPrototypeChainRootMap(isolate); 2301 } 2302 2303 Map* Map::GetPrototypeChainRootMap(Isolate* isolate) const { 2304 DisallowHeapAllocation no_alloc; 2305 if (IsJSReceiverMap()) { 2306 return const_cast<Map*>(this); 2307 } 2308 int constructor_function_index = GetConstructorFunctionIndex(); 2309 if (constructor_function_index != Map::kNoConstructorFunctionIndex) { 2310 Context* native_context = isolate->context()->native_context(); 2311 JSFunction* constructor_function = 2312 JSFunction::cast(native_context->get(constructor_function_index)); 2313 return constructor_function->initial_map(); 2314 } 2315 return ReadOnlyRoots(isolate).null_value()->map(); 2316 } 2317 2318 // static 2319 Smi* Object::GetOrCreateHash(Isolate* isolate, Object* key) { 2320 DisallowHeapAllocation no_gc; 2321 return key->GetOrCreateHash(isolate); 2322 } 2323 2324 Smi* Object::GetOrCreateHash(Isolate* isolate) { 2325 DisallowHeapAllocation no_gc; 2326 Object* hash = Object::GetSimpleHash(this); 2327 if (hash->IsSmi()) return Smi::cast(hash); 2328 2329 DCHECK(IsJSReceiver()); 2330 return JSReceiver::cast(this)->GetOrCreateIdentityHash(isolate); 2331 } 2332 2333 2334 bool Object::SameValue(Object* other) { 2335 if (other == this) return true; 2336 2337 if (IsNumber() && other->IsNumber()) { 2338 double this_value = Number(); 2339 double other_value = other->Number(); 2340 // SameValue(NaN, NaN) is true. 2341 if (this_value != other_value) { 2342 return std::isnan(this_value) && std::isnan(other_value); 2343 } 2344 // SameValue(0.0, -0.0) is false. 2345 return (std::signbit(this_value) == std::signbit(other_value)); 2346 } 2347 if (IsString() && other->IsString()) { 2348 return String::cast(this)->Equals(String::cast(other)); 2349 } 2350 if (IsBigInt() && other->IsBigInt()) { 2351 return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(other)); 2352 } 2353 return false; 2354 } 2355 2356 2357 bool Object::SameValueZero(Object* other) { 2358 if (other == this) return true; 2359 2360 if (IsNumber() && other->IsNumber()) { 2361 double this_value = Number(); 2362 double other_value = other->Number(); 2363 // +0 == -0 is true 2364 return this_value == other_value || 2365 (std::isnan(this_value) && std::isnan(other_value)); 2366 } 2367 if (IsString() && other->IsString()) { 2368 return String::cast(this)->Equals(String::cast(other)); 2369 } 2370 if (IsBigInt() && other->IsBigInt()) { 2371 return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(other)); 2372 } 2373 return false; 2374 } 2375 2376 2377 MaybeHandle<Object> Object::ArraySpeciesConstructor( 2378 Isolate* isolate, Handle<Object> original_array) { 2379 Handle<Object> default_species = isolate->array_function(); 2380 if (original_array->IsJSArray() && 2381 Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) && 2382 isolate->IsArraySpeciesLookupChainIntact()) { 2383 return default_species; 2384 } 2385 Handle<Object> constructor = isolate->factory()->undefined_value(); 2386 Maybe<bool> is_array = Object::IsArray(original_array); 2387 MAYBE_RETURN_NULL(is_array); 2388 if (is_array.FromJust()) { 2389 ASSIGN_RETURN_ON_EXCEPTION( 2390 isolate, constructor, 2391 Object::GetProperty(isolate, original_array, 2392 isolate->factory()->constructor_string()), 2393 Object); 2394 if (constructor->IsConstructor()) { 2395 Handle<Context> constructor_context; 2396 ASSIGN_RETURN_ON_EXCEPTION( 2397 isolate, constructor_context, 2398 JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)), 2399 Object); 2400 if (*constructor_context != *isolate->native_context() && 2401 *constructor == constructor_context->array_function()) { 2402 constructor = isolate->factory()->undefined_value(); 2403 } 2404 } 2405 if (constructor->IsJSReceiver()) { 2406 ASSIGN_RETURN_ON_EXCEPTION( 2407 isolate, constructor, 2408 JSReceiver::GetProperty(isolate, 2409 Handle<JSReceiver>::cast(constructor), 2410 isolate->factory()->species_symbol()), 2411 Object); 2412 if (constructor->IsNull(isolate)) { 2413 constructor = isolate->factory()->undefined_value(); 2414 } 2415 } 2416 } 2417 if (constructor->IsUndefined(isolate)) { 2418 return default_species; 2419 } else { 2420 if (!constructor->IsConstructor()) { 2421 THROW_NEW_ERROR(isolate, 2422 NewTypeError(MessageTemplate::kSpeciesNotConstructor), 2423 Object); 2424 } 2425 return constructor; 2426 } 2427 } 2428 2429 // ES6 section 7.3.20 SpeciesConstructor ( O, defaultConstructor ) 2430 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Object::SpeciesConstructor( 2431 Isolate* isolate, Handle<JSReceiver> recv, 2432 Handle<JSFunction> default_ctor) { 2433 Handle<Object> ctor_obj; 2434 ASSIGN_RETURN_ON_EXCEPTION( 2435 isolate, ctor_obj, 2436 JSObject::GetProperty(isolate, recv, 2437 isolate->factory()->constructor_string()), 2438 Object); 2439 2440 if (ctor_obj->IsUndefined(isolate)) return default_ctor; 2441 2442 if (!ctor_obj->IsJSReceiver()) { 2443 THROW_NEW_ERROR(isolate, 2444 NewTypeError(MessageTemplate::kConstructorNotReceiver), 2445 Object); 2446 } 2447 2448 Handle<JSReceiver> ctor = Handle<JSReceiver>::cast(ctor_obj); 2449 2450 Handle<Object> species; 2451 ASSIGN_RETURN_ON_EXCEPTION( 2452 isolate, species, 2453 JSObject::GetProperty(isolate, ctor, 2454 isolate->factory()->species_symbol()), 2455 Object); 2456 2457 if (species->IsNullOrUndefined(isolate)) { 2458 return default_ctor; 2459 } 2460 2461 if (species->IsConstructor()) return species; 2462 2463 THROW_NEW_ERROR( 2464 isolate, NewTypeError(MessageTemplate::kSpeciesNotConstructor), Object); 2465 } 2466 2467 bool Object::IterationHasObservableEffects() { 2468 // Check that this object is an array. 2469 if (!IsJSArray()) return true; 2470 JSArray* array = JSArray::cast(this); 2471 Isolate* isolate = array->GetIsolate(); 2472 2473 #ifdef V8_ENABLE_FORCE_SLOW_PATH 2474 if (isolate->force_slow_path()) return true; 2475 #endif 2476 2477 // Check that we have the original ArrayPrototype. 2478 if (!array->map()->prototype()->IsJSObject()) return true; 2479 JSObject* array_proto = JSObject::cast(array->map()->prototype()); 2480 if (!isolate->is_initial_array_prototype(array_proto)) return true; 2481 2482 // Check that the ArrayPrototype hasn't been modified in a way that would 2483 // affect iteration. 2484 if (!isolate->IsArrayIteratorLookupChainIntact()) return true; 2485 2486 // For FastPacked kinds, iteration will have the same effect as simply 2487 // accessing each property in order. 2488 ElementsKind array_kind = array->GetElementsKind(); 2489 if (IsFastPackedElementsKind(array_kind)) return false; 2490 2491 // For FastHoley kinds, an element access on a hole would cause a lookup on 2492 // the prototype. This could have different results if the prototype has been 2493 // changed. 2494 if (IsHoleyElementsKind(array_kind) && 2495 isolate->IsNoElementsProtectorIntact()) { 2496 return false; 2497 } 2498 return true; 2499 } 2500 2501 void Object::ShortPrint(FILE* out) { 2502 OFStream os(out); 2503 os << Brief(this); 2504 } 2505 2506 2507 void Object::ShortPrint(StringStream* accumulator) { 2508 std::ostringstream os; 2509 os << Brief(this); 2510 accumulator->Add(os.str().c_str()); 2511 } 2512 2513 2514 void Object::ShortPrint(std::ostream& os) { os << Brief(this); } 2515 2516 void MaybeObject::ShortPrint(FILE* out) { 2517 OFStream os(out); 2518 os << Brief(this); 2519 } 2520 2521 void MaybeObject::ShortPrint(StringStream* accumulator) { 2522 std::ostringstream os; 2523 os << Brief(this); 2524 accumulator->Add(os.str().c_str()); 2525 } 2526 2527 void MaybeObject::ShortPrint(std::ostream& os) { os << Brief(this); } 2528 2529 Brief::Brief(const Object* v) 2530 : value(MaybeObject::FromObject(const_cast<Object*>(v))) {} 2531 2532 std::ostream& operator<<(std::ostream& os, const Brief& v) { 2533 // TODO(marja): const-correct HeapObjectShortPrint. 2534 MaybeObject* maybe_object = const_cast<MaybeObject*>(v.value); 2535 Smi* smi; 2536 HeapObject* heap_object; 2537 if (maybe_object->ToSmi(&smi)) { 2538 smi->SmiPrint(os); 2539 } else if (maybe_object->IsClearedWeakHeapObject()) { 2540 os << "[cleared]"; 2541 } else if (maybe_object->ToWeakHeapObject(&heap_object)) { 2542 os << "[weak] "; 2543 heap_object->HeapObjectShortPrint(os); 2544 } else if (maybe_object->ToStrongHeapObject(&heap_object)) { 2545 heap_object->HeapObjectShortPrint(os); 2546 } else { 2547 UNREACHABLE(); 2548 } 2549 return os; 2550 } 2551 2552 void Smi::SmiPrint(std::ostream& os) const { // NOLINT 2553 os << value(); 2554 } 2555 2556 Handle<String> String::SlowFlatten(Isolate* isolate, Handle<ConsString> cons, 2557 PretenureFlag pretenure) { 2558 DCHECK_NE(cons->second()->length(), 0); 2559 2560 // TurboFan can create cons strings with empty first parts. 2561 while (cons->first()->length() == 0) { 2562 // We do not want to call this function recursively. Therefore we call 2563 // String::Flatten only in those cases where String::SlowFlatten is not 2564 // called again. 2565 if (cons->second()->IsConsString() && !cons->second()->IsFlat()) { 2566 cons = handle(ConsString::cast(cons->second()), isolate); 2567 } else { 2568 return String::Flatten(isolate, handle(cons->second(), isolate)); 2569 } 2570 } 2571 2572 DCHECK(AllowHeapAllocation::IsAllowed()); 2573 int length = cons->length(); 2574 PretenureFlag tenure = Heap::InNewSpace(*cons) ? pretenure : TENURED; 2575 Handle<SeqString> result; 2576 if (cons->IsOneByteRepresentation()) { 2577 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString( 2578 length, tenure).ToHandleChecked(); 2579 DisallowHeapAllocation no_gc; 2580 WriteToFlat(*cons, flat->GetChars(), 0, length); 2581 result = flat; 2582 } else { 2583 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString( 2584 length, tenure).ToHandleChecked(); 2585 DisallowHeapAllocation no_gc; 2586 WriteToFlat(*cons, flat->GetChars(), 0, length); 2587 result = flat; 2588 } 2589 cons->set_first(isolate, *result); 2590 cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string()); 2591 DCHECK(result->IsFlat()); 2592 return result; 2593 } 2594 2595 2596 2597 bool String::MakeExternal(v8::String::ExternalStringResource* resource) { 2598 DisallowHeapAllocation no_allocation; 2599 // Externalizing twice leaks the external resource, so it's 2600 // prohibited by the API. 2601 DCHECK(this->SupportsExternalization()); 2602 DCHECK(!resource->IsCompressible()); 2603 #ifdef ENABLE_SLOW_DCHECKS 2604 if (FLAG_enable_slow_asserts) { 2605 // Assert that the resource and the string are equivalent. 2606 DCHECK(static_cast<size_t>(this->length()) == resource->length()); 2607 ScopedVector<uc16> smart_chars(this->length()); 2608 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2609 DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(), 2610 resource->length() * sizeof(smart_chars[0]))); 2611 } 2612 #endif // DEBUG 2613 int size = this->Size(); // Byte size of the original string. 2614 // Abort if size does not allow in-place conversion. 2615 if (size < ExternalString::kShortSize) return false; 2616 Isolate* isolate; 2617 // Read-only strings cannot be made external, since that would mutate the 2618 // string. 2619 if (!Isolate::FromWritableHeapObject(this, &isolate)) return false; 2620 Heap* heap = isolate->heap(); 2621 bool is_one_byte = this->IsOneByteRepresentation(); 2622 bool is_internalized = this->IsInternalizedString(); 2623 bool has_pointers = StringShape(this).IsIndirect(); 2624 if (has_pointers) { 2625 heap->NotifyObjectLayoutChange(this, size, no_allocation); 2626 } 2627 // Morph the string to an external string by replacing the map and 2628 // reinitializing the fields. This won't work if the space the existing 2629 // string occupies is too small for a regular external string. 2630 // Instead, we resort to a short external string instead, omitting 2631 // the field caching the address of the backing store. When we encounter 2632 // short external strings in generated code, we need to bailout to runtime. 2633 Map* new_map; 2634 ReadOnlyRoots roots(heap); 2635 if (size < ExternalString::kSize) { 2636 if (is_internalized) { 2637 new_map = 2638 is_one_byte 2639 ? roots 2640 .short_external_internalized_string_with_one_byte_data_map() 2641 : roots.short_external_internalized_string_map(); 2642 } else { 2643 new_map = is_one_byte 2644 ? roots.short_external_string_with_one_byte_data_map() 2645 : roots.short_external_string_map(); 2646 } 2647 } else { 2648 new_map = 2649 is_internalized 2650 ? (is_one_byte 2651 ? roots.external_internalized_string_with_one_byte_data_map() 2652 : roots.external_internalized_string_map()) 2653 : (is_one_byte ? roots.external_string_with_one_byte_data_map() 2654 : roots.external_string_map()); 2655 } 2656 2657 // Byte size of the external String object. 2658 int new_size = this->SizeFromMap(new_map); 2659 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size, 2660 ClearRecordedSlots::kNo); 2661 if (has_pointers) { 2662 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size); 2663 } 2664 2665 // We are storing the new map using release store after creating a filler for 2666 // the left-over space to avoid races with the sweeper thread. 2667 this->synchronized_set_map(new_map); 2668 2669 ExternalTwoByteString* self = ExternalTwoByteString::cast(this); 2670 self->SetResource(isolate, resource); 2671 heap->RegisterExternalString(this); 2672 if (is_internalized) self->Hash(); // Force regeneration of the hash value. 2673 return true; 2674 } 2675 2676 2677 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) { 2678 DisallowHeapAllocation no_allocation; 2679 // Externalizing twice leaks the external resource, so it's 2680 // prohibited by the API. 2681 DCHECK(this->SupportsExternalization()); 2682 DCHECK(!resource->IsCompressible()); 2683 #ifdef ENABLE_SLOW_DCHECKS 2684 if (FLAG_enable_slow_asserts) { 2685 // Assert that the resource and the string are equivalent. 2686 DCHECK(static_cast<size_t>(this->length()) == resource->length()); 2687 if (this->IsTwoByteRepresentation()) { 2688 ScopedVector<uint16_t> smart_chars(this->length()); 2689 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2690 DCHECK(String::IsOneByte(smart_chars.start(), this->length())); 2691 } 2692 ScopedVector<char> smart_chars(this->length()); 2693 String::WriteToFlat(this, smart_chars.start(), 0, this->length()); 2694 DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(), 2695 resource->length() * sizeof(smart_chars[0]))); 2696 } 2697 #endif // DEBUG 2698 int size = this->Size(); // Byte size of the original string. 2699 // Abort if size does not allow in-place conversion. 2700 if (size < ExternalString::kShortSize) return false; 2701 Isolate* isolate; 2702 // Read-only strings cannot be made external, since that would mutate the 2703 // string. 2704 if (!Isolate::FromWritableHeapObject(this, &isolate)) return false; 2705 Heap* heap = isolate->heap(); 2706 bool is_internalized = this->IsInternalizedString(); 2707 bool has_pointers = StringShape(this).IsIndirect(); 2708 2709 if (has_pointers) { 2710 heap->NotifyObjectLayoutChange(this, size, no_allocation); 2711 } 2712 2713 // Morph the string to an external string by replacing the map and 2714 // reinitializing the fields. This won't work if the space the existing 2715 // string occupies is too small for a regular external string. 2716 // Instead, we resort to a short external string instead, omitting 2717 // the field caching the address of the backing store. When we encounter 2718 // short external strings in generated code, we need to bailout to runtime. 2719 Map* new_map; 2720 ReadOnlyRoots roots(heap); 2721 if (size < ExternalString::kSize) { 2722 new_map = is_internalized 2723 ? roots.short_external_one_byte_internalized_string_map() 2724 : roots.short_external_one_byte_string_map(); 2725 } else { 2726 new_map = is_internalized 2727 ? roots.external_one_byte_internalized_string_map() 2728 : roots.external_one_byte_string_map(); 2729 } 2730 2731 // Byte size of the external String object. 2732 int new_size = this->SizeFromMap(new_map); 2733 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size, 2734 ClearRecordedSlots::kNo); 2735 if (has_pointers) { 2736 heap->ClearRecordedSlotRange(this->address(), this->address() + new_size); 2737 } 2738 2739 // We are storing the new map using release store after creating a filler for 2740 // the left-over space to avoid races with the sweeper thread. 2741 this->synchronized_set_map(new_map); 2742 2743 ExternalOneByteString* self = ExternalOneByteString::cast(this); 2744 self->SetResource(isolate, resource); 2745 heap->RegisterExternalString(this); 2746 if (is_internalized) self->Hash(); // Force regeneration of the hash value. 2747 return true; 2748 } 2749 2750 bool String::SupportsExternalization() { 2751 if (this->IsThinString()) { 2752 return i::ThinString::cast(this)->actual()->SupportsExternalization(); 2753 } 2754 2755 Isolate* isolate; 2756 // RO_SPACE strings cannot be externalized. 2757 if (!Isolate::FromWritableHeapObject(this, &isolate)) { 2758 return false; 2759 } 2760 2761 // Already an external string. 2762 if (StringShape(this).IsExternal()) { 2763 return false; 2764 } 2765 2766 return !isolate->heap()->IsInGCPostProcessing(); 2767 } 2768 2769 void String::StringShortPrint(StringStream* accumulator, bool show_details) { 2770 int len = length(); 2771 if (len > kMaxShortPrintLength) { 2772 accumulator->Add("<Very long string[%u]>", len); 2773 return; 2774 } 2775 2776 if (!LooksValid()) { 2777 accumulator->Add("<Invalid String>"); 2778 return; 2779 } 2780 2781 StringCharacterStream stream(this); 2782 2783 bool truncated = false; 2784 if (len > kMaxShortPrintLength) { 2785 len = kMaxShortPrintLength; 2786 truncated = true; 2787 } 2788 bool one_byte = true; 2789 for (int i = 0; i < len; i++) { 2790 uint16_t c = stream.GetNext(); 2791 2792 if (c < 32 || c >= 127) { 2793 one_byte = false; 2794 } 2795 } 2796 stream.Reset(this); 2797 if (one_byte) { 2798 if (show_details) accumulator->Add("<String[%u]: ", length()); 2799 for (int i = 0; i < len; i++) { 2800 accumulator->Put(static_cast<char>(stream.GetNext())); 2801 } 2802 if (show_details) accumulator->Put('>'); 2803 } else { 2804 // Backslash indicates that the string contains control 2805 // characters and that backslashes are therefore escaped. 2806 if (show_details) accumulator->Add("<String[%u]\\: ", length()); 2807 for (int i = 0; i < len; i++) { 2808 uint16_t c = stream.GetNext(); 2809 if (c == '\n') { 2810 accumulator->Add("\\n"); 2811 } else if (c == '\r') { 2812 accumulator->Add("\\r"); 2813 } else if (c == '\\') { 2814 accumulator->Add("\\\\"); 2815 } else if (c < 32 || c > 126) { 2816 accumulator->Add("\\x%02x", c); 2817 } else { 2818 accumulator->Put(static_cast<char>(c)); 2819 } 2820 } 2821 if (truncated) { 2822 accumulator->Put('.'); 2823 accumulator->Put('.'); 2824 accumulator->Put('.'); 2825 } 2826 if (show_details) accumulator->Put('>'); 2827 } 2828 return; 2829 } 2830 2831 2832 void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT 2833 if (end < 0) end = length(); 2834 StringCharacterStream stream(this, start); 2835 for (int i = start; i < end && stream.HasMore(); i++) { 2836 os << AsUC16(stream.GetNext()); 2837 } 2838 } 2839 2840 2841 void JSObject::JSObjectShortPrint(StringStream* accumulator) { 2842 switch (map()->instance_type()) { 2843 case JS_ARRAY_TYPE: { 2844 double length = JSArray::cast(this)->length()->IsUndefined() 2845 ? 0 2846 : JSArray::cast(this)->length()->Number(); 2847 accumulator->Add("<JSArray[%u]>", static_cast<uint32_t>(length)); 2848 break; 2849 } 2850 case JS_BOUND_FUNCTION_TYPE: { 2851 JSBoundFunction* bound_function = JSBoundFunction::cast(this); 2852 accumulator->Add("<JSBoundFunction"); 2853 accumulator->Add( 2854 " (BoundTargetFunction %p)>", 2855 reinterpret_cast<void*>(bound_function->bound_target_function())); 2856 break; 2857 } 2858 case JS_WEAK_MAP_TYPE: { 2859 accumulator->Add("<JSWeakMap>"); 2860 break; 2861 } 2862 case JS_WEAK_SET_TYPE: { 2863 accumulator->Add("<JSWeakSet>"); 2864 break; 2865 } 2866 case JS_REGEXP_TYPE: { 2867 accumulator->Add("<JSRegExp"); 2868 JSRegExp* regexp = JSRegExp::cast(this); 2869 if (regexp->source()->IsString()) { 2870 accumulator->Add(" "); 2871 String::cast(regexp->source())->StringShortPrint(accumulator); 2872 } 2873 accumulator->Add(">"); 2874 2875 break; 2876 } 2877 case JS_FUNCTION_TYPE: { 2878 JSFunction* function = JSFunction::cast(this); 2879 Object* fun_name = function->shared()->DebugName(); 2880 bool printed = false; 2881 if (fun_name->IsString()) { 2882 String* str = String::cast(fun_name); 2883 if (str->length() > 0) { 2884 accumulator->Add("<JSFunction "); 2885 accumulator->Put(str); 2886 printed = true; 2887 } 2888 } 2889 if (!printed) { 2890 accumulator->Add("<JSFunction"); 2891 } 2892 if (FLAG_trace_file_names) { 2893 Object* source_name = 2894 Script::cast(function->shared()->script())->name(); 2895 if (source_name->IsString()) { 2896 String* str = String::cast(source_name); 2897 if (str->length() > 0) { 2898 accumulator->Add(" <"); 2899 accumulator->Put(str); 2900 accumulator->Add(">"); 2901 } 2902 } 2903 } 2904 accumulator->Add(" (sfi = %p)", 2905 reinterpret_cast<void*>(function->shared())); 2906 accumulator->Put('>'); 2907 break; 2908 } 2909 case JS_GENERATOR_OBJECT_TYPE: { 2910 accumulator->Add("<JSGenerator>"); 2911 break; 2912 } 2913 case JS_ASYNC_GENERATOR_OBJECT_TYPE: { 2914 accumulator->Add("<JS AsyncGenerator>"); 2915 break; 2916 } 2917 2918 // All other JSObjects are rather similar to each other (JSObject, 2919 // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue). 2920 default: { 2921 Map* map_of_this = map(); 2922 Heap* heap = GetHeap(); 2923 Object* constructor = map_of_this->GetConstructor(); 2924 bool printed = false; 2925 if (constructor->IsHeapObject() && 2926 !heap->Contains(HeapObject::cast(constructor))) { 2927 accumulator->Add("!!!INVALID CONSTRUCTOR!!!"); 2928 } else { 2929 bool global_object = IsJSGlobalProxy(); 2930 if (constructor->IsJSFunction()) { 2931 if (!heap->Contains(JSFunction::cast(constructor)->shared())) { 2932 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!"); 2933 } else { 2934 String* constructor_name = 2935 JSFunction::cast(constructor)->shared()->Name(); 2936 if (constructor_name->length() > 0) { 2937 accumulator->Add(global_object ? "<GlobalObject " : "<"); 2938 accumulator->Put(constructor_name); 2939 accumulator->Add( 2940 " %smap = %p", 2941 map_of_this->is_deprecated() ? "deprecated-" : "", 2942 map_of_this); 2943 printed = true; 2944 } 2945 } 2946 } else if (constructor->IsFunctionTemplateInfo()) { 2947 accumulator->Add(global_object ? "<RemoteObject>" : "<RemoteObject>"); 2948 printed = true; 2949 } 2950 if (!printed) { 2951 accumulator->Add("<JS%sObject", global_object ? "Global " : ""); 2952 } 2953 } 2954 if (IsJSValue()) { 2955 accumulator->Add(" value = "); 2956 JSValue::cast(this)->value()->ShortPrint(accumulator); 2957 } 2958 accumulator->Put('>'); 2959 break; 2960 } 2961 } 2962 } 2963 2964 2965 void JSObject::PrintElementsTransition( 2966 FILE* file, Handle<JSObject> object, 2967 ElementsKind from_kind, Handle<FixedArrayBase> from_elements, 2968 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) { 2969 if (from_kind != to_kind) { 2970 OFStream os(file); 2971 os << "elements transition [" << ElementsKindToString(from_kind) << " -> " 2972 << ElementsKindToString(to_kind) << "] in "; 2973 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true); 2974 PrintF(file, " for "); 2975 object->ShortPrint(file); 2976 PrintF(file, " from "); 2977 from_elements->ShortPrint(file); 2978 PrintF(file, " to "); 2979 to_elements->ShortPrint(file); 2980 PrintF(file, "\n"); 2981 } 2982 } 2983 2984 2985 // static 2986 MaybeHandle<JSFunction> Map::GetConstructorFunction( 2987 Handle<Map> map, Handle<Context> native_context) { 2988 if (map->IsPrimitiveMap()) { 2989 int const constructor_function_index = map->GetConstructorFunctionIndex(); 2990 if (constructor_function_index != kNoConstructorFunctionIndex) { 2991 return handle( 2992 JSFunction::cast(native_context->get(constructor_function_index)), 2993 native_context->GetIsolate()); 2994 } 2995 } 2996 return MaybeHandle<JSFunction>(); 2997 } 2998 2999 void Map::PrintReconfiguration(Isolate* isolate, FILE* file, int modify_index, 3000 PropertyKind kind, 3001 PropertyAttributes attributes) { 3002 OFStream os(file); 3003 os << "[reconfiguring]"; 3004 Name* name = instance_descriptors()->GetKey(modify_index); 3005 if (name->IsString()) { 3006 String::cast(name)->PrintOn(file); 3007 } else { 3008 os << "{symbol " << static_cast<void*>(name) << "}"; 3009 } 3010 os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: "; 3011 os << attributes << " ["; 3012 JavaScriptFrame::PrintTop(isolate, file, false, true); 3013 os << "]\n"; 3014 } 3015 3016 VisitorId Map::GetVisitorId(Map* map) { 3017 STATIC_ASSERT(kVisitorIdCount <= 256); 3018 3019 const int instance_type = map->instance_type(); 3020 const bool has_unboxed_fields = 3021 FLAG_unbox_double_fields && !map->HasFastPointerLayout(); 3022 if (instance_type < FIRST_NONSTRING_TYPE) { 3023 switch (instance_type & kStringRepresentationMask) { 3024 case kSeqStringTag: 3025 if ((instance_type & kStringEncodingMask) == kOneByteStringTag) { 3026 return kVisitSeqOneByteString; 3027 } else { 3028 return kVisitSeqTwoByteString; 3029 } 3030 3031 case kConsStringTag: 3032 if (IsShortcutCandidate(instance_type)) { 3033 return kVisitShortcutCandidate; 3034 } else { 3035 return kVisitConsString; 3036 } 3037 3038 case kSlicedStringTag: 3039 return kVisitSlicedString; 3040 3041 case kExternalStringTag: 3042 return kVisitDataObject; 3043 3044 case kThinStringTag: 3045 return kVisitThinString; 3046 } 3047 UNREACHABLE(); 3048 } 3049 3050 switch (instance_type) { 3051 case BYTE_ARRAY_TYPE: 3052 return kVisitByteArray; 3053 3054 case BYTECODE_ARRAY_TYPE: 3055 return kVisitBytecodeArray; 3056 3057 case FREE_SPACE_TYPE: 3058 return kVisitFreeSpace; 3059 3060 case FIXED_ARRAY_TYPE: 3061 case OBJECT_BOILERPLATE_DESCRIPTION_TYPE: 3062 case HASH_TABLE_TYPE: 3063 case ORDERED_HASH_MAP_TYPE: 3064 case ORDERED_HASH_SET_TYPE: 3065 case NAME_DICTIONARY_TYPE: 3066 case GLOBAL_DICTIONARY_TYPE: 3067 case NUMBER_DICTIONARY_TYPE: 3068 case SIMPLE_NUMBER_DICTIONARY_TYPE: 3069 case STRING_TABLE_TYPE: 3070 case SCOPE_INFO_TYPE: 3071 case SCRIPT_CONTEXT_TABLE_TYPE: 3072 case BLOCK_CONTEXT_TYPE: 3073 case CATCH_CONTEXT_TYPE: 3074 case DEBUG_EVALUATE_CONTEXT_TYPE: 3075 case EVAL_CONTEXT_TYPE: 3076 case FUNCTION_CONTEXT_TYPE: 3077 case MODULE_CONTEXT_TYPE: 3078 case NATIVE_CONTEXT_TYPE: 3079 case SCRIPT_CONTEXT_TYPE: 3080 case WITH_CONTEXT_TYPE: 3081 return kVisitFixedArray; 3082 3083 case EPHEMERON_HASH_TABLE_TYPE: 3084 return kVisitEphemeronHashTable; 3085 3086 case WEAK_FIXED_ARRAY_TYPE: 3087 case WEAK_ARRAY_LIST_TYPE: 3088 case DESCRIPTOR_ARRAY_TYPE: 3089 return kVisitWeakArray; 3090 3091 case FIXED_DOUBLE_ARRAY_TYPE: 3092 return kVisitFixedDoubleArray; 3093 3094 case PROPERTY_ARRAY_TYPE: 3095 return kVisitPropertyArray; 3096 3097 case FEEDBACK_CELL_TYPE: 3098 return kVisitFeedbackCell; 3099 3100 case FEEDBACK_VECTOR_TYPE: 3101 return kVisitFeedbackVector; 3102 3103 case ODDBALL_TYPE: 3104 return kVisitOddball; 3105 3106 case MAP_TYPE: 3107 return kVisitMap; 3108 3109 case CODE_TYPE: 3110 return kVisitCode; 3111 3112 case CELL_TYPE: 3113 return kVisitCell; 3114 3115 case PROPERTY_CELL_TYPE: 3116 return kVisitPropertyCell; 3117 3118 case TRANSITION_ARRAY_TYPE: 3119 return kVisitTransitionArray; 3120 3121 case JS_WEAK_MAP_TYPE: 3122 case JS_WEAK_SET_TYPE: 3123 return kVisitJSWeakCollection; 3124 3125 case CALL_HANDLER_INFO_TYPE: 3126 return kVisitStruct; 3127 3128 case SHARED_FUNCTION_INFO_TYPE: 3129 return kVisitSharedFunctionInfo; 3130 3131 case JS_PROXY_TYPE: 3132 return kVisitStruct; 3133 3134 case SYMBOL_TYPE: 3135 return kVisitSymbol; 3136 3137 case JS_ARRAY_BUFFER_TYPE: 3138 return kVisitJSArrayBuffer; 3139 3140 case SMALL_ORDERED_HASH_MAP_TYPE: 3141 return kVisitSmallOrderedHashMap; 3142 3143 case SMALL_ORDERED_HASH_SET_TYPE: 3144 return kVisitSmallOrderedHashSet; 3145 3146 case CODE_DATA_CONTAINER_TYPE: 3147 return kVisitCodeDataContainer; 3148 3149 case WASM_INSTANCE_TYPE: 3150 return kVisitWasmInstanceObject; 3151 3152 case PRE_PARSED_SCOPE_DATA_TYPE: 3153 return kVisitPreParsedScopeData; 3154 3155 case UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE: 3156 return kVisitUncompiledDataWithoutPreParsedScope; 3157 3158 case UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE: 3159 return kVisitUncompiledDataWithPreParsedScope; 3160 3161 case JS_OBJECT_TYPE: 3162 case JS_ERROR_TYPE: 3163 case JS_ARGUMENTS_TYPE: 3164 case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE: 3165 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 3166 case JS_GENERATOR_OBJECT_TYPE: 3167 case JS_ASYNC_GENERATOR_OBJECT_TYPE: 3168 case JS_MODULE_NAMESPACE_TYPE: 3169 case JS_VALUE_TYPE: 3170 case JS_DATE_TYPE: 3171 case JS_ARRAY_ITERATOR_TYPE: 3172 case JS_ARRAY_TYPE: 3173 case JS_GLOBAL_PROXY_TYPE: 3174 case JS_GLOBAL_OBJECT_TYPE: 3175 case JS_MESSAGE_OBJECT_TYPE: 3176 case JS_TYPED_ARRAY_TYPE: 3177 case JS_DATA_VIEW_TYPE: 3178 case JS_SET_TYPE: 3179 case JS_MAP_TYPE: 3180 case JS_SET_KEY_VALUE_ITERATOR_TYPE: 3181 case JS_SET_VALUE_ITERATOR_TYPE: 3182 case JS_MAP_KEY_ITERATOR_TYPE: 3183 case JS_MAP_KEY_VALUE_ITERATOR_TYPE: 3184 case JS_MAP_VALUE_ITERATOR_TYPE: 3185 case JS_STRING_ITERATOR_TYPE: 3186 case JS_PROMISE_TYPE: 3187 case JS_REGEXP_TYPE: 3188 case JS_REGEXP_STRING_ITERATOR_TYPE: 3189 #ifdef V8_INTL_SUPPORT 3190 case JS_INTL_COLLATOR_TYPE: 3191 case JS_INTL_LIST_FORMAT_TYPE: 3192 case JS_INTL_LOCALE_TYPE: 3193 case JS_INTL_PLURAL_RULES_TYPE: 3194 case JS_INTL_RELATIVE_TIME_FORMAT_TYPE: 3195 #endif // V8_INTL_SUPPORT 3196 case WASM_GLOBAL_TYPE: 3197 case WASM_MEMORY_TYPE: 3198 case WASM_MODULE_TYPE: 3199 case WASM_TABLE_TYPE: 3200 case JS_BOUND_FUNCTION_TYPE: 3201 return has_unboxed_fields ? kVisitJSObject : kVisitJSObjectFast; 3202 case JS_API_OBJECT_TYPE: 3203 case JS_SPECIAL_API_OBJECT_TYPE: 3204 return kVisitJSApiObject; 3205 3206 case JS_FUNCTION_TYPE: 3207 return kVisitJSFunction; 3208 3209 case FILLER_TYPE: 3210 case FOREIGN_TYPE: 3211 case HEAP_NUMBER_TYPE: 3212 case MUTABLE_HEAP_NUMBER_TYPE: 3213 case FEEDBACK_METADATA_TYPE: 3214 return kVisitDataObject; 3215 3216 case BIGINT_TYPE: 3217 return kVisitBigInt; 3218 3219 case FIXED_UINT8_ARRAY_TYPE: 3220 case FIXED_INT8_ARRAY_TYPE: 3221 case FIXED_UINT16_ARRAY_TYPE: 3222 case FIXED_INT16_ARRAY_TYPE: 3223 case FIXED_UINT32_ARRAY_TYPE: 3224 case FIXED_INT32_ARRAY_TYPE: 3225 case FIXED_FLOAT32_ARRAY_TYPE: 3226 case FIXED_UINT8_CLAMPED_ARRAY_TYPE: 3227 case FIXED_BIGUINT64_ARRAY_TYPE: 3228 case FIXED_BIGINT64_ARRAY_TYPE: 3229 return kVisitFixedTypedArrayBase; 3230 3231 case FIXED_FLOAT64_ARRAY_TYPE: 3232 return kVisitFixedFloat64Array; 3233 3234 case ALLOCATION_SITE_TYPE: 3235 return kVisitAllocationSite; 3236 3237 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: 3238 STRUCT_LIST(MAKE_STRUCT_CASE) 3239 #undef MAKE_STRUCT_CASE 3240 if (instance_type == PROTOTYPE_INFO_TYPE) { 3241 return kVisitPrototypeInfo; 3242 } 3243 return kVisitStruct; 3244 3245 case LOAD_HANDLER_TYPE: 3246 case STORE_HANDLER_TYPE: 3247 return kVisitDataHandler; 3248 3249 default: 3250 UNREACHABLE(); 3251 } 3252 } 3253 3254 void Map::PrintGeneralization( 3255 Isolate* isolate, FILE* file, const char* reason, int modify_index, 3256 int split, int descriptors, bool descriptor_to_field, 3257 Representation old_representation, Representation new_representation, 3258 MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value, 3259 MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) { 3260 OFStream os(file); 3261 os << "[generalizing]"; 3262 Name* name = instance_descriptors()->GetKey(modify_index); 3263 if (name->IsString()) { 3264 String::cast(name)->PrintOn(file); 3265 } else { 3266 os << "{symbol " << static_cast<void*>(name) << "}"; 3267 } 3268 os << ":"; 3269 if (descriptor_to_field) { 3270 os << "c"; 3271 } else { 3272 os << old_representation.Mnemonic() << "{"; 3273 if (old_field_type.is_null()) { 3274 os << Brief(*(old_value.ToHandleChecked())); 3275 } else { 3276 old_field_type.ToHandleChecked()->PrintTo(os); 3277 } 3278 os << "}"; 3279 } 3280 os << "->" << new_representation.Mnemonic() << "{"; 3281 if (new_field_type.is_null()) { 3282 os << Brief(*(new_value.ToHandleChecked())); 3283 } else { 3284 new_field_type.ToHandleChecked()->PrintTo(os); 3285 } 3286 os << "} ("; 3287 if (strlen(reason) > 0) { 3288 os << reason; 3289 } else { 3290 os << "+" << (descriptors - split) << " maps"; 3291 } 3292 os << ") ["; 3293 JavaScriptFrame::PrintTop(isolate, file, false, true); 3294 os << "]\n"; 3295 } 3296 3297 3298 void JSObject::PrintInstanceMigration(FILE* file, 3299 Map* original_map, 3300 Map* new_map) { 3301 if (new_map->is_dictionary_map()) { 3302 PrintF(file, "[migrating to slow]\n"); 3303 return; 3304 } 3305 PrintF(file, "[migrating]"); 3306 DescriptorArray* o = original_map->instance_descriptors(); 3307 DescriptorArray* n = new_map->instance_descriptors(); 3308 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) { 3309 Representation o_r = o->GetDetails(i).representation(); 3310 Representation n_r = n->GetDetails(i).representation(); 3311 if (!o_r.Equals(n_r)) { 3312 String::cast(o->GetKey(i))->PrintOn(file); 3313 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic()); 3314 } else if (o->GetDetails(i).location() == kDescriptor && 3315 n->GetDetails(i).location() == kField) { 3316 Name* name = o->GetKey(i); 3317 if (name->IsString()) { 3318 String::cast(name)->PrintOn(file); 3319 } else { 3320 PrintF(file, "{symbol %p}", static_cast<void*>(name)); 3321 } 3322 PrintF(file, " "); 3323 } 3324 } 3325 if (original_map->elements_kind() != new_map->elements_kind()) { 3326 PrintF(file, "elements_kind[%i->%i]", original_map->elements_kind(), 3327 new_map->elements_kind()); 3328 } 3329 PrintF(file, "\n"); 3330 } 3331 3332 bool JSObject::IsUnmodifiedApiObject(Object** o) { 3333 Object* object = *o; 3334 if (object->IsSmi()) return false; 3335 HeapObject* heap_object = HeapObject::cast(object); 3336 if (!object->IsJSObject()) return false; 3337 JSObject* js_object = JSObject::cast(object); 3338 if (!js_object->IsApiWrapper()) return false; 3339 Object* maybe_constructor = js_object->map()->GetConstructor(); 3340 if (!maybe_constructor->IsJSFunction()) return false; 3341 JSFunction* constructor = JSFunction::cast(maybe_constructor); 3342 if (js_object->elements()->length() != 0) return false; 3343 3344 return constructor->initial_map() == heap_object->map(); 3345 } 3346 3347 void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT 3348 os << AsHex(reinterpret_cast<Address>(this), kPointerHexDigits, true) << " "; 3349 3350 if (IsString()) { 3351 HeapStringAllocator allocator; 3352 StringStream accumulator(&allocator); 3353 String::cast(this)->StringShortPrint(&accumulator); 3354 os << accumulator.ToCString().get(); 3355 return; 3356 } 3357 if (IsJSObject()) { 3358 HeapStringAllocator allocator; 3359 StringStream accumulator(&allocator); 3360 JSObject::cast(this)->JSObjectShortPrint(&accumulator); 3361 os << accumulator.ToCString().get(); 3362 return; 3363 } 3364 switch (map()->instance_type()) { 3365 case MAP_TYPE: { 3366 os << "<Map"; 3367 Map* mapInstance = Map::cast(this); 3368 if (mapInstance->IsJSObjectMap()) { 3369 os << "(" << ElementsKindToString(mapInstance->elements_kind()) << ")"; 3370 } else if (mapInstance->instance_size() != kVariableSizeSentinel) { 3371 os << "[" << mapInstance->instance_size() << "]"; 3372 } 3373 os << ">"; 3374 } break; 3375 case BLOCK_CONTEXT_TYPE: 3376 os << "<BlockContext[" << FixedArray::cast(this)->length() << "]>"; 3377 break; 3378 case CATCH_CONTEXT_TYPE: 3379 os << "<CatchContext[" << FixedArray::cast(this)->length() << "]>"; 3380 break; 3381 case DEBUG_EVALUATE_CONTEXT_TYPE: 3382 os << "<DebugEvaluateContext[" << FixedArray::cast(this)->length() 3383 << "]>"; 3384 break; 3385 case EVAL_CONTEXT_TYPE: 3386 os << "<EvalContext[" << FixedArray::cast(this)->length() << "]>"; 3387 break; 3388 case FUNCTION_CONTEXT_TYPE: 3389 os << "<FunctionContext[" << FixedArray::cast(this)->length() << "]>"; 3390 break; 3391 case MODULE_CONTEXT_TYPE: 3392 os << "<ModuleContext[" << FixedArray::cast(this)->length() << "]>"; 3393 break; 3394 case NATIVE_CONTEXT_TYPE: 3395 os << "<NativeContext[" << FixedArray::cast(this)->length() << "]>"; 3396 break; 3397 case SCRIPT_CONTEXT_TYPE: 3398 os << "<ScriptContext[" << FixedArray::cast(this)->length() << "]>"; 3399 break; 3400 case WITH_CONTEXT_TYPE: 3401 os << "<WithContext[" << FixedArray::cast(this)->length() << "]>"; 3402 break; 3403 case SCRIPT_CONTEXT_TABLE_TYPE: 3404 os << "<ScriptContextTable[" << FixedArray::cast(this)->length() << "]>"; 3405 break; 3406 case HASH_TABLE_TYPE: 3407 os << "<HashTable[" << FixedArray::cast(this)->length() << "]>"; 3408 break; 3409 case ORDERED_HASH_MAP_TYPE: 3410 os << "<OrderedHashMap[" << FixedArray::cast(this)->length() << "]>"; 3411 break; 3412 case ORDERED_HASH_SET_TYPE: 3413 os << "<OrderedHashSet[" << FixedArray::cast(this)->length() << "]>"; 3414 break; 3415 case NAME_DICTIONARY_TYPE: 3416 os << "<NameDictionary[" << FixedArray::cast(this)->length() << "]>"; 3417 break; 3418 case GLOBAL_DICTIONARY_TYPE: 3419 os << "<GlobalDictionary[" << FixedArray::cast(this)->length() << "]>"; 3420 break; 3421 case NUMBER_DICTIONARY_TYPE: 3422 os << "<NumberDictionary[" << FixedArray::cast(this)->length() << "]>"; 3423 break; 3424 case SIMPLE_NUMBER_DICTIONARY_TYPE: 3425 os << "<SimpleNumberDictionary[" << FixedArray::cast(this)->length() 3426 << "]>"; 3427 break; 3428 case STRING_TABLE_TYPE: 3429 os << "<StringTable[" << FixedArray::cast(this)->length() << "]>"; 3430 break; 3431 case FIXED_ARRAY_TYPE: 3432 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>"; 3433 break; 3434 case OBJECT_BOILERPLATE_DESCRIPTION_TYPE: 3435 os << "<ObjectBoilerplateDescription[" << FixedArray::cast(this)->length() 3436 << "]>"; 3437 break; 3438 case FIXED_DOUBLE_ARRAY_TYPE: 3439 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length() 3440 << "]>"; 3441 break; 3442 case BYTE_ARRAY_TYPE: 3443 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>"; 3444 break; 3445 case BYTECODE_ARRAY_TYPE: 3446 os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>"; 3447 break; 3448 case DESCRIPTOR_ARRAY_TYPE: 3449 os << "<DescriptorArray[" << DescriptorArray::cast(this)->length() 3450 << "]>"; 3451 break; 3452 case TRANSITION_ARRAY_TYPE: 3453 os << "<TransitionArray[" << TransitionArray::cast(this)->length() 3454 << "]>"; 3455 break; 3456 case PROPERTY_ARRAY_TYPE: 3457 os << "<PropertyArray[" << PropertyArray::cast(this)->length() << "]>"; 3458 break; 3459 case FEEDBACK_CELL_TYPE: { 3460 { 3461 ReadOnlyRoots roots = GetReadOnlyRoots(); 3462 os << "<FeedbackCell["; 3463 if (map() == roots.no_closures_cell_map()) { 3464 os << "no closures"; 3465 } else if (map() == roots.one_closure_cell_map()) { 3466 os << "one closure"; 3467 } else if (map() == roots.many_closures_cell_map()) { 3468 os << "many closures"; 3469 } else { 3470 os << "!!!INVALID MAP!!!"; 3471 } 3472 os << "]>"; 3473 } 3474 break; 3475 } 3476 case FEEDBACK_VECTOR_TYPE: 3477 os << "<FeedbackVector[" << FeedbackVector::cast(this)->length() << "]>"; 3478 break; 3479 case FREE_SPACE_TYPE: 3480 os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>"; 3481 break; 3482 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype) \ 3483 case FIXED_##TYPE##_ARRAY_TYPE: \ 3484 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \ 3485 << "]>"; \ 3486 break; 3487 3488 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT) 3489 #undef TYPED_ARRAY_SHORT_PRINT 3490 3491 case PRE_PARSED_SCOPE_DATA_TYPE: { 3492 PreParsedScopeData* data = PreParsedScopeData::cast(this); 3493 os << "<PreParsedScopeData[" << data->length() << "]>"; 3494 break; 3495 } 3496 3497 case UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE: { 3498 UncompiledDataWithoutPreParsedScope* data = 3499 UncompiledDataWithoutPreParsedScope::cast(this); 3500 os << "<UncompiledDataWithoutPreParsedScope (" << data->start_position() 3501 << ", " << data->end_position() << ")]>"; 3502 break; 3503 } 3504 3505 case UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE: { 3506 UncompiledDataWithPreParsedScope* data = 3507 UncompiledDataWithPreParsedScope::cast(this); 3508 os << "<UncompiledDataWithPreParsedScope (" << data->start_position() 3509 << ", " << data->end_position() 3510 << ") preparsed=" << Brief(data->pre_parsed_scope_data()) << ">"; 3511 break; 3512 } 3513 3514 case SHARED_FUNCTION_INFO_TYPE: { 3515 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this); 3516 std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString(); 3517 if (debug_name[0] != 0) { 3518 os << "<SharedFunctionInfo " << debug_name.get() << ">"; 3519 } else { 3520 os << "<SharedFunctionInfo>"; 3521 } 3522 break; 3523 } 3524 case JS_MESSAGE_OBJECT_TYPE: 3525 os << "<JSMessageObject>"; 3526 break; 3527 #define MAKE_STRUCT_CASE(NAME, Name, name) \ 3528 case NAME##_TYPE: \ 3529 os << "<" #Name; \ 3530 Name::cast(this)->BriefPrintDetails(os); \ 3531 os << ">"; \ 3532 break; 3533 STRUCT_LIST(MAKE_STRUCT_CASE) 3534 #undef MAKE_STRUCT_CASE 3535 case ALLOCATION_SITE_TYPE: { 3536 os << "<AllocationSite"; 3537 AllocationSite::cast(this)->BriefPrintDetails(os); 3538 os << ">"; 3539 break; 3540 } 3541 case SCOPE_INFO_TYPE: { 3542 ScopeInfo* scope = ScopeInfo::cast(this); 3543 os << "<ScopeInfo"; 3544 if (scope->length()) os << " " << scope->scope_type() << " "; 3545 os << "[" << scope->length() << "]>"; 3546 break; 3547 } 3548 case CODE_TYPE: { 3549 Code* code = Code::cast(this); 3550 os << "<Code " << Code::Kind2String(code->kind()); 3551 if (code->is_stub()) { 3552 os << " " << CodeStub::MajorName(CodeStub::GetMajorKey(code)); 3553 } else if (code->is_builtin()) { 3554 os << " " << Builtins::name(code->builtin_index()); 3555 } 3556 os << ">"; 3557 break; 3558 } 3559 case ODDBALL_TYPE: { 3560 if (IsUndefined()) { 3561 os << "<undefined>"; 3562 } else if (IsTheHole()) { 3563 os << "<the_hole>"; 3564 } else if (IsNull()) { 3565 os << "<null>"; 3566 } else if (IsTrue()) { 3567 os << "<true>"; 3568 } else if (IsFalse()) { 3569 os << "<false>"; 3570 } else { 3571 os << "<Odd Oddball: "; 3572 os << Oddball::cast(this)->to_string()->ToCString().get(); 3573 os << ">"; 3574 } 3575 break; 3576 } 3577 case SYMBOL_TYPE: { 3578 Symbol* symbol = Symbol::cast(this); 3579 symbol->SymbolShortPrint(os); 3580 break; 3581 } 3582 case HEAP_NUMBER_TYPE: { 3583 os << "<HeapNumber "; 3584 HeapNumber::cast(this)->HeapNumberPrint(os); 3585 os << ">"; 3586 break; 3587 } 3588 case MUTABLE_HEAP_NUMBER_TYPE: { 3589 os << "<MutableHeapNumber "; 3590 MutableHeapNumber::cast(this)->MutableHeapNumberPrint(os); 3591 os << '>'; 3592 break; 3593 } 3594 case BIGINT_TYPE: { 3595 os << "<BigInt "; 3596 BigInt::cast(this)->BigIntShortPrint(os); 3597 os << ">"; 3598 break; 3599 } 3600 case JS_PROXY_TYPE: 3601 os << "<JSProxy>"; 3602 break; 3603 case FOREIGN_TYPE: 3604 os << "<Foreign>"; 3605 break; 3606 case CELL_TYPE: { 3607 os << "<Cell value= "; 3608 HeapStringAllocator allocator; 3609 StringStream accumulator(&allocator); 3610 Cell::cast(this)->value()->ShortPrint(&accumulator); 3611 os << accumulator.ToCString().get(); 3612 os << '>'; 3613 break; 3614 } 3615 case PROPERTY_CELL_TYPE: { 3616 PropertyCell* cell = PropertyCell::cast(this); 3617 os << "<PropertyCell name="; 3618 cell->name()->ShortPrint(os); 3619 os << " value="; 3620 HeapStringAllocator allocator; 3621 StringStream accumulator(&allocator); 3622 cell->value()->ShortPrint(&accumulator); 3623 os << accumulator.ToCString().get(); 3624 os << '>'; 3625 break; 3626 } 3627 case CALL_HANDLER_INFO_TYPE: { 3628 CallHandlerInfo* info = CallHandlerInfo::cast(this); 3629 os << "<CallHandlerInfo "; 3630 os << "callback= " << Brief(info->callback()); 3631 os << ", js_callback= " << Brief(info->js_callback()); 3632 os << ", data= " << Brief(info->data()); 3633 if (info->IsSideEffectFreeCallHandlerInfo()) { 3634 os << ", side_effect_free= true>"; 3635 } else { 3636 os << ", side_effect_free= false>"; 3637 } 3638 break; 3639 } 3640 default: 3641 os << "<Other heap object (" << map()->instance_type() << ")>"; 3642 break; 3643 } 3644 } 3645 3646 void Struct::BriefPrintDetails(std::ostream& os) {} 3647 3648 void Tuple2::BriefPrintDetails(std::ostream& os) { 3649 os << " " << Brief(value1()) << ", " << Brief(value2()); 3650 } 3651 3652 void Tuple3::BriefPrintDetails(std::ostream& os) { 3653 os << " " << Brief(value1()) << ", " << Brief(value2()) << ", " 3654 << Brief(value3()); 3655 } 3656 3657 void ArrayBoilerplateDescription::BriefPrintDetails(std::ostream& os) { 3658 os << " " << elements_kind() << ", " << Brief(constant_elements()); 3659 } 3660 3661 void CallableTask::BriefPrintDetails(std::ostream& os) { 3662 os << " callable=" << Brief(callable()); 3663 } 3664 3665 void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); } 3666 3667 3668 void HeapObject::IterateBody(ObjectVisitor* v) { 3669 Map* m = map(); 3670 IterateBodyFast<ObjectVisitor>(m, SizeFromMap(m), v); 3671 } 3672 3673 void HeapObject::IterateBody(Map* map, int object_size, ObjectVisitor* v) { 3674 IterateBodyFast<ObjectVisitor>(map, object_size, v); 3675 } 3676 3677 3678 struct CallIsValidSlot { 3679 template <typename BodyDescriptor> 3680 static bool apply(Map* map, HeapObject* obj, int offset, int) { 3681 return BodyDescriptor::IsValidSlot(map, obj, offset); 3682 } 3683 }; 3684 3685 bool HeapObject::IsValidSlot(Map* map, int offset) { 3686 DCHECK_NE(0, offset); 3687 return BodyDescriptorApply<CallIsValidSlot, bool>(map->instance_type(), map, 3688 this, offset, 0); 3689 } 3690 3691 String* JSReceiver::class_name() { 3692 ReadOnlyRoots roots = GetReadOnlyRoots(); 3693 if (IsFunction()) return roots.Function_string(); 3694 if (IsJSArgumentsObject()) return roots.Arguments_string(); 3695 if (IsJSArray()) return roots.Array_string(); 3696 if (IsJSArrayBuffer()) { 3697 if (JSArrayBuffer::cast(this)->is_shared()) { 3698 return roots.SharedArrayBuffer_string(); 3699 } 3700 return roots.ArrayBuffer_string(); 3701 } 3702 if (IsJSArrayIterator()) return roots.ArrayIterator_string(); 3703 if (IsJSDate()) return roots.Date_string(); 3704 if (IsJSError()) return roots.Error_string(); 3705 if (IsJSGeneratorObject()) return roots.Generator_string(); 3706 if (IsJSMap()) return roots.Map_string(); 3707 if (IsJSMapIterator()) return roots.MapIterator_string(); 3708 if (IsJSProxy()) { 3709 return map()->is_callable() ? roots.Function_string() 3710 : roots.Object_string(); 3711 } 3712 if (IsJSRegExp()) return roots.RegExp_string(); 3713 if (IsJSSet()) return roots.Set_string(); 3714 if (IsJSSetIterator()) return roots.SetIterator_string(); 3715 if (IsJSTypedArray()) { 3716 #define SWITCH_KIND(Type, type, TYPE, ctype) \ 3717 if (map()->elements_kind() == TYPE##_ELEMENTS) { \ 3718 return roots.Type##Array_string(); \ 3719 } 3720 TYPED_ARRAYS(SWITCH_KIND) 3721 #undef SWITCH_KIND 3722 } 3723 if (IsJSValue()) { 3724 Object* value = JSValue::cast(this)->value(); 3725 if (value->IsBoolean()) return roots.Boolean_string(); 3726 if (value->IsString()) return roots.String_string(); 3727 if (value->IsNumber()) return roots.Number_string(); 3728 if (value->IsBigInt()) return roots.BigInt_string(); 3729 if (value->IsSymbol()) return roots.Symbol_string(); 3730 if (value->IsScript()) return roots.Script_string(); 3731 UNREACHABLE(); 3732 } 3733 if (IsJSWeakMap()) return roots.WeakMap_string(); 3734 if (IsJSWeakSet()) return roots.WeakSet_string(); 3735 if (IsJSGlobalProxy()) return roots.global_string(); 3736 3737 Object* maybe_constructor = map()->GetConstructor(); 3738 if (maybe_constructor->IsJSFunction()) { 3739 JSFunction* constructor = JSFunction::cast(maybe_constructor); 3740 if (constructor->shared()->IsApiFunction()) { 3741 maybe_constructor = constructor->shared()->get_api_func_data(); 3742 } 3743 } 3744 3745 if (maybe_constructor->IsFunctionTemplateInfo()) { 3746 FunctionTemplateInfo* info = FunctionTemplateInfo::cast(maybe_constructor); 3747 if (info->class_name()->IsString()) return String::cast(info->class_name()); 3748 } 3749 3750 return roots.Object_string(); 3751 } 3752 3753 bool HeapObject::CanBeRehashed() const { 3754 DCHECK(NeedsRehashing()); 3755 switch (map()->instance_type()) { 3756 case ORDERED_HASH_MAP_TYPE: 3757 case ORDERED_HASH_SET_TYPE: 3758 // TODO(yangguo): actually support rehashing OrderedHash{Map,Set}. 3759 return false; 3760 case NAME_DICTIONARY_TYPE: 3761 case GLOBAL_DICTIONARY_TYPE: 3762 case NUMBER_DICTIONARY_TYPE: 3763 case SIMPLE_NUMBER_DICTIONARY_TYPE: 3764 case STRING_TABLE_TYPE: 3765 return true; 3766 case DESCRIPTOR_ARRAY_TYPE: 3767 return true; 3768 case TRANSITION_ARRAY_TYPE: 3769 return true; 3770 case SMALL_ORDERED_HASH_MAP_TYPE: 3771 return SmallOrderedHashMap::cast(this)->NumberOfElements() == 0; 3772 case SMALL_ORDERED_HASH_SET_TYPE: 3773 return SmallOrderedHashMap::cast(this)->NumberOfElements() == 0; 3774 default: 3775 return false; 3776 } 3777 return false; 3778 } 3779 3780 void HeapObject::RehashBasedOnMap(Isolate* isolate) { 3781 switch (map()->instance_type()) { 3782 case HASH_TABLE_TYPE: 3783 UNREACHABLE(); 3784 break; 3785 case NAME_DICTIONARY_TYPE: 3786 NameDictionary::cast(this)->Rehash(isolate); 3787 break; 3788 case GLOBAL_DICTIONARY_TYPE: 3789 GlobalDictionary::cast(this)->Rehash(isolate); 3790 break; 3791 case NUMBER_DICTIONARY_TYPE: 3792 NumberDictionary::cast(this)->Rehash(isolate); 3793 break; 3794 case SIMPLE_NUMBER_DICTIONARY_TYPE: 3795 SimpleNumberDictionary::cast(this)->Rehash(isolate); 3796 break; 3797 case STRING_TABLE_TYPE: 3798 StringTable::cast(this)->Rehash(isolate); 3799 break; 3800 case DESCRIPTOR_ARRAY_TYPE: 3801 DCHECK_LE(1, DescriptorArray::cast(this)->number_of_descriptors()); 3802 DescriptorArray::cast(this)->Sort(); 3803 break; 3804 case TRANSITION_ARRAY_TYPE: 3805 TransitionArray::cast(this)->Sort(); 3806 break; 3807 case SMALL_ORDERED_HASH_MAP_TYPE: 3808 DCHECK_EQ(0, SmallOrderedHashMap::cast(this)->NumberOfElements()); 3809 break; 3810 case SMALL_ORDERED_HASH_SET_TYPE: 3811 DCHECK_EQ(0, SmallOrderedHashSet::cast(this)->NumberOfElements()); 3812 break; 3813 default: 3814 break; 3815 } 3816 } 3817 3818 namespace { 3819 std::pair<MaybeHandle<JSFunction>, Handle<String>> GetConstructorHelper( 3820 Handle<JSReceiver> receiver) { 3821 Isolate* isolate = receiver->GetIsolate(); 3822 3823 // If the object was instantiated simply with base == new.target, the 3824 // constructor on the map provides the most accurate name. 3825 // Don't provide the info for prototypes, since their constructors are 3826 // reclaimed and replaced by Object in OptimizeAsPrototype. 3827 if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() && 3828 !receiver->map()->is_prototype_map()) { 3829 Object* maybe_constructor = receiver->map()->GetConstructor(); 3830 if (maybe_constructor->IsJSFunction()) { 3831 JSFunction* constructor = JSFunction::cast(maybe_constructor); 3832 String* name = constructor->shared()->DebugName(); 3833 if (name->length() != 0 && 3834 !name->Equals(ReadOnlyRoots(isolate).Object_string())) { 3835 return std::make_pair(handle(constructor, isolate), 3836 handle(name, isolate)); 3837 } 3838 } else if (maybe_constructor->IsFunctionTemplateInfo()) { 3839 FunctionTemplateInfo* info = 3840 FunctionTemplateInfo::cast(maybe_constructor); 3841 if (info->class_name()->IsString()) { 3842 return std::make_pair( 3843 MaybeHandle<JSFunction>(), 3844 handle(String::cast(info->class_name()), isolate)); 3845 } 3846 } 3847 } 3848 3849 Handle<Object> maybe_tag = JSReceiver::GetDataProperty( 3850 receiver, isolate->factory()->to_string_tag_symbol()); 3851 if (maybe_tag->IsString()) 3852 return std::make_pair(MaybeHandle<JSFunction>(), 3853 Handle<String>::cast(maybe_tag)); 3854 3855 PrototypeIterator iter(isolate, receiver); 3856 if (iter.IsAtEnd()) { 3857 return std::make_pair(MaybeHandle<JSFunction>(), 3858 handle(receiver->class_name(), isolate)); 3859 } 3860 3861 Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter); 3862 LookupIterator it(receiver, isolate->factory()->constructor_string(), start, 3863 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); 3864 Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it); 3865 if (maybe_constructor->IsJSFunction()) { 3866 JSFunction* constructor = JSFunction::cast(*maybe_constructor); 3867 String* name = constructor->shared()->DebugName(); 3868 3869 if (name->length() != 0 && 3870 !name->Equals(ReadOnlyRoots(isolate).Object_string())) { 3871 return std::make_pair(handle(constructor, isolate), 3872 handle(name, isolate)); 3873 } 3874 } 3875 3876 return std::make_pair(MaybeHandle<JSFunction>(), 3877 handle(receiver->class_name(), isolate)); 3878 } 3879 } // anonymous namespace 3880 3881 // static 3882 MaybeHandle<JSFunction> JSReceiver::GetConstructor( 3883 Handle<JSReceiver> receiver) { 3884 return GetConstructorHelper(receiver).first; 3885 } 3886 3887 // static 3888 Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) { 3889 return GetConstructorHelper(receiver).second; 3890 } 3891 3892 Handle<Context> JSReceiver::GetCreationContext() { 3893 JSReceiver* receiver = this; 3894 // Externals are JSObjects with null as a constructor. 3895 DCHECK(!receiver->IsExternal(GetIsolate())); 3896 Object* constructor = receiver->map()->GetConstructor(); 3897 JSFunction* function; 3898 if (constructor->IsJSFunction()) { 3899 function = JSFunction::cast(constructor); 3900 } else if (constructor->IsFunctionTemplateInfo()) { 3901 // Remote objects don't have a creation context. 3902 return Handle<Context>::null(); 3903 } else { 3904 // Functions have null as a constructor, 3905 // but any JSFunction knows its context immediately. 3906 CHECK(receiver->IsJSFunction()); 3907 function = JSFunction::cast(receiver); 3908 } 3909 3910 return function->has_context() 3911 ? Handle<Context>(function->context()->native_context(), 3912 receiver->GetIsolate()) 3913 : Handle<Context>::null(); 3914 } 3915 3916 // static 3917 MaybeObjectHandle Map::WrapFieldType(Isolate* isolate, Handle<FieldType> type) { 3918 if (type->IsClass()) { 3919 return MaybeObjectHandle::Weak(type->AsClass(), isolate); 3920 } 3921 return MaybeObjectHandle(type); 3922 } 3923 3924 // static 3925 FieldType* Map::UnwrapFieldType(MaybeObject* wrapped_type) { 3926 if (wrapped_type->IsClearedWeakHeapObject()) { 3927 return FieldType::None(); 3928 } 3929 HeapObject* heap_object; 3930 if (wrapped_type->ToWeakHeapObject(&heap_object)) { 3931 return FieldType::cast(heap_object); 3932 } 3933 return FieldType::cast(wrapped_type->ToObject()); 3934 } 3935 3936 MaybeHandle<Map> Map::CopyWithField(Isolate* isolate, Handle<Map> map, 3937 Handle<Name> name, Handle<FieldType> type, 3938 PropertyAttributes attributes, 3939 PropertyConstness constness, 3940 Representation representation, 3941 TransitionFlag flag) { 3942 DCHECK(DescriptorArray::kNotFound == 3943 map->instance_descriptors()->Search( 3944 *name, map->NumberOfOwnDescriptors())); 3945 3946 // Ensure the descriptor array does not get too big. 3947 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { 3948 return MaybeHandle<Map>(); 3949 } 3950 3951 // Compute the new index for new field. 3952 int index = map->NextFreePropertyIndex(); 3953 3954 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) { 3955 constness = PropertyConstness::kMutable; 3956 representation = Representation::Tagged(); 3957 type = FieldType::Any(isolate); 3958 } else { 3959 Map::GeneralizeIfCanHaveTransitionableFastElementsKind( 3960 isolate, map->instance_type(), &constness, &representation, &type); 3961 } 3962 3963 MaybeObjectHandle wrapped_type = WrapFieldType(isolate, type); 3964 3965 DCHECK_IMPLIES(!FLAG_track_constant_fields, 3966 constness == PropertyConstness::kMutable); 3967 Descriptor d = Descriptor::DataField(name, index, attributes, constness, 3968 representation, wrapped_type); 3969 Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag); 3970 new_map->AccountAddedPropertyField(); 3971 return new_map; 3972 } 3973 3974 MaybeHandle<Map> Map::CopyWithConstant(Isolate* isolate, Handle<Map> map, 3975 Handle<Name> name, 3976 Handle<Object> constant, 3977 PropertyAttributes attributes, 3978 TransitionFlag flag) { 3979 // Ensure the descriptor array does not get too big. 3980 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { 3981 return MaybeHandle<Map>(); 3982 } 3983 3984 if (FLAG_track_constant_fields) { 3985 Representation representation = constant->OptimalRepresentation(); 3986 Handle<FieldType> type = constant->OptimalType(isolate, representation); 3987 return CopyWithField(isolate, map, name, type, attributes, 3988 PropertyConstness::kConst, representation, flag); 3989 } else { 3990 // Allocate new instance descriptors with (name, constant) added. 3991 Descriptor d = 3992 Descriptor::DataConstant(isolate, name, 0, constant, attributes); 3993 Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag); 3994 return new_map; 3995 } 3996 } 3997 3998 const char* Representation::Mnemonic() const { 3999 switch (kind_) { 4000 case kNone: return "v"; 4001 case kTagged: return "t"; 4002 case kSmi: return "s"; 4003 case kDouble: return "d"; 4004 case kInteger32: return "i"; 4005 case kHeapObject: return "h"; 4006 case kExternal: return "x"; 4007 default: 4008 UNREACHABLE(); 4009 } 4010 } 4011 4012 bool Map::TransitionRemovesTaggedField(Map* target) const { 4013 int inobject = NumberOfFields(); 4014 int target_inobject = target->NumberOfFields(); 4015 for (int i = target_inobject; i < inobject; i++) { 4016 FieldIndex index = FieldIndex::ForPropertyIndex(this, i); 4017 if (!IsUnboxedDoubleField(index)) return true; 4018 } 4019 return false; 4020 } 4021 4022 bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) const { 4023 int inobject = NumberOfFields(); 4024 int target_inobject = target->NumberOfFields(); 4025 int limit = Min(inobject, target_inobject); 4026 for (int i = 0; i < limit; i++) { 4027 FieldIndex index = FieldIndex::ForPropertyIndex(target, i); 4028 if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) { 4029 return true; 4030 } 4031 } 4032 return false; 4033 } 4034 4035 bool Map::TransitionRequiresSynchronizationWithGC(Map* target) const { 4036 return TransitionRemovesTaggedField(target) || 4037 TransitionChangesTaggedFieldToUntaggedField(target); 4038 } 4039 4040 bool Map::InstancesNeedRewriting(Map* target) const { 4041 int target_number_of_fields = target->NumberOfFields(); 4042 int target_inobject = target->GetInObjectProperties(); 4043 int target_unused = target->UnusedPropertyFields(); 4044 int old_number_of_fields; 4045 4046 return InstancesNeedRewriting(target, target_number_of_fields, 4047 target_inobject, target_unused, 4048 &old_number_of_fields); 4049 } 4050 4051 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields, 4052 int target_inobject, int target_unused, 4053 int* old_number_of_fields) const { 4054 // If fields were added (or removed), rewrite the instance. 4055 *old_number_of_fields = NumberOfFields(); 4056 DCHECK(target_number_of_fields >= *old_number_of_fields); 4057 if (target_number_of_fields != *old_number_of_fields) return true; 4058 4059 // If smi descriptors were replaced by double descriptors, rewrite. 4060 DescriptorArray* old_desc = instance_descriptors(); 4061 DescriptorArray* new_desc = target->instance_descriptors(); 4062 int limit = NumberOfOwnDescriptors(); 4063 for (int i = 0; i < limit; i++) { 4064 if (new_desc->GetDetails(i).representation().IsDouble() != 4065 old_desc->GetDetails(i).representation().IsDouble()) { 4066 return true; 4067 } 4068 } 4069 4070 // If no fields were added, and no inobject properties were removed, setting 4071 // the map is sufficient. 4072 if (target_inobject == GetInObjectProperties()) return false; 4073 // In-object slack tracking may have reduced the object size of the new map. 4074 // In that case, succeed if all existing fields were inobject, and they still 4075 // fit within the new inobject size. 4076 DCHECK(target_inobject < GetInObjectProperties()); 4077 if (target_number_of_fields <= target_inobject) { 4078 DCHECK(target_number_of_fields + target_unused == target_inobject); 4079 return false; 4080 } 4081 // Otherwise, properties will need to be moved to the backing store. 4082 return true; 4083 } 4084 4085 4086 // static 4087 void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map, 4088 Handle<Map> new_map, 4089 Isolate* isolate) { 4090 DCHECK(old_map->is_prototype_map()); 4091 DCHECK(new_map->is_prototype_map()); 4092 bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate); 4093 new_map->set_prototype_info(old_map->prototype_info()); 4094 old_map->set_prototype_info(Smi::kZero); 4095 if (FLAG_trace_prototype_users) { 4096 PrintF("Moving prototype_info %p from map %p to map %p.\n", 4097 reinterpret_cast<void*>(new_map->prototype_info()), 4098 reinterpret_cast<void*>(*old_map), 4099 reinterpret_cast<void*>(*new_map)); 4100 } 4101 if (was_registered) { 4102 if (new_map->prototype_info()->IsPrototypeInfo()) { 4103 // The new map isn't registered with its prototype yet; reflect this fact 4104 // in the PrototypeInfo it just inherited from the old map. 4105 PrototypeInfo::cast(new_map->prototype_info()) 4106 ->set_registry_slot(PrototypeInfo::UNREGISTERED); 4107 } 4108 JSObject::LazyRegisterPrototypeUser(new_map, isolate); 4109 } 4110 } 4111 4112 namespace { 4113 // To migrate a fast instance to a fast map: 4114 // - First check whether the instance needs to be rewritten. If not, simply 4115 // change the map. 4116 // - Otherwise, allocate a fixed array large enough to hold all fields, in 4117 // addition to unused space. 4118 // - Copy all existing properties in, in the following order: backing store 4119 // properties, unused fields, inobject properties. 4120 // - If all allocation succeeded, commit the state atomically: 4121 // * Copy inobject properties from the backing store back into the object. 4122 // * Trim the difference in instance size of the object. This also cleanly 4123 // frees inobject properties that moved to the backing store. 4124 // * If there are properties left in the backing store, trim of the space used 4125 // to temporarily store the inobject properties. 4126 // * If there are properties left in the backing store, install the backing 4127 // store. 4128 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { 4129 Isolate* isolate = object->GetIsolate(); 4130 Handle<Map> old_map(object->map(), isolate); 4131 // In case of a regular transition. 4132 if (new_map->GetBackPointer() == *old_map) { 4133 // If the map does not add named properties, simply set the map. 4134 if (old_map->NumberOfOwnDescriptors() == 4135 new_map->NumberOfOwnDescriptors()) { 4136 object->synchronized_set_map(*new_map); 4137 return; 4138 } 4139 4140 PropertyDetails details = new_map->GetLastDescriptorDetails(); 4141 int target_index = details.field_index() - new_map->GetInObjectProperties(); 4142 int property_array_length = object->property_array()->length(); 4143 bool have_space = old_map->UnusedPropertyFields() > 0 || 4144 (details.location() == kField && target_index >= 0 && 4145 property_array_length > target_index); 4146 // Either new_map adds an kDescriptor property, or a kField property for 4147 // which there is still space, and which does not require a mutable double 4148 // box (an out-of-object double). 4149 if (details.location() == kDescriptor || 4150 (have_space && ((FLAG_unbox_double_fields && target_index < 0) || 4151 !details.representation().IsDouble()))) { 4152 object->synchronized_set_map(*new_map); 4153 return; 4154 } 4155 4156 // If there is still space in the object, we need to allocate a mutable 4157 // double box. 4158 if (have_space) { 4159 FieldIndex index = 4160 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded()); 4161 DCHECK(details.representation().IsDouble()); 4162 DCHECK(!new_map->IsUnboxedDoubleField(index)); 4163 auto value = isolate->factory()->NewMutableHeapNumberWithHoleNaN(); 4164 object->RawFastPropertyAtPut(index, *value); 4165 object->synchronized_set_map(*new_map); 4166 return; 4167 } 4168 4169 // This migration is a transition from a map that has run out of property 4170 // space. Extend the backing store. 4171 int grow_by = new_map->UnusedPropertyFields() + 1; 4172 Handle<PropertyArray> old_storage(object->property_array(), isolate); 4173 Handle<PropertyArray> new_storage = 4174 isolate->factory()->CopyPropertyArrayAndGrow(old_storage, grow_by); 4175 4176 // Properly initialize newly added property. 4177 Handle<Object> value; 4178 if (details.representation().IsDouble()) { 4179 value = isolate->factory()->NewMutableHeapNumberWithHoleNaN(); 4180 } else { 4181 value = isolate->factory()->uninitialized_value(); 4182 } 4183 DCHECK_EQ(kField, details.location()); 4184 DCHECK_EQ(kData, details.kind()); 4185 DCHECK_GE(target_index, 0); // Must be a backing store index. 4186 new_storage->set(target_index, *value); 4187 4188 // From here on we cannot fail and we shouldn't GC anymore. 4189 DisallowHeapAllocation no_allocation; 4190 4191 // Set the new property value and do the map transition. 4192 object->SetProperties(*new_storage); 4193 object->synchronized_set_map(*new_map); 4194 return; 4195 } 4196 4197 int old_number_of_fields; 4198 int number_of_fields = new_map->NumberOfFields(); 4199 int inobject = new_map->GetInObjectProperties(); 4200 int unused = new_map->UnusedPropertyFields(); 4201 4202 // Nothing to do if no functions were converted to fields and no smis were 4203 // converted to doubles. 4204 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject, 4205 unused, &old_number_of_fields)) { 4206 object->synchronized_set_map(*new_map); 4207 return; 4208 } 4209 4210 int total_size = number_of_fields + unused; 4211 int external = total_size - inobject; 4212 Handle<PropertyArray> array = isolate->factory()->NewPropertyArray(external); 4213 4214 // We use this array to temporarily store the inobject properties. 4215 Handle<FixedArray> inobject_props = 4216 isolate->factory()->NewFixedArray(inobject); 4217 4218 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors(), 4219 isolate); 4220 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors(), 4221 isolate); 4222 int old_nof = old_map->NumberOfOwnDescriptors(); 4223 int new_nof = new_map->NumberOfOwnDescriptors(); 4224 4225 // This method only supports generalizing instances to at least the same 4226 // number of properties. 4227 DCHECK(old_nof <= new_nof); 4228 4229 for (int i = 0; i < old_nof; i++) { 4230 PropertyDetails details = new_descriptors->GetDetails(i); 4231 if (details.location() != kField) continue; 4232 DCHECK_EQ(kData, details.kind()); 4233 PropertyDetails old_details = old_descriptors->GetDetails(i); 4234 Representation old_representation = old_details.representation(); 4235 Representation representation = details.representation(); 4236 Handle<Object> value; 4237 if (old_details.location() == kDescriptor) { 4238 if (old_details.kind() == kAccessor) { 4239 // In case of kAccessor -> kData property reconfiguration, the property 4240 // must already be prepared for data of certain type. 4241 DCHECK(!details.representation().IsNone()); 4242 if (details.representation().IsDouble()) { 4243 value = isolate->factory()->NewMutableHeapNumberWithHoleNaN(); 4244 } else { 4245 value = isolate->factory()->uninitialized_value(); 4246 } 4247 } else { 4248 DCHECK_EQ(kData, old_details.kind()); 4249 value = handle(old_descriptors->GetStrongValue(i), isolate); 4250 DCHECK(!old_representation.IsDouble() && !representation.IsDouble()); 4251 } 4252 } else { 4253 DCHECK_EQ(kField, old_details.location()); 4254 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i); 4255 if (object->IsUnboxedDoubleField(index)) { 4256 uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index); 4257 if (representation.IsDouble()) { 4258 value = isolate->factory()->NewMutableHeapNumberFromBits(old_bits); 4259 } else { 4260 value = isolate->factory()->NewHeapNumberFromBits(old_bits); 4261 } 4262 } else { 4263 value = handle(object->RawFastPropertyAt(index), isolate); 4264 if (!old_representation.IsDouble() && representation.IsDouble()) { 4265 DCHECK_IMPLIES(old_representation.IsNone(), 4266 value->IsUninitialized(isolate)); 4267 value = Object::NewStorageFor(isolate, value, representation); 4268 } else if (old_representation.IsDouble() && 4269 !representation.IsDouble()) { 4270 value = Object::WrapForRead(isolate, value, old_representation); 4271 } 4272 } 4273 } 4274 DCHECK(!(representation.IsDouble() && value->IsSmi())); 4275 int target_index = new_descriptors->GetFieldIndex(i); 4276 if (target_index < inobject) { 4277 inobject_props->set(target_index, *value); 4278 } else { 4279 array->set(target_index - inobject, *value); 4280 } 4281 } 4282 4283 for (int i = old_nof; i < new_nof; i++) { 4284 PropertyDetails details = new_descriptors->GetDetails(i); 4285 if (details.location() != kField) continue; 4286 DCHECK_EQ(kData, details.kind()); 4287 Handle<Object> value; 4288 if (details.representation().IsDouble()) { 4289 value = isolate->factory()->NewMutableHeapNumberWithHoleNaN(); 4290 } else { 4291 value = isolate->factory()->uninitialized_value(); 4292 } 4293 int target_index = new_descriptors->GetFieldIndex(i); 4294 if (target_index < inobject) { 4295 inobject_props->set(target_index, *value); 4296 } else { 4297 array->set(target_index - inobject, *value); 4298 } 4299 } 4300 4301 // From here on we cannot fail and we shouldn't GC anymore. 4302 DisallowHeapAllocation no_allocation; 4303 4304 Heap* heap = isolate->heap(); 4305 4306 int old_instance_size = old_map->instance_size(); 4307 4308 heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation); 4309 4310 // Copy (real) inobject properties. If necessary, stop at number_of_fields to 4311 // avoid overwriting |one_pointer_filler_map|. 4312 int limit = Min(inobject, number_of_fields); 4313 for (int i = 0; i < limit; i++) { 4314 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); 4315 Object* value = inobject_props->get(i); 4316 // Can't use JSObject::FastPropertyAtPut() because proper map was not set 4317 // yet. 4318 if (new_map->IsUnboxedDoubleField(index)) { 4319 DCHECK(value->IsMutableHeapNumber()); 4320 // Ensure that all bits of the double value are preserved. 4321 object->RawFastDoublePropertyAsBitsAtPut( 4322 index, MutableHeapNumber::cast(value)->value_as_bits()); 4323 if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) { 4324 // Transition from tagged to untagged slot. 4325 heap->ClearRecordedSlot(*object, 4326 HeapObject::RawField(*object, index.offset())); 4327 } else { 4328 DCHECK(!heap->HasRecordedSlot( 4329 *object, HeapObject::RawField(*object, index.offset()))); 4330 } 4331 } else { 4332 object->RawFastPropertyAtPut(index, value); 4333 } 4334 } 4335 4336 object->SetProperties(*array); 4337 4338 // Create filler object past the new instance size. 4339 int new_instance_size = new_map->instance_size(); 4340 int instance_size_delta = old_instance_size - new_instance_size; 4341 DCHECK_GE(instance_size_delta, 0); 4342 4343 if (instance_size_delta > 0) { 4344 Address address = object->address(); 4345 heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta, 4346 ClearRecordedSlots::kYes); 4347 } 4348 4349 // We are storing the new map using release store after creating a filler for 4350 // the left-over space to avoid races with the sweeper thread. 4351 object->synchronized_set_map(*new_map); 4352 } 4353 4354 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map, 4355 int expected_additional_properties) { 4356 // The global object is always normalized. 4357 DCHECK(!object->IsJSGlobalObject()); 4358 // JSGlobalProxy must never be normalized 4359 DCHECK(!object->IsJSGlobalProxy()); 4360 4361 DCHECK_IMPLIES(new_map->is_prototype_map(), 4362 Map::IsPrototypeChainInvalidated(*new_map)); 4363 4364 Isolate* isolate = object->GetIsolate(); 4365 HandleScope scope(isolate); 4366 Handle<Map> map(object->map(), isolate); 4367 4368 // Allocate new content. 4369 int real_size = map->NumberOfOwnDescriptors(); 4370 int property_count = real_size; 4371 if (expected_additional_properties > 0) { 4372 property_count += expected_additional_properties; 4373 } else { 4374 // Make space for two more properties. 4375 property_count += NameDictionary::kInitialCapacity; 4376 } 4377 Handle<NameDictionary> dictionary = 4378 NameDictionary::New(isolate, property_count); 4379 4380 Handle<DescriptorArray> descs(map->instance_descriptors(), isolate); 4381 for (int i = 0; i < real_size; i++) { 4382 PropertyDetails details = descs->GetDetails(i); 4383 Handle<Name> key(descs->GetKey(i), isolate); 4384 Handle<Object> value; 4385 if (details.location() == kField) { 4386 FieldIndex index = FieldIndex::ForDescriptor(*map, i); 4387 if (details.kind() == kData) { 4388 if (object->IsUnboxedDoubleField(index)) { 4389 double old_value = object->RawFastDoublePropertyAt(index); 4390 value = isolate->factory()->NewHeapNumber(old_value); 4391 } else { 4392 value = handle(object->RawFastPropertyAt(index), isolate); 4393 if (details.representation().IsDouble()) { 4394 DCHECK(value->IsMutableHeapNumber()); 4395 double old_value = Handle<MutableHeapNumber>::cast(value)->value(); 4396 value = isolate->factory()->NewHeapNumber(old_value); 4397 } 4398 } 4399 } else { 4400 DCHECK_EQ(kAccessor, details.kind()); 4401 value = handle(object->RawFastPropertyAt(index), isolate); 4402 } 4403 4404 } else { 4405 DCHECK_EQ(kDescriptor, details.location()); 4406 value = handle(descs->GetStrongValue(i), isolate); 4407 } 4408 DCHECK(!value.is_null()); 4409 PropertyDetails d(details.kind(), details.attributes(), 4410 PropertyCellType::kNoCell); 4411 dictionary = NameDictionary::Add(isolate, dictionary, key, value, d); 4412 } 4413 4414 // Copy the next enumeration index from instance descriptor. 4415 dictionary->SetNextEnumerationIndex(real_size + 1); 4416 4417 // From here on we cannot fail and we shouldn't GC anymore. 4418 DisallowHeapAllocation no_allocation; 4419 4420 Heap* heap = isolate->heap(); 4421 int old_instance_size = map->instance_size(); 4422 heap->NotifyObjectLayoutChange(*object, old_instance_size, no_allocation); 4423 4424 // Resize the object in the heap if necessary. 4425 int new_instance_size = new_map->instance_size(); 4426 int instance_size_delta = old_instance_size - new_instance_size; 4427 DCHECK_GE(instance_size_delta, 0); 4428 4429 if (instance_size_delta > 0) { 4430 heap->CreateFillerObjectAt(object->address() + new_instance_size, 4431 instance_size_delta, ClearRecordedSlots::kYes); 4432 } 4433 4434 // We are storing the new map using release store after creating a filler for 4435 // the left-over space to avoid races with the sweeper thread. 4436 object->synchronized_set_map(*new_map); 4437 4438 object->SetProperties(*dictionary); 4439 4440 // Ensure that in-object space of slow-mode object does not contain random 4441 // garbage. 4442 int inobject_properties = new_map->GetInObjectProperties(); 4443 if (inobject_properties) { 4444 Heap* heap = isolate->heap(); 4445 heap->ClearRecordedSlotRange( 4446 object->address() + map->GetInObjectPropertyOffset(0), 4447 object->address() + new_instance_size); 4448 4449 for (int i = 0; i < inobject_properties; i++) { 4450 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); 4451 object->RawFastPropertyAtPut(index, Smi::kZero); 4452 } 4453 } 4454 4455 isolate->counters()->props_to_dictionary()->Increment(); 4456 4457 #ifdef DEBUG 4458 if (FLAG_trace_normalization) { 4459 StdoutStream os; 4460 os << "Object properties have been normalized:\n"; 4461 object->Print(os); 4462 } 4463 #endif 4464 } 4465 4466 } // namespace 4467 4468 // static 4469 void JSObject::NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map, 4470 Isolate* isolate) { 4471 if (!old_map->is_prototype_map()) return; 4472 4473 InvalidatePrototypeChains(*old_map); 4474 4475 // If the map was registered with its prototype before, ensure that it 4476 // registers with its new prototype now. This preserves the invariant that 4477 // when a map on a prototype chain is registered with its prototype, then 4478 // all prototypes further up the chain are also registered with their 4479 // respective prototypes. 4480 UpdatePrototypeUserRegistration(old_map, new_map, isolate); 4481 } 4482 4483 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, 4484 int expected_additional_properties) { 4485 if (object->map() == *new_map) return; 4486 Handle<Map> old_map(object->map(), object->GetIsolate()); 4487 NotifyMapChange(old_map, new_map, object->GetIsolate()); 4488 4489 if (old_map->is_dictionary_map()) { 4490 // For slow-to-fast migrations JSObject::MigrateSlowToFast() 4491 // must be used instead. 4492 CHECK(new_map->is_dictionary_map()); 4493 4494 // Slow-to-slow migration is trivial. 4495 object->synchronized_set_map(*new_map); 4496 } else if (!new_map->is_dictionary_map()) { 4497 MigrateFastToFast(object, new_map); 4498 if (old_map->is_prototype_map()) { 4499 DCHECK(!old_map->is_stable()); 4500 DCHECK(new_map->is_stable()); 4501 DCHECK(new_map->owns_descriptors()); 4502 DCHECK(old_map->owns_descriptors()); 4503 // Transfer ownership to the new map. Keep the descriptor pointer of the 4504 // old map intact because the concurrent marker might be iterating the 4505 // object with the old map. 4506 old_map->set_owns_descriptors(false); 4507 DCHECK(old_map->is_abandoned_prototype_map()); 4508 // Ensure that no transition was inserted for prototype migrations. 4509 DCHECK_EQ(0, TransitionsAccessor(object->GetIsolate(), old_map) 4510 .NumberOfTransitions()); 4511 DCHECK(new_map->GetBackPointer()->IsUndefined()); 4512 DCHECK(object->map() != *old_map); 4513 } 4514 } else { 4515 MigrateFastToSlow(object, new_map, expected_additional_properties); 4516 } 4517 4518 // Careful: Don't allocate here! 4519 // For some callers of this method, |object| might be in an inconsistent 4520 // state now: the new map might have a new elements_kind, but the object's 4521 // elements pointer hasn't been updated yet. Callers will fix this, but in 4522 // the meantime, (indirectly) calling JSObjectVerify() must be avoided. 4523 // When adding code here, add a DisallowHeapAllocation too. 4524 } 4525 4526 void JSObject::ForceSetPrototype(Handle<JSObject> object, 4527 Handle<Object> proto) { 4528 // object.__proto__ = proto; 4529 Handle<Map> old_map = Handle<Map>(object->map(), object->GetIsolate()); 4530 Handle<Map> new_map = 4531 Map::Copy(object->GetIsolate(), old_map, "ForceSetPrototype"); 4532 Map::SetPrototype(object->GetIsolate(), new_map, proto); 4533 JSObject::MigrateToMap(object, new_map); 4534 } 4535 4536 int Map::NumberOfFields() const { 4537 DescriptorArray* descriptors = instance_descriptors(); 4538 int result = 0; 4539 for (int i = 0; i < NumberOfOwnDescriptors(); i++) { 4540 if (descriptors->GetDetails(i).location() == kField) result++; 4541 } 4542 return result; 4543 } 4544 4545 bool Map::HasOutOfObjectProperties() const { 4546 return GetInObjectProperties() < NumberOfFields(); 4547 } 4548 4549 void DescriptorArray::GeneralizeAllFields() { 4550 int length = number_of_descriptors(); 4551 for (int i = 0; i < length; i++) { 4552 PropertyDetails details = GetDetails(i); 4553 details = details.CopyWithRepresentation(Representation::Tagged()); 4554 if (details.location() == kField) { 4555 DCHECK_EQ(kData, details.kind()); 4556 details = details.CopyWithConstness(PropertyConstness::kMutable); 4557 SetValue(i, FieldType::Any()); 4558 } 4559 set(ToDetailsIndex(i), MaybeObject::FromObject(details.AsSmi())); 4560 } 4561 } 4562 4563 Handle<Map> Map::CopyGeneralizeAllFields(Isolate* isolate, Handle<Map> map, 4564 ElementsKind elements_kind, 4565 int modify_index, PropertyKind kind, 4566 PropertyAttributes attributes, 4567 const char* reason) { 4568 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate); 4569 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 4570 Handle<DescriptorArray> descriptors = DescriptorArray::CopyUpTo( 4571 isolate, old_descriptors, number_of_own_descriptors); 4572 descriptors->GeneralizeAllFields(); 4573 4574 Handle<LayoutDescriptor> new_layout_descriptor( 4575 LayoutDescriptor::FastPointerLayout(), isolate); 4576 Handle<Map> new_map = CopyReplaceDescriptors( 4577 isolate, map, descriptors, new_layout_descriptor, OMIT_TRANSITION, 4578 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION); 4579 4580 // Unless the instance is being migrated, ensure that modify_index is a field. 4581 if (modify_index >= 0) { 4582 PropertyDetails details = descriptors->GetDetails(modify_index); 4583 if (details.constness() != PropertyConstness::kMutable || 4584 details.location() != kField || details.attributes() != attributes) { 4585 int field_index = details.location() == kField 4586 ? details.field_index() 4587 : new_map->NumberOfFields(); 4588 Descriptor d = Descriptor::DataField( 4589 isolate, handle(descriptors->GetKey(modify_index), isolate), 4590 field_index, attributes, Representation::Tagged()); 4591 descriptors->Replace(modify_index, &d); 4592 if (details.location() != kField) { 4593 new_map->AccountAddedPropertyField(); 4594 } 4595 } else { 4596 DCHECK(details.attributes() == attributes); 4597 } 4598 4599 if (FLAG_trace_generalization) { 4600 MaybeHandle<FieldType> field_type = FieldType::None(isolate); 4601 if (details.location() == kField) { 4602 field_type = handle( 4603 map->instance_descriptors()->GetFieldType(modify_index), isolate); 4604 } 4605 map->PrintGeneralization( 4606 isolate, stdout, reason, modify_index, 4607 new_map->NumberOfOwnDescriptors(), new_map->NumberOfOwnDescriptors(), 4608 details.location() == kDescriptor, details.representation(), 4609 Representation::Tagged(), field_type, MaybeHandle<Object>(), 4610 FieldType::Any(isolate), MaybeHandle<Object>()); 4611 } 4612 } 4613 new_map->set_elements_kind(elements_kind); 4614 return new_map; 4615 } 4616 4617 void Map::DeprecateTransitionTree(Isolate* isolate) { 4618 if (is_deprecated()) return; 4619 DisallowHeapAllocation no_gc; 4620 TransitionsAccessor transitions(isolate, this, &no_gc); 4621 int num_transitions = transitions.NumberOfTransitions(); 4622 for (int i = 0; i < num_transitions; ++i) { 4623 transitions.GetTarget(i)->DeprecateTransitionTree(isolate); 4624 } 4625 DCHECK(!constructor_or_backpointer()->IsFunctionTemplateInfo()); 4626 set_is_deprecated(true); 4627 if (FLAG_trace_maps) { 4628 LOG(isolate, MapEvent("Deprecate", this, nullptr)); 4629 } 4630 dependent_code()->DeoptimizeDependentCodeGroup( 4631 isolate, DependentCode::kTransitionGroup); 4632 NotifyLeafMapLayoutChange(isolate); 4633 } 4634 4635 4636 // Installs |new_descriptors| over the current instance_descriptors to ensure 4637 // proper sharing of descriptor arrays. 4638 void Map::ReplaceDescriptors(Isolate* isolate, DescriptorArray* new_descriptors, 4639 LayoutDescriptor* new_layout_descriptor) { 4640 // Don't overwrite the empty descriptor array or initial map's descriptors. 4641 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) { 4642 return; 4643 } 4644 4645 DescriptorArray* to_replace = instance_descriptors(); 4646 // Replace descriptors by new_descriptors in all maps that share it. The old 4647 // descriptors will not be trimmed in the mark-compactor, we need to mark 4648 // all its elements. 4649 MarkingBarrierForElements(isolate->heap(), to_replace); 4650 Map* current = this; 4651 while (current->instance_descriptors() == to_replace) { 4652 Object* next = current->GetBackPointer(); 4653 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map. 4654 current->SetEnumLength(kInvalidEnumCacheSentinel); 4655 current->UpdateDescriptors(new_descriptors, new_layout_descriptor); 4656 current = Map::cast(next); 4657 } 4658 set_owns_descriptors(false); 4659 } 4660 4661 Map* Map::FindRootMap(Isolate* isolate) const { 4662 const Map* result = this; 4663 while (true) { 4664 Object* back = result->GetBackPointer(); 4665 if (back->IsUndefined(isolate)) { 4666 // Initial map always owns descriptors and doesn't have unused entries 4667 // in the descriptor array. 4668 DCHECK(result->owns_descriptors()); 4669 DCHECK_EQ(result->NumberOfOwnDescriptors(), 4670 result->instance_descriptors()->number_of_descriptors()); 4671 return const_cast<Map*>(result); 4672 } 4673 result = Map::cast(back); 4674 } 4675 } 4676 4677 Map* Map::FindFieldOwner(Isolate* isolate, int descriptor) const { 4678 DisallowHeapAllocation no_allocation; 4679 DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location()); 4680 const Map* result = this; 4681 while (true) { 4682 Object* back = result->GetBackPointer(); 4683 if (back->IsUndefined(isolate)) break; 4684 const Map* parent = Map::cast(back); 4685 if (parent->NumberOfOwnDescriptors() <= descriptor) break; 4686 result = parent; 4687 } 4688 return const_cast<Map*>(result); 4689 } 4690 4691 void Map::UpdateFieldType(Isolate* isolate, int descriptor, Handle<Name> name, 4692 PropertyConstness new_constness, 4693 Representation new_representation, 4694 MaybeObjectHandle new_wrapped_type) { 4695 DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakHeapObject()); 4696 // We store raw pointers in the queue, so no allocations are allowed. 4697 DisallowHeapAllocation no_allocation; 4698 PropertyDetails details = instance_descriptors()->GetDetails(descriptor); 4699 if (details.location() != kField) return; 4700 DCHECK_EQ(kData, details.kind()); 4701 4702 Zone zone(isolate->allocator(), ZONE_NAME); 4703 ZoneQueue<Map*> backlog(&zone); 4704 backlog.push(this); 4705 4706 while (!backlog.empty()) { 4707 Map* current = backlog.front(); 4708 backlog.pop(); 4709 4710 TransitionsAccessor transitions(isolate, current, &no_allocation); 4711 int num_transitions = transitions.NumberOfTransitions(); 4712 for (int i = 0; i < num_transitions; ++i) { 4713 Map* target = transitions.GetTarget(i); 4714 backlog.push(target); 4715 } 4716 DescriptorArray* descriptors = current->instance_descriptors(); 4717 PropertyDetails details = descriptors->GetDetails(descriptor); 4718 4719 // Currently constness change implies map change. 4720 DCHECK_IMPLIES(new_constness != details.constness(), 4721 FLAG_modify_map_inplace); 4722 4723 // It is allowed to change representation here only from None to something. 4724 DCHECK(details.representation().Equals(new_representation) || 4725 details.representation().IsNone()); 4726 4727 // Skip if already updated the shared descriptor. 4728 if ((FLAG_modify_map_inplace && new_constness != details.constness()) || 4729 descriptors->GetFieldType(descriptor) != *new_wrapped_type.object()) { 4730 DCHECK_IMPLIES(!FLAG_track_constant_fields, 4731 new_constness == PropertyConstness::kMutable); 4732 Descriptor d = Descriptor::DataField( 4733 name, descriptors->GetFieldIndex(descriptor), details.attributes(), 4734 new_constness, new_representation, new_wrapped_type); 4735 descriptors->Replace(descriptor, &d); 4736 } 4737 } 4738 } 4739 4740 bool FieldTypeIsCleared(Representation rep, FieldType* type) { 4741 return type->IsNone() && rep.IsHeapObject(); 4742 } 4743 4744 4745 // static 4746 Handle<FieldType> Map::GeneralizeFieldType(Representation rep1, 4747 Handle<FieldType> type1, 4748 Representation rep2, 4749 Handle<FieldType> type2, 4750 Isolate* isolate) { 4751 // Cleared field types need special treatment. They represent lost knowledge, 4752 // so we must be conservative, so their generalization with any other type 4753 // is "Any". 4754 if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) { 4755 return FieldType::Any(isolate); 4756 } 4757 if (type1->NowIs(type2)) return type2; 4758 if (type2->NowIs(type1)) return type1; 4759 return FieldType::Any(isolate); 4760 } 4761 4762 // static 4763 void Map::GeneralizeField(Isolate* isolate, Handle<Map> map, int modify_index, 4764 PropertyConstness new_constness, 4765 Representation new_representation, 4766 Handle<FieldType> new_field_type) { 4767 // Check if we actually need to generalize the field type at all. 4768 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate); 4769 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); 4770 PropertyConstness old_constness = old_details.constness(); 4771 Representation old_representation = old_details.representation(); 4772 Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index), 4773 isolate); 4774 4775 // Return if the current map is general enough to hold requested constness and 4776 // representation/field type. 4777 if (((FLAG_modify_map_inplace && 4778 IsGeneralizableTo(new_constness, old_constness)) || 4779 (!FLAG_modify_map_inplace && (old_constness == new_constness))) && 4780 old_representation.Equals(new_representation) && 4781 !FieldTypeIsCleared(new_representation, *new_field_type) && 4782 // Checking old_field_type for being cleared is not necessary because 4783 // the NowIs check below would fail anyway in that case. 4784 new_field_type->NowIs(old_field_type)) { 4785 DCHECK(GeneralizeFieldType(old_representation, old_field_type, 4786 new_representation, new_field_type, isolate) 4787 ->NowIs(old_field_type)); 4788 return; 4789 } 4790 4791 // Determine the field owner. 4792 Handle<Map> field_owner(map->FindFieldOwner(isolate, modify_index), isolate); 4793 Handle<DescriptorArray> descriptors(field_owner->instance_descriptors(), 4794 isolate); 4795 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index)); 4796 4797 new_field_type = 4798 Map::GeneralizeFieldType(old_representation, old_field_type, 4799 new_representation, new_field_type, isolate); 4800 if (FLAG_modify_map_inplace) { 4801 new_constness = GeneralizeConstness(old_constness, new_constness); 4802 } 4803 4804 PropertyDetails details = descriptors->GetDetails(modify_index); 4805 Handle<Name> name(descriptors->GetKey(modify_index), isolate); 4806 4807 MaybeObjectHandle wrapped_type(WrapFieldType(isolate, new_field_type)); 4808 field_owner->UpdateFieldType(isolate, modify_index, name, new_constness, 4809 new_representation, wrapped_type); 4810 field_owner->dependent_code()->DeoptimizeDependentCodeGroup( 4811 isolate, DependentCode::kFieldOwnerGroup); 4812 4813 if (FLAG_trace_generalization) { 4814 map->PrintGeneralization( 4815 isolate, stdout, "field type generalization", modify_index, 4816 map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false, 4817 details.representation(), details.representation(), old_field_type, 4818 MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>()); 4819 } 4820 } 4821 4822 // TODO(ishell): remove. 4823 // static 4824 Handle<Map> Map::ReconfigureProperty(Isolate* isolate, Handle<Map> map, 4825 int modify_index, PropertyKind new_kind, 4826 PropertyAttributes new_attributes, 4827 Representation new_representation, 4828 Handle<FieldType> new_field_type) { 4829 DCHECK_EQ(kData, new_kind); // Only kData case is supported. 4830 MapUpdater mu(isolate, map); 4831 return mu.ReconfigureToDataField(modify_index, new_attributes, 4832 PropertyConstness::kConst, 4833 new_representation, new_field_type); 4834 } 4835 4836 // TODO(ishell): remove. 4837 // static 4838 Handle<Map> Map::ReconfigureElementsKind(Isolate* isolate, Handle<Map> map, 4839 ElementsKind new_elements_kind) { 4840 MapUpdater mu(isolate, map); 4841 return mu.ReconfigureElementsKind(new_elements_kind); 4842 } 4843 4844 // Generalize all fields and update the transition tree. 4845 Handle<Map> Map::GeneralizeAllFields(Isolate* isolate, Handle<Map> map) { 4846 Handle<FieldType> any_type = FieldType::Any(isolate); 4847 4848 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 4849 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) { 4850 PropertyDetails details = descriptors->GetDetails(i); 4851 if (details.location() == kField) { 4852 DCHECK_EQ(kData, details.kind()); 4853 MapUpdater mu(isolate, map); 4854 map = mu.ReconfigureToDataField(i, details.attributes(), 4855 PropertyConstness::kMutable, 4856 Representation::Tagged(), any_type); 4857 } 4858 } 4859 return map; 4860 } 4861 4862 4863 // static 4864 MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) { 4865 DisallowHeapAllocation no_allocation; 4866 DisallowDeoptimization no_deoptimization(isolate); 4867 4868 if (!old_map->is_deprecated()) return old_map; 4869 4870 // Check the state of the root map. 4871 Map* root_map = old_map->FindRootMap(isolate); 4872 if (root_map->is_deprecated()) { 4873 JSFunction* constructor = JSFunction::cast(root_map->GetConstructor()); 4874 DCHECK(constructor->has_initial_map()); 4875 DCHECK(constructor->initial_map()->is_dictionary_map()); 4876 if (constructor->initial_map()->elements_kind() != 4877 old_map->elements_kind()) { 4878 return MaybeHandle<Map>(); 4879 } 4880 return handle(constructor->initial_map(), constructor->GetIsolate()); 4881 } 4882 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>(); 4883 4884 ElementsKind from_kind = root_map->elements_kind(); 4885 ElementsKind to_kind = old_map->elements_kind(); 4886 if (from_kind != to_kind) { 4887 // Try to follow existing elements kind transitions. 4888 root_map = root_map->LookupElementsTransitionMap(isolate, to_kind); 4889 if (root_map == nullptr) return MaybeHandle<Map>(); 4890 // From here on, use the map with correct elements kind as root map. 4891 } 4892 Map* new_map = root_map->TryReplayPropertyTransitions(isolate, *old_map); 4893 if (new_map == nullptr) return MaybeHandle<Map>(); 4894 return handle(new_map, isolate); 4895 } 4896 4897 Map* Map::TryReplayPropertyTransitions(Isolate* isolate, Map* old_map) { 4898 DisallowHeapAllocation no_allocation; 4899 DisallowDeoptimization no_deoptimization(isolate); 4900 4901 int root_nof = NumberOfOwnDescriptors(); 4902 4903 int old_nof = old_map->NumberOfOwnDescriptors(); 4904 DescriptorArray* old_descriptors = old_map->instance_descriptors(); 4905 4906 Map* new_map = this; 4907 for (int i = root_nof; i < old_nof; ++i) { 4908 PropertyDetails old_details = old_descriptors->GetDetails(i); 4909 Map* transition = 4910 TransitionsAccessor(isolate, new_map, &no_allocation) 4911 .SearchTransition(old_descriptors->GetKey(i), old_details.kind(), 4912 old_details.attributes()); 4913 if (transition == nullptr) return nullptr; 4914 new_map = transition; 4915 DescriptorArray* new_descriptors = new_map->instance_descriptors(); 4916 4917 PropertyDetails new_details = new_descriptors->GetDetails(i); 4918 DCHECK_EQ(old_details.kind(), new_details.kind()); 4919 DCHECK_EQ(old_details.attributes(), new_details.attributes()); 4920 if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) { 4921 return nullptr; 4922 } 4923 DCHECK(IsGeneralizableTo(old_details.location(), new_details.location())); 4924 if (!old_details.representation().fits_into(new_details.representation())) { 4925 return nullptr; 4926 } 4927 if (new_details.location() == kField) { 4928 if (new_details.kind() == kData) { 4929 FieldType* new_type = new_descriptors->GetFieldType(i); 4930 // Cleared field types need special treatment. They represent lost 4931 // knowledge, so we must first generalize the new_type to "Any". 4932 if (FieldTypeIsCleared(new_details.representation(), new_type)) { 4933 return nullptr; 4934 } 4935 DCHECK_EQ(kData, old_details.kind()); 4936 if (old_details.location() == kField) { 4937 FieldType* old_type = old_descriptors->GetFieldType(i); 4938 if (FieldTypeIsCleared(old_details.representation(), old_type) || 4939 !old_type->NowIs(new_type)) { 4940 return nullptr; 4941 } 4942 } else { 4943 DCHECK_EQ(kDescriptor, old_details.location()); 4944 DCHECK(!FLAG_track_constant_fields); 4945 Object* old_value = old_descriptors->GetStrongValue(i); 4946 if (!new_type->NowContains(old_value)) { 4947 return nullptr; 4948 } 4949 } 4950 4951 } else { 4952 DCHECK_EQ(kAccessor, new_details.kind()); 4953 #ifdef DEBUG 4954 FieldType* new_type = new_descriptors->GetFieldType(i); 4955 DCHECK(new_type->IsAny()); 4956 #endif 4957 UNREACHABLE(); 4958 } 4959 } else { 4960 DCHECK_EQ(kDescriptor, new_details.location()); 4961 if (old_details.location() == kField || 4962 old_descriptors->GetStrongValue(i) != 4963 new_descriptors->GetStrongValue(i)) { 4964 return nullptr; 4965 } 4966 } 4967 } 4968 if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr; 4969 return new_map; 4970 } 4971 4972 4973 // static 4974 Handle<Map> Map::Update(Isolate* isolate, Handle<Map> map) { 4975 if (!map->is_deprecated()) return map; 4976 MapUpdater mu(isolate, map); 4977 return mu.Update(); 4978 } 4979 4980 Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it, 4981 ShouldThrow should_throw, 4982 Handle<Object> value) { 4983 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 4984 return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(), 4985 should_throw, value); 4986 } 4987 4988 MaybeHandle<Object> Object::SetProperty(Isolate* isolate, Handle<Object> object, 4989 Handle<Name> name, Handle<Object> value, 4990 LanguageMode language_mode, 4991 StoreFromKeyed store_mode) { 4992 LookupIterator it(isolate, object, name); 4993 MAYBE_RETURN_NULL(SetProperty(&it, value, language_mode, store_mode)); 4994 return value; 4995 } 4996 4997 4998 Maybe<bool> Object::SetPropertyInternal(LookupIterator* it, 4999 Handle<Object> value, 5000 LanguageMode language_mode, 5001 StoreFromKeyed store_mode, 5002 bool* found) { 5003 it->UpdateProtector(); 5004 DCHECK(it->IsFound()); 5005 ShouldThrow should_throw = 5006 is_sloppy(language_mode) ? kDontThrow : kThrowOnError; 5007 5008 // Make sure that the top context does not change when doing callbacks or 5009 // interceptor calls. 5010 AssertNoContextChange ncc(it->isolate()); 5011 5012 do { 5013 switch (it->state()) { 5014 case LookupIterator::NOT_FOUND: 5015 UNREACHABLE(); 5016 5017 case LookupIterator::ACCESS_CHECK: 5018 if (it->HasAccess()) break; 5019 // Check whether it makes sense to reuse the lookup iterator. Here it 5020 // might still call into setters up the prototype chain. 5021 return JSObject::SetPropertyWithFailedAccessCheck(it, value, 5022 should_throw); 5023 5024 case LookupIterator::JSPROXY: 5025 return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(), 5026 value, it->GetReceiver(), language_mode); 5027 5028 case LookupIterator::INTERCEPTOR: { 5029 if (it->HolderIsReceiverOrHiddenPrototype()) { 5030 Maybe<bool> result = 5031 JSObject::SetPropertyWithInterceptor(it, should_throw, value); 5032 if (result.IsNothing() || result.FromJust()) return result; 5033 } else { 5034 Maybe<PropertyAttributes> maybe_attributes = 5035 JSObject::GetPropertyAttributesWithInterceptor(it); 5036 if (maybe_attributes.IsNothing()) return Nothing<bool>(); 5037 if ((maybe_attributes.FromJust() & READ_ONLY) != 0) { 5038 return WriteToReadOnlyProperty(it, value, should_throw); 5039 } 5040 if (maybe_attributes.FromJust() == ABSENT) break; 5041 *found = false; 5042 return Nothing<bool>(); 5043 } 5044 break; 5045 } 5046 5047 case LookupIterator::ACCESSOR: { 5048 if (it->IsReadOnly()) { 5049 return WriteToReadOnlyProperty(it, value, should_throw); 5050 } 5051 Handle<Object> accessors = it->GetAccessors(); 5052 if (accessors->IsAccessorInfo() && 5053 !it->HolderIsReceiverOrHiddenPrototype() && 5054 AccessorInfo::cast(*accessors)->is_special_data_property()) { 5055 *found = false; 5056 return Nothing<bool>(); 5057 } 5058 return SetPropertyWithAccessor(it, value, should_throw); 5059 } 5060 case LookupIterator::INTEGER_INDEXED_EXOTIC: { 5061 // IntegerIndexedElementSet converts value to a Number/BigInt prior to 5062 // the bounds check. The bounds check has already happened here, but 5063 // perform the possibly effectful ToNumber (or ToBigInt) operation 5064 // anyways. 5065 auto holder = it->GetHolder<JSTypedArray>(); 5066 Handle<Object> throwaway_value; 5067 if (holder->type() == kExternalBigInt64Array || 5068 holder->type() == kExternalBigUint64Array) { 5069 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5070 it->isolate(), throwaway_value, 5071 BigInt::FromObject(it->isolate(), value), Nothing<bool>()); 5072 } else { 5073 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5074 it->isolate(), throwaway_value, 5075 Object::ToNumber(it->isolate(), value), Nothing<bool>()); 5076 } 5077 5078 // FIXME: Throw a TypeError if the holder is neutered here 5079 // (IntegerIndexedElementSpec step 5). 5080 5081 // TODO(verwaest): Per spec, we should return false here (steps 6-9 5082 // in IntegerIndexedElementSpec), resulting in an exception being thrown 5083 // on OOB accesses in strict code. Historically, v8 has not done made 5084 // this change due to uncertainty about web compat. (v8:4901) 5085 return Just(true); 5086 } 5087 5088 case LookupIterator::DATA: 5089 if (it->IsReadOnly()) { 5090 return WriteToReadOnlyProperty(it, value, should_throw); 5091 } 5092 if (it->HolderIsReceiverOrHiddenPrototype()) { 5093 return SetDataProperty(it, value); 5094 } 5095 V8_FALLTHROUGH; 5096 case LookupIterator::TRANSITION: 5097 *found = false; 5098 return Nothing<bool>(); 5099 } 5100 it->Next(); 5101 } while (it->IsFound()); 5102 5103 *found = false; 5104 return Nothing<bool>(); 5105 } 5106 5107 5108 Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value, 5109 LanguageMode language_mode, 5110 StoreFromKeyed store_mode) { 5111 if (it->IsFound()) { 5112 bool found = true; 5113 Maybe<bool> result = 5114 SetPropertyInternal(it, value, language_mode, store_mode, &found); 5115 if (found) return result; 5116 } 5117 5118 // If the receiver is the JSGlobalObject, the store was contextual. In case 5119 // the property did not exist yet on the global object itself, we have to 5120 // throw a reference error in strict mode. In sloppy mode, we continue. 5121 if (is_strict(language_mode) && it->GetReceiver()->IsJSGlobalObject()) { 5122 it->isolate()->Throw(*it->isolate()->factory()->NewReferenceError( 5123 MessageTemplate::kNotDefined, it->name())); 5124 return Nothing<bool>(); 5125 } 5126 5127 ShouldThrow should_throw = 5128 is_sloppy(language_mode) ? kDontThrow : kThrowOnError; 5129 return AddDataProperty(it, value, NONE, should_throw, store_mode); 5130 } 5131 5132 5133 Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, 5134 LanguageMode language_mode, 5135 StoreFromKeyed store_mode) { 5136 Isolate* isolate = it->isolate(); 5137 5138 if (it->IsFound()) { 5139 bool found = true; 5140 Maybe<bool> result = 5141 SetPropertyInternal(it, value, language_mode, store_mode, &found); 5142 if (found) return result; 5143 } 5144 5145 it->UpdateProtector(); 5146 5147 // The property either doesn't exist on the holder or exists there as a data 5148 // property. 5149 5150 ShouldThrow should_throw = 5151 is_sloppy(language_mode) ? kDontThrow : kThrowOnError; 5152 5153 if (!it->GetReceiver()->IsJSReceiver()) { 5154 return WriteToReadOnlyProperty(it, value, should_throw); 5155 } 5156 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 5157 5158 LookupIterator::Configuration c = LookupIterator::OWN; 5159 LookupIterator own_lookup = 5160 it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c) 5161 : LookupIterator(isolate, receiver, it->name(), c); 5162 5163 for (; own_lookup.IsFound(); own_lookup.Next()) { 5164 switch (own_lookup.state()) { 5165 case LookupIterator::ACCESS_CHECK: 5166 if (!own_lookup.HasAccess()) { 5167 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value, 5168 should_throw); 5169 } 5170 break; 5171 5172 case LookupIterator::ACCESSOR: 5173 if (own_lookup.GetAccessors()->IsAccessorInfo()) { 5174 if (own_lookup.IsReadOnly()) { 5175 return WriteToReadOnlyProperty(&own_lookup, value, should_throw); 5176 } 5177 return JSObject::SetPropertyWithAccessor(&own_lookup, value, 5178 should_throw); 5179 } 5180 V8_FALLTHROUGH; 5181 case LookupIterator::INTEGER_INDEXED_EXOTIC: 5182 return RedefineIncompatibleProperty(isolate, it->GetName(), value, 5183 should_throw); 5184 5185 case LookupIterator::DATA: { 5186 if (own_lookup.IsReadOnly()) { 5187 return WriteToReadOnlyProperty(&own_lookup, value, should_throw); 5188 } 5189 return SetDataProperty(&own_lookup, value); 5190 } 5191 5192 case LookupIterator::INTERCEPTOR: 5193 case LookupIterator::JSPROXY: { 5194 PropertyDescriptor desc; 5195 Maybe<bool> owned = 5196 JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc); 5197 MAYBE_RETURN(owned, Nothing<bool>()); 5198 if (!owned.FromJust()) { 5199 return JSReceiver::CreateDataProperty(&own_lookup, value, 5200 should_throw); 5201 } 5202 if (PropertyDescriptor::IsAccessorDescriptor(&desc) || 5203 !desc.writable()) { 5204 return RedefineIncompatibleProperty(isolate, it->GetName(), value, 5205 should_throw); 5206 } 5207 5208 PropertyDescriptor value_desc; 5209 value_desc.set_value(value); 5210 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(), 5211 &value_desc, should_throw); 5212 } 5213 5214 case LookupIterator::NOT_FOUND: 5215 case LookupIterator::TRANSITION: 5216 UNREACHABLE(); 5217 } 5218 } 5219 5220 return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode); 5221 } 5222 5223 Maybe<bool> Object::CannotCreateProperty(Isolate* isolate, 5224 Handle<Object> receiver, 5225 Handle<Object> name, 5226 Handle<Object> value, 5227 ShouldThrow should_throw) { 5228 RETURN_FAILURE( 5229 isolate, should_throw, 5230 NewTypeError(MessageTemplate::kStrictCannotCreateProperty, name, 5231 Object::TypeOf(isolate, receiver), receiver)); 5232 } 5233 5234 5235 Maybe<bool> Object::WriteToReadOnlyProperty(LookupIterator* it, 5236 Handle<Object> value, 5237 ShouldThrow should_throw) { 5238 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), 5239 it->GetName(), value, should_throw); 5240 } 5241 5242 5243 Maybe<bool> Object::WriteToReadOnlyProperty(Isolate* isolate, 5244 Handle<Object> receiver, 5245 Handle<Object> name, 5246 Handle<Object> value, 5247 ShouldThrow should_throw) { 5248 RETURN_FAILURE(isolate, should_throw, 5249 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name, 5250 Object::TypeOf(isolate, receiver), receiver)); 5251 } 5252 5253 5254 Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate, 5255 Handle<Object> name, 5256 Handle<Object> value, 5257 ShouldThrow should_throw) { 5258 RETURN_FAILURE(isolate, should_throw, 5259 NewTypeError(MessageTemplate::kRedefineDisallowed, name)); 5260 } 5261 5262 5263 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { 5264 DCHECK_IMPLIES(it->GetReceiver()->IsJSProxy(), 5265 it->GetName()->IsPrivateField()); 5266 DCHECK_IMPLIES(!it->IsElement() && it->GetName()->IsPrivateField(), 5267 it->state() == LookupIterator::DATA); 5268 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 5269 5270 // Store on the holder which may be hidden behind the receiver. 5271 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); 5272 5273 Handle<Object> to_assign = value; 5274 // Convert the incoming value to a number for storing into typed arrays. 5275 if (it->IsElement() && receiver->IsJSObject() && 5276 JSObject::cast(*receiver)->HasFixedTypedArrayElements()) { 5277 ElementsKind elements_kind = JSObject::cast(*receiver)->GetElementsKind(); 5278 if (elements_kind == BIGINT64_ELEMENTS || 5279 elements_kind == BIGUINT64_ELEMENTS) { 5280 ASSIGN_RETURN_ON_EXCEPTION_VALUE(it->isolate(), to_assign, 5281 BigInt::FromObject(it->isolate(), value), 5282 Nothing<bool>()); 5283 // We have to recheck the length. However, it can only change if the 5284 // underlying buffer was neutered, so just check that. 5285 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) { 5286 return Just(true); 5287 // TODO(neis): According to the spec, this should throw a TypeError. 5288 } 5289 } else if (!value->IsNumber() && !value->IsUndefined(it->isolate())) { 5290 ASSIGN_RETURN_ON_EXCEPTION_VALUE(it->isolate(), to_assign, 5291 Object::ToNumber(it->isolate(), value), 5292 Nothing<bool>()); 5293 // We have to recheck the length. However, it can only change if the 5294 // underlying buffer was neutered, so just check that. 5295 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) { 5296 return Just(true); 5297 // TODO(neis): According to the spec, this should throw a TypeError. 5298 } 5299 } 5300 } 5301 5302 // Possibly migrate to the most up-to-date map that will be able to store 5303 // |value| under it->name(). 5304 it->PrepareForDataProperty(to_assign); 5305 5306 // Write the property value. 5307 it->WriteDataValue(to_assign, false); 5308 5309 #if VERIFY_HEAP 5310 if (FLAG_verify_heap) { 5311 receiver->HeapObjectVerify(it->isolate()); 5312 } 5313 #endif 5314 return Just(true); 5315 } 5316 5317 5318 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, 5319 PropertyAttributes attributes, 5320 ShouldThrow should_throw, 5321 StoreFromKeyed store_mode) { 5322 if (!it->GetReceiver()->IsJSReceiver()) { 5323 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(), 5324 value, should_throw); 5325 } 5326 5327 // Private symbols should be installed on JSProxy using 5328 // JSProxy::SetPrivateSymbol. 5329 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate() && 5330 !it->GetName()->IsPrivateField()) { 5331 RETURN_FAILURE(it->isolate(), should_throw, 5332 NewTypeError(MessageTemplate::kProxyPrivate)); 5333 } 5334 5335 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state()); 5336 5337 Handle<JSReceiver> receiver = it->GetStoreTarget<JSReceiver>(); 5338 DCHECK_IMPLIES(receiver->IsJSProxy(), it->GetName()->IsPrivateField()); 5339 DCHECK_IMPLIES(receiver->IsJSProxy(), 5340 it->state() == LookupIterator::NOT_FOUND); 5341 5342 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) 5343 // instead. If the prototype is Null, the proxy is detached. 5344 if (receiver->IsJSGlobalProxy()) return Just(true); 5345 5346 Isolate* isolate = it->isolate(); 5347 5348 if (it->ExtendingNonExtensible(receiver)) { 5349 RETURN_FAILURE( 5350 isolate, should_throw, 5351 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName())); 5352 } 5353 5354 if (it->IsElement()) { 5355 if (receiver->IsJSArray()) { 5356 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 5357 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) { 5358 RETURN_FAILURE(isolate, should_throw, 5359 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, 5360 isolate->factory()->length_string(), 5361 Object::TypeOf(isolate, array), array)); 5362 } 5363 5364 if (FLAG_trace_external_array_abuse && 5365 array->HasFixedTypedArrayElements()) { 5366 CheckArrayAbuse(array, "typed elements write", it->index(), true); 5367 } 5368 5369 if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) { 5370 CheckArrayAbuse(array, "elements write", it->index(), false); 5371 } 5372 } 5373 5374 Handle<JSObject> receiver_obj = Handle<JSObject>::cast(receiver); 5375 JSObject::AddDataElement(receiver_obj, it->index(), value, attributes); 5376 JSObject::ValidateElements(*receiver_obj); 5377 return Just(true); 5378 } else { 5379 it->UpdateProtector(); 5380 // Migrate to the most up-to-date map that will be able to store |value| 5381 // under it->name() with |attributes|. 5382 it->PrepareTransitionToDataProperty(receiver, value, attributes, 5383 store_mode); 5384 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); 5385 it->ApplyTransitionToDataProperty(receiver); 5386 5387 // Write the property value. 5388 it->WriteDataValue(value, true); 5389 5390 #if VERIFY_HEAP 5391 if (FLAG_verify_heap) { 5392 receiver->HeapObjectVerify(isolate); 5393 } 5394 #endif 5395 } 5396 5397 return Just(true); 5398 } 5399 5400 void Map::EnsureDescriptorSlack(Isolate* isolate, Handle<Map> map, int slack) { 5401 // Only supports adding slack to owned descriptors. 5402 DCHECK(map->owns_descriptors()); 5403 5404 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 5405 int old_size = map->NumberOfOwnDescriptors(); 5406 if (slack <= descriptors->NumberOfSlackDescriptors()) return; 5407 5408 Handle<DescriptorArray> new_descriptors = 5409 DescriptorArray::CopyUpTo(isolate, descriptors, old_size, slack); 5410 5411 DisallowHeapAllocation no_allocation; 5412 // The descriptors are still the same, so keep the layout descriptor. 5413 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor(); 5414 5415 if (old_size == 0) { 5416 map->UpdateDescriptors(*new_descriptors, layout_descriptor); 5417 return; 5418 } 5419 5420 // If the source descriptors had an enum cache we copy it. This ensures 5421 // that the maps to which we push the new descriptor array back can rely 5422 // on a cache always being available once it is set. If the map has more 5423 // enumerated descriptors than available in the original cache, the cache 5424 // will be lazily replaced by the extended cache when needed. 5425 new_descriptors->CopyEnumCacheFrom(*descriptors); 5426 5427 // Replace descriptors by new_descriptors in all maps that share it. The old 5428 // descriptors will not be trimmed in the mark-compactor, we need to mark 5429 // all its elements. 5430 MarkingBarrierForElements(isolate->heap(), *descriptors); 5431 5432 Map* current = *map; 5433 while (current->instance_descriptors() == *descriptors) { 5434 Object* next = current->GetBackPointer(); 5435 if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map. 5436 current->UpdateDescriptors(*new_descriptors, layout_descriptor); 5437 current = Map::cast(next); 5438 } 5439 map->UpdateDescriptors(*new_descriptors, layout_descriptor); 5440 } 5441 5442 // static 5443 Handle<Map> Map::GetObjectCreateMap(Isolate* isolate, 5444 Handle<HeapObject> prototype) { 5445 Handle<Map> map(isolate->native_context()->object_function()->initial_map(), 5446 isolate); 5447 if (map->prototype() == *prototype) return map; 5448 if (prototype->IsNull(isolate)) { 5449 return isolate->slow_object_with_null_prototype_map(); 5450 } 5451 if (prototype->IsJSObject()) { 5452 Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype); 5453 if (!js_prototype->map()->is_prototype_map()) { 5454 JSObject::OptimizeAsPrototype(js_prototype); 5455 } 5456 Handle<PrototypeInfo> info = 5457 Map::GetOrCreatePrototypeInfo(js_prototype, isolate); 5458 // TODO(verwaest): Use inobject slack tracking for this map. 5459 if (info->HasObjectCreateMap()) { 5460 map = handle(info->ObjectCreateMap(), isolate); 5461 } else { 5462 map = Map::CopyInitialMap(isolate, map); 5463 Map::SetPrototype(isolate, map, prototype); 5464 PrototypeInfo::SetObjectCreateMap(info, map); 5465 } 5466 return map; 5467 } 5468 5469 return Map::TransitionToPrototype(isolate, map, prototype); 5470 } 5471 5472 // static 5473 MaybeHandle<Map> Map::TryGetObjectCreateMap(Isolate* isolate, 5474 Handle<HeapObject> prototype) { 5475 Handle<Map> map(isolate->native_context()->object_function()->initial_map(), 5476 isolate); 5477 if (map->prototype() == *prototype) return map; 5478 if (prototype->IsNull(isolate)) { 5479 return isolate->slow_object_with_null_prototype_map(); 5480 } 5481 if (!prototype->IsJSObject()) return MaybeHandle<Map>(); 5482 Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype); 5483 if (!js_prototype->map()->is_prototype_map()) return MaybeHandle<Map>(); 5484 Handle<PrototypeInfo> info = 5485 Map::GetOrCreatePrototypeInfo(js_prototype, isolate); 5486 if (!info->HasObjectCreateMap()) return MaybeHandle<Map>(); 5487 return handle(info->ObjectCreateMap(), isolate); 5488 } 5489 5490 template <class T> 5491 static int AppendUniqueCallbacks(Isolate* isolate, 5492 Handle<TemplateList> callbacks, 5493 Handle<typename T::Array> array, 5494 int valid_descriptors) { 5495 int nof_callbacks = callbacks->length(); 5496 5497 // Fill in new callback descriptors. Process the callbacks from 5498 // back to front so that the last callback with a given name takes 5499 // precedence over previously added callbacks with that name. 5500 for (int i = nof_callbacks - 1; i >= 0; i--) { 5501 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)), isolate); 5502 Handle<Name> key(Name::cast(entry->name()), isolate); 5503 DCHECK(key->IsUniqueName()); 5504 // Check if a descriptor with this name already exists before writing. 5505 if (!T::Contains(key, entry, valid_descriptors, array)) { 5506 T::Insert(key, entry, valid_descriptors, array); 5507 valid_descriptors++; 5508 } 5509 } 5510 5511 return valid_descriptors; 5512 } 5513 5514 struct FixedArrayAppender { 5515 typedef FixedArray Array; 5516 static bool Contains(Handle<Name> key, 5517 Handle<AccessorInfo> entry, 5518 int valid_descriptors, 5519 Handle<FixedArray> array) { 5520 for (int i = 0; i < valid_descriptors; i++) { 5521 if (*key == AccessorInfo::cast(array->get(i))->name()) return true; 5522 } 5523 return false; 5524 } 5525 static void Insert(Handle<Name> key, 5526 Handle<AccessorInfo> entry, 5527 int valid_descriptors, 5528 Handle<FixedArray> array) { 5529 DisallowHeapAllocation no_gc; 5530 array->set(valid_descriptors, *entry); 5531 } 5532 }; 5533 5534 int AccessorInfo::AppendUnique(Isolate* isolate, Handle<Object> descriptors, 5535 Handle<FixedArray> array, 5536 int valid_descriptors) { 5537 Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors); 5538 DCHECK_GE(array->length(), callbacks->length() + valid_descriptors); 5539 return AppendUniqueCallbacks<FixedArrayAppender>(isolate, callbacks, array, 5540 valid_descriptors); 5541 } 5542 5543 static bool ContainsMap(MapHandles const& maps, Map* map) { 5544 DCHECK_NOT_NULL(map); 5545 for (Handle<Map> current : maps) { 5546 if (!current.is_null() && *current == map) return true; 5547 } 5548 return false; 5549 } 5550 5551 Map* Map::FindElementsKindTransitionedMap(Isolate* isolate, 5552 MapHandles const& candidates) { 5553 DisallowHeapAllocation no_allocation; 5554 DisallowDeoptimization no_deoptimization(isolate); 5555 5556 if (is_prototype_map()) return nullptr; 5557 5558 ElementsKind kind = elements_kind(); 5559 bool packed = IsFastPackedElementsKind(kind); 5560 5561 Map* transition = nullptr; 5562 if (IsTransitionableFastElementsKind(kind)) { 5563 // Check the state of the root map. 5564 Map* root_map = FindRootMap(isolate); 5565 if (!EquivalentToForElementsKindTransition(root_map)) return nullptr; 5566 root_map = root_map->LookupElementsTransitionMap(isolate, kind); 5567 DCHECK_NOT_NULL(root_map); 5568 // Starting from the next existing elements kind transition try to 5569 // replay the property transitions that does not involve instance rewriting 5570 // (ElementsTransitionAndStoreStub does not support that). 5571 for (root_map = root_map->ElementsTransitionMap(); 5572 root_map != nullptr && root_map->has_fast_elements(); 5573 root_map = root_map->ElementsTransitionMap()) { 5574 Map* current = root_map->TryReplayPropertyTransitions(isolate, this); 5575 if (current == nullptr) continue; 5576 if (InstancesNeedRewriting(current)) continue; 5577 5578 if (ContainsMap(candidates, current) && 5579 (packed || !IsFastPackedElementsKind(current->elements_kind()))) { 5580 transition = current; 5581 packed = packed && IsFastPackedElementsKind(current->elements_kind()); 5582 } 5583 } 5584 } 5585 return transition; 5586 } 5587 5588 static Map* FindClosestElementsTransition(Isolate* isolate, Map* map, 5589 ElementsKind to_kind) { 5590 // Ensure we are requested to search elements kind transition "near the root". 5591 DCHECK_EQ(map->FindRootMap(isolate)->NumberOfOwnDescriptors(), 5592 map->NumberOfOwnDescriptors()); 5593 Map* current_map = map; 5594 5595 ElementsKind kind = map->elements_kind(); 5596 while (kind != to_kind) { 5597 Map* next_map = current_map->ElementsTransitionMap(); 5598 if (next_map == nullptr) return current_map; 5599 kind = next_map->elements_kind(); 5600 current_map = next_map; 5601 } 5602 5603 DCHECK_EQ(to_kind, current_map->elements_kind()); 5604 return current_map; 5605 } 5606 5607 Map* Map::LookupElementsTransitionMap(Isolate* isolate, ElementsKind to_kind) { 5608 Map* to_map = FindClosestElementsTransition(isolate, this, to_kind); 5609 if (to_map->elements_kind() == to_kind) return to_map; 5610 return nullptr; 5611 } 5612 5613 bool Map::IsMapInArrayPrototypeChain(Isolate* isolate) const { 5614 if (isolate->initial_array_prototype()->map() == this) { 5615 return true; 5616 } 5617 5618 if (isolate->initial_object_prototype()->map() == this) { 5619 return true; 5620 } 5621 5622 return false; 5623 } 5624 5625 static Handle<Map> AddMissingElementsTransitions(Isolate* isolate, 5626 Handle<Map> map, 5627 ElementsKind to_kind) { 5628 DCHECK(IsTransitionElementsKind(map->elements_kind())); 5629 5630 Handle<Map> current_map = map; 5631 5632 ElementsKind kind = map->elements_kind(); 5633 TransitionFlag flag; 5634 if (map->is_prototype_map()) { 5635 flag = OMIT_TRANSITION; 5636 } else { 5637 flag = INSERT_TRANSITION; 5638 if (IsFastElementsKind(kind)) { 5639 while (kind != to_kind && !IsTerminalElementsKind(kind)) { 5640 kind = GetNextTransitionElementsKind(kind); 5641 current_map = Map::CopyAsElementsKind(isolate, current_map, kind, flag); 5642 } 5643 } 5644 } 5645 5646 // In case we are exiting the fast elements kind system, just add the map in 5647 // the end. 5648 if (kind != to_kind) { 5649 current_map = Map::CopyAsElementsKind(isolate, current_map, to_kind, flag); 5650 } 5651 5652 DCHECK(current_map->elements_kind() == to_kind); 5653 return current_map; 5654 } 5655 5656 Handle<Map> Map::TransitionElementsTo(Isolate* isolate, Handle<Map> map, 5657 ElementsKind to_kind) { 5658 ElementsKind from_kind = map->elements_kind(); 5659 if (from_kind == to_kind) return map; 5660 5661 Context* native_context = isolate->context()->native_context(); 5662 if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) { 5663 if (*map == native_context->fast_aliased_arguments_map()) { 5664 DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); 5665 return handle(native_context->slow_aliased_arguments_map(), isolate); 5666 } 5667 } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) { 5668 if (*map == native_context->slow_aliased_arguments_map()) { 5669 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind); 5670 return handle(native_context->fast_aliased_arguments_map(), isolate); 5671 } 5672 } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) { 5673 // Reuse map transitions for JSArrays. 5674 DisallowHeapAllocation no_gc; 5675 if (native_context->GetInitialJSArrayMap(from_kind) == *map) { 5676 Object* maybe_transitioned_map = 5677 native_context->get(Context::ArrayMapIndex(to_kind)); 5678 if (maybe_transitioned_map->IsMap()) { 5679 return handle(Map::cast(maybe_transitioned_map), isolate); 5680 } 5681 } 5682 } 5683 5684 DCHECK(!map->IsUndefined(isolate)); 5685 // Check if we can go back in the elements kind transition chain. 5686 if (IsHoleyElementsKind(from_kind) && 5687 to_kind == GetPackedElementsKind(from_kind) && 5688 map->GetBackPointer()->IsMap() && 5689 Map::cast(map->GetBackPointer())->elements_kind() == to_kind) { 5690 return handle(Map::cast(map->GetBackPointer()), isolate); 5691 } 5692 5693 bool allow_store_transition = IsTransitionElementsKind(from_kind); 5694 // Only store fast element maps in ascending generality. 5695 if (IsFastElementsKind(to_kind)) { 5696 allow_store_transition = 5697 allow_store_transition && IsTransitionableFastElementsKind(from_kind) && 5698 IsMoreGeneralElementsKindTransition(from_kind, to_kind); 5699 } 5700 5701 if (!allow_store_transition) { 5702 return Map::CopyAsElementsKind(isolate, map, to_kind, OMIT_TRANSITION); 5703 } 5704 5705 return Map::ReconfigureElementsKind(isolate, map, to_kind); 5706 } 5707 5708 5709 // static 5710 Handle<Map> Map::AsElementsKind(Isolate* isolate, Handle<Map> map, 5711 ElementsKind kind) { 5712 Handle<Map> closest_map(FindClosestElementsTransition(isolate, *map, kind), 5713 isolate); 5714 5715 if (closest_map->elements_kind() == kind) { 5716 return closest_map; 5717 } 5718 5719 return AddMissingElementsTransitions(isolate, closest_map, kind); 5720 } 5721 5722 5723 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, 5724 ElementsKind to_kind) { 5725 Handle<Map> map(object->map(), object->GetIsolate()); 5726 return Map::TransitionElementsTo(object->GetIsolate(), map, to_kind); 5727 } 5728 5729 5730 void JSProxy::Revoke(Handle<JSProxy> proxy) { 5731 Isolate* isolate = proxy->GetIsolate(); 5732 // ES#sec-proxy-revocation-functions 5733 if (!proxy->IsRevoked()) { 5734 // 5. Set p.[[ProxyTarget]] to null. 5735 proxy->set_target(ReadOnlyRoots(isolate).null_value()); 5736 // 6. Set p.[[ProxyHandler]] to null. 5737 proxy->set_handler(ReadOnlyRoots(isolate).null_value()); 5738 } 5739 DCHECK(proxy->IsRevoked()); 5740 } 5741 5742 // static 5743 Maybe<bool> JSProxy::IsArray(Handle<JSProxy> proxy) { 5744 Isolate* isolate = proxy->GetIsolate(); 5745 Handle<JSReceiver> object = Handle<JSReceiver>::cast(proxy); 5746 for (int i = 0; i < JSProxy::kMaxIterationLimit; i++) { 5747 Handle<JSProxy> proxy = Handle<JSProxy>::cast(object); 5748 if (proxy->IsRevoked()) { 5749 isolate->Throw(*isolate->factory()->NewTypeError( 5750 MessageTemplate::kProxyRevoked, 5751 isolate->factory()->NewStringFromAsciiChecked("IsArray"))); 5752 return Nothing<bool>(); 5753 } 5754 object = handle(JSReceiver::cast(proxy->target()), isolate); 5755 if (object->IsJSArray()) return Just(true); 5756 if (!object->IsJSProxy()) return Just(false); 5757 } 5758 5759 // Too deep recursion, throw a RangeError. 5760 isolate->StackOverflow(); 5761 return Nothing<bool>(); 5762 } 5763 5764 Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy, 5765 Handle<Name> name) { 5766 DCHECK(!name->IsPrivate()); 5767 STACK_CHECK(isolate, Nothing<bool>()); 5768 // 1. (Assert) 5769 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 5770 Handle<Object> handler(proxy->handler(), isolate); 5771 // 3. If handler is null, throw a TypeError exception. 5772 // 4. Assert: Type(handler) is Object. 5773 if (proxy->IsRevoked()) { 5774 isolate->Throw(*isolate->factory()->NewTypeError( 5775 MessageTemplate::kProxyRevoked, isolate->factory()->has_string())); 5776 return Nothing<bool>(); 5777 } 5778 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 5779 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 5780 // 6. Let trap be ? GetMethod(handler, "has"). 5781 Handle<Object> trap; 5782 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5783 isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler), 5784 isolate->factory()->has_string()), 5785 Nothing<bool>()); 5786 // 7. If trap is undefined, then 5787 if (trap->IsUndefined(isolate)) { 5788 // 7a. Return target.[[HasProperty]](P). 5789 return JSReceiver::HasProperty(target, name); 5790 } 5791 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, target, P)). 5792 Handle<Object> trap_result_obj; 5793 Handle<Object> args[] = {target, name}; 5794 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5795 isolate, trap_result_obj, 5796 Execution::Call(isolate, trap, handler, arraysize(args), args), 5797 Nothing<bool>()); 5798 bool boolean_trap_result = trap_result_obj->BooleanValue(isolate); 5799 // 9. If booleanTrapResult is false, then: 5800 if (!boolean_trap_result) { 5801 MAYBE_RETURN(JSProxy::CheckHasTrap(isolate, name, target), Nothing<bool>()); 5802 } 5803 // 10. Return booleanTrapResult. 5804 return Just(boolean_trap_result); 5805 } 5806 5807 Maybe<bool> JSProxy::CheckHasTrap(Isolate* isolate, Handle<Name> name, 5808 Handle<JSReceiver> target) { 5809 // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P). 5810 PropertyDescriptor target_desc; 5811 Maybe<bool> target_found = 5812 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 5813 MAYBE_RETURN(target_found, Nothing<bool>()); 5814 // 9b. If targetDesc is not undefined, then: 5815 if (target_found.FromJust()) { 5816 // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError 5817 // exception. 5818 if (!target_desc.configurable()) { 5819 isolate->Throw(*isolate->factory()->NewTypeError( 5820 MessageTemplate::kProxyHasNonConfigurable, name)); 5821 return Nothing<bool>(); 5822 } 5823 // 9b ii. Let extensibleTarget be ? IsExtensible(target). 5824 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 5825 MAYBE_RETURN(extensible_target, Nothing<bool>()); 5826 // 9b iii. If extensibleTarget is false, throw a TypeError exception. 5827 if (!extensible_target.FromJust()) { 5828 isolate->Throw(*isolate->factory()->NewTypeError( 5829 MessageTemplate::kProxyHasNonExtensible, name)); 5830 return Nothing<bool>(); 5831 } 5832 } 5833 return Just(true); 5834 } 5835 5836 Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name, 5837 Handle<Object> value, Handle<Object> receiver, 5838 LanguageMode language_mode) { 5839 DCHECK(!name->IsPrivate()); 5840 Isolate* isolate = proxy->GetIsolate(); 5841 STACK_CHECK(isolate, Nothing<bool>()); 5842 Factory* factory = isolate->factory(); 5843 Handle<String> trap_name = factory->set_string(); 5844 ShouldThrow should_throw = 5845 is_sloppy(language_mode) ? kDontThrow : kThrowOnError; 5846 5847 if (proxy->IsRevoked()) { 5848 isolate->Throw( 5849 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 5850 return Nothing<bool>(); 5851 } 5852 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 5853 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 5854 5855 Handle<Object> trap; 5856 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5857 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 5858 if (trap->IsUndefined(isolate)) { 5859 LookupIterator it = 5860 LookupIterator::PropertyOrElement(isolate, receiver, name, target); 5861 return Object::SetSuperProperty(&it, value, language_mode, 5862 Object::MAY_BE_STORE_FROM_KEYED); 5863 } 5864 5865 Handle<Object> trap_result; 5866 Handle<Object> args[] = {target, name, value, receiver}; 5867 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5868 isolate, trap_result, 5869 Execution::Call(isolate, trap, handler, arraysize(args), args), 5870 Nothing<bool>()); 5871 if (!trap_result->BooleanValue(isolate)) { 5872 RETURN_FAILURE(isolate, should_throw, 5873 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 5874 trap_name, name)); 5875 } 5876 5877 MaybeHandle<Object> result = 5878 JSProxy::CheckGetSetTrapResult(isolate, name, target, value, kSet); 5879 5880 if (result.is_null()) { 5881 return Nothing<bool>(); 5882 } 5883 return Just(true); 5884 } 5885 5886 5887 Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy, 5888 Handle<Name> name, 5889 LanguageMode language_mode) { 5890 DCHECK(!name->IsPrivate()); 5891 ShouldThrow should_throw = 5892 is_sloppy(language_mode) ? kDontThrow : kThrowOnError; 5893 Isolate* isolate = proxy->GetIsolate(); 5894 STACK_CHECK(isolate, Nothing<bool>()); 5895 Factory* factory = isolate->factory(); 5896 Handle<String> trap_name = factory->deleteProperty_string(); 5897 5898 if (proxy->IsRevoked()) { 5899 isolate->Throw( 5900 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 5901 return Nothing<bool>(); 5902 } 5903 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 5904 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 5905 5906 Handle<Object> trap; 5907 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5908 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 5909 if (trap->IsUndefined(isolate)) { 5910 return JSReceiver::DeletePropertyOrElement(target, name, language_mode); 5911 } 5912 5913 Handle<Object> trap_result; 5914 Handle<Object> args[] = {target, name}; 5915 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5916 isolate, trap_result, 5917 Execution::Call(isolate, trap, handler, arraysize(args), args), 5918 Nothing<bool>()); 5919 if (!trap_result->BooleanValue(isolate)) { 5920 RETURN_FAILURE(isolate, should_throw, 5921 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 5922 trap_name, name)); 5923 } 5924 5925 // Enforce the invariant. 5926 PropertyDescriptor target_desc; 5927 Maybe<bool> owned = 5928 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 5929 MAYBE_RETURN(owned, Nothing<bool>()); 5930 if (owned.FromJust() && !target_desc.configurable()) { 5931 isolate->Throw(*factory->NewTypeError( 5932 MessageTemplate::kProxyDeletePropertyNonConfigurable, name)); 5933 return Nothing<bool>(); 5934 } 5935 return Just(true); 5936 } 5937 5938 5939 // static 5940 MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target, 5941 Handle<Object> handler) { 5942 if (!target->IsJSReceiver()) { 5943 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject), 5944 JSProxy); 5945 } 5946 if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) { 5947 THROW_NEW_ERROR(isolate, 5948 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked), 5949 JSProxy); 5950 } 5951 if (!handler->IsJSReceiver()) { 5952 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject), 5953 JSProxy); 5954 } 5955 if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) { 5956 THROW_NEW_ERROR(isolate, 5957 NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked), 5958 JSProxy); 5959 } 5960 return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target), 5961 Handle<JSReceiver>::cast(handler)); 5962 } 5963 5964 5965 // static 5966 MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) { 5967 DCHECK(proxy->map()->is_constructor()); 5968 if (proxy->IsRevoked()) { 5969 THROW_NEW_ERROR(proxy->GetIsolate(), 5970 NewTypeError(MessageTemplate::kProxyRevoked), Context); 5971 } 5972 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), 5973 proxy->GetIsolate()); 5974 return JSReceiver::GetFunctionRealm(target); 5975 } 5976 5977 5978 // static 5979 MaybeHandle<Context> JSBoundFunction::GetFunctionRealm( 5980 Handle<JSBoundFunction> function) { 5981 DCHECK(function->map()->is_constructor()); 5982 return JSReceiver::GetFunctionRealm( 5983 handle(function->bound_target_function(), function->GetIsolate())); 5984 } 5985 5986 // static 5987 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate, 5988 Handle<JSBoundFunction> function) { 5989 Handle<String> prefix = isolate->factory()->bound__string(); 5990 Handle<String> target_name = prefix; 5991 Factory* factory = isolate->factory(); 5992 // Concatenate the "bound " up to the last non-bound target. 5993 while (function->bound_target_function()->IsJSBoundFunction()) { 5994 ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name, 5995 factory->NewConsString(prefix, target_name), 5996 String); 5997 function = handle(JSBoundFunction::cast(function->bound_target_function()), 5998 isolate); 5999 } 6000 if (function->bound_target_function()->IsJSFunction()) { 6001 Handle<JSFunction> target( 6002 JSFunction::cast(function->bound_target_function()), isolate); 6003 Handle<Object> name = JSFunction::GetName(isolate, target); 6004 if (!name->IsString()) return target_name; 6005 return factory->NewConsString(target_name, Handle<String>::cast(name)); 6006 } 6007 // This will omit the proper target name for bound JSProxies. 6008 return target_name; 6009 } 6010 6011 // static 6012 Maybe<int> JSBoundFunction::GetLength(Isolate* isolate, 6013 Handle<JSBoundFunction> function) { 6014 int nof_bound_arguments = function->bound_arguments()->length(); 6015 while (function->bound_target_function()->IsJSBoundFunction()) { 6016 function = handle(JSBoundFunction::cast(function->bound_target_function()), 6017 isolate); 6018 // Make sure we never overflow {nof_bound_arguments}, the number of 6019 // arguments of a function is strictly limited by the max length of an 6020 // JSAarray, Smi::kMaxValue is thus a reasonably good overestimate. 6021 int length = function->bound_arguments()->length(); 6022 if (V8_LIKELY(Smi::kMaxValue - nof_bound_arguments > length)) { 6023 nof_bound_arguments += length; 6024 } else { 6025 nof_bound_arguments = Smi::kMaxValue; 6026 } 6027 } 6028 // All non JSFunction targets get a direct property and don't use this 6029 // accessor. 6030 Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()), 6031 isolate); 6032 Maybe<int> target_length = JSFunction::GetLength(isolate, target); 6033 if (target_length.IsNothing()) return target_length; 6034 6035 int length = Max(0, target_length.FromJust() - nof_bound_arguments); 6036 return Just(length); 6037 } 6038 6039 // static 6040 Handle<Object> JSFunction::GetName(Isolate* isolate, 6041 Handle<JSFunction> function) { 6042 if (function->shared()->name_should_print_as_anonymous()) { 6043 return isolate->factory()->anonymous_string(); 6044 } 6045 return handle(function->shared()->Name(), isolate); 6046 } 6047 6048 // static 6049 Maybe<int> JSFunction::GetLength(Isolate* isolate, 6050 Handle<JSFunction> function) { 6051 int length = 0; 6052 if (function->shared()->is_compiled()) { 6053 length = function->shared()->GetLength(); 6054 } else { 6055 // If the function isn't compiled yet, the length is not computed 6056 // correctly yet. Compile it now and return the right length. 6057 if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) { 6058 length = function->shared()->GetLength(); 6059 } 6060 if (isolate->has_pending_exception()) return Nothing<int>(); 6061 } 6062 DCHECK_GE(length, 0); 6063 return Just(length); 6064 } 6065 6066 // static 6067 Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) { 6068 DCHECK(function->map()->is_constructor()); 6069 return handle(function->context()->native_context(), function->GetIsolate()); 6070 } 6071 6072 6073 // static 6074 MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) { 6075 DCHECK(object->map()->is_constructor()); 6076 DCHECK(!object->IsJSFunction()); 6077 return object->GetCreationContext(); 6078 } 6079 6080 6081 // static 6082 MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) { 6083 if (receiver->IsJSProxy()) { 6084 return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver)); 6085 } 6086 6087 if (receiver->IsJSFunction()) { 6088 return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver)); 6089 } 6090 6091 if (receiver->IsJSBoundFunction()) { 6092 return JSBoundFunction::GetFunctionRealm( 6093 Handle<JSBoundFunction>::cast(receiver)); 6094 } 6095 6096 return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver)); 6097 } 6098 6099 6100 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) { 6101 PropertyDescriptor desc; 6102 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor( 6103 it->isolate(), it->GetHolder<JSProxy>(), it->GetName(), &desc); 6104 MAYBE_RETURN(found, Nothing<PropertyAttributes>()); 6105 if (!found.FromJust()) return Just(ABSENT); 6106 return Just(desc.ToAttributes()); 6107 } 6108 6109 6110 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) { 6111 DCHECK(object->map()->GetInObjectProperties() == 6112 map->GetInObjectProperties()); 6113 ElementsKind obj_kind = object->map()->elements_kind(); 6114 ElementsKind map_kind = map->elements_kind(); 6115 if (map_kind != obj_kind) { 6116 ElementsKind to_kind = GetMoreGeneralElementsKind(map_kind, obj_kind); 6117 if (IsDictionaryElementsKind(obj_kind)) { 6118 to_kind = obj_kind; 6119 } 6120 if (IsDictionaryElementsKind(to_kind)) { 6121 NormalizeElements(object); 6122 } else { 6123 TransitionElementsKind(object, to_kind); 6124 } 6125 map = Map::ReconfigureElementsKind(object->GetIsolate(), map, to_kind); 6126 } 6127 int number_of_fields = map->NumberOfFields(); 6128 int inobject = map->GetInObjectProperties(); 6129 int unused = map->UnusedPropertyFields(); 6130 int total_size = number_of_fields + unused; 6131 int external = total_size - inobject; 6132 // Allocate mutable double boxes if necessary. It is always necessary if we 6133 // have external properties, but is also necessary if we only have inobject 6134 // properties but don't unbox double fields. 6135 if (!FLAG_unbox_double_fields || external > 0) { 6136 Isolate* isolate = object->GetIsolate(); 6137 6138 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 6139 Handle<FixedArray> storage; 6140 if (!FLAG_unbox_double_fields) { 6141 storage = isolate->factory()->NewFixedArray(inobject); 6142 } 6143 6144 Handle<PropertyArray> array = 6145 isolate->factory()->NewPropertyArray(external); 6146 6147 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { 6148 PropertyDetails details = descriptors->GetDetails(i); 6149 Representation representation = details.representation(); 6150 if (!representation.IsDouble()) continue; 6151 FieldIndex index = FieldIndex::ForDescriptor(*map, i); 6152 if (map->IsUnboxedDoubleField(index)) continue; 6153 auto box = isolate->factory()->NewMutableHeapNumberWithHoleNaN(); 6154 if (index.is_inobject()) { 6155 storage->set(index.property_index(), *box); 6156 } else { 6157 array->set(index.outobject_array_index(), *box); 6158 } 6159 } 6160 6161 object->SetProperties(*array); 6162 6163 if (!FLAG_unbox_double_fields) { 6164 for (int i = 0; i < inobject; i++) { 6165 FieldIndex index = FieldIndex::ForPropertyIndex(*map, i); 6166 Object* value = storage->get(i); 6167 object->RawFastPropertyAtPut(index, value); 6168 } 6169 } 6170 } 6171 object->synchronized_set_map(*map); 6172 } 6173 6174 6175 void JSObject::MigrateInstance(Handle<JSObject> object) { 6176 Handle<Map> original_map(object->map(), object->GetIsolate()); 6177 Handle<Map> map = Map::Update(object->GetIsolate(), original_map); 6178 map->set_is_migration_target(true); 6179 MigrateToMap(object, map); 6180 if (FLAG_trace_migration) { 6181 object->PrintInstanceMigration(stdout, *original_map, *map); 6182 } 6183 #if VERIFY_HEAP 6184 if (FLAG_verify_heap) { 6185 object->JSObjectVerify(object->GetIsolate()); 6186 } 6187 #endif 6188 } 6189 6190 6191 // static 6192 bool JSObject::TryMigrateInstance(Handle<JSObject> object) { 6193 Isolate* isolate = object->GetIsolate(); 6194 DisallowDeoptimization no_deoptimization(isolate); 6195 Handle<Map> original_map(object->map(), isolate); 6196 Handle<Map> new_map; 6197 if (!Map::TryUpdate(isolate, original_map).ToHandle(&new_map)) { 6198 return false; 6199 } 6200 JSObject::MigrateToMap(object, new_map); 6201 if (FLAG_trace_migration && *original_map != object->map()) { 6202 object->PrintInstanceMigration(stdout, *original_map, object->map()); 6203 } 6204 #if VERIFY_HEAP 6205 if (FLAG_verify_heap) { 6206 object->JSObjectVerify(isolate); 6207 } 6208 #endif 6209 return true; 6210 } 6211 6212 void JSObject::AddProperty(Isolate* isolate, Handle<JSObject> object, 6213 Handle<Name> name, Handle<Object> value, 6214 PropertyAttributes attributes) { 6215 LookupIterator it(isolate, object, name, object, 6216 LookupIterator::OWN_SKIP_INTERCEPTOR); 6217 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); 6218 #ifdef DEBUG 6219 uint32_t index; 6220 DCHECK(!object->IsJSProxy()); 6221 DCHECK(!name->AsArrayIndex(&index)); 6222 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); 6223 DCHECK(maybe.IsJust()); 6224 DCHECK(!it.IsFound()); 6225 DCHECK(object->map()->is_extensible() || name->IsPrivate()); 6226 #endif 6227 CHECK(AddDataProperty(&it, value, attributes, kThrowOnError, 6228 CERTAINLY_NOT_STORE_FROM_KEYED) 6229 .IsJust()); 6230 } 6231 6232 6233 // Reconfigures a property to a data property with attributes, even if it is not 6234 // reconfigurable. 6235 // Requires a LookupIterator that does not look at the prototype chain beyond 6236 // hidden prototypes. 6237 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes( 6238 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, 6239 AccessorInfoHandling handling) { 6240 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(it, value, attributes, 6241 kThrowOnError, handling)); 6242 return value; 6243 } 6244 6245 6246 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( 6247 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, 6248 ShouldThrow should_throw, AccessorInfoHandling handling) { 6249 it->UpdateProtector(); 6250 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 6251 6252 for (; it->IsFound(); it->Next()) { 6253 switch (it->state()) { 6254 case LookupIterator::JSPROXY: 6255 case LookupIterator::NOT_FOUND: 6256 case LookupIterator::TRANSITION: 6257 UNREACHABLE(); 6258 6259 case LookupIterator::ACCESS_CHECK: 6260 if (!it->HasAccess()) { 6261 it->isolate()->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 6262 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); 6263 return Just(true); 6264 } 6265 break; 6266 6267 // If there's an interceptor, try to store the property with the 6268 // interceptor. 6269 // In case of success, the attributes will have been reset to the default 6270 // attributes of the interceptor, rather than the incoming attributes. 6271 // 6272 // TODO(verwaest): JSProxy afterwards verify the attributes that the 6273 // JSProxy claims it has, and verifies that they are compatible. If not, 6274 // they throw. Here we should do the same. 6275 case LookupIterator::INTERCEPTOR: 6276 if (handling == DONT_FORCE_FIELD) { 6277 Maybe<bool> result = 6278 JSObject::SetPropertyWithInterceptor(it, should_throw, value); 6279 if (result.IsNothing() || result.FromJust()) return result; 6280 } 6281 break; 6282 6283 case LookupIterator::ACCESSOR: { 6284 Handle<Object> accessors = it->GetAccessors(); 6285 6286 // Special handling for AccessorInfo, which behaves like a data 6287 // property. 6288 if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) { 6289 PropertyAttributes current_attributes = it->property_attributes(); 6290 // Ensure the context isn't changed after calling into accessors. 6291 AssertNoContextChange ncc(it->isolate()); 6292 6293 // Update the attributes before calling the setter. The setter may 6294 // later change the shape of the property. 6295 if (current_attributes != attributes) { 6296 it->TransitionToAccessorPair(accessors, attributes); 6297 } 6298 6299 return JSObject::SetPropertyWithAccessor(it, value, should_throw); 6300 } 6301 6302 it->ReconfigureDataProperty(value, attributes); 6303 return Just(true); 6304 } 6305 case LookupIterator::INTEGER_INDEXED_EXOTIC: 6306 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value, 6307 should_throw); 6308 6309 case LookupIterator::DATA: { 6310 // Regular property update if the attributes match. 6311 if (it->property_attributes() == attributes) { 6312 return SetDataProperty(it, value); 6313 } 6314 6315 // Special case: properties of typed arrays cannot be reconfigured to 6316 // non-writable nor to non-enumerable. 6317 if (it->IsElement() && object->HasFixedTypedArrayElements()) { 6318 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), 6319 value, should_throw); 6320 } 6321 6322 // Reconfigure the data property if the attributes mismatch. 6323 it->ReconfigureDataProperty(value, attributes); 6324 6325 return Just(true); 6326 } 6327 } 6328 } 6329 6330 return AddDataProperty(it, value, attributes, should_throw, 6331 CERTAINLY_NOT_STORE_FROM_KEYED); 6332 } 6333 6334 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( 6335 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, 6336 PropertyAttributes attributes) { 6337 DCHECK(!value->IsTheHole()); 6338 LookupIterator it(object, name, object, LookupIterator::OWN); 6339 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 6340 } 6341 6342 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes( 6343 Handle<JSObject> object, uint32_t index, Handle<Object> value, 6344 PropertyAttributes attributes) { 6345 Isolate* isolate = object->GetIsolate(); 6346 LookupIterator it(isolate, object, index, object, LookupIterator::OWN); 6347 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 6348 } 6349 6350 MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes( 6351 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, 6352 PropertyAttributes attributes) { 6353 Isolate* isolate = object->GetIsolate(); 6354 LookupIterator it = LookupIterator::PropertyOrElement( 6355 isolate, object, name, object, LookupIterator::OWN); 6356 return DefineOwnPropertyIgnoreAttributes(&it, value, attributes); 6357 } 6358 6359 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( 6360 LookupIterator* it) { 6361 return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor()); 6362 } 6363 6364 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes( 6365 LookupIterator* it) { 6366 for (; it->IsFound(); it->Next()) { 6367 switch (it->state()) { 6368 case LookupIterator::NOT_FOUND: 6369 case LookupIterator::TRANSITION: 6370 UNREACHABLE(); 6371 case LookupIterator::JSPROXY: 6372 return JSProxy::GetPropertyAttributes(it); 6373 case LookupIterator::INTERCEPTOR: { 6374 Maybe<PropertyAttributes> result = 6375 JSObject::GetPropertyAttributesWithInterceptor(it); 6376 if (result.IsNothing()) return result; 6377 if (result.FromJust() != ABSENT) return result; 6378 break; 6379 } 6380 case LookupIterator::ACCESS_CHECK: 6381 if (it->HasAccess()) break; 6382 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it); 6383 case LookupIterator::INTEGER_INDEXED_EXOTIC: 6384 return Just(ABSENT); 6385 case LookupIterator::ACCESSOR: 6386 if (it->GetHolder<Object>()->IsJSModuleNamespace()) { 6387 return JSModuleNamespace::GetPropertyAttributes(it); 6388 } else { 6389 return Just(it->property_attributes()); 6390 } 6391 case LookupIterator::DATA: 6392 return Just(it->property_attributes()); 6393 } 6394 } 6395 return Just(ABSENT); 6396 } 6397 6398 6399 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) { 6400 Handle<WeakFixedArray> array( 6401 isolate->factory()->NewWeakFixedArray(kEntries, TENURED)); 6402 return Handle<NormalizedMapCache>::cast(array); 6403 } 6404 6405 6406 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map, 6407 PropertyNormalizationMode mode) { 6408 DisallowHeapAllocation no_gc; 6409 MaybeObject* value = WeakFixedArray::Get(GetIndex(fast_map)); 6410 HeapObject* heap_object; 6411 if (!value->ToWeakHeapObject(&heap_object)) { 6412 return MaybeHandle<Map>(); 6413 } 6414 6415 Map* normalized_map = Map::cast(heap_object); 6416 if (!normalized_map->EquivalentToForNormalization(*fast_map, mode)) { 6417 return MaybeHandle<Map>(); 6418 } 6419 return handle(normalized_map, GetIsolate()); 6420 } 6421 6422 void NormalizedMapCache::Set(Handle<Map> fast_map, Handle<Map> normalized_map) { 6423 DisallowHeapAllocation no_gc; 6424 DCHECK(normalized_map->is_dictionary_map()); 6425 WeakFixedArray::Set(GetIndex(fast_map), 6426 HeapObjectReference::Weak(*normalized_map)); 6427 } 6428 6429 void JSObject::NormalizeProperties(Handle<JSObject> object, 6430 PropertyNormalizationMode mode, 6431 int expected_additional_properties, 6432 const char* reason) { 6433 if (!object->HasFastProperties()) return; 6434 6435 Handle<Map> map(object->map(), object->GetIsolate()); 6436 Handle<Map> new_map = Map::Normalize(object->GetIsolate(), map, mode, reason); 6437 6438 MigrateToMap(object, new_map, expected_additional_properties); 6439 } 6440 6441 6442 void JSObject::MigrateSlowToFast(Handle<JSObject> object, 6443 int unused_property_fields, 6444 const char* reason) { 6445 if (object->HasFastProperties()) return; 6446 DCHECK(!object->IsJSGlobalObject()); 6447 Isolate* isolate = object->GetIsolate(); 6448 Factory* factory = isolate->factory(); 6449 Handle<NameDictionary> dictionary(object->property_dictionary(), isolate); 6450 6451 // Make sure we preserve dictionary representation if there are too many 6452 // descriptors. 6453 int number_of_elements = dictionary->NumberOfElements(); 6454 if (number_of_elements > kMaxNumberOfDescriptors) return; 6455 6456 Handle<FixedArray> iteration_order = 6457 NameDictionary::IterationIndices(isolate, dictionary); 6458 6459 int instance_descriptor_length = iteration_order->length(); 6460 int number_of_fields = 0; 6461 6462 // Compute the length of the instance descriptor. 6463 ReadOnlyRoots roots(isolate); 6464 for (int i = 0; i < instance_descriptor_length; i++) { 6465 int index = Smi::ToInt(iteration_order->get(i)); 6466 DCHECK(dictionary->IsKey(roots, dictionary->KeyAt(index))); 6467 6468 PropertyKind kind = dictionary->DetailsAt(index).kind(); 6469 if (kind == kData) { 6470 if (FLAG_track_constant_fields) { 6471 number_of_fields += 1; 6472 } else { 6473 Object* value = dictionary->ValueAt(index); 6474 if (!value->IsJSFunction()) { 6475 number_of_fields += 1; 6476 } 6477 } 6478 } 6479 } 6480 6481 Handle<Map> old_map(object->map(), isolate); 6482 6483 int inobject_props = old_map->GetInObjectProperties(); 6484 6485 // Allocate new map. 6486 Handle<Map> new_map = Map::CopyDropDescriptors(isolate, old_map); 6487 if (new_map->has_named_interceptor() || new_map->is_access_check_needed()) { 6488 // Force certain slow paths when API interceptors are used, or if an access 6489 // check is required. 6490 new_map->set_may_have_interesting_symbols(true); 6491 } 6492 new_map->set_is_dictionary_map(false); 6493 6494 NotifyMapChange(old_map, new_map, isolate); 6495 6496 if (FLAG_trace_maps) { 6497 LOG(isolate, MapEvent("SlowToFast", *old_map, *new_map, reason)); 6498 } 6499 6500 if (instance_descriptor_length == 0) { 6501 DisallowHeapAllocation no_gc; 6502 DCHECK_LE(unused_property_fields, inobject_props); 6503 // Transform the object. 6504 new_map->SetInObjectUnusedPropertyFields(inobject_props); 6505 object->synchronized_set_map(*new_map); 6506 object->SetProperties(ReadOnlyRoots(isolate).empty_fixed_array()); 6507 // Check that it really works. 6508 DCHECK(object->HasFastProperties()); 6509 return; 6510 } 6511 6512 // Allocate the instance descriptor. 6513 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate( 6514 isolate, instance_descriptor_length, 0, TENURED); 6515 6516 int number_of_allocated_fields = 6517 number_of_fields + unused_property_fields - inobject_props; 6518 if (number_of_allocated_fields < 0) { 6519 // There is enough inobject space for all fields (including unused). 6520 number_of_allocated_fields = 0; 6521 unused_property_fields = inobject_props - number_of_fields; 6522 } 6523 6524 // Allocate the property array for the fields. 6525 Handle<PropertyArray> fields = 6526 factory->NewPropertyArray(number_of_allocated_fields); 6527 6528 bool is_transitionable_elements_kind = 6529 IsTransitionableFastElementsKind(old_map->elements_kind()); 6530 6531 // Fill in the instance descriptor and the fields. 6532 int current_offset = 0; 6533 for (int i = 0; i < instance_descriptor_length; i++) { 6534 int index = Smi::ToInt(iteration_order->get(i)); 6535 Name* k = dictionary->NameAt(index); 6536 // Dictionary keys are internalized upon insertion. 6537 // TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild. 6538 CHECK(k->IsUniqueName()); 6539 Handle<Name> key(k, isolate); 6540 6541 // Properly mark the {new_map} if the {key} is an "interesting symbol". 6542 if (key->IsInterestingSymbol()) { 6543 new_map->set_may_have_interesting_symbols(true); 6544 } 6545 6546 Object* value = dictionary->ValueAt(index); 6547 6548 PropertyDetails details = dictionary->DetailsAt(index); 6549 DCHECK_EQ(kField, details.location()); 6550 DCHECK_EQ(PropertyConstness::kMutable, details.constness()); 6551 6552 Descriptor d; 6553 if (details.kind() == kData) { 6554 if (!FLAG_track_constant_fields && value->IsJSFunction()) { 6555 d = Descriptor::DataConstant(key, handle(value, isolate), 6556 details.attributes()); 6557 } else { 6558 // Ensure that we make constant field only when elements kind is not 6559 // transitionable. 6560 PropertyConstness constness = 6561 FLAG_track_constant_fields && !is_transitionable_elements_kind 6562 ? PropertyConstness::kConst 6563 : PropertyConstness::kMutable; 6564 d = Descriptor::DataField( 6565 key, current_offset, details.attributes(), constness, 6566 // TODO(verwaest): value->OptimalRepresentation(); 6567 Representation::Tagged(), 6568 MaybeObjectHandle(FieldType::Any(isolate))); 6569 } 6570 } else { 6571 DCHECK_EQ(kAccessor, details.kind()); 6572 d = Descriptor::AccessorConstant(key, handle(value, isolate), 6573 details.attributes()); 6574 } 6575 details = d.GetDetails(); 6576 if (details.location() == kField) { 6577 if (current_offset < inobject_props) { 6578 object->InObjectPropertyAtPut(current_offset, value, 6579 UPDATE_WRITE_BARRIER); 6580 } else { 6581 int offset = current_offset - inobject_props; 6582 fields->set(offset, value); 6583 } 6584 current_offset += details.field_width_in_words(); 6585 } 6586 descriptors->Set(i, &d); 6587 } 6588 DCHECK(current_offset == number_of_fields); 6589 6590 descriptors->Sort(); 6591 6592 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New( 6593 isolate, new_map, descriptors, descriptors->number_of_descriptors()); 6594 6595 DisallowHeapAllocation no_gc; 6596 new_map->InitializeDescriptors(*descriptors, *layout_descriptor); 6597 if (number_of_allocated_fields == 0) { 6598 new_map->SetInObjectUnusedPropertyFields(unused_property_fields); 6599 } else { 6600 new_map->SetOutOfObjectUnusedPropertyFields(unused_property_fields); 6601 } 6602 6603 // Transform the object. 6604 object->synchronized_set_map(*new_map); 6605 6606 object->SetProperties(*fields); 6607 DCHECK(object->IsJSObject()); 6608 6609 // Check that it really works. 6610 DCHECK(object->HasFastProperties()); 6611 } 6612 6613 void JSObject::RequireSlowElements(NumberDictionary* dictionary) { 6614 if (dictionary->requires_slow_elements()) return; 6615 dictionary->set_requires_slow_elements(); 6616 if (map()->is_prototype_map()) { 6617 // If this object is a prototype (the callee will check), invalidate any 6618 // prototype chains involving it. 6619 InvalidatePrototypeChains(map()); 6620 } 6621 } 6622 6623 Handle<NumberDictionary> JSObject::NormalizeElements(Handle<JSObject> object) { 6624 DCHECK(!object->HasFixedTypedArrayElements()); 6625 Isolate* isolate = object->GetIsolate(); 6626 bool is_sloppy_arguments = object->HasSloppyArgumentsElements(); 6627 { 6628 DisallowHeapAllocation no_gc; 6629 FixedArrayBase* elements = object->elements(); 6630 6631 if (is_sloppy_arguments) { 6632 elements = SloppyArgumentsElements::cast(elements)->arguments(); 6633 } 6634 6635 if (elements->IsNumberDictionary()) { 6636 return handle(NumberDictionary::cast(elements), isolate); 6637 } 6638 } 6639 6640 DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements() || 6641 object->HasFastArgumentsElements() || 6642 object->HasFastStringWrapperElements()); 6643 6644 Handle<NumberDictionary> dictionary = 6645 object->GetElementsAccessor()->Normalize(object); 6646 6647 // Switch to using the dictionary as the backing storage for elements. 6648 ElementsKind target_kind = is_sloppy_arguments 6649 ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS 6650 : object->HasFastStringWrapperElements() 6651 ? SLOW_STRING_WRAPPER_ELEMENTS 6652 : DICTIONARY_ELEMENTS; 6653 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind); 6654 // Set the new map first to satify the elements type assert in set_elements(). 6655 JSObject::MigrateToMap(object, new_map); 6656 6657 if (is_sloppy_arguments) { 6658 SloppyArgumentsElements::cast(object->elements()) 6659 ->set_arguments(*dictionary); 6660 } else { 6661 object->set_elements(*dictionary); 6662 } 6663 6664 isolate->counters()->elements_to_dictionary()->Increment(); 6665 6666 #ifdef DEBUG 6667 if (FLAG_trace_normalization) { 6668 StdoutStream os; 6669 os << "Object elements have been normalized:\n"; 6670 object->Print(os); 6671 } 6672 #endif 6673 6674 DCHECK(object->HasDictionaryElements() || 6675 object->HasSlowArgumentsElements() || 6676 object->HasSlowStringWrapperElements()); 6677 return dictionary; 6678 } 6679 6680 namespace { 6681 6682 Object* SetHashAndUpdateProperties(Isolate* isolate, HeapObject* properties, 6683 int hash) { 6684 DCHECK_NE(PropertyArray::kNoHashSentinel, hash); 6685 DCHECK(PropertyArray::HashField::is_valid(hash)); 6686 6687 Heap* heap = isolate->heap(); 6688 ReadOnlyRoots roots(heap); 6689 if (properties == roots.empty_fixed_array() || 6690 properties == roots.empty_property_array() || 6691 properties == heap->empty_property_dictionary()) { 6692 return Smi::FromInt(hash); 6693 } 6694 6695 if (properties->IsPropertyArray()) { 6696 PropertyArray::cast(properties)->SetHash(hash); 6697 DCHECK_LT(0, PropertyArray::cast(properties)->length()); 6698 return properties; 6699 } 6700 6701 DCHECK(properties->IsNameDictionary()); 6702 NameDictionary::cast(properties)->SetHash(hash); 6703 return properties; 6704 } 6705 6706 int GetIdentityHashHelper(Isolate* isolate, JSReceiver* object) { 6707 DisallowHeapAllocation no_gc; 6708 Object* properties = object->raw_properties_or_hash(); 6709 if (properties->IsSmi()) { 6710 return Smi::ToInt(properties); 6711 } 6712 6713 if (properties->IsPropertyArray()) { 6714 return PropertyArray::cast(properties)->Hash(); 6715 } 6716 6717 if (properties->IsNameDictionary()) { 6718 return NameDictionary::cast(properties)->Hash(); 6719 } 6720 6721 if (properties->IsGlobalDictionary()) { 6722 return GlobalDictionary::cast(properties)->Hash(); 6723 } 6724 6725 #ifdef DEBUG 6726 FixedArray* empty_fixed_array = ReadOnlyRoots(isolate).empty_fixed_array(); 6727 FixedArray* empty_property_dictionary = 6728 isolate->heap()->empty_property_dictionary(); 6729 DCHECK(properties == empty_fixed_array || 6730 properties == empty_property_dictionary); 6731 #endif 6732 6733 return PropertyArray::kNoHashSentinel; 6734 } 6735 } // namespace 6736 6737 void JSReceiver::SetIdentityHash(int hash) { 6738 DisallowHeapAllocation no_gc; 6739 DCHECK_NE(PropertyArray::kNoHashSentinel, hash); 6740 DCHECK(PropertyArray::HashField::is_valid(hash)); 6741 6742 HeapObject* existing_properties = HeapObject::cast(raw_properties_or_hash()); 6743 Object* new_properties = 6744 SetHashAndUpdateProperties(GetIsolate(), existing_properties, hash); 6745 set_raw_properties_or_hash(new_properties); 6746 } 6747 6748 void JSReceiver::SetProperties(HeapObject* properties) { 6749 DCHECK_IMPLIES(properties->IsPropertyArray() && 6750 PropertyArray::cast(properties)->length() == 0, 6751 properties == GetReadOnlyRoots().empty_property_array()); 6752 DisallowHeapAllocation no_gc; 6753 Isolate* isolate = GetIsolate(); 6754 int hash = GetIdentityHashHelper(isolate, this); 6755 Object* new_properties = properties; 6756 6757 // TODO(cbruni): Make GetIdentityHashHelper return a bool so that we 6758 // don't have to manually compare against kNoHashSentinel. 6759 if (hash != PropertyArray::kNoHashSentinel) { 6760 new_properties = SetHashAndUpdateProperties(isolate, properties, hash); 6761 } 6762 6763 set_raw_properties_or_hash(new_properties); 6764 } 6765 6766 Object* JSReceiver::GetIdentityHash(Isolate* isolate) { 6767 DisallowHeapAllocation no_gc; 6768 6769 int hash = GetIdentityHashHelper(isolate, this); 6770 if (hash == PropertyArray::kNoHashSentinel) { 6771 return ReadOnlyRoots(isolate).undefined_value(); 6772 } 6773 6774 return Smi::FromInt(hash); 6775 } 6776 6777 // static 6778 Smi* JSReceiver::CreateIdentityHash(Isolate* isolate, JSReceiver* key) { 6779 DisallowHeapAllocation no_gc; 6780 int hash = isolate->GenerateIdentityHash(PropertyArray::HashField::kMax); 6781 DCHECK_NE(PropertyArray::kNoHashSentinel, hash); 6782 6783 key->SetIdentityHash(hash); 6784 return Smi::FromInt(hash); 6785 } 6786 6787 Smi* JSReceiver::GetOrCreateIdentityHash(Isolate* isolate) { 6788 DisallowHeapAllocation no_gc; 6789 6790 Object* hash_obj = GetIdentityHash(isolate); 6791 if (!hash_obj->IsUndefined(isolate)) { 6792 return Smi::cast(hash_obj); 6793 } 6794 6795 return JSReceiver::CreateIdentityHash(isolate, this); 6796 } 6797 6798 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it, 6799 ShouldThrow should_throw) { 6800 Isolate* isolate = it->isolate(); 6801 // Make sure that the top context does not change when doing callbacks or 6802 // interceptor calls. 6803 AssertNoContextChange ncc(isolate); 6804 6805 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 6806 Handle<InterceptorInfo> interceptor(it->GetInterceptor()); 6807 if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>(); 6808 6809 Handle<JSObject> holder = it->GetHolder<JSObject>(); 6810 Handle<Object> receiver = it->GetReceiver(); 6811 if (!receiver->IsJSReceiver()) { 6812 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 6813 Object::ConvertReceiver(isolate, receiver), 6814 Nothing<bool>()); 6815 } 6816 6817 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 6818 *holder, should_throw); 6819 Handle<Object> result; 6820 if (it->IsElement()) { 6821 result = args.CallIndexedDeleter(interceptor, it->index()); 6822 } else { 6823 result = args.CallNamedDeleter(interceptor, it->name()); 6824 } 6825 6826 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 6827 if (result.is_null()) return Nothing<bool>(); 6828 6829 DCHECK(result->IsBoolean()); 6830 // Rebox CustomArguments::kReturnValueOffset before returning. 6831 return Just(result->IsTrue(isolate)); 6832 } 6833 6834 void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object, 6835 int entry) { 6836 DCHECK(!object->HasFastProperties()); 6837 Isolate* isolate = object->GetIsolate(); 6838 6839 if (object->IsJSGlobalObject()) { 6840 // If we have a global object, invalidate the cell and swap in a new one. 6841 Handle<GlobalDictionary> dictionary( 6842 JSGlobalObject::cast(*object)->global_dictionary(), isolate); 6843 DCHECK_NE(GlobalDictionary::kNotFound, entry); 6844 6845 auto cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry); 6846 cell->set_value(ReadOnlyRoots(isolate).the_hole_value()); 6847 cell->set_property_details( 6848 PropertyDetails::Empty(PropertyCellType::kUninitialized)); 6849 } else { 6850 Handle<NameDictionary> dictionary(object->property_dictionary(), isolate); 6851 DCHECK_NE(NameDictionary::kNotFound, entry); 6852 6853 dictionary = NameDictionary::DeleteEntry(isolate, dictionary, entry); 6854 object->SetProperties(*dictionary); 6855 } 6856 if (object->map()->is_prototype_map()) { 6857 // Invalidate prototype validity cell as this may invalidate transitioning 6858 // store IC handlers. 6859 JSObject::InvalidatePrototypeChains(object->map()); 6860 } 6861 } 6862 6863 6864 Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it, 6865 LanguageMode language_mode) { 6866 it->UpdateProtector(); 6867 6868 Isolate* isolate = it->isolate(); 6869 6870 if (it->state() == LookupIterator::JSPROXY) { 6871 return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(), 6872 it->GetName(), language_mode); 6873 } 6874 6875 if (it->GetReceiver()->IsJSProxy()) { 6876 if (it->state() != LookupIterator::NOT_FOUND) { 6877 DCHECK_EQ(LookupIterator::DATA, it->state()); 6878 DCHECK(it->name()->IsPrivate()); 6879 it->Delete(); 6880 } 6881 return Just(true); 6882 } 6883 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); 6884 6885 for (; it->IsFound(); it->Next()) { 6886 switch (it->state()) { 6887 case LookupIterator::JSPROXY: 6888 case LookupIterator::NOT_FOUND: 6889 case LookupIterator::TRANSITION: 6890 UNREACHABLE(); 6891 case LookupIterator::ACCESS_CHECK: 6892 if (it->HasAccess()) break; 6893 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 6894 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 6895 return Just(false); 6896 case LookupIterator::INTERCEPTOR: { 6897 ShouldThrow should_throw = 6898 is_sloppy(language_mode) ? kDontThrow : kThrowOnError; 6899 Maybe<bool> result = 6900 JSObject::DeletePropertyWithInterceptor(it, should_throw); 6901 // An exception was thrown in the interceptor. Propagate. 6902 if (isolate->has_pending_exception()) return Nothing<bool>(); 6903 // Delete with interceptor succeeded. Return result. 6904 // TODO(neis): In strict mode, we should probably throw if the 6905 // interceptor returns false. 6906 if (result.IsJust()) return result; 6907 break; 6908 } 6909 case LookupIterator::INTEGER_INDEXED_EXOTIC: 6910 return Just(true); 6911 case LookupIterator::DATA: 6912 case LookupIterator::ACCESSOR: { 6913 if (!it->IsConfigurable()) { 6914 // Fail if the property is not configurable. 6915 if (is_strict(language_mode)) { 6916 isolate->Throw(*isolate->factory()->NewTypeError( 6917 MessageTemplate::kStrictDeleteProperty, it->GetName(), 6918 receiver)); 6919 return Nothing<bool>(); 6920 } 6921 return Just(false); 6922 } 6923 6924 it->Delete(); 6925 6926 return Just(true); 6927 } 6928 } 6929 } 6930 6931 return Just(true); 6932 } 6933 6934 6935 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index, 6936 LanguageMode language_mode) { 6937 LookupIterator it(object->GetIsolate(), object, index, object, 6938 LookupIterator::OWN); 6939 return DeleteProperty(&it, language_mode); 6940 } 6941 6942 6943 Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object, 6944 Handle<Name> name, 6945 LanguageMode language_mode) { 6946 LookupIterator it(object, name, object, LookupIterator::OWN); 6947 return DeleteProperty(&it, language_mode); 6948 } 6949 6950 6951 Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object, 6952 Handle<Name> name, 6953 LanguageMode language_mode) { 6954 LookupIterator it = LookupIterator::PropertyOrElement( 6955 object->GetIsolate(), object, name, object, LookupIterator::OWN); 6956 return DeleteProperty(&it, language_mode); 6957 } 6958 6959 // ES6 19.1.2.4 6960 // static 6961 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object, 6962 Handle<Object> key, 6963 Handle<Object> attributes) { 6964 // 1. If Type(O) is not Object, throw a TypeError exception. 6965 if (!object->IsJSReceiver()) { 6966 Handle<String> fun_name = 6967 isolate->factory()->InternalizeUtf8String("Object.defineProperty"); 6968 THROW_NEW_ERROR_RETURN_FAILURE( 6969 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name)); 6970 } 6971 // 2. Let key be ToPropertyKey(P). 6972 // 3. ReturnIfAbrupt(key). 6973 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key)); 6974 // 4. Let desc be ToPropertyDescriptor(Attributes). 6975 // 5. ReturnIfAbrupt(desc). 6976 PropertyDescriptor desc; 6977 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) { 6978 return ReadOnlyRoots(isolate).exception(); 6979 } 6980 // 6. Let success be DefinePropertyOrThrow(O,key, desc). 6981 Maybe<bool> success = DefineOwnProperty( 6982 isolate, Handle<JSReceiver>::cast(object), key, &desc, kThrowOnError); 6983 // 7. ReturnIfAbrupt(success). 6984 MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception()); 6985 CHECK(success.FromJust()); 6986 // 8. Return O. 6987 return *object; 6988 } 6989 6990 6991 // ES6 19.1.2.3.1 6992 // static 6993 MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate, 6994 Handle<Object> object, 6995 Handle<Object> properties) { 6996 // 1. If Type(O) is not Object, throw a TypeError exception. 6997 if (!object->IsJSReceiver()) { 6998 Handle<String> fun_name = 6999 isolate->factory()->InternalizeUtf8String("Object.defineProperties"); 7000 THROW_NEW_ERROR(isolate, 7001 NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name), 7002 Object); 7003 } 7004 // 2. Let props be ToObject(Properties). 7005 // 3. ReturnIfAbrupt(props). 7006 Handle<JSReceiver> props; 7007 ASSIGN_RETURN_ON_EXCEPTION(isolate, props, 7008 Object::ToObject(isolate, properties), Object); 7009 7010 // 4. Let keys be props.[[OwnPropertyKeys]](). 7011 // 5. ReturnIfAbrupt(keys). 7012 Handle<FixedArray> keys; 7013 ASSIGN_RETURN_ON_EXCEPTION( 7014 isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly, 7015 ALL_PROPERTIES), 7016 Object); 7017 // 6. Let descriptors be an empty List. 7018 int capacity = keys->length(); 7019 std::vector<PropertyDescriptor> descriptors(capacity); 7020 size_t descriptors_index = 0; 7021 // 7. Repeat for each element nextKey of keys in List order, 7022 for (int i = 0; i < keys->length(); ++i) { 7023 Handle<Object> next_key(keys->get(i), isolate); 7024 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey). 7025 // 7b. ReturnIfAbrupt(propDesc). 7026 bool success = false; 7027 LookupIterator it = LookupIterator::PropertyOrElement( 7028 isolate, props, next_key, &success, LookupIterator::OWN); 7029 DCHECK(success); 7030 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); 7031 if (maybe.IsNothing()) return MaybeHandle<Object>(); 7032 PropertyAttributes attrs = maybe.FromJust(); 7033 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true: 7034 if (attrs == ABSENT) continue; 7035 if (attrs & DONT_ENUM) continue; 7036 // 7c i. Let descObj be Get(props, nextKey). 7037 // 7c ii. ReturnIfAbrupt(descObj). 7038 Handle<Object> desc_obj; 7039 ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it), 7040 Object); 7041 // 7c iii. Let desc be ToPropertyDescriptor(descObj). 7042 success = PropertyDescriptor::ToPropertyDescriptor( 7043 isolate, desc_obj, &descriptors[descriptors_index]); 7044 // 7c iv. ReturnIfAbrupt(desc). 7045 if (!success) return MaybeHandle<Object>(); 7046 // 7c v. Append the pair (a two element List) consisting of nextKey and 7047 // desc to the end of descriptors. 7048 descriptors[descriptors_index].set_name(next_key); 7049 descriptors_index++; 7050 } 7051 // 8. For each pair from descriptors in list order, 7052 for (size_t i = 0; i < descriptors_index; ++i) { 7053 PropertyDescriptor* desc = &descriptors[i]; 7054 // 8a. Let P be the first element of pair. 7055 // 8b. Let desc be the second element of pair. 7056 // 8c. Let status be DefinePropertyOrThrow(O, P, desc). 7057 Maybe<bool> status = 7058 DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object), 7059 desc->name(), desc, kThrowOnError); 7060 // 8d. ReturnIfAbrupt(status). 7061 if (status.IsNothing()) return MaybeHandle<Object>(); 7062 CHECK(status.FromJust()); 7063 } 7064 // 9. Return o. 7065 return object; 7066 } 7067 7068 // static 7069 Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate, 7070 Handle<JSReceiver> object, 7071 Handle<Object> key, 7072 PropertyDescriptor* desc, 7073 ShouldThrow should_throw) { 7074 if (object->IsJSArray()) { 7075 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object), 7076 key, desc, should_throw); 7077 } 7078 if (object->IsJSProxy()) { 7079 return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object), 7080 key, desc, should_throw); 7081 } 7082 if (object->IsJSTypedArray()) { 7083 return JSTypedArray::DefineOwnProperty( 7084 isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw); 7085 } 7086 7087 // OrdinaryDefineOwnProperty, by virtue of calling 7088 // DefineOwnPropertyIgnoreAttributes, can handle arguments 7089 // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc). 7090 return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key, 7091 desc, should_throw); 7092 } 7093 7094 7095 // static 7096 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate, 7097 Handle<JSObject> object, 7098 Handle<Object> key, 7099 PropertyDescriptor* desc, 7100 ShouldThrow should_throw) { 7101 bool success = false; 7102 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey... 7103 LookupIterator it = LookupIterator::PropertyOrElement( 7104 isolate, object, key, &success, LookupIterator::OWN); 7105 DCHECK(success); // ...so creating a LookupIterator can't fail. 7106 7107 // Deal with access checks first. 7108 if (it.state() == LookupIterator::ACCESS_CHECK) { 7109 if (!it.HasAccess()) { 7110 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>()); 7111 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 7112 return Just(true); 7113 } 7114 it.Next(); 7115 } 7116 7117 return OrdinaryDefineOwnProperty(&it, desc, should_throw); 7118 } 7119 7120 7121 // ES6 9.1.6.1 7122 // static 7123 Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it, 7124 PropertyDescriptor* desc, 7125 ShouldThrow should_throw) { 7126 Isolate* isolate = it->isolate(); 7127 // 1. Let current be O.[[GetOwnProperty]](P). 7128 // 2. ReturnIfAbrupt(current). 7129 PropertyDescriptor current; 7130 MAYBE_RETURN(GetOwnPropertyDescriptor(it, ¤t), Nothing<bool>()); 7131 7132 it->Restart(); 7133 // Handle interceptor 7134 for (; it->IsFound(); it->Next()) { 7135 if (it->state() == LookupIterator::INTERCEPTOR) { 7136 if (it->HolderIsReceiverOrHiddenPrototype()) { 7137 Maybe<bool> result = DefinePropertyWithInterceptorInternal( 7138 it, it->GetInterceptor(), should_throw, *desc); 7139 if (result.IsNothing() || result.FromJust()) { 7140 return result; 7141 } 7142 } 7143 } 7144 } 7145 7146 // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset 7147 // the iterator every time. Currently, the reasons why we need it are: 7148 // - handle interceptors correctly 7149 // - handle accessors correctly (which might change the holder's map) 7150 it->Restart(); 7151 // 3. Let extensible be the value of the [[Extensible]] internal slot of O. 7152 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 7153 bool extensible = JSObject::IsExtensible(object); 7154 7155 return ValidateAndApplyPropertyDescriptor( 7156 isolate, it, extensible, desc, ¤t, should_throw, Handle<Name>()); 7157 } 7158 7159 7160 // ES6 9.1.6.2 7161 // static 7162 Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor( 7163 Isolate* isolate, bool extensible, PropertyDescriptor* desc, 7164 PropertyDescriptor* current, Handle<Name> property_name, 7165 ShouldThrow should_throw) { 7166 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined, 7167 // Extensible, Desc, Current). 7168 return ValidateAndApplyPropertyDescriptor( 7169 isolate, nullptr, extensible, desc, current, should_throw, property_name); 7170 } 7171 7172 7173 // ES6 9.1.6.3 7174 // static 7175 Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor( 7176 Isolate* isolate, LookupIterator* it, bool extensible, 7177 PropertyDescriptor* desc, PropertyDescriptor* current, 7178 ShouldThrow should_throw, Handle<Name> property_name) { 7179 // We either need a LookupIterator, or a property name. 7180 DCHECK((it == nullptr) != property_name.is_null()); 7181 Handle<JSObject> object; 7182 if (it != nullptr) object = Handle<JSObject>::cast(it->GetReceiver()); 7183 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc); 7184 bool desc_is_accessor_descriptor = 7185 PropertyDescriptor::IsAccessorDescriptor(desc); 7186 bool desc_is_generic_descriptor = 7187 PropertyDescriptor::IsGenericDescriptor(desc); 7188 // 1. (Assert) 7189 // 2. If current is undefined, then 7190 if (current->is_empty()) { 7191 // 2a. If extensible is false, return false. 7192 if (!extensible) { 7193 RETURN_FAILURE( 7194 isolate, should_throw, 7195 NewTypeError(MessageTemplate::kDefineDisallowed, 7196 it != nullptr ? it->GetName() : property_name)); 7197 } 7198 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then: 7199 // (This is equivalent to !IsAccessorDescriptor(desc).) 7200 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) == 7201 !desc_is_accessor_descriptor); 7202 if (!desc_is_accessor_descriptor) { 7203 // 2c i. If O is not undefined, create an own data property named P of 7204 // object O whose [[Value]], [[Writable]], [[Enumerable]] and 7205 // [[Configurable]] attribute values are described by Desc. If the value 7206 // of an attribute field of Desc is absent, the attribute of the newly 7207 // created property is set to its default value. 7208 if (it != nullptr) { 7209 if (!desc->has_writable()) desc->set_writable(false); 7210 if (!desc->has_enumerable()) desc->set_enumerable(false); 7211 if (!desc->has_configurable()) desc->set_configurable(false); 7212 Handle<Object> value( 7213 desc->has_value() 7214 ? desc->value() 7215 : Handle<Object>::cast(isolate->factory()->undefined_value())); 7216 MaybeHandle<Object> result = 7217 JSObject::DefineOwnPropertyIgnoreAttributes(it, value, 7218 desc->ToAttributes()); 7219 if (result.is_null()) return Nothing<bool>(); 7220 } 7221 } else { 7222 // 2d. Else Desc must be an accessor Property Descriptor, 7223 DCHECK(desc_is_accessor_descriptor); 7224 // 2d i. If O is not undefined, create an own accessor property named P 7225 // of object O whose [[Get]], [[Set]], [[Enumerable]] and 7226 // [[Configurable]] attribute values are described by Desc. If the value 7227 // of an attribute field of Desc is absent, the attribute of the newly 7228 // created property is set to its default value. 7229 if (it != nullptr) { 7230 if (!desc->has_enumerable()) desc->set_enumerable(false); 7231 if (!desc->has_configurable()) desc->set_configurable(false); 7232 Handle<Object> getter( 7233 desc->has_get() 7234 ? desc->get() 7235 : Handle<Object>::cast(isolate->factory()->null_value())); 7236 Handle<Object> setter( 7237 desc->has_set() 7238 ? desc->set() 7239 : Handle<Object>::cast(isolate->factory()->null_value())); 7240 MaybeHandle<Object> result = 7241 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes()); 7242 if (result.is_null()) return Nothing<bool>(); 7243 } 7244 } 7245 // 2e. Return true. 7246 return Just(true); 7247 } 7248 // 3. Return true, if every field in Desc is absent. 7249 // 4. Return true, if every field in Desc also occurs in current and the 7250 // value of every field in Desc is the same value as the corresponding field 7251 // in current when compared using the SameValue algorithm. 7252 if ((!desc->has_enumerable() || 7253 desc->enumerable() == current->enumerable()) && 7254 (!desc->has_configurable() || 7255 desc->configurable() == current->configurable()) && 7256 (!desc->has_value() || 7257 (current->has_value() && current->value()->SameValue(*desc->value()))) && 7258 (!desc->has_writable() || 7259 (current->has_writable() && current->writable() == desc->writable())) && 7260 (!desc->has_get() || 7261 (current->has_get() && current->get()->SameValue(*desc->get()))) && 7262 (!desc->has_set() || 7263 (current->has_set() && current->set()->SameValue(*desc->set())))) { 7264 return Just(true); 7265 } 7266 // 5. If the [[Configurable]] field of current is false, then 7267 if (!current->configurable()) { 7268 // 5a. Return false, if the [[Configurable]] field of Desc is true. 7269 if (desc->has_configurable() && desc->configurable()) { 7270 RETURN_FAILURE( 7271 isolate, should_throw, 7272 NewTypeError(MessageTemplate::kRedefineDisallowed, 7273 it != nullptr ? it->GetName() : property_name)); 7274 } 7275 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the 7276 // [[Enumerable]] fields of current and Desc are the Boolean negation of 7277 // each other. 7278 if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) { 7279 RETURN_FAILURE( 7280 isolate, should_throw, 7281 NewTypeError(MessageTemplate::kRedefineDisallowed, 7282 it != nullptr ? it->GetName() : property_name)); 7283 } 7284 } 7285 7286 bool current_is_data_descriptor = 7287 PropertyDescriptor::IsDataDescriptor(current); 7288 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required. 7289 if (desc_is_generic_descriptor) { 7290 // Nothing to see here. 7291 7292 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have 7293 // different results, then: 7294 } else if (current_is_data_descriptor != desc_is_data_descriptor) { 7295 // 7a. Return false, if the [[Configurable]] field of current is false. 7296 if (!current->configurable()) { 7297 RETURN_FAILURE( 7298 isolate, should_throw, 7299 NewTypeError(MessageTemplate::kRedefineDisallowed, 7300 it != nullptr ? it->GetName() : property_name)); 7301 } 7302 // 7b. If IsDataDescriptor(current) is true, then: 7303 if (current_is_data_descriptor) { 7304 // 7b i. If O is not undefined, convert the property named P of object O 7305 // from a data property to an accessor property. Preserve the existing 7306 // values of the converted property's [[Configurable]] and [[Enumerable]] 7307 // attributes and set the rest of the property's attributes to their 7308 // default values. 7309 // --> Folded into step 10. 7310 } else { 7311 // 7c i. If O is not undefined, convert the property named P of object O 7312 // from an accessor property to a data property. Preserve the existing 7313 // values of the converted propertys [[Configurable]] and [[Enumerable]] 7314 // attributes and set the rest of the propertys attributes to their 7315 // default values. 7316 // --> Folded into step 10. 7317 } 7318 7319 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both 7320 // true, then: 7321 } else if (current_is_data_descriptor && desc_is_data_descriptor) { 7322 // 8a. If the [[Configurable]] field of current is false, then: 7323 if (!current->configurable()) { 7324 // 8a i. Return false, if the [[Writable]] field of current is false and 7325 // the [[Writable]] field of Desc is true. 7326 if (!current->writable() && desc->has_writable() && desc->writable()) { 7327 RETURN_FAILURE( 7328 isolate, should_throw, 7329 NewTypeError(MessageTemplate::kRedefineDisallowed, 7330 it != nullptr ? it->GetName() : property_name)); 7331 } 7332 // 8a ii. If the [[Writable]] field of current is false, then: 7333 if (!current->writable()) { 7334 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and 7335 // SameValue(Desc.[[Value]], current.[[Value]]) is false. 7336 if (desc->has_value() && !desc->value()->SameValue(*current->value())) { 7337 RETURN_FAILURE( 7338 isolate, should_throw, 7339 NewTypeError(MessageTemplate::kRedefineDisallowed, 7340 it != nullptr ? it->GetName() : property_name)); 7341 } 7342 } 7343 } 7344 } else { 7345 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) 7346 // are both true, 7347 DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) && 7348 desc_is_accessor_descriptor); 7349 // 9a. If the [[Configurable]] field of current is false, then: 7350 if (!current->configurable()) { 7351 // 9a i. Return false, if the [[Set]] field of Desc is present and 7352 // SameValue(Desc.[[Set]], current.[[Set]]) is false. 7353 if (desc->has_set() && !desc->set()->SameValue(*current->set())) { 7354 RETURN_FAILURE( 7355 isolate, should_throw, 7356 NewTypeError(MessageTemplate::kRedefineDisallowed, 7357 it != nullptr ? it->GetName() : property_name)); 7358 } 7359 // 9a ii. Return false, if the [[Get]] field of Desc is present and 7360 // SameValue(Desc.[[Get]], current.[[Get]]) is false. 7361 if (desc->has_get() && !desc->get()->SameValue(*current->get())) { 7362 RETURN_FAILURE( 7363 isolate, should_throw, 7364 NewTypeError(MessageTemplate::kRedefineDisallowed, 7365 it != nullptr ? it->GetName() : property_name)); 7366 } 7367 } 7368 } 7369 7370 // 10. If O is not undefined, then: 7371 if (it != nullptr) { 7372 // 10a. For each field of Desc that is present, set the corresponding 7373 // attribute of the property named P of object O to the value of the field. 7374 PropertyAttributes attrs = NONE; 7375 7376 if (desc->has_enumerable()) { 7377 attrs = static_cast<PropertyAttributes>( 7378 attrs | (desc->enumerable() ? NONE : DONT_ENUM)); 7379 } else { 7380 attrs = static_cast<PropertyAttributes>( 7381 attrs | (current->enumerable() ? NONE : DONT_ENUM)); 7382 } 7383 if (desc->has_configurable()) { 7384 attrs = static_cast<PropertyAttributes>( 7385 attrs | (desc->configurable() ? NONE : DONT_DELETE)); 7386 } else { 7387 attrs = static_cast<PropertyAttributes>( 7388 attrs | (current->configurable() ? NONE : DONT_DELETE)); 7389 } 7390 if (desc_is_data_descriptor || 7391 (desc_is_generic_descriptor && current_is_data_descriptor)) { 7392 if (desc->has_writable()) { 7393 attrs = static_cast<PropertyAttributes>( 7394 attrs | (desc->writable() ? NONE : READ_ONLY)); 7395 } else { 7396 attrs = static_cast<PropertyAttributes>( 7397 attrs | (current->writable() ? NONE : READ_ONLY)); 7398 } 7399 Handle<Object> value( 7400 desc->has_value() ? desc->value() 7401 : current->has_value() 7402 ? current->value() 7403 : Handle<Object>::cast( 7404 isolate->factory()->undefined_value())); 7405 return JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs, 7406 should_throw); 7407 } else { 7408 DCHECK(desc_is_accessor_descriptor || 7409 (desc_is_generic_descriptor && 7410 PropertyDescriptor::IsAccessorDescriptor(current))); 7411 Handle<Object> getter( 7412 desc->has_get() 7413 ? desc->get() 7414 : current->has_get() 7415 ? current->get() 7416 : Handle<Object>::cast(isolate->factory()->null_value())); 7417 Handle<Object> setter( 7418 desc->has_set() 7419 ? desc->set() 7420 : current->has_set() 7421 ? current->set() 7422 : Handle<Object>::cast(isolate->factory()->null_value())); 7423 MaybeHandle<Object> result = 7424 JSObject::DefineAccessor(it, getter, setter, attrs); 7425 if (result.is_null()) return Nothing<bool>(); 7426 } 7427 } 7428 7429 // 11. Return true. 7430 return Just(true); 7431 } 7432 7433 // static 7434 Maybe<bool> JSReceiver::CreateDataProperty(Isolate* isolate, 7435 Handle<JSReceiver> object, 7436 Handle<Name> key, 7437 Handle<Object> value, 7438 ShouldThrow should_throw) { 7439 LookupIterator it = LookupIterator::PropertyOrElement(isolate, object, key, 7440 LookupIterator::OWN); 7441 return CreateDataProperty(&it, value, should_throw); 7442 } 7443 7444 // static 7445 Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it, 7446 Handle<Object> value, 7447 ShouldThrow should_throw) { 7448 DCHECK(!it->check_prototype_chain()); 7449 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 7450 Isolate* isolate = receiver->GetIsolate(); 7451 7452 if (receiver->IsJSObject()) { 7453 return JSObject::CreateDataProperty(it, value, should_throw); // Shortcut. 7454 } 7455 7456 PropertyDescriptor new_desc; 7457 new_desc.set_value(value); 7458 new_desc.set_writable(true); 7459 new_desc.set_enumerable(true); 7460 new_desc.set_configurable(true); 7461 7462 return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(), 7463 &new_desc, should_throw); 7464 } 7465 7466 Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it, 7467 Handle<Object> value, 7468 ShouldThrow should_throw) { 7469 DCHECK(it->GetReceiver()->IsJSObject()); 7470 MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>()); 7471 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); 7472 Isolate* isolate = receiver->GetIsolate(); 7473 7474 if (it->IsFound()) { 7475 Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it); 7476 MAYBE_RETURN(attributes, Nothing<bool>()); 7477 if ((attributes.FromJust() & DONT_DELETE) != 0) { 7478 RETURN_FAILURE( 7479 isolate, should_throw, 7480 NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName())); 7481 } 7482 } else { 7483 if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) { 7484 RETURN_FAILURE( 7485 isolate, should_throw, 7486 NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName())); 7487 } 7488 } 7489 7490 RETURN_ON_EXCEPTION_VALUE(it->isolate(), 7491 DefineOwnPropertyIgnoreAttributes(it, value, NONE), 7492 Nothing<bool>()); 7493 7494 return Just(true); 7495 } 7496 7497 // TODO(jkummerow): Consider unification with FastAsArrayLength() in 7498 // accessors.cc. 7499 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) { 7500 DCHECK(value->IsNumber() || value->IsName()); 7501 if (value->ToArrayLength(length)) return true; 7502 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length); 7503 return false; 7504 } 7505 7506 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) { 7507 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32; 7508 } 7509 7510 7511 // ES6 9.4.2.1 7512 // static 7513 Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o, 7514 Handle<Object> name, 7515 PropertyDescriptor* desc, 7516 ShouldThrow should_throw) { 7517 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.) 7518 // 2. If P is "length", then: 7519 // TODO(jkummerow): Check if we need slow string comparison. 7520 if (*name == ReadOnlyRoots(isolate).length_string()) { 7521 // 2a. Return ArraySetLength(A, Desc). 7522 return ArraySetLength(isolate, o, desc, should_throw); 7523 } 7524 // 3. Else if P is an array index, then: 7525 uint32_t index = 0; 7526 if (PropertyKeyToArrayIndex(name, &index)) { 7527 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). 7528 PropertyDescriptor old_len_desc; 7529 Maybe<bool> success = GetOwnPropertyDescriptor( 7530 isolate, o, isolate->factory()->length_string(), &old_len_desc); 7531 // 3b. (Assert) 7532 DCHECK(success.FromJust()); 7533 USE(success); 7534 // 3c. Let oldLen be oldLenDesc.[[Value]]. 7535 uint32_t old_len = 0; 7536 CHECK(old_len_desc.value()->ToArrayLength(&old_len)); 7537 // 3d. Let index be ToUint32(P). 7538 // (Already done above.) 7539 // 3e. (Assert) 7540 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false, 7541 // return false. 7542 if (index >= old_len && old_len_desc.has_writable() && 7543 !old_len_desc.writable()) { 7544 RETURN_FAILURE(isolate, should_throw, 7545 NewTypeError(MessageTemplate::kDefineDisallowed, name)); 7546 } 7547 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc). 7548 Maybe<bool> succeeded = 7549 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); 7550 // 3h. Assert: succeeded is not an abrupt completion. 7551 // In our case, if should_throw == kThrowOnError, it can be! 7552 // 3i. If succeeded is false, return false. 7553 if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded; 7554 // 3j. If index >= oldLen, then: 7555 if (index >= old_len) { 7556 // 3j i. Set oldLenDesc.[[Value]] to index + 1. 7557 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1)); 7558 // 3j ii. Let succeeded be 7559 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc). 7560 succeeded = OrdinaryDefineOwnProperty(isolate, o, 7561 isolate->factory()->length_string(), 7562 &old_len_desc, should_throw); 7563 // 3j iii. Assert: succeeded is true. 7564 DCHECK(succeeded.FromJust()); 7565 USE(succeeded); 7566 } 7567 // 3k. Return true. 7568 return Just(true); 7569 } 7570 7571 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc). 7572 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); 7573 } 7574 7575 7576 // Part of ES6 9.4.2.4 ArraySetLength. 7577 // static 7578 bool JSArray::AnythingToArrayLength(Isolate* isolate, 7579 Handle<Object> length_object, 7580 uint32_t* output) { 7581 // Fast path: check numbers and strings that can be converted directly 7582 // and unobservably. 7583 if (length_object->ToArrayLength(output)) return true; 7584 if (length_object->IsString() && 7585 Handle<String>::cast(length_object)->AsArrayIndex(output)) { 7586 return true; 7587 } 7588 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength". 7589 // 3. Let newLen be ToUint32(Desc.[[Value]]). 7590 Handle<Object> uint32_v; 7591 if (!Object::ToUint32(isolate, length_object).ToHandle(&uint32_v)) { 7592 // 4. ReturnIfAbrupt(newLen). 7593 return false; 7594 } 7595 // 5. Let numberLen be ToNumber(Desc.[[Value]]). 7596 Handle<Object> number_v; 7597 if (!Object::ToNumber(isolate, length_object).ToHandle(&number_v)) { 7598 // 6. ReturnIfAbrupt(newLen). 7599 return false; 7600 } 7601 // 7. If newLen != numberLen, throw a RangeError exception. 7602 if (uint32_v->Number() != number_v->Number()) { 7603 Handle<Object> exception = 7604 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength); 7605 isolate->Throw(*exception); 7606 return false; 7607 } 7608 CHECK(uint32_v->ToArrayLength(output)); 7609 return true; 7610 } 7611 7612 7613 // ES6 9.4.2.4 7614 // static 7615 Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a, 7616 PropertyDescriptor* desc, 7617 ShouldThrow should_throw) { 7618 // 1. If the [[Value]] field of Desc is absent, then 7619 if (!desc->has_value()) { 7620 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc). 7621 return OrdinaryDefineOwnProperty( 7622 isolate, a, isolate->factory()->length_string(), desc, should_throw); 7623 } 7624 // 2. Let newLenDesc be a copy of Desc. 7625 // (Actual copying is not necessary.) 7626 PropertyDescriptor* new_len_desc = desc; 7627 // 3. - 7. Convert Desc.[[Value]] to newLen. 7628 uint32_t new_len = 0; 7629 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) { 7630 DCHECK(isolate->has_pending_exception()); 7631 return Nothing<bool>(); 7632 } 7633 // 8. Set newLenDesc.[[Value]] to newLen. 7634 // (Done below, if needed.) 7635 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). 7636 PropertyDescriptor old_len_desc; 7637 Maybe<bool> success = GetOwnPropertyDescriptor( 7638 isolate, a, isolate->factory()->length_string(), &old_len_desc); 7639 // 10. (Assert) 7640 DCHECK(success.FromJust()); 7641 USE(success); 7642 // 11. Let oldLen be oldLenDesc.[[Value]]. 7643 uint32_t old_len = 0; 7644 CHECK(old_len_desc.value()->ToArrayLength(&old_len)); 7645 // 12. If newLen >= oldLen, then 7646 if (new_len >= old_len) { 7647 // 8. Set newLenDesc.[[Value]] to newLen. 7648 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc). 7649 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len)); 7650 return OrdinaryDefineOwnProperty(isolate, a, 7651 isolate->factory()->length_string(), 7652 new_len_desc, should_throw); 7653 } 7654 // 13. If oldLenDesc.[[Writable]] is false, return false. 7655 if (!old_len_desc.writable()) { 7656 RETURN_FAILURE(isolate, should_throw, 7657 NewTypeError(MessageTemplate::kRedefineDisallowed, 7658 isolate->factory()->length_string())); 7659 } 7660 // 14. If newLenDesc.[[Writable]] is absent or has the value true, 7661 // let newWritable be true. 7662 bool new_writable = false; 7663 if (!new_len_desc->has_writable() || new_len_desc->writable()) { 7664 new_writable = true; 7665 } else { 7666 // 15. Else, 7667 // 15a. Need to defer setting the [[Writable]] attribute to false in case 7668 // any elements cannot be deleted. 7669 // 15b. Let newWritable be false. (It's initialized as "false" anyway.) 7670 // 15c. Set newLenDesc.[[Writable]] to true. 7671 // (Not needed.) 7672 } 7673 // Most of steps 16 through 19 is implemented by JSArray::SetLength. 7674 JSArray::SetLength(a, new_len); 7675 // Steps 19d-ii, 20. 7676 if (!new_writable) { 7677 PropertyDescriptor readonly; 7678 readonly.set_writable(false); 7679 Maybe<bool> success = OrdinaryDefineOwnProperty( 7680 isolate, a, isolate->factory()->length_string(), &readonly, 7681 should_throw); 7682 DCHECK(success.FromJust()); 7683 USE(success); 7684 } 7685 uint32_t actual_new_len = 0; 7686 CHECK(a->length()->ToArrayLength(&actual_new_len)); 7687 // Steps 19d-v, 21. Return false if there were non-deletable elements. 7688 bool result = actual_new_len == new_len; 7689 if (!result) { 7690 RETURN_FAILURE( 7691 isolate, should_throw, 7692 NewTypeError(MessageTemplate::kStrictDeleteProperty, 7693 isolate->factory()->NewNumberFromUint(actual_new_len - 1), 7694 a)); 7695 } 7696 return Just(result); 7697 } 7698 7699 7700 // ES6 9.5.6 7701 // static 7702 Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy, 7703 Handle<Object> key, 7704 PropertyDescriptor* desc, 7705 ShouldThrow should_throw) { 7706 STACK_CHECK(isolate, Nothing<bool>()); 7707 if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) { 7708 DCHECK(!Handle<Symbol>::cast(key)->IsPrivateField()); 7709 return JSProxy::SetPrivateSymbol(isolate, proxy, Handle<Symbol>::cast(key), 7710 desc, should_throw); 7711 } 7712 Handle<String> trap_name = isolate->factory()->defineProperty_string(); 7713 // 1. Assert: IsPropertyKey(P) is true. 7714 DCHECK(key->IsName() || key->IsNumber()); 7715 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 7716 Handle<Object> handler(proxy->handler(), isolate); 7717 // 3. If handler is null, throw a TypeError exception. 7718 // 4. Assert: Type(handler) is Object. 7719 if (proxy->IsRevoked()) { 7720 isolate->Throw(*isolate->factory()->NewTypeError( 7721 MessageTemplate::kProxyRevoked, trap_name)); 7722 return Nothing<bool>(); 7723 } 7724 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 7725 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 7726 // 6. Let trap be ? GetMethod(handler, "defineProperty"). 7727 Handle<Object> trap; 7728 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7729 isolate, trap, 7730 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 7731 Nothing<bool>()); 7732 // 7. If trap is undefined, then: 7733 if (trap->IsUndefined(isolate)) { 7734 // 7a. Return target.[[DefineOwnProperty]](P, Desc). 7735 return JSReceiver::DefineOwnProperty(isolate, target, key, desc, 7736 should_throw); 7737 } 7738 // 8. Let descObj be FromPropertyDescriptor(Desc). 7739 Handle<Object> desc_obj = desc->ToObject(isolate); 7740 // 9. Let booleanTrapResult be 7741 // ToBoolean(? Call(trap, handler, target, P, descObj)). 7742 Handle<Name> property_name = 7743 key->IsName() 7744 ? Handle<Name>::cast(key) 7745 : Handle<Name>::cast(isolate->factory()->NumberToString(key)); 7746 // Do not leak private property names. 7747 DCHECK(!property_name->IsPrivate()); 7748 Handle<Object> trap_result_obj; 7749 Handle<Object> args[] = {target, property_name, desc_obj}; 7750 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 7751 isolate, trap_result_obj, 7752 Execution::Call(isolate, trap, handler, arraysize(args), args), 7753 Nothing<bool>()); 7754 // 10. If booleanTrapResult is false, return false. 7755 if (!trap_result_obj->BooleanValue(isolate)) { 7756 RETURN_FAILURE(isolate, should_throw, 7757 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, 7758 trap_name, property_name)); 7759 } 7760 // 11. Let targetDesc be ? target.[[GetOwnProperty]](P). 7761 PropertyDescriptor target_desc; 7762 Maybe<bool> target_found = 7763 JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc); 7764 MAYBE_RETURN(target_found, Nothing<bool>()); 7765 // 12. Let extensibleTarget be ? IsExtensible(target). 7766 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target); 7767 MAYBE_RETURN(maybe_extensible, Nothing<bool>()); 7768 bool extensible_target = maybe_extensible.FromJust(); 7769 // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] 7770 // is false, then: 7771 // 13a. Let settingConfigFalse be true. 7772 // 14. Else let settingConfigFalse be false. 7773 bool setting_config_false = desc->has_configurable() && !desc->configurable(); 7774 // 15. If targetDesc is undefined, then 7775 if (!target_found.FromJust()) { 7776 // 15a. If extensibleTarget is false, throw a TypeError exception. 7777 if (!extensible_target) { 7778 isolate->Throw(*isolate->factory()->NewTypeError( 7779 MessageTemplate::kProxyDefinePropertyNonExtensible, property_name)); 7780 return Nothing<bool>(); 7781 } 7782 // 15b. If settingConfigFalse is true, throw a TypeError exception. 7783 if (setting_config_false) { 7784 isolate->Throw(*isolate->factory()->NewTypeError( 7785 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); 7786 return Nothing<bool>(); 7787 } 7788 } else { 7789 // 16. Else targetDesc is not undefined, 7790 // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, 7791 // targetDesc) is false, throw a TypeError exception. 7792 Maybe<bool> valid = 7793 IsCompatiblePropertyDescriptor(isolate, extensible_target, desc, 7794 &target_desc, property_name, kDontThrow); 7795 MAYBE_RETURN(valid, Nothing<bool>()); 7796 if (!valid.FromJust()) { 7797 isolate->Throw(*isolate->factory()->NewTypeError( 7798 MessageTemplate::kProxyDefinePropertyIncompatible, property_name)); 7799 return Nothing<bool>(); 7800 } 7801 // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is 7802 // true, throw a TypeError exception. 7803 if (setting_config_false && target_desc.configurable()) { 7804 isolate->Throw(*isolate->factory()->NewTypeError( 7805 MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); 7806 return Nothing<bool>(); 7807 } 7808 } 7809 // 17. Return true. 7810 return Just(true); 7811 } 7812 7813 // static 7814 Maybe<bool> JSProxy::SetPrivateSymbol(Isolate* isolate, Handle<JSProxy> proxy, 7815 Handle<Symbol> private_name, 7816 PropertyDescriptor* desc, 7817 ShouldThrow should_throw) { 7818 DCHECK(!private_name->IsPrivateField()); 7819 // Despite the generic name, this can only add private data properties. 7820 if (!PropertyDescriptor::IsDataDescriptor(desc) || 7821 desc->ToAttributes() != DONT_ENUM) { 7822 RETURN_FAILURE(isolate, should_throw, 7823 NewTypeError(MessageTemplate::kProxyPrivate)); 7824 } 7825 DCHECK(proxy->map()->is_dictionary_map()); 7826 Handle<Object> value = 7827 desc->has_value() 7828 ? desc->value() 7829 : Handle<Object>::cast(isolate->factory()->undefined_value()); 7830 7831 LookupIterator it(proxy, private_name, proxy); 7832 7833 if (it.IsFound()) { 7834 DCHECK_EQ(LookupIterator::DATA, it.state()); 7835 DCHECK_EQ(DONT_ENUM, it.property_attributes()); 7836 it.WriteDataValue(value, false); 7837 return Just(true); 7838 } 7839 7840 Handle<NameDictionary> dict(proxy->property_dictionary(), isolate); 7841 PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell); 7842 Handle<NameDictionary> result = 7843 NameDictionary::Add(isolate, dict, private_name, value, details); 7844 if (!dict.is_identical_to(result)) proxy->SetProperties(*result); 7845 return Just(true); 7846 } 7847 7848 // static 7849 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate, 7850 Handle<JSReceiver> object, 7851 Handle<Object> key, 7852 PropertyDescriptor* desc) { 7853 bool success = false; 7854 DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey... 7855 LookupIterator it = LookupIterator::PropertyOrElement( 7856 isolate, object, key, &success, LookupIterator::OWN); 7857 DCHECK(success); // ...so creating a LookupIterator can't fail. 7858 return GetOwnPropertyDescriptor(&it, desc); 7859 } 7860 7861 namespace { 7862 7863 Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it, 7864 PropertyDescriptor* desc) { 7865 if (it->state() == LookupIterator::ACCESS_CHECK) { 7866 if (it->HasAccess()) { 7867 it->Next(); 7868 } else if (!JSObject::AllCanRead(it) || 7869 it->state() != LookupIterator::INTERCEPTOR) { 7870 it->Restart(); 7871 return Just(false); 7872 } 7873 } 7874 7875 if (it->state() != LookupIterator::INTERCEPTOR) return Just(false); 7876 7877 Isolate* isolate = it->isolate(); 7878 Handle<InterceptorInfo> interceptor = it->GetInterceptor(); 7879 if (interceptor->descriptor()->IsUndefined(isolate)) return Just(false); 7880 7881 Handle<Object> result; 7882 Handle<JSObject> holder = it->GetHolder<JSObject>(); 7883 7884 Handle<Object> receiver = it->GetReceiver(); 7885 if (!receiver->IsJSReceiver()) { 7886 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, 7887 Object::ConvertReceiver(isolate, receiver), 7888 Nothing<bool>()); 7889 } 7890 7891 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, 7892 *holder, kDontThrow); 7893 if (it->IsElement()) { 7894 result = args.CallIndexedDescriptor(interceptor, it->index()); 7895 } else { 7896 result = args.CallNamedDescriptor(interceptor, it->name()); 7897 } 7898 if (!result.is_null()) { 7899 // Request successfully intercepted, try to set the property 7900 // descriptor. 7901 Utils::ApiCheck( 7902 PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc), 7903 it->IsElement() ? "v8::IndexedPropertyDescriptorCallback" 7904 : "v8::NamedPropertyDescriptorCallback", 7905 "Invalid property descriptor."); 7906 7907 return Just(true); 7908 } 7909 7910 it->Next(); 7911 return Just(false); 7912 } 7913 } // namespace 7914 7915 // ES6 9.1.5.1 7916 // Returns true on success, false if the property didn't exist, nothing if 7917 // an exception was thrown. 7918 // static 7919 Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it, 7920 PropertyDescriptor* desc) { 7921 Isolate* isolate = it->isolate(); 7922 // "Virtual" dispatch. 7923 if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) { 7924 return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(), 7925 it->GetName(), desc); 7926 } 7927 7928 Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc); 7929 MAYBE_RETURN(intercepted, Nothing<bool>()); 7930 if (intercepted.FromJust()) { 7931 return Just(true); 7932 } 7933 7934 // Request was not intercepted, continue as normal. 7935 // 1. (Assert) 7936 // 2. If O does not have an own property with key P, return undefined. 7937 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it); 7938 MAYBE_RETURN(maybe, Nothing<bool>()); 7939 PropertyAttributes attrs = maybe.FromJust(); 7940 if (attrs == ABSENT) return Just(false); 7941 DCHECK(!isolate->has_pending_exception()); 7942 7943 // 3. Let D be a newly created Property Descriptor with no fields. 7944 DCHECK(desc->is_empty()); 7945 // 4. Let X be O's own property whose key is P. 7946 // 5. If X is a data property, then 7947 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR && 7948 it->GetAccessors()->IsAccessorPair(); 7949 if (!is_accessor_pair) { 7950 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute. 7951 Handle<Object> value; 7952 if (!Object::GetProperty(it).ToHandle(&value)) { 7953 DCHECK(isolate->has_pending_exception()); 7954 return Nothing<bool>(); 7955 } 7956 desc->set_value(value); 7957 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute 7958 desc->set_writable((attrs & READ_ONLY) == 0); 7959 } else { 7960 // 6. Else X is an accessor property, so 7961 Handle<AccessorPair> accessors = 7962 Handle<AccessorPair>::cast(it->GetAccessors()); 7963 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute. 7964 desc->set_get( 7965 AccessorPair::GetComponent(isolate, accessors, ACCESSOR_GETTER)); 7966 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute. 7967 desc->set_set( 7968 AccessorPair::GetComponent(isolate, accessors, ACCESSOR_SETTER)); 7969 } 7970 7971 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute. 7972 desc->set_enumerable((attrs & DONT_ENUM) == 0); 7973 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute. 7974 desc->set_configurable((attrs & DONT_DELETE) == 0); 7975 // 9. Return D. 7976 DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) != 7977 PropertyDescriptor::IsDataDescriptor(desc)); 7978 return Just(true); 7979 } 7980 7981 7982 // ES6 9.5.5 7983 // static 7984 Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate, 7985 Handle<JSProxy> proxy, 7986 Handle<Name> name, 7987 PropertyDescriptor* desc) { 7988 DCHECK(!name->IsPrivate()); 7989 STACK_CHECK(isolate, Nothing<bool>()); 7990 7991 Handle<String> trap_name = 7992 isolate->factory()->getOwnPropertyDescriptor_string(); 7993 // 1. (Assert) 7994 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 7995 Handle<Object> handler(proxy->handler(), isolate); 7996 // 3. If handler is null, throw a TypeError exception. 7997 // 4. Assert: Type(handler) is Object. 7998 if (proxy->IsRevoked()) { 7999 isolate->Throw(*isolate->factory()->NewTypeError( 8000 MessageTemplate::kProxyRevoked, trap_name)); 8001 return Nothing<bool>(); 8002 } 8003 // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. 8004 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 8005 // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor"). 8006 Handle<Object> trap; 8007 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8008 isolate, trap, 8009 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 8010 Nothing<bool>()); 8011 // 7. If trap is undefined, then 8012 if (trap->IsUndefined(isolate)) { 8013 // 7a. Return target.[[GetOwnProperty]](P). 8014 return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc); 8015 } 8016 // 8. Let trapResultObj be ? Call(trap, handler, target, P). 8017 Handle<Object> trap_result_obj; 8018 Handle<Object> args[] = {target, name}; 8019 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8020 isolate, trap_result_obj, 8021 Execution::Call(isolate, trap, handler, arraysize(args), args), 8022 Nothing<bool>()); 8023 // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a 8024 // TypeError exception. 8025 if (!trap_result_obj->IsJSReceiver() && 8026 !trap_result_obj->IsUndefined(isolate)) { 8027 isolate->Throw(*isolate->factory()->NewTypeError( 8028 MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name)); 8029 return Nothing<bool>(); 8030 } 8031 // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). 8032 PropertyDescriptor target_desc; 8033 Maybe<bool> found = 8034 JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); 8035 MAYBE_RETURN(found, Nothing<bool>()); 8036 // 11. If trapResultObj is undefined, then 8037 if (trap_result_obj->IsUndefined(isolate)) { 8038 // 11a. If targetDesc is undefined, return undefined. 8039 if (!found.FromJust()) return Just(false); 8040 // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError 8041 // exception. 8042 if (!target_desc.configurable()) { 8043 isolate->Throw(*isolate->factory()->NewTypeError( 8044 MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name)); 8045 return Nothing<bool>(); 8046 } 8047 // 11c. Let extensibleTarget be ? IsExtensible(target). 8048 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 8049 MAYBE_RETURN(extensible_target, Nothing<bool>()); 8050 // 11d. (Assert) 8051 // 11e. If extensibleTarget is false, throw a TypeError exception. 8052 if (!extensible_target.FromJust()) { 8053 isolate->Throw(*isolate->factory()->NewTypeError( 8054 MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name)); 8055 return Nothing<bool>(); 8056 } 8057 // 11f. Return undefined. 8058 return Just(false); 8059 } 8060 // 12. Let extensibleTarget be ? IsExtensible(target). 8061 Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); 8062 MAYBE_RETURN(extensible_target, Nothing<bool>()); 8063 // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj). 8064 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj, 8065 desc)) { 8066 DCHECK(isolate->has_pending_exception()); 8067 return Nothing<bool>(); 8068 } 8069 // 14. Call CompletePropertyDescriptor(resultDesc). 8070 PropertyDescriptor::CompletePropertyDescriptor(isolate, desc); 8071 // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget, 8072 // resultDesc, targetDesc). 8073 Maybe<bool> valid = 8074 IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(), 8075 desc, &target_desc, name, kDontThrow); 8076 MAYBE_RETURN(valid, Nothing<bool>()); 8077 // 16. If valid is false, throw a TypeError exception. 8078 if (!valid.FromJust()) { 8079 isolate->Throw(*isolate->factory()->NewTypeError( 8080 MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name)); 8081 return Nothing<bool>(); 8082 } 8083 // 17. If resultDesc.[[Configurable]] is false, then 8084 if (!desc->configurable()) { 8085 // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true: 8086 if (target_desc.is_empty() || target_desc.configurable()) { 8087 // 17a i. Throw a TypeError exception. 8088 isolate->Throw(*isolate->factory()->NewTypeError( 8089 MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable, 8090 name)); 8091 return Nothing<bool>(); 8092 } 8093 } 8094 // 18. Return resultDesc. 8095 return Just(true); 8096 } 8097 8098 8099 bool JSObject::ReferencesObjectFromElements(FixedArray* elements, 8100 ElementsKind kind, 8101 Object* object) { 8102 Isolate* isolate = GetIsolate(); 8103 if (IsObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) { 8104 int length = IsJSArray() ? Smi::ToInt(JSArray::cast(this)->length()) 8105 : elements->length(); 8106 for (int i = 0; i < length; ++i) { 8107 Object* element = elements->get(i); 8108 if (!element->IsTheHole(isolate) && element == object) return true; 8109 } 8110 } else { 8111 DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS); 8112 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object); 8113 if (!key->IsUndefined(isolate)) return true; 8114 } 8115 return false; 8116 } 8117 8118 8119 // Check whether this object references another object. 8120 bool JSObject::ReferencesObject(Object* obj) { 8121 Map* map_of_this = map(); 8122 Heap* heap = GetHeap(); 8123 DisallowHeapAllocation no_allocation; 8124 8125 // Is the object the constructor for this object? 8126 if (map_of_this->GetConstructor() == obj) { 8127 return true; 8128 } 8129 8130 // Is the object the prototype for this object? 8131 if (map_of_this->prototype() == obj) { 8132 return true; 8133 } 8134 8135 // Check if the object is among the named properties. 8136 Object* key = SlowReverseLookup(obj); 8137 if (!key->IsUndefined(heap->isolate())) { 8138 return true; 8139 } 8140 8141 // Check if the object is among the indexed properties. 8142 ElementsKind kind = GetElementsKind(); 8143 switch (kind) { 8144 // Raw pixels and external arrays do not reference other 8145 // objects. 8146 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ 8147 case TYPE##_ELEMENTS: \ 8148 break; 8149 8150 TYPED_ARRAYS(TYPED_ARRAY_CASE) 8151 #undef TYPED_ARRAY_CASE 8152 8153 case PACKED_DOUBLE_ELEMENTS: 8154 case HOLEY_DOUBLE_ELEMENTS: 8155 break; 8156 case PACKED_SMI_ELEMENTS: 8157 case HOLEY_SMI_ELEMENTS: 8158 break; 8159 case PACKED_ELEMENTS: 8160 case HOLEY_ELEMENTS: 8161 case DICTIONARY_ELEMENTS: 8162 case FAST_STRING_WRAPPER_ELEMENTS: 8163 case SLOW_STRING_WRAPPER_ELEMENTS: { 8164 FixedArray* elements = FixedArray::cast(this->elements()); 8165 if (ReferencesObjectFromElements(elements, kind, obj)) return true; 8166 break; 8167 } 8168 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 8169 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { 8170 SloppyArgumentsElements* elements = 8171 SloppyArgumentsElements::cast(this->elements()); 8172 // Check the mapped parameters. 8173 for (uint32_t i = 0; i < elements->parameter_map_length(); ++i) { 8174 Object* value = elements->get_mapped_entry(i); 8175 if (!value->IsTheHole(heap->isolate()) && value == obj) return true; 8176 } 8177 // Check the arguments. 8178 FixedArray* arguments = elements->arguments(); 8179 kind = arguments->IsNumberDictionary() ? DICTIONARY_ELEMENTS 8180 : HOLEY_ELEMENTS; 8181 if (ReferencesObjectFromElements(arguments, kind, obj)) return true; 8182 break; 8183 } 8184 case NO_ELEMENTS: 8185 break; 8186 } 8187 8188 // For functions check the context. 8189 if (IsJSFunction()) { 8190 // Get the constructor function for arguments array. 8191 Map* arguments_map = 8192 heap->isolate()->context()->native_context()->sloppy_arguments_map(); 8193 JSFunction* arguments_function = 8194 JSFunction::cast(arguments_map->GetConstructor()); 8195 8196 // Get the context and don't check if it is the native context. 8197 JSFunction* f = JSFunction::cast(this); 8198 Context* context = f->context(); 8199 if (context->IsNativeContext()) { 8200 return false; 8201 } 8202 8203 // Check the non-special context slots. 8204 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) { 8205 // Only check JS objects. 8206 if (context->get(i)->IsJSObject()) { 8207 JSObject* ctxobj = JSObject::cast(context->get(i)); 8208 // If it is an arguments array check the content. 8209 if (ctxobj->map()->GetConstructor() == arguments_function) { 8210 if (ctxobj->ReferencesObject(obj)) { 8211 return true; 8212 } 8213 } else if (ctxobj == obj) { 8214 return true; 8215 } 8216 } 8217 } 8218 8219 // Check the context extension (if any) if it can have references. 8220 if (context->has_extension() && !context->IsCatchContext() && 8221 !context->IsModuleContext()) { 8222 // With harmony scoping, a JSFunction may have a script context. 8223 // TODO(mvstanton): walk into the ScopeInfo. 8224 if (context->IsScriptContext()) { 8225 return false; 8226 } 8227 8228 return context->extension_object()->ReferencesObject(obj); 8229 } 8230 } 8231 8232 // No references to object. 8233 return false; 8234 } 8235 8236 8237 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver, 8238 IntegrityLevel level, 8239 ShouldThrow should_throw) { 8240 DCHECK(level == SEALED || level == FROZEN); 8241 8242 if (receiver->IsJSObject()) { 8243 Handle<JSObject> object = Handle<JSObject>::cast(receiver); 8244 8245 if (!object->HasSloppyArgumentsElements() && 8246 !object->IsJSModuleNamespace()) { // Fast path. 8247 // Prevent memory leaks by not adding unnecessary transitions. 8248 Maybe<bool> test = JSObject::TestIntegrityLevel(object, level); 8249 MAYBE_RETURN(test, Nothing<bool>()); 8250 if (test.FromJust()) return test; 8251 8252 if (level == SEALED) { 8253 return JSObject::PreventExtensionsWithTransition<SEALED>(object, 8254 should_throw); 8255 } else { 8256 return JSObject::PreventExtensionsWithTransition<FROZEN>(object, 8257 should_throw); 8258 } 8259 } 8260 } 8261 8262 Isolate* isolate = receiver->GetIsolate(); 8263 8264 MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw), 8265 Nothing<bool>()); 8266 8267 Handle<FixedArray> keys; 8268 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8269 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>()); 8270 8271 PropertyDescriptor no_conf; 8272 no_conf.set_configurable(false); 8273 8274 PropertyDescriptor no_conf_no_write; 8275 no_conf_no_write.set_configurable(false); 8276 no_conf_no_write.set_writable(false); 8277 8278 if (level == SEALED) { 8279 for (int i = 0; i < keys->length(); ++i) { 8280 Handle<Object> key(keys->get(i), isolate); 8281 MAYBE_RETURN( 8282 DefineOwnProperty(isolate, receiver, key, &no_conf, kThrowOnError), 8283 Nothing<bool>()); 8284 } 8285 return Just(true); 8286 } 8287 8288 for (int i = 0; i < keys->length(); ++i) { 8289 Handle<Object> key(keys->get(i), isolate); 8290 PropertyDescriptor current_desc; 8291 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( 8292 isolate, receiver, key, ¤t_desc); 8293 MAYBE_RETURN(owned, Nothing<bool>()); 8294 if (owned.FromJust()) { 8295 PropertyDescriptor desc = 8296 PropertyDescriptor::IsAccessorDescriptor(¤t_desc) 8297 ? no_conf 8298 : no_conf_no_write; 8299 MAYBE_RETURN( 8300 DefineOwnProperty(isolate, receiver, key, &desc, kThrowOnError), 8301 Nothing<bool>()); 8302 } 8303 } 8304 return Just(true); 8305 } 8306 8307 namespace { 8308 8309 template <typename Dictionary> 8310 bool TestDictionaryPropertiesIntegrityLevel(Dictionary* dict, 8311 ReadOnlyRoots roots, 8312 PropertyAttributes level) { 8313 DCHECK(level == SEALED || level == FROZEN); 8314 8315 uint32_t capacity = dict->Capacity(); 8316 for (uint32_t i = 0; i < capacity; i++) { 8317 Object* key; 8318 if (!dict->ToKey(roots, i, &key)) continue; 8319 if (key->FilterKey(ALL_PROPERTIES)) continue; 8320 PropertyDetails details = dict->DetailsAt(i); 8321 if (details.IsConfigurable()) return false; 8322 if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) { 8323 return false; 8324 } 8325 } 8326 return true; 8327 } 8328 8329 bool TestFastPropertiesIntegrityLevel(Map* map, PropertyAttributes level) { 8330 DCHECK(level == SEALED || level == FROZEN); 8331 DCHECK(!map->IsCustomElementsReceiverMap()); 8332 DCHECK(!map->is_dictionary_map()); 8333 8334 DescriptorArray* descriptors = map->instance_descriptors(); 8335 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 8336 for (int i = 0; i < number_of_own_descriptors; i++) { 8337 if (descriptors->GetKey(i)->IsPrivate()) continue; 8338 PropertyDetails details = descriptors->GetDetails(i); 8339 if (details.IsConfigurable()) return false; 8340 if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) { 8341 return false; 8342 } 8343 } 8344 return true; 8345 } 8346 8347 bool TestPropertiesIntegrityLevel(JSObject* object, PropertyAttributes level) { 8348 DCHECK(!object->map()->IsCustomElementsReceiverMap()); 8349 8350 if (object->HasFastProperties()) { 8351 return TestFastPropertiesIntegrityLevel(object->map(), level); 8352 } 8353 8354 return TestDictionaryPropertiesIntegrityLevel( 8355 object->property_dictionary(), object->GetReadOnlyRoots(), level); 8356 } 8357 8358 bool TestElementsIntegrityLevel(JSObject* object, PropertyAttributes level) { 8359 DCHECK(!object->HasSloppyArgumentsElements()); 8360 8361 ElementsKind kind = object->GetElementsKind(); 8362 8363 if (IsDictionaryElementsKind(kind)) { 8364 return TestDictionaryPropertiesIntegrityLevel( 8365 NumberDictionary::cast(object->elements()), object->GetReadOnlyRoots(), 8366 level); 8367 } 8368 8369 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); 8370 // Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have 8371 // PropertyAttributes so just test if empty 8372 return accessor->NumberOfElements(object) == 0; 8373 } 8374 8375 bool FastTestIntegrityLevel(JSObject* object, PropertyAttributes level) { 8376 DCHECK(!object->map()->IsCustomElementsReceiverMap()); 8377 8378 return !object->map()->is_extensible() && 8379 TestElementsIntegrityLevel(object, level) && 8380 TestPropertiesIntegrityLevel(object, level); 8381 } 8382 8383 Maybe<bool> GenericTestIntegrityLevel(Handle<JSReceiver> receiver, 8384 PropertyAttributes level) { 8385 DCHECK(level == SEALED || level == FROZEN); 8386 8387 Maybe<bool> extensible = JSReceiver::IsExtensible(receiver); 8388 MAYBE_RETURN(extensible, Nothing<bool>()); 8389 if (extensible.FromJust()) return Just(false); 8390 8391 Isolate* isolate = receiver->GetIsolate(); 8392 8393 Handle<FixedArray> keys; 8394 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8395 isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>()); 8396 8397 for (int i = 0; i < keys->length(); ++i) { 8398 Handle<Object> key(keys->get(i), isolate); 8399 PropertyDescriptor current_desc; 8400 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( 8401 isolate, receiver, key, ¤t_desc); 8402 MAYBE_RETURN(owned, Nothing<bool>()); 8403 if (owned.FromJust()) { 8404 if (current_desc.configurable()) return Just(false); 8405 if (level == FROZEN && 8406 PropertyDescriptor::IsDataDescriptor(¤t_desc) && 8407 current_desc.writable()) { 8408 return Just(false); 8409 } 8410 } 8411 } 8412 return Just(true); 8413 } 8414 8415 } // namespace 8416 8417 Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> receiver, 8418 IntegrityLevel level) { 8419 if (!receiver->map()->IsCustomElementsReceiverMap()) { 8420 return JSObject::TestIntegrityLevel(Handle<JSObject>::cast(receiver), 8421 level); 8422 } 8423 return GenericTestIntegrityLevel(receiver, level); 8424 } 8425 8426 Maybe<bool> JSObject::TestIntegrityLevel(Handle<JSObject> object, 8427 IntegrityLevel level) { 8428 if (!object->map()->IsCustomElementsReceiverMap() && 8429 !object->HasSloppyArgumentsElements()) { 8430 return Just(FastTestIntegrityLevel(*object, level)); 8431 } 8432 return GenericTestIntegrityLevel(Handle<JSReceiver>::cast(object), level); 8433 } 8434 8435 Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object, 8436 ShouldThrow should_throw) { 8437 if (object->IsJSProxy()) { 8438 return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object), 8439 should_throw); 8440 } 8441 DCHECK(object->IsJSObject()); 8442 return JSObject::PreventExtensions(Handle<JSObject>::cast(object), 8443 should_throw); 8444 } 8445 8446 8447 Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy, 8448 ShouldThrow should_throw) { 8449 Isolate* isolate = proxy->GetIsolate(); 8450 STACK_CHECK(isolate, Nothing<bool>()); 8451 Factory* factory = isolate->factory(); 8452 Handle<String> trap_name = factory->preventExtensions_string(); 8453 8454 if (proxy->IsRevoked()) { 8455 isolate->Throw( 8456 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 8457 return Nothing<bool>(); 8458 } 8459 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 8460 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 8461 8462 Handle<Object> trap; 8463 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8464 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 8465 if (trap->IsUndefined(isolate)) { 8466 return JSReceiver::PreventExtensions(target, should_throw); 8467 } 8468 8469 Handle<Object> trap_result; 8470 Handle<Object> args[] = {target}; 8471 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8472 isolate, trap_result, 8473 Execution::Call(isolate, trap, handler, arraysize(args), args), 8474 Nothing<bool>()); 8475 if (!trap_result->BooleanValue(isolate)) { 8476 RETURN_FAILURE( 8477 isolate, should_throw, 8478 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 8479 } 8480 8481 // Enforce the invariant. 8482 Maybe<bool> target_result = JSReceiver::IsExtensible(target); 8483 MAYBE_RETURN(target_result, Nothing<bool>()); 8484 if (target_result.FromJust()) { 8485 isolate->Throw(*factory->NewTypeError( 8486 MessageTemplate::kProxyPreventExtensionsExtensible)); 8487 return Nothing<bool>(); 8488 } 8489 return Just(true); 8490 } 8491 8492 8493 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object, 8494 ShouldThrow should_throw) { 8495 Isolate* isolate = object->GetIsolate(); 8496 8497 if (!object->HasSloppyArgumentsElements()) { 8498 return PreventExtensionsWithTransition<NONE>(object, should_throw); 8499 } 8500 8501 if (object->IsAccessCheckNeeded() && 8502 !isolate->MayAccess(handle(isolate->context(), isolate), object)) { 8503 isolate->ReportFailedAccessCheck(object); 8504 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 8505 RETURN_FAILURE(isolate, should_throw, 8506 NewTypeError(MessageTemplate::kNoAccess)); 8507 } 8508 8509 if (!object->map()->is_extensible()) return Just(true); 8510 8511 if (object->IsJSGlobalProxy()) { 8512 PrototypeIterator iter(isolate, object); 8513 if (iter.IsAtEnd()) return Just(true); 8514 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); 8515 return PreventExtensions(PrototypeIterator::GetCurrent<JSObject>(iter), 8516 should_throw); 8517 } 8518 8519 if (object->map()->has_named_interceptor() || 8520 object->map()->has_indexed_interceptor()) { 8521 RETURN_FAILURE(isolate, should_throw, 8522 NewTypeError(MessageTemplate::kCannotPreventExt)); 8523 } 8524 8525 if (!object->HasFixedTypedArrayElements()) { 8526 // If there are fast elements we normalize. 8527 Handle<NumberDictionary> dictionary = NormalizeElements(object); 8528 DCHECK(object->HasDictionaryElements() || 8529 object->HasSlowArgumentsElements()); 8530 8531 // Make sure that we never go back to fast case. 8532 object->RequireSlowElements(*dictionary); 8533 } 8534 8535 // Do a map transition, other objects with this map may still 8536 // be extensible. 8537 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. 8538 Handle<Map> new_map = 8539 Map::Copy(isolate, handle(object->map(), isolate), "PreventExtensions"); 8540 8541 new_map->set_is_extensible(false); 8542 JSObject::MigrateToMap(object, new_map); 8543 DCHECK(!object->map()->is_extensible()); 8544 8545 return Just(true); 8546 } 8547 8548 8549 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) { 8550 if (object->IsJSProxy()) { 8551 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object)); 8552 } 8553 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object))); 8554 } 8555 8556 8557 Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) { 8558 Isolate* isolate = proxy->GetIsolate(); 8559 STACK_CHECK(isolate, Nothing<bool>()); 8560 Factory* factory = isolate->factory(); 8561 Handle<String> trap_name = factory->isExtensible_string(); 8562 8563 if (proxy->IsRevoked()) { 8564 isolate->Throw( 8565 *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); 8566 return Nothing<bool>(); 8567 } 8568 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 8569 Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); 8570 8571 Handle<Object> trap; 8572 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8573 isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>()); 8574 if (trap->IsUndefined(isolate)) { 8575 return JSReceiver::IsExtensible(target); 8576 } 8577 8578 Handle<Object> trap_result; 8579 Handle<Object> args[] = {target}; 8580 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 8581 isolate, trap_result, 8582 Execution::Call(isolate, trap, handler, arraysize(args), args), 8583 Nothing<bool>()); 8584 8585 // Enforce the invariant. 8586 Maybe<bool> target_result = JSReceiver::IsExtensible(target); 8587 MAYBE_RETURN(target_result, Nothing<bool>()); 8588 if (target_result.FromJust() != trap_result->BooleanValue(isolate)) { 8589 isolate->Throw( 8590 *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent, 8591 factory->ToBoolean(target_result.FromJust()))); 8592 return Nothing<bool>(); 8593 } 8594 return target_result; 8595 } 8596 8597 8598 bool JSObject::IsExtensible(Handle<JSObject> object) { 8599 Isolate* isolate = object->GetIsolate(); 8600 if (object->IsAccessCheckNeeded() && 8601 !isolate->MayAccess(handle(isolate->context(), isolate), object)) { 8602 return true; 8603 } 8604 if (object->IsJSGlobalProxy()) { 8605 PrototypeIterator iter(isolate, *object); 8606 if (iter.IsAtEnd()) return false; 8607 DCHECK(iter.GetCurrent()->IsJSGlobalObject()); 8608 return iter.GetCurrent<JSObject>()->map()->is_extensible(); 8609 } 8610 return object->map()->is_extensible(); 8611 } 8612 8613 namespace { 8614 8615 template <typename Dictionary> 8616 void ApplyAttributesToDictionary(Isolate* isolate, ReadOnlyRoots roots, 8617 Handle<Dictionary> dictionary, 8618 const PropertyAttributes attributes) { 8619 int capacity = dictionary->Capacity(); 8620 for (int i = 0; i < capacity; i++) { 8621 Object* k; 8622 if (!dictionary->ToKey(roots, i, &k)) continue; 8623 if (k->FilterKey(ALL_PROPERTIES)) continue; 8624 PropertyDetails details = dictionary->DetailsAt(i); 8625 int attrs = attributes; 8626 // READ_ONLY is an invalid attribute for JS setters/getters. 8627 if ((attributes & READ_ONLY) && details.kind() == kAccessor) { 8628 Object* v = dictionary->ValueAt(i); 8629 if (v->IsAccessorPair()) attrs &= ~READ_ONLY; 8630 } 8631 details = details.CopyAddAttributes(static_cast<PropertyAttributes>(attrs)); 8632 dictionary->DetailsAtPut(isolate, i, details); 8633 } 8634 } 8635 8636 } // namespace 8637 8638 template <PropertyAttributes attrs> 8639 Maybe<bool> JSObject::PreventExtensionsWithTransition( 8640 Handle<JSObject> object, ShouldThrow should_throw) { 8641 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN); 8642 8643 // Sealing/freezing sloppy arguments or namespace objects should be handled 8644 // elsewhere. 8645 DCHECK(!object->HasSloppyArgumentsElements()); 8646 DCHECK_IMPLIES(object->IsJSModuleNamespace(), attrs == NONE); 8647 8648 Isolate* isolate = object->GetIsolate(); 8649 if (object->IsAccessCheckNeeded() && 8650 !isolate->MayAccess(handle(isolate->context(), isolate), object)) { 8651 isolate->ReportFailedAccessCheck(object); 8652 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 8653 RETURN_FAILURE(isolate, should_throw, 8654 NewTypeError(MessageTemplate::kNoAccess)); 8655 } 8656 8657 if (attrs == NONE && !object->map()->is_extensible()) return Just(true); 8658 8659 if (object->IsJSGlobalProxy()) { 8660 PrototypeIterator iter(isolate, object); 8661 if (iter.IsAtEnd()) return Just(true); 8662 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); 8663 return PreventExtensionsWithTransition<attrs>( 8664 PrototypeIterator::GetCurrent<JSObject>(iter), should_throw); 8665 } 8666 8667 if (object->map()->has_named_interceptor() || 8668 object->map()->has_indexed_interceptor()) { 8669 MessageTemplate::Template message = MessageTemplate::kNone; 8670 switch (attrs) { 8671 case NONE: 8672 message = MessageTemplate::kCannotPreventExt; 8673 break; 8674 8675 case SEALED: 8676 message = MessageTemplate::kCannotSeal; 8677 break; 8678 8679 case FROZEN: 8680 message = MessageTemplate::kCannotFreeze; 8681 break; 8682 } 8683 RETURN_FAILURE(isolate, should_throw, NewTypeError(message)); 8684 } 8685 8686 Handle<NumberDictionary> new_element_dictionary; 8687 if (!object->HasFixedTypedArrayElements() && 8688 !object->HasDictionaryElements() && 8689 !object->HasSlowStringWrapperElements()) { 8690 int length = object->IsJSArray() 8691 ? Smi::ToInt(Handle<JSArray>::cast(object)->length()) 8692 : object->elements()->length(); 8693 new_element_dictionary = 8694 length == 0 ? isolate->factory()->empty_slow_element_dictionary() 8695 : object->GetElementsAccessor()->Normalize(object); 8696 } 8697 8698 Handle<Symbol> transition_marker; 8699 if (attrs == NONE) { 8700 transition_marker = isolate->factory()->nonextensible_symbol(); 8701 } else if (attrs == SEALED) { 8702 transition_marker = isolate->factory()->sealed_symbol(); 8703 } else { 8704 DCHECK(attrs == FROZEN); 8705 transition_marker = isolate->factory()->frozen_symbol(); 8706 } 8707 8708 Handle<Map> old_map(object->map(), isolate); 8709 TransitionsAccessor transitions(isolate, old_map); 8710 Map* transition = transitions.SearchSpecial(*transition_marker); 8711 if (transition != nullptr) { 8712 Handle<Map> transition_map(transition, isolate); 8713 DCHECK(transition_map->has_dictionary_elements() || 8714 transition_map->has_fixed_typed_array_elements() || 8715 transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS); 8716 DCHECK(!transition_map->is_extensible()); 8717 JSObject::MigrateToMap(object, transition_map); 8718 } else if (transitions.CanHaveMoreTransitions()) { 8719 // Create a new descriptor array with the appropriate property attributes 8720 Handle<Map> new_map = Map::CopyForPreventExtensions( 8721 isolate, old_map, attrs, transition_marker, "CopyForPreventExtensions"); 8722 JSObject::MigrateToMap(object, new_map); 8723 } else { 8724 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map()); 8725 // Slow path: need to normalize properties for safety 8726 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, 8727 "SlowPreventExtensions"); 8728 8729 // Create a new map, since other objects with this map may be extensible. 8730 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. 8731 Handle<Map> new_map = Map::Copy(isolate, handle(object->map(), isolate), 8732 "SlowCopyForPreventExtensions"); 8733 new_map->set_is_extensible(false); 8734 if (!new_element_dictionary.is_null()) { 8735 ElementsKind new_kind = 8736 IsStringWrapperElementsKind(old_map->elements_kind()) 8737 ? SLOW_STRING_WRAPPER_ELEMENTS 8738 : DICTIONARY_ELEMENTS; 8739 new_map->set_elements_kind(new_kind); 8740 } 8741 JSObject::MigrateToMap(object, new_map); 8742 8743 if (attrs != NONE) { 8744 ReadOnlyRoots roots(isolate); 8745 if (object->IsJSGlobalObject()) { 8746 Handle<GlobalDictionary> dictionary( 8747 JSGlobalObject::cast(*object)->global_dictionary(), isolate); 8748 ApplyAttributesToDictionary(isolate, roots, dictionary, attrs); 8749 } else { 8750 Handle<NameDictionary> dictionary(object->property_dictionary(), 8751 isolate); 8752 ApplyAttributesToDictionary(isolate, roots, dictionary, attrs); 8753 } 8754 } 8755 } 8756 8757 // Both seal and preventExtensions always go through without modifications to 8758 // typed array elements. Freeze works only if there are no actual elements. 8759 if (object->HasFixedTypedArrayElements()) { 8760 if (attrs == FROZEN && 8761 JSArrayBufferView::cast(*object)->byte_length()->Number() > 0) { 8762 isolate->Throw(*isolate->factory()->NewTypeError( 8763 MessageTemplate::kCannotFreezeArrayBufferView)); 8764 return Nothing<bool>(); 8765 } 8766 return Just(true); 8767 } 8768 8769 DCHECK(object->map()->has_dictionary_elements() || 8770 object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS); 8771 if (!new_element_dictionary.is_null()) { 8772 object->set_elements(*new_element_dictionary); 8773 } 8774 8775 if (object->elements() != 8776 ReadOnlyRoots(isolate).empty_slow_element_dictionary()) { 8777 Handle<NumberDictionary> dictionary(object->element_dictionary(), isolate); 8778 // Make sure we never go back to the fast case 8779 object->RequireSlowElements(*dictionary); 8780 if (attrs != NONE) { 8781 ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate), dictionary, 8782 attrs); 8783 } 8784 } 8785 8786 return Just(true); 8787 } 8788 8789 8790 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object, 8791 Representation representation, 8792 FieldIndex index) { 8793 Isolate* isolate = object->GetIsolate(); 8794 if (object->IsUnboxedDoubleField(index)) { 8795 double value = object->RawFastDoublePropertyAt(index); 8796 return isolate->factory()->NewHeapNumber(value); 8797 } 8798 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate); 8799 return Object::WrapForRead(isolate, raw_value, representation); 8800 } 8801 8802 // static 8803 MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver, 8804 ToPrimitiveHint hint) { 8805 Isolate* const isolate = receiver->GetIsolate(); 8806 Handle<Object> exotic_to_prim; 8807 ASSIGN_RETURN_ON_EXCEPTION( 8808 isolate, exotic_to_prim, 8809 GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object); 8810 if (!exotic_to_prim->IsUndefined(isolate)) { 8811 Handle<Object> hint_string = 8812 isolate->factory()->ToPrimitiveHintString(hint); 8813 Handle<Object> result; 8814 ASSIGN_RETURN_ON_EXCEPTION( 8815 isolate, result, 8816 Execution::Call(isolate, exotic_to_prim, receiver, 1, &hint_string), 8817 Object); 8818 if (result->IsPrimitive()) return result; 8819 THROW_NEW_ERROR(isolate, 8820 NewTypeError(MessageTemplate::kCannotConvertToPrimitive), 8821 Object); 8822 } 8823 return OrdinaryToPrimitive(receiver, (hint == ToPrimitiveHint::kString) 8824 ? OrdinaryToPrimitiveHint::kString 8825 : OrdinaryToPrimitiveHint::kNumber); 8826 } 8827 8828 8829 // static 8830 MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive( 8831 Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint) { 8832 Isolate* const isolate = receiver->GetIsolate(); 8833 Handle<String> method_names[2]; 8834 switch (hint) { 8835 case OrdinaryToPrimitiveHint::kNumber: 8836 method_names[0] = isolate->factory()->valueOf_string(); 8837 method_names[1] = isolate->factory()->toString_string(); 8838 break; 8839 case OrdinaryToPrimitiveHint::kString: 8840 method_names[0] = isolate->factory()->toString_string(); 8841 method_names[1] = isolate->factory()->valueOf_string(); 8842 break; 8843 } 8844 for (Handle<String> name : method_names) { 8845 Handle<Object> method; 8846 ASSIGN_RETURN_ON_EXCEPTION(isolate, method, 8847 JSReceiver::GetProperty(isolate, receiver, name), 8848 Object); 8849 if (method->IsCallable()) { 8850 Handle<Object> result; 8851 ASSIGN_RETURN_ON_EXCEPTION( 8852 isolate, result, 8853 Execution::Call(isolate, method, receiver, 0, nullptr), Object); 8854 if (result->IsPrimitive()) return result; 8855 } 8856 } 8857 THROW_NEW_ERROR(isolate, 8858 NewTypeError(MessageTemplate::kCannotConvertToPrimitive), 8859 Object); 8860 } 8861 8862 8863 // TODO(cbruni/jkummerow): Consider moving this into elements.cc. 8864 bool JSObject::HasEnumerableElements() { 8865 // TODO(cbruni): cleanup 8866 JSObject* object = this; 8867 switch (object->GetElementsKind()) { 8868 case PACKED_SMI_ELEMENTS: 8869 case PACKED_ELEMENTS: 8870 case PACKED_DOUBLE_ELEMENTS: { 8871 int length = object->IsJSArray() 8872 ? Smi::ToInt(JSArray::cast(object)->length()) 8873 : object->elements()->length(); 8874 return length > 0; 8875 } 8876 case HOLEY_SMI_ELEMENTS: 8877 case HOLEY_ELEMENTS: { 8878 FixedArray* elements = FixedArray::cast(object->elements()); 8879 int length = object->IsJSArray() 8880 ? Smi::ToInt(JSArray::cast(object)->length()) 8881 : elements->length(); 8882 Isolate* isolate = GetIsolate(); 8883 for (int i = 0; i < length; i++) { 8884 if (!elements->is_the_hole(isolate, i)) return true; 8885 } 8886 return false; 8887 } 8888 case HOLEY_DOUBLE_ELEMENTS: { 8889 int length = object->IsJSArray() 8890 ? Smi::ToInt(JSArray::cast(object)->length()) 8891 : object->elements()->length(); 8892 // Zero-length arrays would use the empty FixedArray... 8893 if (length == 0) return false; 8894 // ...so only cast to FixedDoubleArray otherwise. 8895 FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements()); 8896 for (int i = 0; i < length; i++) { 8897 if (!elements->is_the_hole(i)) return true; 8898 } 8899 return false; 8900 } 8901 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: 8902 8903 TYPED_ARRAYS(TYPED_ARRAY_CASE) 8904 #undef TYPED_ARRAY_CASE 8905 { 8906 int length = object->elements()->length(); 8907 return length > 0; 8908 } 8909 case DICTIONARY_ELEMENTS: { 8910 NumberDictionary* elements = NumberDictionary::cast(object->elements()); 8911 return elements->NumberOfEnumerableProperties() > 0; 8912 } 8913 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 8914 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 8915 // We're approximating non-empty arguments objects here. 8916 return true; 8917 case FAST_STRING_WRAPPER_ELEMENTS: 8918 case SLOW_STRING_WRAPPER_ELEMENTS: 8919 if (String::cast(JSValue::cast(object)->value())->length() > 0) { 8920 return true; 8921 } 8922 return object->elements()->length() > 0; 8923 case NO_ELEMENTS: 8924 return false; 8925 } 8926 UNREACHABLE(); 8927 } 8928 8929 int Map::NumberOfEnumerableProperties() const { 8930 int result = 0; 8931 DescriptorArray* descs = instance_descriptors(); 8932 int limit = NumberOfOwnDescriptors(); 8933 for (int i = 0; i < limit; i++) { 8934 if ((descs->GetDetails(i).attributes() & ONLY_ENUMERABLE) == 0 && 8935 !descs->GetKey(i)->FilterKey(ENUMERABLE_STRINGS)) { 8936 result++; 8937 } 8938 } 8939 return result; 8940 } 8941 8942 int Map::NextFreePropertyIndex() const { 8943 int free_index = 0; 8944 int number_of_own_descriptors = NumberOfOwnDescriptors(); 8945 DescriptorArray* descs = instance_descriptors(); 8946 for (int i = 0; i < number_of_own_descriptors; i++) { 8947 PropertyDetails details = descs->GetDetails(i); 8948 if (details.location() == kField) { 8949 int candidate = details.field_index() + details.field_width_in_words(); 8950 if (candidate > free_index) free_index = candidate; 8951 } 8952 } 8953 return free_index; 8954 } 8955 8956 bool Map::OnlyHasSimpleProperties() const { 8957 // Wrapped string elements aren't explicitly stored in the elements backing 8958 // store, but are loaded indirectly from the underlying string. 8959 return !IsStringWrapperElementsKind(elements_kind()) && 8960 !IsSpecialReceiverMap() && !has_hidden_prototype() && 8961 !is_dictionary_map(); 8962 } 8963 8964 V8_WARN_UNUSED_RESULT Maybe<bool> FastGetOwnValuesOrEntries( 8965 Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries, 8966 Handle<FixedArray>* result) { 8967 Handle<Map> map(JSReceiver::cast(*receiver)->map(), isolate); 8968 8969 if (!map->IsJSObjectMap()) return Just(false); 8970 if (!map->OnlyHasSimpleProperties()) return Just(false); 8971 8972 Handle<JSObject> object(JSObject::cast(*receiver), isolate); 8973 8974 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 8975 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 8976 int number_of_own_elements = 8977 object->GetElementsAccessor()->GetCapacity(*object, object->elements()); 8978 Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray( 8979 number_of_own_descriptors + number_of_own_elements); 8980 int count = 0; 8981 8982 if (object->elements() != ReadOnlyRoots(isolate).empty_fixed_array()) { 8983 MAYBE_RETURN(object->GetElementsAccessor()->CollectValuesOrEntries( 8984 isolate, object, values_or_entries, get_entries, &count, 8985 ENUMERABLE_STRINGS), 8986 Nothing<bool>()); 8987 } 8988 8989 bool stable = object->map() == *map; 8990 8991 for (int index = 0; index < number_of_own_descriptors; index++) { 8992 Handle<Name> next_key(descriptors->GetKey(index), isolate); 8993 if (!next_key->IsString()) continue; 8994 Handle<Object> prop_value; 8995 8996 // Directly decode from the descriptor array if |from| did not change shape. 8997 if (stable) { 8998 PropertyDetails details = descriptors->GetDetails(index); 8999 if (!details.IsEnumerable()) continue; 9000 if (details.kind() == kData) { 9001 if (details.location() == kDescriptor) { 9002 prop_value = handle(descriptors->GetStrongValue(index), isolate); 9003 } else { 9004 Representation representation = details.representation(); 9005 FieldIndex field_index = FieldIndex::ForDescriptor(*map, index); 9006 prop_value = 9007 JSObject::FastPropertyAt(object, representation, field_index); 9008 } 9009 } else { 9010 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 9011 isolate, prop_value, 9012 JSReceiver::GetProperty(isolate, object, next_key), 9013 Nothing<bool>()); 9014 stable = object->map() == *map; 9015 } 9016 } else { 9017 // If the map did change, do a slower lookup. We are still guaranteed that 9018 // the object has a simple shape, and that the key is a name. 9019 LookupIterator it(isolate, object, next_key, 9020 LookupIterator::OWN_SKIP_INTERCEPTOR); 9021 if (!it.IsFound()) continue; 9022 DCHECK(it.state() == LookupIterator::DATA || 9023 it.state() == LookupIterator::ACCESSOR); 9024 if (!it.IsEnumerable()) continue; 9025 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 9026 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); 9027 } 9028 9029 if (get_entries) { 9030 prop_value = MakeEntryPair(isolate, next_key, prop_value); 9031 } 9032 9033 values_or_entries->set(count, *prop_value); 9034 count++; 9035 } 9036 9037 DCHECK_LE(count, values_or_entries->length()); 9038 *result = FixedArray::ShrinkOrEmpty(isolate, values_or_entries, count); 9039 return Just(true); 9040 } 9041 9042 MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate, 9043 Handle<JSReceiver> object, 9044 PropertyFilter filter, 9045 bool try_fast_path, 9046 bool get_entries) { 9047 Handle<FixedArray> values_or_entries; 9048 if (try_fast_path && filter == ENUMERABLE_STRINGS) { 9049 Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries( 9050 isolate, object, get_entries, &values_or_entries); 9051 if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>(); 9052 if (fast_values_or_entries.FromJust()) return values_or_entries; 9053 } 9054 9055 PropertyFilter key_filter = 9056 static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE); 9057 9058 Handle<FixedArray> keys; 9059 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 9060 isolate, keys, 9061 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter, 9062 GetKeysConversion::kConvertToString), 9063 MaybeHandle<FixedArray>()); 9064 9065 values_or_entries = isolate->factory()->NewFixedArray(keys->length()); 9066 int length = 0; 9067 9068 for (int i = 0; i < keys->length(); ++i) { 9069 Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate)); 9070 9071 if (filter & ONLY_ENUMERABLE) { 9072 PropertyDescriptor descriptor; 9073 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor( 9074 isolate, object, key, &descriptor); 9075 MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>()); 9076 if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue; 9077 } 9078 9079 Handle<Object> value; 9080 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 9081 isolate, value, JSReceiver::GetPropertyOrElement(isolate, object, key), 9082 MaybeHandle<FixedArray>()); 9083 9084 if (get_entries) { 9085 Handle<FixedArray> entry_storage = 9086 isolate->factory()->NewUninitializedFixedArray(2); 9087 entry_storage->set(0, *key); 9088 entry_storage->set(1, *value); 9089 value = isolate->factory()->NewJSArrayWithElements(entry_storage, 9090 PACKED_ELEMENTS, 2); 9091 } 9092 9093 values_or_entries->set(length, *value); 9094 length++; 9095 } 9096 DCHECK_LE(length, values_or_entries->length()); 9097 return FixedArray::ShrinkOrEmpty(isolate, values_or_entries, length); 9098 } 9099 9100 MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object, 9101 PropertyFilter filter, 9102 bool try_fast_path) { 9103 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, 9104 try_fast_path, false); 9105 } 9106 9107 MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object, 9108 PropertyFilter filter, 9109 bool try_fast_path) { 9110 return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, 9111 try_fast_path, true); 9112 } 9113 9114 Handle<FixedArray> JSReceiver::GetOwnElementIndices(Isolate* isolate, 9115 Handle<JSReceiver> receiver, 9116 Handle<JSObject> object) { 9117 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, 9118 ALL_PROPERTIES); 9119 accumulator.CollectOwnElementIndices(receiver, object); 9120 Handle<FixedArray> keys = 9121 accumulator.GetKeys(GetKeysConversion::kKeepNumbers); 9122 DCHECK(keys->ContainsSortedNumbers()); 9123 return keys; 9124 } 9125 9126 bool Map::DictionaryElementsInPrototypeChainOnly(Isolate* isolate) { 9127 if (IsDictionaryElementsKind(elements_kind())) { 9128 return false; 9129 } 9130 9131 for (PrototypeIterator iter(isolate, this); !iter.IsAtEnd(); iter.Advance()) { 9132 // Be conservative, don't walk into proxies. 9133 if (iter.GetCurrent()->IsJSProxy()) return true; 9134 // String wrappers have non-configurable, non-writable elements. 9135 if (iter.GetCurrent()->IsStringWrapper()) return true; 9136 JSObject* current = iter.GetCurrent<JSObject>(); 9137 9138 if (current->HasDictionaryElements() && 9139 current->element_dictionary()->requires_slow_elements()) { 9140 return true; 9141 } 9142 9143 if (current->HasSlowArgumentsElements()) { 9144 FixedArray* parameter_map = FixedArray::cast(current->elements()); 9145 Object* arguments = parameter_map->get(1); 9146 if (NumberDictionary::cast(arguments)->requires_slow_elements()) { 9147 return true; 9148 } 9149 } 9150 } 9151 9152 return false; 9153 } 9154 9155 9156 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object, 9157 Handle<Name> name, 9158 Handle<Object> getter, 9159 Handle<Object> setter, 9160 PropertyAttributes attributes) { 9161 Isolate* isolate = object->GetIsolate(); 9162 9163 LookupIterator it = LookupIterator::PropertyOrElement( 9164 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 9165 return DefineAccessor(&it, getter, setter, attributes); 9166 } 9167 9168 9169 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it, 9170 Handle<Object> getter, 9171 Handle<Object> setter, 9172 PropertyAttributes attributes) { 9173 Isolate* isolate = it->isolate(); 9174 9175 it->UpdateProtector(); 9176 9177 if (it->state() == LookupIterator::ACCESS_CHECK) { 9178 if (!it->HasAccess()) { 9179 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); 9180 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 9181 return isolate->factory()->undefined_value(); 9182 } 9183 it->Next(); 9184 } 9185 9186 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); 9187 // Ignore accessors on typed arrays. 9188 if (it->IsElement() && object->HasFixedTypedArrayElements()) { 9189 return it->factory()->undefined_value(); 9190 } 9191 9192 DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) || 9193 getter->IsNull(isolate) || getter->IsFunctionTemplateInfo()); 9194 DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) || 9195 setter->IsNull(isolate) || setter->IsFunctionTemplateInfo()); 9196 it->TransitionToAccessorProperty(getter, setter, attributes); 9197 9198 return isolate->factory()->undefined_value(); 9199 } 9200 9201 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object, 9202 Handle<Name> name, 9203 Handle<AccessorInfo> info, 9204 PropertyAttributes attributes) { 9205 Isolate* isolate = object->GetIsolate(); 9206 9207 LookupIterator it = LookupIterator::PropertyOrElement( 9208 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 9209 9210 // Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that 9211 // the FailedAccessCheckCallbackFunction doesn't throw an exception. 9212 // 9213 // TODO(verwaest): Force throw an exception if the callback doesn't, so we can 9214 // remove reliance on default return values. 9215 if (it.state() == LookupIterator::ACCESS_CHECK) { 9216 if (!it.HasAccess()) { 9217 isolate->ReportFailedAccessCheck(object); 9218 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 9219 return it.factory()->undefined_value(); 9220 } 9221 it.Next(); 9222 } 9223 9224 // Ignore accessors on typed arrays. 9225 if (it.IsElement() && object->HasFixedTypedArrayElements()) { 9226 return it.factory()->undefined_value(); 9227 } 9228 9229 CHECK(GetPropertyAttributes(&it).IsJust()); 9230 9231 // ES5 forbids turning a property into an accessor if it's not 9232 // configurable. See 8.6.1 (Table 5). 9233 if (it.IsFound() && !it.IsConfigurable()) { 9234 return it.factory()->undefined_value(); 9235 } 9236 9237 it.TransitionToAccessorPair(info, attributes); 9238 9239 return object; 9240 } 9241 9242 Object* JSObject::SlowReverseLookup(Object* value) { 9243 if (HasFastProperties()) { 9244 int number_of_own_descriptors = map()->NumberOfOwnDescriptors(); 9245 DescriptorArray* descs = map()->instance_descriptors(); 9246 bool value_is_number = value->IsNumber(); 9247 for (int i = 0; i < number_of_own_descriptors; i++) { 9248 PropertyDetails details = descs->GetDetails(i); 9249 if (details.location() == kField) { 9250 DCHECK_EQ(kData, details.kind()); 9251 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i); 9252 if (IsUnboxedDoubleField(field_index)) { 9253 if (value_is_number) { 9254 double property = RawFastDoublePropertyAt(field_index); 9255 if (property == value->Number()) { 9256 return descs->GetKey(i); 9257 } 9258 } 9259 } else { 9260 Object* property = RawFastPropertyAt(field_index); 9261 if (field_index.is_double()) { 9262 DCHECK(property->IsMutableHeapNumber()); 9263 if (value_is_number && property->Number() == value->Number()) { 9264 return descs->GetKey(i); 9265 } 9266 } else if (property == value) { 9267 return descs->GetKey(i); 9268 } 9269 } 9270 } else { 9271 DCHECK_EQ(kDescriptor, details.location()); 9272 if (details.kind() == kData) { 9273 if (descs->GetStrongValue(i) == value) { 9274 return descs->GetKey(i); 9275 } 9276 } 9277 } 9278 } 9279 return GetReadOnlyRoots().undefined_value(); 9280 } else if (IsJSGlobalObject()) { 9281 return JSGlobalObject::cast(this)->global_dictionary()->SlowReverseLookup( 9282 value); 9283 } else { 9284 return property_dictionary()->SlowReverseLookup(value); 9285 } 9286 } 9287 9288 Handle<Map> Map::RawCopy(Isolate* isolate, Handle<Map> map, int instance_size, 9289 int inobject_properties) { 9290 Handle<Map> result = isolate->factory()->NewMap( 9291 map->instance_type(), instance_size, TERMINAL_FAST_ELEMENTS_KIND, 9292 inobject_properties); 9293 Handle<Object> prototype(map->prototype(), isolate); 9294 Map::SetPrototype(isolate, result, prototype); 9295 result->set_constructor_or_backpointer(map->GetConstructor()); 9296 result->set_bit_field(map->bit_field()); 9297 result->set_bit_field2(map->bit_field2()); 9298 int new_bit_field3 = map->bit_field3(); 9299 new_bit_field3 = OwnsDescriptorsBit::update(new_bit_field3, true); 9300 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); 9301 new_bit_field3 = EnumLengthBits::update(new_bit_field3, 9302 kInvalidEnumCacheSentinel); 9303 new_bit_field3 = IsDeprecatedBit::update(new_bit_field3, false); 9304 if (!map->is_dictionary_map()) { 9305 new_bit_field3 = IsUnstableBit::update(new_bit_field3, false); 9306 } 9307 result->set_bit_field3(new_bit_field3); 9308 return result; 9309 } 9310 9311 Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map, 9312 PropertyNormalizationMode mode, const char* reason) { 9313 DCHECK(!fast_map->is_dictionary_map()); 9314 9315 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(), 9316 isolate); 9317 bool use_cache = 9318 !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate); 9319 Handle<NormalizedMapCache> cache; 9320 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache); 9321 9322 Handle<Map> new_map; 9323 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) { 9324 #ifdef VERIFY_HEAP 9325 if (FLAG_verify_heap) new_map->DictionaryMapVerify(isolate); 9326 #endif 9327 #ifdef ENABLE_SLOW_DCHECKS 9328 if (FLAG_enable_slow_asserts) { 9329 // The cached map should match newly created normalized map bit-by-bit, 9330 // except for the code cache, which can contain some ICs which can be 9331 // applied to the shared map, dependent code and weak cell cache. 9332 Handle<Map> fresh = Map::CopyNormalized(isolate, fast_map, mode); 9333 9334 if (new_map->is_prototype_map()) { 9335 // For prototype maps, the PrototypeInfo is not copied. 9336 DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()), 9337 reinterpret_cast<void*>(new_map->address()), 9338 kTransitionsOrPrototypeInfoOffset)); 9339 DCHECK_EQ(fresh->raw_transitions(), 9340 MaybeObject::FromObject(Smi::kZero)); 9341 STATIC_ASSERT(kDescriptorsOffset == 9342 kTransitionsOrPrototypeInfoOffset + kPointerSize); 9343 DCHECK_EQ(0, memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset), 9344 HeapObject::RawField(*new_map, kDescriptorsOffset), 9345 kDependentCodeOffset - kDescriptorsOffset)); 9346 } else { 9347 DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()), 9348 reinterpret_cast<void*>(new_map->address()), 9349 Map::kDependentCodeOffset)); 9350 } 9351 STATIC_ASSERT(Map::kPrototypeValidityCellOffset == 9352 Map::kDependentCodeOffset + kPointerSize); 9353 int offset = Map::kPrototypeValidityCellOffset + kPointerSize; 9354 DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address() + offset), 9355 reinterpret_cast<void*>(new_map->address() + offset), 9356 Map::kSize - offset)); 9357 } 9358 #endif 9359 } else { 9360 new_map = Map::CopyNormalized(isolate, fast_map, mode); 9361 if (use_cache) { 9362 cache->Set(fast_map, new_map); 9363 isolate->counters()->maps_normalized()->Increment(); 9364 } 9365 if (FLAG_trace_maps) { 9366 LOG(isolate, MapEvent("Normalize", *fast_map, *new_map, reason)); 9367 } 9368 } 9369 fast_map->NotifyLeafMapLayoutChange(isolate); 9370 return new_map; 9371 } 9372 9373 Handle<Map> Map::CopyNormalized(Isolate* isolate, Handle<Map> map, 9374 PropertyNormalizationMode mode) { 9375 int new_instance_size = map->instance_size(); 9376 if (mode == CLEAR_INOBJECT_PROPERTIES) { 9377 new_instance_size -= map->GetInObjectProperties() * kPointerSize; 9378 } 9379 9380 Handle<Map> result = RawCopy( 9381 isolate, map, new_instance_size, 9382 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : map->GetInObjectProperties()); 9383 // Clear the unused_property_fields explicitly as this field should not 9384 // be accessed for normalized maps. 9385 result->SetInObjectUnusedPropertyFields(0); 9386 result->set_is_dictionary_map(true); 9387 result->set_is_migration_target(false); 9388 result->set_may_have_interesting_symbols(true); 9389 result->set_construction_counter(kNoSlackTracking); 9390 9391 #ifdef VERIFY_HEAP 9392 if (FLAG_verify_heap) result->DictionaryMapVerify(isolate); 9393 #endif 9394 9395 return result; 9396 } 9397 9398 // Return an immutable prototype exotic object version of the input map. 9399 // Never even try to cache it in the transition tree, as it is intended 9400 // for the global object and its prototype chain, and excluding it saves 9401 // memory on the map transition tree. 9402 9403 // static 9404 Handle<Map> Map::TransitionToImmutableProto(Isolate* isolate, Handle<Map> map) { 9405 Handle<Map> new_map = Map::Copy(isolate, map, "ImmutablePrototype"); 9406 new_map->set_is_immutable_proto(true); 9407 return new_map; 9408 } 9409 9410 namespace { 9411 void EnsureInitialMap(Isolate* isolate, Handle<Map> map) { 9412 #ifdef DEBUG 9413 // Strict function maps have Function as a constructor but the 9414 // Function's initial map is a sloppy function map. Same holds for 9415 // GeneratorFunction / AsyncFunction and its initial map. 9416 Object* constructor = map->GetConstructor(); 9417 DCHECK(constructor->IsJSFunction()); 9418 DCHECK(*map == JSFunction::cast(constructor)->initial_map() || 9419 *map == *isolate->strict_function_map() || 9420 *map == *isolate->strict_function_with_name_map() || 9421 *map == *isolate->generator_function_map() || 9422 *map == *isolate->generator_function_with_name_map() || 9423 *map == *isolate->generator_function_with_home_object_map() || 9424 *map == *isolate->generator_function_with_name_and_home_object_map() || 9425 *map == *isolate->async_function_map() || 9426 *map == *isolate->async_function_with_name_map() || 9427 *map == *isolate->async_function_with_home_object_map() || 9428 *map == *isolate->async_function_with_name_and_home_object_map()); 9429 #endif 9430 // Initial maps must always own their descriptors and it's descriptor array 9431 // does not contain descriptors that do not belong to the map. 9432 DCHECK(map->owns_descriptors()); 9433 DCHECK_EQ(map->NumberOfOwnDescriptors(), 9434 map->instance_descriptors()->number_of_descriptors()); 9435 } 9436 } // namespace 9437 9438 // static 9439 Handle<Map> Map::CopyInitialMapNormalized(Isolate* isolate, Handle<Map> map, 9440 PropertyNormalizationMode mode) { 9441 EnsureInitialMap(isolate, map); 9442 return CopyNormalized(isolate, map, mode); 9443 } 9444 9445 // static 9446 Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map, 9447 int instance_size, int inobject_properties, 9448 int unused_property_fields) { 9449 EnsureInitialMap(isolate, map); 9450 Handle<Map> result = 9451 RawCopy(isolate, map, instance_size, inobject_properties); 9452 9453 // Please note instance_type and instance_size are set when allocated. 9454 result->SetInObjectUnusedPropertyFields(unused_property_fields); 9455 9456 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 9457 if (number_of_own_descriptors > 0) { 9458 // The copy will use the same descriptors array. 9459 result->UpdateDescriptors(map->instance_descriptors(), 9460 map->GetLayoutDescriptor()); 9461 result->SetNumberOfOwnDescriptors(number_of_own_descriptors); 9462 9463 DCHECK_EQ(result->NumberOfFields(), 9464 result->GetInObjectProperties() - result->UnusedPropertyFields()); 9465 } 9466 9467 return result; 9468 } 9469 9470 Handle<Map> Map::CopyDropDescriptors(Isolate* isolate, Handle<Map> map) { 9471 Handle<Map> result = 9472 RawCopy(isolate, map, map->instance_size(), 9473 map->IsJSObjectMap() ? map->GetInObjectProperties() : 0); 9474 9475 // Please note instance_type and instance_size are set when allocated. 9476 if (map->IsJSObjectMap()) { 9477 result->CopyUnusedPropertyFields(*map); 9478 } 9479 map->NotifyLeafMapLayoutChange(isolate); 9480 return result; 9481 } 9482 9483 Handle<Map> Map::ShareDescriptor(Isolate* isolate, Handle<Map> map, 9484 Handle<DescriptorArray> descriptors, 9485 Descriptor* descriptor) { 9486 // Sanity check. This path is only to be taken if the map owns its descriptor 9487 // array, implying that its NumberOfOwnDescriptors equals the number of 9488 // descriptors in the descriptor array. 9489 DCHECK_EQ(map->NumberOfOwnDescriptors(), 9490 map->instance_descriptors()->number_of_descriptors()); 9491 9492 Handle<Map> result = CopyDropDescriptors(isolate, map); 9493 Handle<Name> name = descriptor->GetKey(); 9494 9495 // Properly mark the {result} if the {name} is an "interesting symbol". 9496 if (name->IsInterestingSymbol()) { 9497 result->set_may_have_interesting_symbols(true); 9498 } 9499 9500 // Ensure there's space for the new descriptor in the shared descriptor array. 9501 if (descriptors->NumberOfSlackDescriptors() == 0) { 9502 int old_size = descriptors->number_of_descriptors(); 9503 if (old_size == 0) { 9504 descriptors = DescriptorArray::Allocate(isolate, 0, 1); 9505 } else { 9506 int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors); 9507 EnsureDescriptorSlack(isolate, map, slack); 9508 descriptors = handle(map->instance_descriptors(), isolate); 9509 } 9510 } 9511 9512 Handle<LayoutDescriptor> layout_descriptor = 9513 FLAG_unbox_double_fields 9514 ? LayoutDescriptor::ShareAppend(isolate, map, 9515 descriptor->GetDetails()) 9516 : handle(LayoutDescriptor::FastPointerLayout(), isolate); 9517 9518 { 9519 DisallowHeapAllocation no_gc; 9520 descriptors->Append(descriptor); 9521 result->InitializeDescriptors(*descriptors, *layout_descriptor); 9522 } 9523 9524 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1); 9525 ConnectTransition(isolate, map, result, name, SIMPLE_PROPERTY_TRANSITION); 9526 9527 return result; 9528 } 9529 9530 void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent, 9531 Handle<Map> child, Handle<Name> name, 9532 SimpleTransitionFlag flag) { 9533 DCHECK_IMPLIES(name->IsInterestingSymbol(), 9534 child->may_have_interesting_symbols()); 9535 DCHECK_IMPLIES(parent->may_have_interesting_symbols(), 9536 child->may_have_interesting_symbols()); 9537 // Do not track transitions during bootstrap except for element transitions. 9538 if (isolate->bootstrapper()->IsActive() && 9539 !name.is_identical_to(isolate->factory()->elements_transition_symbol())) { 9540 if (FLAG_trace_maps) { 9541 LOG(isolate, 9542 MapEvent("Transition", *parent, *child, 9543 child->is_prototype_map() ? "prototype" : "", *name)); 9544 } 9545 return; 9546 } 9547 if (!parent->GetBackPointer()->IsUndefined(isolate)) { 9548 parent->set_owns_descriptors(false); 9549 } else { 9550 // |parent| is initial map and it must keep the ownership, there must be no 9551 // descriptors in the descriptors array that do not belong to the map. 9552 DCHECK(parent->owns_descriptors()); 9553 DCHECK_EQ(parent->NumberOfOwnDescriptors(), 9554 parent->instance_descriptors()->number_of_descriptors()); 9555 } 9556 if (parent->is_prototype_map()) { 9557 DCHECK(child->is_prototype_map()); 9558 if (FLAG_trace_maps) { 9559 LOG(isolate, MapEvent("Transition", *parent, *child, "prototype", *name)); 9560 } 9561 } else { 9562 TransitionsAccessor(isolate, parent).Insert(name, child, flag); 9563 if (FLAG_trace_maps) { 9564 LOG(isolate, MapEvent("Transition", *parent, *child, "", *name)); 9565 } 9566 } 9567 } 9568 9569 Handle<Map> Map::CopyReplaceDescriptors( 9570 Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors, 9571 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag, 9572 MaybeHandle<Name> maybe_name, const char* reason, 9573 SimpleTransitionFlag simple_flag) { 9574 DCHECK(descriptors->IsSortedNoDuplicates()); 9575 9576 Handle<Map> result = CopyDropDescriptors(isolate, map); 9577 9578 // Properly mark the {result} if the {name} is an "interesting symbol". 9579 Handle<Name> name; 9580 if (maybe_name.ToHandle(&name) && name->IsInterestingSymbol()) { 9581 result->set_may_have_interesting_symbols(true); 9582 } 9583 9584 if (!map->is_prototype_map()) { 9585 if (flag == INSERT_TRANSITION && 9586 TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) { 9587 result->InitializeDescriptors(*descriptors, *layout_descriptor); 9588 9589 DCHECK(!maybe_name.is_null()); 9590 ConnectTransition(isolate, map, result, name, simple_flag); 9591 } else { 9592 descriptors->GeneralizeAllFields(); 9593 result->InitializeDescriptors(*descriptors, 9594 LayoutDescriptor::FastPointerLayout()); 9595 } 9596 } else { 9597 result->InitializeDescriptors(*descriptors, *layout_descriptor); 9598 } 9599 if (FLAG_trace_maps && 9600 // Mirror conditions above that did not call ConnectTransition(). 9601 (map->is_prototype_map() || 9602 !(flag == INSERT_TRANSITION && 9603 TransitionsAccessor(isolate, map).CanHaveMoreTransitions()))) { 9604 LOG(isolate, MapEvent("ReplaceDescriptors", *map, *result, reason, 9605 maybe_name.is_null() ? nullptr : *name)); 9606 } 9607 return result; 9608 } 9609 9610 9611 // Creates transition tree starting from |split_map| and adding all descriptors 9612 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors(). 9613 // The way how it is done is tricky because of GC and special descriptors 9614 // marking logic. 9615 Handle<Map> Map::AddMissingTransitions( 9616 Isolate* isolate, Handle<Map> split_map, 9617 Handle<DescriptorArray> descriptors, 9618 Handle<LayoutDescriptor> full_layout_descriptor) { 9619 DCHECK(descriptors->IsSortedNoDuplicates()); 9620 int split_nof = split_map->NumberOfOwnDescriptors(); 9621 int nof_descriptors = descriptors->number_of_descriptors(); 9622 DCHECK_LT(split_nof, nof_descriptors); 9623 9624 // Start with creating last map which will own full descriptors array. 9625 // This is necessary to guarantee that GC will mark the whole descriptor 9626 // array if any of the allocations happening below fail. 9627 // Number of unused properties is temporarily incorrect and the layout 9628 // descriptor could unnecessarily be in slow mode but we will fix after 9629 // all the other intermediate maps are created. 9630 // Also the last map might have interesting symbols, we temporarily set 9631 // the flag and clear it right before the descriptors are installed. This 9632 // makes heap verification happy and ensures the flag ends up accurate. 9633 Handle<Map> last_map = CopyDropDescriptors(isolate, split_map); 9634 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor); 9635 last_map->SetInObjectUnusedPropertyFields(0); 9636 last_map->set_may_have_interesting_symbols(true); 9637 9638 // During creation of intermediate maps we violate descriptors sharing 9639 // invariant since the last map is not yet connected to the transition tree 9640 // we create here. But it is safe because GC never trims map's descriptors 9641 // if there are no dead transitions from that map and this is exactly the 9642 // case for all the intermediate maps we create here. 9643 Handle<Map> map = split_map; 9644 for (int i = split_nof; i < nof_descriptors - 1; ++i) { 9645 Handle<Map> new_map = CopyDropDescriptors(isolate, map); 9646 InstallDescriptors(isolate, map, new_map, i, descriptors, 9647 full_layout_descriptor); 9648 map = new_map; 9649 } 9650 map->NotifyLeafMapLayoutChange(isolate); 9651 last_map->set_may_have_interesting_symbols(false); 9652 InstallDescriptors(isolate, map, last_map, nof_descriptors - 1, descriptors, 9653 full_layout_descriptor); 9654 return last_map; 9655 } 9656 9657 9658 // Since this method is used to rewrite an existing transition tree, it can 9659 // always insert transitions without checking. 9660 void Map::InstallDescriptors(Isolate* isolate, Handle<Map> parent, 9661 Handle<Map> child, int new_descriptor, 9662 Handle<DescriptorArray> descriptors, 9663 Handle<LayoutDescriptor> full_layout_descriptor) { 9664 DCHECK(descriptors->IsSortedNoDuplicates()); 9665 9666 child->set_instance_descriptors(*descriptors); 9667 child->SetNumberOfOwnDescriptors(new_descriptor + 1); 9668 child->CopyUnusedPropertyFields(*parent); 9669 PropertyDetails details = descriptors->GetDetails(new_descriptor); 9670 if (details.location() == kField) { 9671 child->AccountAddedPropertyField(); 9672 } 9673 9674 if (FLAG_unbox_double_fields) { 9675 Handle<LayoutDescriptor> layout_descriptor = 9676 LayoutDescriptor::AppendIfFastOrUseFull(isolate, parent, details, 9677 full_layout_descriptor); 9678 child->set_layout_descriptor(*layout_descriptor); 9679 #ifdef VERIFY_HEAP 9680 // TODO(ishell): remove these checks from VERIFY_HEAP mode. 9681 if (FLAG_verify_heap) { 9682 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child)); 9683 } 9684 #else 9685 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child)); 9686 #endif 9687 child->set_visitor_id(Map::GetVisitorId(*child)); 9688 } 9689 9690 Handle<Name> name = handle(descriptors->GetKey(new_descriptor), isolate); 9691 if (parent->may_have_interesting_symbols() || name->IsInterestingSymbol()) { 9692 child->set_may_have_interesting_symbols(true); 9693 } 9694 ConnectTransition(isolate, parent, child, name, SIMPLE_PROPERTY_TRANSITION); 9695 } 9696 9697 Handle<Map> Map::CopyAsElementsKind(Isolate* isolate, Handle<Map> map, 9698 ElementsKind kind, TransitionFlag flag) { 9699 // Only certain objects are allowed to have non-terminal fast transitional 9700 // elements kinds. 9701 DCHECK(map->IsJSObjectMap()); 9702 DCHECK_IMPLIES( 9703 !map->CanHaveFastTransitionableElementsKind(), 9704 IsDictionaryElementsKind(kind) || IsTerminalElementsKind(kind)); 9705 9706 Map* maybe_elements_transition_map = nullptr; 9707 if (flag == INSERT_TRANSITION) { 9708 // Ensure we are requested to add elements kind transition "near the root". 9709 DCHECK_EQ(map->FindRootMap(isolate)->NumberOfOwnDescriptors(), 9710 map->NumberOfOwnDescriptors()); 9711 9712 maybe_elements_transition_map = map->ElementsTransitionMap(); 9713 DCHECK(maybe_elements_transition_map == nullptr || 9714 (maybe_elements_transition_map->elements_kind() == 9715 DICTIONARY_ELEMENTS && 9716 kind == DICTIONARY_ELEMENTS)); 9717 DCHECK(!IsFastElementsKind(kind) || 9718 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind)); 9719 DCHECK(kind != map->elements_kind()); 9720 } 9721 9722 bool insert_transition = 9723 flag == INSERT_TRANSITION && 9724 TransitionsAccessor(isolate, map).CanHaveMoreTransitions() && 9725 maybe_elements_transition_map == nullptr; 9726 9727 if (insert_transition) { 9728 Handle<Map> new_map = CopyForTransition(isolate, map, "CopyAsElementsKind"); 9729 new_map->set_elements_kind(kind); 9730 9731 Handle<Name> name = isolate->factory()->elements_transition_symbol(); 9732 ConnectTransition(isolate, map, new_map, name, SPECIAL_TRANSITION); 9733 return new_map; 9734 } 9735 9736 // Create a new free-floating map only if we are not allowed to store it. 9737 Handle<Map> new_map = Copy(isolate, map, "CopyAsElementsKind"); 9738 new_map->set_elements_kind(kind); 9739 return new_map; 9740 } 9741 9742 Handle<Map> Map::AsLanguageMode(Isolate* isolate, Handle<Map> initial_map, 9743 Handle<SharedFunctionInfo> shared_info) { 9744 DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type()); 9745 // Initial map for sloppy mode function is stored in the function 9746 // constructor. Initial maps for strict mode are cached as special transitions 9747 // using |strict_function_transition_symbol| as a key. 9748 if (is_sloppy(shared_info->language_mode())) return initial_map; 9749 9750 Handle<Map> function_map(Map::cast(isolate->native_context()->get( 9751 shared_info->function_map_index())), 9752 isolate); 9753 9754 STATIC_ASSERT(LanguageModeSize == 2); 9755 DCHECK_EQ(LanguageMode::kStrict, shared_info->language_mode()); 9756 Handle<Symbol> transition_symbol = 9757 isolate->factory()->strict_function_transition_symbol(); 9758 Map* maybe_transition = TransitionsAccessor(isolate, initial_map) 9759 .SearchSpecial(*transition_symbol); 9760 if (maybe_transition != nullptr) { 9761 return handle(maybe_transition, isolate); 9762 } 9763 initial_map->NotifyLeafMapLayoutChange(isolate); 9764 9765 // Create new map taking descriptors from the |function_map| and all 9766 // the other details from the |initial_map|. 9767 Handle<Map> map = 9768 Map::CopyInitialMap(isolate, function_map, initial_map->instance_size(), 9769 initial_map->GetInObjectProperties(), 9770 initial_map->UnusedPropertyFields()); 9771 map->SetConstructor(initial_map->GetConstructor()); 9772 map->set_prototype(initial_map->prototype()); 9773 map->set_construction_counter(initial_map->construction_counter()); 9774 9775 if (TransitionsAccessor(isolate, initial_map).CanHaveMoreTransitions()) { 9776 Map::ConnectTransition(isolate, initial_map, map, transition_symbol, 9777 SPECIAL_TRANSITION); 9778 } 9779 return map; 9780 } 9781 9782 Handle<Map> Map::CopyForTransition(Isolate* isolate, Handle<Map> map, 9783 const char* reason) { 9784 DCHECK(!map->is_prototype_map()); 9785 Handle<Map> new_map = CopyDropDescriptors(isolate, map); 9786 9787 if (map->owns_descriptors()) { 9788 // In case the map owned its own descriptors, share the descriptors and 9789 // transfer ownership to the new map. 9790 // The properties did not change, so reuse descriptors. 9791 new_map->InitializeDescriptors(map->instance_descriptors(), 9792 map->GetLayoutDescriptor()); 9793 } else { 9794 // In case the map did not own its own descriptors, a split is forced by 9795 // copying the map; creating a new descriptor array cell. 9796 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 9797 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 9798 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( 9799 isolate, descriptors, number_of_own_descriptors); 9800 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9801 isolate); 9802 new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor); 9803 } 9804 9805 if (FLAG_trace_maps) { 9806 LOG(isolate, MapEvent("CopyForTransition", *map, *new_map, reason)); 9807 } 9808 return new_map; 9809 } 9810 9811 Handle<Map> Map::Copy(Isolate* isolate, Handle<Map> map, const char* reason) { 9812 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 9813 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); 9814 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( 9815 isolate, descriptors, number_of_own_descriptors); 9816 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9817 isolate); 9818 return CopyReplaceDescriptors( 9819 isolate, map, new_descriptors, new_layout_descriptor, OMIT_TRANSITION, 9820 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION); 9821 } 9822 9823 9824 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) { 9825 Handle<Map> copy = 9826 Copy(isolate, handle(isolate->object_function()->initial_map(), isolate), 9827 "MapCreate"); 9828 9829 // Check that we do not overflow the instance size when adding the extra 9830 // inobject properties. If the instance size overflows, we allocate as many 9831 // properties as we can as inobject properties. 9832 if (inobject_properties > JSObject::kMaxInObjectProperties) { 9833 inobject_properties = JSObject::kMaxInObjectProperties; 9834 } 9835 9836 int new_instance_size = 9837 JSObject::kHeaderSize + kPointerSize * inobject_properties; 9838 9839 // Adjust the map with the extra inobject properties. 9840 copy->set_instance_size(new_instance_size); 9841 copy->SetInObjectPropertiesStartInWords(JSObject::kHeaderSize / kPointerSize); 9842 DCHECK_EQ(copy->GetInObjectProperties(), inobject_properties); 9843 copy->SetInObjectUnusedPropertyFields(inobject_properties); 9844 copy->set_visitor_id(Map::GetVisitorId(*copy)); 9845 return copy; 9846 } 9847 9848 Handle<Map> Map::CopyForPreventExtensions(Isolate* isolate, Handle<Map> map, 9849 PropertyAttributes attrs_to_add, 9850 Handle<Symbol> transition_marker, 9851 const char* reason) { 9852 int num_descriptors = map->NumberOfOwnDescriptors(); 9853 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes( 9854 isolate, handle(map->instance_descriptors(), isolate), num_descriptors, 9855 attrs_to_add); 9856 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), 9857 isolate); 9858 Handle<Map> new_map = CopyReplaceDescriptors( 9859 isolate, map, new_desc, new_layout_descriptor, INSERT_TRANSITION, 9860 transition_marker, reason, SPECIAL_TRANSITION); 9861 new_map->set_is_extensible(false); 9862 if (!IsFixedTypedArrayElementsKind(map->elements_kind())) { 9863 ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind()) 9864 ? SLOW_STRING_WRAPPER_ELEMENTS 9865 : DICTIONARY_ELEMENTS; 9866 new_map->set_elements_kind(new_kind); 9867 } 9868 return new_map; 9869 } 9870 9871 namespace { 9872 9873 bool CanHoldValue(DescriptorArray* descriptors, int descriptor, 9874 PropertyConstness constness, Object* value) { 9875 PropertyDetails details = descriptors->GetDetails(descriptor); 9876 if (details.location() == kField) { 9877 if (details.kind() == kData) { 9878 return IsGeneralizableTo(constness, details.constness()) && 9879 value->FitsRepresentation(details.representation()) && 9880 descriptors->GetFieldType(descriptor)->NowContains(value); 9881 } else { 9882 DCHECK_EQ(kAccessor, details.kind()); 9883 return false; 9884 } 9885 9886 } else { 9887 DCHECK_EQ(kDescriptor, details.location()); 9888 DCHECK_EQ(PropertyConstness::kConst, details.constness()); 9889 if (details.kind() == kData) { 9890 DCHECK(!FLAG_track_constant_fields); 9891 DCHECK(descriptors->GetStrongValue(descriptor) != value || 9892 value->FitsRepresentation(details.representation())); 9893 return descriptors->GetStrongValue(descriptor) == value; 9894 } else { 9895 DCHECK_EQ(kAccessor, details.kind()); 9896 return false; 9897 } 9898 } 9899 UNREACHABLE(); 9900 } 9901 9902 Handle<Map> UpdateDescriptorForValue(Isolate* isolate, Handle<Map> map, 9903 int descriptor, 9904 PropertyConstness constness, 9905 Handle<Object> value) { 9906 if (CanHoldValue(map->instance_descriptors(), descriptor, constness, 9907 *value)) { 9908 return map; 9909 } 9910 9911 PropertyAttributes attributes = 9912 map->instance_descriptors()->GetDetails(descriptor).attributes(); 9913 Representation representation = value->OptimalRepresentation(); 9914 Handle<FieldType> type = value->OptimalType(isolate, representation); 9915 9916 MapUpdater mu(isolate, map); 9917 return mu.ReconfigureToDataField(descriptor, attributes, constness, 9918 representation, type); 9919 } 9920 9921 } // namespace 9922 9923 // static 9924 Handle<Map> Map::PrepareForDataProperty(Isolate* isolate, Handle<Map> map, 9925 int descriptor, 9926 PropertyConstness constness, 9927 Handle<Object> value) { 9928 // Dictionaries can store any property value. 9929 DCHECK(!map->is_dictionary_map()); 9930 // Update to the newest map before storing the property. 9931 return UpdateDescriptorForValue(isolate, Update(isolate, map), descriptor, 9932 constness, value); 9933 } 9934 9935 Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map, 9936 Handle<Name> name, 9937 Handle<Object> value, 9938 PropertyAttributes attributes, 9939 PropertyConstness constness, 9940 StoreFromKeyed store_mode) { 9941 RuntimeCallTimerScope stats_scope( 9942 isolate, *map, 9943 map->is_prototype_map() 9944 ? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty 9945 : RuntimeCallCounterId::kMap_TransitionToDataProperty); 9946 9947 DCHECK(name->IsUniqueName()); 9948 DCHECK(!map->is_dictionary_map()); 9949 9950 // Migrate to the newest map before storing the property. 9951 map = Update(isolate, map); 9952 9953 Map* maybe_transition = TransitionsAccessor(isolate, map) 9954 .SearchTransition(*name, kData, attributes); 9955 if (maybe_transition != nullptr) { 9956 Handle<Map> transition(maybe_transition, isolate); 9957 int descriptor = transition->LastAdded(); 9958 9959 DCHECK_EQ(attributes, transition->instance_descriptors() 9960 ->GetDetails(descriptor) 9961 .attributes()); 9962 9963 return UpdateDescriptorForValue(isolate, transition, descriptor, constness, 9964 value); 9965 } 9966 9967 TransitionFlag flag = INSERT_TRANSITION; 9968 MaybeHandle<Map> maybe_map; 9969 if (!map->TooManyFastProperties(store_mode)) { 9970 if (!FLAG_track_constant_fields && value->IsJSFunction()) { 9971 maybe_map = 9972 Map::CopyWithConstant(isolate, map, name, value, attributes, flag); 9973 } else { 9974 Representation representation = value->OptimalRepresentation(); 9975 Handle<FieldType> type = value->OptimalType(isolate, representation); 9976 maybe_map = Map::CopyWithField(isolate, map, name, type, attributes, 9977 constness, representation, flag); 9978 } 9979 } 9980 9981 Handle<Map> result; 9982 if (!maybe_map.ToHandle(&result)) { 9983 const char* reason = "TooManyFastProperties"; 9984 #if V8_TRACE_MAPS 9985 std::unique_ptr<ScopedVector<char>> buffer; 9986 if (FLAG_trace_maps) { 9987 ScopedVector<char> name_buffer(100); 9988 name->NameShortPrint(name_buffer); 9989 buffer.reset(new ScopedVector<char>(128)); 9990 SNPrintF(*buffer, "TooManyFastProperties %s", name_buffer.start()); 9991 reason = buffer->start(); 9992 } 9993 #endif 9994 Handle<Object> maybe_constructor(map->GetConstructor(), isolate); 9995 if (FLAG_feedback_normalization && map->new_target_is_base() && 9996 maybe_constructor->IsJSFunction() && 9997 !JSFunction::cast(*maybe_constructor)->shared()->native()) { 9998 Handle<JSFunction> constructor = 9999 Handle<JSFunction>::cast(maybe_constructor); 10000 DCHECK_NE(*constructor, 10001 constructor->context()->native_context()->object_function()); 10002 Handle<Map> initial_map(constructor->initial_map(), isolate); 10003 result = Map::Normalize(isolate, initial_map, CLEAR_INOBJECT_PROPERTIES, 10004 reason); 10005 initial_map->DeprecateTransitionTree(isolate); 10006 Handle<Object> prototype(result->prototype(), isolate); 10007 JSFunction::SetInitialMap(constructor, result, prototype); 10008 10009 // Deoptimize all code that embeds the previous initial map. 10010 initial_map->dependent_code()->DeoptimizeDependentCodeGroup( 10011 isolate, DependentCode::kInitialMapChangedGroup); 10012 if (!result->EquivalentToForNormalization(*map, 10013 CLEAR_INOBJECT_PROPERTIES)) { 10014 result = 10015 Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason); 10016 } 10017 } else { 10018 result = Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason); 10019 } 10020 } 10021 10022 return result; 10023 } 10024 10025 Handle<Map> Map::ReconfigureExistingProperty(Isolate* isolate, Handle<Map> map, 10026 int descriptor, PropertyKind kind, 10027 PropertyAttributes attributes) { 10028 // Dictionaries have to be reconfigured in-place. 10029 DCHECK(!map->is_dictionary_map()); 10030 10031 if (!map->GetBackPointer()->IsMap()) { 10032 // There is no benefit from reconstructing transition tree for maps without 10033 // back pointers. 10034 return CopyGeneralizeAllFields(isolate, map, map->elements_kind(), 10035 descriptor, kind, attributes, 10036 "GenAll_AttributesMismatchProtoMap"); 10037 } 10038 10039 if (FLAG_trace_generalization) { 10040 map->PrintReconfiguration(isolate, stdout, descriptor, kind, attributes); 10041 } 10042 10043 MapUpdater mu(isolate, map); 10044 DCHECK_EQ(kData, kind); // Only kData case is supported so far. 10045 Handle<Map> new_map = mu.ReconfigureToDataField( 10046 descriptor, attributes, kDefaultFieldConstness, Representation::None(), 10047 FieldType::None(isolate)); 10048 return new_map; 10049 } 10050 10051 Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map, 10052 Handle<Name> name, int descriptor, 10053 Handle<Object> getter, 10054 Handle<Object> setter, 10055 PropertyAttributes attributes) { 10056 RuntimeCallTimerScope stats_scope( 10057 isolate, 10058 map->is_prototype_map() 10059 ? RuntimeCallCounterId::kPrototypeMap_TransitionToAccessorProperty 10060 : RuntimeCallCounterId::kMap_TransitionToAccessorProperty); 10061 10062 // At least one of the accessors needs to be a new value. 10063 DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate)); 10064 DCHECK(name->IsUniqueName()); 10065 10066 // Dictionary maps can always have additional data properties. 10067 if (map->is_dictionary_map()) return map; 10068 10069 // Migrate to the newest map before transitioning to the new property. 10070 map = Update(isolate, map); 10071 10072 PropertyNormalizationMode mode = map->is_prototype_map() 10073 ? KEEP_INOBJECT_PROPERTIES 10074 : CLEAR_INOBJECT_PROPERTIES; 10075 10076 Map* maybe_transition = TransitionsAccessor(isolate, map) 10077 .SearchTransition(*name, kAccessor, attributes); 10078 if (maybe_transition != nullptr) { 10079 Handle<Map> transition(maybe_transition, isolate); 10080 DescriptorArray* descriptors = transition->instance_descriptors(); 10081 int descriptor = transition->LastAdded(); 10082 DCHECK(descriptors->GetKey(descriptor)->Equals(*name)); 10083 10084 DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind()); 10085 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes()); 10086 10087 Handle<Object> maybe_pair(descriptors->GetStrongValue(descriptor), isolate); 10088 if (!maybe_pair->IsAccessorPair()) { 10089 return Map::Normalize(isolate, map, mode, 10090 "TransitionToAccessorFromNonPair"); 10091 } 10092 10093 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair); 10094 if (!pair->Equals(*getter, *setter)) { 10095 return Map::Normalize(isolate, map, mode, 10096 "TransitionToDifferentAccessor"); 10097 } 10098 10099 return transition; 10100 } 10101 10102 Handle<AccessorPair> pair; 10103 DescriptorArray* old_descriptors = map->instance_descriptors(); 10104 if (descriptor != DescriptorArray::kNotFound) { 10105 if (descriptor != map->LastAdded()) { 10106 return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonLast"); 10107 } 10108 PropertyDetails old_details = old_descriptors->GetDetails(descriptor); 10109 if (old_details.kind() != kAccessor) { 10110 return Map::Normalize(isolate, map, mode, 10111 "AccessorsOverwritingNonAccessors"); 10112 } 10113 10114 if (old_details.attributes() != attributes) { 10115 return Map::Normalize(isolate, map, mode, "AccessorsWithAttributes"); 10116 } 10117 10118 Handle<Object> maybe_pair(old_descriptors->GetStrongValue(descriptor), 10119 isolate); 10120 if (!maybe_pair->IsAccessorPair()) { 10121 return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonPair"); 10122 } 10123 10124 Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair); 10125 if (current_pair->Equals(*getter, *setter)) return map; 10126 10127 bool overwriting_accessor = false; 10128 if (!getter->IsNull(isolate) && 10129 !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) && 10130 current_pair->get(ACCESSOR_GETTER) != *getter) { 10131 overwriting_accessor = true; 10132 } 10133 if (!setter->IsNull(isolate) && 10134 !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) && 10135 current_pair->get(ACCESSOR_SETTER) != *setter) { 10136 overwriting_accessor = true; 10137 } 10138 if (overwriting_accessor) { 10139 return Map::Normalize(isolate, map, mode, 10140 "AccessorsOverwritingAccessors"); 10141 } 10142 10143 pair = AccessorPair::Copy(isolate, Handle<AccessorPair>::cast(maybe_pair)); 10144 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors || 10145 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) { 10146 return Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, 10147 "TooManyAccessors"); 10148 } else { 10149 pair = isolate->factory()->NewAccessorPair(); 10150 } 10151 10152 pair->SetComponents(*getter, *setter); 10153 10154 TransitionFlag flag = INSERT_TRANSITION; 10155 Descriptor d = Descriptor::AccessorConstant(name, pair, attributes); 10156 return Map::CopyInsertDescriptor(isolate, map, &d, flag); 10157 } 10158 10159 Handle<Map> Map::CopyAddDescriptor(Isolate* isolate, Handle<Map> map, 10160 Descriptor* descriptor, 10161 TransitionFlag flag) { 10162 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 10163 10164 // Share descriptors only if map owns descriptors and it not an initial map. 10165 if (flag == INSERT_TRANSITION && map->owns_descriptors() && 10166 !map->GetBackPointer()->IsUndefined(isolate) && 10167 TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) { 10168 return ShareDescriptor(isolate, map, descriptors, descriptor); 10169 } 10170 10171 int nof = map->NumberOfOwnDescriptors(); 10172 Handle<DescriptorArray> new_descriptors = 10173 DescriptorArray::CopyUpTo(isolate, descriptors, nof, 1); 10174 new_descriptors->Append(descriptor); 10175 10176 Handle<LayoutDescriptor> new_layout_descriptor = 10177 FLAG_unbox_double_fields 10178 ? LayoutDescriptor::New(isolate, map, new_descriptors, nof + 1) 10179 : handle(LayoutDescriptor::FastPointerLayout(), isolate); 10180 10181 return CopyReplaceDescriptors( 10182 isolate, map, new_descriptors, new_layout_descriptor, flag, 10183 descriptor->GetKey(), "CopyAddDescriptor", SIMPLE_PROPERTY_TRANSITION); 10184 } 10185 10186 Handle<Map> Map::CopyInsertDescriptor(Isolate* isolate, Handle<Map> map, 10187 Descriptor* descriptor, 10188 TransitionFlag flag) { 10189 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate); 10190 10191 // We replace the key if it is already present. 10192 int index = 10193 old_descriptors->SearchWithCache(isolate, *descriptor->GetKey(), *map); 10194 if (index != DescriptorArray::kNotFound) { 10195 return CopyReplaceDescriptor(isolate, map, old_descriptors, descriptor, 10196 index, flag); 10197 } 10198 return CopyAddDescriptor(isolate, map, descriptor, flag); 10199 } 10200 10201 Handle<DescriptorArray> DescriptorArray::CopyUpTo(Isolate* isolate, 10202 Handle<DescriptorArray> desc, 10203 int enumeration_index, 10204 int slack) { 10205 return DescriptorArray::CopyUpToAddAttributes(isolate, desc, 10206 enumeration_index, NONE, slack); 10207 } 10208 10209 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes( 10210 Isolate* isolate, Handle<DescriptorArray> desc, int enumeration_index, 10211 PropertyAttributes attributes, int slack) { 10212 if (enumeration_index + slack == 0) { 10213 return isolate->factory()->empty_descriptor_array(); 10214 } 10215 10216 int size = enumeration_index; 10217 10218 Handle<DescriptorArray> descriptors = 10219 DescriptorArray::Allocate(isolate, size, slack); 10220 10221 if (attributes != NONE) { 10222 for (int i = 0; i < size; ++i) { 10223 MaybeObject* value_or_field_type = desc->GetValue(i); 10224 Name* key = desc->GetKey(i); 10225 PropertyDetails details = desc->GetDetails(i); 10226 // Bulk attribute changes never affect private properties. 10227 if (!key->IsPrivate()) { 10228 int mask = DONT_DELETE | DONT_ENUM; 10229 // READ_ONLY is an invalid attribute for JS setters/getters. 10230 HeapObject* heap_object; 10231 if (details.kind() != kAccessor || 10232 !(value_or_field_type->ToStrongHeapObject(&heap_object) && 10233 heap_object->IsAccessorPair())) { 10234 mask |= READ_ONLY; 10235 } 10236 details = details.CopyAddAttributes( 10237 static_cast<PropertyAttributes>(attributes & mask)); 10238 } 10239 descriptors->Set(i, key, value_or_field_type, details); 10240 } 10241 } else { 10242 for (int i = 0; i < size; ++i) { 10243 descriptors->CopyFrom(i, *desc); 10244 } 10245 } 10246 10247 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort(); 10248 10249 return descriptors; 10250 } 10251 10252 // Create a new descriptor array with only enumerable, configurable, writeable 10253 // data properties, but identical field locations. 10254 Handle<DescriptorArray> DescriptorArray::CopyForFastObjectClone( 10255 Isolate* isolate, Handle<DescriptorArray> src, int enumeration_index, 10256 int slack) { 10257 if (enumeration_index + slack == 0) { 10258 return isolate->factory()->empty_descriptor_array(); 10259 } 10260 10261 int size = enumeration_index; 10262 Handle<DescriptorArray> descriptors = 10263 DescriptorArray::Allocate(isolate, size, slack); 10264 10265 for (int i = 0; i < size; ++i) { 10266 Name* key = src->GetKey(i); 10267 PropertyDetails details = src->GetDetails(i); 10268 10269 DCHECK(!key->IsPrivateField()); 10270 DCHECK(details.IsEnumerable()); 10271 DCHECK_EQ(details.kind(), kData); 10272 10273 // Ensure the ObjectClone property details are NONE, and that all source 10274 // details did not contain DONT_ENUM. 10275 PropertyDetails new_details(kData, NONE, details.location(), 10276 details.constness(), details.representation(), 10277 details.field_index()); 10278 // Do not propagate the field type of normal object fields from the 10279 // original descriptors since FieldType changes don't create new maps. 10280 MaybeObject* type = src->GetValue(i); 10281 if (details.location() == PropertyLocation::kField) { 10282 type = MaybeObject::FromObject(FieldType::Any()); 10283 } 10284 descriptors->Set(i, key, type, new_details); 10285 } 10286 10287 descriptors->Sort(); 10288 10289 return descriptors; 10290 } 10291 10292 bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) { 10293 for (int i = 0; i < nof_descriptors; i++) { 10294 if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) { 10295 return false; 10296 } 10297 PropertyDetails details = GetDetails(i); 10298 PropertyDetails other_details = desc->GetDetails(i); 10299 if (details.kind() != other_details.kind() || 10300 details.location() != other_details.location() || 10301 !details.representation().Equals(other_details.representation())) { 10302 return false; 10303 } 10304 } 10305 return true; 10306 } 10307 10308 Handle<Map> Map::CopyReplaceDescriptor(Isolate* isolate, Handle<Map> map, 10309 Handle<DescriptorArray> descriptors, 10310 Descriptor* descriptor, 10311 int insertion_index, 10312 TransitionFlag flag) { 10313 Handle<Name> key = descriptor->GetKey(); 10314 DCHECK_EQ(*key, descriptors->GetKey(insertion_index)); 10315 // This function does not support replacing property fields as 10316 // that would break property field counters. 10317 DCHECK_NE(kField, descriptor->GetDetails().location()); 10318 DCHECK_NE(kField, descriptors->GetDetails(insertion_index).location()); 10319 10320 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( 10321 isolate, descriptors, map->NumberOfOwnDescriptors()); 10322 10323 new_descriptors->Replace(insertion_index, descriptor); 10324 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New( 10325 isolate, map, new_descriptors, new_descriptors->number_of_descriptors()); 10326 10327 SimpleTransitionFlag simple_flag = 10328 (insertion_index == descriptors->number_of_descriptors() - 1) 10329 ? SIMPLE_PROPERTY_TRANSITION 10330 : PROPERTY_TRANSITION; 10331 return CopyReplaceDescriptors(isolate, map, new_descriptors, 10332 new_layout_descriptor, flag, key, 10333 "CopyReplaceDescriptor", simple_flag); 10334 } 10335 10336 Handle<FixedArray> FixedArray::SetAndGrow(Isolate* isolate, 10337 Handle<FixedArray> array, int index, 10338 Handle<Object> value, 10339 PretenureFlag pretenure) { 10340 if (index < array->length()) { 10341 array->set(index, *value); 10342 return array; 10343 } 10344 int capacity = array->length(); 10345 do { 10346 capacity = JSObject::NewElementsCapacity(capacity); 10347 } while (capacity <= index); 10348 Handle<FixedArray> new_array = 10349 isolate->factory()->NewUninitializedFixedArray(capacity, pretenure); 10350 array->CopyTo(0, *new_array, 0, array->length()); 10351 new_array->FillWithHoles(array->length(), new_array->length()); 10352 new_array->set(index, *value); 10353 return new_array; 10354 } 10355 10356 bool FixedArray::ContainsSortedNumbers() { 10357 for (int i = 1; i < length(); ++i) { 10358 Object* a_obj = get(i - 1); 10359 Object* b_obj = get(i); 10360 if (!a_obj->IsNumber() || !b_obj->IsNumber()) return false; 10361 10362 uint32_t a = NumberToUint32(a_obj); 10363 uint32_t b = NumberToUint32(b_obj); 10364 10365 if (a > b) return false; 10366 } 10367 return true; 10368 } 10369 10370 Handle<FixedArray> FixedArray::ShrinkOrEmpty(Isolate* isolate, 10371 Handle<FixedArray> array, 10372 int new_length) { 10373 if (new_length == 0) { 10374 return array->GetReadOnlyRoots().empty_fixed_array_handle(); 10375 } else { 10376 array->Shrink(isolate, new_length); 10377 return array; 10378 } 10379 } 10380 10381 void FixedArray::Shrink(Isolate* isolate, int new_length) { 10382 DCHECK(0 < new_length && new_length <= length()); 10383 if (new_length < length()) { 10384 isolate->heap()->RightTrimFixedArray(this, length() - new_length); 10385 } 10386 } 10387 10388 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, 10389 int len) const { 10390 DisallowHeapAllocation no_gc; 10391 // Return early if len == 0 so that we don't try to read the write barrier off 10392 // a canonical read-only empty fixed array. 10393 if (len == 0) return; 10394 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc); 10395 for (int index = 0; index < len; index++) { 10396 dest->set(dest_pos+index, get(pos+index), mode); 10397 } 10398 } 10399 10400 #ifdef DEBUG 10401 bool FixedArray::IsEqualTo(FixedArray* other) { 10402 if (length() != other->length()) return false; 10403 for (int i = 0 ; i < length(); ++i) { 10404 if (get(i) != other->get(i)) return false; 10405 } 10406 return true; 10407 } 10408 #endif 10409 10410 void JSObject::PrototypeRegistryCompactionCallback(HeapObject* value, 10411 int old_index, 10412 int new_index) { 10413 DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map()); 10414 Map* map = Map::cast(value); 10415 DCHECK(map->prototype_info()->IsPrototypeInfo()); 10416 PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info()); 10417 DCHECK_EQ(old_index, proto_info->registry_slot()); 10418 proto_info->set_registry_slot(new_index); 10419 } 10420 10421 // static 10422 Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array, 10423 Handle<Object> obj) { 10424 int length = array->Length(); 10425 array = EnsureSpace(isolate, array, length + 1); 10426 // Check that GC didn't remove elements from the array. 10427 DCHECK_EQ(array->Length(), length); 10428 array->Set(length, *obj); 10429 array->SetLength(length + 1); 10430 return array; 10431 } 10432 10433 // static 10434 Handle<ArrayList> ArrayList::Add(Isolate* isolate, Handle<ArrayList> array, 10435 Handle<Object> obj1, Handle<Object> obj2) { 10436 int length = array->Length(); 10437 array = EnsureSpace(isolate, array, length + 2); 10438 // Check that GC didn't remove elements from the array. 10439 DCHECK_EQ(array->Length(), length); 10440 array->Set(length, *obj1); 10441 array->Set(length + 1, *obj2); 10442 array->SetLength(length + 2); 10443 return array; 10444 } 10445 10446 // static 10447 Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) { 10448 Handle<FixedArray> fixed_array = 10449 isolate->factory()->NewFixedArray(size + kFirstIndex); 10450 fixed_array->set_map_no_write_barrier( 10451 ReadOnlyRoots(isolate).array_list_map()); 10452 Handle<ArrayList> result = Handle<ArrayList>::cast(fixed_array); 10453 result->SetLength(0); 10454 return result; 10455 } 10456 10457 Handle<FixedArray> ArrayList::Elements(Isolate* isolate, 10458 Handle<ArrayList> array) { 10459 int length = array->Length(); 10460 Handle<FixedArray> result = isolate->factory()->NewFixedArray(length); 10461 // Do not copy the first entry, i.e., the length. 10462 array->CopyTo(kFirstIndex, *result, 0, length); 10463 return result; 10464 } 10465 10466 bool ArrayList::IsFull() { 10467 int capacity = length(); 10468 return kFirstIndex + Length() == capacity; 10469 } 10470 10471 namespace { 10472 10473 Handle<FixedArray> EnsureSpaceInFixedArray(Isolate* isolate, 10474 Handle<FixedArray> array, 10475 int length) { 10476 int capacity = array->length(); 10477 if (capacity < length) { 10478 int new_capacity = length; 10479 new_capacity = new_capacity + Max(new_capacity / 2, 2); 10480 int grow_by = new_capacity - capacity; 10481 array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by); 10482 } 10483 return array; 10484 } 10485 10486 } // namespace 10487 10488 // static 10489 Handle<ArrayList> ArrayList::EnsureSpace(Isolate* isolate, 10490 Handle<ArrayList> array, int length) { 10491 const bool empty = (array->length() == 0); 10492 auto ret = EnsureSpaceInFixedArray(isolate, array, kFirstIndex + length); 10493 if (empty) { 10494 ret->set_map_no_write_barrier(array->GetReadOnlyRoots().array_list_map()); 10495 10496 Handle<ArrayList>::cast(ret)->SetLength(0); 10497 } 10498 return Handle<ArrayList>::cast(ret); 10499 } 10500 10501 // static 10502 Handle<WeakArrayList> WeakArrayList::AddToEnd(Isolate* isolate, 10503 Handle<WeakArrayList> array, 10504 MaybeObjectHandle value) { 10505 int length = array->length(); 10506 array = EnsureSpace(isolate, array, length + 1); 10507 // Reload length; GC might have removed elements from the array. 10508 length = array->length(); 10509 array->Set(length, *value); 10510 array->set_length(length + 1); 10511 return array; 10512 } 10513 10514 bool WeakArrayList::IsFull() { return length() == capacity(); } 10515 10516 // static 10517 Handle<WeakArrayList> WeakArrayList::EnsureSpace(Isolate* isolate, 10518 Handle<WeakArrayList> array, 10519 int length, 10520 PretenureFlag pretenure) { 10521 int capacity = array->capacity(); 10522 if (capacity < length) { 10523 int new_capacity = length; 10524 new_capacity = new_capacity + Max(new_capacity / 2, 2); 10525 int grow_by = new_capacity - capacity; 10526 array = 10527 isolate->factory()->CopyWeakArrayListAndGrow(array, grow_by, pretenure); 10528 } 10529 return array; 10530 } 10531 10532 int WeakArrayList::CountLiveWeakReferences() const { 10533 int live_weak_references = 0; 10534 for (int i = 0; i < length(); i++) { 10535 if (Get(i)->IsWeakHeapObject()) { 10536 ++live_weak_references; 10537 } 10538 } 10539 return live_weak_references; 10540 } 10541 10542 bool WeakArrayList::RemoveOne(MaybeObjectHandle value) { 10543 if (length() == 0) return false; 10544 // Optimize for the most recently added element to be removed again. 10545 int last_index = length() - 1; 10546 for (int i = last_index; i >= 0; --i) { 10547 if (Get(i) == *value) { 10548 // Move the last element into the this slot (or no-op, if this is the 10549 // last slot). 10550 Set(i, Get(last_index)); 10551 Set(last_index, HeapObjectReference::ClearedValue()); 10552 set_length(last_index); 10553 return true; 10554 } 10555 } 10556 return false; 10557 } 10558 10559 // static 10560 Handle<WeakArrayList> PrototypeUsers::Add(Isolate* isolate, 10561 Handle<WeakArrayList> array, 10562 Handle<Map> value, 10563 int* assigned_index) { 10564 int length = array->length(); 10565 if (length == 0) { 10566 // Uninitialized WeakArrayList; need to initialize empty_slot_index. 10567 array = WeakArrayList::EnsureSpace(isolate, array, kFirstIndex + 1); 10568 set_empty_slot_index(*array, kNoEmptySlotsMarker); 10569 array->Set(kFirstIndex, HeapObjectReference::Weak(*value)); 10570 array->set_length(kFirstIndex + 1); 10571 if (assigned_index != nullptr) *assigned_index = kFirstIndex; 10572 return array; 10573 } 10574 10575 // If the array has unfilled space at the end, use it. 10576 if (!array->IsFull()) { 10577 array->Set(length, HeapObjectReference::Weak(*value)); 10578 array->set_length(length + 1); 10579 if (assigned_index != nullptr) *assigned_index = length; 10580 return array; 10581 } 10582 10583 // If there are empty slots, use one of them. 10584 int empty_slot = Smi::ToInt(empty_slot_index(*array)); 10585 if (empty_slot != kNoEmptySlotsMarker) { 10586 DCHECK_GE(empty_slot, kFirstIndex); 10587 CHECK_LT(empty_slot, array->length()); 10588 int next_empty_slot = Smi::ToInt(array->Get(empty_slot)->ToSmi()); 10589 10590 array->Set(empty_slot, HeapObjectReference::Weak(*value)); 10591 if (assigned_index != nullptr) *assigned_index = empty_slot; 10592 10593 set_empty_slot_index(*array, next_empty_slot); 10594 return array; 10595 } else { 10596 DCHECK_EQ(empty_slot, kNoEmptySlotsMarker); 10597 } 10598 10599 // Array full and no empty slots. Grow the array. 10600 array = WeakArrayList::EnsureSpace(isolate, array, length + 1); 10601 array->Set(length, HeapObjectReference::Weak(*value)); 10602 array->set_length(length + 1); 10603 if (assigned_index != nullptr) *assigned_index = length; 10604 return array; 10605 } 10606 10607 WeakArrayList* PrototypeUsers::Compact(Handle<WeakArrayList> array, Heap* heap, 10608 CompactionCallback callback, 10609 PretenureFlag pretenure) { 10610 if (array->length() == 0) { 10611 return *array; 10612 } 10613 int new_length = kFirstIndex + array->CountLiveWeakReferences(); 10614 if (new_length == array->length()) { 10615 return *array; 10616 } 10617 10618 Handle<WeakArrayList> new_array = WeakArrayList::EnsureSpace( 10619 heap->isolate(), 10620 handle(ReadOnlyRoots(heap).empty_weak_array_list(), heap->isolate()), 10621 new_length, pretenure); 10622 // Allocation might have caused GC and turned some of the elements into 10623 // cleared weak heap objects. Count the number of live objects again. 10624 int copy_to = kFirstIndex; 10625 for (int i = kFirstIndex; i < array->length(); i++) { 10626 MaybeObject* element = array->Get(i); 10627 if (element->IsSmi()) continue; 10628 if (element->IsClearedWeakHeapObject()) continue; 10629 HeapObject* value = element->ToWeakHeapObject(); 10630 callback(value, i, copy_to); 10631 new_array->Set(copy_to++, element); 10632 } 10633 new_array->set_length(copy_to); 10634 set_empty_slot_index(*new_array, kNoEmptySlotsMarker); 10635 return *new_array; 10636 } 10637 10638 Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures( 10639 Isolate* isolate, Handle<RegExpMatchInfo> match_info, int capture_count) { 10640 DCHECK_GE(match_info->length(), kLastMatchOverhead); 10641 const int required_length = kFirstCaptureIndex + capture_count; 10642 Handle<FixedArray> result = 10643 EnsureSpaceInFixedArray(isolate, match_info, required_length); 10644 return Handle<RegExpMatchInfo>::cast(result); 10645 } 10646 10647 // static 10648 Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in, 10649 Handle<Object> receiver, 10650 Handle<JSFunction> function, 10651 Handle<AbstractCode> code, 10652 int offset, int flags) { 10653 const int frame_count = in->FrameCount(); 10654 const int new_length = LengthFor(frame_count + 1); 10655 Handle<FrameArray> array = 10656 EnsureSpace(function->GetIsolate(), in, new_length); 10657 array->SetReceiver(frame_count, *receiver); 10658 array->SetFunction(frame_count, *function); 10659 array->SetCode(frame_count, *code); 10660 array->SetOffset(frame_count, Smi::FromInt(offset)); 10661 array->SetFlags(frame_count, Smi::FromInt(flags)); 10662 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1)); 10663 return array; 10664 } 10665 10666 // static 10667 Handle<FrameArray> FrameArray::AppendWasmFrame( 10668 Handle<FrameArray> in, Handle<WasmInstanceObject> wasm_instance, 10669 int wasm_function_index, wasm::WasmCode* code, int offset, int flags) { 10670 Isolate* isolate = wasm_instance->GetIsolate(); 10671 const int frame_count = in->FrameCount(); 10672 const int new_length = LengthFor(frame_count + 1); 10673 Handle<FrameArray> array = EnsureSpace(isolate, in, new_length); 10674 // The {code} will be {nullptr} for interpreted wasm frames. 10675 Handle<Foreign> code_foreign = 10676 isolate->factory()->NewForeign(reinterpret_cast<Address>(code)); 10677 array->SetWasmInstance(frame_count, *wasm_instance); 10678 array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index)); 10679 array->SetWasmCodeObject(frame_count, *code_foreign); 10680 array->SetOffset(frame_count, Smi::FromInt(offset)); 10681 array->SetFlags(frame_count, Smi::FromInt(flags)); 10682 array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1)); 10683 return array; 10684 } 10685 10686 void FrameArray::ShrinkToFit(Isolate* isolate) { 10687 Shrink(isolate, LengthFor(FrameCount())); 10688 } 10689 10690 // static 10691 Handle<FrameArray> FrameArray::EnsureSpace(Isolate* isolate, 10692 Handle<FrameArray> array, 10693 int length) { 10694 return Handle<FrameArray>::cast( 10695 EnsureSpaceInFixedArray(isolate, array, length)); 10696 } 10697 10698 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate, 10699 int number_of_descriptors, 10700 int slack, 10701 PretenureFlag pretenure) { 10702 DCHECK_LE(0, number_of_descriptors); 10703 Factory* factory = isolate->factory(); 10704 // Do not use DescriptorArray::cast on incomplete object. 10705 int size = number_of_descriptors + slack; 10706 if (size == 0) return factory->empty_descriptor_array(); 10707 // Allocate the array of keys. 10708 Handle<WeakFixedArray> result = 10709 factory->NewWeakFixedArrayWithMap<DescriptorArray>( 10710 Heap::kDescriptorArrayMapRootIndex, LengthFor(size), pretenure); 10711 result->Set(kDescriptorLengthIndex, 10712 MaybeObject::FromObject(Smi::FromInt(number_of_descriptors))); 10713 result->Set(kEnumCacheIndex, MaybeObject::FromObject( 10714 ReadOnlyRoots(isolate).empty_enum_cache())); 10715 return Handle<DescriptorArray>::cast(result); 10716 } 10717 10718 void DescriptorArray::ClearEnumCache() { 10719 set(kEnumCacheIndex, 10720 MaybeObject::FromObject(GetReadOnlyRoots().empty_enum_cache())); 10721 } 10722 10723 void DescriptorArray::Replace(int index, Descriptor* descriptor) { 10724 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index)); 10725 Set(index, descriptor); 10726 } 10727 10728 // static 10729 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors, 10730 Isolate* isolate, Handle<FixedArray> keys, 10731 Handle<FixedArray> indices) { 10732 EnumCache* enum_cache = descriptors->GetEnumCache(); 10733 if (enum_cache == ReadOnlyRoots(isolate).empty_enum_cache()) { 10734 enum_cache = *isolate->factory()->NewEnumCache(keys, indices); 10735 descriptors->set(kEnumCacheIndex, MaybeObject::FromObject(enum_cache)); 10736 } else { 10737 enum_cache->set_keys(*keys); 10738 enum_cache->set_indices(*indices); 10739 } 10740 } 10741 10742 void DescriptorArray::CopyFrom(int index, DescriptorArray* src) { 10743 PropertyDetails details = src->GetDetails(index); 10744 Set(index, src->GetKey(index), src->GetValue(index), details); 10745 } 10746 10747 void DescriptorArray::Sort() { 10748 // In-place heap sort. 10749 int len = number_of_descriptors(); 10750 // Reset sorting since the descriptor array might contain invalid pointers. 10751 for (int i = 0; i < len; ++i) SetSortedKey(i, i); 10752 // Bottom-up max-heap construction. 10753 // Index of the last node with children 10754 const int max_parent_index = (len / 2) - 1; 10755 for (int i = max_parent_index; i >= 0; --i) { 10756 int parent_index = i; 10757 const uint32_t parent_hash = GetSortedKey(i)->Hash(); 10758 while (parent_index <= max_parent_index) { 10759 int child_index = 2 * parent_index + 1; 10760 uint32_t child_hash = GetSortedKey(child_index)->Hash(); 10761 if (child_index + 1 < len) { 10762 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash(); 10763 if (right_child_hash > child_hash) { 10764 child_index++; 10765 child_hash = right_child_hash; 10766 } 10767 } 10768 if (child_hash <= parent_hash) break; 10769 SwapSortedKeys(parent_index, child_index); 10770 // Now element at child_index could be < its children. 10771 parent_index = child_index; // parent_hash remains correct. 10772 } 10773 } 10774 10775 // Extract elements and create sorted array. 10776 for (int i = len - 1; i > 0; --i) { 10777 // Put max element at the back of the array. 10778 SwapSortedKeys(0, i); 10779 // Shift down the new top element. 10780 int parent_index = 0; 10781 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash(); 10782 const int max_parent_index = (i / 2) - 1; 10783 while (parent_index <= max_parent_index) { 10784 int child_index = parent_index * 2 + 1; 10785 uint32_t child_hash = GetSortedKey(child_index)->Hash(); 10786 if (child_index + 1 < i) { 10787 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash(); 10788 if (right_child_hash > child_hash) { 10789 child_index++; 10790 child_hash = right_child_hash; 10791 } 10792 } 10793 if (child_hash <= parent_hash) break; 10794 SwapSortedKeys(parent_index, child_index); 10795 parent_index = child_index; 10796 } 10797 } 10798 DCHECK(IsSortedNoDuplicates()); 10799 } 10800 10801 Handle<AccessorPair> AccessorPair::Copy(Isolate* isolate, 10802 Handle<AccessorPair> pair) { 10803 Handle<AccessorPair> copy = isolate->factory()->NewAccessorPair(); 10804 copy->set_getter(pair->getter()); 10805 copy->set_setter(pair->setter()); 10806 return copy; 10807 } 10808 10809 Handle<Object> AccessorPair::GetComponent(Isolate* isolate, 10810 Handle<AccessorPair> accessor_pair, 10811 AccessorComponent component) { 10812 Object* accessor = accessor_pair->get(component); 10813 if (accessor->IsFunctionTemplateInfo()) { 10814 return ApiNatives::InstantiateFunction( 10815 handle(FunctionTemplateInfo::cast(accessor), isolate)) 10816 .ToHandleChecked(); 10817 } 10818 if (accessor->IsNull(isolate)) { 10819 return isolate->factory()->undefined_value(); 10820 } 10821 return handle(accessor, isolate); 10822 } 10823 10824 Handle<DeoptimizationData> DeoptimizationData::New(Isolate* isolate, 10825 int deopt_entry_count, 10826 PretenureFlag pretenure) { 10827 return Handle<DeoptimizationData>::cast(isolate->factory()->NewFixedArray( 10828 LengthFor(deopt_entry_count), pretenure)); 10829 } 10830 10831 Handle<DeoptimizationData> DeoptimizationData::Empty(Isolate* isolate) { 10832 return Handle<DeoptimizationData>::cast( 10833 isolate->factory()->empty_fixed_array()); 10834 } 10835 10836 SharedFunctionInfo* DeoptimizationData::GetInlinedFunction(int index) { 10837 if (index == -1) { 10838 return SharedFunctionInfo::cast(SharedFunctionInfo()); 10839 } else { 10840 return SharedFunctionInfo::cast(LiteralArray()->get(index)); 10841 } 10842 } 10843 10844 #ifdef DEBUG 10845 bool DescriptorArray::IsEqualTo(DescriptorArray* other) { 10846 if (length() != other->length()) return false; 10847 for (int i = 0; i < length(); ++i) { 10848 if (get(i) != other->get(i)) return false; 10849 } 10850 return true; 10851 } 10852 #endif 10853 10854 // static 10855 Handle<String> String::Trim(Isolate* isolate, Handle<String> string, 10856 TrimMode mode) { 10857 string = String::Flatten(isolate, string); 10858 int const length = string->length(); 10859 10860 // Perform left trimming if requested. 10861 int left = 0; 10862 UnicodeCache* unicode_cache = isolate->unicode_cache(); 10863 if (mode == kTrim || mode == kTrimStart) { 10864 while (left < length && 10865 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) { 10866 left++; 10867 } 10868 } 10869 10870 // Perform right trimming if requested. 10871 int right = length; 10872 if (mode == kTrim || mode == kTrimEnd) { 10873 while ( 10874 right > left && 10875 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { 10876 right--; 10877 } 10878 } 10879 10880 return isolate->factory()->NewSubString(string, left, right); 10881 } 10882 10883 bool String::LooksValid() { 10884 // TODO(leszeks): Maybe remove this check entirely, Heap::Contains uses 10885 // basically the same logic as the way we access the heap in the first place. 10886 MemoryChunk* chunk = MemoryChunk::FromHeapObject(this); 10887 // RO_SPACE objects should always be valid. 10888 if (chunk->owner()->identity() == RO_SPACE) return true; 10889 if (chunk->heap() == nullptr) return false; 10890 return chunk->heap()->Contains(this); 10891 } 10892 10893 // static 10894 MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name) { 10895 if (name->IsString()) return Handle<String>::cast(name); 10896 // ES6 section 9.2.11 SetFunctionName, step 4. 10897 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); 10898 if (description->IsUndefined(isolate)) { 10899 return isolate->factory()->empty_string(); 10900 } 10901 IncrementalStringBuilder builder(isolate); 10902 builder.AppendCharacter('['); 10903 builder.AppendString(Handle<String>::cast(description)); 10904 builder.AppendCharacter(']'); 10905 return builder.Finish(); 10906 } 10907 10908 // static 10909 MaybeHandle<String> Name::ToFunctionName(Isolate* isolate, Handle<Name> name, 10910 Handle<String> prefix) { 10911 Handle<String> name_string; 10912 ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, 10913 ToFunctionName(isolate, name), String); 10914 IncrementalStringBuilder builder(isolate); 10915 builder.AppendString(prefix); 10916 builder.AppendCharacter(' '); 10917 builder.AppendString(name_string); 10918 return builder.Finish(); 10919 } 10920 10921 namespace { 10922 10923 bool AreDigits(const uint8_t* s, int from, int to) { 10924 for (int i = from; i < to; i++) { 10925 if (s[i] < '0' || s[i] > '9') return false; 10926 } 10927 10928 return true; 10929 } 10930 10931 10932 int ParseDecimalInteger(const uint8_t* s, int from, int to) { 10933 DCHECK_LT(to - from, 10); // Overflow is not possible. 10934 DCHECK(from < to); 10935 int d = s[from] - '0'; 10936 10937 for (int i = from + 1; i < to; i++) { 10938 d = 10 * d + (s[i] - '0'); 10939 } 10940 10941 return d; 10942 } 10943 10944 } // namespace 10945 10946 // static 10947 Handle<Object> String::ToNumber(Isolate* isolate, Handle<String> subject) { 10948 // Flatten {subject} string first. 10949 subject = String::Flatten(isolate, subject); 10950 10951 // Fast array index case. 10952 uint32_t index; 10953 if (subject->AsArrayIndex(&index)) { 10954 return isolate->factory()->NewNumberFromUint(index); 10955 } 10956 10957 // Fast case: short integer or some sorts of junk values. 10958 if (subject->IsSeqOneByteString()) { 10959 int len = subject->length(); 10960 if (len == 0) return handle(Smi::kZero, isolate); 10961 10962 DisallowHeapAllocation no_gc; 10963 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars(); 10964 bool minus = (data[0] == '-'); 10965 int start_pos = (minus ? 1 : 0); 10966 10967 if (start_pos == len) { 10968 return isolate->factory()->nan_value(); 10969 } else if (data[start_pos] > '9') { 10970 // Fast check for a junk value. A valid string may start from a 10971 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit 10972 // or the 'I' character ('Infinity'). All of that have codes not greater 10973 // than '9' except 'I' and . 10974 if (data[start_pos] != 'I' && data[start_pos] != 0xA0) { 10975 return isolate->factory()->nan_value(); 10976 } 10977 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { 10978 // The maximal/minimal smi has 10 digits. If the string has less digits 10979 // we know it will fit into the smi-data type. 10980 int d = ParseDecimalInteger(data, start_pos, len); 10981 if (minus) { 10982 if (d == 0) return isolate->factory()->minus_zero_value(); 10983 d = -d; 10984 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize && 10985 (len == 1 || data[0] != '0')) { 10986 // String hash is not calculated yet but all the data are present. 10987 // Update the hash field to speed up sequential convertions. 10988 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); 10989 #ifdef DEBUG 10990 subject->Hash(); // Force hash calculation. 10991 DCHECK_EQ(static_cast<int>(subject->hash_field()), 10992 static_cast<int>(hash)); 10993 #endif 10994 subject->set_hash_field(hash); 10995 } 10996 return handle(Smi::FromInt(d), isolate); 10997 } 10998 } 10999 11000 // Slower case. 11001 int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY; 11002 return isolate->factory()->NewNumber( 11003 StringToDouble(isolate, isolate->unicode_cache(), subject, flags)); 11004 } 11005 11006 11007 String::FlatContent String::GetFlatContent() { 11008 DCHECK(!AllowHeapAllocation::IsAllowed()); 11009 int length = this->length(); 11010 StringShape shape(this); 11011 String* string = this; 11012 int offset = 0; 11013 if (shape.representation_tag() == kConsStringTag) { 11014 ConsString* cons = ConsString::cast(string); 11015 if (cons->second()->length() != 0) { 11016 return FlatContent(); 11017 } 11018 string = cons->first(); 11019 shape = StringShape(string); 11020 } else if (shape.representation_tag() == kSlicedStringTag) { 11021 SlicedString* slice = SlicedString::cast(string); 11022 offset = slice->offset(); 11023 string = slice->parent(); 11024 shape = StringShape(string); 11025 DCHECK(shape.representation_tag() != kConsStringTag && 11026 shape.representation_tag() != kSlicedStringTag); 11027 } 11028 if (shape.representation_tag() == kThinStringTag) { 11029 ThinString* thin = ThinString::cast(string); 11030 string = thin->actual(); 11031 shape = StringShape(string); 11032 DCHECK(!shape.IsCons()); 11033 DCHECK(!shape.IsSliced()); 11034 } 11035 if (shape.encoding_tag() == kOneByteStringTag) { 11036 const uint8_t* start; 11037 if (shape.representation_tag() == kSeqStringTag) { 11038 start = SeqOneByteString::cast(string)->GetChars(); 11039 } else { 11040 start = ExternalOneByteString::cast(string)->GetChars(); 11041 } 11042 return FlatContent(start + offset, length); 11043 } else { 11044 DCHECK_EQ(shape.encoding_tag(), kTwoByteStringTag); 11045 const uc16* start; 11046 if (shape.representation_tag() == kSeqStringTag) { 11047 start = SeqTwoByteString::cast(string)->GetChars(); 11048 } else { 11049 start = ExternalTwoByteString::cast(string)->GetChars(); 11050 } 11051 return FlatContent(start + offset, length); 11052 } 11053 } 11054 11055 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls, 11056 RobustnessFlag robust_flag, 11057 int offset, int length, 11058 int* length_return) { 11059 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { 11060 return std::unique_ptr<char[]>(); 11061 } 11062 // Negative length means the to the end of the string. 11063 if (length < 0) length = kMaxInt - offset; 11064 11065 // Compute the size of the UTF-8 string. Start at the specified offset. 11066 StringCharacterStream stream(this, offset); 11067 int character_position = offset; 11068 int utf8_bytes = 0; 11069 int last = unibrow::Utf16::kNoPreviousCharacter; 11070 while (stream.HasMore() && character_position++ < offset + length) { 11071 uint16_t character = stream.GetNext(); 11072 utf8_bytes += unibrow::Utf8::Length(character, last); 11073 last = character; 11074 } 11075 11076 if (length_return) { 11077 *length_return = utf8_bytes; 11078 } 11079 11080 char* result = NewArray<char>(utf8_bytes + 1); 11081 11082 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset. 11083 stream.Reset(this, offset); 11084 character_position = offset; 11085 int utf8_byte_position = 0; 11086 last = unibrow::Utf16::kNoPreviousCharacter; 11087 while (stream.HasMore() && character_position++ < offset + length) { 11088 uint16_t character = stream.GetNext(); 11089 if (allow_nulls == DISALLOW_NULLS && character == 0) { 11090 character = ' '; 11091 } 11092 utf8_byte_position += 11093 unibrow::Utf8::Encode(result + utf8_byte_position, character, last); 11094 last = character; 11095 } 11096 result[utf8_byte_position] = 0; 11097 return std::unique_ptr<char[]>(result); 11098 } 11099 11100 std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls, 11101 RobustnessFlag robust_flag, 11102 int* length_return) { 11103 return ToCString(allow_nulls, robust_flag, 0, -1, length_return); 11104 } 11105 11106 11107 const uc16* String::GetTwoByteData(unsigned start) { 11108 DCHECK(!IsOneByteRepresentationUnderneath()); 11109 switch (StringShape(this).representation_tag()) { 11110 case kSeqStringTag: 11111 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); 11112 case kExternalStringTag: 11113 return ExternalTwoByteString::cast(this)-> 11114 ExternalTwoByteStringGetData(start); 11115 case kSlicedStringTag: { 11116 SlicedString* slice = SlicedString::cast(this); 11117 return slice->parent()->GetTwoByteData(start + slice->offset()); 11118 } 11119 case kConsStringTag: 11120 case kThinStringTag: 11121 UNREACHABLE(); 11122 } 11123 UNREACHABLE(); 11124 } 11125 11126 11127 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { 11128 return reinterpret_cast<uc16*>( 11129 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start; 11130 } 11131 11132 11133 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) { 11134 Relocatable* current = isolate->relocatable_top(); 11135 while (current != nullptr) { 11136 current->PostGarbageCollection(); 11137 current = current->prev_; 11138 } 11139 } 11140 11141 11142 // Reserve space for statics needing saving and restoring. 11143 int Relocatable::ArchiveSpacePerThread() { 11144 return sizeof(Relocatable*); // NOLINT 11145 } 11146 11147 11148 // Archive statics that are thread-local. 11149 char* Relocatable::ArchiveState(Isolate* isolate, char* to) { 11150 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top(); 11151 isolate->set_relocatable_top(nullptr); 11152 return to + ArchiveSpacePerThread(); 11153 } 11154 11155 11156 // Restore statics that are thread-local. 11157 char* Relocatable::RestoreState(Isolate* isolate, char* from) { 11158 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from)); 11159 return from + ArchiveSpacePerThread(); 11160 } 11161 11162 char* Relocatable::Iterate(RootVisitor* v, char* thread_storage) { 11163 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage); 11164 Iterate(v, top); 11165 return thread_storage + ArchiveSpacePerThread(); 11166 } 11167 11168 void Relocatable::Iterate(Isolate* isolate, RootVisitor* v) { 11169 Iterate(v, isolate->relocatable_top()); 11170 } 11171 11172 void Relocatable::Iterate(RootVisitor* v, Relocatable* top) { 11173 Relocatable* current = top; 11174 while (current != nullptr) { 11175 current->IterateInstance(v); 11176 current = current->prev_; 11177 } 11178 } 11179 11180 11181 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str) 11182 : Relocatable(isolate), 11183 str_(str.location()), 11184 length_(str->length()) { 11185 PostGarbageCollection(); 11186 } 11187 11188 11189 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input) 11190 : Relocatable(isolate), 11191 str_(0), 11192 is_one_byte_(true), 11193 length_(input.length()), 11194 start_(input.start()) {} 11195 11196 11197 void FlatStringReader::PostGarbageCollection() { 11198 if (str_ == nullptr) return; 11199 Handle<String> str(str_); 11200 DCHECK(str->IsFlat()); 11201 DisallowHeapAllocation no_gc; 11202 // This does not actually prevent the vector from being relocated later. 11203 String::FlatContent content = str->GetFlatContent(); 11204 DCHECK(content.IsFlat()); 11205 is_one_byte_ = content.IsOneByte(); 11206 if (is_one_byte_) { 11207 start_ = content.ToOneByteVector().start(); 11208 } else { 11209 start_ = content.ToUC16Vector().start(); 11210 } 11211 } 11212 11213 11214 void ConsStringIterator::Initialize(ConsString* cons_string, int offset) { 11215 DCHECK_NOT_NULL(cons_string); 11216 root_ = cons_string; 11217 consumed_ = offset; 11218 // Force stack blown condition to trigger restart. 11219 depth_ = 1; 11220 maximum_depth_ = kStackSize + depth_; 11221 DCHECK(StackBlown()); 11222 } 11223 11224 11225 String* ConsStringIterator::Continue(int* offset_out) { 11226 DCHECK_NE(depth_, 0); 11227 DCHECK_EQ(0, *offset_out); 11228 bool blew_stack = StackBlown(); 11229 String* string = nullptr; 11230 // Get the next leaf if there is one. 11231 if (!blew_stack) string = NextLeaf(&blew_stack); 11232 // Restart search from root. 11233 if (blew_stack) { 11234 DCHECK_NULL(string); 11235 string = Search(offset_out); 11236 } 11237 // Ensure future calls return null immediately. 11238 if (string == nullptr) Reset(nullptr); 11239 return string; 11240 } 11241 11242 11243 String* ConsStringIterator::Search(int* offset_out) { 11244 ConsString* cons_string = root_; 11245 // Reset the stack, pushing the root string. 11246 depth_ = 1; 11247 maximum_depth_ = 1; 11248 frames_[0] = cons_string; 11249 const int consumed = consumed_; 11250 int offset = 0; 11251 while (true) { 11252 // Loop until the string is found which contains the target offset. 11253 String* string = cons_string->first(); 11254 int length = string->length(); 11255 int32_t type; 11256 if (consumed < offset + length) { 11257 // Target offset is in the left branch. 11258 // Keep going if we're still in a ConString. 11259 type = string->map()->instance_type(); 11260 if ((type & kStringRepresentationMask) == kConsStringTag) { 11261 cons_string = ConsString::cast(string); 11262 PushLeft(cons_string); 11263 continue; 11264 } 11265 // Tell the stack we're done descending. 11266 AdjustMaximumDepth(); 11267 } else { 11268 // Descend right. 11269 // Update progress through the string. 11270 offset += length; 11271 // Keep going if we're still in a ConString. 11272 string = cons_string->second(); 11273 type = string->map()->instance_type(); 11274 if ((type & kStringRepresentationMask) == kConsStringTag) { 11275 cons_string = ConsString::cast(string); 11276 PushRight(cons_string); 11277 continue; 11278 } 11279 // Need this to be updated for the current string. 11280 length = string->length(); 11281 // Account for the possibility of an empty right leaf. 11282 // This happens only if we have asked for an offset outside the string. 11283 if (length == 0) { 11284 // Reset so future operations will return null immediately. 11285 Reset(nullptr); 11286 return nullptr; 11287 } 11288 // Tell the stack we're done descending. 11289 AdjustMaximumDepth(); 11290 // Pop stack so next iteration is in correct place. 11291 Pop(); 11292 } 11293 DCHECK_NE(length, 0); 11294 // Adjust return values and exit. 11295 consumed_ = offset + length; 11296 *offset_out = consumed - offset; 11297 return string; 11298 } 11299 UNREACHABLE(); 11300 } 11301 11302 11303 String* ConsStringIterator::NextLeaf(bool* blew_stack) { 11304 while (true) { 11305 // Tree traversal complete. 11306 if (depth_ == 0) { 11307 *blew_stack = false; 11308 return nullptr; 11309 } 11310 // We've lost track of higher nodes. 11311 if (StackBlown()) { 11312 *blew_stack = true; 11313 return nullptr; 11314 } 11315 // Go right. 11316 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)]; 11317 String* string = cons_string->second(); 11318 int32_t type = string->map()->instance_type(); 11319 if ((type & kStringRepresentationMask) != kConsStringTag) { 11320 // Pop stack so next iteration is in correct place. 11321 Pop(); 11322 int length = string->length(); 11323 // Could be a flattened ConsString. 11324 if (length == 0) continue; 11325 consumed_ += length; 11326 return string; 11327 } 11328 cons_string = ConsString::cast(string); 11329 PushRight(cons_string); 11330 // Need to traverse all the way left. 11331 while (true) { 11332 // Continue left. 11333 string = cons_string->first(); 11334 type = string->map()->instance_type(); 11335 if ((type & kStringRepresentationMask) != kConsStringTag) { 11336 AdjustMaximumDepth(); 11337 int length = string->length(); 11338 if (length == 0) break; // Skip empty left-hand sides of ConsStrings. 11339 consumed_ += length; 11340 return string; 11341 } 11342 cons_string = ConsString::cast(string); 11343 PushLeft(cons_string); 11344 } 11345 } 11346 UNREACHABLE(); 11347 } 11348 11349 11350 uint16_t ConsString::ConsStringGet(int index) { 11351 DCHECK(index >= 0 && index < this->length()); 11352 11353 // Check for a flattened cons string 11354 if (second()->length() == 0) { 11355 String* left = first(); 11356 return left->Get(index); 11357 } 11358 11359 String* string = String::cast(this); 11360 11361 while (true) { 11362 if (StringShape(string).IsCons()) { 11363 ConsString* cons_string = ConsString::cast(string); 11364 String* left = cons_string->first(); 11365 if (left->length() > index) { 11366 string = left; 11367 } else { 11368 index -= left->length(); 11369 string = cons_string->second(); 11370 } 11371 } else { 11372 return string->Get(index); 11373 } 11374 } 11375 11376 UNREACHABLE(); 11377 } 11378 11379 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); } 11380 11381 uint16_t SlicedString::SlicedStringGet(int index) { 11382 return parent()->Get(offset() + index); 11383 } 11384 11385 11386 template <typename sinkchar> 11387 void String::WriteToFlat(String* src, 11388 sinkchar* sink, 11389 int f, 11390 int t) { 11391 String* source = src; 11392 int from = f; 11393 int to = t; 11394 while (true) { 11395 DCHECK(0 <= from && from <= to && to <= source->length()); 11396 switch (StringShape(source).full_representation_tag()) { 11397 case kOneByteStringTag | kExternalStringTag: { 11398 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from, 11399 to - from); 11400 return; 11401 } 11402 case kTwoByteStringTag | kExternalStringTag: { 11403 const uc16* data = 11404 ExternalTwoByteString::cast(source)->GetChars(); 11405 CopyChars(sink, 11406 data + from, 11407 to - from); 11408 return; 11409 } 11410 case kOneByteStringTag | kSeqStringTag: { 11411 CopyChars(sink, 11412 SeqOneByteString::cast(source)->GetChars() + from, 11413 to - from); 11414 return; 11415 } 11416 case kTwoByteStringTag | kSeqStringTag: { 11417 CopyChars(sink, 11418 SeqTwoByteString::cast(source)->GetChars() + from, 11419 to - from); 11420 return; 11421 } 11422 case kOneByteStringTag | kConsStringTag: 11423 case kTwoByteStringTag | kConsStringTag: { 11424 ConsString* cons_string = ConsString::cast(source); 11425 String* first = cons_string->first(); 11426 int boundary = first->length(); 11427 if (to - boundary >= boundary - from) { 11428 // Right hand side is longer. Recurse over left. 11429 if (from < boundary) { 11430 WriteToFlat(first, sink, from, boundary); 11431 if (from == 0 && cons_string->second() == first) { 11432 CopyChars(sink + boundary, sink, boundary); 11433 return; 11434 } 11435 sink += boundary - from; 11436 from = 0; 11437 } else { 11438 from -= boundary; 11439 } 11440 to -= boundary; 11441 source = cons_string->second(); 11442 } else { 11443 // Left hand side is longer. Recurse over right. 11444 if (to > boundary) { 11445 String* second = cons_string->second(); 11446 // When repeatedly appending to a string, we get a cons string that 11447 // is unbalanced to the left, a list, essentially. We inline the 11448 // common case of sequential one-byte right child. 11449 if (to - boundary == 1) { 11450 sink[boundary - from] = static_cast<sinkchar>(second->Get(0)); 11451 } else if (second->IsSeqOneByteString()) { 11452 CopyChars(sink + boundary - from, 11453 SeqOneByteString::cast(second)->GetChars(), 11454 to - boundary); 11455 } else { 11456 WriteToFlat(second, 11457 sink + boundary - from, 11458 0, 11459 to - boundary); 11460 } 11461 to = boundary; 11462 } 11463 source = first; 11464 } 11465 break; 11466 } 11467 case kOneByteStringTag | kSlicedStringTag: 11468 case kTwoByteStringTag | kSlicedStringTag: { 11469 SlicedString* slice = SlicedString::cast(source); 11470 unsigned offset = slice->offset(); 11471 WriteToFlat(slice->parent(), sink, from + offset, to + offset); 11472 return; 11473 } 11474 case kOneByteStringTag | kThinStringTag: 11475 case kTwoByteStringTag | kThinStringTag: 11476 source = ThinString::cast(source)->actual(); 11477 break; 11478 } 11479 } 11480 } 11481 11482 template <typename SourceChar> 11483 static void CalculateLineEndsImpl(Isolate* isolate, std::vector<int>* line_ends, 11484 Vector<const SourceChar> src, 11485 bool include_ending_line) { 11486 const int src_len = src.length(); 11487 UnicodeCache* cache = isolate->unicode_cache(); 11488 for (int i = 0; i < src_len - 1; i++) { 11489 SourceChar current = src[i]; 11490 SourceChar next = src[i + 1]; 11491 if (cache->IsLineTerminatorSequence(current, next)) line_ends->push_back(i); 11492 } 11493 11494 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) { 11495 line_ends->push_back(src_len - 1); 11496 } 11497 if (include_ending_line) { 11498 // Include one character beyond the end of script. The rewriter uses that 11499 // position for the implicit return statement. 11500 line_ends->push_back(src_len); 11501 } 11502 } 11503 11504 Handle<FixedArray> String::CalculateLineEnds(Isolate* isolate, 11505 Handle<String> src, 11506 bool include_ending_line) { 11507 src = Flatten(isolate, src); 11508 // Rough estimate of line count based on a roughly estimated average 11509 // length of (unpacked) code. 11510 int line_count_estimate = src->length() >> 4; 11511 std::vector<int> line_ends; 11512 line_ends.reserve(line_count_estimate); 11513 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid. 11514 // Dispatch on type of strings. 11515 String::FlatContent content = src->GetFlatContent(); 11516 DCHECK(content.IsFlat()); 11517 if (content.IsOneByte()) { 11518 CalculateLineEndsImpl(isolate, 11519 &line_ends, 11520 content.ToOneByteVector(), 11521 include_ending_line); 11522 } else { 11523 CalculateLineEndsImpl(isolate, 11524 &line_ends, 11525 content.ToUC16Vector(), 11526 include_ending_line); 11527 } 11528 } 11529 int line_count = static_cast<int>(line_ends.size()); 11530 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count); 11531 for (int i = 0; i < line_count; i++) { 11532 array->set(i, Smi::FromInt(line_ends[i])); 11533 } 11534 return array; 11535 } 11536 11537 11538 // Compares the contents of two strings by reading and comparing 11539 // int-sized blocks of characters. 11540 template <typename Char> 11541 static inline bool CompareRawStringContents(const Char* const a, 11542 const Char* const b, 11543 int length) { 11544 return CompareChars(a, b, length) == 0; 11545 } 11546 11547 11548 template<typename Chars1, typename Chars2> 11549 class RawStringComparator : public AllStatic { 11550 public: 11551 static inline bool compare(const Chars1* a, const Chars2* b, int len) { 11552 DCHECK(sizeof(Chars1) != sizeof(Chars2)); 11553 for (int i = 0; i < len; i++) { 11554 if (a[i] != b[i]) { 11555 return false; 11556 } 11557 } 11558 return true; 11559 } 11560 }; 11561 11562 11563 template<> 11564 class RawStringComparator<uint16_t, uint16_t> { 11565 public: 11566 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) { 11567 return CompareRawStringContents(a, b, len); 11568 } 11569 }; 11570 11571 11572 template<> 11573 class RawStringComparator<uint8_t, uint8_t> { 11574 public: 11575 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) { 11576 return CompareRawStringContents(a, b, len); 11577 } 11578 }; 11579 11580 11581 class StringComparator { 11582 class State { 11583 public: 11584 State() : is_one_byte_(true), length_(0), buffer8_(nullptr) {} 11585 11586 void Init(String* string) { 11587 ConsString* cons_string = String::VisitFlat(this, string); 11588 iter_.Reset(cons_string); 11589 if (cons_string != nullptr) { 11590 int offset; 11591 string = iter_.Next(&offset); 11592 String::VisitFlat(this, string, offset); 11593 } 11594 } 11595 11596 inline void VisitOneByteString(const uint8_t* chars, int length) { 11597 is_one_byte_ = true; 11598 buffer8_ = chars; 11599 length_ = length; 11600 } 11601 11602 inline void VisitTwoByteString(const uint16_t* chars, int length) { 11603 is_one_byte_ = false; 11604 buffer16_ = chars; 11605 length_ = length; 11606 } 11607 11608 void Advance(int consumed) { 11609 DCHECK(consumed <= length_); 11610 // Still in buffer. 11611 if (length_ != consumed) { 11612 if (is_one_byte_) { 11613 buffer8_ += consumed; 11614 } else { 11615 buffer16_ += consumed; 11616 } 11617 length_ -= consumed; 11618 return; 11619 } 11620 // Advance state. 11621 int offset; 11622 String* next = iter_.Next(&offset); 11623 DCHECK_EQ(0, offset); 11624 DCHECK_NOT_NULL(next); 11625 String::VisitFlat(this, next); 11626 } 11627 11628 ConsStringIterator iter_; 11629 bool is_one_byte_; 11630 int length_; 11631 union { 11632 const uint8_t* buffer8_; 11633 const uint16_t* buffer16_; 11634 }; 11635 11636 private: 11637 DISALLOW_COPY_AND_ASSIGN(State); 11638 }; 11639 11640 public: 11641 inline StringComparator() {} 11642 11643 template<typename Chars1, typename Chars2> 11644 static inline bool Equals(State* state_1, State* state_2, int to_check) { 11645 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_); 11646 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_); 11647 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check); 11648 } 11649 11650 bool Equals(String* string_1, String* string_2) { 11651 int length = string_1->length(); 11652 state_1_.Init(string_1); 11653 state_2_.Init(string_2); 11654 while (true) { 11655 int to_check = Min(state_1_.length_, state_2_.length_); 11656 DCHECK(to_check > 0 && to_check <= length); 11657 bool is_equal; 11658 if (state_1_.is_one_byte_) { 11659 if (state_2_.is_one_byte_) { 11660 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check); 11661 } else { 11662 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check); 11663 } 11664 } else { 11665 if (state_2_.is_one_byte_) { 11666 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check); 11667 } else { 11668 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check); 11669 } 11670 } 11671 // Looping done. 11672 if (!is_equal) return false; 11673 length -= to_check; 11674 // Exit condition. Strings are equal. 11675 if (length == 0) return true; 11676 state_1_.Advance(to_check); 11677 state_2_.Advance(to_check); 11678 } 11679 } 11680 11681 private: 11682 State state_1_; 11683 State state_2_; 11684 11685 DISALLOW_COPY_AND_ASSIGN(StringComparator); 11686 }; 11687 11688 11689 bool String::SlowEquals(String* other) { 11690 DisallowHeapAllocation no_gc; 11691 // Fast check: negative check with lengths. 11692 int len = length(); 11693 if (len != other->length()) return false; 11694 if (len == 0) return true; 11695 11696 // Fast check: if at least one ThinString is involved, dereference it/them 11697 // and restart. 11698 if (this->IsThinString() || other->IsThinString()) { 11699 if (other->IsThinString()) other = ThinString::cast(other)->actual(); 11700 if (this->IsThinString()) { 11701 return ThinString::cast(this)->actual()->Equals(other); 11702 } else { 11703 return this->Equals(other); 11704 } 11705 } 11706 11707 // Fast check: if hash code is computed for both strings 11708 // a fast negative check can be performed. 11709 if (HasHashCode() && other->HasHashCode()) { 11710 #ifdef ENABLE_SLOW_DCHECKS 11711 if (FLAG_enable_slow_asserts) { 11712 if (Hash() != other->Hash()) { 11713 bool found_difference = false; 11714 for (int i = 0; i < len; i++) { 11715 if (Get(i) != other->Get(i)) { 11716 found_difference = true; 11717 break; 11718 } 11719 } 11720 DCHECK(found_difference); 11721 } 11722 } 11723 #endif 11724 if (Hash() != other->Hash()) return false; 11725 } 11726 11727 // We know the strings are both non-empty. Compare the first chars 11728 // before we try to flatten the strings. 11729 if (this->Get(0) != other->Get(0)) return false; 11730 11731 if (IsSeqOneByteString() && other->IsSeqOneByteString()) { 11732 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars(); 11733 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars(); 11734 return CompareRawStringContents(str1, str2, len); 11735 } 11736 11737 StringComparator comparator; 11738 return comparator.Equals(this, other); 11739 } 11740 11741 bool String::SlowEquals(Isolate* isolate, Handle<String> one, 11742 Handle<String> two) { 11743 // Fast check: negative check with lengths. 11744 int one_length = one->length(); 11745 if (one_length != two->length()) return false; 11746 if (one_length == 0) return true; 11747 11748 // Fast check: if at least one ThinString is involved, dereference it/them 11749 // and restart. 11750 if (one->IsThinString() || two->IsThinString()) { 11751 if (one->IsThinString()) 11752 one = handle(ThinString::cast(*one)->actual(), isolate); 11753 if (two->IsThinString()) 11754 two = handle(ThinString::cast(*two)->actual(), isolate); 11755 return String::Equals(isolate, one, two); 11756 } 11757 11758 // Fast check: if hash code is computed for both strings 11759 // a fast negative check can be performed. 11760 if (one->HasHashCode() && two->HasHashCode()) { 11761 #ifdef ENABLE_SLOW_DCHECKS 11762 if (FLAG_enable_slow_asserts) { 11763 if (one->Hash() != two->Hash()) { 11764 bool found_difference = false; 11765 for (int i = 0; i < one_length; i++) { 11766 if (one->Get(i) != two->Get(i)) { 11767 found_difference = true; 11768 break; 11769 } 11770 } 11771 DCHECK(found_difference); 11772 } 11773 } 11774 #endif 11775 if (one->Hash() != two->Hash()) return false; 11776 } 11777 11778 // We know the strings are both non-empty. Compare the first chars 11779 // before we try to flatten the strings. 11780 if (one->Get(0) != two->Get(0)) return false; 11781 11782 one = String::Flatten(isolate, one); 11783 two = String::Flatten(isolate, two); 11784 11785 DisallowHeapAllocation no_gc; 11786 String::FlatContent flat1 = one->GetFlatContent(); 11787 String::FlatContent flat2 = two->GetFlatContent(); 11788 11789 if (flat1.IsOneByte() && flat2.IsOneByte()) { 11790 return CompareRawStringContents(flat1.ToOneByteVector().start(), 11791 flat2.ToOneByteVector().start(), 11792 one_length); 11793 } else { 11794 for (int i = 0; i < one_length; i++) { 11795 if (flat1.Get(i) != flat2.Get(i)) return false; 11796 } 11797 return true; 11798 } 11799 } 11800 11801 11802 // static 11803 ComparisonResult String::Compare(Isolate* isolate, Handle<String> x, 11804 Handle<String> y) { 11805 // A few fast case tests before we flatten. 11806 if (x.is_identical_to(y)) { 11807 return ComparisonResult::kEqual; 11808 } else if (y->length() == 0) { 11809 return x->length() == 0 ? ComparisonResult::kEqual 11810 : ComparisonResult::kGreaterThan; 11811 } else if (x->length() == 0) { 11812 return ComparisonResult::kLessThan; 11813 } 11814 11815 int const d = x->Get(0) - y->Get(0); 11816 if (d < 0) { 11817 return ComparisonResult::kLessThan; 11818 } else if (d > 0) { 11819 return ComparisonResult::kGreaterThan; 11820 } 11821 11822 // Slow case. 11823 x = String::Flatten(isolate, x); 11824 y = String::Flatten(isolate, y); 11825 11826 DisallowHeapAllocation no_gc; 11827 ComparisonResult result = ComparisonResult::kEqual; 11828 int prefix_length = x->length(); 11829 if (y->length() < prefix_length) { 11830 prefix_length = y->length(); 11831 result = ComparisonResult::kGreaterThan; 11832 } else if (y->length() > prefix_length) { 11833 result = ComparisonResult::kLessThan; 11834 } 11835 int r; 11836 String::FlatContent x_content = x->GetFlatContent(); 11837 String::FlatContent y_content = y->GetFlatContent(); 11838 if (x_content.IsOneByte()) { 11839 Vector<const uint8_t> x_chars = x_content.ToOneByteVector(); 11840 if (y_content.IsOneByte()) { 11841 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 11842 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11843 } else { 11844 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 11845 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11846 } 11847 } else { 11848 Vector<const uc16> x_chars = x_content.ToUC16Vector(); 11849 if (y_content.IsOneByte()) { 11850 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 11851 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11852 } else { 11853 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 11854 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 11855 } 11856 } 11857 if (r < 0) { 11858 result = ComparisonResult::kLessThan; 11859 } else if (r > 0) { 11860 result = ComparisonResult::kGreaterThan; 11861 } 11862 return result; 11863 } 11864 11865 Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver, 11866 Handle<Object> search, Handle<Object> position) { 11867 if (receiver->IsNullOrUndefined(isolate)) { 11868 THROW_NEW_ERROR_RETURN_FAILURE( 11869 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, 11870 isolate->factory()->NewStringFromAsciiChecked( 11871 "String.prototype.indexOf"))); 11872 } 11873 Handle<String> receiver_string; 11874 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string, 11875 Object::ToString(isolate, receiver)); 11876 11877 Handle<String> search_string; 11878 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string, 11879 Object::ToString(isolate, search)); 11880 11881 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, 11882 Object::ToInteger(isolate, position)); 11883 11884 uint32_t index = receiver_string->ToValidIndex(*position); 11885 return Smi::FromInt( 11886 String::IndexOf(isolate, receiver_string, search_string, index)); 11887 } 11888 11889 namespace { 11890 11891 template <typename T> 11892 int SearchString(Isolate* isolate, String::FlatContent receiver_content, 11893 Vector<T> pat_vector, int start_index) { 11894 if (receiver_content.IsOneByte()) { 11895 return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector, 11896 start_index); 11897 } 11898 return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector, 11899 start_index); 11900 } 11901 11902 } // namespace 11903 11904 int String::IndexOf(Isolate* isolate, Handle<String> receiver, 11905 Handle<String> search, int start_index) { 11906 DCHECK_LE(0, start_index); 11907 DCHECK(start_index <= receiver->length()); 11908 11909 uint32_t search_length = search->length(); 11910 if (search_length == 0) return start_index; 11911 11912 uint32_t receiver_length = receiver->length(); 11913 if (start_index + search_length > receiver_length) return -1; 11914 11915 receiver = String::Flatten(isolate, receiver); 11916 search = String::Flatten(isolate, search); 11917 11918 DisallowHeapAllocation no_gc; // ensure vectors stay valid 11919 // Extract flattened substrings of cons strings before getting encoding. 11920 String::FlatContent receiver_content = receiver->GetFlatContent(); 11921 String::FlatContent search_content = search->GetFlatContent(); 11922 11923 // dispatch on type of strings 11924 if (search_content.IsOneByte()) { 11925 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector(); 11926 return SearchString<const uint8_t>(isolate, receiver_content, pat_vector, 11927 start_index); 11928 } 11929 Vector<const uc16> pat_vector = search_content.ToUC16Vector(); 11930 return SearchString<const uc16>(isolate, receiver_content, pat_vector, 11931 start_index); 11932 } 11933 11934 MaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match, 11935 Handle<String> replacement, 11936 int start_index) { 11937 DCHECK_GE(start_index, 0); 11938 11939 Factory* factory = isolate->factory(); 11940 11941 const int replacement_length = replacement->length(); 11942 const int captures_length = match->CaptureCount(); 11943 11944 replacement = String::Flatten(isolate, replacement); 11945 11946 Handle<String> dollar_string = 11947 factory->LookupSingleCharacterStringFromCode('$'); 11948 int next_dollar_ix = 11949 String::IndexOf(isolate, replacement, dollar_string, start_index); 11950 if (next_dollar_ix < 0) { 11951 return replacement; 11952 } 11953 11954 IncrementalStringBuilder builder(isolate); 11955 11956 if (next_dollar_ix > 0) { 11957 builder.AppendString(factory->NewSubString(replacement, 0, next_dollar_ix)); 11958 } 11959 11960 while (true) { 11961 const int peek_ix = next_dollar_ix + 1; 11962 if (peek_ix >= replacement_length) { 11963 builder.AppendCharacter('$'); 11964 return builder.Finish(); 11965 } 11966 11967 int continue_from_ix = -1; 11968 const uint16_t peek = replacement->Get(peek_ix); 11969 switch (peek) { 11970 case '$': // $$ 11971 builder.AppendCharacter('$'); 11972 continue_from_ix = peek_ix + 1; 11973 break; 11974 case '&': // $& - match 11975 builder.AppendString(match->GetMatch()); 11976 continue_from_ix = peek_ix + 1; 11977 break; 11978 case '`': // $` - prefix 11979 builder.AppendString(match->GetPrefix()); 11980 continue_from_ix = peek_ix + 1; 11981 break; 11982 case '\'': // $' - suffix 11983 builder.AppendString(match->GetSuffix()); 11984 continue_from_ix = peek_ix + 1; 11985 break; 11986 case '0': 11987 case '1': 11988 case '2': 11989 case '3': 11990 case '4': 11991 case '5': 11992 case '6': 11993 case '7': 11994 case '8': 11995 case '9': { 11996 // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99 11997 int scaled_index = (peek - '0'); 11998 int advance = 1; 11999 12000 if (peek_ix + 1 < replacement_length) { 12001 const uint16_t next_peek = replacement->Get(peek_ix + 1); 12002 if (next_peek >= '0' && next_peek <= '9') { 12003 const int new_scaled_index = scaled_index * 10 + (next_peek - '0'); 12004 if (new_scaled_index < captures_length) { 12005 scaled_index = new_scaled_index; 12006 advance = 2; 12007 } 12008 } 12009 } 12010 12011 if (scaled_index == 0 || scaled_index >= captures_length) { 12012 builder.AppendCharacter('$'); 12013 continue_from_ix = peek_ix; 12014 break; 12015 } 12016 12017 bool capture_exists; 12018 Handle<String> capture; 12019 ASSIGN_RETURN_ON_EXCEPTION( 12020 isolate, capture, match->GetCapture(scaled_index, &capture_exists), 12021 String); 12022 if (capture_exists) builder.AppendString(capture); 12023 continue_from_ix = peek_ix + advance; 12024 break; 12025 } 12026 case '<': { // $<name> - named capture 12027 typedef String::Match::CaptureState CaptureState; 12028 12029 if (!match->HasNamedCaptures()) { 12030 builder.AppendCharacter('$'); 12031 continue_from_ix = peek_ix; 12032 break; 12033 } 12034 12035 Handle<String> bracket_string = 12036 factory->LookupSingleCharacterStringFromCode('>'); 12037 const int closing_bracket_ix = 12038 String::IndexOf(isolate, replacement, bracket_string, peek_ix + 1); 12039 12040 if (closing_bracket_ix == -1) { 12041 // No closing bracket was found, treat '$<' as a string literal. 12042 builder.AppendCharacter('$'); 12043 continue_from_ix = peek_ix; 12044 break; 12045 } 12046 12047 Handle<String> capture_name = 12048 factory->NewSubString(replacement, peek_ix + 1, closing_bracket_ix); 12049 Handle<String> capture; 12050 CaptureState capture_state; 12051 ASSIGN_RETURN_ON_EXCEPTION( 12052 isolate, capture, 12053 match->GetNamedCapture(capture_name, &capture_state), String); 12054 12055 switch (capture_state) { 12056 case CaptureState::INVALID: 12057 case CaptureState::UNMATCHED: 12058 break; 12059 case CaptureState::MATCHED: 12060 builder.AppendString(capture); 12061 break; 12062 } 12063 12064 continue_from_ix = closing_bracket_ix + 1; 12065 break; 12066 } 12067 default: 12068 builder.AppendCharacter('$'); 12069 continue_from_ix = peek_ix; 12070 break; 12071 } 12072 12073 // Go the the next $ in the replacement. 12074 // TODO(jgruber): Single-char lookups could be much more efficient. 12075 DCHECK_NE(continue_from_ix, -1); 12076 next_dollar_ix = 12077 String::IndexOf(isolate, replacement, dollar_string, continue_from_ix); 12078 12079 // Return if there are no more $ characters in the replacement. If we 12080 // haven't reached the end, we need to append the suffix. 12081 if (next_dollar_ix < 0) { 12082 if (continue_from_ix < replacement_length) { 12083 builder.AppendString(factory->NewSubString( 12084 replacement, continue_from_ix, replacement_length)); 12085 } 12086 return builder.Finish(); 12087 } 12088 12089 // Append substring between the previous and the next $ character. 12090 if (next_dollar_ix > continue_from_ix) { 12091 builder.AppendString( 12092 factory->NewSubString(replacement, continue_from_ix, next_dollar_ix)); 12093 } 12094 } 12095 12096 UNREACHABLE(); 12097 } 12098 12099 namespace { // for String.Prototype.lastIndexOf 12100 12101 template <typename schar, typename pchar> 12102 int StringMatchBackwards(Vector<const schar> subject, 12103 Vector<const pchar> pattern, int idx) { 12104 int pattern_length = pattern.length(); 12105 DCHECK_GE(pattern_length, 1); 12106 DCHECK(idx + pattern_length <= subject.length()); 12107 12108 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { 12109 for (int i = 0; i < pattern_length; i++) { 12110 uc16 c = pattern[i]; 12111 if (c > String::kMaxOneByteCharCode) { 12112 return -1; 12113 } 12114 } 12115 } 12116 12117 pchar pattern_first_char = pattern[0]; 12118 for (int i = idx; i >= 0; i--) { 12119 if (subject[i] != pattern_first_char) continue; 12120 int j = 1; 12121 while (j < pattern_length) { 12122 if (pattern[j] != subject[i + j]) { 12123 break; 12124 } 12125 j++; 12126 } 12127 if (j == pattern_length) { 12128 return i; 12129 } 12130 } 12131 return -1; 12132 } 12133 12134 } // namespace 12135 12136 Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver, 12137 Handle<Object> search, Handle<Object> position) { 12138 if (receiver->IsNullOrUndefined(isolate)) { 12139 THROW_NEW_ERROR_RETURN_FAILURE( 12140 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, 12141 isolate->factory()->NewStringFromAsciiChecked( 12142 "String.prototype.lastIndexOf"))); 12143 } 12144 Handle<String> receiver_string; 12145 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string, 12146 Object::ToString(isolate, receiver)); 12147 12148 Handle<String> search_string; 12149 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string, 12150 Object::ToString(isolate, search)); 12151 12152 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, 12153 Object::ToNumber(isolate, position)); 12154 12155 uint32_t start_index; 12156 12157 if (position->IsNaN()) { 12158 start_index = receiver_string->length(); 12159 } else { 12160 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, 12161 Object::ToInteger(isolate, position)); 12162 start_index = receiver_string->ToValidIndex(*position); 12163 } 12164 12165 uint32_t pattern_length = search_string->length(); 12166 uint32_t receiver_length = receiver_string->length(); 12167 12168 if (start_index + pattern_length > receiver_length) { 12169 start_index = receiver_length - pattern_length; 12170 } 12171 12172 if (pattern_length == 0) { 12173 return Smi::FromInt(start_index); 12174 } 12175 12176 receiver_string = String::Flatten(isolate, receiver_string); 12177 search_string = String::Flatten(isolate, search_string); 12178 12179 int last_index = -1; 12180 DisallowHeapAllocation no_gc; // ensure vectors stay valid 12181 12182 String::FlatContent receiver_content = receiver_string->GetFlatContent(); 12183 String::FlatContent search_content = search_string->GetFlatContent(); 12184 12185 if (search_content.IsOneByte()) { 12186 Vector<const uint8_t> pat_vector = search_content.ToOneByteVector(); 12187 if (receiver_content.IsOneByte()) { 12188 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(), 12189 pat_vector, start_index); 12190 } else { 12191 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(), 12192 pat_vector, start_index); 12193 } 12194 } else { 12195 Vector<const uc16> pat_vector = search_content.ToUC16Vector(); 12196 if (receiver_content.IsOneByte()) { 12197 last_index = StringMatchBackwards(receiver_content.ToOneByteVector(), 12198 pat_vector, start_index); 12199 } else { 12200 last_index = StringMatchBackwards(receiver_content.ToUC16Vector(), 12201 pat_vector, start_index); 12202 } 12203 } 12204 return Smi::FromInt(last_index); 12205 } 12206 12207 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) { 12208 int slen = length(); 12209 // Can't check exact length equality, but we can check bounds. 12210 int str_len = str.length(); 12211 if (!allow_prefix_match && 12212 (str_len < slen || 12213 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) { 12214 return false; 12215 } 12216 12217 int i = 0; 12218 unibrow::Utf8Iterator it = unibrow::Utf8Iterator(str); 12219 while (i < slen && !it.Done()) { 12220 if (Get(i++) != *it) return false; 12221 ++it; 12222 } 12223 12224 return (allow_prefix_match || i == slen) && it.Done(); 12225 } 12226 12227 template <> 12228 bool String::IsEqualTo(Vector<const uint8_t> str) { 12229 return IsOneByteEqualTo(str); 12230 } 12231 12232 template <> 12233 bool String::IsEqualTo(Vector<const uc16> str) { 12234 return IsTwoByteEqualTo(str); 12235 } 12236 12237 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) { 12238 int slen = length(); 12239 if (str.length() != slen) return false; 12240 DisallowHeapAllocation no_gc; 12241 FlatContent content = GetFlatContent(); 12242 if (content.IsOneByte()) { 12243 return CompareChars(content.ToOneByteVector().start(), 12244 str.start(), slen) == 0; 12245 } 12246 for (int i = 0; i < slen; i++) { 12247 if (Get(i) != static_cast<uint16_t>(str[i])) return false; 12248 } 12249 return true; 12250 } 12251 12252 12253 bool String::IsTwoByteEqualTo(Vector<const uc16> str) { 12254 int slen = length(); 12255 if (str.length() != slen) return false; 12256 DisallowHeapAllocation no_gc; 12257 FlatContent content = GetFlatContent(); 12258 if (content.IsTwoByte()) { 12259 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0; 12260 } 12261 for (int i = 0; i < slen; i++) { 12262 if (Get(i) != str[i]) return false; 12263 } 12264 return true; 12265 } 12266 12267 uint32_t String::ComputeAndSetHash(Isolate* isolate) { 12268 // Should only be called if hash code has not yet been computed. 12269 DCHECK(!HasHashCode()); 12270 12271 // Store the hash code in the object. 12272 uint32_t field = 12273 IteratingStringHasher::Hash(this, isolate->heap()->HashSeed()); 12274 set_hash_field(field); 12275 12276 // Check the hash code is there. 12277 DCHECK(HasHashCode()); 12278 uint32_t result = field >> kHashShift; 12279 DCHECK_NE(result, 0); // Ensure that the hash value of 0 is never computed. 12280 return result; 12281 } 12282 12283 12284 bool String::ComputeArrayIndex(uint32_t* index) { 12285 int length = this->length(); 12286 if (length == 0 || length > kMaxArrayIndexSize) return false; 12287 StringCharacterStream stream(this); 12288 return StringToArrayIndex(&stream, index); 12289 } 12290 12291 12292 bool String::SlowAsArrayIndex(uint32_t* index) { 12293 if (length() <= kMaxCachedArrayIndexLength) { 12294 Hash(); // force computation of hash code 12295 uint32_t field = hash_field(); 12296 if ((field & kIsNotArrayIndexMask) != 0) return false; 12297 // Isolate the array index form the full hash field. 12298 *index = ArrayIndexValueBits::decode(field); 12299 return true; 12300 } else { 12301 return ComputeArrayIndex(index); 12302 } 12303 } 12304 12305 12306 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) { 12307 if (new_length == 0) return string->GetReadOnlyRoots().empty_string_handle(); 12308 12309 int new_size, old_size; 12310 int old_length = string->length(); 12311 if (old_length <= new_length) return string; 12312 12313 if (string->IsSeqOneByteString()) { 12314 old_size = SeqOneByteString::SizeFor(old_length); 12315 new_size = SeqOneByteString::SizeFor(new_length); 12316 } else { 12317 DCHECK(string->IsSeqTwoByteString()); 12318 old_size = SeqTwoByteString::SizeFor(old_length); 12319 new_size = SeqTwoByteString::SizeFor(new_length); 12320 } 12321 12322 int delta = old_size - new_size; 12323 12324 Address start_of_string = string->address(); 12325 DCHECK_OBJECT_ALIGNED(start_of_string); 12326 DCHECK_OBJECT_ALIGNED(start_of_string + new_size); 12327 12328 Heap* heap = Heap::FromWritableHeapObject(*string); 12329 // Sizes are pointer size aligned, so that we can use filler objects 12330 // that are a multiple of pointer size. 12331 heap->CreateFillerObjectAt(start_of_string + new_size, delta, 12332 ClearRecordedSlots::kNo); 12333 // We are storing the new length using release store after creating a filler 12334 // for the left-over space to avoid races with the sweeper thread. 12335 string->synchronized_set_length(new_length); 12336 12337 return string; 12338 } 12339 12340 void SeqOneByteString::clear_padding() { 12341 int data_size = SeqString::kHeaderSize + length() * kOneByteSize; 12342 memset(reinterpret_cast<void*>(address() + data_size), 0, 12343 SizeFor(length()) - data_size); 12344 } 12345 12346 void SeqTwoByteString::clear_padding() { 12347 int data_size = SeqString::kHeaderSize + length() * kUC16Size; 12348 memset(reinterpret_cast<void*>(address() + data_size), 0, 12349 SizeFor(length()) - data_size); 12350 } 12351 12352 int ExternalString::ExternalPayloadSize() const { 12353 int length_multiplier = IsTwoByteRepresentation() ? i::kShortSize : kCharSize; 12354 return length() * length_multiplier; 12355 } 12356 12357 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) { 12358 // For array indexes mix the length into the hash as an array index could 12359 // be zero. 12360 DCHECK_GT(length, 0); 12361 DCHECK_LE(length, String::kMaxArrayIndexSize); 12362 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < 12363 (1 << String::kArrayIndexValueBits)); 12364 12365 value <<= String::ArrayIndexValueBits::kShift; 12366 value |= length << String::ArrayIndexLengthBits::kShift; 12367 12368 DCHECK_EQ(value & String::kIsNotArrayIndexMask, 0); 12369 DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength, 12370 Name::ContainsCachedArrayIndex(value)); 12371 return value; 12372 } 12373 12374 12375 uint32_t StringHasher::GetHashField() { 12376 if (length_ <= String::kMaxHashCalcLength) { 12377 if (is_array_index_) { 12378 return MakeArrayIndexHash(array_index_, length_); 12379 } 12380 return (GetHashCore(raw_running_hash_) << String::kHashShift) | 12381 String::kIsNotArrayIndexMask; 12382 } else { 12383 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask; 12384 } 12385 } 12386 12387 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars, uint64_t seed, 12388 int* utf16_length_out) { 12389 int vector_length = chars.length(); 12390 // Handle some edge cases 12391 if (vector_length <= 1) { 12392 DCHECK(vector_length == 0 || 12393 static_cast<uint8_t>(chars.start()[0]) <= 12394 unibrow::Utf8::kMaxOneByteChar); 12395 *utf16_length_out = vector_length; 12396 return HashSequentialString(chars.start(), vector_length, seed); 12397 } 12398 12399 // Start with a fake length which won't affect computation. 12400 // It will be updated later. 12401 StringHasher hasher(String::kMaxArrayIndexSize, seed); 12402 DCHECK(hasher.is_array_index_); 12403 12404 unibrow::Utf8Iterator it = unibrow::Utf8Iterator(chars); 12405 int utf16_length = 0; 12406 bool is_index = true; 12407 12408 while (utf16_length < String::kMaxHashCalcLength && !it.Done()) { 12409 utf16_length++; 12410 uint16_t c = *it; 12411 ++it; 12412 hasher.AddCharacter(c); 12413 if (is_index) is_index = hasher.UpdateIndex(c); 12414 } 12415 12416 // Now that hashing is done, we just need to calculate utf16_length 12417 while (!it.Done()) { 12418 ++it; 12419 utf16_length++; 12420 } 12421 12422 *utf16_length_out = utf16_length; 12423 // Must set length here so that hash computation is correct. 12424 hasher.length_ = utf16_length; 12425 return hasher.GetHashField(); 12426 } 12427 12428 12429 void IteratingStringHasher::VisitConsString(ConsString* cons_string) { 12430 // Run small ConsStrings through ConsStringIterator. 12431 if (cons_string->length() < 64) { 12432 ConsStringIterator iter(cons_string); 12433 int offset; 12434 String* string; 12435 while (nullptr != (string = iter.Next(&offset))) { 12436 DCHECK_EQ(0, offset); 12437 String::VisitFlat(this, string, 0); 12438 } 12439 return; 12440 } 12441 // Slow case. 12442 const int max_length = String::kMaxHashCalcLength; 12443 int length = std::min(cons_string->length(), max_length); 12444 if (cons_string->HasOnlyOneByteChars()) { 12445 uint8_t* buffer = new uint8_t[length]; 12446 String::WriteToFlat(cons_string, buffer, 0, length); 12447 AddCharacters(buffer, length); 12448 delete[] buffer; 12449 } else { 12450 uint16_t* buffer = new uint16_t[length]; 12451 String::WriteToFlat(cons_string, buffer, 0, length); 12452 AddCharacters(buffer, length); 12453 delete[] buffer; 12454 } 12455 } 12456 12457 12458 void String::PrintOn(FILE* file) { 12459 int length = this->length(); 12460 for (int i = 0; i < length; i++) { 12461 PrintF(file, "%c", Get(i)); 12462 } 12463 } 12464 12465 12466 int Map::Hash() { 12467 // For performance reasons we only hash the 3 most variable fields of a map: 12468 // constructor, prototype and bit_field2. For predictability reasons we 12469 // use objects' offsets in respective pages for hashing instead of raw 12470 // addresses. 12471 12472 // Shift away the tag. 12473 int hash = ObjectAddressForHashing(GetConstructor()) >> 2; 12474 12475 // XOR-ing the prototype and constructor directly yields too many zero bits 12476 // when the two pointers are close (which is fairly common). 12477 // To avoid this we shift the prototype bits relatively to the constructor. 12478 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits); 12479 12480 return hash ^ (hash >> 16) ^ bit_field2(); 12481 } 12482 12483 12484 namespace { 12485 12486 bool CheckEquivalent(const Map* first, const Map* second) { 12487 return first->GetConstructor() == second->GetConstructor() && 12488 first->prototype() == second->prototype() && 12489 first->instance_type() == second->instance_type() && 12490 first->bit_field() == second->bit_field() && 12491 first->is_extensible() == second->is_extensible() && 12492 first->new_target_is_base() == second->new_target_is_base() && 12493 first->has_hidden_prototype() == second->has_hidden_prototype(); 12494 } 12495 12496 } // namespace 12497 12498 bool Map::EquivalentToForTransition(const Map* other) const { 12499 if (!CheckEquivalent(this, other)) return false; 12500 if (instance_type() == JS_FUNCTION_TYPE) { 12501 // JSFunctions require more checks to ensure that sloppy function is 12502 // not equivalent to strict function. 12503 int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors()); 12504 return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(), 12505 nof); 12506 } 12507 return true; 12508 } 12509 12510 bool Map::EquivalentToForElementsKindTransition(const Map* other) const { 12511 if (!EquivalentToForTransition(other)) return false; 12512 #ifdef DEBUG 12513 // Ensure that we don't try to generate elements kind transitions from maps 12514 // with fields that may be generalized in-place. This must already be handled 12515 // during addition of a new field. 12516 DescriptorArray* descriptors = instance_descriptors(); 12517 int nof = NumberOfOwnDescriptors(); 12518 for (int i = 0; i < nof; i++) { 12519 PropertyDetails details = descriptors->GetDetails(i); 12520 if (details.location() == kField) { 12521 DCHECK(!IsInplaceGeneralizableField(details.constness(), 12522 details.representation(), 12523 descriptors->GetFieldType(i))); 12524 } 12525 } 12526 #endif 12527 return true; 12528 } 12529 12530 bool Map::EquivalentToForNormalization(const Map* other, 12531 PropertyNormalizationMode mode) const { 12532 int properties = 12533 mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties(); 12534 return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() && 12535 GetInObjectProperties() == properties && 12536 JSObject::GetEmbedderFieldCount(this) == 12537 JSObject::GetEmbedderFieldCount(other); 12538 } 12539 12540 12541 void JSFunction::MarkForOptimization(ConcurrencyMode mode) { 12542 Isolate* isolate = GetIsolate(); 12543 if (!isolate->concurrent_recompilation_enabled() || 12544 isolate->bootstrapper()->IsActive()) { 12545 mode = ConcurrencyMode::kNotConcurrent; 12546 } 12547 12548 DCHECK(!is_compiled() || IsInterpreted()); 12549 DCHECK(shared()->IsInterpreted()); 12550 DCHECK(!IsOptimized()); 12551 DCHECK(!HasOptimizedCode()); 12552 DCHECK(shared()->allows_lazy_compilation() || 12553 !shared()->optimization_disabled()); 12554 12555 if (mode == ConcurrencyMode::kConcurrent) { 12556 if (IsInOptimizationQueue()) { 12557 if (FLAG_trace_concurrent_recompilation) { 12558 PrintF(" ** Not marking "); 12559 ShortPrint(); 12560 PrintF(" -- already in optimization queue.\n"); 12561 } 12562 return; 12563 } 12564 if (FLAG_trace_concurrent_recompilation) { 12565 PrintF(" ** Marking "); 12566 ShortPrint(); 12567 PrintF(" for concurrent recompilation.\n"); 12568 } 12569 } 12570 12571 SetOptimizationMarker(mode == ConcurrencyMode::kConcurrent 12572 ? OptimizationMarker::kCompileOptimizedConcurrent 12573 : OptimizationMarker::kCompileOptimized); 12574 } 12575 12576 // static 12577 void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function) { 12578 Isolate* const isolate = function->GetIsolate(); 12579 if (function->feedback_cell()->value()->IsUndefined(isolate)) { 12580 Handle<SharedFunctionInfo> shared(function->shared(), isolate); 12581 if (!shared->HasAsmWasmData()) { 12582 Handle<FeedbackVector> feedback_vector = 12583 FeedbackVector::New(isolate, shared); 12584 if (function->feedback_cell() == isolate->heap()->many_closures_cell()) { 12585 Handle<FeedbackCell> feedback_cell = 12586 isolate->factory()->NewOneClosureCell(feedback_vector); 12587 function->set_feedback_cell(*feedback_cell); 12588 } else { 12589 function->feedback_cell()->set_value(*feedback_vector); 12590 } 12591 } 12592 } 12593 } 12594 12595 static void GetMinInobjectSlack(Map* map, void* data) { 12596 int slack = map->UnusedPropertyFields(); 12597 if (*reinterpret_cast<int*>(data) > slack) { 12598 *reinterpret_cast<int*>(data) = slack; 12599 } 12600 } 12601 12602 int Map::InstanceSizeFromSlack(int slack) const { 12603 return instance_size() - slack * kPointerSize; 12604 } 12605 12606 static void ShrinkInstanceSize(Map* map, void* data) { 12607 int slack = *reinterpret_cast<int*>(data); 12608 DCHECK_GE(slack, 0); 12609 #ifdef DEBUG 12610 int old_visitor_id = Map::GetVisitorId(map); 12611 int new_unused = map->UnusedPropertyFields() - slack; 12612 #endif 12613 map->set_instance_size(map->InstanceSizeFromSlack(slack)); 12614 map->set_construction_counter(Map::kNoSlackTracking); 12615 DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map)); 12616 DCHECK_EQ(new_unused, map->UnusedPropertyFields()); 12617 } 12618 12619 static void StopSlackTracking(Map* map, void* data) { 12620 map->set_construction_counter(Map::kNoSlackTracking); 12621 } 12622 12623 int Map::ComputeMinObjectSlack(Isolate* isolate) { 12624 DisallowHeapAllocation no_gc; 12625 // Has to be an initial map. 12626 DCHECK(GetBackPointer()->IsUndefined(isolate)); 12627 12628 int slack = UnusedPropertyFields(); 12629 TransitionsAccessor transitions(isolate, this, &no_gc); 12630 transitions.TraverseTransitionTree(&GetMinInobjectSlack, &slack); 12631 return slack; 12632 } 12633 12634 void Map::CompleteInobjectSlackTracking(Isolate* isolate) { 12635 DisallowHeapAllocation no_gc; 12636 // Has to be an initial map. 12637 DCHECK(GetBackPointer()->IsUndefined(isolate)); 12638 12639 int slack = ComputeMinObjectSlack(isolate); 12640 TransitionsAccessor transitions(isolate, this, &no_gc); 12641 if (slack != 0) { 12642 // Resize the initial map and all maps in its transition tree. 12643 transitions.TraverseTransitionTree(&ShrinkInstanceSize, &slack); 12644 } else { 12645 transitions.TraverseTransitionTree(&StopSlackTracking, nullptr); 12646 } 12647 } 12648 12649 12650 static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) { 12651 DisallowHeapAllocation no_gc; 12652 if (!object->HasFastProperties()) return false; 12653 if (object->IsJSGlobalProxy()) return false; 12654 if (object->GetIsolate()->bootstrapper()->IsActive()) return false; 12655 return !object->map()->is_prototype_map() || 12656 !object->map()->should_be_fast_prototype_map(); 12657 } 12658 12659 // static 12660 void JSObject::MakePrototypesFast(Handle<Object> receiver, 12661 WhereToStart where_to_start, 12662 Isolate* isolate) { 12663 if (!receiver->IsJSReceiver()) return; 12664 for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver), 12665 where_to_start); 12666 !iter.IsAtEnd(); iter.Advance()) { 12667 Handle<Object> current = PrototypeIterator::GetCurrent(iter); 12668 if (!current->IsJSObject()) return; 12669 Handle<JSObject> current_obj = Handle<JSObject>::cast(current); 12670 Map* current_map = current_obj->map(); 12671 if (current_map->is_prototype_map()) { 12672 // If the map is already marked as should be fast, we're done. Its 12673 // prototypes will have been marked already as well. 12674 if (current_map->should_be_fast_prototype_map()) return; 12675 Handle<Map> map(current_map, isolate); 12676 Map::SetShouldBeFastPrototypeMap(map, true, isolate); 12677 JSObject::OptimizeAsPrototype(current_obj); 12678 } 12679 } 12680 } 12681 12682 // static 12683 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, 12684 bool enable_setup_mode) { 12685 if (object->IsJSGlobalObject()) return; 12686 if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) { 12687 // First normalize to ensure all JSFunctions are DATA_CONSTANT. 12688 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, 12689 "NormalizeAsPrototype"); 12690 } 12691 if (object->map()->is_prototype_map()) { 12692 if (object->map()->should_be_fast_prototype_map() && 12693 !object->HasFastProperties()) { 12694 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); 12695 } 12696 } else { 12697 Handle<Map> new_map = Map::Copy(object->GetIsolate(), 12698 handle(object->map(), object->GetIsolate()), 12699 "CopyAsPrototype"); 12700 JSObject::MigrateToMap(object, new_map); 12701 object->map()->set_is_prototype_map(true); 12702 12703 // Replace the pointer to the exact constructor with the Object function 12704 // from the same context if undetectable from JS. This is to avoid keeping 12705 // memory alive unnecessarily. 12706 Object* maybe_constructor = object->map()->GetConstructor(); 12707 if (maybe_constructor->IsJSFunction()) { 12708 JSFunction* constructor = JSFunction::cast(maybe_constructor); 12709 if (!constructor->shared()->IsApiFunction()) { 12710 Context* context = constructor->context()->native_context(); 12711 JSFunction* object_function = context->object_function(); 12712 object->map()->SetConstructor(object_function); 12713 } 12714 } 12715 } 12716 } 12717 12718 12719 // static 12720 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { 12721 if (!object->map()->is_prototype_map()) return; 12722 if (!object->map()->should_be_fast_prototype_map()) return; 12723 OptimizeAsPrototype(object); 12724 } 12725 12726 12727 // static 12728 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) { 12729 // Contract: In line with InvalidatePrototypeChains()'s requirements, 12730 // leaf maps don't need to register as users, only prototypes do. 12731 DCHECK(user->is_prototype_map()); 12732 12733 Handle<Map> current_user = user; 12734 Handle<PrototypeInfo> current_user_info = 12735 Map::GetOrCreatePrototypeInfo(user, isolate); 12736 for (PrototypeIterator iter(isolate, user); !iter.IsAtEnd(); iter.Advance()) { 12737 // Walk up the prototype chain as far as links haven't been registered yet. 12738 if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) { 12739 break; 12740 } 12741 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter); 12742 // Proxies on the prototype chain are not supported. They make it 12743 // impossible to make any assumptions about the prototype chain anyway. 12744 if (maybe_proto->IsJSProxy()) return; 12745 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto); 12746 Handle<PrototypeInfo> proto_info = 12747 Map::GetOrCreatePrototypeInfo(proto, isolate); 12748 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate); 12749 Handle<WeakArrayList> registry = 12750 maybe_registry->IsSmi() 12751 ? handle(ReadOnlyRoots(isolate->heap()).empty_weak_array_list(), 12752 isolate) 12753 : Handle<WeakArrayList>::cast(maybe_registry); 12754 int slot = 0; 12755 Handle<WeakArrayList> new_array = 12756 PrototypeUsers::Add(isolate, registry, current_user, &slot); 12757 current_user_info->set_registry_slot(slot); 12758 if (!maybe_registry.is_identical_to(new_array)) { 12759 proto_info->set_prototype_users(*new_array); 12760 } 12761 if (FLAG_trace_prototype_users) { 12762 PrintF("Registering %p as a user of prototype %p (map=%p).\n", 12763 reinterpret_cast<void*>(*current_user), 12764 reinterpret_cast<void*>(*proto), 12765 reinterpret_cast<void*>(proto->map())); 12766 } 12767 12768 current_user = handle(proto->map(), isolate); 12769 current_user_info = proto_info; 12770 } 12771 } 12772 12773 12774 // Can be called regardless of whether |user| was actually registered with 12775 // |prototype|. Returns true when there was a registration. 12776 // static 12777 bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) { 12778 DCHECK(user->is_prototype_map()); 12779 // If it doesn't have a PrototypeInfo, it was never registered. 12780 if (!user->prototype_info()->IsPrototypeInfo()) return false; 12781 // If it had no prototype before, see if it had users that might expect 12782 // registration. 12783 if (!user->prototype()->IsJSObject()) { 12784 Object* users = 12785 PrototypeInfo::cast(user->prototype_info())->prototype_users(); 12786 return users->IsWeakArrayList(); 12787 } 12788 Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate); 12789 Handle<PrototypeInfo> user_info = 12790 Map::GetOrCreatePrototypeInfo(user, isolate); 12791 int slot = user_info->registry_slot(); 12792 if (slot == PrototypeInfo::UNREGISTERED) return false; 12793 DCHECK(prototype->map()->is_prototype_map()); 12794 Object* maybe_proto_info = prototype->map()->prototype_info(); 12795 // User knows its registry slot, prototype info and user registry must exist. 12796 DCHECK(maybe_proto_info->IsPrototypeInfo()); 12797 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), 12798 isolate); 12799 Handle<WeakArrayList> prototype_users( 12800 WeakArrayList::cast(proto_info->prototype_users()), isolate); 12801 DCHECK_EQ(prototype_users->Get(slot), HeapObjectReference::Weak(*user)); 12802 PrototypeUsers::MarkSlotEmpty(*prototype_users, slot); 12803 if (FLAG_trace_prototype_users) { 12804 PrintF("Unregistering %p as a user of prototype %p.\n", 12805 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype)); 12806 } 12807 return true; 12808 } 12809 12810 namespace { 12811 12812 // This function must be kept in sync with 12813 // AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks 12814 // before jumping here. 12815 void InvalidateOnePrototypeValidityCellInternal(Map* map) { 12816 DCHECK(map->is_prototype_map()); 12817 if (FLAG_trace_prototype_users) { 12818 PrintF("Invalidating prototype map %p 's cell\n", 12819 reinterpret_cast<void*>(map)); 12820 } 12821 Object* maybe_cell = map->prototype_validity_cell(); 12822 if (maybe_cell->IsCell()) { 12823 // Just set the value; the cell will be replaced lazily. 12824 Cell* cell = Cell::cast(maybe_cell); 12825 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid)); 12826 } 12827 } 12828 12829 void InvalidatePrototypeChainsInternal(Map* map) { 12830 InvalidateOnePrototypeValidityCellInternal(map); 12831 12832 Object* maybe_proto_info = map->prototype_info(); 12833 if (!maybe_proto_info->IsPrototypeInfo()) return; 12834 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info); 12835 WeakArrayList* prototype_users = 12836 WeakArrayList::cast(proto_info->prototype_users()); 12837 // For now, only maps register themselves as users. 12838 for (int i = PrototypeUsers::kFirstIndex; i < prototype_users->length(); 12839 ++i) { 12840 HeapObject* heap_object; 12841 if (prototype_users->Get(i)->ToWeakHeapObject(&heap_object) && 12842 heap_object->IsMap()) { 12843 // Walk the prototype chain (backwards, towards leaf objects) if 12844 // necessary. 12845 InvalidatePrototypeChainsInternal(Map::cast(heap_object)); 12846 } 12847 } 12848 } 12849 12850 } // namespace 12851 12852 // static 12853 Map* JSObject::InvalidatePrototypeChains(Map* map) { 12854 DisallowHeapAllocation no_gc; 12855 InvalidatePrototypeChainsInternal(map); 12856 return map; 12857 } 12858 12859 // We also invalidate global objects validity cell when a new lexical 12860 // environment variable is added. This is necessary to ensure that 12861 // Load/StoreGlobalIC handlers that load/store from global object's prototype 12862 // get properly invalidated. 12863 // Note, that the normal Load/StoreICs that load/store through the global object 12864 // in the prototype chain are not affected by appearance of a new lexical 12865 // variable and therefore we don't propagate invalidation down. 12866 // static 12867 void JSObject::InvalidatePrototypeValidityCell(JSGlobalObject* global) { 12868 DisallowHeapAllocation no_gc; 12869 InvalidateOnePrototypeValidityCellInternal(global->map()); 12870 } 12871 12872 // static 12873 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype, 12874 Isolate* isolate) { 12875 Object* maybe_proto_info = prototype->map()->prototype_info(); 12876 if (maybe_proto_info->IsPrototypeInfo()) { 12877 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); 12878 } 12879 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); 12880 prototype->map()->set_prototype_info(*proto_info); 12881 return proto_info; 12882 } 12883 12884 12885 // static 12886 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map, 12887 Isolate* isolate) { 12888 Object* maybe_proto_info = prototype_map->prototype_info(); 12889 if (maybe_proto_info->IsPrototypeInfo()) { 12890 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); 12891 } 12892 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); 12893 prototype_map->set_prototype_info(*proto_info); 12894 return proto_info; 12895 } 12896 12897 // static 12898 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value, 12899 Isolate* isolate) { 12900 if (value == false && !map->prototype_info()->IsPrototypeInfo()) { 12901 // "False" is the implicit default value, so there's nothing to do. 12902 return; 12903 } 12904 GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value); 12905 } 12906 12907 // static 12908 Handle<Object> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, 12909 Isolate* isolate) { 12910 Handle<Object> maybe_prototype; 12911 if (map->IsJSGlobalObjectMap()) { 12912 DCHECK(map->is_prototype_map()); 12913 // Global object is prototype of a global proxy and therefore we can 12914 // use its validity cell for guarding global object's prototype change. 12915 maybe_prototype = isolate->global_object(); 12916 } else { 12917 maybe_prototype = 12918 handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate); 12919 } 12920 if (!maybe_prototype->IsJSObject()) { 12921 return handle(Smi::FromInt(Map::kPrototypeChainValid), isolate); 12922 } 12923 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); 12924 // Ensure the prototype is registered with its own prototypes so its cell 12925 // will be invalidated when necessary. 12926 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate), 12927 isolate); 12928 12929 Object* maybe_cell = prototype->map()->prototype_validity_cell(); 12930 // Return existing cell if it's still valid. 12931 if (maybe_cell->IsCell()) { 12932 Handle<Cell> cell(Cell::cast(maybe_cell), isolate); 12933 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) { 12934 return cell; 12935 } 12936 } 12937 // Otherwise create a new cell. 12938 Handle<Cell> cell = isolate->factory()->NewCell( 12939 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate)); 12940 prototype->map()->set_prototype_validity_cell(*cell); 12941 return cell; 12942 } 12943 12944 // static 12945 bool Map::IsPrototypeChainInvalidated(Map* map) { 12946 DCHECK(map->is_prototype_map()); 12947 Object* maybe_cell = map->prototype_validity_cell(); 12948 if (maybe_cell->IsCell()) { 12949 Cell* cell = Cell::cast(maybe_cell); 12950 return cell->value() != Smi::FromInt(Map::kPrototypeChainValid); 12951 } 12952 return true; 12953 } 12954 12955 // static 12956 void Map::SetPrototype(Isolate* isolate, Handle<Map> map, 12957 Handle<Object> prototype, 12958 bool enable_prototype_setup_mode) { 12959 RuntimeCallTimerScope stats_scope(isolate, *map, 12960 RuntimeCallCounterId::kMap_SetPrototype); 12961 12962 bool is_hidden = false; 12963 if (prototype->IsJSObject()) { 12964 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); 12965 JSObject::OptimizeAsPrototype(prototype_jsobj, enable_prototype_setup_mode); 12966 12967 Object* maybe_constructor = prototype_jsobj->map()->GetConstructor(); 12968 if (maybe_constructor->IsJSFunction()) { 12969 JSFunction* constructor = JSFunction::cast(maybe_constructor); 12970 Object* data = constructor->shared()->function_data(); 12971 is_hidden = (data->IsFunctionTemplateInfo() && 12972 FunctionTemplateInfo::cast(data)->hidden_prototype()) || 12973 prototype->IsJSGlobalObject(); 12974 } else if (maybe_constructor->IsFunctionTemplateInfo()) { 12975 is_hidden = 12976 FunctionTemplateInfo::cast(maybe_constructor)->hidden_prototype() || 12977 prototype->IsJSGlobalObject(); 12978 } 12979 } 12980 map->set_has_hidden_prototype(is_hidden); 12981 12982 WriteBarrierMode wb_mode = 12983 prototype->IsNull(isolate) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; 12984 map->set_prototype(*prototype, wb_mode); 12985 } 12986 12987 Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context, 12988 Handle<Map> initial_map) { 12989 // Replace all of the cached initial array maps in the native context with 12990 // the appropriate transitioned elements kind maps. 12991 Handle<Map> current_map = initial_map; 12992 ElementsKind kind = current_map->elements_kind(); 12993 DCHECK_EQ(GetInitialFastElementsKind(), kind); 12994 native_context->set(Context::ArrayMapIndex(kind), *current_map); 12995 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1; 12996 i < kFastElementsKindCount; ++i) { 12997 Handle<Map> new_map; 12998 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i); 12999 if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) { 13000 new_map = handle(maybe_elements_transition, native_context->GetIsolate()); 13001 } else { 13002 new_map = 13003 Map::CopyAsElementsKind(native_context->GetIsolate(), current_map, 13004 next_kind, INSERT_TRANSITION); 13005 } 13006 DCHECK_EQ(next_kind, new_map->elements_kind()); 13007 native_context->set(Context::ArrayMapIndex(next_kind), *new_map); 13008 current_map = new_map; 13009 } 13010 return initial_map; 13011 } 13012 13013 namespace { 13014 13015 void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function, 13016 Handle<JSReceiver> value) { 13017 // Now some logic for the maps of the objects that are created by using this 13018 // function as a constructor. 13019 if (function->has_initial_map()) { 13020 // If the function has allocated the initial map replace it with a 13021 // copy containing the new prototype. Also complete any in-object 13022 // slack tracking that is in progress at this point because it is 13023 // still tracking the old copy. 13024 function->CompleteInobjectSlackTrackingIfActive(); 13025 13026 Handle<Map> initial_map(function->initial_map(), isolate); 13027 13028 if (!isolate->bootstrapper()->IsActive() && 13029 initial_map->instance_type() == JS_OBJECT_TYPE) { 13030 // Put the value in the initial map field until an initial map is needed. 13031 // At that point, a new initial map is created and the prototype is put 13032 // into the initial map where it belongs. 13033 function->set_prototype_or_initial_map(*value); 13034 } else { 13035 Handle<Map> new_map = 13036 Map::Copy(isolate, initial_map, "SetInstancePrototype"); 13037 JSFunction::SetInitialMap(function, new_map, value); 13038 13039 // If the function is used as the global Array function, cache the 13040 // updated initial maps (and transitioned versions) in the native context. 13041 Handle<Context> native_context(function->context()->native_context(), 13042 isolate); 13043 Handle<Object> array_function( 13044 native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate); 13045 if (array_function->IsJSFunction() && 13046 *function == JSFunction::cast(*array_function)) { 13047 CacheInitialJSArrayMaps(native_context, new_map); 13048 } 13049 } 13050 13051 // Deoptimize all code that embeds the previous initial map. 13052 initial_map->dependent_code()->DeoptimizeDependentCodeGroup( 13053 isolate, DependentCode::kInitialMapChangedGroup); 13054 } else { 13055 // Put the value in the initial map field until an initial map is 13056 // needed. At that point, a new initial map is created and the 13057 // prototype is put into the initial map where it belongs. 13058 function->set_prototype_or_initial_map(*value); 13059 if (value->IsJSObject()) { 13060 // Optimize as prototype to detach it from its transition tree. 13061 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value)); 13062 } 13063 } 13064 } 13065 13066 } // anonymous namespace 13067 13068 void JSFunction::SetPrototype(Handle<JSFunction> function, 13069 Handle<Object> value) { 13070 DCHECK(function->IsConstructor() || 13071 IsGeneratorFunction(function->shared()->kind())); 13072 Isolate* isolate = function->GetIsolate(); 13073 Handle<JSReceiver> construct_prototype; 13074 13075 // If the value is not a JSReceiver, store the value in the map's 13076 // constructor field so it can be accessed. Also, set the prototype 13077 // used for constructing objects to the original object prototype. 13078 // See ECMA-262 13.2.2. 13079 if (!value->IsJSReceiver()) { 13080 // Copy the map so this does not affect unrelated functions. 13081 // Remove map transitions because they point to maps with a 13082 // different prototype. 13083 Handle<Map> new_map = 13084 Map::Copy(isolate, handle(function->map(), isolate), "SetPrototype"); 13085 13086 JSObject::MigrateToMap(function, new_map); 13087 new_map->SetConstructor(*value); 13088 new_map->set_has_non_instance_prototype(true); 13089 13090 FunctionKind kind = function->shared()->kind(); 13091 Handle<Context> native_context(function->context()->native_context(), 13092 isolate); 13093 13094 construct_prototype = Handle<JSReceiver>( 13095 IsGeneratorFunction(kind) 13096 ? IsAsyncFunction(kind) 13097 ? native_context->initial_async_generator_prototype() 13098 : native_context->initial_generator_prototype() 13099 : native_context->initial_object_prototype(), 13100 isolate); 13101 } else { 13102 construct_prototype = Handle<JSReceiver>::cast(value); 13103 function->map()->set_has_non_instance_prototype(false); 13104 } 13105 13106 SetInstancePrototype(isolate, function, construct_prototype); 13107 } 13108 13109 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map, 13110 Handle<Object> prototype) { 13111 if (map->prototype() != *prototype) 13112 Map::SetPrototype(function->GetIsolate(), map, prototype); 13113 function->set_prototype_or_initial_map(*map); 13114 map->SetConstructor(*function); 13115 if (FLAG_trace_maps) { 13116 LOG(function->GetIsolate(), MapEvent("InitialMap", nullptr, *map, "", 13117 function->shared()->DebugName())); 13118 } 13119 } 13120 13121 13122 #ifdef DEBUG 13123 namespace { 13124 13125 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) { 13126 switch (instance_type) { 13127 case JS_API_OBJECT_TYPE: 13128 case JS_ARRAY_BUFFER_TYPE: 13129 case JS_ARRAY_TYPE: 13130 case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE: 13131 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 13132 case JS_DATA_VIEW_TYPE: 13133 case JS_DATE_TYPE: 13134 case JS_FUNCTION_TYPE: 13135 case JS_GENERATOR_OBJECT_TYPE: 13136 #ifdef V8_INTL_SUPPORT 13137 case JS_INTL_COLLATOR_TYPE: 13138 case JS_INTL_LIST_FORMAT_TYPE: 13139 case JS_INTL_PLURAL_RULES_TYPE: 13140 case JS_INTL_RELATIVE_TIME_FORMAT_TYPE: 13141 #endif 13142 case JS_ASYNC_GENERATOR_OBJECT_TYPE: 13143 case JS_MAP_TYPE: 13144 case JS_MESSAGE_OBJECT_TYPE: 13145 case JS_OBJECT_TYPE: 13146 case JS_ERROR_TYPE: 13147 case JS_ARGUMENTS_TYPE: 13148 case JS_PROMISE_TYPE: 13149 case JS_REGEXP_TYPE: 13150 case JS_SET_TYPE: 13151 case JS_SPECIAL_API_OBJECT_TYPE: 13152 case JS_TYPED_ARRAY_TYPE: 13153 case JS_VALUE_TYPE: 13154 case JS_WEAK_MAP_TYPE: 13155 case JS_WEAK_SET_TYPE: 13156 case WASM_GLOBAL_TYPE: 13157 case WASM_INSTANCE_TYPE: 13158 case WASM_MEMORY_TYPE: 13159 case WASM_MODULE_TYPE: 13160 case WASM_TABLE_TYPE: 13161 return true; 13162 13163 case BIGINT_TYPE: 13164 case OBJECT_BOILERPLATE_DESCRIPTION_TYPE: 13165 case BYTECODE_ARRAY_TYPE: 13166 case BYTE_ARRAY_TYPE: 13167 case CELL_TYPE: 13168 case CODE_TYPE: 13169 case FILLER_TYPE: 13170 case FIXED_ARRAY_TYPE: 13171 case SCRIPT_CONTEXT_TABLE_TYPE: 13172 case FIXED_DOUBLE_ARRAY_TYPE: 13173 case FEEDBACK_METADATA_TYPE: 13174 case FOREIGN_TYPE: 13175 case FREE_SPACE_TYPE: 13176 case HASH_TABLE_TYPE: 13177 case ORDERED_HASH_MAP_TYPE: 13178 case ORDERED_HASH_SET_TYPE: 13179 case NAME_DICTIONARY_TYPE: 13180 case GLOBAL_DICTIONARY_TYPE: 13181 case NUMBER_DICTIONARY_TYPE: 13182 case SIMPLE_NUMBER_DICTIONARY_TYPE: 13183 case STRING_TABLE_TYPE: 13184 case HEAP_NUMBER_TYPE: 13185 case JS_BOUND_FUNCTION_TYPE: 13186 case JS_GLOBAL_OBJECT_TYPE: 13187 case JS_GLOBAL_PROXY_TYPE: 13188 case JS_PROXY_TYPE: 13189 case MAP_TYPE: 13190 case MUTABLE_HEAP_NUMBER_TYPE: 13191 case ODDBALL_TYPE: 13192 case PROPERTY_CELL_TYPE: 13193 case SHARED_FUNCTION_INFO_TYPE: 13194 case SYMBOL_TYPE: 13195 case ALLOCATION_SITE_TYPE: 13196 13197 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 13198 case FIXED_##TYPE##_ARRAY_TYPE: 13199 #undef TYPED_ARRAY_CASE 13200 13201 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: 13202 STRUCT_LIST(MAKE_STRUCT_CASE) 13203 #undef MAKE_STRUCT_CASE 13204 // We must not end up here for these instance types at all. 13205 UNREACHABLE(); 13206 // Fall through. 13207 default: 13208 return false; 13209 } 13210 } 13211 13212 } // namespace 13213 #endif 13214 13215 13216 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { 13217 DCHECK(function->has_prototype_slot()); 13218 DCHECK(function->IsConstructor() || 13219 IsResumableFunction(function->shared()->kind())); 13220 if (function->has_initial_map()) return; 13221 Isolate* isolate = function->GetIsolate(); 13222 13223 // First create a new map with the size and number of in-object properties 13224 // suggested by the function. 13225 InstanceType instance_type; 13226 if (IsResumableFunction(function->shared()->kind())) { 13227 instance_type = IsAsyncGeneratorFunction(function->shared()->kind()) 13228 ? JS_ASYNC_GENERATOR_OBJECT_TYPE 13229 : JS_GENERATOR_OBJECT_TYPE; 13230 } else { 13231 instance_type = JS_OBJECT_TYPE; 13232 } 13233 13234 // The constructor should be compiled for the optimization hints to be 13235 // available. 13236 int expected_nof_properties = 0; 13237 if (function->shared()->is_compiled() || 13238 Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) { 13239 DCHECK(function->shared()->is_compiled()); 13240 expected_nof_properties = function->shared()->expected_nof_properties(); 13241 } 13242 13243 int instance_size; 13244 int inobject_properties; 13245 CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties, 13246 &instance_size, &inobject_properties); 13247 13248 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size, 13249 TERMINAL_FAST_ELEMENTS_KIND, 13250 inobject_properties); 13251 13252 // Fetch or allocate prototype. 13253 Handle<Object> prototype; 13254 if (function->has_instance_prototype()) { 13255 prototype = handle(function->instance_prototype(), isolate); 13256 } else { 13257 prototype = isolate->factory()->NewFunctionPrototype(function); 13258 } 13259 DCHECK(map->has_fast_object_elements()); 13260 13261 // Finally link initial map and constructor function. 13262 DCHECK(prototype->IsJSReceiver()); 13263 JSFunction::SetInitialMap(function, map, prototype); 13264 map->StartInobjectSlackTracking(); 13265 } 13266 13267 namespace { 13268 bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target, 13269 Handle<JSFunction> constructor, 13270 Handle<Map> constructor_initial_map) { 13271 // Check that |function|'s initial map still in sync with the |constructor|, 13272 // otherwise we must create a new initial map for |function|. 13273 if (new_target->has_initial_map() && 13274 new_target->initial_map()->GetConstructor() == *constructor) { 13275 DCHECK(new_target->instance_prototype()->IsJSReceiver()); 13276 return true; 13277 } 13278 InstanceType instance_type = constructor_initial_map->instance_type(); 13279 DCHECK(CanSubclassHaveInobjectProperties(instance_type)); 13280 // Create a new map with the size and number of in-object properties 13281 // suggested by |function|. 13282 13283 // Link initial map and constructor function if the new.target is actually a 13284 // subclass constructor. 13285 if (!IsDerivedConstructor(new_target->shared()->kind())) return false; 13286 13287 int instance_size; 13288 int in_object_properties; 13289 int embedder_fields = 13290 JSObject::GetEmbedderFieldCount(*constructor_initial_map); 13291 bool success = JSFunction::CalculateInstanceSizeForDerivedClass( 13292 new_target, instance_type, embedder_fields, &instance_size, 13293 &in_object_properties); 13294 13295 Handle<Map> map; 13296 if (success) { 13297 int pre_allocated = constructor_initial_map->GetInObjectProperties() - 13298 constructor_initial_map->UnusedPropertyFields(); 13299 CHECK_LE(constructor_initial_map->UsedInstanceSize(), instance_size); 13300 int unused_property_fields = in_object_properties - pre_allocated; 13301 map = Map::CopyInitialMap(isolate, constructor_initial_map, instance_size, 13302 in_object_properties, unused_property_fields); 13303 } else { 13304 map = Map::CopyInitialMap(isolate, constructor_initial_map); 13305 } 13306 map->set_new_target_is_base(false); 13307 Handle<Object> prototype(new_target->instance_prototype(), isolate); 13308 JSFunction::SetInitialMap(new_target, map, prototype); 13309 DCHECK(new_target->instance_prototype()->IsJSReceiver()); 13310 map->SetConstructor(*constructor); 13311 map->set_construction_counter(Map::kNoSlackTracking); 13312 map->StartInobjectSlackTracking(); 13313 return true; 13314 } 13315 13316 } // namespace 13317 13318 // static 13319 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate, 13320 Handle<JSFunction> constructor, 13321 Handle<JSReceiver> new_target) { 13322 EnsureHasInitialMap(constructor); 13323 13324 Handle<Map> constructor_initial_map(constructor->initial_map(), isolate); 13325 if (*new_target == *constructor) return constructor_initial_map; 13326 13327 Handle<Map> result_map; 13328 // Fast case, new.target is a subclass of constructor. The map is cacheable 13329 // (and may already have been cached). new.target.prototype is guaranteed to 13330 // be a JSReceiver. 13331 if (new_target->IsJSFunction()) { 13332 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target); 13333 if (FastInitializeDerivedMap(isolate, function, constructor, 13334 constructor_initial_map)) { 13335 return handle(function->initial_map(), isolate); 13336 } 13337 } 13338 13339 // Slow path, new.target is either a proxy or can't cache the map. 13340 // new.target.prototype is not guaranteed to be a JSReceiver, and may need to 13341 // fall back to the intrinsicDefaultProto. 13342 Handle<Object> prototype; 13343 if (new_target->IsJSFunction()) { 13344 Handle<JSFunction> function = Handle<JSFunction>::cast(new_target); 13345 // Make sure the new.target.prototype is cached. 13346 EnsureHasInitialMap(function); 13347 prototype = handle(function->prototype(), isolate); 13348 } else { 13349 Handle<String> prototype_string = isolate->factory()->prototype_string(); 13350 ASSIGN_RETURN_ON_EXCEPTION( 13351 isolate, prototype, 13352 JSReceiver::GetProperty(isolate, new_target, prototype_string), Map); 13353 // The above prototype lookup might change the constructor and its 13354 // prototype, hence we have to reload the initial map. 13355 EnsureHasInitialMap(constructor); 13356 constructor_initial_map = handle(constructor->initial_map(), isolate); 13357 } 13358 13359 // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the 13360 // correct realm. Rather than directly fetching the .prototype, we fetch the 13361 // constructor that points to the .prototype. This relies on 13362 // constructor.prototype being FROZEN for those constructors. 13363 if (!prototype->IsJSReceiver()) { 13364 Handle<Context> context; 13365 ASSIGN_RETURN_ON_EXCEPTION(isolate, context, 13366 JSReceiver::GetFunctionRealm(new_target), Map); 13367 DCHECK(context->IsNativeContext()); 13368 Handle<Object> maybe_index = JSReceiver::GetDataProperty( 13369 constructor, isolate->factory()->native_context_index_symbol()); 13370 int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index) 13371 : Context::OBJECT_FUNCTION_INDEX; 13372 Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)), 13373 isolate); 13374 prototype = handle(realm_constructor->prototype(), isolate); 13375 } 13376 13377 Handle<Map> map = Map::CopyInitialMap(isolate, constructor_initial_map); 13378 map->set_new_target_is_base(false); 13379 CHECK(prototype->IsJSReceiver()); 13380 if (map->prototype() != *prototype) 13381 Map::SetPrototype(isolate, map, prototype); 13382 map->SetConstructor(*constructor); 13383 return map; 13384 } 13385 13386 int JSFunction::ComputeInstanceSizeWithMinSlack(Isolate* isolate) { 13387 if (has_prototype_slot() && has_initial_map() && 13388 initial_map()->IsInobjectSlackTrackingInProgress()) { 13389 int slack = initial_map()->ComputeMinObjectSlack(isolate); 13390 return initial_map()->InstanceSizeFromSlack(slack); 13391 } 13392 return initial_map()->instance_size(); 13393 } 13394 13395 void JSFunction::PrintName(FILE* out) { 13396 std::unique_ptr<char[]> name = shared()->DebugName()->ToCString(); 13397 PrintF(out, "%s", name.get()); 13398 } 13399 13400 13401 Handle<String> JSFunction::GetName(Handle<JSFunction> function) { 13402 Isolate* isolate = function->GetIsolate(); 13403 Handle<Object> name = 13404 JSReceiver::GetDataProperty(function, isolate->factory()->name_string()); 13405 if (name->IsString()) return Handle<String>::cast(name); 13406 return handle(function->shared()->DebugName(), isolate); 13407 } 13408 13409 13410 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) { 13411 Isolate* isolate = function->GetIsolate(); 13412 Handle<Object> name = JSReceiver::GetDataProperty( 13413 function, isolate->factory()->display_name_string()); 13414 if (name->IsString()) return Handle<String>::cast(name); 13415 return JSFunction::GetName(function); 13416 } 13417 13418 bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name, 13419 Handle<String> prefix) { 13420 Isolate* isolate = function->GetIsolate(); 13421 Handle<String> function_name; 13422 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, 13423 Name::ToFunctionName(isolate, name), false); 13424 if (prefix->length() > 0) { 13425 IncrementalStringBuilder builder(isolate); 13426 builder.AppendString(prefix); 13427 builder.AppendCharacter(' '); 13428 builder.AppendString(function_name); 13429 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, builder.Finish(), 13430 false); 13431 } 13432 RETURN_ON_EXCEPTION_VALUE( 13433 isolate, 13434 JSObject::DefinePropertyOrElementIgnoreAttributes( 13435 function, isolate->factory()->name_string(), function_name, 13436 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)), 13437 false); 13438 return true; 13439 } 13440 13441 namespace { 13442 13443 Handle<String> NativeCodeFunctionSourceString( 13444 Handle<SharedFunctionInfo> shared_info) { 13445 Isolate* const isolate = shared_info->GetIsolate(); 13446 IncrementalStringBuilder builder(isolate); 13447 builder.AppendCString("function "); 13448 builder.AppendString(handle(shared_info->Name(), isolate)); 13449 builder.AppendCString("() { [native code] }"); 13450 return builder.Finish().ToHandleChecked(); 13451 } 13452 13453 } // namespace 13454 13455 13456 // static 13457 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) { 13458 Isolate* const isolate = function->GetIsolate(); 13459 return isolate->factory()->function_native_code_string(); 13460 } 13461 13462 13463 // static 13464 Handle<String> JSFunction::ToString(Handle<JSFunction> function) { 13465 Isolate* const isolate = function->GetIsolate(); 13466 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate); 13467 13468 // Check if {function} should hide its source code. 13469 if (!shared_info->IsUserJavaScript()) { 13470 return NativeCodeFunctionSourceString(shared_info); 13471 } 13472 13473 // Check if we should print {function} as a class. 13474 Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty( 13475 function, isolate->factory()->class_positions_symbol()); 13476 if (maybe_class_positions->IsTuple2()) { 13477 Tuple2* class_positions = Tuple2::cast(*maybe_class_positions); 13478 int start_position = Smi::ToInt(class_positions->value1()); 13479 int end_position = Smi::ToInt(class_positions->value2()); 13480 Handle<String> script_source( 13481 String::cast(Script::cast(shared_info->script())->source()), isolate); 13482 return isolate->factory()->NewSubString(script_source, start_position, 13483 end_position); 13484 } 13485 13486 // Check if we have source code for the {function}. 13487 if (!shared_info->HasSourceCode()) { 13488 return NativeCodeFunctionSourceString(shared_info); 13489 } 13490 13491 if (FLAG_harmony_function_tostring) { 13492 if (shared_info->function_token_position() == kNoSourcePosition) { 13493 // If the function token position isn't valid, return [native code] to 13494 // ensure calling eval on the returned source code throws rather than 13495 // giving inconsistent call behaviour. 13496 isolate->CountUsage(v8::Isolate::UseCounterFeature:: 13497 kFunctionTokenOffsetTooLongForToString); 13498 return NativeCodeFunctionSourceString(shared_info); 13499 } 13500 return Handle<String>::cast( 13501 SharedFunctionInfo::GetSourceCodeHarmony(shared_info)); 13502 } 13503 13504 IncrementalStringBuilder builder(isolate); 13505 FunctionKind kind = shared_info->kind(); 13506 if (!IsArrowFunction(kind)) { 13507 if (IsConciseMethod(kind)) { 13508 if (IsAsyncGeneratorFunction(kind)) { 13509 builder.AppendCString("async *"); 13510 } else if (IsGeneratorFunction(kind)) { 13511 builder.AppendCharacter('*'); 13512 } else if (IsAsyncFunction(kind)) { 13513 builder.AppendCString("async "); 13514 } 13515 } else { 13516 if (IsAsyncGeneratorFunction(kind)) { 13517 builder.AppendCString("async function* "); 13518 } else if (IsGeneratorFunction(kind)) { 13519 builder.AppendCString("function* "); 13520 } else if (IsAsyncFunction(kind)) { 13521 builder.AppendCString("async function "); 13522 } else { 13523 builder.AppendCString("function "); 13524 } 13525 } 13526 if (shared_info->name_should_print_as_anonymous()) { 13527 builder.AppendCString("anonymous"); 13528 } else if (!shared_info->is_anonymous_expression()) { 13529 builder.AppendString(handle(shared_info->Name(), isolate)); 13530 } 13531 } 13532 if (shared_info->is_wrapped()) { 13533 builder.AppendCharacter('('); 13534 Handle<FixedArray> args( 13535 Script::cast(shared_info->script())->wrapped_arguments(), isolate); 13536 int argc = args->length(); 13537 for (int i = 0; i < argc; i++) { 13538 if (i > 0) builder.AppendCString(", "); 13539 builder.AppendString(Handle<String>(String::cast(args->get(i)), isolate)); 13540 } 13541 builder.AppendCString(") {\n"); 13542 } 13543 builder.AppendString( 13544 Handle<String>::cast(SharedFunctionInfo::GetSourceCode(shared_info))); 13545 if (shared_info->is_wrapped()) { 13546 builder.AppendCString("\n}"); 13547 } 13548 return builder.Finish().ToHandleChecked(); 13549 } 13550 13551 void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball, 13552 const char* to_string, Handle<Object> to_number, 13553 const char* type_of, byte kind) { 13554 Handle<String> internalized_to_string = 13555 isolate->factory()->InternalizeUtf8String(to_string); 13556 Handle<String> internalized_type_of = 13557 isolate->factory()->InternalizeUtf8String(type_of); 13558 if (to_number->IsHeapNumber()) { 13559 oddball->set_to_number_raw_as_bits( 13560 Handle<HeapNumber>::cast(to_number)->value_as_bits()); 13561 } else { 13562 oddball->set_to_number_raw(to_number->Number()); 13563 } 13564 oddball->set_to_number(*to_number); 13565 oddball->set_to_string(*internalized_to_string); 13566 oddball->set_type_of(*internalized_type_of); 13567 oddball->set_kind(kind); 13568 } 13569 13570 int Script::GetEvalPosition() { 13571 DisallowHeapAllocation no_gc; 13572 DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL); 13573 int position = eval_from_position(); 13574 if (position < 0) { 13575 // Due to laziness, the position may not have been translated from code 13576 // offset yet, which would be encoded as negative integer. In that case, 13577 // translate and set the position. 13578 if (!has_eval_from_shared()) { 13579 position = 0; 13580 } else { 13581 SharedFunctionInfo* shared = eval_from_shared(); 13582 position = shared->abstract_code()->SourcePosition(-position); 13583 } 13584 DCHECK_GE(position, 0); 13585 set_eval_from_position(position); 13586 } 13587 return position; 13588 } 13589 13590 void Script::InitLineEnds(Handle<Script> script) { 13591 Isolate* isolate = script->GetIsolate(); 13592 if (!script->line_ends()->IsUndefined(isolate)) return; 13593 DCHECK_NE(Script::TYPE_WASM, script->type()); 13594 13595 Object* src_obj = script->source(); 13596 if (!src_obj->IsString()) { 13597 DCHECK(src_obj->IsUndefined(isolate)); 13598 script->set_line_ends(ReadOnlyRoots(isolate).empty_fixed_array()); 13599 } else { 13600 DCHECK(src_obj->IsString()); 13601 Handle<String> src(String::cast(src_obj), isolate); 13602 Handle<FixedArray> array = String::CalculateLineEnds(isolate, src, true); 13603 script->set_line_ends(*array); 13604 } 13605 13606 DCHECK(script->line_ends()->IsFixedArray()); 13607 } 13608 13609 bool Script::GetPositionInfo(Handle<Script> script, int position, 13610 PositionInfo* info, OffsetFlag offset_flag) { 13611 // For wasm, we do not create an artificial line_ends array, but do the 13612 // translation directly. 13613 if (script->type() != Script::TYPE_WASM) InitLineEnds(script); 13614 return script->GetPositionInfo(position, info, offset_flag); 13615 } 13616 13617 bool Script::IsUserJavaScript() { return type() == Script::TYPE_NORMAL; } 13618 13619 bool Script::ContainsAsmModule() { 13620 DisallowHeapAllocation no_gc; 13621 SharedFunctionInfo::ScriptIterator iter(this->GetIsolate(), this); 13622 while (SharedFunctionInfo* info = iter.Next()) { 13623 if (info->HasAsmWasmData()) return true; 13624 } 13625 return false; 13626 } 13627 13628 namespace { 13629 bool GetPositionInfoSlow(const Script* script, int position, 13630 Script::PositionInfo* info) { 13631 if (!script->source()->IsString()) return false; 13632 if (position < 0) position = 0; 13633 13634 String* source_string = String::cast(script->source()); 13635 int line = 0; 13636 int line_start = 0; 13637 int len = source_string->length(); 13638 for (int pos = 0; pos <= len; ++pos) { 13639 if (pos == len || source_string->Get(pos) == '\n') { 13640 if (position <= pos) { 13641 info->line = line; 13642 info->column = position - line_start; 13643 info->line_start = line_start; 13644 info->line_end = pos; 13645 return true; 13646 } 13647 line++; 13648 line_start = pos + 1; 13649 } 13650 } 13651 return false; 13652 } 13653 } // namespace 13654 13655 #define SMI_VALUE(x) (Smi::ToInt(x)) 13656 bool Script::GetPositionInfo(int position, PositionInfo* info, 13657 OffsetFlag offset_flag) const { 13658 DisallowHeapAllocation no_allocation; 13659 13660 // For wasm, we do not rely on the line_ends array, but do the translation 13661 // directly. 13662 if (type() == Script::TYPE_WASM) { 13663 DCHECK_LE(0, position); 13664 return WasmModuleObject::cast(wasm_module_object()) 13665 ->GetPositionInfo(static_cast<uint32_t>(position), info); 13666 } 13667 13668 if (line_ends()->IsUndefined()) { 13669 // Slow mode: we do not have line_ends. We have to iterate through source. 13670 if (!GetPositionInfoSlow(this, position, info)) return false; 13671 } else { 13672 DCHECK(line_ends()->IsFixedArray()); 13673 FixedArray* ends = FixedArray::cast(line_ends()); 13674 13675 const int ends_len = ends->length(); 13676 if (ends_len == 0) return false; 13677 13678 // Return early on invalid positions. Negative positions behave as if 0 was 13679 // passed, and positions beyond the end of the script return as failure. 13680 if (position < 0) { 13681 position = 0; 13682 } else if (position > SMI_VALUE(ends->get(ends_len - 1))) { 13683 return false; 13684 } 13685 13686 // Determine line number by doing a binary search on the line ends array. 13687 if (SMI_VALUE(ends->get(0)) >= position) { 13688 info->line = 0; 13689 info->line_start = 0; 13690 info->column = position; 13691 } else { 13692 int left = 0; 13693 int right = ends_len - 1; 13694 13695 while (right > 0) { 13696 DCHECK_LE(left, right); 13697 const int mid = (left + right) / 2; 13698 if (position > SMI_VALUE(ends->get(mid))) { 13699 left = mid + 1; 13700 } else if (position <= SMI_VALUE(ends->get(mid - 1))) { 13701 right = mid - 1; 13702 } else { 13703 info->line = mid; 13704 break; 13705 } 13706 } 13707 DCHECK(SMI_VALUE(ends->get(info->line)) >= position && 13708 SMI_VALUE(ends->get(info->line - 1)) < position); 13709 info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1; 13710 info->column = position - info->line_start; 13711 } 13712 13713 // Line end is position of the linebreak character. 13714 info->line_end = SMI_VALUE(ends->get(info->line)); 13715 if (info->line_end > 0) { 13716 DCHECK(source()->IsString()); 13717 String* src = String::cast(source()); 13718 if (src->length() >= info->line_end && 13719 src->Get(info->line_end - 1) == '\r') { 13720 info->line_end--; 13721 } 13722 } 13723 } 13724 13725 // Add offsets if requested. 13726 if (offset_flag == WITH_OFFSET) { 13727 if (info->line == 0) { 13728 info->column += column_offset(); 13729 } 13730 info->line += line_offset(); 13731 } 13732 13733 return true; 13734 } 13735 #undef SMI_VALUE 13736 13737 int Script::GetColumnNumber(Handle<Script> script, int code_pos) { 13738 PositionInfo info; 13739 GetPositionInfo(script, code_pos, &info, WITH_OFFSET); 13740 return info.column; 13741 } 13742 13743 int Script::GetColumnNumber(int code_pos) const { 13744 PositionInfo info; 13745 GetPositionInfo(code_pos, &info, WITH_OFFSET); 13746 return info.column; 13747 } 13748 13749 int Script::GetLineNumber(Handle<Script> script, int code_pos) { 13750 PositionInfo info; 13751 GetPositionInfo(script, code_pos, &info, WITH_OFFSET); 13752 return info.line; 13753 } 13754 13755 int Script::GetLineNumber(int code_pos) const { 13756 PositionInfo info; 13757 GetPositionInfo(code_pos, &info, WITH_OFFSET); 13758 return info.line; 13759 } 13760 13761 Object* Script::GetNameOrSourceURL() { 13762 // Keep in sync with ScriptNameOrSourceURL in messages.js. 13763 if (!source_url()->IsUndefined()) return source_url(); 13764 return name(); 13765 } 13766 13767 MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( 13768 Isolate* isolate, const FunctionLiteral* fun) { 13769 CHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid); 13770 // If this check fails, the problem is most probably the function id 13771 // renumbering done by AstFunctionLiteralIdReindexer; in particular, that 13772 // AstTraversalVisitor doesn't recurse properly in the construct which 13773 // triggers the mismatch. 13774 CHECK_LT(fun->function_literal_id(), shared_function_infos()->length()); 13775 MaybeObject* shared = 13776 shared_function_infos()->Get(fun->function_literal_id()); 13777 HeapObject* heap_object; 13778 if (!shared->ToStrongOrWeakHeapObject(&heap_object) || 13779 heap_object->IsUndefined(isolate)) { 13780 return MaybeHandle<SharedFunctionInfo>(); 13781 } 13782 return handle(SharedFunctionInfo::cast(heap_object), isolate); 13783 } 13784 13785 Script::Iterator::Iterator(Isolate* isolate) 13786 : iterator_(isolate->heap()->script_list()) {} 13787 13788 Script* Script::Iterator::Next() { 13789 Object* o = iterator_.Next(); 13790 if (o != nullptr) { 13791 return Script::cast(o); 13792 } 13793 return nullptr; 13794 } 13795 13796 Code* SharedFunctionInfo::GetCode() const { 13797 // ====== 13798 // NOTE: This chain of checks MUST be kept in sync with the equivalent CSA 13799 // GetSharedFunctionInfoCode method in code-stub-assembler.cc. 13800 // ====== 13801 13802 Isolate* isolate = GetIsolate(); 13803 Object* data = function_data(); 13804 if (data->IsSmi()) { 13805 // Holding a Smi means we are a builtin. 13806 DCHECK(HasBuiltinId()); 13807 return isolate->builtins()->builtin(builtin_id()); 13808 } else if (data->IsBytecodeArray()) { 13809 // Having a bytecode array means we are a compiled, interpreted function. 13810 DCHECK(HasBytecodeArray()); 13811 return isolate->builtins()->builtin(Builtins::kInterpreterEntryTrampoline); 13812 } else if (data->IsFixedArray()) { 13813 // Having a fixed array means we are an asm.js/wasm function. 13814 DCHECK(HasAsmWasmData()); 13815 return isolate->builtins()->builtin(Builtins::kInstantiateAsmJs); 13816 } else if (data->IsUncompiledData()) { 13817 // Having uncompiled data (with or without scope) means we need to compile. 13818 DCHECK(HasUncompiledData()); 13819 return isolate->builtins()->builtin(Builtins::kCompileLazy); 13820 } else if (data->IsFunctionTemplateInfo()) { 13821 // Having a function template info means we are an API function. 13822 DCHECK(IsApiFunction()); 13823 return isolate->builtins()->builtin(Builtins::kHandleApiCall); 13824 } else if (data->IsWasmExportedFunctionData()) { 13825 // Having a WasmExportedFunctionData means the code is in there. 13826 DCHECK(HasWasmExportedFunctionData()); 13827 return wasm_exported_function_data()->wrapper_code(); 13828 } else if (data->IsInterpreterData()) { 13829 Code* code = InterpreterTrampoline(); 13830 DCHECK(code->IsCode()); 13831 DCHECK(code->is_interpreter_trampoline_builtin()); 13832 return code; 13833 } 13834 UNREACHABLE(); 13835 } 13836 13837 WasmExportedFunctionData* SharedFunctionInfo::wasm_exported_function_data() 13838 const { 13839 DCHECK(HasWasmExportedFunctionData()); 13840 return WasmExportedFunctionData::cast(function_data()); 13841 } 13842 13843 SharedFunctionInfo::ScriptIterator::ScriptIterator(Isolate* isolate, 13844 Script* script) 13845 : ScriptIterator(isolate, 13846 handle(script->shared_function_infos(), isolate)) {} 13847 13848 SharedFunctionInfo::ScriptIterator::ScriptIterator( 13849 Isolate* isolate, Handle<WeakFixedArray> shared_function_infos) 13850 : isolate_(isolate), 13851 shared_function_infos_(shared_function_infos), 13852 index_(0) {} 13853 13854 SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() { 13855 while (index_ < shared_function_infos_->length()) { 13856 MaybeObject* raw = shared_function_infos_->Get(index_++); 13857 HeapObject* heap_object; 13858 if (!raw->ToStrongOrWeakHeapObject(&heap_object) || 13859 heap_object->IsUndefined(isolate_)) { 13860 continue; 13861 } 13862 return SharedFunctionInfo::cast(heap_object); 13863 } 13864 return nullptr; 13865 } 13866 13867 void SharedFunctionInfo::ScriptIterator::Reset(Script* script) { 13868 shared_function_infos_ = handle(script->shared_function_infos(), isolate_); 13869 index_ = 0; 13870 } 13871 13872 SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate) 13873 : script_iterator_(isolate), 13874 noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()), 13875 sfi_iterator_(isolate, script_iterator_.Next()) {} 13876 13877 SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() { 13878 HeapObject* next = noscript_sfi_iterator_.Next(); 13879 if (next != nullptr) return SharedFunctionInfo::cast(next); 13880 for (;;) { 13881 next = sfi_iterator_.Next(); 13882 if (next != nullptr) return SharedFunctionInfo::cast(next); 13883 Script* next_script = script_iterator_.Next(); 13884 if (next_script == nullptr) return nullptr; 13885 sfi_iterator_.Reset(next_script); 13886 } 13887 } 13888 13889 void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared, 13890 Handle<Object> script_object, 13891 int function_literal_id, 13892 bool reset_preparsed_scope_data) { 13893 if (shared->script() == *script_object) return; 13894 Isolate* isolate = shared->GetIsolate(); 13895 13896 if (reset_preparsed_scope_data && 13897 shared->HasUncompiledDataWithPreParsedScope()) { 13898 shared->ClearPreParsedScopeData(); 13899 } 13900 13901 // Add shared function info to new script's list. If a collection occurs, 13902 // the shared function info may be temporarily in two lists. 13903 // This is okay because the gc-time processing of these lists can tolerate 13904 // duplicates. 13905 if (script_object->IsScript()) { 13906 DCHECK(!shared->script()->IsScript()); 13907 Handle<Script> script = Handle<Script>::cast(script_object); 13908 Handle<WeakFixedArray> list = 13909 handle(script->shared_function_infos(), isolate); 13910 #ifdef DEBUG 13911 DCHECK_LT(function_literal_id, list->length()); 13912 MaybeObject* maybe_object = list->Get(function_literal_id); 13913 HeapObject* heap_object; 13914 if (maybe_object->ToWeakHeapObject(&heap_object)) { 13915 DCHECK_EQ(heap_object, *shared); 13916 } 13917 #endif 13918 list->Set(function_literal_id, HeapObjectReference::Weak(*shared)); 13919 13920 // Remove shared function info from root array. 13921 WeakArrayList* noscript_list = 13922 isolate->heap()->noscript_shared_function_infos(); 13923 CHECK(noscript_list->RemoveOne(MaybeObjectHandle::Weak(shared))); 13924 } else { 13925 DCHECK(shared->script()->IsScript()); 13926 Handle<WeakArrayList> list = 13927 isolate->factory()->noscript_shared_function_infos(); 13928 13929 #ifdef DEBUG 13930 if (FLAG_enable_slow_asserts) { 13931 WeakArrayList::Iterator iterator(*list); 13932 HeapObject* next; 13933 while ((next = iterator.Next()) != nullptr) { 13934 DCHECK_NE(next, *shared); 13935 } 13936 } 13937 #endif // DEBUG 13938 13939 list = 13940 WeakArrayList::AddToEnd(isolate, list, MaybeObjectHandle::Weak(shared)); 13941 13942 isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list); 13943 13944 // Remove shared function info from old script's list. 13945 Script* old_script = Script::cast(shared->script()); 13946 13947 // Due to liveedit, it might happen that the old_script doesn't know 13948 // about the SharedFunctionInfo, so we have to guard against that. 13949 Handle<WeakFixedArray> infos(old_script->shared_function_infos(), isolate); 13950 if (function_literal_id < infos->length()) { 13951 MaybeObject* raw = 13952 old_script->shared_function_infos()->Get(function_literal_id); 13953 HeapObject* heap_object; 13954 if (raw->ToWeakHeapObject(&heap_object) && heap_object == *shared) { 13955 old_script->shared_function_infos()->Set( 13956 function_literal_id, HeapObjectReference::Strong( 13957 ReadOnlyRoots(isolate).undefined_value())); 13958 } 13959 } 13960 } 13961 13962 // Finally set new script. 13963 shared->set_script(*script_object); 13964 } 13965 13966 bool SharedFunctionInfo::HasBreakInfo() const { 13967 if (!HasDebugInfo()) return false; 13968 DebugInfo* info = DebugInfo::cast(GetDebugInfo()); 13969 bool has_break_info = info->HasBreakInfo(); 13970 return has_break_info; 13971 } 13972 13973 bool SharedFunctionInfo::BreakAtEntry() const { 13974 if (!HasDebugInfo()) return false; 13975 DebugInfo* info = DebugInfo::cast(GetDebugInfo()); 13976 bool break_at_entry = info->BreakAtEntry(); 13977 return break_at_entry; 13978 } 13979 13980 bool SharedFunctionInfo::HasCoverageInfo() const { 13981 if (!HasDebugInfo()) return false; 13982 DebugInfo* info = DebugInfo::cast(GetDebugInfo()); 13983 bool has_coverage_info = info->HasCoverageInfo(); 13984 return has_coverage_info; 13985 } 13986 13987 CoverageInfo* SharedFunctionInfo::GetCoverageInfo() const { 13988 DCHECK(HasCoverageInfo()); 13989 return CoverageInfo::cast(GetDebugInfo()->coverage_info()); 13990 } 13991 13992 String* SharedFunctionInfo::DebugName() { 13993 DisallowHeapAllocation no_gc; 13994 String* function_name = Name(); 13995 if (function_name->length() > 0) return function_name; 13996 return inferred_name(); 13997 } 13998 13999 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) { 14000 Vector<const char> filter = CStrVector(raw_filter); 14001 std::unique_ptr<char[]> cstrname(DebugName()->ToCString()); 14002 return v8::internal::PassesFilter(CStrVector(cstrname.get()), filter); 14003 } 14004 14005 bool SharedFunctionInfo::HasSourceCode() const { 14006 Isolate* isolate = GetIsolate(); 14007 return !script()->IsUndefined(isolate) && 14008 !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate); 14009 } 14010 14011 // static 14012 Handle<Object> SharedFunctionInfo::GetSourceCode( 14013 Handle<SharedFunctionInfo> shared) { 14014 Isolate* isolate = shared->GetIsolate(); 14015 if (!shared->HasSourceCode()) return isolate->factory()->undefined_value(); 14016 Handle<String> source(String::cast(Script::cast(shared->script())->source()), 14017 isolate); 14018 return isolate->factory()->NewSubString(source, shared->StartPosition(), 14019 shared->EndPosition()); 14020 } 14021 14022 // static 14023 Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony( 14024 Handle<SharedFunctionInfo> shared) { 14025 Isolate* isolate = shared->GetIsolate(); 14026 if (!shared->HasSourceCode()) return isolate->factory()->undefined_value(); 14027 Handle<String> script_source( 14028 String::cast(Script::cast(shared->script())->source()), isolate); 14029 int start_pos = shared->function_token_position(); 14030 DCHECK_NE(start_pos, kNoSourcePosition); 14031 Handle<String> source = isolate->factory()->NewSubString( 14032 script_source, start_pos, shared->EndPosition()); 14033 if (!shared->is_wrapped()) return source; 14034 14035 DCHECK(!shared->name_should_print_as_anonymous()); 14036 IncrementalStringBuilder builder(isolate); 14037 builder.AppendCString("function "); 14038 builder.AppendString(Handle<String>(shared->Name(), isolate)); 14039 builder.AppendCString("("); 14040 Handle<FixedArray> args(Script::cast(shared->script())->wrapped_arguments(), 14041 isolate); 14042 int argc = args->length(); 14043 for (int i = 0; i < argc; i++) { 14044 if (i > 0) builder.AppendCString(", "); 14045 builder.AppendString(Handle<String>(String::cast(args->get(i)), isolate)); 14046 } 14047 builder.AppendCString(") {\n"); 14048 builder.AppendString(source); 14049 builder.AppendCString("\n}"); 14050 return builder.Finish().ToHandleChecked(); 14051 } 14052 14053 bool SharedFunctionInfo::IsInlineable() { 14054 // Check that the function has a script associated with it. 14055 if (!script()->IsScript()) return false; 14056 if (GetIsolate()->is_precise_binary_code_coverage() && 14057 !has_reported_binary_coverage()) { 14058 // We may miss invocations if this function is inlined. 14059 return false; 14060 } 14061 return !optimization_disabled(); 14062 } 14063 14064 int SharedFunctionInfo::SourceSize() { return EndPosition() - StartPosition(); } 14065 14066 int SharedFunctionInfo::FindIndexInScript(Isolate* isolate) const { 14067 DisallowHeapAllocation no_gc; 14068 14069 Object* script_obj = script(); 14070 if (!script_obj->IsScript()) return FunctionLiteral::kIdTypeInvalid; 14071 14072 WeakFixedArray* shared_info_list = 14073 Script::cast(script_obj)->shared_function_infos(); 14074 SharedFunctionInfo::ScriptIterator iterator( 14075 isolate, Handle<WeakFixedArray>(&shared_info_list)); 14076 14077 for (SharedFunctionInfo* shared = iterator.Next(); shared != nullptr; 14078 shared = iterator.Next()) { 14079 if (shared == this) { 14080 return iterator.CurrentIndex(); 14081 } 14082 } 14083 14084 return FunctionLiteral::kIdTypeInvalid; 14085 } 14086 14087 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type, 14088 bool has_prototype_slot, 14089 int requested_embedder_fields, 14090 int requested_in_object_properties, 14091 int* instance_size, 14092 int* in_object_properties) { 14093 DCHECK_LE(static_cast<unsigned>(requested_embedder_fields), 14094 JSObject::kMaxEmbedderFields); 14095 int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot); 14096 int max_nof_fields = 14097 (JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2; 14098 CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties); 14099 CHECK_LE(static_cast<unsigned>(requested_embedder_fields), 14100 static_cast<unsigned>(max_nof_fields)); 14101 *in_object_properties = Min(requested_in_object_properties, 14102 max_nof_fields - requested_embedder_fields); 14103 *instance_size = 14104 header_size + 14105 ((requested_embedder_fields + *in_object_properties) << kPointerSizeLog2); 14106 CHECK_EQ(*in_object_properties, 14107 ((*instance_size - header_size) >> kPointerSizeLog2) - 14108 requested_embedder_fields); 14109 CHECK_LE(static_cast<unsigned>(*instance_size), 14110 static_cast<unsigned>(JSObject::kMaxInstanceSize)); 14111 } 14112 14113 // static 14114 bool JSFunction::CalculateInstanceSizeForDerivedClass( 14115 Handle<JSFunction> function, InstanceType instance_type, 14116 int requested_embedder_fields, int* instance_size, 14117 int* in_object_properties) { 14118 Isolate* isolate = function->GetIsolate(); 14119 int expected_nof_properties = 0; 14120 for (PrototypeIterator iter(isolate, function, kStartAtReceiver); 14121 !iter.IsAtEnd(); iter.Advance()) { 14122 Handle<JSReceiver> current = 14123 PrototypeIterator::GetCurrent<JSReceiver>(iter); 14124 if (!current->IsJSFunction()) break; 14125 Handle<JSFunction> func(Handle<JSFunction>::cast(current)); 14126 // The super constructor should be compiled for the number of expected 14127 // properties to be available. 14128 Handle<SharedFunctionInfo> shared(func->shared(), isolate); 14129 if (shared->is_compiled() || 14130 Compiler::Compile(func, Compiler::CLEAR_EXCEPTION)) { 14131 DCHECK(shared->is_compiled()); 14132 int count = shared->expected_nof_properties(); 14133 // Check that the estimate is sane. 14134 if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) { 14135 expected_nof_properties += count; 14136 } else { 14137 expected_nof_properties = JSObject::kMaxInObjectProperties; 14138 } 14139 } else if (!shared->is_compiled()) { 14140 // In case there was a compilation error for the constructor we will 14141 // throw an error during instantiation. Hence we directly return 0; 14142 return false; 14143 } 14144 if (!IsDerivedConstructor(shared->kind())) break; 14145 } 14146 CalculateInstanceSizeHelper(instance_type, true, requested_embedder_fields, 14147 expected_nof_properties, instance_size, 14148 in_object_properties); 14149 return true; 14150 } 14151 14152 14153 // Output the source code without any allocation in the heap. 14154 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) { 14155 const SharedFunctionInfo* s = v.value; 14156 // For some native functions there is no source. 14157 if (!s->HasSourceCode()) return os << "<No Source>"; 14158 14159 // Get the source for the script which this function came from. 14160 // Don't use String::cast because we don't want more assertion errors while 14161 // we are already creating a stack dump. 14162 String* script_source = 14163 reinterpret_cast<String*>(Script::cast(s->script())->source()); 14164 14165 if (!script_source->LooksValid()) return os << "<Invalid Source>"; 14166 14167 if (!s->is_toplevel()) { 14168 os << "function "; 14169 String* name = s->Name(); 14170 if (name->length() > 0) { 14171 name->PrintUC16(os); 14172 } 14173 } 14174 14175 int len = s->EndPosition() - s->StartPosition(); 14176 if (len <= v.max_length || v.max_length < 0) { 14177 script_source->PrintUC16(os, s->StartPosition(), s->EndPosition()); 14178 return os; 14179 } else { 14180 script_source->PrintUC16(os, s->StartPosition(), 14181 s->StartPosition() + v.max_length); 14182 return os << "...\n"; 14183 } 14184 } 14185 14186 14187 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) { 14188 DCHECK_NE(reason, BailoutReason::kNoReason); 14189 14190 set_flags(DisabledOptimizationReasonBits::update(flags(), reason)); 14191 // Code should be the lazy compilation stub or else interpreted. 14192 DCHECK(abstract_code()->kind() == AbstractCode::INTERPRETED_FUNCTION || 14193 abstract_code()->kind() == AbstractCode::BUILTIN); 14194 PROFILE(GetIsolate(), CodeDisableOptEvent(abstract_code(), this)); 14195 if (FLAG_trace_opt) { 14196 PrintF("[disabled optimization for "); 14197 ShortPrint(); 14198 PrintF(", reason: %s]\n", GetBailoutReason(reason)); 14199 } 14200 } 14201 14202 void SharedFunctionInfo::InitFromFunctionLiteral( 14203 Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit, 14204 bool is_toplevel) { 14205 Isolate* isolate = shared_info->GetIsolate(); 14206 bool needs_position_info = true; 14207 14208 // When adding fields here, make sure DeclarationScope::AnalyzePartially is 14209 // updated accordingly. 14210 shared_info->set_internal_formal_parameter_count(lit->parameter_count()); 14211 shared_info->SetFunctionTokenPosition(lit->function_token_position(), 14212 lit->start_position()); 14213 if (shared_info->scope_info()->HasPositionInfo()) { 14214 shared_info->scope_info()->SetPositionInfo(lit->start_position(), 14215 lit->end_position()); 14216 needs_position_info = false; 14217 } 14218 shared_info->set_is_declaration(lit->is_declaration()); 14219 shared_info->set_is_named_expression(lit->is_named_expression()); 14220 shared_info->set_is_anonymous_expression(lit->is_anonymous_expression()); 14221 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); 14222 shared_info->set_language_mode(lit->language_mode()); 14223 shared_info->set_is_wrapped(lit->is_wrapped()); 14224 // shared_info->set_kind(lit->kind()); 14225 // FunctionKind must have already been set. 14226 DCHECK(lit->kind() == shared_info->kind()); 14227 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject()); 14228 DCHECK_IMPLIES(lit->requires_instance_fields_initializer(), 14229 IsClassConstructor(lit->kind())); 14230 shared_info->set_requires_instance_fields_initializer( 14231 lit->requires_instance_fields_initializer()); 14232 14233 shared_info->set_is_toplevel(is_toplevel); 14234 DCHECK(shared_info->outer_scope_info()->IsTheHole()); 14235 if (!is_toplevel) { 14236 Scope* outer_scope = lit->scope()->GetOuterScopeWithContext(); 14237 if (outer_scope) { 14238 shared_info->set_outer_scope_info(*outer_scope->scope_info()); 14239 } 14240 } 14241 14242 // For lazy parsed functions, the following flags will be inaccurate since we 14243 // don't have the information yet. They're set later in 14244 // SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is 14245 // really parsed and compiled. 14246 if (lit->body() != nullptr) { 14247 shared_info->set_length(lit->function_length()); 14248 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); 14249 shared_info->SetExpectedNofPropertiesFromEstimate(lit); 14250 DCHECK_NULL(lit->produced_preparsed_scope_data()); 14251 if (lit->ShouldEagerCompile()) { 14252 // If we're about to eager compile, we'll have the function literal 14253 // available, so there's no need to wastefully allocate an uncompiled 14254 // data. 14255 // TODO(leszeks): This should be explicitly passed as a parameter, rather 14256 // than relying on a property of the literal. 14257 needs_position_info = false; 14258 } 14259 } else { 14260 // Set an invalid length for lazy functions. This way we can set the correct 14261 // value after compiling, but avoid overwriting values set manually by the 14262 // bootstrapper. 14263 shared_info->set_length(SharedFunctionInfo::kInvalidLength); 14264 if (FLAG_preparser_scope_analysis) { 14265 ProducedPreParsedScopeData* scope_data = 14266 lit->produced_preparsed_scope_data(); 14267 if (scope_data != nullptr) { 14268 Handle<PreParsedScopeData> pre_parsed_scope_data; 14269 if (scope_data->Serialize(shared_info->GetIsolate()) 14270 .ToHandle(&pre_parsed_scope_data)) { 14271 Handle<UncompiledData> data = 14272 isolate->factory()->NewUncompiledDataWithPreParsedScope( 14273 lit->inferred_name(), lit->start_position(), 14274 lit->end_position(), lit->function_literal_id(), 14275 pre_parsed_scope_data); 14276 shared_info->set_uncompiled_data(*data); 14277 needs_position_info = false; 14278 } 14279 } 14280 } 14281 } 14282 if (needs_position_info) { 14283 Handle<UncompiledData> data = 14284 isolate->factory()->NewUncompiledDataWithoutPreParsedScope( 14285 lit->inferred_name(), lit->start_position(), lit->end_position(), 14286 lit->function_literal_id()); 14287 shared_info->set_uncompiled_data(*data); 14288 } 14289 } 14290 14291 void SharedFunctionInfo::SetExpectedNofPropertiesFromEstimate( 14292 FunctionLiteral* literal) { 14293 int estimate = literal->expected_property_count(); 14294 14295 // If no properties are added in the constructor, they are more likely 14296 // to be added later. 14297 if (estimate == 0) estimate = 2; 14298 14299 // Inobject slack tracking will reclaim redundant inobject space later, 14300 // so we can afford to adjust the estimate generously. 14301 estimate += 8; 14302 14303 // Limit actual estimate to fit in a 8 bit field, we will never allocate 14304 // more than this in any case. 14305 STATIC_ASSERT(JSObject::kMaxInObjectProperties <= kMaxUInt8); 14306 estimate = std::min(estimate, kMaxUInt8); 14307 14308 set_expected_nof_properties(estimate); 14309 } 14310 14311 void SharedFunctionInfo::SetFunctionTokenPosition(int function_token_position, 14312 int start_position) { 14313 int offset; 14314 if (function_token_position == kNoSourcePosition) { 14315 offset = 0; 14316 } else { 14317 offset = start_position - function_token_position; 14318 } 14319 14320 if (offset > kMaximumFunctionTokenOffset) { 14321 offset = kFunctionTokenOutOfRange; 14322 } 14323 set_raw_function_token_offset(offset); 14324 } 14325 14326 void Map::StartInobjectSlackTracking() { 14327 DCHECK(!IsInobjectSlackTrackingInProgress()); 14328 if (UnusedPropertyFields() == 0) return; 14329 set_construction_counter(Map::kSlackTrackingCounterStart); 14330 } 14331 14332 void ObjectVisitor::VisitCodeTarget(Code* host, RelocInfo* rinfo) { 14333 DCHECK(RelocInfo::IsCodeTargetMode(rinfo->rmode())); 14334 Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address()); 14335 Object* new_pointer = old_pointer; 14336 VisitPointer(host, &new_pointer); 14337 DCHECK_EQ(old_pointer, new_pointer); 14338 } 14339 14340 void ObjectVisitor::VisitEmbeddedPointer(Code* host, RelocInfo* rinfo) { 14341 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); 14342 Object* old_pointer = rinfo->target_object(); 14343 Object* new_pointer = old_pointer; 14344 VisitPointer(host, &new_pointer); 14345 DCHECK_EQ(old_pointer, new_pointer); 14346 } 14347 14348 void ObjectVisitor::VisitRelocInfo(RelocIterator* it) { 14349 for (; !it->done(); it->next()) { 14350 it->rinfo()->Visit(this); 14351 } 14352 } 14353 14354 void Code::InvalidateEmbeddedObjects(Heap* heap) { 14355 HeapObject* undefined = ReadOnlyRoots(heap).undefined_value(); 14356 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 14357 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { 14358 RelocInfo::Mode mode = it.rinfo()->rmode(); 14359 if (mode == RelocInfo::EMBEDDED_OBJECT) { 14360 it.rinfo()->set_target_object(heap, undefined, SKIP_WRITE_BARRIER); 14361 } 14362 } 14363 } 14364 14365 14366 void Code::Relocate(intptr_t delta) { 14367 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) { 14368 it.rinfo()->apply(delta); 14369 } 14370 Assembler::FlushICache(raw_instruction_start(), raw_instruction_size()); 14371 } 14372 14373 void Code::FlushICache() const { 14374 Assembler::FlushICache(raw_instruction_start(), raw_instruction_size()); 14375 } 14376 14377 void Code::CopyFrom(Heap* heap, const CodeDesc& desc) { 14378 CopyFromNoFlush(heap, desc); 14379 FlushICache(); 14380 } 14381 14382 void Code::CopyFromNoFlush(Heap* heap, const CodeDesc& desc) { 14383 // Copy code. 14384 CopyBytes(reinterpret_cast<byte*>(raw_instruction_start()), desc.buffer, 14385 static_cast<size_t>(desc.instr_size)); 14386 14387 // Copy unwinding info, if any. 14388 if (desc.unwinding_info) { 14389 DCHECK_GT(desc.unwinding_info_size, 0); 14390 set_unwinding_info_size(desc.unwinding_info_size); 14391 CopyBytes(reinterpret_cast<byte*>(unwinding_info_start()), 14392 desc.unwinding_info, 14393 static_cast<size_t>(desc.unwinding_info_size)); 14394 } 14395 14396 // Copy reloc info. 14397 CopyBytes(relocation_start(), 14398 desc.buffer + desc.buffer_size - desc.reloc_size, 14399 static_cast<size_t>(desc.reloc_size)); 14400 14401 // Unbox handles and relocate. 14402 Assembler* origin = desc.origin; 14403 AllowDeferredHandleDereference embedding_raw_address; 14404 const int mode_mask = RelocInfo::PostCodegenRelocationMask(); 14405 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { 14406 RelocInfo::Mode mode = it.rinfo()->rmode(); 14407 if (mode == RelocInfo::EMBEDDED_OBJECT) { 14408 Handle<HeapObject> p = it.rinfo()->target_object_handle(origin); 14409 it.rinfo()->set_target_object(heap, *p, UPDATE_WRITE_BARRIER, 14410 SKIP_ICACHE_FLUSH); 14411 } else if (RelocInfo::IsCodeTargetMode(mode)) { 14412 // Rewrite code handles to direct pointers to the first instruction in the 14413 // code object. 14414 Handle<Object> p = it.rinfo()->target_object_handle(origin); 14415 Code* code = Code::cast(*p); 14416 it.rinfo()->set_target_address(code->raw_instruction_start(), 14417 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); 14418 } else if (RelocInfo::IsRuntimeEntry(mode)) { 14419 Address p = it.rinfo()->target_runtime_entry(origin); 14420 it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER, 14421 SKIP_ICACHE_FLUSH); 14422 } else { 14423 intptr_t delta = 14424 raw_instruction_start() - reinterpret_cast<Address>(desc.buffer); 14425 it.rinfo()->apply(delta); 14426 } 14427 } 14428 } 14429 14430 14431 SafepointEntry Code::GetSafepointEntry(Address pc) { 14432 SafepointTable table(this); 14433 return table.FindEntry(pc); 14434 } 14435 14436 int Code::OffHeapInstructionSize() const { 14437 DCHECK(is_off_heap_trampoline()); 14438 if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_size(); 14439 EmbeddedData d = EmbeddedData::FromBlob(); 14440 return d.InstructionSizeOfBuiltin(builtin_index()); 14441 } 14442 14443 Address Code::OffHeapInstructionStart() const { 14444 DCHECK(is_off_heap_trampoline()); 14445 if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_start(); 14446 EmbeddedData d = EmbeddedData::FromBlob(); 14447 return d.InstructionStartOfBuiltin(builtin_index()); 14448 } 14449 14450 Address Code::OffHeapInstructionEnd() const { 14451 DCHECK(is_off_heap_trampoline()); 14452 if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_end(); 14453 EmbeddedData d = EmbeddedData::FromBlob(); 14454 return d.InstructionStartOfBuiltin(builtin_index()) + 14455 d.InstructionSizeOfBuiltin(builtin_index()); 14456 } 14457 14458 namespace { 14459 template <typename Code> 14460 void SetStackFrameCacheCommon(Isolate* isolate, Handle<Code> code, 14461 Handle<SimpleNumberDictionary> cache) { 14462 Handle<Object> maybe_table(code->source_position_table(), isolate); 14463 if (maybe_table->IsSourcePositionTableWithFrameCache()) { 14464 Handle<SourcePositionTableWithFrameCache>::cast(maybe_table) 14465 ->set_stack_frame_cache(*cache); 14466 return; 14467 } 14468 DCHECK(maybe_table->IsByteArray()); 14469 Handle<ByteArray> table(Handle<ByteArray>::cast(maybe_table)); 14470 Handle<SourcePositionTableWithFrameCache> table_with_cache = 14471 isolate->factory()->NewSourcePositionTableWithFrameCache(table, cache); 14472 code->set_source_position_table(*table_with_cache); 14473 } 14474 } // namespace 14475 14476 // static 14477 void AbstractCode::SetStackFrameCache(Handle<AbstractCode> abstract_code, 14478 Handle<SimpleNumberDictionary> cache) { 14479 if (abstract_code->IsCode()) { 14480 SetStackFrameCacheCommon( 14481 abstract_code->GetIsolate(), 14482 handle(abstract_code->GetCode(), abstract_code->GetIsolate()), cache); 14483 } else { 14484 SetStackFrameCacheCommon( 14485 abstract_code->GetIsolate(), 14486 handle(abstract_code->GetBytecodeArray(), abstract_code->GetIsolate()), 14487 cache); 14488 } 14489 } 14490 14491 namespace { 14492 template <typename Code> 14493 void DropStackFrameCacheCommon(Code* code) { 14494 i::Object* maybe_table = code->source_position_table(); 14495 if (maybe_table->IsByteArray()) return; 14496 DCHECK(maybe_table->IsSourcePositionTableWithFrameCache()); 14497 code->set_source_position_table( 14498 i::SourcePositionTableWithFrameCache::cast(maybe_table) 14499 ->source_position_table()); 14500 } 14501 } // namespace 14502 14503 void AbstractCode::DropStackFrameCache() { 14504 if (IsCode()) { 14505 DropStackFrameCacheCommon(GetCode()); 14506 } else { 14507 DropStackFrameCacheCommon(GetBytecodeArray()); 14508 } 14509 } 14510 14511 int AbstractCode::SourcePosition(int offset) { 14512 int position = 0; 14513 // Subtract one because the current PC is one instruction after the call site. 14514 if (IsCode()) offset--; 14515 for (SourcePositionTableIterator iterator(source_position_table()); 14516 !iterator.done() && iterator.code_offset() <= offset; 14517 iterator.Advance()) { 14518 position = iterator.source_position().ScriptOffset(); 14519 } 14520 return position; 14521 } 14522 14523 int AbstractCode::SourceStatementPosition(int offset) { 14524 // First find the closest position. 14525 int position = SourcePosition(offset); 14526 // Now find the closest statement position before the position. 14527 int statement_position = 0; 14528 for (SourcePositionTableIterator it(source_position_table()); !it.done(); 14529 it.Advance()) { 14530 if (it.is_statement()) { 14531 int p = it.source_position().ScriptOffset(); 14532 if (statement_position < p && p <= position) { 14533 statement_position = p; 14534 } 14535 } 14536 } 14537 return statement_position; 14538 } 14539 14540 void JSFunction::ClearTypeFeedbackInfo() { 14541 if (feedback_cell()->value()->IsFeedbackVector()) { 14542 FeedbackVector* vector = feedback_vector(); 14543 Isolate* isolate = GetIsolate(); 14544 if (vector->ClearSlots(isolate)) { 14545 IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(), this, 14546 "ClearTypeFeedbackInfo"); 14547 } 14548 } 14549 } 14550 14551 void Code::PrintDeoptLocation(FILE* out, const char* str, Address pc) { 14552 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc); 14553 class SourcePosition pos = info.position; 14554 if (info.deopt_reason != DeoptimizeReason::kUnknown || pos.IsKnown()) { 14555 PrintF(out, "%s", str); 14556 OFStream outstr(out); 14557 pos.Print(outstr, this); 14558 PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason)); 14559 } 14560 } 14561 14562 14563 bool Code::CanDeoptAt(Address pc) { 14564 DeoptimizationData* deopt_data = 14565 DeoptimizationData::cast(deoptimization_data()); 14566 Address code_start_address = InstructionStart(); 14567 for (int i = 0; i < deopt_data->DeoptCount(); i++) { 14568 if (deopt_data->Pc(i)->value() == -1) continue; 14569 Address address = code_start_address + deopt_data->Pc(i)->value(); 14570 if (address == pc && deopt_data->BytecodeOffset(i) != BailoutId::None()) { 14571 return true; 14572 } 14573 } 14574 return false; 14575 } 14576 14577 14578 // Identify kind of code. 14579 const char* Code::Kind2String(Kind kind) { 14580 switch (kind) { 14581 #define CASE(name) case name: return #name; 14582 CODE_KIND_LIST(CASE) 14583 #undef CASE 14584 case NUMBER_OF_KINDS: break; 14585 } 14586 UNREACHABLE(); 14587 } 14588 14589 // Identify kind of code. 14590 const char* AbstractCode::Kind2String(Kind kind) { 14591 if (kind < AbstractCode::INTERPRETED_FUNCTION) 14592 return Code::Kind2String((Code::Kind)kind); 14593 if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION"; 14594 UNREACHABLE(); 14595 } 14596 14597 bool Code::IsIsolateIndependent(Isolate* isolate) { 14598 constexpr int all_real_modes_mask = 14599 (1 << (RelocInfo::LAST_REAL_RELOC_MODE + 1)) - 1; 14600 constexpr int mode_mask = all_real_modes_mask & 14601 ~RelocInfo::ModeMask(RelocInfo::COMMENT) & 14602 ~RelocInfo::ModeMask(RelocInfo::CONST_POOL) & 14603 ~RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) & 14604 ~RelocInfo::ModeMask(RelocInfo::VENEER_POOL); 14605 STATIC_ASSERT(RelocInfo::LAST_REAL_RELOC_MODE == RelocInfo::VENEER_POOL); 14606 STATIC_ASSERT(RelocInfo::ModeMask(RelocInfo::COMMENT) == 14607 (1 << RelocInfo::COMMENT)); 14608 STATIC_ASSERT(mode_mask == 14609 (RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | 14610 RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) | 14611 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 14612 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | 14613 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | 14614 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) | 14615 RelocInfo::ModeMask(RelocInfo::JS_TO_WASM_CALL) | 14616 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | 14617 RelocInfo::ModeMask(RelocInfo::WASM_CALL) | 14618 RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL))); 14619 14620 bool is_process_independent = true; 14621 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { 14622 #if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64) || \ 14623 defined(V8_TARGET_ARCH_ARM) 14624 // On X64, ARM, ARM64 we emit relative builtin-to-builtin jumps for isolate 14625 // independent builtins in the snapshot. They are later rewritten as 14626 // pc-relative jumps to the off-heap instruction stream and are thus 14627 // process-independent. 14628 // See also: FinalizeEmbeddedCodeTargets. 14629 if (RelocInfo::IsCodeTargetMode(it.rinfo()->rmode())) { 14630 Address target_address = it.rinfo()->target_address(); 14631 if (InstructionStream::PcIsOffHeap(isolate, target_address)) continue; 14632 14633 Code* target = Code::GetCodeFromTargetAddress(target_address); 14634 CHECK(target->IsCode()); 14635 if (Builtins::IsIsolateIndependentBuiltin(target)) continue; 14636 } 14637 #endif 14638 is_process_independent = false; 14639 } 14640 14641 return is_process_independent; 14642 } 14643 14644 bool Code::Inlines(SharedFunctionInfo* sfi) { 14645 // We can only check for inlining for optimized code. 14646 DCHECK(is_optimized_code()); 14647 DisallowHeapAllocation no_gc; 14648 DeoptimizationData* const data = 14649 DeoptimizationData::cast(deoptimization_data()); 14650 if (data->length() == 0) return false; 14651 if (data->SharedFunctionInfo() == sfi) return true; 14652 FixedArray* const literals = data->LiteralArray(); 14653 int const inlined_count = data->InlinedFunctionCount()->value(); 14654 for (int i = 0; i < inlined_count; ++i) { 14655 if (SharedFunctionInfo::cast(literals->get(i)) == sfi) return true; 14656 } 14657 return false; 14658 } 14659 14660 Code::OptimizedCodeIterator::OptimizedCodeIterator(Isolate* isolate) { 14661 isolate_ = isolate; 14662 Object* list = isolate->heap()->native_contexts_list(); 14663 next_context_ = list->IsUndefined(isolate_) ? nullptr : Context::cast(list); 14664 current_code_ = nullptr; 14665 } 14666 14667 Code* Code::OptimizedCodeIterator::Next() { 14668 do { 14669 Object* next; 14670 if (current_code_ != nullptr) { 14671 // Get next code in the linked list. 14672 next = Code::cast(current_code_)->next_code_link(); 14673 } else if (next_context_ != nullptr) { 14674 // Linked list of code exhausted. Get list of next context. 14675 next = next_context_->OptimizedCodeListHead(); 14676 Object* next_context = next_context_->next_context_link(); 14677 next_context_ = next_context->IsUndefined(isolate_) 14678 ? nullptr 14679 : Context::cast(next_context); 14680 } else { 14681 // Exhausted contexts. 14682 return nullptr; 14683 } 14684 current_code_ = next->IsUndefined(isolate_) ? nullptr : Code::cast(next); 14685 } while (current_code_ == nullptr); 14686 Code* code = Code::cast(current_code_); 14687 DCHECK_EQ(Code::OPTIMIZED_FUNCTION, code->kind()); 14688 return code; 14689 } 14690 14691 #ifdef ENABLE_DISASSEMBLER 14692 14693 namespace { 14694 void print_pc(std::ostream& os, int pc) { 14695 if (pc == -1) { 14696 os << "NA"; 14697 } else { 14698 os << std::hex << pc << std::dec; 14699 } 14700 } 14701 } // anonymous namespace 14702 14703 void DeoptimizationData::DeoptimizationDataPrint(std::ostream& os) { // NOLINT 14704 if (length() == 0) { 14705 os << "Deoptimization Input Data invalidated by lazy deoptimization\n"; 14706 return; 14707 } 14708 14709 disasm::NameConverter converter; 14710 int const inlined_function_count = InlinedFunctionCount()->value(); 14711 os << "Inlined functions (count = " << inlined_function_count << ")\n"; 14712 for (int id = 0; id < inlined_function_count; ++id) { 14713 Object* info = LiteralArray()->get(id); 14714 os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n"; 14715 } 14716 os << "\n"; 14717 int deopt_count = DeoptCount(); 14718 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n"; 14719 if (0 != deopt_count) { 14720 os << " index bytecode-offset pc"; 14721 if (FLAG_print_code_verbose) os << " commands"; 14722 os << "\n"; 14723 } 14724 for (int i = 0; i < deopt_count; i++) { 14725 os << std::setw(6) << i << " " << std::setw(15) 14726 << BytecodeOffset(i).ToInt() << " " << std::setw(4); 14727 print_pc(os, Pc(i)->value()); 14728 os << std::setw(2); 14729 14730 if (!FLAG_print_code_verbose) { 14731 os << "\n"; 14732 continue; 14733 } 14734 14735 // Print details of the frame translation. 14736 int translation_index = TranslationIndex(i)->value(); 14737 TranslationIterator iterator(TranslationByteArray(), translation_index); 14738 Translation::Opcode opcode = 14739 static_cast<Translation::Opcode>(iterator.Next()); 14740 DCHECK(Translation::BEGIN == opcode); 14741 int frame_count = iterator.Next(); 14742 int jsframe_count = iterator.Next(); 14743 int update_feedback_count = iterator.Next(); 14744 os << " " << Translation::StringFor(opcode) 14745 << " {frame count=" << frame_count 14746 << ", js frame count=" << jsframe_count 14747 << ", update_feedback_count=" << update_feedback_count << "}\n"; 14748 14749 while (iterator.HasNext() && 14750 Translation::BEGIN != 14751 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) { 14752 os << std::setw(31) << " " << Translation::StringFor(opcode) << " "; 14753 14754 switch (opcode) { 14755 case Translation::BEGIN: 14756 UNREACHABLE(); 14757 break; 14758 14759 case Translation::INTERPRETED_FRAME: { 14760 int bytecode_offset = iterator.Next(); 14761 int shared_info_id = iterator.Next(); 14762 unsigned height = iterator.Next(); 14763 Object* shared_info = LiteralArray()->get(shared_info_id); 14764 os << "{bytecode_offset=" << bytecode_offset << ", function=" 14765 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14766 << ", height=" << height << "}"; 14767 break; 14768 } 14769 14770 case Translation::CONSTRUCT_STUB_FRAME: { 14771 int bailout_id = iterator.Next(); 14772 int shared_info_id = iterator.Next(); 14773 Object* shared_info = LiteralArray()->get(shared_info_id); 14774 unsigned height = iterator.Next(); 14775 os << "{bailout_id=" << bailout_id << ", function=" 14776 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14777 << ", height=" << height << "}"; 14778 break; 14779 } 14780 14781 case Translation::BUILTIN_CONTINUATION_FRAME: 14782 case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME: 14783 case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: { 14784 int bailout_id = iterator.Next(); 14785 int shared_info_id = iterator.Next(); 14786 Object* shared_info = LiteralArray()->get(shared_info_id); 14787 unsigned height = iterator.Next(); 14788 os << "{bailout_id=" << bailout_id << ", function=" 14789 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14790 << ", height=" << height << "}"; 14791 break; 14792 } 14793 14794 case Translation::ARGUMENTS_ADAPTOR_FRAME: { 14795 int shared_info_id = iterator.Next(); 14796 Object* shared_info = LiteralArray()->get(shared_info_id); 14797 unsigned height = iterator.Next(); 14798 os << "{function=" 14799 << Brief(SharedFunctionInfo::cast(shared_info)->DebugName()) 14800 << ", height=" << height << "}"; 14801 break; 14802 } 14803 14804 case Translation::REGISTER: { 14805 int reg_code = iterator.Next(); 14806 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}"; 14807 break; 14808 } 14809 14810 case Translation::INT32_REGISTER: { 14811 int reg_code = iterator.Next(); 14812 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}"; 14813 break; 14814 } 14815 14816 case Translation::UINT32_REGISTER: { 14817 int reg_code = iterator.Next(); 14818 os << "{input=" << converter.NameOfCPURegister(reg_code) 14819 << " (unsigned)}"; 14820 break; 14821 } 14822 14823 case Translation::BOOL_REGISTER: { 14824 int reg_code = iterator.Next(); 14825 os << "{input=" << converter.NameOfCPURegister(reg_code) 14826 << " (bool)}"; 14827 break; 14828 } 14829 14830 case Translation::FLOAT_REGISTER: { 14831 int reg_code = iterator.Next(); 14832 os << "{input=" 14833 << RegisterConfiguration::Default()->GetFloatRegisterName(reg_code) 14834 << "}"; 14835 break; 14836 } 14837 14838 case Translation::DOUBLE_REGISTER: { 14839 int reg_code = iterator.Next(); 14840 os << "{input=" 14841 << RegisterConfiguration::Default()->GetDoubleRegisterName( 14842 reg_code) 14843 << "}"; 14844 break; 14845 } 14846 14847 case Translation::STACK_SLOT: { 14848 int input_slot_index = iterator.Next(); 14849 os << "{input=" << input_slot_index << "}"; 14850 break; 14851 } 14852 14853 case Translation::INT32_STACK_SLOT: { 14854 int input_slot_index = iterator.Next(); 14855 os << "{input=" << input_slot_index << "}"; 14856 break; 14857 } 14858 14859 case Translation::UINT32_STACK_SLOT: { 14860 int input_slot_index = iterator.Next(); 14861 os << "{input=" << input_slot_index << " (unsigned)}"; 14862 break; 14863 } 14864 14865 case Translation::BOOL_STACK_SLOT: { 14866 int input_slot_index = iterator.Next(); 14867 os << "{input=" << input_slot_index << " (bool)}"; 14868 break; 14869 } 14870 14871 case Translation::FLOAT_STACK_SLOT: 14872 case Translation::DOUBLE_STACK_SLOT: { 14873 int input_slot_index = iterator.Next(); 14874 os << "{input=" << input_slot_index << "}"; 14875 break; 14876 } 14877 14878 case Translation::LITERAL: { 14879 int literal_index = iterator.Next(); 14880 Object* literal_value = LiteralArray()->get(literal_index); 14881 os << "{literal_id=" << literal_index << " (" << Brief(literal_value) 14882 << ")}"; 14883 break; 14884 } 14885 14886 case Translation::DUPLICATED_OBJECT: { 14887 int object_index = iterator.Next(); 14888 os << "{object_index=" << object_index << "}"; 14889 break; 14890 } 14891 14892 case Translation::ARGUMENTS_ELEMENTS: 14893 case Translation::ARGUMENTS_LENGTH: { 14894 CreateArgumentsType arguments_type = 14895 static_cast<CreateArgumentsType>(iterator.Next()); 14896 os << "{arguments_type=" << arguments_type << "}"; 14897 break; 14898 } 14899 14900 case Translation::CAPTURED_OBJECT: { 14901 int args_length = iterator.Next(); 14902 os << "{length=" << args_length << "}"; 14903 break; 14904 } 14905 14906 case Translation::UPDATE_FEEDBACK: { 14907 int literal_index = iterator.Next(); 14908 FeedbackSlot slot(iterator.Next()); 14909 os << "{feedback={vector_index=" << literal_index << ", slot=" << slot 14910 << "}}"; 14911 break; 14912 } 14913 } 14914 os << "\n"; 14915 } 14916 } 14917 } 14918 14919 const char* Code::GetName(Isolate* isolate) const { 14920 if (is_stub()) { 14921 return CodeStub::MajorName(CodeStub::GetMajorKey(this)); 14922 } else if (kind() == BYTECODE_HANDLER) { 14923 return isolate->interpreter()->LookupNameOfBytecodeHandler(this); 14924 } else { 14925 // There are some handlers and ICs that we can also find names for with 14926 // Builtins::Lookup. 14927 return isolate->builtins()->Lookup(raw_instruction_start()); 14928 } 14929 } 14930 14931 void Code::PrintBuiltinCode(Isolate* isolate, const char* name) { 14932 DCHECK(FLAG_print_builtin_code); 14933 if (name == nullptr) { 14934 name = GetName(isolate); 14935 } 14936 if (name != nullptr && 14937 PassesFilter(CStrVector(name), 14938 CStrVector(FLAG_print_builtin_code_filter))) { 14939 CodeTracer::Scope trace_scope(isolate->GetCodeTracer()); 14940 OFStream os(trace_scope.file()); 14941 Disassemble(name, os); 14942 os << "\n"; 14943 } 14944 } 14945 14946 namespace { 14947 14948 inline void DisassembleCodeRange(Isolate* isolate, std::ostream& os, Code* code, 14949 Address begin, size_t size, 14950 Address current_pc) { 14951 Address end = begin + size; 14952 // TODO(mstarzinger): Refactor CodeReference to avoid the 14953 // unhandlified->handlified transition. 14954 AllowHandleAllocation allow_handles; 14955 DisallowHeapAllocation no_gc; 14956 HandleScope handle_scope(isolate); 14957 Disassembler::Decode(isolate, &os, reinterpret_cast<byte*>(begin), 14958 reinterpret_cast<byte*>(end), 14959 CodeReference(handle(code, isolate)), current_pc); 14960 } 14961 14962 } // namespace 14963 14964 void Code::Disassemble(const char* name, std::ostream& os, Address current_pc) { 14965 Isolate* isolate = GetIsolate(); 14966 os << "kind = " << Kind2String(kind()) << "\n"; 14967 if (is_stub()) { 14968 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this)); 14969 os << "major_key = " << (n == nullptr ? "null" : n) << "\n"; 14970 os << "minor_key = " << CodeStub::MinorKeyFromKey(this->stub_key()) << "\n"; 14971 } 14972 if (name == nullptr) { 14973 name = GetName(isolate); 14974 } 14975 if ((name != nullptr) && (name[0] != '\0')) { 14976 os << "name = " << name << "\n"; 14977 } 14978 if (kind() == OPTIMIZED_FUNCTION) { 14979 os << "stack_slots = " << stack_slots() << "\n"; 14980 } 14981 os << "compiler = " << (is_turbofanned() ? "turbofan" : "unknown") << "\n"; 14982 os << "address = " << static_cast<const void*>(this) << "\n\n"; 14983 14984 if (is_off_heap_trampoline()) { 14985 int trampoline_size = raw_instruction_size(); 14986 os << "Trampoline (size = " << trampoline_size << ")\n"; 14987 DisassembleCodeRange(isolate, os, this, raw_instruction_start(), 14988 trampoline_size, current_pc); 14989 os << "\n"; 14990 } 14991 14992 { 14993 int size = InstructionSize(); 14994 int safepoint_offset = 14995 has_safepoint_info() ? safepoint_table_offset() : size; 14996 int constant_pool_offset = this->constant_pool_offset(); 14997 int handler_offset = handler_table_offset() ? handler_table_offset() : size; 14998 14999 // Stop before reaching any embedded tables 15000 int code_size = 15001 Min(handler_offset, Min(safepoint_offset, constant_pool_offset)); 15002 os << "Instructions (size = " << code_size << ")\n"; 15003 DisassembleCodeRange(isolate, os, this, InstructionStart(), code_size, 15004 current_pc); 15005 15006 if (constant_pool_offset < size) { 15007 int constant_pool_size = safepoint_offset - constant_pool_offset; 15008 DCHECK_EQ(constant_pool_size & kPointerAlignmentMask, 0); 15009 os << "\nConstant Pool (size = " << constant_pool_size << ")\n"; 15010 Vector<char> buf = Vector<char>::New(50); 15011 intptr_t* ptr = reinterpret_cast<intptr_t*>(InstructionStart() + 15012 constant_pool_offset); 15013 for (int i = 0; i < constant_pool_size; i += kPointerSize, ptr++) { 15014 SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr); 15015 os << static_cast<const void*>(ptr) << " " << buf.start() << "\n"; 15016 } 15017 } 15018 } 15019 os << "\n"; 15020 15021 SourcePositionTableIterator it(SourcePositionTable()); 15022 if (!it.done()) { 15023 os << "Source positions:\n pc offset position\n"; 15024 for (; !it.done(); it.Advance()) { 15025 os << std::setw(10) << std::hex << it.code_offset() << std::dec 15026 << std::setw(10) << it.source_position().ScriptOffset() 15027 << (it.is_statement() ? " statement" : "") << "\n"; 15028 } 15029 os << "\n"; 15030 } 15031 15032 if (kind() == OPTIMIZED_FUNCTION) { 15033 DeoptimizationData* data = 15034 DeoptimizationData::cast(this->deoptimization_data()); 15035 data->DeoptimizationDataPrint(os); 15036 } 15037 os << "\n"; 15038 15039 if (has_safepoint_info()) { 15040 SafepointTable table(this); 15041 os << "Safepoints (size = " << table.size() << ")\n"; 15042 for (unsigned i = 0; i < table.length(); i++) { 15043 unsigned pc_offset = table.GetPcOffset(i); 15044 os << reinterpret_cast<const void*>(InstructionStart() + pc_offset) 15045 << " "; 15046 os << std::setw(6) << std::hex << pc_offset << " " << std::setw(4); 15047 int trampoline_pc = table.GetTrampolinePcOffset(i); 15048 print_pc(os, trampoline_pc); 15049 os << std::dec << " "; 15050 table.PrintEntry(i, os); 15051 os << " (sp -> fp) "; 15052 SafepointEntry entry = table.GetEntry(i); 15053 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) { 15054 os << std::setw(6) << entry.deoptimization_index(); 15055 } else { 15056 os << "<none>"; 15057 } 15058 if (entry.argument_count() > 0) { 15059 os << " argc: " << entry.argument_count(); 15060 } 15061 os << "\n"; 15062 } 15063 os << "\n"; 15064 } 15065 15066 if (handler_table_offset() > 0) { 15067 HandlerTable table(this); 15068 os << "Handler Table (size = " << table.NumberOfReturnEntries() << ")\n"; 15069 if (kind() == OPTIMIZED_FUNCTION) { 15070 table.HandlerTableReturnPrint(os); 15071 } 15072 os << "\n"; 15073 } 15074 15075 os << "RelocInfo (size = " << relocation_size() << ")\n"; 15076 for (RelocIterator it(this); !it.done(); it.next()) { 15077 it.rinfo()->Print(isolate, os); 15078 } 15079 os << "\n"; 15080 15081 if (has_unwinding_info()) { 15082 os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n"; 15083 EhFrameDisassembler eh_frame_disassembler( 15084 reinterpret_cast<byte*>(unwinding_info_start()), 15085 reinterpret_cast<byte*>(unwinding_info_end())); 15086 eh_frame_disassembler.DisassembleToStream(os); 15087 os << "\n"; 15088 } 15089 } 15090 #endif // ENABLE_DISASSEMBLER 15091 15092 void BytecodeArray::Disassemble(std::ostream& os) { 15093 DisallowHeapAllocation no_gc; 15094 15095 os << "Parameter count " << parameter_count() << "\n"; 15096 os << "Frame size " << frame_size() << "\n"; 15097 15098 Address base_address = GetFirstBytecodeAddress(); 15099 SourcePositionTableIterator source_positions(SourcePositionTable()); 15100 15101 // Storage for backing the handle passed to the iterator. This handle won't be 15102 // updated by the gc, but that's ok because we've disallowed GCs anyway. 15103 BytecodeArray* handle_storage = this; 15104 Handle<BytecodeArray> handle(&handle_storage); 15105 interpreter::BytecodeArrayIterator iterator(handle); 15106 while (!iterator.done()) { 15107 if (!source_positions.done() && 15108 iterator.current_offset() == source_positions.code_offset()) { 15109 os << std::setw(5) << source_positions.source_position().ScriptOffset(); 15110 os << (source_positions.is_statement() ? " S> " : " E> "); 15111 source_positions.Advance(); 15112 } else { 15113 os << " "; 15114 } 15115 Address current_address = base_address + iterator.current_offset(); 15116 os << reinterpret_cast<const void*>(current_address) << " @ " 15117 << std::setw(4) << iterator.current_offset() << " : "; 15118 interpreter::BytecodeDecoder::Decode( 15119 os, reinterpret_cast<byte*>(current_address), parameter_count()); 15120 if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) { 15121 Address jump_target = base_address + iterator.GetJumpTargetOffset(); 15122 os << " (" << reinterpret_cast<void*>(jump_target) << " @ " 15123 << iterator.GetJumpTargetOffset() << ")"; 15124 } 15125 if (interpreter::Bytecodes::IsSwitch(iterator.current_bytecode())) { 15126 os << " {"; 15127 bool first_entry = true; 15128 for (const auto& entry : iterator.GetJumpTableTargetOffsets()) { 15129 if (first_entry) { 15130 first_entry = false; 15131 } else { 15132 os << ","; 15133 } 15134 os << " " << entry.case_value << ": @" << entry.target_offset; 15135 } 15136 os << " }"; 15137 } 15138 os << std::endl; 15139 iterator.Advance(); 15140 } 15141 15142 os << "Constant pool (size = " << constant_pool()->length() << ")\n"; 15143 #ifdef OBJECT_PRINT 15144 if (constant_pool()->length() > 0) { 15145 constant_pool()->Print(); 15146 } 15147 #endif 15148 15149 os << "Handler Table (size = " << handler_table()->length() << ")\n"; 15150 #ifdef ENABLE_DISASSEMBLER 15151 if (handler_table()->length() > 0) { 15152 HandlerTable table(this); 15153 table.HandlerTableRangePrint(os); 15154 } 15155 #endif 15156 } 15157 15158 void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) { 15159 BytecodeArray* from = this; 15160 DCHECK_EQ(from->length(), to->length()); 15161 CopyBytes(reinterpret_cast<byte*>(to->GetFirstBytecodeAddress()), 15162 reinterpret_cast<byte*>(from->GetFirstBytecodeAddress()), 15163 from->length()); 15164 } 15165 15166 void BytecodeArray::MakeOlder() { 15167 // BytecodeArray is aged in concurrent marker. 15168 // The word must be completely within the byte code array. 15169 Address age_addr = address() + kBytecodeAgeOffset; 15170 DCHECK_LE((age_addr & ~kPointerAlignmentMask) + kPointerSize, 15171 address() + Size()); 15172 Age age = bytecode_age(); 15173 if (age < kLastBytecodeAge) { 15174 base::AsAtomic8::Release_CompareAndSwap(reinterpret_cast<byte*>(age_addr), 15175 age, age + 1); 15176 } 15177 15178 DCHECK_GE(bytecode_age(), kFirstBytecodeAge); 15179 DCHECK_LE(bytecode_age(), kLastBytecodeAge); 15180 } 15181 15182 bool BytecodeArray::IsOld() const { 15183 return bytecode_age() >= kIsOldBytecodeAge; 15184 } 15185 15186 // static 15187 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { 15188 DCHECK_GE(capacity, 0); 15189 array->GetIsolate()->factory()->NewJSArrayStorage( 15190 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 15191 } 15192 15193 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) { 15194 // We should never end in here with a pixel or external array. 15195 DCHECK(array->AllowsSetLength()); 15196 if (array->SetLengthWouldNormalize(new_length)) { 15197 JSObject::NormalizeElements(array); 15198 } 15199 array->GetElementsAccessor()->SetLength(array, new_length); 15200 } 15201 15202 DependentCode* DependentCode::GetDependentCode(Handle<HeapObject> object) { 15203 if (object->IsMap()) { 15204 return Handle<Map>::cast(object)->dependent_code(); 15205 } else if (object->IsPropertyCell()) { 15206 return Handle<PropertyCell>::cast(object)->dependent_code(); 15207 } else if (object->IsAllocationSite()) { 15208 return Handle<AllocationSite>::cast(object)->dependent_code(); 15209 } 15210 UNREACHABLE(); 15211 } 15212 15213 void DependentCode::SetDependentCode(Handle<HeapObject> object, 15214 Handle<DependentCode> dep) { 15215 if (object->IsMap()) { 15216 Handle<Map>::cast(object)->set_dependent_code(*dep); 15217 } else if (object->IsPropertyCell()) { 15218 Handle<PropertyCell>::cast(object)->set_dependent_code(*dep); 15219 } else if (object->IsAllocationSite()) { 15220 Handle<AllocationSite>::cast(object)->set_dependent_code(*dep); 15221 } else { 15222 UNREACHABLE(); 15223 } 15224 } 15225 15226 void DependentCode::InstallDependency(Isolate* isolate, MaybeObjectHandle code, 15227 Handle<HeapObject> object, 15228 DependencyGroup group) { 15229 Handle<DependentCode> old_deps(DependentCode::GetDependentCode(object), 15230 isolate); 15231 Handle<DependentCode> new_deps = 15232 InsertWeakCode(isolate, old_deps, group, code); 15233 // Update the list head if necessary. 15234 if (!new_deps.is_identical_to(old_deps)) 15235 DependentCode::SetDependentCode(object, new_deps); 15236 } 15237 15238 Handle<DependentCode> DependentCode::InsertWeakCode( 15239 Isolate* isolate, Handle<DependentCode> entries, DependencyGroup group, 15240 MaybeObjectHandle code) { 15241 if (entries->length() == 0 || entries->group() > group) { 15242 // There is no such group. 15243 return DependentCode::New(isolate, group, code, entries); 15244 } 15245 if (entries->group() < group) { 15246 // The group comes later in the list. 15247 Handle<DependentCode> old_next(entries->next_link(), isolate); 15248 Handle<DependentCode> new_next = 15249 InsertWeakCode(isolate, old_next, group, code); 15250 if (!old_next.is_identical_to(new_next)) { 15251 entries->set_next_link(*new_next); 15252 } 15253 return entries; 15254 } 15255 DCHECK_EQ(group, entries->group()); 15256 int count = entries->count(); 15257 // Check for existing entry to avoid duplicates. 15258 for (int i = 0; i < count; i++) { 15259 if (entries->object_at(i) == *code) return entries; 15260 } 15261 if (entries->length() < kCodesStartIndex + count + 1) { 15262 entries = EnsureSpace(isolate, entries); 15263 // Count could have changed, reload it. 15264 count = entries->count(); 15265 } 15266 entries->set_object_at(count, *code); 15267 entries->set_count(count + 1); 15268 return entries; 15269 } 15270 15271 Handle<DependentCode> DependentCode::New(Isolate* isolate, 15272 DependencyGroup group, 15273 MaybeObjectHandle object, 15274 Handle<DependentCode> next) { 15275 Handle<DependentCode> result = Handle<DependentCode>::cast( 15276 isolate->factory()->NewWeakFixedArray(kCodesStartIndex + 1, TENURED)); 15277 result->set_next_link(*next); 15278 result->set_flags(GroupField::encode(group) | CountField::encode(1)); 15279 result->set_object_at(0, *object); 15280 return result; 15281 } 15282 15283 Handle<DependentCode> DependentCode::EnsureSpace( 15284 Isolate* isolate, Handle<DependentCode> entries) { 15285 if (entries->Compact()) return entries; 15286 int capacity = kCodesStartIndex + DependentCode::Grow(entries->count()); 15287 int grow_by = capacity - entries->length(); 15288 return Handle<DependentCode>::cast( 15289 isolate->factory()->CopyWeakFixedArrayAndGrow(entries, grow_by, TENURED)); 15290 } 15291 15292 15293 bool DependentCode::Compact() { 15294 int old_count = count(); 15295 int new_count = 0; 15296 for (int i = 0; i < old_count; i++) { 15297 MaybeObject* obj = object_at(i); 15298 if (!obj->IsClearedWeakHeapObject()) { 15299 if (i != new_count) { 15300 copy(i, new_count); 15301 } 15302 new_count++; 15303 } 15304 } 15305 set_count(new_count); 15306 for (int i = new_count; i < old_count; i++) { 15307 clear_at(i); 15308 } 15309 return new_count < old_count; 15310 } 15311 15312 bool DependentCode::Contains(DependencyGroup group, MaybeObject* code) { 15313 if (this->length() == 0 || this->group() > group) { 15314 // There is no such group. 15315 return false; 15316 } 15317 if (this->group() < group) { 15318 // The group comes later in the list. 15319 return next_link()->Contains(group, code); 15320 } 15321 DCHECK_EQ(group, this->group()); 15322 int count = this->count(); 15323 for (int i = 0; i < count; i++) { 15324 if (object_at(i) == code) return true; 15325 } 15326 return false; 15327 } 15328 15329 15330 bool DependentCode::IsEmpty(DependencyGroup group) { 15331 if (this->length() == 0 || this->group() > group) { 15332 // There is no such group. 15333 return true; 15334 } 15335 if (this->group() < group) { 15336 // The group comes later in the list. 15337 return next_link()->IsEmpty(group); 15338 } 15339 DCHECK_EQ(group, this->group()); 15340 return count() == 0; 15341 } 15342 15343 15344 bool DependentCode::MarkCodeForDeoptimization( 15345 Isolate* isolate, 15346 DependentCode::DependencyGroup group) { 15347 if (this->length() == 0 || this->group() > group) { 15348 // There is no such group. 15349 return false; 15350 } 15351 if (this->group() < group) { 15352 // The group comes later in the list. 15353 return next_link()->MarkCodeForDeoptimization(isolate, group); 15354 } 15355 DCHECK_EQ(group, this->group()); 15356 DisallowHeapAllocation no_allocation_scope; 15357 // Mark all the code that needs to be deoptimized. 15358 bool marked = false; 15359 int count = this->count(); 15360 for (int i = 0; i < count; i++) { 15361 MaybeObject* obj = object_at(i); 15362 if (obj->IsClearedWeakHeapObject()) continue; 15363 Code* code = Code::cast(obj->ToWeakHeapObject()); 15364 if (!code->marked_for_deoptimization()) { 15365 code->SetMarkedForDeoptimization(DependencyGroupName(group)); 15366 marked = true; 15367 } 15368 } 15369 for (int i = 0; i < count; i++) { 15370 clear_at(i); 15371 } 15372 set_count(0); 15373 return marked; 15374 } 15375 15376 15377 void DependentCode::DeoptimizeDependentCodeGroup( 15378 Isolate* isolate, 15379 DependentCode::DependencyGroup group) { 15380 DisallowHeapAllocation no_allocation_scope; 15381 bool marked = MarkCodeForDeoptimization(isolate, group); 15382 if (marked) { 15383 DCHECK(AllowCodeDependencyChange::IsAllowed()); 15384 Deoptimizer::DeoptimizeMarkedCode(isolate); 15385 } 15386 } 15387 15388 void Code::SetMarkedForDeoptimization(const char* reason) { 15389 set_marked_for_deoptimization(true); 15390 if (FLAG_trace_deopt && 15391 (deoptimization_data() != GetReadOnlyRoots().empty_fixed_array())) { 15392 DeoptimizationData* deopt_data = 15393 DeoptimizationData::cast(deoptimization_data()); 15394 CodeTracer::Scope scope(GetHeap()->isolate()->GetCodeTracer()); 15395 PrintF(scope.file(), 15396 "[marking dependent code " V8PRIxPTR_FMT 15397 " (opt #%d) for deoptimization, reason: %s]\n", 15398 reinterpret_cast<intptr_t>(this), 15399 deopt_data->OptimizationId()->value(), reason); 15400 } 15401 } 15402 15403 15404 const char* DependentCode::DependencyGroupName(DependencyGroup group) { 15405 switch (group) { 15406 case kTransitionGroup: 15407 return "transition"; 15408 case kPrototypeCheckGroup: 15409 return "prototype-check"; 15410 case kPropertyCellChangedGroup: 15411 return "property-cell-changed"; 15412 case kFieldOwnerGroup: 15413 return "field-owner"; 15414 case kInitialMapChangedGroup: 15415 return "initial-map-changed"; 15416 case kAllocationSiteTenuringChangedGroup: 15417 return "allocation-site-tenuring-changed"; 15418 case kAllocationSiteTransitionChangedGroup: 15419 return "allocation-site-transition-changed"; 15420 } 15421 UNREACHABLE(); 15422 } 15423 15424 Handle<Map> Map::TransitionToPrototype(Isolate* isolate, Handle<Map> map, 15425 Handle<Object> prototype) { 15426 Handle<Map> new_map = 15427 TransitionsAccessor(isolate, map).GetPrototypeTransition(prototype); 15428 if (new_map.is_null()) { 15429 new_map = Copy(isolate, map, "TransitionToPrototype"); 15430 TransitionsAccessor(isolate, map) 15431 .PutPrototypeTransition(prototype, new_map); 15432 Map::SetPrototype(isolate, new_map, prototype); 15433 } 15434 return new_map; 15435 } 15436 15437 15438 Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object, 15439 Handle<Object> value, bool from_javascript, 15440 ShouldThrow should_throw) { 15441 if (object->IsJSProxy()) { 15442 return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value, 15443 from_javascript, should_throw); 15444 } 15445 return JSObject::SetPrototype(Handle<JSObject>::cast(object), value, 15446 from_javascript, should_throw); 15447 } 15448 15449 15450 // ES6: 9.5.2 [[SetPrototypeOf]] (V) 15451 // static 15452 Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value, 15453 bool from_javascript, 15454 ShouldThrow should_throw) { 15455 Isolate* isolate = proxy->GetIsolate(); 15456 STACK_CHECK(isolate, Nothing<bool>()); 15457 Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string(); 15458 // 1. Assert: Either Type(V) is Object or Type(V) is Null. 15459 DCHECK(value->IsJSReceiver() || value->IsNull(isolate)); 15460 // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. 15461 Handle<Object> handler(proxy->handler(), isolate); 15462 // 3. If handler is null, throw a TypeError exception. 15463 // 4. Assert: Type(handler) is Object. 15464 if (proxy->IsRevoked()) { 15465 isolate->Throw(*isolate->factory()->NewTypeError( 15466 MessageTemplate::kProxyRevoked, trap_name)); 15467 return Nothing<bool>(); 15468 } 15469 // 5. Let target be the value of the [[ProxyTarget]] internal slot. 15470 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); 15471 // 6. Let trap be ? GetMethod(handler, "getPrototypeOf"). 15472 Handle<Object> trap; 15473 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 15474 isolate, trap, 15475 Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), 15476 Nothing<bool>()); 15477 // 7. If trap is undefined, then return target.[[SetPrototypeOf]](). 15478 if (trap->IsUndefined(isolate)) { 15479 return JSReceiver::SetPrototype(target, value, from_javascript, 15480 should_throw); 15481 } 15482 // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, target, V)). 15483 Handle<Object> argv[] = {target, value}; 15484 Handle<Object> trap_result; 15485 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 15486 isolate, trap_result, 15487 Execution::Call(isolate, trap, handler, arraysize(argv), argv), 15488 Nothing<bool>()); 15489 bool bool_trap_result = trap_result->BooleanValue(isolate); 15490 // 9. If booleanTrapResult is false, return false. 15491 if (!bool_trap_result) { 15492 RETURN_FAILURE( 15493 isolate, should_throw, 15494 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 15495 } 15496 // 10. Let extensibleTarget be ? IsExtensible(target). 15497 Maybe<bool> is_extensible = JSReceiver::IsExtensible(target); 15498 if (is_extensible.IsNothing()) return Nothing<bool>(); 15499 // 11. If extensibleTarget is true, return true. 15500 if (is_extensible.FromJust()) { 15501 if (bool_trap_result) return Just(true); 15502 RETURN_FAILURE( 15503 isolate, should_throw, 15504 NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name)); 15505 } 15506 // 12. Let targetProto be ? target.[[GetPrototypeOf]](). 15507 Handle<Object> target_proto; 15508 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto, 15509 JSReceiver::GetPrototype(isolate, target), 15510 Nothing<bool>()); 15511 // 13. If SameValue(V, targetProto) is false, throw a TypeError exception. 15512 if (bool_trap_result && !value->SameValue(*target_proto)) { 15513 isolate->Throw(*isolate->factory()->NewTypeError( 15514 MessageTemplate::kProxySetPrototypeOfNonExtensible)); 15515 return Nothing<bool>(); 15516 } 15517 // 14. Return true. 15518 return Just(true); 15519 } 15520 15521 15522 Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object, 15523 Handle<Object> value, bool from_javascript, 15524 ShouldThrow should_throw) { 15525 Isolate* isolate = object->GetIsolate(); 15526 15527 #ifdef DEBUG 15528 int size = object->Size(); 15529 #endif 15530 15531 if (from_javascript) { 15532 if (object->IsAccessCheckNeeded() && 15533 !isolate->MayAccess(handle(isolate->context(), isolate), object)) { 15534 isolate->ReportFailedAccessCheck(object); 15535 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); 15536 RETURN_FAILURE(isolate, should_throw, 15537 NewTypeError(MessageTemplate::kNoAccess)); 15538 } 15539 } else { 15540 DCHECK(!object->IsAccessCheckNeeded()); 15541 } 15542 15543 // Silently ignore the change if value is not a JSObject or null. 15544 // SpiderMonkey behaves this way. 15545 if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true); 15546 15547 bool all_extensible = object->map()->is_extensible(); 15548 Handle<JSObject> real_receiver = object; 15549 if (from_javascript) { 15550 // Find the first object in the chain whose prototype object is not 15551 // hidden. 15552 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype, 15553 PrototypeIterator::END_AT_NON_HIDDEN); 15554 while (!iter.IsAtEnd()) { 15555 // Casting to JSObject is fine because hidden prototypes are never 15556 // JSProxies. 15557 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); 15558 iter.Advance(); 15559 all_extensible = all_extensible && real_receiver->map()->is_extensible(); 15560 } 15561 } 15562 Handle<Map> map(real_receiver->map(), isolate); 15563 15564 // Nothing to do if prototype is already set. 15565 if (map->prototype() == *value) return Just(true); 15566 15567 bool immutable_proto = map->is_immutable_proto(); 15568 if (immutable_proto) { 15569 RETURN_FAILURE( 15570 isolate, should_throw, 15571 NewTypeError(MessageTemplate::kImmutablePrototypeSet, object)); 15572 } 15573 15574 // From 8.6.2 Object Internal Methods 15575 // ... 15576 // In addition, if [[Extensible]] is false the value of the [[Class]] and 15577 // [[Prototype]] internal properties of the object may not be modified. 15578 // ... 15579 // Implementation specific extensions that modify [[Class]], [[Prototype]] 15580 // or [[Extensible]] must not violate the invariants defined in the preceding 15581 // paragraph. 15582 if (!all_extensible) { 15583 RETURN_FAILURE(isolate, should_throw, 15584 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); 15585 } 15586 15587 // Before we can set the prototype we need to be sure prototype cycles are 15588 // prevented. It is sufficient to validate that the receiver is not in the 15589 // new prototype chain. 15590 if (value->IsJSReceiver()) { 15591 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value), 15592 kStartAtReceiver); 15593 !iter.IsAtEnd(); iter.Advance()) { 15594 if (iter.GetCurrent<JSReceiver>() == *object) { 15595 // Cycle detected. 15596 RETURN_FAILURE(isolate, should_throw, 15597 NewTypeError(MessageTemplate::kCyclicProto)); 15598 } 15599 } 15600 } 15601 15602 // Set the new prototype of the object. 15603 15604 isolate->UpdateNoElementsProtectorOnSetPrototype(real_receiver); 15605 15606 Handle<Map> new_map = Map::TransitionToPrototype(isolate, map, value); 15607 DCHECK(new_map->prototype() == *value); 15608 JSObject::MigrateToMap(real_receiver, new_map); 15609 15610 DCHECK(size == object->Size()); 15611 return Just(true); 15612 } 15613 15614 // static 15615 void JSObject::SetImmutableProto(Handle<JSObject> object) { 15616 DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS 15617 Handle<Map> map(object->map(), object->GetIsolate()); 15618 15619 // Nothing to do if prototype is already set. 15620 if (map->is_immutable_proto()) return; 15621 15622 Handle<Map> new_map = 15623 Map::TransitionToImmutableProto(object->GetIsolate(), map); 15624 object->synchronized_set_map(*new_map); 15625 } 15626 15627 void JSObject::EnsureCanContainElements(Handle<JSObject> object, 15628 Arguments* args, 15629 uint32_t first_arg, 15630 uint32_t arg_count, 15631 EnsureElementsMode mode) { 15632 // Elements in |Arguments| are ordered backwards (because they're on the 15633 // stack), but the method that's called here iterates over them in forward 15634 // direction. 15635 return EnsureCanContainElements( 15636 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode); 15637 } 15638 15639 15640 ElementsAccessor* JSObject::GetElementsAccessor() { 15641 return ElementsAccessor::ForKind(GetElementsKind()); 15642 } 15643 15644 void JSObject::ValidateElements(JSObject* object) { 15645 #ifdef ENABLE_SLOW_DCHECKS 15646 if (FLAG_enable_slow_asserts) { 15647 object->GetElementsAccessor()->Validate(object); 15648 } 15649 #endif 15650 } 15651 15652 15653 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity, 15654 uint32_t index, 15655 uint32_t* new_capacity) { 15656 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <= 15657 JSObject::kMaxUncheckedFastElementsLength); 15658 if (index < capacity) { 15659 *new_capacity = capacity; 15660 return false; 15661 } 15662 if (index - capacity >= JSObject::kMaxGap) return true; 15663 *new_capacity = JSObject::NewElementsCapacity(index + 1); 15664 DCHECK_LT(index, *new_capacity); 15665 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength || 15666 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength && 15667 Heap::InNewSpace(object))) { 15668 return false; 15669 } 15670 // If the fast-case backing storage takes up much more memory than a 15671 // dictionary backing storage would, the object should have slow elements. 15672 int used_elements = object->GetFastElementsUsage(); 15673 uint32_t size_threshold = NumberDictionary::kPreferFastElementsSizeFactor * 15674 NumberDictionary::ComputeCapacity(used_elements) * 15675 NumberDictionary::kEntrySize; 15676 return size_threshold <= *new_capacity; 15677 } 15678 15679 15680 bool JSObject::WouldConvertToSlowElements(uint32_t index) { 15681 if (!HasFastElements()) return false; 15682 uint32_t capacity = static_cast<uint32_t>(elements()->length()); 15683 uint32_t new_capacity; 15684 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity); 15685 } 15686 15687 15688 static ElementsKind BestFittingFastElementsKind(JSObject* object) { 15689 if (!object->map()->CanHaveFastTransitionableElementsKind()) { 15690 return HOLEY_ELEMENTS; 15691 } 15692 if (object->HasSloppyArgumentsElements()) { 15693 return FAST_SLOPPY_ARGUMENTS_ELEMENTS; 15694 } 15695 if (object->HasStringWrapperElements()) { 15696 return FAST_STRING_WRAPPER_ELEMENTS; 15697 } 15698 DCHECK(object->HasDictionaryElements()); 15699 NumberDictionary* dictionary = object->element_dictionary(); 15700 ElementsKind kind = HOLEY_SMI_ELEMENTS; 15701 for (int i = 0; i < dictionary->Capacity(); i++) { 15702 Object* key = dictionary->KeyAt(i); 15703 if (key->IsNumber()) { 15704 Object* value = dictionary->ValueAt(i); 15705 if (!value->IsNumber()) return HOLEY_ELEMENTS; 15706 if (!value->IsSmi()) { 15707 if (!FLAG_unbox_double_arrays) return HOLEY_ELEMENTS; 15708 kind = HOLEY_DOUBLE_ELEMENTS; 15709 } 15710 } 15711 } 15712 return kind; 15713 } 15714 15715 static bool ShouldConvertToFastElements(JSObject* object, 15716 NumberDictionary* dictionary, 15717 uint32_t index, 15718 uint32_t* new_capacity) { 15719 // If properties with non-standard attributes or accessors were added, we 15720 // cannot go back to fast elements. 15721 if (dictionary->requires_slow_elements()) return false; 15722 15723 // Adding a property with this index will require slow elements. 15724 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false; 15725 15726 if (object->IsJSArray()) { 15727 Object* length = JSArray::cast(object)->length(); 15728 if (!length->IsSmi()) return false; 15729 *new_capacity = static_cast<uint32_t>(Smi::ToInt(length)); 15730 } else if (object->IsJSSloppyArgumentsObject()) { 15731 return false; 15732 } else { 15733 *new_capacity = dictionary->max_number_key() + 1; 15734 } 15735 *new_capacity = Max(index + 1, *new_capacity); 15736 15737 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * 15738 NumberDictionary::kEntrySize; 15739 15740 // Turn fast if the dictionary only saves 50% space. 15741 return 2 * dictionary_size >= *new_capacity; 15742 } 15743 15744 // static 15745 void JSObject::AddDataElement(Handle<JSObject> object, uint32_t index, 15746 Handle<Object> value, 15747 PropertyAttributes attributes) { 15748 DCHECK(object->map()->is_extensible()); 15749 15750 Isolate* isolate = object->GetIsolate(); 15751 15752 uint32_t old_length = 0; 15753 uint32_t new_capacity = 0; 15754 15755 if (object->IsJSArray()) { 15756 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length)); 15757 } 15758 15759 ElementsKind kind = object->GetElementsKind(); 15760 FixedArrayBase* elements = object->elements(); 15761 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS; 15762 if (IsSloppyArgumentsElementsKind(kind)) { 15763 elements = SloppyArgumentsElements::cast(elements)->arguments(); 15764 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS; 15765 } else if (IsStringWrapperElementsKind(kind)) { 15766 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS; 15767 } 15768 15769 if (attributes != NONE) { 15770 kind = dictionary_kind; 15771 } else if (elements->IsNumberDictionary()) { 15772 kind = ShouldConvertToFastElements( 15773 *object, NumberDictionary::cast(elements), index, &new_capacity) 15774 ? BestFittingFastElementsKind(*object) 15775 : dictionary_kind; 15776 } else if (ShouldConvertToSlowElements( 15777 *object, static_cast<uint32_t>(elements->length()), index, 15778 &new_capacity)) { 15779 kind = dictionary_kind; 15780 } 15781 15782 ElementsKind to = value->OptimalElementsKind(); 15783 if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) { 15784 to = GetHoleyElementsKind(to); 15785 kind = GetHoleyElementsKind(kind); 15786 } 15787 to = GetMoreGeneralElementsKind(kind, to); 15788 ElementsAccessor* accessor = ElementsAccessor::ForKind(to); 15789 accessor->Add(object, index, value, attributes, new_capacity); 15790 15791 if (object->IsJSArray() && index >= old_length) { 15792 Handle<Object> new_length = 15793 isolate->factory()->NewNumberFromUint(index + 1); 15794 JSArray::cast(*object)->set_length(*new_length); 15795 } 15796 } 15797 15798 15799 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) { 15800 if (!HasFastElements()) return false; 15801 uint32_t capacity = static_cast<uint32_t>(elements()->length()); 15802 uint32_t new_capacity; 15803 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) && 15804 ShouldConvertToSlowElements(this, capacity, new_length - 1, 15805 &new_capacity); 15806 } 15807 15808 15809 const double AllocationSite::kPretenureRatio = 0.85; 15810 15811 15812 void AllocationSite::ResetPretenureDecision() { 15813 set_pretenure_decision(kUndecided); 15814 set_memento_found_count(0); 15815 set_memento_create_count(0); 15816 } 15817 15818 PretenureFlag AllocationSite::GetPretenureMode() const { 15819 PretenureDecision mode = pretenure_decision(); 15820 // Zombie objects "decide" to be untenured. 15821 return mode == kTenure ? TENURED : NOT_TENURED; 15822 } 15823 15824 bool AllocationSite::IsNested() { 15825 DCHECK(FLAG_trace_track_allocation_sites); 15826 Object* current = boilerplate()->GetHeap()->allocation_sites_list(); 15827 while (current->IsAllocationSite()) { 15828 AllocationSite* current_site = AllocationSite::cast(current); 15829 if (current_site->nested_site() == this) { 15830 return true; 15831 } 15832 current = current_site->weak_next(); 15833 } 15834 return false; 15835 } 15836 15837 template <AllocationSiteUpdateMode update_or_check> 15838 bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site, 15839 ElementsKind to_kind) { 15840 Isolate* isolate = site->GetIsolate(); 15841 bool result = false; 15842 15843 if (site->PointsToLiteral() && site->boilerplate()->IsJSArray()) { 15844 Handle<JSArray> boilerplate(JSArray::cast(site->boilerplate()), isolate); 15845 ElementsKind kind = boilerplate->GetElementsKind(); 15846 // if kind is holey ensure that to_kind is as well. 15847 if (IsHoleyElementsKind(kind)) { 15848 to_kind = GetHoleyElementsKind(to_kind); 15849 } 15850 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { 15851 // If the array is huge, it's not likely to be defined in a local 15852 // function, so we shouldn't make new instances of it very often. 15853 uint32_t length = 0; 15854 CHECK(boilerplate->length()->ToArrayLength(&length)); 15855 if (length <= kMaximumArrayBytesToPretransition) { 15856 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) { 15857 return true; 15858 } 15859 if (FLAG_trace_track_allocation_sites) { 15860 bool is_nested = site->IsNested(); 15861 PrintF("AllocationSite: JSArray %p boilerplate %supdated %s->%s\n", 15862 reinterpret_cast<void*>(*site), is_nested ? "(nested)" : " ", 15863 ElementsKindToString(kind), ElementsKindToString(to_kind)); 15864 } 15865 JSObject::TransitionElementsKind(boilerplate, to_kind); 15866 site->dependent_code()->DeoptimizeDependentCodeGroup( 15867 isolate, DependentCode::kAllocationSiteTransitionChangedGroup); 15868 result = true; 15869 } 15870 } 15871 } else { 15872 // The AllocationSite is for a constructed Array. 15873 ElementsKind kind = site->GetElementsKind(); 15874 // if kind is holey ensure that to_kind is as well. 15875 if (IsHoleyElementsKind(kind)) { 15876 to_kind = GetHoleyElementsKind(to_kind); 15877 } 15878 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { 15879 if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true; 15880 if (FLAG_trace_track_allocation_sites) { 15881 PrintF("AllocationSite: JSArray %p site updated %s->%s\n", 15882 reinterpret_cast<void*>(*site), 15883 ElementsKindToString(kind), 15884 ElementsKindToString(to_kind)); 15885 } 15886 site->SetElementsKind(to_kind); 15887 site->dependent_code()->DeoptimizeDependentCodeGroup( 15888 isolate, DependentCode::kAllocationSiteTransitionChangedGroup); 15889 result = true; 15890 } 15891 } 15892 return result; 15893 } 15894 15895 bool AllocationSite::ShouldTrack(ElementsKind from, ElementsKind to) { 15896 return IsSmiElementsKind(from) && 15897 IsMoreGeneralElementsKindTransition(from, to); 15898 } 15899 15900 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) { 15901 switch (decision) { 15902 case kUndecided: return "undecided"; 15903 case kDontTenure: return "don't tenure"; 15904 case kMaybeTenure: return "maybe tenure"; 15905 case kTenure: return "tenure"; 15906 case kZombie: return "zombie"; 15907 default: UNREACHABLE(); 15908 } 15909 return nullptr; 15910 } 15911 15912 template <AllocationSiteUpdateMode update_or_check> 15913 bool JSObject::UpdateAllocationSite(Handle<JSObject> object, 15914 ElementsKind to_kind) { 15915 if (!object->IsJSArray()) return false; 15916 15917 if (!Heap::InNewSpace(*object)) return false; 15918 15919 Handle<AllocationSite> site; 15920 { 15921 DisallowHeapAllocation no_allocation; 15922 15923 Heap* heap = object->GetHeap(); 15924 AllocationMemento* memento = 15925 heap->FindAllocationMemento<Heap::kForRuntime>(object->map(), *object); 15926 if (memento == nullptr) return false; 15927 15928 // Walk through to the Allocation Site 15929 site = handle(memento->GetAllocationSite(), heap->isolate()); 15930 } 15931 return AllocationSite::DigestTransitionFeedback<update_or_check>(site, 15932 to_kind); 15933 } 15934 15935 template bool 15936 JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>( 15937 Handle<JSObject> object, ElementsKind to_kind); 15938 15939 template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>( 15940 Handle<JSObject> object, ElementsKind to_kind); 15941 15942 void JSObject::TransitionElementsKind(Handle<JSObject> object, 15943 ElementsKind to_kind) { 15944 ElementsKind from_kind = object->GetElementsKind(); 15945 15946 if (IsHoleyElementsKind(from_kind)) { 15947 to_kind = GetHoleyElementsKind(to_kind); 15948 } 15949 15950 if (from_kind == to_kind) return; 15951 15952 // This method should never be called for any other case. 15953 DCHECK(IsFastElementsKind(from_kind)); 15954 DCHECK(IsFastElementsKind(to_kind)); 15955 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind); 15956 15957 UpdateAllocationSite(object, to_kind); 15958 if (object->elements() == object->GetReadOnlyRoots().empty_fixed_array() || 15959 IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) { 15960 // No change is needed to the elements() buffer, the transition 15961 // only requires a map change. 15962 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); 15963 MigrateToMap(object, new_map); 15964 if (FLAG_trace_elements_transitions) { 15965 Handle<FixedArrayBase> elms(object->elements(), object->GetIsolate()); 15966 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); 15967 } 15968 } else { 15969 DCHECK((IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) || 15970 (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind))); 15971 uint32_t c = static_cast<uint32_t>(object->elements()->length()); 15972 ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c); 15973 } 15974 } 15975 15976 15977 // static 15978 bool Map::IsValidElementsTransition(ElementsKind from_kind, 15979 ElementsKind to_kind) { 15980 // Transitions can't go backwards. 15981 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) { 15982 return false; 15983 } 15984 15985 // Transitions from HOLEY -> PACKED are not allowed. 15986 return !IsHoleyElementsKind(from_kind) || IsHoleyElementsKind(to_kind); 15987 } 15988 15989 15990 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { 15991 Map* map = array->map(); 15992 // Fast path: "length" is the first fast property of arrays. Since it's not 15993 // configurable, it's guaranteed to be the first in the descriptor array. 15994 if (!map->is_dictionary_map()) { 15995 DCHECK(map->instance_descriptors()->GetKey(0) == 15996 array->GetReadOnlyRoots().length_string()); 15997 return map->instance_descriptors()->GetDetails(0).IsReadOnly(); 15998 } 15999 16000 Isolate* isolate = array->GetIsolate(); 16001 LookupIterator it(array, isolate->factory()->length_string(), array, 16002 LookupIterator::OWN_SKIP_INTERCEPTOR); 16003 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); 16004 return it.IsReadOnly(); 16005 } 16006 16007 16008 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array, 16009 uint32_t index) { 16010 uint32_t length = 0; 16011 CHECK(array->length()->ToArrayLength(&length)); 16012 if (length <= index) return HasReadOnlyLength(array); 16013 return false; 16014 } 16015 16016 template <typename BackingStore> 16017 static int HoleyElementsUsage(JSObject* object, BackingStore* store) { 16018 Isolate* isolate = object->GetIsolate(); 16019 int limit = object->IsJSArray() ? Smi::ToInt(JSArray::cast(object)->length()) 16020 : store->length(); 16021 int used = 0; 16022 for (int i = 0; i < limit; ++i) { 16023 if (!store->is_the_hole(isolate, i)) ++used; 16024 } 16025 return used; 16026 } 16027 16028 int JSObject::GetFastElementsUsage() { 16029 FixedArrayBase* store = elements(); 16030 switch (GetElementsKind()) { 16031 case PACKED_SMI_ELEMENTS: 16032 case PACKED_DOUBLE_ELEMENTS: 16033 case PACKED_ELEMENTS: 16034 return IsJSArray() ? Smi::ToInt(JSArray::cast(this)->length()) 16035 : store->length(); 16036 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 16037 store = SloppyArgumentsElements::cast(store)->arguments(); 16038 V8_FALLTHROUGH; 16039 case HOLEY_SMI_ELEMENTS: 16040 case HOLEY_ELEMENTS: 16041 case FAST_STRING_WRAPPER_ELEMENTS: 16042 return HoleyElementsUsage(this, FixedArray::cast(store)); 16043 case HOLEY_DOUBLE_ELEMENTS: 16044 if (elements()->length() == 0) return 0; 16045 return HoleyElementsUsage(this, FixedDoubleArray::cast(store)); 16046 16047 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 16048 case SLOW_STRING_WRAPPER_ELEMENTS: 16049 case DICTIONARY_ELEMENTS: 16050 case NO_ELEMENTS: 16051 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: 16052 16053 TYPED_ARRAYS(TYPED_ARRAY_CASE) 16054 #undef TYPED_ARRAY_CASE 16055 UNREACHABLE(); 16056 } 16057 return 0; 16058 } 16059 16060 16061 // Certain compilers request function template instantiation when they 16062 // see the definition of the other template functions in the 16063 // class. This requires us to have the template functions put 16064 // together, so even though this function belongs in objects-debug.cc, 16065 // we keep it here instead to satisfy certain compilers. 16066 #ifdef OBJECT_PRINT 16067 template <typename Derived, typename Shape> 16068 void Dictionary<Derived, Shape>::Print(std::ostream& os) { 16069 DisallowHeapAllocation no_gc; 16070 ReadOnlyRoots roots = this->GetReadOnlyRoots(); 16071 Derived* dictionary = Derived::cast(this); 16072 int capacity = dictionary->Capacity(); 16073 for (int i = 0; i < capacity; i++) { 16074 Object* k = dictionary->KeyAt(i); 16075 if (!dictionary->ToKey(roots, i, &k)) continue; 16076 os << "\n "; 16077 if (k->IsString()) { 16078 String::cast(k)->StringPrint(os); 16079 } else { 16080 os << Brief(k); 16081 } 16082 os << ": " << Brief(dictionary->ValueAt(i)) << " "; 16083 dictionary->DetailsAt(i).PrintAsSlowTo(os); 16084 } 16085 } 16086 template <typename Derived, typename Shape> 16087 void Dictionary<Derived, Shape>::Print() { 16088 StdoutStream os; 16089 Print(os); 16090 os << std::endl; 16091 } 16092 #endif 16093 16094 16095 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it, 16096 bool* done) { 16097 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); 16098 return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done); 16099 } 16100 16101 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object, 16102 Handle<Name> name) { 16103 LookupIterator it = LookupIterator::PropertyOrElement( 16104 object->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 16105 return HasProperty(&it); 16106 } 16107 16108 16109 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object, 16110 uint32_t index) { 16111 Isolate* isolate = object->GetIsolate(); 16112 LookupIterator it(isolate, object, index, object, 16113 LookupIterator::OWN_SKIP_INTERCEPTOR); 16114 return HasProperty(&it); 16115 } 16116 16117 16118 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object, 16119 Handle<Name> name) { 16120 LookupIterator it = LookupIterator::PropertyOrElement( 16121 object->GetIsolate(), object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 16122 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it); 16123 return maybe_result.IsJust() ? Just(it.state() == LookupIterator::ACCESSOR) 16124 : Nothing<bool>(); 16125 } 16126 16127 int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) { 16128 return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >> 16129 ElementsKindToShiftSize(kind)); 16130 } 16131 16132 bool FixedArrayBase::IsCowArray() const { 16133 return map() == GetReadOnlyRoots().fixed_cow_array_map(); 16134 } 16135 16136 bool JSObject::IsApiWrapper() { 16137 auto instance_type = map()->instance_type(); 16138 return instance_type == JS_API_OBJECT_TYPE || 16139 instance_type == JS_SPECIAL_API_OBJECT_TYPE; 16140 } 16141 16142 const char* Symbol::PrivateSymbolToName() const { 16143 ReadOnlyRoots roots = GetReadOnlyRoots(); 16144 #define SYMBOL_CHECK_AND_PRINT(name) \ 16145 if (this == roots.name()) return #name; 16146 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT) 16147 #undef SYMBOL_CHECK_AND_PRINT 16148 return "UNKNOWN"; 16149 } 16150 16151 16152 void Symbol::SymbolShortPrint(std::ostream& os) { 16153 os << "<Symbol:"; 16154 if (!name()->IsUndefined()) { 16155 os << " "; 16156 HeapStringAllocator allocator; 16157 StringStream accumulator(&allocator); 16158 String::cast(name())->StringShortPrint(&accumulator, false); 16159 os << accumulator.ToCString().get(); 16160 } else { 16161 os << " (" << PrivateSymbolToName() << ")"; 16162 } 16163 os << ">"; 16164 } 16165 16166 16167 // StringSharedKeys are used as keys in the eval cache. 16168 class StringSharedKey : public HashTableKey { 16169 public: 16170 // This tuple unambiguously identifies calls to eval() or 16171 // CreateDynamicFunction() (such as through the Function() constructor). 16172 // * source is the string passed into eval(). For dynamic functions, this is 16173 // the effective source for the function, some of which is implicitly 16174 // generated. 16175 // * shared is the shared function info for the function containing the call 16176 // to eval(). for dynamic functions, shared is the native context closure. 16177 // * When positive, position is the position in the source where eval is 16178 // called. When negative, position is the negation of the position in the 16179 // dynamic function's effective source where the ')' ends the parameters. 16180 StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared, 16181 LanguageMode language_mode, int position) 16182 : HashTableKey(CompilationCacheShape::StringSharedHash( 16183 *source, *shared, language_mode, position)), 16184 source_(source), 16185 shared_(shared), 16186 language_mode_(language_mode), 16187 position_(position) {} 16188 16189 bool IsMatch(Object* other) override { 16190 DisallowHeapAllocation no_allocation; 16191 if (!other->IsFixedArray()) { 16192 DCHECK(other->IsNumber()); 16193 uint32_t other_hash = static_cast<uint32_t>(other->Number()); 16194 return Hash() == other_hash; 16195 } 16196 FixedArray* other_array = FixedArray::cast(other); 16197 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0)); 16198 if (shared != *shared_) return false; 16199 int language_unchecked = Smi::ToInt(other_array->get(2)); 16200 DCHECK(is_valid_language_mode(language_unchecked)); 16201 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked); 16202 if (language_mode != language_mode_) return false; 16203 int position = Smi::ToInt(other_array->get(3)); 16204 if (position != position_) return false; 16205 String* source = String::cast(other_array->get(1)); 16206 return source->Equals(*source_); 16207 } 16208 16209 Handle<Object> AsHandle(Isolate* isolate) { 16210 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4); 16211 array->set(0, *shared_); 16212 array->set(1, *source_); 16213 array->set(2, Smi::FromEnum(language_mode_)); 16214 array->set(3, Smi::FromInt(position_)); 16215 array->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map()); 16216 return array; 16217 } 16218 16219 private: 16220 Handle<String> source_; 16221 Handle<SharedFunctionInfo> shared_; 16222 LanguageMode language_mode_; 16223 int position_; 16224 }; 16225 16226 v8::Promise::PromiseState JSPromise::status() const { 16227 int value = flags() & kStatusMask; 16228 DCHECK(value == 0 || value == 1 || value == 2); 16229 return static_cast<v8::Promise::PromiseState>(value); 16230 } 16231 16232 void JSPromise::set_status(Promise::PromiseState status) { 16233 int value = flags() & ~kStatusMask; 16234 set_flags(value | status); 16235 } 16236 16237 // static 16238 const char* JSPromise::Status(v8::Promise::PromiseState status) { 16239 switch (status) { 16240 case v8::Promise::kFulfilled: 16241 return "resolved"; 16242 case v8::Promise::kPending: 16243 return "pending"; 16244 case v8::Promise::kRejected: 16245 return "rejected"; 16246 } 16247 UNREACHABLE(); 16248 } 16249 16250 int JSPromise::async_task_id() const { 16251 return AsyncTaskIdField::decode(flags()); 16252 } 16253 16254 void JSPromise::set_async_task_id(int id) { 16255 set_flags(AsyncTaskIdField::update(flags(), id)); 16256 } 16257 16258 // static 16259 Handle<Object> JSPromise::Fulfill(Handle<JSPromise> promise, 16260 Handle<Object> value) { 16261 Isolate* const isolate = promise->GetIsolate(); 16262 16263 // 1. Assert: The value of promise.[[PromiseState]] is "pending". 16264 DCHECK_EQ(Promise::kPending, promise->status()); 16265 16266 // 2. Let reactions be promise.[[PromiseFulfillReactions]]. 16267 Handle<Object> reactions(promise->reactions(), isolate); 16268 16269 // 3. Set promise.[[PromiseResult]] to value. 16270 // 4. Set promise.[[PromiseFulfillReactions]] to undefined. 16271 // 5. Set promise.[[PromiseRejectReactions]] to undefined. 16272 promise->set_reactions_or_result(*value); 16273 16274 // 6. Set promise.[[PromiseState]] to "fulfilled". 16275 promise->set_status(Promise::kFulfilled); 16276 16277 // 7. Return TriggerPromiseReactions(reactions, value). 16278 return TriggerPromiseReactions(isolate, reactions, value, 16279 PromiseReaction::kFulfill); 16280 } 16281 16282 // static 16283 Handle<Object> JSPromise::Reject(Handle<JSPromise> promise, 16284 Handle<Object> reason, bool debug_event) { 16285 Isolate* const isolate = promise->GetIsolate(); 16286 16287 if (debug_event) isolate->debug()->OnPromiseReject(promise, reason); 16288 isolate->RunPromiseHook(PromiseHookType::kResolve, promise, 16289 isolate->factory()->undefined_value()); 16290 16291 // 1. Assert: The value of promise.[[PromiseState]] is "pending". 16292 DCHECK_EQ(Promise::kPending, promise->status()); 16293 16294 // 2. Let reactions be promise.[[PromiseRejectReactions]]. 16295 Handle<Object> reactions(promise->reactions(), isolate); 16296 16297 // 3. Set promise.[[PromiseResult]] to reason. 16298 // 4. Set promise.[[PromiseFulfillReactions]] to undefined. 16299 // 5. Set promise.[[PromiseRejectReactions]] to undefined. 16300 promise->set_reactions_or_result(*reason); 16301 16302 // 6. Set promise.[[PromiseState]] to "rejected". 16303 promise->set_status(Promise::kRejected); 16304 16305 // 7. If promise.[[PromiseIsHandled]] is false, perform 16306 // HostPromiseRejectionTracker(promise, "reject"). 16307 if (!promise->has_handler()) { 16308 isolate->ReportPromiseReject(promise, reason, kPromiseRejectWithNoHandler); 16309 } 16310 16311 // 8. Return TriggerPromiseReactions(reactions, reason). 16312 return TriggerPromiseReactions(isolate, reactions, reason, 16313 PromiseReaction::kReject); 16314 } 16315 16316 // static 16317 MaybeHandle<Object> JSPromise::Resolve(Handle<JSPromise> promise, 16318 Handle<Object> resolution) { 16319 Isolate* const isolate = promise->GetIsolate(); 16320 16321 isolate->RunPromiseHook(PromiseHookType::kResolve, promise, 16322 isolate->factory()->undefined_value()); 16323 16324 // 6. If SameValue(resolution, promise) is true, then 16325 if (promise.is_identical_to(resolution)) { 16326 // a. Let selfResolutionError be a newly created TypeError object. 16327 Handle<Object> self_resolution_error = isolate->factory()->NewTypeError( 16328 MessageTemplate::kPromiseCyclic, resolution); 16329 // b. Return RejectPromise(promise, selfResolutionError). 16330 return Reject(promise, self_resolution_error); 16331 } 16332 16333 // 7. If Type(resolution) is not Object, then 16334 if (!resolution->IsJSReceiver()) { 16335 // a. Return FulfillPromise(promise, resolution). 16336 return Fulfill(promise, resolution); 16337 } 16338 16339 // 8. Let then be Get(resolution, "then"). 16340 MaybeHandle<Object> then; 16341 if (isolate->IsPromiseThenLookupChainIntact( 16342 Handle<JSReceiver>::cast(resolution))) { 16343 // We can skip the "then" lookup on {resolution} if its [[Prototype]] 16344 // is the (initial) Promise.prototype and the Promise#then protector 16345 // is intact, as that guards the lookup path for the "then" property 16346 // on JSPromise instances which have the (initial) %PromisePrototype%. 16347 then = isolate->promise_then(); 16348 } else { 16349 then = 16350 JSReceiver::GetProperty(isolate, Handle<JSReceiver>::cast(resolution), 16351 isolate->factory()->then_string()); 16352 } 16353 16354 // 9. If then is an abrupt completion, then 16355 Handle<Object> then_action; 16356 if (!then.ToHandle(&then_action)) { 16357 // a. Return RejectPromise(promise, then.[[Value]]). 16358 Handle<Object> reason(isolate->pending_exception(), isolate); 16359 isolate->clear_pending_exception(); 16360 return Reject(promise, reason, false); 16361 } 16362 16363 // 10. Let thenAction be then.[[Value]]. 16364 // 11. If IsCallable(thenAction) is false, then 16365 if (!then_action->IsCallable()) { 16366 // a. Return FulfillPromise(promise, resolution). 16367 return Fulfill(promise, resolution); 16368 } 16369 16370 // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob, 16371 // promise, resolution, thenAction). 16372 Handle<PromiseResolveThenableJobTask> task = 16373 isolate->factory()->NewPromiseResolveThenableJobTask( 16374 promise, Handle<JSReceiver>::cast(then_action), 16375 Handle<JSReceiver>::cast(resolution), isolate->native_context()); 16376 if (isolate->debug()->is_active() && resolution->IsJSPromise()) { 16377 // Mark the dependency of the new {promise} on the {resolution}. 16378 Object::SetProperty(isolate, resolution, 16379 isolate->factory()->promise_handled_by_symbol(), 16380 promise, LanguageMode::kStrict) 16381 .Check(); 16382 } 16383 isolate->EnqueueMicrotask(task); 16384 16385 // 13. Return undefined. 16386 return isolate->factory()->undefined_value(); 16387 } 16388 16389 // static 16390 Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate, 16391 Handle<Object> reactions, 16392 Handle<Object> argument, 16393 PromiseReaction::Type type) { 16394 DCHECK(reactions->IsSmi() || reactions->IsPromiseReaction()); 16395 16396 // We need to reverse the {reactions} here, since we record them 16397 // on the JSPromise in the reverse order. 16398 { 16399 DisallowHeapAllocation no_gc; 16400 Object* current = *reactions; 16401 Object* reversed = Smi::kZero; 16402 while (!current->IsSmi()) { 16403 Object* next = PromiseReaction::cast(current)->next(); 16404 PromiseReaction::cast(current)->set_next(reversed); 16405 reversed = current; 16406 current = next; 16407 } 16408 reactions = handle(reversed, isolate); 16409 } 16410 16411 // Morph the {reactions} into PromiseReactionJobTasks 16412 // and push them onto the microtask queue. 16413 while (!reactions->IsSmi()) { 16414 Handle<HeapObject> task = Handle<HeapObject>::cast(reactions); 16415 Handle<PromiseReaction> reaction = Handle<PromiseReaction>::cast(task); 16416 reactions = handle(reaction->next(), isolate); 16417 16418 STATIC_ASSERT(PromiseReaction::kSize == PromiseReactionJobTask::kSize); 16419 if (type == PromiseReaction::kFulfill) { 16420 task->synchronized_set_map( 16421 ReadOnlyRoots(isolate).promise_fulfill_reaction_job_task_map()); 16422 Handle<PromiseFulfillReactionJobTask>::cast(task)->set_argument( 16423 *argument); 16424 Handle<PromiseFulfillReactionJobTask>::cast(task)->set_context( 16425 *isolate->native_context()); 16426 STATIC_ASSERT(PromiseReaction::kFulfillHandlerOffset == 16427 PromiseFulfillReactionJobTask::kHandlerOffset); 16428 STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset == 16429 PromiseFulfillReactionJobTask::kPromiseOrCapabilityOffset); 16430 } else { 16431 DisallowHeapAllocation no_gc; 16432 HeapObject* handler = reaction->reject_handler(); 16433 task->synchronized_set_map( 16434 ReadOnlyRoots(isolate).promise_reject_reaction_job_task_map()); 16435 Handle<PromiseRejectReactionJobTask>::cast(task)->set_argument(*argument); 16436 Handle<PromiseRejectReactionJobTask>::cast(task)->set_context( 16437 *isolate->native_context()); 16438 Handle<PromiseRejectReactionJobTask>::cast(task)->set_handler(handler); 16439 STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset == 16440 PromiseRejectReactionJobTask::kPromiseOrCapabilityOffset); 16441 } 16442 16443 isolate->EnqueueMicrotask(Handle<PromiseReactionJobTask>::cast(task)); 16444 } 16445 16446 return isolate->factory()->undefined_value(); 16447 } 16448 16449 namespace { 16450 16451 JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) { 16452 JSRegExp::Flags value = JSRegExp::kNone; 16453 int length = flags->length(); 16454 // A longer flags string cannot be valid. 16455 if (length > JSRegExp::FlagCount()) return JSRegExp::Flags(0); 16456 for (int i = 0; i < length; i++) { 16457 JSRegExp::Flag flag = JSRegExp::kNone; 16458 switch (flags->Get(i)) { 16459 case 'g': 16460 flag = JSRegExp::kGlobal; 16461 break; 16462 case 'i': 16463 flag = JSRegExp::kIgnoreCase; 16464 break; 16465 case 'm': 16466 flag = JSRegExp::kMultiline; 16467 break; 16468 case 's': 16469 flag = JSRegExp::kDotAll; 16470 break; 16471 case 'u': 16472 flag = JSRegExp::kUnicode; 16473 break; 16474 case 'y': 16475 flag = JSRegExp::kSticky; 16476 break; 16477 default: 16478 return JSRegExp::Flags(0); 16479 } 16480 // Duplicate flag. 16481 if (value & flag) return JSRegExp::Flags(0); 16482 value |= flag; 16483 } 16484 *success = true; 16485 return value; 16486 } 16487 16488 } // namespace 16489 16490 16491 // static 16492 MaybeHandle<JSRegExp> JSRegExp::New(Isolate* isolate, Handle<String> pattern, 16493 Flags flags) { 16494 Handle<JSFunction> constructor = isolate->regexp_function(); 16495 Handle<JSRegExp> regexp = 16496 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor)); 16497 16498 return JSRegExp::Initialize(regexp, pattern, flags); 16499 } 16500 16501 16502 // static 16503 Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) { 16504 Isolate* const isolate = regexp->GetIsolate(); 16505 return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp)); 16506 } 16507 16508 16509 template <typename Char> 16510 inline int CountRequiredEscapes(Handle<String> source) { 16511 DisallowHeapAllocation no_gc; 16512 int escapes = 0; 16513 Vector<const Char> src = source->GetCharVector<Char>(); 16514 for (int i = 0; i < src.length(); i++) { 16515 if (src[i] == '\\') { 16516 // Escape. Skip next character; 16517 i++; 16518 } else if (src[i] == '/') { 16519 // Not escaped forward-slash needs escape. 16520 escapes++; 16521 } 16522 } 16523 return escapes; 16524 } 16525 16526 16527 template <typename Char, typename StringType> 16528 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source, 16529 Handle<StringType> result) { 16530 DisallowHeapAllocation no_gc; 16531 Vector<const Char> src = source->GetCharVector<Char>(); 16532 Vector<Char> dst(result->GetChars(), result->length()); 16533 int s = 0; 16534 int d = 0; 16535 while (s < src.length()) { 16536 if (src[s] == '\\') { 16537 // Escape. Copy this and next character. 16538 dst[d++] = src[s++]; 16539 if (s == src.length()) break; 16540 } else if (src[s] == '/') { 16541 // Not escaped forward-slash needs escape. 16542 dst[d++] = '\\'; 16543 } 16544 dst[d++] = src[s++]; 16545 } 16546 DCHECK_EQ(result->length(), d); 16547 return result; 16548 } 16549 16550 16551 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate, 16552 Handle<String> source) { 16553 DCHECK(source->IsFlat()); 16554 if (source->length() == 0) return isolate->factory()->query_colon_string(); 16555 bool one_byte = source->IsOneByteRepresentationUnderneath(); 16556 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source) 16557 : CountRequiredEscapes<uc16>(source); 16558 if (escapes == 0) return source; 16559 int length = source->length() + escapes; 16560 if (one_byte) { 16561 Handle<SeqOneByteString> result; 16562 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 16563 isolate->factory()->NewRawOneByteString(length), 16564 String); 16565 return WriteEscapedRegExpSource<uint8_t>(source, result); 16566 } else { 16567 Handle<SeqTwoByteString> result; 16568 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 16569 isolate->factory()->NewRawTwoByteString(length), 16570 String); 16571 return WriteEscapedRegExpSource<uc16>(source, result); 16572 } 16573 } 16574 16575 16576 // static 16577 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, 16578 Handle<String> source, 16579 Handle<String> flags_string) { 16580 Isolate* isolate = regexp->GetIsolate(); 16581 bool success = false; 16582 Flags flags = RegExpFlagsFromString(flags_string, &success); 16583 if (!success) { 16584 THROW_NEW_ERROR( 16585 isolate, 16586 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string), 16587 JSRegExp); 16588 } 16589 return Initialize(regexp, source, flags); 16590 } 16591 16592 16593 // static 16594 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, 16595 Handle<String> source, Flags flags) { 16596 Isolate* isolate = regexp->GetIsolate(); 16597 Factory* factory = isolate->factory(); 16598 // If source is the empty string we set it to "(?:)" instead as 16599 // suggested by ECMA-262, 5th, section 15.10.4.1. 16600 if (source->length() == 0) source = factory->query_colon_string(); 16601 16602 source = String::Flatten(isolate, source); 16603 16604 Handle<String> escaped_source; 16605 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source, 16606 EscapeRegExpSource(isolate, source), JSRegExp); 16607 16608 RETURN_ON_EXCEPTION( 16609 isolate, RegExpImpl::Compile(isolate, regexp, source, flags), JSRegExp); 16610 16611 regexp->set_source(*escaped_source); 16612 regexp->set_flags(Smi::FromInt(flags)); 16613 16614 Map* map = regexp->map(); 16615 Object* constructor = map->GetConstructor(); 16616 if (constructor->IsJSFunction() && 16617 JSFunction::cast(constructor)->initial_map() == map) { 16618 // If we still have the original map, set in-object properties directly. 16619 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::kZero, 16620 SKIP_WRITE_BARRIER); 16621 } else { 16622 // Map has changed, so use generic, but slower, method. 16623 RETURN_ON_EXCEPTION( 16624 isolate, 16625 JSReceiver::SetProperty(isolate, regexp, factory->lastIndex_string(), 16626 Handle<Smi>(Smi::kZero, isolate), 16627 LanguageMode::kStrict), 16628 JSRegExp); 16629 } 16630 16631 return regexp; 16632 } 16633 16634 16635 // RegExpKey carries the source and flags of a regular expression as key. 16636 class RegExpKey : public HashTableKey { 16637 public: 16638 RegExpKey(Handle<String> string, JSRegExp::Flags flags) 16639 : HashTableKey( 16640 CompilationCacheShape::RegExpHash(*string, Smi::FromInt(flags))), 16641 string_(string), 16642 flags_(Smi::FromInt(flags)) {} 16643 16644 // Rather than storing the key in the hash table, a pointer to the 16645 // stored value is stored where the key should be. IsMatch then 16646 // compares the search key to the found object, rather than comparing 16647 // a key to a key. 16648 bool IsMatch(Object* obj) override { 16649 FixedArray* val = FixedArray::cast(obj); 16650 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex))) 16651 && (flags_ == val->get(JSRegExp::kFlagsIndex)); 16652 } 16653 16654 Handle<String> string_; 16655 Smi* flags_; 16656 }; 16657 16658 Handle<String> OneByteStringKey::AsHandle(Isolate* isolate) { 16659 return isolate->factory()->NewOneByteInternalizedString(string_, HashField()); 16660 } 16661 16662 Handle<String> TwoByteStringKey::AsHandle(Isolate* isolate) { 16663 return isolate->factory()->NewTwoByteInternalizedString(string_, HashField()); 16664 } 16665 16666 Handle<String> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) { 16667 return isolate->factory()->NewOneByteInternalizedSubString( 16668 string_, from_, length_, HashField()); 16669 } 16670 16671 16672 bool SeqOneByteSubStringKey::IsMatch(Object* string) { 16673 Vector<const uint8_t> chars(string_->GetChars() + from_, length_); 16674 return String::cast(string)->IsOneByteEqualTo(chars); 16675 } 16676 16677 16678 // InternalizedStringKey carries a string/internalized-string object as key. 16679 class InternalizedStringKey : public StringTableKey { 16680 public: 16681 explicit InternalizedStringKey(Handle<String> string) 16682 : StringTableKey(0), string_(string) { 16683 DCHECK(!string->IsInternalizedString()); 16684 DCHECK(string->IsFlat()); 16685 // Make sure hash_field is computed. 16686 string->Hash(); 16687 set_hash_field(string->hash_field()); 16688 } 16689 16690 bool IsMatch(Object* string) override { 16691 return string_->SlowEquals(String::cast(string)); 16692 } 16693 16694 Handle<String> AsHandle(Isolate* isolate) override { 16695 // Internalize the string if possible. 16696 MaybeHandle<Map> maybe_map = 16697 isolate->factory()->InternalizedStringMapForString(string_); 16698 Handle<Map> map; 16699 if (maybe_map.ToHandle(&map)) { 16700 string_->set_map_no_write_barrier(*map); 16701 DCHECK(string_->IsInternalizedString()); 16702 return string_; 16703 } 16704 if (FLAG_thin_strings) { 16705 // External strings get special treatment, to avoid copying their 16706 // contents. 16707 if (string_->IsExternalOneByteString()) { 16708 return isolate->factory() 16709 ->InternalizeExternalString<ExternalOneByteString>(string_); 16710 } else if (string_->IsExternalTwoByteString()) { 16711 return isolate->factory() 16712 ->InternalizeExternalString<ExternalTwoByteString>(string_); 16713 } 16714 } 16715 // Otherwise allocate a new internalized string. 16716 return isolate->factory()->NewInternalizedStringImpl( 16717 string_, string_->length(), string_->hash_field()); 16718 } 16719 16720 private: 16721 Handle<String> string_; 16722 }; 16723 16724 template <typename Derived, typename Shape> 16725 void HashTable<Derived, Shape>::IteratePrefix(ObjectVisitor* v) { 16726 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); 16727 } 16728 16729 template <typename Derived, typename Shape> 16730 void HashTable<Derived, Shape>::IterateElements(ObjectVisitor* v) { 16731 BodyDescriptorBase::IteratePointers(this, kElementsStartOffset, 16732 kHeaderSize + length() * kPointerSize, v); 16733 } 16734 16735 template <typename Derived, typename Shape> 16736 Handle<Derived> HashTable<Derived, Shape>::New( 16737 Isolate* isolate, int at_least_space_for, PretenureFlag pretenure, 16738 MinimumCapacity capacity_option) { 16739 DCHECK_LE(0, at_least_space_for); 16740 DCHECK_IMPLIES(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY, 16741 base::bits::IsPowerOfTwo(at_least_space_for)); 16742 16743 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY) 16744 ? at_least_space_for 16745 : ComputeCapacity(at_least_space_for); 16746 if (capacity > HashTable::kMaxCapacity) { 16747 isolate->heap()->FatalProcessOutOfMemory("invalid table size"); 16748 } 16749 return NewInternal(isolate, capacity, pretenure); 16750 } 16751 16752 template <typename Derived, typename Shape> 16753 Handle<Derived> HashTable<Derived, Shape>::NewInternal( 16754 Isolate* isolate, int capacity, PretenureFlag pretenure) { 16755 Factory* factory = isolate->factory(); 16756 int length = EntryToIndex(capacity); 16757 Heap::RootListIndex map_root_index = 16758 static_cast<Heap::RootListIndex>(Shape::GetMapRootIndex()); 16759 Handle<FixedArray> array = 16760 factory->NewFixedArrayWithMap(map_root_index, length, pretenure); 16761 Handle<Derived> table = Handle<Derived>::cast(array); 16762 16763 table->SetNumberOfElements(0); 16764 table->SetNumberOfDeletedElements(0); 16765 table->SetCapacity(capacity); 16766 return table; 16767 } 16768 16769 template <typename Derived, typename Shape> 16770 void HashTable<Derived, Shape>::Rehash(Isolate* isolate, Derived* new_table) { 16771 DisallowHeapAllocation no_gc; 16772 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc); 16773 16774 DCHECK_LT(NumberOfElements(), new_table->Capacity()); 16775 16776 // Copy prefix to new array. 16777 for (int i = kPrefixStartIndex; i < kElementsStartIndex; i++) { 16778 new_table->set(i, get(i), mode); 16779 } 16780 16781 // Rehash the elements. 16782 int capacity = this->Capacity(); 16783 ReadOnlyRoots roots(isolate); 16784 for (int i = 0; i < capacity; i++) { 16785 uint32_t from_index = EntryToIndex(i); 16786 Object* k = this->get(from_index); 16787 if (!Shape::IsLive(roots, k)) continue; 16788 uint32_t hash = Shape::HashForObject(isolate, k); 16789 uint32_t insertion_index = 16790 EntryToIndex(new_table->FindInsertionEntry(hash)); 16791 for (int j = 0; j < Shape::kEntrySize; j++) { 16792 new_table->set(insertion_index + j, get(from_index + j), mode); 16793 } 16794 } 16795 new_table->SetNumberOfElements(NumberOfElements()); 16796 new_table->SetNumberOfDeletedElements(0); 16797 } 16798 16799 template <typename Derived, typename Shape> 16800 uint32_t HashTable<Derived, Shape>::EntryForProbe(Isolate* isolate, Object* k, 16801 int probe, 16802 uint32_t expected) { 16803 uint32_t hash = Shape::HashForObject(isolate, k); 16804 uint32_t capacity = this->Capacity(); 16805 uint32_t entry = FirstProbe(hash, capacity); 16806 for (int i = 1; i < probe; i++) { 16807 if (entry == expected) return expected; 16808 entry = NextProbe(entry, i, capacity); 16809 } 16810 return entry; 16811 } 16812 16813 template <typename Derived, typename Shape> 16814 void HashTable<Derived, Shape>::Swap(uint32_t entry1, uint32_t entry2, 16815 WriteBarrierMode mode) { 16816 int index1 = EntryToIndex(entry1); 16817 int index2 = EntryToIndex(entry2); 16818 Object* temp[Shape::kEntrySize]; 16819 for (int j = 0; j < Shape::kEntrySize; j++) { 16820 temp[j] = get(index1 + j); 16821 } 16822 for (int j = 0; j < Shape::kEntrySize; j++) { 16823 set(index1 + j, get(index2 + j), mode); 16824 } 16825 for (int j = 0; j < Shape::kEntrySize; j++) { 16826 set(index2 + j, temp[j], mode); 16827 } 16828 } 16829 16830 template <typename Derived, typename Shape> 16831 void HashTable<Derived, Shape>::Rehash(Isolate* isolate) { 16832 DisallowHeapAllocation no_gc; 16833 WriteBarrierMode mode = GetWriteBarrierMode(no_gc); 16834 ReadOnlyRoots roots(isolate); 16835 uint32_t capacity = Capacity(); 16836 bool done = false; 16837 for (int probe = 1; !done; probe++) { 16838 // All elements at entries given by one of the first _probe_ probes 16839 // are placed correctly. Other elements might need to be moved. 16840 done = true; 16841 for (uint32_t current = 0; current < capacity; current++) { 16842 Object* current_key = KeyAt(current); 16843 if (!Shape::IsLive(roots, current_key)) continue; 16844 uint32_t target = EntryForProbe(isolate, current_key, probe, current); 16845 if (current == target) continue; 16846 Object* target_key = KeyAt(target); 16847 if (!Shape::IsLive(roots, target_key) || 16848 EntryForProbe(isolate, target_key, probe, target) != target) { 16849 // Put the current element into the correct position. 16850 Swap(current, target, mode); 16851 // The other element will be processed on the next iteration. 16852 current--; 16853 } else { 16854 // The place for the current element is occupied. Leave the element 16855 // for the next probe. 16856 done = false; 16857 } 16858 } 16859 } 16860 // Wipe deleted entries. 16861 Object* the_hole = roots.the_hole_value(); 16862 Object* undefined = roots.undefined_value(); 16863 for (uint32_t current = 0; current < capacity; current++) { 16864 if (KeyAt(current) == the_hole) { 16865 set(EntryToIndex(current) + kEntryKeyIndex, undefined); 16866 } 16867 } 16868 SetNumberOfDeletedElements(0); 16869 } 16870 16871 template <typename Derived, typename Shape> 16872 Handle<Derived> HashTable<Derived, Shape>::EnsureCapacity( 16873 Isolate* isolate, Handle<Derived> table, int n, PretenureFlag pretenure) { 16874 if (table->HasSufficientCapacityToAdd(n)) return table; 16875 16876 int capacity = table->Capacity(); 16877 int new_nof = table->NumberOfElements() + n; 16878 16879 const int kMinCapacityForPretenure = 256; 16880 bool should_pretenure = 16881 pretenure == TENURED || 16882 ((capacity > kMinCapacityForPretenure) && !Heap::InNewSpace(*table)); 16883 Handle<Derived> new_table = HashTable::New( 16884 isolate, new_nof, should_pretenure ? TENURED : NOT_TENURED); 16885 16886 table->Rehash(isolate, *new_table); 16887 return new_table; 16888 } 16889 16890 template bool 16891 HashTable<NameDictionary, NameDictionaryShape>::HasSufficientCapacityToAdd(int); 16892 16893 template <typename Derived, typename Shape> 16894 bool HashTable<Derived, Shape>::HasSufficientCapacityToAdd( 16895 int number_of_additional_elements) { 16896 int capacity = Capacity(); 16897 int nof = NumberOfElements() + number_of_additional_elements; 16898 int nod = NumberOfDeletedElements(); 16899 // Return true if: 16900 // 50% is still free after adding number_of_additional_elements elements and 16901 // at most 50% of the free elements are deleted elements. 16902 if ((nof < capacity) && ((nod <= (capacity - nof) >> 1))) { 16903 int needed_free = nof >> 1; 16904 if (nof + needed_free <= capacity) return true; 16905 } 16906 return false; 16907 } 16908 16909 template <typename Derived, typename Shape> 16910 Handle<Derived> HashTable<Derived, Shape>::Shrink(Isolate* isolate, 16911 Handle<Derived> table, 16912 int additionalCapacity) { 16913 int capacity = table->Capacity(); 16914 int nof = table->NumberOfElements(); 16915 16916 // Shrink to fit the number of elements if only a quarter of the 16917 // capacity is filled with elements. 16918 if (nof > (capacity >> 2)) return table; 16919 // Allocate a new dictionary with room for at least the current number of 16920 // elements + {additionalCapacity}. The allocation method will make sure that 16921 // there is extra room in the dictionary for additions. Don't go lower than 16922 // room for {kMinShrinkCapacity} elements. 16923 int at_least_room_for = nof + additionalCapacity; 16924 int new_capacity = ComputeCapacity(at_least_room_for); 16925 if (new_capacity < Derived::kMinShrinkCapacity) return table; 16926 if (new_capacity == capacity) return table; 16927 16928 const int kMinCapacityForPretenure = 256; 16929 bool pretenure = (at_least_room_for > kMinCapacityForPretenure) && 16930 !Heap::InNewSpace(*table); 16931 Handle<Derived> new_table = 16932 HashTable::New(isolate, new_capacity, pretenure ? TENURED : NOT_TENURED, 16933 USE_CUSTOM_MINIMUM_CAPACITY); 16934 16935 table->Rehash(isolate, *new_table); 16936 return new_table; 16937 } 16938 16939 template <typename Derived, typename Shape> 16940 uint32_t HashTable<Derived, Shape>::FindInsertionEntry(uint32_t hash) { 16941 uint32_t capacity = Capacity(); 16942 uint32_t entry = FirstProbe(hash, capacity); 16943 uint32_t count = 1; 16944 // EnsureCapacity will guarantee the hash table is never full. 16945 ReadOnlyRoots roots = GetReadOnlyRoots(); 16946 while (true) { 16947 if (!Shape::IsLive(roots, KeyAt(entry))) break; 16948 entry = NextProbe(entry, count++, capacity); 16949 } 16950 return entry; 16951 } 16952 16953 void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global, 16954 Handle<Name> name) { 16955 // Regardless of whether the property is there or not invalidate 16956 // Load/StoreGlobalICs that load/store through global object's prototype. 16957 JSObject::InvalidatePrototypeValidityCell(*global); 16958 16959 DCHECK(!global->HasFastProperties()); 16960 auto dictionary = handle(global->global_dictionary(), global->GetIsolate()); 16961 int entry = dictionary->FindEntry(global->GetIsolate(), name); 16962 if (entry == GlobalDictionary::kNotFound) return; 16963 PropertyCell::InvalidateEntry(global->GetIsolate(), dictionary, entry); 16964 } 16965 16966 Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell( 16967 Handle<JSGlobalObject> global, Handle<Name> name, 16968 PropertyCellType cell_type, int* entry_out) { 16969 Isolate* isolate = global->GetIsolate(); 16970 DCHECK(!global->HasFastProperties()); 16971 Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate); 16972 int entry = dictionary->FindEntry(isolate, name); 16973 Handle<PropertyCell> cell; 16974 if (entry != GlobalDictionary::kNotFound) { 16975 if (entry_out) *entry_out = entry; 16976 cell = handle(dictionary->CellAt(entry), isolate); 16977 PropertyCellType original_cell_type = cell->property_details().cell_type(); 16978 DCHECK(original_cell_type == PropertyCellType::kInvalidated || 16979 original_cell_type == PropertyCellType::kUninitialized); 16980 DCHECK(cell->value()->IsTheHole(isolate)); 16981 if (original_cell_type == PropertyCellType::kInvalidated) { 16982 cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry); 16983 } 16984 PropertyDetails details(kData, NONE, cell_type); 16985 cell->set_property_details(details); 16986 return cell; 16987 } 16988 cell = isolate->factory()->NewPropertyCell(name); 16989 PropertyDetails details(kData, NONE, cell_type); 16990 dictionary = GlobalDictionary::Add(isolate, dictionary, name, cell, details, 16991 entry_out); 16992 // {*entry_out} is initialized inside GlobalDictionary::Add(). 16993 global->SetProperties(*dictionary); 16994 return cell; 16995 } 16996 16997 16998 // This class is used for looking up two character strings in the string table. 16999 // If we don't have a hit we don't want to waste much time so we unroll the 17000 // string hash calculation loop here for speed. Doesn't work if the two 17001 // characters form a decimal integer, since such strings have a different hash 17002 // algorithm. 17003 class TwoCharHashTableKey : public StringTableKey { 17004 public: 17005 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint64_t seed) 17006 : StringTableKey(ComputeHashField(c1, c2, seed)), c1_(c1), c2_(c2) {} 17007 17008 bool IsMatch(Object* o) override { 17009 String* other = String::cast(o); 17010 if (other->length() != 2) return false; 17011 if (other->Get(0) != c1_) return false; 17012 return other->Get(1) == c2_; 17013 } 17014 17015 Handle<String> AsHandle(Isolate* isolate) override { 17016 // The TwoCharHashTableKey is only used for looking in the string 17017 // table, not for adding to it. 17018 UNREACHABLE(); 17019 } 17020 17021 private: 17022 uint32_t ComputeHashField(uint16_t c1, uint16_t c2, uint64_t seed) { 17023 // Char 1. 17024 uint32_t hash = static_cast<uint32_t>(seed); 17025 hash += c1; 17026 hash += hash << 10; 17027 hash ^= hash >> 6; 17028 // Char 2. 17029 hash += c2; 17030 hash += hash << 10; 17031 hash ^= hash >> 6; 17032 // GetHash. 17033 hash += hash << 3; 17034 hash ^= hash >> 11; 17035 hash += hash << 15; 17036 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash; 17037 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask; 17038 #ifdef DEBUG 17039 // If this assert fails then we failed to reproduce the two-character 17040 // version of the string hashing algorithm above. One reason could be 17041 // that we were passed two digits as characters, since the hash 17042 // algorithm is different in that case. 17043 uint16_t chars[2] = {c1, c2}; 17044 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed); 17045 DCHECK_EQ(hash, check_hash); 17046 #endif 17047 return hash; 17048 } 17049 17050 uint16_t c1_; 17051 uint16_t c2_; 17052 }; 17053 17054 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists( 17055 Isolate* isolate, 17056 uint16_t c1, 17057 uint16_t c2) { 17058 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed()); 17059 Handle<StringTable> string_table = isolate->factory()->string_table(); 17060 int entry = string_table->FindEntry(isolate, &key); 17061 if (entry == kNotFound) return MaybeHandle<String>(); 17062 17063 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate); 17064 DCHECK(StringShape(*result).IsInternalized()); 17065 DCHECK_EQ(result->Hash(), key.Hash()); 17066 return result; 17067 } 17068 17069 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, 17070 int expected) { 17071 Handle<StringTable> table = isolate->factory()->string_table(); 17072 // We need a key instance for the virtual hash function. 17073 table = StringTable::EnsureCapacity(isolate, table, expected); 17074 isolate->heap()->SetRootStringTable(*table); 17075 } 17076 17077 namespace { 17078 17079 template <class StringClass> 17080 void MigrateExternalStringResource(Isolate* isolate, String* from, String* to) { 17081 StringClass* cast_from = StringClass::cast(from); 17082 StringClass* cast_to = StringClass::cast(to); 17083 const typename StringClass::Resource* to_resource = cast_to->resource(); 17084 if (to_resource == nullptr) { 17085 // |to| is a just-created internalized copy of |from|. Migrate the resource. 17086 cast_to->SetResource(isolate, cast_from->resource()); 17087 // Zap |from|'s resource pointer to reflect the fact that |from| has 17088 // relinquished ownership of its resource. 17089 isolate->heap()->UpdateExternalString( 17090 from, ExternalString::cast(from)->ExternalPayloadSize(), 0); 17091 cast_from->SetResource(isolate, nullptr); 17092 } else if (to_resource != cast_from->resource()) { 17093 // |to| already existed and has its own resource. Finalize |from|. 17094 isolate->heap()->FinalizeExternalString(from); 17095 } 17096 } 17097 17098 void MakeStringThin(String* string, String* internalized, Isolate* isolate) { 17099 DCHECK_NE(string, internalized); 17100 DCHECK(internalized->IsInternalizedString()); 17101 17102 if (string->IsExternalString()) { 17103 if (internalized->IsExternalOneByteString()) { 17104 MigrateExternalStringResource<ExternalOneByteString>(isolate, string, 17105 internalized); 17106 } else if (internalized->IsExternalTwoByteString()) { 17107 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string, 17108 internalized); 17109 } else { 17110 // If the external string is duped into an existing non-external 17111 // internalized string, free its resource (it's about to be rewritten 17112 // into a ThinString below). 17113 isolate->heap()->FinalizeExternalString(string); 17114 } 17115 } 17116 17117 DisallowHeapAllocation no_gc; 17118 int old_size = string->Size(); 17119 isolate->heap()->NotifyObjectLayoutChange(string, old_size, no_gc); 17120 bool one_byte = internalized->IsOneByteRepresentation(); 17121 Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map() 17122 : isolate->factory()->thin_string_map(); 17123 DCHECK_GE(old_size, ThinString::kSize); 17124 string->synchronized_set_map(*map); 17125 ThinString* thin = ThinString::cast(string); 17126 thin->set_actual(internalized); 17127 Address thin_end = thin->address() + ThinString::kSize; 17128 int size_delta = old_size - ThinString::kSize; 17129 if (size_delta != 0) { 17130 Heap* heap = isolate->heap(); 17131 heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo); 17132 } 17133 } 17134 17135 } // namespace 17136 17137 // static 17138 Handle<String> StringTable::LookupString(Isolate* isolate, 17139 Handle<String> string) { 17140 string = String::Flatten(isolate, string); 17141 if (string->IsInternalizedString()) return string; 17142 17143 InternalizedStringKey key(string); 17144 Handle<String> result = LookupKey(isolate, &key); 17145 17146 if (FLAG_thin_strings) { 17147 if (!string->IsInternalizedString()) { 17148 MakeStringThin(*string, *result, isolate); 17149 } 17150 } else { // !FLAG_thin_strings 17151 if (string->IsConsString()) { 17152 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17153 cons->set_first(isolate, *result); 17154 cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string()); 17155 } else if (string->IsSlicedString()) { 17156 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); 17157 DisallowHeapAllocation no_gc; 17158 bool one_byte = result->IsOneByteRepresentation(); 17159 Handle<Map> map = one_byte 17160 ? isolate->factory()->cons_one_byte_string_map() 17161 : isolate->factory()->cons_string_map(); 17162 string->set_map(*map); 17163 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17164 cons->set_first(isolate, *result); 17165 cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string()); 17166 } 17167 } 17168 return result; 17169 } 17170 17171 // static 17172 Handle<String> StringTable::LookupKey(Isolate* isolate, StringTableKey* key) { 17173 Handle<StringTable> table = isolate->factory()->string_table(); 17174 int entry = table->FindEntry(isolate, key); 17175 17176 // String already in table. 17177 if (entry != kNotFound) { 17178 return handle(String::cast(table->KeyAt(entry)), isolate); 17179 } 17180 17181 table = StringTable::CautiousShrink(isolate, table); 17182 // Adding new string. Grow table if needed. 17183 table = StringTable::EnsureCapacity(isolate, table, 1); 17184 isolate->heap()->SetRootStringTable(*table); 17185 17186 return AddKeyNoResize(isolate, key); 17187 } 17188 17189 Handle<String> StringTable::AddKeyNoResize(Isolate* isolate, 17190 StringTableKey* key) { 17191 Handle<StringTable> table = isolate->factory()->string_table(); 17192 DCHECK(table->HasSufficientCapacityToAdd(1)); 17193 // Create string object. 17194 Handle<String> string = key->AsHandle(isolate); 17195 // There must be no attempts to internalize strings that could throw 17196 // InvalidStringLength error. 17197 CHECK(!string.is_null()); 17198 DCHECK(string->HasHashCode()); 17199 DCHECK_EQ(table->FindEntry(isolate, key), kNotFound); 17200 17201 // Add the new string and return it along with the string table. 17202 int entry = table->FindInsertionEntry(key->Hash()); 17203 table->set(EntryToIndex(entry), *string); 17204 table->ElementAdded(); 17205 17206 return Handle<String>::cast(string); 17207 } 17208 17209 Handle<StringTable> StringTable::CautiousShrink(Isolate* isolate, 17210 Handle<StringTable> table) { 17211 // Only shrink if the table is very empty to avoid performance penalty. 17212 int capacity = table->Capacity(); 17213 int nof = table->NumberOfElements(); 17214 if (capacity <= StringTable::kMinCapacity) return table; 17215 if (nof > (capacity / kMaxEmptyFactor)) return table; 17216 // Keep capacity for at least half of the current nof elements. 17217 int slack_capacity = nof >> 2; 17218 return Shrink(isolate, table, slack_capacity); 17219 } 17220 17221 namespace { 17222 17223 class StringTableNoAllocateKey : public StringTableKey { 17224 public: 17225 StringTableNoAllocateKey(String* string, uint64_t seed) 17226 : StringTableKey(0), string_(string) { 17227 StringShape shape(string); 17228 one_byte_ = shape.HasOnlyOneByteChars(); 17229 DCHECK(!shape.IsInternalized()); 17230 DCHECK(!shape.IsThin()); 17231 int length = string->length(); 17232 if (shape.IsCons() && length <= String::kMaxHashCalcLength) { 17233 special_flattening_ = true; 17234 uint32_t hash_field = 0; 17235 if (one_byte_) { 17236 if (V8_LIKELY(length <= 17237 static_cast<int>(arraysize(one_byte_buffer_)))) { 17238 one_byte_content_ = one_byte_buffer_; 17239 } else { 17240 one_byte_content_ = new uint8_t[length]; 17241 } 17242 String::WriteToFlat(string, one_byte_content_, 0, length); 17243 hash_field = 17244 StringHasher::HashSequentialString(one_byte_content_, length, seed); 17245 } else { 17246 if (V8_LIKELY(length <= 17247 static_cast<int>(arraysize(two_byte_buffer_)))) { 17248 two_byte_content_ = two_byte_buffer_; 17249 } else { 17250 two_byte_content_ = new uint16_t[length]; 17251 } 17252 String::WriteToFlat(string, two_byte_content_, 0, length); 17253 hash_field = 17254 StringHasher::HashSequentialString(two_byte_content_, length, seed); 17255 } 17256 string->set_hash_field(hash_field); 17257 } else { 17258 special_flattening_ = false; 17259 one_byte_content_ = nullptr; 17260 string->Hash(); 17261 } 17262 17263 DCHECK(string->HasHashCode()); 17264 set_hash_field(string->hash_field()); 17265 } 17266 17267 ~StringTableNoAllocateKey() { 17268 if (one_byte_) { 17269 if (one_byte_content_ != one_byte_buffer_) delete[] one_byte_content_; 17270 } else { 17271 if (two_byte_content_ != two_byte_buffer_) delete[] two_byte_content_; 17272 } 17273 } 17274 17275 bool IsMatch(Object* otherstring) override { 17276 String* other = String::cast(otherstring); 17277 DCHECK(other->IsInternalizedString()); 17278 DCHECK(other->IsFlat()); 17279 if (Hash() != other->Hash()) return false; 17280 int len = string_->length(); 17281 if (len != other->length()) return false; 17282 17283 if (!special_flattening_) { 17284 if (string_->Get(0) != other->Get(0)) return false; 17285 if (string_->IsFlat()) { 17286 StringShape shape1(string_); 17287 StringShape shape2(other); 17288 if (shape1.encoding_tag() == kOneByteStringTag && 17289 shape2.encoding_tag() == kOneByteStringTag) { 17290 String::FlatContent flat1 = string_->GetFlatContent(); 17291 String::FlatContent flat2 = other->GetFlatContent(); 17292 return CompareRawStringContents(flat1.ToOneByteVector().start(), 17293 flat2.ToOneByteVector().start(), len); 17294 } 17295 if (shape1.encoding_tag() == kTwoByteStringTag && 17296 shape2.encoding_tag() == kTwoByteStringTag) { 17297 String::FlatContent flat1 = string_->GetFlatContent(); 17298 String::FlatContent flat2 = other->GetFlatContent(); 17299 return CompareRawStringContents(flat1.ToUC16Vector().start(), 17300 flat2.ToUC16Vector().start(), len); 17301 } 17302 } 17303 StringComparator comparator; 17304 return comparator.Equals(string_, other); 17305 } 17306 17307 String::FlatContent flat_content = other->GetFlatContent(); 17308 if (one_byte_) { 17309 if (flat_content.IsOneByte()) { 17310 return CompareRawStringContents( 17311 one_byte_content_, flat_content.ToOneByteVector().start(), len); 17312 } else { 17313 DCHECK(flat_content.IsTwoByte()); 17314 for (int i = 0; i < len; i++) { 17315 if (flat_content.Get(i) != one_byte_content_[i]) return false; 17316 } 17317 return true; 17318 } 17319 } else { 17320 if (flat_content.IsTwoByte()) { 17321 return CompareRawStringContents( 17322 two_byte_content_, flat_content.ToUC16Vector().start(), len); 17323 } else { 17324 DCHECK(flat_content.IsOneByte()); 17325 for (int i = 0; i < len; i++) { 17326 if (flat_content.Get(i) != two_byte_content_[i]) return false; 17327 } 17328 return true; 17329 } 17330 } 17331 } 17332 17333 V8_WARN_UNUSED_RESULT Handle<String> AsHandle(Isolate* isolate) override { 17334 UNREACHABLE(); 17335 } 17336 17337 private: 17338 String* string_; 17339 bool one_byte_; 17340 bool special_flattening_; 17341 union { 17342 uint8_t* one_byte_content_; 17343 uint16_t* two_byte_content_; 17344 }; 17345 union { 17346 uint8_t one_byte_buffer_[256]; 17347 uint16_t two_byte_buffer_[128]; 17348 }; 17349 }; 17350 17351 } // namespace 17352 17353 // static 17354 Object* StringTable::LookupStringIfExists_NoAllocate(Isolate* isolate, 17355 String* string) { 17356 DisallowHeapAllocation no_gc; 17357 Heap* heap = isolate->heap(); 17358 StringTable* table = heap->string_table(); 17359 17360 StringTableNoAllocateKey key(string, heap->HashSeed()); 17361 17362 // String could be an array index. 17363 uint32_t hash = string->hash_field(); 17364 17365 // Valid array indices are >= 0, so they cannot be mixed up with any of 17366 // the result sentinels, which are negative. 17367 STATIC_ASSERT( 17368 !String::ArrayIndexValueBits::is_valid(ResultSentinel::kUnsupported)); 17369 STATIC_ASSERT( 17370 !String::ArrayIndexValueBits::is_valid(ResultSentinel::kNotFound)); 17371 17372 if (Name::ContainsCachedArrayIndex(hash)) { 17373 return Smi::FromInt(String::ArrayIndexValueBits::decode(hash)); 17374 } 17375 if ((hash & Name::kIsNotArrayIndexMask) == 0) { 17376 // It is an indexed, but it's not cached. 17377 return Smi::FromInt(ResultSentinel::kUnsupported); 17378 } 17379 17380 DCHECK(!string->IsInternalizedString()); 17381 int entry = table->FindEntry(ReadOnlyRoots(isolate), &key, key.Hash()); 17382 if (entry != kNotFound) { 17383 String* internalized = String::cast(table->KeyAt(entry)); 17384 if (FLAG_thin_strings) { 17385 MakeStringThin(string, internalized, isolate); 17386 } 17387 return internalized; 17388 } 17389 // A string that's not an array index, and not in the string table, 17390 // cannot have been used as a property name before. 17391 return Smi::FromInt(ResultSentinel::kNotFound); 17392 } 17393 17394 String* StringTable::ForwardStringIfExists(Isolate* isolate, 17395 StringTableKey* key, 17396 String* string) { 17397 Handle<StringTable> table = isolate->factory()->string_table(); 17398 int entry = table->FindEntry(isolate, key); 17399 if (entry == kNotFound) return nullptr; 17400 17401 String* canonical = String::cast(table->KeyAt(entry)); 17402 if (canonical != string) MakeStringThin(string, canonical, isolate); 17403 return canonical; 17404 } 17405 17406 Handle<StringSet> StringSet::New(Isolate* isolate) { 17407 return HashTable::New(isolate, 0); 17408 } 17409 17410 Handle<StringSet> StringSet::Add(Isolate* isolate, Handle<StringSet> stringset, 17411 Handle<String> name) { 17412 if (!stringset->Has(isolate, name)) { 17413 stringset = EnsureCapacity(isolate, stringset, 1); 17414 uint32_t hash = ShapeT::Hash(isolate, *name); 17415 int entry = stringset->FindInsertionEntry(hash); 17416 stringset->set(EntryToIndex(entry), *name); 17417 stringset->ElementAdded(); 17418 } 17419 return stringset; 17420 } 17421 17422 bool StringSet::Has(Isolate* isolate, Handle<String> name) { 17423 return FindEntry(isolate, *name) != kNotFound; 17424 } 17425 17426 Handle<ObjectHashSet> ObjectHashSet::Add(Isolate* isolate, 17427 Handle<ObjectHashSet> set, 17428 Handle<Object> key) { 17429 int32_t hash = key->GetOrCreateHash(isolate)->value(); 17430 if (!set->Has(isolate, key, hash)) { 17431 set = EnsureCapacity(isolate, set, 1); 17432 int entry = set->FindInsertionEntry(hash); 17433 set->set(EntryToIndex(entry), *key); 17434 set->ElementAdded(); 17435 } 17436 return set; 17437 } 17438 17439 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src, 17440 Handle<SharedFunctionInfo> shared, 17441 LanguageMode language_mode) { 17442 Isolate* isolate = GetIsolate(); 17443 StringSharedKey key(src, shared, language_mode, kNoSourcePosition); 17444 int entry = FindEntry(isolate, &key); 17445 if (entry == kNotFound) return isolate->factory()->undefined_value(); 17446 int index = EntryToIndex(entry); 17447 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value(); 17448 return Handle<Object>(get(index + 1), isolate); 17449 } 17450 17451 namespace { 17452 17453 const int kLiteralEntryLength = 2; 17454 const int kLiteralInitialLength = 2; 17455 const int kLiteralContextOffset = 0; 17456 const int kLiteralLiteralsOffset = 1; 17457 17458 int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry, 17459 Context* native_context) { 17460 DisallowHeapAllocation no_gc; 17461 DCHECK(native_context->IsNativeContext()); 17462 Object* obj = cache->get(cache_entry); 17463 17464 // Check that there's no confusion between FixedArray and WeakFixedArray (the 17465 // object used to be a FixedArray here). 17466 DCHECK(!obj->IsFixedArray()); 17467 if (obj->IsWeakFixedArray()) { 17468 WeakFixedArray* literals_map = WeakFixedArray::cast(obj); 17469 int length = literals_map->length(); 17470 for (int i = 0; i < length; i += kLiteralEntryLength) { 17471 DCHECK(literals_map->Get(i + kLiteralContextOffset) 17472 ->IsWeakOrClearedHeapObject()); 17473 if (literals_map->Get(i + kLiteralContextOffset) == 17474 HeapObjectReference::Weak(native_context)) { 17475 return i; 17476 } 17477 } 17478 } 17479 return -1; 17480 } 17481 17482 void AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache, int cache_entry, 17483 Handle<Context> native_context, 17484 Handle<FeedbackCell> feedback_cell) { 17485 Isolate* isolate = native_context->GetIsolate(); 17486 DCHECK(native_context->IsNativeContext()); 17487 STATIC_ASSERT(kLiteralEntryLength == 2); 17488 Handle<WeakFixedArray> new_literals_map; 17489 int entry; 17490 17491 Object* obj = cache->get(cache_entry); 17492 17493 // Check that there's no confusion between FixedArray and WeakFixedArray (the 17494 // object used to be a FixedArray here). 17495 DCHECK(!obj->IsFixedArray()); 17496 if (!obj->IsWeakFixedArray() || WeakFixedArray::cast(obj)->length() == 0) { 17497 new_literals_map = 17498 isolate->factory()->NewWeakFixedArray(kLiteralInitialLength, TENURED); 17499 entry = 0; 17500 } else { 17501 Handle<WeakFixedArray> old_literals_map(WeakFixedArray::cast(obj), isolate); 17502 entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context); 17503 if (entry >= 0) { 17504 // Just set the code of the entry. 17505 old_literals_map->Set(entry + kLiteralLiteralsOffset, 17506 HeapObjectReference::Weak(*feedback_cell)); 17507 return; 17508 } 17509 17510 // Can we reuse an entry? 17511 DCHECK_LT(entry, 0); 17512 int length = old_literals_map->length(); 17513 for (int i = 0; i < length; i += kLiteralEntryLength) { 17514 if (old_literals_map->Get(i + kLiteralContextOffset) 17515 ->IsClearedWeakHeapObject()) { 17516 new_literals_map = old_literals_map; 17517 entry = i; 17518 break; 17519 } 17520 } 17521 17522 if (entry < 0) { 17523 // Copy old optimized code map and append one new entry. 17524 new_literals_map = isolate->factory()->CopyWeakFixedArrayAndGrow( 17525 old_literals_map, kLiteralEntryLength, TENURED); 17526 entry = old_literals_map->length(); 17527 } 17528 } 17529 17530 new_literals_map->Set(entry + kLiteralContextOffset, 17531 HeapObjectReference::Weak(*native_context)); 17532 new_literals_map->Set(entry + kLiteralLiteralsOffset, 17533 HeapObjectReference::Weak(*feedback_cell)); 17534 17535 #ifdef DEBUG 17536 for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) { 17537 MaybeObject* object = new_literals_map->Get(i + kLiteralContextOffset); 17538 DCHECK(object->IsClearedWeakHeapObject() || 17539 object->ToWeakHeapObject()->IsNativeContext()); 17540 object = new_literals_map->Get(i + kLiteralLiteralsOffset); 17541 DCHECK(object->IsClearedWeakHeapObject() || 17542 object->ToWeakHeapObject()->IsFeedbackCell()); 17543 } 17544 #endif 17545 17546 Object* old_literals_map = cache->get(cache_entry); 17547 if (old_literals_map != *new_literals_map) { 17548 cache->set(cache_entry, *new_literals_map); 17549 } 17550 } 17551 17552 FeedbackCell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry, 17553 Context* native_context) { 17554 FeedbackCell* result = nullptr; 17555 int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context); 17556 if (entry >= 0) { 17557 WeakFixedArray* literals_map = 17558 WeakFixedArray::cast(cache->get(cache_entry)); 17559 DCHECK_LE(entry + kLiteralEntryLength, literals_map->length()); 17560 MaybeObject* object = literals_map->Get(entry + kLiteralLiteralsOffset); 17561 17562 result = object->IsClearedWeakHeapObject() 17563 ? nullptr 17564 : FeedbackCell::cast(object->ToWeakHeapObject()); 17565 } 17566 DCHECK(result == nullptr || result->IsFeedbackCell()); 17567 return result; 17568 } 17569 17570 } // namespace 17571 17572 MaybeHandle<SharedFunctionInfo> CompilationCacheTable::LookupScript( 17573 Handle<String> src, Handle<Context> native_context, 17574 LanguageMode language_mode) { 17575 // We use the empty function SFI as part of the key. Although the 17576 // empty_function is native context dependent, the SFI is de-duped on 17577 // snapshot builds by the PartialSnapshotCache, and so this does not prevent 17578 // reuse of scripts in the compilation cache across native contexts. 17579 Handle<SharedFunctionInfo> shared(native_context->empty_function()->shared(), 17580 native_context->GetIsolate()); 17581 StringSharedKey key(src, shared, language_mode, kNoSourcePosition); 17582 int entry = FindEntry(GetIsolate(), &key); 17583 if (entry == kNotFound) return MaybeHandle<SharedFunctionInfo>(); 17584 int index = EntryToIndex(entry); 17585 if (!get(index)->IsFixedArray()) return MaybeHandle<SharedFunctionInfo>(); 17586 Object* obj = get(index + 1); 17587 if (obj->IsSharedFunctionInfo()) { 17588 return handle(SharedFunctionInfo::cast(obj), native_context->GetIsolate()); 17589 } 17590 return MaybeHandle<SharedFunctionInfo>(); 17591 } 17592 17593 InfoCellPair CompilationCacheTable::LookupEval( 17594 Handle<String> src, Handle<SharedFunctionInfo> outer_info, 17595 Handle<Context> native_context, LanguageMode language_mode, int position) { 17596 InfoCellPair empty_result; 17597 StringSharedKey key(src, outer_info, language_mode, position); 17598 int entry = FindEntry(GetIsolate(), &key); 17599 if (entry == kNotFound) return empty_result; 17600 int index = EntryToIndex(entry); 17601 if (!get(index)->IsFixedArray()) return empty_result; 17602 Object* obj = get(EntryToIndex(entry) + 1); 17603 if (obj->IsSharedFunctionInfo()) { 17604 FeedbackCell* feedback_cell = 17605 SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context); 17606 return InfoCellPair(SharedFunctionInfo::cast(obj), feedback_cell); 17607 } 17608 return empty_result; 17609 } 17610 17611 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src, 17612 JSRegExp::Flags flags) { 17613 Isolate* isolate = GetIsolate(); 17614 DisallowHeapAllocation no_allocation; 17615 RegExpKey key(src, flags); 17616 int entry = FindEntry(isolate, &key); 17617 if (entry == kNotFound) return isolate->factory()->undefined_value(); 17618 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate); 17619 } 17620 17621 Handle<CompilationCacheTable> CompilationCacheTable::Put( 17622 Handle<CompilationCacheTable> cache, Handle<String> src, 17623 Handle<SharedFunctionInfo> shared, LanguageMode language_mode, 17624 Handle<Object> value) { 17625 Isolate* isolate = cache->GetIsolate(); 17626 StringSharedKey key(src, shared, language_mode, kNoSourcePosition); 17627 Handle<Object> k = key.AsHandle(isolate); 17628 cache = EnsureCapacity(isolate, cache, 1); 17629 int entry = cache->FindInsertionEntry(key.Hash()); 17630 cache->set(EntryToIndex(entry), *k); 17631 cache->set(EntryToIndex(entry) + 1, *value); 17632 cache->ElementAdded(); 17633 return cache; 17634 } 17635 17636 Handle<CompilationCacheTable> CompilationCacheTable::PutScript( 17637 Handle<CompilationCacheTable> cache, Handle<String> src, 17638 Handle<Context> native_context, LanguageMode language_mode, 17639 Handle<SharedFunctionInfo> value) { 17640 Isolate* isolate = native_context->GetIsolate(); 17641 // We use the empty function SFI as part of the key. Although the 17642 // empty_function is native context dependent, the SFI is de-duped on 17643 // snapshot builds by the PartialSnapshotCache, and so this does not prevent 17644 // reuse of scripts in the compilation cache across native contexts. 17645 Handle<SharedFunctionInfo> shared(native_context->empty_function()->shared(), 17646 isolate); 17647 StringSharedKey key(src, shared, language_mode, kNoSourcePosition); 17648 Handle<Object> k = key.AsHandle(isolate); 17649 cache = EnsureCapacity(isolate, cache, 1); 17650 int entry = cache->FindInsertionEntry(key.Hash()); 17651 cache->set(EntryToIndex(entry), *k); 17652 cache->set(EntryToIndex(entry) + 1, *value); 17653 cache->ElementAdded(); 17654 return cache; 17655 } 17656 17657 Handle<CompilationCacheTable> CompilationCacheTable::PutEval( 17658 Handle<CompilationCacheTable> cache, Handle<String> src, 17659 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value, 17660 Handle<Context> native_context, Handle<FeedbackCell> feedback_cell, 17661 int position) { 17662 Isolate* isolate = native_context->GetIsolate(); 17663 StringSharedKey key(src, outer_info, value->language_mode(), position); 17664 { 17665 Handle<Object> k = key.AsHandle(isolate); 17666 int entry = cache->FindEntry(isolate, &key); 17667 if (entry != kNotFound) { 17668 cache->set(EntryToIndex(entry), *k); 17669 cache->set(EntryToIndex(entry) + 1, *value); 17670 // AddToFeedbackCellsMap may allocate a new sub-array to live in the 17671 // entry, but it won't change the cache array. Therefore EntryToIndex 17672 // and entry remains correct. 17673 AddToFeedbackCellsMap(cache, EntryToIndex(entry) + 2, native_context, 17674 feedback_cell); 17675 return cache; 17676 } 17677 } 17678 17679 cache = EnsureCapacity(isolate, cache, 1); 17680 int entry = cache->FindInsertionEntry(key.Hash()); 17681 Handle<Object> k = 17682 isolate->factory()->NewNumber(static_cast<double>(key.Hash())); 17683 cache->set(EntryToIndex(entry), *k); 17684 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations)); 17685 cache->ElementAdded(); 17686 return cache; 17687 } 17688 17689 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp( 17690 Isolate* isolate, Handle<CompilationCacheTable> cache, Handle<String> src, 17691 JSRegExp::Flags flags, Handle<FixedArray> value) { 17692 RegExpKey key(src, flags); 17693 cache = EnsureCapacity(isolate, cache, 1); 17694 int entry = cache->FindInsertionEntry(key.Hash()); 17695 // We store the value in the key slot, and compare the search key 17696 // to the stored value with a custon IsMatch function during lookups. 17697 cache->set(EntryToIndex(entry), *value); 17698 cache->set(EntryToIndex(entry) + 1, *value); 17699 cache->ElementAdded(); 17700 return cache; 17701 } 17702 17703 17704 void CompilationCacheTable::Age() { 17705 DisallowHeapAllocation no_allocation; 17706 Object* the_hole_value = GetReadOnlyRoots().the_hole_value(); 17707 for (int entry = 0, size = Capacity(); entry < size; entry++) { 17708 int entry_index = EntryToIndex(entry); 17709 int value_index = entry_index + 1; 17710 17711 if (get(entry_index)->IsNumber()) { 17712 Smi* count = Smi::cast(get(value_index)); 17713 count = Smi::FromInt(count->value() - 1); 17714 if (count->value() == 0) { 17715 NoWriteBarrierSet(this, entry_index, the_hole_value); 17716 NoWriteBarrierSet(this, value_index, the_hole_value); 17717 ElementRemoved(); 17718 } else { 17719 NoWriteBarrierSet(this, value_index, count); 17720 } 17721 } else if (get(entry_index)->IsFixedArray()) { 17722 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index)); 17723 if (info->IsInterpreted() && info->GetBytecodeArray()->IsOld()) { 17724 for (int i = 0; i < kEntrySize; i++) { 17725 NoWriteBarrierSet(this, entry_index + i, the_hole_value); 17726 } 17727 ElementRemoved(); 17728 } 17729 } 17730 } 17731 } 17732 17733 17734 void CompilationCacheTable::Remove(Object* value) { 17735 DisallowHeapAllocation no_allocation; 17736 Object* the_hole_value = GetReadOnlyRoots().the_hole_value(); 17737 for (int entry = 0, size = Capacity(); entry < size; entry++) { 17738 int entry_index = EntryToIndex(entry); 17739 int value_index = entry_index + 1; 17740 if (get(value_index) == value) { 17741 for (int i = 0; i < kEntrySize; i++) { 17742 NoWriteBarrierSet(this, entry_index + i, the_hole_value); 17743 } 17744 ElementRemoved(); 17745 } 17746 } 17747 return; 17748 } 17749 17750 template <typename Derived, typename Shape> 17751 Handle<Derived> BaseNameDictionary<Derived, Shape>::New( 17752 Isolate* isolate, int at_least_space_for, PretenureFlag pretenure, 17753 MinimumCapacity capacity_option) { 17754 DCHECK_LE(0, at_least_space_for); 17755 Handle<Derived> dict = Dictionary<Derived, Shape>::New( 17756 isolate, at_least_space_for, pretenure, capacity_option); 17757 dict->SetHash(PropertyArray::kNoHashSentinel); 17758 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex); 17759 return dict; 17760 } 17761 17762 template <typename Derived, typename Shape> 17763 Handle<Derived> BaseNameDictionary<Derived, Shape>::EnsureCapacity( 17764 Isolate* isolate, Handle<Derived> dictionary, int n) { 17765 // Check whether there are enough enumeration indices to add n elements. 17766 if (!PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) { 17767 // If not, we generate new indices for the properties. 17768 int length = dictionary->NumberOfElements(); 17769 17770 Handle<FixedArray> iteration_order = IterationIndices(isolate, dictionary); 17771 DCHECK_EQ(length, iteration_order->length()); 17772 17773 // Iterate over the dictionary using the enumeration order and update 17774 // the dictionary with new enumeration indices. 17775 for (int i = 0; i < length; i++) { 17776 int index = Smi::ToInt(iteration_order->get(i)); 17777 DCHECK(dictionary->IsKey(dictionary->GetReadOnlyRoots(), 17778 dictionary->KeyAt(index))); 17779 17780 int enum_index = PropertyDetails::kInitialIndex + i; 17781 17782 PropertyDetails details = dictionary->DetailsAt(index); 17783 PropertyDetails new_details = details.set_index(enum_index); 17784 dictionary->DetailsAtPut(isolate, index, new_details); 17785 } 17786 17787 // Set the next enumeration index. 17788 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex + 17789 length); 17790 } 17791 return HashTable<Derived, Shape>::EnsureCapacity(isolate, dictionary, n); 17792 } 17793 17794 template <typename Derived, typename Shape> 17795 Handle<Derived> Dictionary<Derived, Shape>::DeleteEntry( 17796 Isolate* isolate, Handle<Derived> dictionary, int entry) { 17797 DCHECK(Shape::kEntrySize != 3 || 17798 dictionary->DetailsAt(entry).IsConfigurable()); 17799 dictionary->ClearEntry(isolate, entry); 17800 dictionary->ElementRemoved(); 17801 return Shrink(isolate, dictionary); 17802 } 17803 17804 template <typename Derived, typename Shape> 17805 Handle<Derived> Dictionary<Derived, Shape>::AtPut(Isolate* isolate, 17806 Handle<Derived> dictionary, 17807 Key key, Handle<Object> value, 17808 PropertyDetails details) { 17809 int entry = dictionary->FindEntry(isolate, key); 17810 17811 // If the entry is present set the value; 17812 if (entry == Dictionary::kNotFound) { 17813 return Derived::Add(isolate, dictionary, key, value, details); 17814 } 17815 17816 // We don't need to copy over the enumeration index. 17817 dictionary->ValueAtPut(entry, *value); 17818 if (Shape::kEntrySize == 3) dictionary->DetailsAtPut(isolate, entry, details); 17819 return dictionary; 17820 } 17821 17822 template <typename Derived, typename Shape> 17823 Handle<Derived> 17824 BaseNameDictionary<Derived, Shape>::AddNoUpdateNextEnumerationIndex( 17825 Isolate* isolate, Handle<Derived> dictionary, Key key, Handle<Object> value, 17826 PropertyDetails details, int* entry_out) { 17827 // Insert element at empty or deleted entry 17828 return Dictionary<Derived, Shape>::Add(isolate, dictionary, key, value, 17829 details, entry_out); 17830 } 17831 17832 // GCC workaround: Explicitly instantiate template method for NameDictionary 17833 // to avoid "undefined reference" issues during linking. 17834 template Handle<NameDictionary> 17835 BaseNameDictionary<NameDictionary, NameDictionaryShape>:: 17836 AddNoUpdateNextEnumerationIndex(Isolate* isolate, Handle<NameDictionary>, 17837 Handle<Name>, Handle<Object>, 17838 PropertyDetails, int*); 17839 17840 template <typename Derived, typename Shape> 17841 Handle<Derived> BaseNameDictionary<Derived, Shape>::Add( 17842 Isolate* isolate, Handle<Derived> dictionary, Key key, Handle<Object> value, 17843 PropertyDetails details, int* entry_out) { 17844 // Insert element at empty or deleted entry 17845 DCHECK_EQ(0, details.dictionary_index()); 17846 // Assign an enumeration index to the property and update 17847 // SetNextEnumerationIndex. 17848 int index = dictionary->NextEnumerationIndex(); 17849 details = details.set_index(index); 17850 dictionary->SetNextEnumerationIndex(index + 1); 17851 return AddNoUpdateNextEnumerationIndex(isolate, dictionary, key, value, 17852 details, entry_out); 17853 } 17854 17855 template <typename Derived, typename Shape> 17856 Handle<Derived> Dictionary<Derived, Shape>::Add(Isolate* isolate, 17857 Handle<Derived> dictionary, 17858 Key key, Handle<Object> value, 17859 PropertyDetails details, 17860 int* entry_out) { 17861 uint32_t hash = Shape::Hash(isolate, key); 17862 // Valdate key is absent. 17863 SLOW_DCHECK((dictionary->FindEntry(isolate, key) == Dictionary::kNotFound)); 17864 // Check whether the dictionary should be extended. 17865 dictionary = Derived::EnsureCapacity(isolate, dictionary, 1); 17866 17867 // Compute the key object. 17868 Handle<Object> k = Shape::AsHandle(isolate, key); 17869 17870 uint32_t entry = dictionary->FindInsertionEntry(hash); 17871 dictionary->SetEntry(isolate, entry, *k, *value, details); 17872 DCHECK(dictionary->KeyAt(entry)->IsNumber() || 17873 Shape::Unwrap(dictionary->KeyAt(entry))->IsUniqueName()); 17874 dictionary->ElementAdded(); 17875 if (entry_out) *entry_out = entry; 17876 return dictionary; 17877 } 17878 17879 // static 17880 Handle<SimpleNumberDictionary> SimpleNumberDictionary::Set( 17881 Isolate* isolate, Handle<SimpleNumberDictionary> dictionary, uint32_t key, 17882 Handle<Object> value) { 17883 return AtPut(isolate, dictionary, key, value, PropertyDetails::Empty()); 17884 } 17885 17886 bool NumberDictionary::HasComplexElements() { 17887 if (!requires_slow_elements()) return false; 17888 ReadOnlyRoots roots = GetReadOnlyRoots(); 17889 int capacity = this->Capacity(); 17890 for (int i = 0; i < capacity; i++) { 17891 Object* k; 17892 if (!this->ToKey(roots, i, &k)) continue; 17893 PropertyDetails details = this->DetailsAt(i); 17894 if (details.kind() == kAccessor) return true; 17895 PropertyAttributes attr = details.attributes(); 17896 if (attr & ALL_ATTRIBUTES_MASK) return true; 17897 } 17898 return false; 17899 } 17900 17901 void NumberDictionary::UpdateMaxNumberKey(uint32_t key, 17902 Handle<JSObject> dictionary_holder) { 17903 DisallowHeapAllocation no_allocation; 17904 // If the dictionary requires slow elements an element has already 17905 // been added at a high index. 17906 if (requires_slow_elements()) return; 17907 // Check if this index is high enough that we should require slow 17908 // elements. 17909 if (key > kRequiresSlowElementsLimit) { 17910 if (!dictionary_holder.is_null()) { 17911 dictionary_holder->RequireSlowElements(this); 17912 } 17913 set_requires_slow_elements(); 17914 return; 17915 } 17916 // Update max key value. 17917 Object* max_index_object = get(kMaxNumberKeyIndex); 17918 if (!max_index_object->IsSmi() || max_number_key() < key) { 17919 FixedArray::set(kMaxNumberKeyIndex, 17920 Smi::FromInt(key << kRequiresSlowElementsTagSize)); 17921 } 17922 } 17923 17924 Handle<NumberDictionary> NumberDictionary::Set( 17925 Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key, 17926 Handle<Object> value, Handle<JSObject> dictionary_holder, 17927 PropertyDetails details) { 17928 dictionary->UpdateMaxNumberKey(key, dictionary_holder); 17929 return AtPut(isolate, dictionary, key, value, details); 17930 } 17931 17932 void NumberDictionary::CopyValuesTo(FixedArray* elements) { 17933 ReadOnlyRoots roots = GetReadOnlyRoots(); 17934 int pos = 0; 17935 int capacity = this->Capacity(); 17936 DisallowHeapAllocation no_gc; 17937 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); 17938 for (int i = 0; i < capacity; i++) { 17939 Object* k; 17940 if (this->ToKey(roots, i, &k)) { 17941 elements->set(pos++, this->ValueAt(i), mode); 17942 } 17943 } 17944 DCHECK_EQ(pos, elements->length()); 17945 } 17946 17947 template <typename Derived, typename Shape> 17948 int Dictionary<Derived, Shape>::NumberOfEnumerableProperties() { 17949 ReadOnlyRoots roots = this->GetReadOnlyRoots(); 17950 int capacity = this->Capacity(); 17951 int result = 0; 17952 for (int i = 0; i < capacity; i++) { 17953 Object* k; 17954 if (!this->ToKey(roots, i, &k)) continue; 17955 if (k->FilterKey(ENUMERABLE_STRINGS)) continue; 17956 PropertyDetails details = this->DetailsAt(i); 17957 PropertyAttributes attr = details.attributes(); 17958 if ((attr & ONLY_ENUMERABLE) == 0) result++; 17959 } 17960 return result; 17961 } 17962 17963 17964 template <typename Dictionary> 17965 struct EnumIndexComparator { 17966 explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {} 17967 bool operator()(const base::AtomicElement<Smi*>& a, 17968 const base::AtomicElement<Smi*>& b) { 17969 PropertyDetails da(dict->DetailsAt(a.value()->value())); 17970 PropertyDetails db(dict->DetailsAt(b.value()->value())); 17971 return da.dictionary_index() < db.dictionary_index(); 17972 } 17973 Dictionary* dict; 17974 }; 17975 17976 template <typename Derived, typename Shape> 17977 void BaseNameDictionary<Derived, Shape>::CopyEnumKeysTo( 17978 Isolate* isolate, Handle<Derived> dictionary, Handle<FixedArray> storage, 17979 KeyCollectionMode mode, KeyAccumulator* accumulator) { 17980 DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr); 17981 int length = storage->length(); 17982 int capacity = dictionary->Capacity(); 17983 int properties = 0; 17984 ReadOnlyRoots roots(isolate); 17985 for (int i = 0; i < capacity; i++) { 17986 Object* key; 17987 if (!dictionary->ToKey(roots, i, &key)) continue; 17988 bool is_shadowing_key = false; 17989 if (key->IsSymbol()) continue; 17990 PropertyDetails details = dictionary->DetailsAt(i); 17991 if (details.IsDontEnum()) { 17992 if (mode == KeyCollectionMode::kIncludePrototypes) { 17993 is_shadowing_key = true; 17994 } else { 17995 continue; 17996 } 17997 } 17998 if (is_shadowing_key) { 17999 accumulator->AddShadowingKey(key); 18000 continue; 18001 } else { 18002 storage->set(properties, Smi::FromInt(i)); 18003 } 18004 properties++; 18005 if (mode == KeyCollectionMode::kOwnOnly && properties == length) break; 18006 } 18007 18008 CHECK_EQ(length, properties); 18009 DisallowHeapAllocation no_gc; 18010 Derived* raw_dictionary = *dictionary; 18011 FixedArray* raw_storage = *storage; 18012 EnumIndexComparator<Derived> cmp(raw_dictionary); 18013 // Use AtomicElement wrapper to ensure that std::sort uses atomic load and 18014 // store operations that are safe for concurrent marking. 18015 base::AtomicElement<Smi*>* start = 18016 reinterpret_cast<base::AtomicElement<Smi*>*>( 18017 storage->GetFirstElementAddress()); 18018 std::sort(start, start + length, cmp); 18019 for (int i = 0; i < length; i++) { 18020 int index = Smi::ToInt(raw_storage->get(i)); 18021 raw_storage->set(i, raw_dictionary->NameAt(index)); 18022 } 18023 } 18024 18025 template <typename Derived, typename Shape> 18026 Handle<FixedArray> BaseNameDictionary<Derived, Shape>::IterationIndices( 18027 Isolate* isolate, Handle<Derived> dictionary) { 18028 int capacity = dictionary->Capacity(); 18029 int length = dictionary->NumberOfElements(); 18030 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); 18031 ReadOnlyRoots roots(isolate); 18032 int array_size = 0; 18033 { 18034 DisallowHeapAllocation no_gc; 18035 Derived* raw_dictionary = *dictionary; 18036 for (int i = 0; i < capacity; i++) { 18037 Object* k; 18038 if (!raw_dictionary->ToKey(roots, i, &k)) continue; 18039 array->set(array_size++, Smi::FromInt(i)); 18040 } 18041 18042 DCHECK_EQ(array_size, length); 18043 18044 EnumIndexComparator<Derived> cmp(raw_dictionary); 18045 // Use AtomicElement wrapper to ensure that std::sort uses atomic load and 18046 // store operations that are safe for concurrent marking. 18047 base::AtomicElement<Smi*>* start = 18048 reinterpret_cast<base::AtomicElement<Smi*>*>( 18049 array->GetFirstElementAddress()); 18050 std::sort(start, start + array_size, cmp); 18051 } 18052 return FixedArray::ShrinkOrEmpty(isolate, array, array_size); 18053 } 18054 18055 template <typename Derived, typename Shape> 18056 void BaseNameDictionary<Derived, Shape>::CollectKeysTo( 18057 Handle<Derived> dictionary, KeyAccumulator* keys) { 18058 Isolate* isolate = keys->isolate(); 18059 ReadOnlyRoots roots(isolate); 18060 int capacity = dictionary->Capacity(); 18061 Handle<FixedArray> array = 18062 isolate->factory()->NewFixedArray(dictionary->NumberOfElements()); 18063 int array_size = 0; 18064 PropertyFilter filter = keys->filter(); 18065 { 18066 DisallowHeapAllocation no_gc; 18067 Derived* raw_dictionary = *dictionary; 18068 for (int i = 0; i < capacity; i++) { 18069 Object* k; 18070 if (!raw_dictionary->ToKey(roots, i, &k)) continue; 18071 if (k->FilterKey(filter)) continue; 18072 PropertyDetails details = raw_dictionary->DetailsAt(i); 18073 if ((details.attributes() & filter) != 0) { 18074 keys->AddShadowingKey(k); 18075 continue; 18076 } 18077 if (filter & ONLY_ALL_CAN_READ) { 18078 if (details.kind() != kAccessor) continue; 18079 Object* accessors = raw_dictionary->ValueAt(i); 18080 if (!accessors->IsAccessorInfo()) continue; 18081 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; 18082 } 18083 array->set(array_size++, Smi::FromInt(i)); 18084 } 18085 18086 EnumIndexComparator<Derived> cmp(raw_dictionary); 18087 // Use AtomicElement wrapper to ensure that std::sort uses atomic load and 18088 // store operations that are safe for concurrent marking. 18089 base::AtomicElement<Smi*>* start = 18090 reinterpret_cast<base::AtomicElement<Smi*>*>( 18091 array->GetFirstElementAddress()); 18092 std::sort(start, start + array_size, cmp); 18093 } 18094 18095 bool has_seen_symbol = false; 18096 for (int i = 0; i < array_size; i++) { 18097 int index = Smi::ToInt(array->get(i)); 18098 Object* key = dictionary->NameAt(index); 18099 if (key->IsSymbol()) { 18100 has_seen_symbol = true; 18101 continue; 18102 } 18103 keys->AddKey(key, DO_NOT_CONVERT); 18104 } 18105 if (has_seen_symbol) { 18106 for (int i = 0; i < array_size; i++) { 18107 int index = Smi::ToInt(array->get(i)); 18108 Object* key = dictionary->NameAt(index); 18109 if (!key->IsSymbol()) continue; 18110 keys->AddKey(key, DO_NOT_CONVERT); 18111 } 18112 } 18113 } 18114 18115 // Backwards lookup (slow). 18116 template <typename Derived, typename Shape> 18117 Object* Dictionary<Derived, Shape>::SlowReverseLookup(Object* value) { 18118 Derived* dictionary = Derived::cast(this); 18119 ReadOnlyRoots roots = dictionary->GetReadOnlyRoots(); 18120 int capacity = dictionary->Capacity(); 18121 for (int i = 0; i < capacity; i++) { 18122 Object* k; 18123 if (!dictionary->ToKey(roots, i, &k)) continue; 18124 Object* e = dictionary->ValueAt(i); 18125 if (e == value) return k; 18126 } 18127 return roots.undefined_value(); 18128 } 18129 18130 template <typename Derived, typename Shape> 18131 void ObjectHashTableBase<Derived, Shape>::FillEntriesWithHoles( 18132 Handle<Derived> table) { 18133 int length = table->length(); 18134 for (int i = Derived::EntryToIndex(0); i < length; i++) { 18135 table->set_the_hole(i); 18136 } 18137 } 18138 18139 template <typename Derived, typename Shape> 18140 Object* ObjectHashTableBase<Derived, Shape>::Lookup(ReadOnlyRoots roots, 18141 Handle<Object> key, 18142 int32_t hash) { 18143 DisallowHeapAllocation no_gc; 18144 DCHECK(this->IsKey(roots, *key)); 18145 18146 int entry = this->FindEntry(roots, key, hash); 18147 if (entry == kNotFound) return roots.the_hole_value(); 18148 return this->get(Derived::EntryToIndex(entry) + 1); 18149 } 18150 18151 template <typename Derived, typename Shape> 18152 Object* ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key) { 18153 DisallowHeapAllocation no_gc; 18154 18155 ReadOnlyRoots roots = this->GetReadOnlyRoots(); 18156 DCHECK(this->IsKey(roots, *key)); 18157 18158 // If the object does not have an identity hash, it was never used as a key. 18159 Object* hash = key->GetHash(); 18160 if (hash->IsUndefined(roots)) { 18161 return roots.the_hole_value(); 18162 } 18163 return Lookup(roots, key, Smi::ToInt(hash)); 18164 } 18165 18166 template <typename Derived, typename Shape> 18167 Object* ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key, 18168 int32_t hash) { 18169 return Lookup(this->GetReadOnlyRoots(), key, hash); 18170 } 18171 18172 template <typename Derived, typename Shape> 18173 Object* ObjectHashTableBase<Derived, Shape>::ValueAt(int entry) { 18174 return this->get(EntryToValueIndex(entry)); 18175 } 18176 18177 template <typename Derived, typename Shape> 18178 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table, 18179 Handle<Object> key, 18180 Handle<Object> value) { 18181 Isolate* isolate = Heap::FromWritableHeapObject(*table)->isolate(); 18182 DCHECK(table->IsKey(ReadOnlyRoots(isolate), *key)); 18183 DCHECK(!value->IsTheHole(ReadOnlyRoots(isolate))); 18184 18185 // Make sure the key object has an identity hash code. 18186 int32_t hash = key->GetOrCreateHash(isolate)->value(); 18187 18188 return ObjectHashTableBase<Derived, Shape>::Put(isolate, table, key, value, 18189 hash); 18190 } 18191 18192 template <typename Derived, typename Shape> 18193 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Isolate* isolate, 18194 Handle<Derived> table, 18195 Handle<Object> key, 18196 Handle<Object> value, 18197 int32_t hash) { 18198 ReadOnlyRoots roots(isolate); 18199 DCHECK(table->IsKey(roots, *key)); 18200 DCHECK(!value->IsTheHole(roots)); 18201 18202 int entry = table->FindEntry(roots, key, hash); 18203 18204 // Key is already in table, just overwrite value. 18205 if (entry != kNotFound) { 18206 table->set(Derived::EntryToIndex(entry) + 1, *value); 18207 return table; 18208 } 18209 18210 // Rehash if more than 33% of the entries are deleted entries. 18211 // TODO(jochen): Consider to shrink the fixed array in place. 18212 if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) { 18213 table->Rehash(isolate); 18214 } 18215 // If we're out of luck, we didn't get a GC recently, and so rehashing 18216 // isn't enough to avoid a crash. 18217 if (!table->HasSufficientCapacityToAdd(1)) { 18218 int nof = table->NumberOfElements() + 1; 18219 int capacity = ObjectHashTable::ComputeCapacity(nof * 2); 18220 if (capacity > ObjectHashTable::kMaxCapacity) { 18221 for (size_t i = 0; i < 2; ++i) { 18222 isolate->heap()->CollectAllGarbage( 18223 Heap::kFinalizeIncrementalMarkingMask, 18224 GarbageCollectionReason::kFullHashtable); 18225 } 18226 table->Rehash(isolate); 18227 } 18228 } 18229 18230 // Check whether the hash table should be extended. 18231 table = Derived::EnsureCapacity(isolate, table, 1); 18232 table->AddEntry(table->FindInsertionEntry(hash), *key, *value); 18233 return table; 18234 } 18235 18236 template <typename Derived, typename Shape> 18237 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove( 18238 Isolate* isolate, Handle<Derived> table, Handle<Object> key, 18239 bool* was_present) { 18240 DCHECK(table->IsKey(table->GetReadOnlyRoots(), *key)); 18241 18242 Object* hash = key->GetHash(); 18243 if (hash->IsUndefined()) { 18244 *was_present = false; 18245 return table; 18246 } 18247 18248 return Remove(isolate, table, key, was_present, Smi::ToInt(hash)); 18249 } 18250 18251 template <typename Derived, typename Shape> 18252 Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove( 18253 Isolate* isolate, Handle<Derived> table, Handle<Object> key, 18254 bool* was_present, int32_t hash) { 18255 ReadOnlyRoots roots = table->GetReadOnlyRoots(); 18256 DCHECK(table->IsKey(roots, *key)); 18257 18258 int entry = table->FindEntry(roots, key, hash); 18259 if (entry == kNotFound) { 18260 *was_present = false; 18261 return table; 18262 } 18263 18264 *was_present = true; 18265 table->RemoveEntry(entry); 18266 return Derived::Shrink(isolate, table); 18267 } 18268 18269 template <typename Derived, typename Shape> 18270 void ObjectHashTableBase<Derived, Shape>::AddEntry(int entry, Object* key, 18271 Object* value) { 18272 this->set(Derived::EntryToIndex(entry), key); 18273 this->set(Derived::EntryToIndex(entry) + 1, value); 18274 this->ElementAdded(); 18275 } 18276 18277 template <typename Derived, typename Shape> 18278 void ObjectHashTableBase<Derived, Shape>::RemoveEntry(int entry) { 18279 this->set_the_hole(Derived::EntryToIndex(entry)); 18280 this->set_the_hole(Derived::EntryToIndex(entry) + 1); 18281 this->ElementRemoved(); 18282 } 18283 18284 18285 void JSSet::Initialize(Handle<JSSet> set, Isolate* isolate) { 18286 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet(); 18287 set->set_table(*table); 18288 } 18289 18290 void JSSet::Clear(Isolate* isolate, Handle<JSSet> set) { 18291 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()), isolate); 18292 table = OrderedHashSet::Clear(isolate, table); 18293 set->set_table(*table); 18294 } 18295 18296 18297 void JSMap::Initialize(Handle<JSMap> map, Isolate* isolate) { 18298 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap(); 18299 map->set_table(*table); 18300 } 18301 18302 void JSMap::Clear(Isolate* isolate, Handle<JSMap> map) { 18303 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()), isolate); 18304 table = OrderedHashMap::Clear(isolate, table); 18305 map->set_table(*table); 18306 } 18307 18308 18309 void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection, 18310 Isolate* isolate) { 18311 Handle<EphemeronHashTable> table = EphemeronHashTable::New(isolate, 0); 18312 weak_collection->set_table(*table); 18313 } 18314 18315 18316 void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection, 18317 Handle<Object> key, Handle<Object> value, 18318 int32_t hash) { 18319 DCHECK(key->IsJSReceiver() || key->IsSymbol()); 18320 Handle<EphemeronHashTable> table( 18321 EphemeronHashTable::cast(weak_collection->table()), 18322 weak_collection->GetIsolate()); 18323 DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key)); 18324 Handle<EphemeronHashTable> new_table = EphemeronHashTable::Put( 18325 weak_collection->GetIsolate(), table, key, value, hash); 18326 weak_collection->set_table(*new_table); 18327 if (*table != *new_table) { 18328 // Zap the old table since we didn't record slots for its elements. 18329 EphemeronHashTable::FillEntriesWithHoles(table); 18330 } 18331 } 18332 18333 18334 bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection, 18335 Handle<Object> key, int32_t hash) { 18336 DCHECK(key->IsJSReceiver() || key->IsSymbol()); 18337 Handle<EphemeronHashTable> table( 18338 EphemeronHashTable::cast(weak_collection->table()), 18339 weak_collection->GetIsolate()); 18340 DCHECK(table->IsKey(weak_collection->GetReadOnlyRoots(), *key)); 18341 bool was_present = false; 18342 Handle<EphemeronHashTable> new_table = EphemeronHashTable::Remove( 18343 weak_collection->GetIsolate(), table, key, &was_present, hash); 18344 weak_collection->set_table(*new_table); 18345 if (*table != *new_table) { 18346 // Zap the old table since we didn't record slots for its elements. 18347 EphemeronHashTable::FillEntriesWithHoles(table); 18348 } 18349 return was_present; 18350 } 18351 18352 Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder, 18353 int max_entries) { 18354 Isolate* isolate = holder->GetIsolate(); 18355 Handle<EphemeronHashTable> table(EphemeronHashTable::cast(holder->table()), 18356 isolate); 18357 if (max_entries == 0 || max_entries > table->NumberOfElements()) { 18358 max_entries = table->NumberOfElements(); 18359 } 18360 int values_per_entry = holder->IsJSWeakMap() ? 2 : 1; 18361 Handle<FixedArray> entries = 18362 isolate->factory()->NewFixedArray(max_entries * values_per_entry); 18363 // Recompute max_values because GC could have removed elements from the table. 18364 if (max_entries > table->NumberOfElements()) { 18365 max_entries = table->NumberOfElements(); 18366 } 18367 18368 { 18369 DisallowHeapAllocation no_gc; 18370 ReadOnlyRoots roots = ReadOnlyRoots(isolate); 18371 int count = 0; 18372 for (int i = 0; 18373 count / values_per_entry < max_entries && i < table->Capacity(); i++) { 18374 Object* key; 18375 if (table->ToKey(roots, i, &key)) { 18376 entries->set(count++, key); 18377 if (values_per_entry > 1) { 18378 Object* value = table->Lookup(handle(key, isolate)); 18379 entries->set(count++, value); 18380 } 18381 } 18382 } 18383 DCHECK_EQ(max_entries * values_per_entry, count); 18384 } 18385 return isolate->factory()->NewJSArrayWithElements(entries); 18386 } 18387 18388 // static 18389 MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor, 18390 Handle<JSReceiver> new_target, double tv) { 18391 Isolate* const isolate = constructor->GetIsolate(); 18392 Handle<JSObject> result; 18393 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, 18394 JSObject::New(constructor, new_target), JSDate); 18395 if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) { 18396 tv = DoubleToInteger(tv) + 0.0; 18397 } else { 18398 tv = std::numeric_limits<double>::quiet_NaN(); 18399 } 18400 Handle<Object> value = isolate->factory()->NewNumber(tv); 18401 Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv)); 18402 return Handle<JSDate>::cast(result); 18403 } 18404 18405 18406 // static 18407 double JSDate::CurrentTimeValue(Isolate* isolate) { 18408 if (FLAG_log_internal_timer_events) LOG(isolate, CurrentTimeEvent()); 18409 18410 // According to ECMA-262, section 15.9.1, page 117, the precision of 18411 // the number in a Date object representing a particular instant in 18412 // time is milliseconds. Therefore, we floor the result of getting 18413 // the OS time. 18414 return Floor(V8::GetCurrentPlatform()->CurrentClockTimeMillis()); 18415 } 18416 18417 18418 // static 18419 Object* JSDate::GetField(Object* object, Smi* index) { 18420 return JSDate::cast(object)->DoGetField( 18421 static_cast<FieldIndex>(index->value())); 18422 } 18423 18424 18425 Object* JSDate::DoGetField(FieldIndex index) { 18426 DCHECK_NE(index, kDateValue); 18427 18428 DateCache* date_cache = GetIsolate()->date_cache(); 18429 18430 if (index < kFirstUncachedField) { 18431 Object* stamp = cache_stamp(); 18432 if (stamp != date_cache->stamp() && stamp->IsSmi()) { 18433 // Since the stamp is not NaN, the value is also not NaN. 18434 int64_t local_time_ms = 18435 date_cache->ToLocal(static_cast<int64_t>(value()->Number())); 18436 SetCachedFields(local_time_ms, date_cache); 18437 } 18438 switch (index) { 18439 case kYear: return year(); 18440 case kMonth: return month(); 18441 case kDay: return day(); 18442 case kWeekday: return weekday(); 18443 case kHour: return hour(); 18444 case kMinute: return min(); 18445 case kSecond: return sec(); 18446 default: UNREACHABLE(); 18447 } 18448 } 18449 18450 if (index >= kFirstUTCField) { 18451 return GetUTCField(index, value()->Number(), date_cache); 18452 } 18453 18454 double time = value()->Number(); 18455 if (std::isnan(time)) return GetReadOnlyRoots().nan_value(); 18456 18457 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time)); 18458 int days = DateCache::DaysFromTime(local_time_ms); 18459 18460 if (index == kDays) return Smi::FromInt(days); 18461 18462 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days); 18463 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000); 18464 DCHECK_EQ(index, kTimeInDay); 18465 return Smi::FromInt(time_in_day_ms); 18466 } 18467 18468 18469 Object* JSDate::GetUTCField(FieldIndex index, 18470 double value, 18471 DateCache* date_cache) { 18472 DCHECK_GE(index, kFirstUTCField); 18473 18474 if (std::isnan(value)) return GetReadOnlyRoots().nan_value(); 18475 18476 int64_t time_ms = static_cast<int64_t>(value); 18477 18478 if (index == kTimezoneOffset) { 18479 return Smi::FromInt(date_cache->TimezoneOffset(time_ms)); 18480 } 18481 18482 int days = DateCache::DaysFromTime(time_ms); 18483 18484 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days)); 18485 18486 if (index <= kDayUTC) { 18487 int year, month, day; 18488 date_cache->YearMonthDayFromDays(days, &year, &month, &day); 18489 if (index == kYearUTC) return Smi::FromInt(year); 18490 if (index == kMonthUTC) return Smi::FromInt(month); 18491 DCHECK_EQ(index, kDayUTC); 18492 return Smi::FromInt(day); 18493 } 18494 18495 int time_in_day_ms = DateCache::TimeInDay(time_ms, days); 18496 switch (index) { 18497 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000)); 18498 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60); 18499 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60); 18500 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000); 18501 case kDaysUTC: return Smi::FromInt(days); 18502 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms); 18503 default: UNREACHABLE(); 18504 } 18505 18506 UNREACHABLE(); 18507 } 18508 18509 18510 // static 18511 Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) { 18512 Isolate* const isolate = date->GetIsolate(); 18513 Handle<Object> value = isolate->factory()->NewNumber(v); 18514 bool value_is_nan = std::isnan(v); 18515 date->SetValue(*value, value_is_nan); 18516 return value; 18517 } 18518 18519 18520 void JSDate::SetValue(Object* value, bool is_value_nan) { 18521 set_value(value); 18522 if (is_value_nan) { 18523 HeapNumber* nan = GetReadOnlyRoots().nan_value(); 18524 set_cache_stamp(nan, SKIP_WRITE_BARRIER); 18525 set_year(nan, SKIP_WRITE_BARRIER); 18526 set_month(nan, SKIP_WRITE_BARRIER); 18527 set_day(nan, SKIP_WRITE_BARRIER); 18528 set_hour(nan, SKIP_WRITE_BARRIER); 18529 set_min(nan, SKIP_WRITE_BARRIER); 18530 set_sec(nan, SKIP_WRITE_BARRIER); 18531 set_weekday(nan, SKIP_WRITE_BARRIER); 18532 } else { 18533 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER); 18534 } 18535 } 18536 18537 18538 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) { 18539 int days = DateCache::DaysFromTime(local_time_ms); 18540 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days); 18541 int year, month, day; 18542 date_cache->YearMonthDayFromDays(days, &year, &month, &day); 18543 int weekday = date_cache->Weekday(days); 18544 int hour = time_in_day_ms / (60 * 60 * 1000); 18545 int min = (time_in_day_ms / (60 * 1000)) % 60; 18546 int sec = (time_in_day_ms / 1000) % 60; 18547 set_cache_stamp(date_cache->stamp()); 18548 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); 18549 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); 18550 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); 18551 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); 18552 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); 18553 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); 18554 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); 18555 } 18556 18557 int JSMessageObject::GetLineNumber() const { 18558 if (start_position() == -1) return Message::kNoLineNumberInfo; 18559 18560 Handle<Script> the_script(script(), GetIsolate()); 18561 18562 Script::PositionInfo info; 18563 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET; 18564 if (!Script::GetPositionInfo(the_script, start_position(), &info, 18565 offset_flag)) { 18566 return Message::kNoLineNumberInfo; 18567 } 18568 18569 return info.line + 1; 18570 } 18571 18572 int JSMessageObject::GetColumnNumber() const { 18573 if (start_position() == -1) return -1; 18574 18575 Handle<Script> the_script(script(), GetIsolate()); 18576 18577 Script::PositionInfo info; 18578 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET; 18579 if (!Script::GetPositionInfo(the_script, start_position(), &info, 18580 offset_flag)) { 18581 return -1; 18582 } 18583 18584 return info.column; // Note: No '+1' in contrast to GetLineNumber. 18585 } 18586 18587 Handle<String> JSMessageObject::GetSourceLine() const { 18588 Isolate* isolate = GetIsolate(); 18589 Handle<Script> the_script(script(), isolate); 18590 18591 if (the_script->type() == Script::TYPE_WASM) { 18592 return isolate->factory()->empty_string(); 18593 } 18594 18595 Script::PositionInfo info; 18596 const Script::OffsetFlag offset_flag = Script::WITH_OFFSET; 18597 if (!Script::GetPositionInfo(the_script, start_position(), &info, 18598 offset_flag)) { 18599 return isolate->factory()->empty_string(); 18600 } 18601 18602 Handle<String> src = handle(String::cast(the_script->source()), isolate); 18603 return isolate->factory()->NewSubString(src, info.line_start, info.line_end); 18604 } 18605 18606 Handle<PropertyCell> PropertyCell::InvalidateEntry( 18607 Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry) { 18608 // Swap with a copy. 18609 Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate); 18610 Handle<Name> name(cell->name(), isolate); 18611 Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(name); 18612 new_cell->set_value(cell->value()); 18613 dictionary->ValueAtPut(entry, *new_cell); 18614 bool is_the_hole = cell->value()->IsTheHole(isolate); 18615 // Cell is officially mutable henceforth. 18616 PropertyDetails details = cell->property_details(); 18617 details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized 18618 : PropertyCellType::kMutable); 18619 new_cell->set_property_details(details); 18620 // Old cell is ready for invalidation. 18621 if (is_the_hole) { 18622 cell->set_value(ReadOnlyRoots(isolate).undefined_value()); 18623 } else { 18624 cell->set_value(ReadOnlyRoots(isolate).the_hole_value()); 18625 } 18626 details = details.set_cell_type(PropertyCellType::kInvalidated); 18627 cell->set_property_details(details); 18628 cell->dependent_code()->DeoptimizeDependentCodeGroup( 18629 isolate, DependentCode::kPropertyCellChangedGroup); 18630 return new_cell; 18631 } 18632 18633 18634 PropertyCellConstantType PropertyCell::GetConstantType() { 18635 if (value()->IsSmi()) return PropertyCellConstantType::kSmi; 18636 return PropertyCellConstantType::kStableMap; 18637 } 18638 18639 18640 static bool RemainsConstantType(Handle<PropertyCell> cell, 18641 Handle<Object> value) { 18642 // TODO(dcarney): double->smi and smi->double transition from kConstant 18643 if (cell->value()->IsSmi() && value->IsSmi()) { 18644 return true; 18645 } else if (cell->value()->IsHeapObject() && value->IsHeapObject()) { 18646 return HeapObject::cast(cell->value())->map() == 18647 HeapObject::cast(*value)->map() && 18648 HeapObject::cast(*value)->map()->is_stable(); 18649 } 18650 return false; 18651 } 18652 18653 PropertyCellType PropertyCell::UpdatedType(Isolate* isolate, 18654 Handle<PropertyCell> cell, 18655 Handle<Object> value, 18656 PropertyDetails details) { 18657 PropertyCellType type = details.cell_type(); 18658 DCHECK(!value->IsTheHole(isolate)); 18659 if (cell->value()->IsTheHole(isolate)) { 18660 switch (type) { 18661 // Only allow a cell to transition once into constant state. 18662 case PropertyCellType::kUninitialized: 18663 if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined; 18664 return PropertyCellType::kConstant; 18665 case PropertyCellType::kInvalidated: 18666 return PropertyCellType::kMutable; 18667 default: 18668 UNREACHABLE(); 18669 } 18670 } 18671 switch (type) { 18672 case PropertyCellType::kUndefined: 18673 return PropertyCellType::kConstant; 18674 case PropertyCellType::kConstant: 18675 if (*value == cell->value()) return PropertyCellType::kConstant; 18676 V8_FALLTHROUGH; 18677 case PropertyCellType::kConstantType: 18678 if (RemainsConstantType(cell, value)) { 18679 return PropertyCellType::kConstantType; 18680 } 18681 V8_FALLTHROUGH; 18682 case PropertyCellType::kMutable: 18683 return PropertyCellType::kMutable; 18684 } 18685 UNREACHABLE(); 18686 } 18687 18688 Handle<PropertyCell> PropertyCell::PrepareForValue( 18689 Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry, 18690 Handle<Object> value, PropertyDetails details) { 18691 DCHECK(!value->IsTheHole(isolate)); 18692 Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate); 18693 const PropertyDetails original_details = cell->property_details(); 18694 // Data accesses could be cached in ics or optimized code. 18695 bool invalidate = 18696 (original_details.kind() == kData && details.kind() == kAccessor) || 18697 (!original_details.IsReadOnly() && details.IsReadOnly()); 18698 int index; 18699 PropertyCellType old_type = original_details.cell_type(); 18700 // Preserve the enumeration index unless the property was deleted or never 18701 // initialized. 18702 if (cell->value()->IsTheHole(isolate)) { 18703 index = dictionary->NextEnumerationIndex(); 18704 dictionary->SetNextEnumerationIndex(index + 1); 18705 } else { 18706 index = original_details.dictionary_index(); 18707 } 18708 DCHECK_LT(0, index); 18709 details = details.set_index(index); 18710 18711 PropertyCellType new_type = 18712 UpdatedType(isolate, cell, value, original_details); 18713 if (invalidate) { 18714 cell = PropertyCell::InvalidateEntry(isolate, dictionary, entry); 18715 } 18716 18717 // Install new property details. 18718 details = details.set_cell_type(new_type); 18719 cell->set_property_details(details); 18720 18721 if (new_type == PropertyCellType::kConstant || 18722 new_type == PropertyCellType::kConstantType) { 18723 // Store the value now to ensure that the cell contains the constant or 18724 // type information. Otherwise subsequent store operation will turn 18725 // the cell to mutable. 18726 cell->set_value(*value); 18727 } 18728 18729 // Deopt when transitioning from a constant type. 18730 if (!invalidate && (old_type != new_type || 18731 original_details.IsReadOnly() != details.IsReadOnly())) { 18732 cell->dependent_code()->DeoptimizeDependentCodeGroup( 18733 isolate, DependentCode::kPropertyCellChangedGroup); 18734 } 18735 return cell; 18736 } 18737 18738 18739 // static 18740 void PropertyCell::SetValueWithInvalidation(Isolate* isolate, 18741 Handle<PropertyCell> cell, 18742 Handle<Object> new_value) { 18743 if (cell->value() != *new_value) { 18744 cell->set_value(*new_value); 18745 cell->dependent_code()->DeoptimizeDependentCodeGroup( 18746 isolate, DependentCode::kPropertyCellChangedGroup); 18747 } 18748 } 18749 18750 int JSGeneratorObject::source_position() const { 18751 CHECK(is_suspended()); 18752 DCHECK(function()->shared()->HasBytecodeArray()); 18753 18754 int code_offset = Smi::ToInt(input_or_debug_pos()); 18755 18756 // The stored bytecode offset is relative to a different base than what 18757 // is used in the source position table, hence the subtraction. 18758 code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag; 18759 AbstractCode* code = 18760 AbstractCode::cast(function()->shared()->GetBytecodeArray()); 18761 return code->SourcePosition(code_offset); 18762 } 18763 18764 // static 18765 AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate, 18766 Handle<JSObject> receiver) { 18767 DisallowHeapAllocation no_gc; 18768 DCHECK(receiver->map()->is_access_check_needed()); 18769 Object* maybe_constructor = receiver->map()->GetConstructor(); 18770 if (maybe_constructor->IsFunctionTemplateInfo()) { 18771 Object* data_obj = 18772 FunctionTemplateInfo::cast(maybe_constructor)->access_check_info(); 18773 if (data_obj->IsUndefined(isolate)) return nullptr; 18774 return AccessCheckInfo::cast(data_obj); 18775 } 18776 // Might happen for a detached context. 18777 if (!maybe_constructor->IsJSFunction()) return nullptr; 18778 JSFunction* constructor = JSFunction::cast(maybe_constructor); 18779 // Might happen for the debug context. 18780 if (!constructor->shared()->IsApiFunction()) return nullptr; 18781 18782 Object* data_obj = 18783 constructor->shared()->get_api_func_data()->access_check_info(); 18784 if (data_obj->IsUndefined(isolate)) return nullptr; 18785 18786 return AccessCheckInfo::cast(data_obj); 18787 } 18788 18789 bool JSReceiver::HasProxyInPrototype(Isolate* isolate) { 18790 for (PrototypeIterator iter(isolate, this, kStartAtReceiver, 18791 PrototypeIterator::END_AT_NULL); 18792 !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) { 18793 if (iter.GetCurrent<Object>()->IsJSProxy()) return true; 18794 } 18795 return false; 18796 } 18797 18798 bool JSReceiver::HasComplexElements() { 18799 if (IsJSProxy()) return true; 18800 JSObject* this_object = JSObject::cast(this); 18801 if (this_object->HasIndexedInterceptor()) { 18802 return true; 18803 } 18804 if (!this_object->HasDictionaryElements()) return false; 18805 return this_object->element_dictionary()->HasComplexElements(); 18806 } 18807 18808 MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName( 18809 Isolate* isolate, Handle<Object> getter) { 18810 if (getter->IsFunctionTemplateInfo()) { 18811 Handle<FunctionTemplateInfo> fti = 18812 Handle<FunctionTemplateInfo>::cast(getter); 18813 // Check if the accessor uses a cached property. 18814 if (!fti->cached_property_name()->IsTheHole(isolate)) { 18815 return handle(Name::cast(fti->cached_property_name()), isolate); 18816 } 18817 } 18818 return MaybeHandle<Name>(); 18819 } 18820 18821 // Force instantiation of template instances class. 18822 // Please note this list is compiler dependent. 18823 // Keep this at the end of this file 18824 18825 template class HashTable<StringTable, StringTableShape>; 18826 18827 template class HashTable<CompilationCacheTable, CompilationCacheShape>; 18828 18829 template class HashTable<ObjectHashTable, ObjectHashTableShape>; 18830 18831 template class HashTable<EphemeronHashTable, EphemeronHashTableShape>; 18832 18833 template class ObjectHashTableBase<ObjectHashTable, ObjectHashTableShape>; 18834 18835 template class ObjectHashTableBase<EphemeronHashTable, EphemeronHashTableShape>; 18836 18837 template class Dictionary<NameDictionary, NameDictionaryShape>; 18838 18839 template class Dictionary<GlobalDictionary, GlobalDictionaryShape>; 18840 18841 template class EXPORT_TEMPLATE_DEFINE( 18842 V8_EXPORT_PRIVATE) HashTable<NumberDictionary, NumberDictionaryShape>; 18843 18844 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) 18845 Dictionary<NumberDictionary, NumberDictionaryShape>; 18846 18847 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) 18848 HashTable<SimpleNumberDictionary, SimpleNumberDictionaryShape>; 18849 18850 template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) 18851 Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>; 18852 18853 template Handle<NameDictionary> 18854 BaseNameDictionary<NameDictionary, NameDictionaryShape>::New( 18855 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option); 18856 18857 template Handle<GlobalDictionary> 18858 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::New( 18859 Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option); 18860 18861 template Handle<NameDictionary> 18862 HashTable<NameDictionary, NameDictionaryShape>::New(Isolate*, int, 18863 PretenureFlag, 18864 MinimumCapacity); 18865 18866 template Handle<ObjectHashSet> 18867 HashTable<ObjectHashSet, ObjectHashSetShape>::New(Isolate*, int n, 18868 PretenureFlag, 18869 MinimumCapacity); 18870 18871 template Handle<NameDictionary> 18872 HashTable<NameDictionary, NameDictionaryShape>::Shrink(Isolate* isolate, 18873 Handle<NameDictionary>, 18874 int additionalCapacity); 18875 18876 template Handle<NameDictionary> 18877 BaseNameDictionary<NameDictionary, NameDictionaryShape>::Add( 18878 Isolate* isolate, Handle<NameDictionary>, Handle<Name>, Handle<Object>, 18879 PropertyDetails, int*); 18880 18881 template Handle<GlobalDictionary> 18882 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::Add( 18883 Isolate* isolate, Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, 18884 PropertyDetails, int*); 18885 18886 template void HashTable<GlobalDictionary, GlobalDictionaryShape>::Rehash( 18887 Isolate* isolate); 18888 18889 template Handle<NameDictionary> 18890 BaseNameDictionary<NameDictionary, NameDictionaryShape>::EnsureCapacity( 18891 Isolate* isolate, Handle<NameDictionary>, int); 18892 18893 template void 18894 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CopyEnumKeysTo( 18895 Isolate* isolate, Handle<GlobalDictionary> dictionary, 18896 Handle<FixedArray> storage, KeyCollectionMode mode, 18897 KeyAccumulator* accumulator); 18898 18899 template void 18900 BaseNameDictionary<NameDictionary, NameDictionaryShape>::CopyEnumKeysTo( 18901 Isolate* isolate, Handle<NameDictionary> dictionary, 18902 Handle<FixedArray> storage, KeyCollectionMode mode, 18903 KeyAccumulator* accumulator); 18904 18905 template Handle<FixedArray> 18906 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::IterationIndices( 18907 Isolate* isolate, Handle<GlobalDictionary> dictionary); 18908 template void 18909 BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>::CollectKeysTo( 18910 Handle<GlobalDictionary> dictionary, KeyAccumulator* keys); 18911 18912 template Handle<FixedArray> 18913 BaseNameDictionary<NameDictionary, NameDictionaryShape>::IterationIndices( 18914 Isolate* isolate, Handle<NameDictionary> dictionary); 18915 template void 18916 BaseNameDictionary<NameDictionary, NameDictionaryShape>::CollectKeysTo( 18917 Handle<NameDictionary> dictionary, KeyAccumulator* keys); 18918 18919 } // namespace internal 18920 } // namespace v8 18921